前一段时间面试官问我Android在Linux的基础上,权限做了哪些改变。霹雳呱啦说了一堆,但是说着说着,始终感觉自己说的缺了点东西,自己理解还是不够到位
,而且网上的很多文章在原理上基本都是大同小异,很多地方都是语焉不详,所以,自己半看源码半看文章的总结了一下。

一:Android权限是什么

  这个是老生长谈的东西了,说到底,权限就是告诉系统我需要干什么,从访问物理数据,到访问第三方组件均是。

二:权限赋予

  权限的赋予可分为两类,一类是高层的组件,例如应用和系统服务,这一部分一般采用包管理器依赖进行管理,查询。而另一部分则是低层的组件,这一部分则是利用了传统了Linux DAC机制进行管理,一般不直接访问包管理器。

  1:低层权限管理

  这里包括但不限于设备文件,UNIX套接字,网络套接字。Android进程主要通过UID,GID以及一组补充的GID实现的。众所周知,Android沙箱是以UID为基础实现的,每个进程拥有自己独特的UID(先不考虑共享UID)。进程的UID和GID会由包管理器映射到应用程序的UID。而补充gid则为额外的权限。值得一提的是,内置权限到组的映射是静态的。部分源码如下

<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>
<permission name="android.permission.BLUETOOTH" >
<group gid="net_bt" />
</permission>
<permission name="android.permission.BLUETOOTH_STACK" >
<group gid="bluetooth" />
<group gid="wakelock" />
</permission>

  如上,android.permission.BLUETOOTH_ADMIN,android.permission.BLUETOOTH 和GID net_bt_admin组是关联的.而在 android_filesystem_config.h中,组和GID是想映射的,如下

static struct android_id_info android_ids[] = {
  ....
  { "shell", AID_SHELL, },
  { "cache", AID_CACHE, },
  { "net_bt_admin", AID_NET_BT_ADMIN, },
  ....
}
#define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
#define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
#define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
#define AID_NET_RAW 3004 /* can create raw INET sockets */
#define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */

  可得android.permission.BLUETOOTH_ADMIN映射的GID的3001。总而言之,包管理器在读取platfrom.xml时,并维护一个权限到GID的列表。在对一个安装中的包进行授权时,包管理器会检查每个权限是否有对应的GID。如果有,则加入在补充GID列表。当然,到这里只是确定了进程需要赋予哪些额外的gid。

  并没有说怎么赋权的,这里要谈到一个叫zygote的进程,顾名思义,当Android启动新进程的时候,为了减少程序所需内存以及加快启动时间,Android会直接fork()zygote进程,并执行Android特有的函数进行分化而不执行固有的exec函数。简化代码如下(android / platform / dalvik / 7033bed / . / vm / native / dalvik_system_Zygote.cpp forkAndSpecializeCommon()):

pid = fork();

if(pid ==0 ){
err = setgroupsIntarray(gids);          //设置补充gid
err = setrlimitsFromArray(rlimits);       //设置资源限制
err = setresgid(gid, gid, gid);          //设置实际用户/组id
err = setresuid(uid, uid, uid);          //设置有效用户/组id
err = setCapabilities(permittedCapabilities, effectiveCapabilities);      //设置进程权能
err = set_sched_policy(0, SP_DEFAULT);      //设置调度策略
err = setSELinuxContext(uid, isSystemServer, seInfo, niceName);      //SElinux
}

  2.高层权限管理

  在仔细讲解之前,先来看看包管理器所维护的安装程序包核心数据库,这个数据库以xml文件的形式放进了/data/system/packages.xml里,先来看看里面究竟有些什么。

<package name="com.android.protips" codePath="/system/app/Protips" nativeLibraryPath="/system/app/Protips/lib" flags="" ft="1560a280490" it="1560a280490" ut="1560a280490" version="" userId="">
<sigs count="">
<cert index="" />
</sigs>
<proper-signing-keyset identifier="" />
<signing-keyset identifier="" />
</package>
<package name="com.android.launcher" codePath="/system/priv-app/Launcher2" nativeLibraryPath="/system/priv-app/Launcher2/lib" flags="" ft="1560a29ae58" it="1560a29ae58" ut="1560a29ae58" version="" userId="">
<sigs count="">
<cert index="" key="308204a1406035504071302fc58d017971bd0f6b52c262d70819d191967e158dfd3a2c7f1b30fa1eaafc2a556f84" />
</sigs>
<proper-signing-keyset identifier="" />
<signing-keyset identifier="" />
</package>
  

 <package name="com.android.widgetpreview" codePath="/data/app/WidgetPreview" nativeLibraryPath="/data/app/WidgetPreview/lib" flags="572996" ft="15bbc858e28" it="1560a27f8d8" ut="1560a27f8d8"       version="22" userId="10052">
    <sigs count="1">
    <cert index="0" />
  </sigs>
  <perms>
  <item name="android.permission.READ_EXTERNAL_STORAGE" />
  <item name="android.permission.WRITE_EXTERNAL_STORAGE" />
  </perms>
  <proper-signing-keyset identifier="2" />
  <signing-keyset identifier="2" />
</package>

  从上面可以发现,这里包括了安装路径,版本号,签名证书,每个包的权限。上层的管理都是通过和包管理器和这个数据库进行交互的。由于组件不能在运行时改变权限,所以权限执行检查都是静态的。但它的执行一般分为两类,一类是静态,另一类是动态的。静态执行和动态执行流程大致相同:Binder.getCallingUid()和Binder.getCallingPid()获取调用者的UID和PID,然后利用UID映射包名,再获得相关权限。如果权限集合中含有所需权限即启动,否则抛出SecurityException异常。

