Android permission control code analysis
Before in the article introduced android system management level: http://www.bkjia.com/kf/201204/127682.html, here the core code analysis
The android system makes full use of the linux user permission management method. Therefore, if you need to port the tool to other systems, this is a considerable workload. So how does the android system use these favorable factors?
First, you need to know two basic knowledge about linux permissions:
1. A user can belong to multiple groups.
2. A file can only belong to a group.
This is mainly in AndroidManifest. the permission is declared in xml mainly through AndroidManifest. the permissions required by the application are explicitly declared in xml to prevent improper use of services and improper access to resources by the application.
Each permission in Android is represented by an independent tag. For example:
<Uses-permission android: name = "android. permission. WAKE_LOCK"/>
<Uses-permission android: name = "android. permission. INTERNET"/>
<Uses-permission android: name = "android. permission. READ_PHONE_STATE"/>
<Uses-permission android: name = "android. permission. WRITE_EXTERNAL_STORAGE"/>
When you Install an application, Android gives a UID. This UID can be linked to the AndroidManifest. xml file of the application. When the User installs your application, he can view the content of this AndroidManifest. xml file in the screen window. During the inspection, the user will see your description of the purpose and permissions of the application. After you accept the intent and permission description of this program, Android will install it and give it a UID. In case of an unauthorized behavior during the execution of your application, the user will receive a warning message from Android.
The following is the interface for installing two installers:
The codes of these two applications are the same. The only difference is that their AndroidManifest. xml contains the following content in AndroidManifest. xml in Figure 2:
<Uses-permission android: name = "android. permission. RECORD_AUDIO"/>
<Uses-permission android: name = "android. permission. WRITE_EXTERNAL_STORAGE"/>
That is, you need to use the storage device and recording device. During installation, the user is prompted for the required permissions. In Android, how is it controlled?
When installing the apk, The AndroidManifest. xml will be parsed and the corresponding information will be saved.
Code path: frameworks \ base \ core \ java \ android \ content \ pm \ PackageParser. java
The private Package parsePackage (
Resources res, XmlResourceParser parser, int flags, String [] outError)
This function is parsed in AndroidManifest. xml, where
Private Package parsePackage (
Resources res, XmlResourceParser parser, int flags, String [] outError)
Throws XmlPullParserException, IOException {
...
String tagName = parser. getName ();
If (tagName. equals ("application ")){
...
} Else if (tagName. equals ("permission-group ")){
If (parsePermissionGroup (pkg, res, parser, attrs, outError) = null ){
Return null;
}
} Else if (tagName. equals ("permission ")){
If (parsePermission (pkg, res, parser, attrs, outError) = null ){
Return null;
}
} Else if (tagName. equals ("permission-tree ")){
If (parsePermissionTree (pkg, res, parser, attrs, outError) = null ){
Return null;
}
} Else if (tagName. equals ("uses-permission ")){
Sa = res. obtainAttributes (attrs,
Com. android. internal. R. styleable. AndroidManifestUsesPermission );
// Note: don't allow this value to be a reference to a resource
// That may change.
String name = sa. getNonResourceString (
Com. android. internal. R. styleable. AndroidManifestUsesPermission_name );
Sa. recycle ();
If (name! = Null &&! Pkg. requestedPermissions. contains (name )){
Pkg. requestedPermissions. add (name. intern ());
}
XmlUtils. skipCurrentTag (parser );
}
...
}
The permissions used are parsed here.
All the strings such as "android. permission. WRITE_EXTERNAL_STORAGE" are saved here. After parsing, The grantPermissionsLP function is called to obtain the corresponding group_id,
Code path: frameworks \ base \ services \ java \ com \ android \ server \ PackageManagerService. java
Private void grantPermissionsLP (PackageParser. Package pkg, boolean replace ){
...
If (allowed ){
If (! Gp. grantedPermissions. contains (perm )){
ChangedPermission = true;
Gp. grantedPermissions. add (perm );
Gp. gids = appendInts (gp. gids, bp. gids );
} Else if (! Ps. haveGids ){
Gp. gids = appendInts (gp. gids, bp. gids );
}
} Else {
Slog. w (TAG, "Not granting permission" + perm
+ "To package" + pkg. packageName
+ "Because it was previusly installed ");
}
...
}
Save the corresponding groups to gids.
When the application is started
Private final void startProcessLocked (ProcessRecord app,
String hostingType, String hostingNameStr)
Code path: frameworks \ base \ services \ java \ com \ android \ server \ am \ ActivityManagerService. java
Private final void startProcessLocked (ProcessRecord app,
String hostingType, String hostingNameStr ){
...
Try {
Int uid = app.info. uid;
Int [] gids = null;
Try {
Gids = mContext. getPackageManager (). getPackageGids (
App.info. packageName );
} Catch (PackageManager. NameNotFoundException e ){
Slog. w (TAG, "Unable to retrieve gids", e );
}
...
Int pid = Process. start ("android. app. ActivityThread ",
MSimpleProcessManagement? App. processName: null, uid, uid,
Gids, debugFlags, null );
}
Here we get the previously saved gids, and then call it to create a new process. The parameters passed here include gids.
Create a new process and use jni to call the forkAndSpecializeCommon function (Path: \ dalvik \ vm \ native \ dalvik_system_Zygote.c)
Static pid_t forkAndSpecializeCommon (const u4 * args, bool isSystemServer)
{
Pid_t pid;
Uid_t uid = (uid_t) args [0];
Gid_t gid = (gid_t) args [1];
ArrayObject * gids = (ArrayObject *) args [2];
U4 debugFlags = args [3];
ArrayObject * rlimits = (ArrayObject *) args [4];
Int64_t permittedCapabilities, effectiveCapabilities;
...
Pid = fork ();
If (pid = 0 ){
Int err;
/* The child process */
Err = setgroupsIntarray (gids );
If (err <0 ){
LOGE ("cannot setgroups (): % s", strerror (errno ));
DvmAbort ();
}
Err = setrlimitsFromArray (rlimits );
If (err <0 ){
LOGE ("cannot setrlimit (): % s", strerror (errno ));
DvmAbort ();
}
Err = setgid (gid );
If (err <0 ){
LOGE ("cannot setgid (% d): % s", gid, strerror (errno ));
DvmAbort ();
}
Err = setuid (uid );
If (err <0 ){
LOGE ("cannot setuid (% d): % s", uid, strerror (errno ));
DvmAbort ();
}
...
}
In the sub-process, call setgroupsIntarray to set the group to which the process belongs, so that it has the permissions of the group. The uid and gid value of the application are also determined by setgid and setuid.
For example:
Create an Android project, read the uid/gid value of the application, and paste the following code:
Try {
Java. lang. Process process = runtime.getruntime(cmd.exe c ("id ");
InputStream input = process. getInputStream ();
Byte [] bytes = new byte [1, 1204];
Int len;
While (len = (input. read (bytes)> 0)
{
System. out. print (new String (bytes, 0, len ));
}
Input. close ();
Run the linux id command code here. The id command is used to output the uid of the current user, the main group id and the group
Add the following permissions in AndroidManifest. xml:
<Uses-permission android: name = "android. permission. WRITE_EXTERNAL_STORAGE"/>
After running the command, check that the log contains:
Groups = 1015
Check android_filesystem_config.h again.
Code path:
System \ core \ include \ private
The following code is available:
# Define AID_ROOT 0/* traditional unix root user */
# Define AID_SYSTEM 1000/* system server */
# Define AID_RADIO 1001/* telephony subsystem, RIL */
# Define AID_BLUETOOTH 1002/* bluetooth subsystem */
# Define AID_GRAPHICS 1003/* graphics devices */
...
# Define AID_WIFI 1010/* wifi subsystem */
# Define AID_ADB 1011/* android debug bridge (adbd )*/
# Define AID_INSTALL 1012/* group for installing packages */
# Define AID_MEDIA 1013/* mediaserver process */
# Define AID_DHCP 1014/* dhcp client */
# Define AID_SDCARD_RW 1015/* external storage write access */
Let's look at platform. xml.
Path: frameworks \ base \ data \ etc
The following configurations are available:
<Permission name = "android. permission. WRITE_EXTERNAL_STORAGE">
<Group gid = "sdcard_rw"/>
</Permission>
In this way, the android. permission. WRITE_EXTERNAL_STORAGE, "sdcard_rw", and the 1015 groups are associated.
Let's look at the directory permission after the SD card is mounted:
Ls-l
Drwxr-xr-x root system 1970-01-01 08:00 obb
Drwxr-xr-x root system 1970-01-01 08:00 asec
Drwx ------ root 1970-01-01 08:00 secure
D --- rwxr-x system sdcard_rw sdcard
We can see that for the SD card, the group user has read and write permissions, and our application is added to this group, so that it can operate on sdcard.
When an application needs to operate sdcard without adding the corresponding permission in AndroidManifest. xml, it cannot be completed successfully.
The following is a program with the WRITE_EXTERNAL_STORAGE permission added to AndroidManifest. xml. If there is no such permission, you can see that the program is abnormal because you do not have the permission to run the program.
From andyhuabing's column