本文共 4895 字,大约阅读时间需要 16 分钟。
两点基本知识:
1、 一个用户可以属于多个组.
2、 一个文件只能属于某个组。
这里主要是在AndroidManifest.xml中声明权限,主要是通过在AndroidManifest.xml中显示地声明应用程序需要的权限,防止应用程序错误的使用服务,不恰当访问资源。
Android中每种权限都用一个独立的标签表示.如:
android.permission.BLUETOOTH
当在安装(Install) 应用程序时,Android就会给予一个UID。这个UID可连结到该应用程序的 AndroidManifest.xml档案的内容。所以User在安装你的应用程序时,在屏幕上的窗口里可以检视这个 AndroidManifest.xml档案的内容。在检视时,用户会看到你对应用程序的目的、权限等说明。当你接受这支程序的意图、权限说明之后,Android就安装它,并给它一个UID。万一在你的应用程序执行期间有越轨(企图做出非权限范围)的行为时,用户将会得到Android的警告讯息。
下面是两个安装程序安装时的界面
这两个应用其实代码是一样的,唯一的不同就是它们的AndroidManifest.xml,图2的AndroidManifest.xml中多了如下内容:
<uses-permissionandroid:name="android.permission.RECORD_AUDIO"/>
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
即需要使用存储设备和录音设备,在安装的时候,就会提示用户它需要的权限。Android里面是怎么去控制的呢?
在安装apk的时候,会解析这个AndroidManifest.xml,把相应的信息保存起来。
- private Package parsePackage(
- Resources res, XmlResourceParser parser, int flags, String[] outError)
- throws XmlPullParserException, IOException {
- ...
- } else if (tagName.equals("uses-permission")) {
- sa = res.obtainAttributes(attrs,
- com.android.internal.R.styleable.AndroidManifestUsesPermission);
-
-
-
- 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);
-
- }
- }
这里对它使用的权限进行了解析。
这里保存的都是"android.permission.WRITE_EXTERNAL_STORAGE"这样的字符串,在解析完后,会调用grantPermissionsLP函数获取对应的group_id,
- 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);
- }
- }
- ...
- }
这里把相应的组都保存到了gids中。
当应用程序起来的过程中会调用 - 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);
- }
创建了一个新的线程,这里传的参数就有gids
这里创建新进程最终调用forkAndSpecializeCommon
- static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
- {
- ...
- pid = fork();
-
- if (pid == 0) {
- int err;
-
-
- #ifdef HAVE_ANDROID_OS
- extern int gMallocLeakZygoteChild;
- gMallocLeakZygoteChild = 1;
-
-
- if (uid != 0) {
- err = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
-
- if (err < 0) {
- LOGE("cannot PR_SET_KEEPCAPS: %s", strerror(errno));
- dvmAbort();
- }
- }
-
- #endif /* HAVE_ANDROID_OS */
-
- err = setgroupsIntarray(gids);
-
- if (err < 0) {
- LOGE("cannot setgroups(): %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();
- }
- }
我们看到在子进程里调用setgroupsIntarray设置该进程所属的组,这样它就拥有了该组的权限。
举个例子:
我们新建一Android工程,贴入如下代码:
- try{
- java.lang.Process process = Runtime.getRuntime().exec("id");
- InputStream input = process.getInputStream();
- byte[] bytes = new byte[1204];
- int len;
- while((len = (input.read(bytes))) > 0)
- {
- System.out.print(new String(bytes, 0, len));
- }
- input.close();
这里运行运行linux的id命令的代码,id命令的功能是输出当前用户的uid,主要的group id和所在的group
在其AndroidManifest.xml添加如下权限:
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
运行后看log里面有:
这里面就有groups=1015
再看下android_filesystem_config.h里面
代码路径:
system\core\include\private
有如下代码
- #define AID_MEDIA 1013 /* mediaserver process */
- #define AID_DHCP 1014 /* dhcp client */
- #define AID_SDCARD_RW 1015 /* external storage write access */
- #define AID_VPN 1016 /* vpn system */
- ......
- { "cache", AID_CACHE, },
- { "diag", AID_DIAG, },
- { "net_bt_admin", AID_NET_BT_ADMIN, },
- { "net_bt", AID_NET_BT, },
- { "sdcard_rw", AID_SDCARD_RW, },
- { "vpn", AID_VPN, },
再看下platform.xml
路径:frameworks\base\data\etc
有如下配置
- <permission name="android.permission.WRITE_EXTERNAL_STORAGE" >
- <group gid="sdcard_rw" />
- </permission>
这样就把android.permission.WRITE_EXTERNAL_STORAGE、"sdcard_rw"、以及 1015组关联起来了,我们再看下当sd卡挂载上去后目录的权限:
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 root 1970-01-01 08:00 secure
d---rwxr-xsystem sdcard_rw 2012-03-29 17:11sdcard
可以看到对于sd卡,组用户具有读写权限,而我们的应用也加入了这个组,这样它就可以操作sdcard了。
当一个应用需要操作sdcard而没有在AndroidManifest.xml添加相应的权限时,就不能成功完成。
以下是同一个程序,一个有在AndroidManifest.xml添加 WRITE_EXTERNAL_STORAGE 权限,一个没有,它们的对比,可以看到由于没有权限程序运行异常了.
这里的权限只是android里面涉及的一小部分,其实还有很多其它的权限。
参考:
转载地址:http://ptlli.baihongyu.com/