三:共享UID(补充)

  使用相同的密匙签发的Android应用可以使用共同的UID运行 ,并且可以运行在同一进程中。这个属性可以简单通过在AndroidManifest.xml的根元素中添加shareUserId属性即可开启,但是不能在已安装的应用里添加该属性,这只会导致它修改自身uid,以至于失去对自身文件的访问权限。

  shareid内置了以下几种:

    android.uid.system(SYSTEM_UID,1000)

    android.uid.phone(PHONE_UID,1001)

    android.uid.bluetooth(BLUETOOH_UID,1002)

    android.uid.log(LOG_UID,1007)

    android.uid.nfc(NFC_UID,1027)

  它们在系统引导时自动添加。具有相同userid的进程,可以访问相同的系统资源,还可以对统一资源的组件进行特殊访问控制。

  

抽丝剥茧:理解Android权限机制的更多相关文章

  1. 全方位理解Android权限之底层实现概览

    0000 这个阶段搞了很多和Android文件权限相关的问题,虽然一知半解,但也算是对Android权限机制有一些自己的理解.遂将这些内容整理出来.因为权限这部分涉及到的内容很多,故将知识分为几块内容 ...

  2. 理解Android安全机制

    本文从Android系统架构着手,分析Android的安全机制以SE Android,最后给出一些Android安全现状和常见的安全解决方案. 1.Android系统架构 Android采用分层的系统 ...

  3. Android权限机制

    Android系统是运行在Linux内核上的,Android与Linux分别有自己的一套严格的安全及权限机制, 很多像我这样的新手,尤其是习惯了windows低安全限制的用户,很容易在这方面弄混淆,下 ...

  4. 理解 Android Binder 机制(一):驱动篇

    Binder的实现是比较复杂的,想要完全弄明白是怎么一回事,并不是一件容易的事情. 这里面牵涉到好几个层次,每一层都有一些模块和机制需要理解.这部分内容预计会分为三篇文章来讲解.本文是第一篇,首先会对 ...

  5. 深入理解Android消息机制

    在日常的开发中,Android 的消息机制作为系统运行的根本机制之一,显得十分的重要. 从 Handler 发送消息开始 查看源码,Handler的post.send方法最终都会走到 public f ...

  6. 深入理解 Android 消息机制原理

    欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:汪毅雄 导语: 本文讲述的是Android的消息机制原理,从Java到Native代码进行了梳理,并结合其中使用到的Epoll模型予以介 ...

  7. 深入理解Android IPC机制之Binder机制

    Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有的进程间通信IPC手段包括(Internet Process Connection): 管道(Pipe).信号(Sign ...

  8. Android Handler的使用示例:结合源码理解Android Handler机制(一)

    什么是Handler? Android 的官方解释: 文档分节1:A Handler allows you to send and process Message and Runnable objec ...

  9. Android权限管理之Permission权限机制及使用

    前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...

随机推荐

  1. Codeforces 713C Sonya and Problem Wihtout a Legend DP

    C. Sonya and Problem Wihtout a Legend time limit per test 5 seconds memory limit per test 256 megaby ...

  2. Tomcat 7下如何利用 catalina.properties 部署公用类

    Tomcat 有很多配置文件,其中一个是  catalina.properties ,本文介绍catalina.properties 中的设置项. 一.组成   catalina.properties ...

  3. Item 11 谨慎地覆盖Clone

    1.进行浅拷贝时,只是复制原始数据类型的值,则可以通过覆盖Clone方法来达到.另外,在进行浅拷贝的时候,还要注意,成员对象中不应该要有引用类型,如果有引用类型,那么,进行了浅拷贝之后,两个对象将会共 ...

  4. 【BZOJ】1031 [JSOI2007]字符加密Cipher

    [算法]后缀数组 [题解]把数组复制一遍然后SA处理即可. 后缀数组 #include<cstdio> #include<algorithm> #include<cstr ...

  5. SpringBoot Mybatis 读写分离配置(山东数漫江湖)

    为什么需要读写分离 当项目越来越大和并发越来大的情况下,单个数据库服务器的压力肯定也是越来越大,最终演变成数据库成为性能的瓶颈,而且当数据越来越多时,查询也更加耗费时间,当然数据库数据过大时,可以采用 ...

  6. elementui raido 单选框 循环渲染加:key

    <el-radio-group v-model="adminRole"> <el-radio v-for="item in adminRoles&quo ...

  7. 【HNOI】 c tree-dp

    [题目描述]给定一个n个节点的树,每个节点有两个属性值a[i],b[i],我们可以在树中选取一个连通块G,这个连通块的值为(Σa[x])(Σb[x]) x∈G,求所有连通块的值的和,输出答案对1000 ...

  8. CSS浮动为什么不会遮盖同级元素

    1.问题描述 在W3CSchool学习web前端时,看完CSS定位-浮动这一节后,感觉没有什么问题.但是在CSS高级-分类这一节的中进行实践时,遇到了如下问题.测试地址:浮动的简单应用. 完整的htm ...

  9. Windows下基于python3使用word2vec训练中文维基百科语料(二)

    在上一篇对中文维基百科语料处理将其转换成.txt的文本文档的基础上,我们要将为文本转换成向量,首先都要对文本进行预处理 步骤四:由于得到的中文维基百科中有许多繁体字,所以我们现在就是将繁体字转换成简体 ...

  10. python基础===【爬虫】爬虫糗事百科首页图片代码

    import requests import re import urllib.request def getHtml(url): page = requests.get(url) html = pa ...