抽丝剥茧:理解Android权限机制
前一段时间面试官问我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权限机制的更多相关文章
- 全方位理解Android权限之底层实现概览
0000 这个阶段搞了很多和Android文件权限相关的问题,虽然一知半解,但也算是对Android权限机制有一些自己的理解.遂将这些内容整理出来.因为权限这部分涉及到的内容很多,故将知识分为几块内容 ...
- 理解Android安全机制
本文从Android系统架构着手,分析Android的安全机制以SE Android,最后给出一些Android安全现状和常见的安全解决方案. 1.Android系统架构 Android采用分层的系统 ...
- Android权限机制
Android系统是运行在Linux内核上的,Android与Linux分别有自己的一套严格的安全及权限机制, 很多像我这样的新手,尤其是习惯了windows低安全限制的用户,很容易在这方面弄混淆,下 ...
- 理解 Android Binder 机制(一):驱动篇
Binder的实现是比较复杂的,想要完全弄明白是怎么一回事,并不是一件容易的事情. 这里面牵涉到好几个层次,每一层都有一些模块和机制需要理解.这部分内容预计会分为三篇文章来讲解.本文是第一篇,首先会对 ...
- 深入理解Android消息机制
在日常的开发中,Android 的消息机制作为系统运行的根本机制之一,显得十分的重要. 从 Handler 发送消息开始 查看源码,Handler的post.send方法最终都会走到 public f ...
- 深入理解 Android 消息机制原理
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:汪毅雄 导语: 本文讲述的是Android的消息机制原理,从Java到Native代码进行了梳理,并结合其中使用到的Epoll模型予以介 ...
- 深入理解Android IPC机制之Binder机制
Binder是Android系统进程间通信(IPC)方式之一.Linux已经拥有的进程间通信IPC手段包括(Internet Process Connection): 管道(Pipe).信号(Sign ...
- Android Handler的使用示例:结合源码理解Android Handler机制(一)
什么是Handler? Android 的官方解释: 文档分节1:A Handler allows you to send and process Message and Runnable objec ...
- Android权限管理之Permission权限机制及使用
前言: 最近突然喜欢上一句诗:"宠辱不惊,看庭前花开花落:去留无意,望天空云卷云舒." 哈哈~,这个和今天的主题无关,最近只要不学习总觉得生活中少了点什么,所以想着围绕着最近面试过 ...
随机推荐
- 彻底找到 Tomcat 启动速度慢的元凶 /dev/random
参考 http://blog.csdn.net/u013939884/article/details/72860358
- 快速搭建 DNS 服务器: skydns + etcd
参考: [ skynetservice github ] [ skydns 测试记录 CSDN ] etcd 安装配置 安装 yum install etcd 配置 sed -i 's@ETCD_LI ...
- 【洛谷 P1073】 最优贸易 (Tarjan缩点+拓扑排序)
题目链接 先\(Tarjan\)缩点,记录每个环内的最大值和最小值. 然后跑拓扑排序,\(Min[u]\)表示到\(u\)的最小值,\(ans[u]\)表示到\(u\)的答案,\(Min\)和\(an ...
- 如何彻底关闭退出vmware虚拟机
如何彻底关闭退出vmware虚拟机 每次使用虚拟机之后退出时,它都会在系统托盘区留下一个虚拟机图标,该如何彻底关闭退出vmware虚拟机呢? 首先我们需要运行一下虚拟机程序 1:我们如果要对虚拟机进行 ...
- HDU 4757 可持久化trie树
首先如果给定一些数,询问这些数中哪个数^给定的数的值最大的话,我们可以建立一颗trie树,根连接的两条边分别为0,1,表示二进制下第15位,那么我们可以建立一颗trie树,每一条从根到叶子节点的链表示 ...
- Sqlmap使用教程
sqlmap也是渗透中常用的一个注入工具,其实在注入工具方面,一个sqlmap就足够用了,只要你用的熟,秒杀各种工具,只是一个便捷性问题,sql注入另一方面就是手工党了,这个就另当别论了. 今天把我一 ...
- scikit-learn中的岭回归(Ridge Regression)与Lasso回归
一.岭回归模型 岭回归其实就是在普通最小二乘法回归(ordinary least squares regression)的基础上,加入了正则化参数λ. 二.如何调用 class sklearn.lin ...
- 如何得知 kernel 或 android 已開機多久時間
adb shell cat /proc/uptime 中的第一個數字, adb shell cat "/proc/uptime" 210.79 312.76 或者是 kernel ...
- 2017多校第6场 HDU 6097 Mindis 计算几何,圆的反演
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6097 题意:有一个圆心在原点的圆,给定圆的半径,给定P.Q两点坐标(PO=QO,P.Q不在圆外),取圆 ...
- [总结]可重用cell的定义方式
1.简介 为了提高tableview中cell的加载速度通常可以使用cell重用的方式来实现,即我们向上拖动cell的时候,上部份消失的cell可以重复的被下部分出现的cell重用. 2.说明 一般c ...