Android系统是运行在Linux内核上的,Android与Linux分别有本身的一套严格的安全及权限机制java
(一)linux文件系统上的权限linux
-rwxr-x--x system system 4156 2012-06-30 16:12 test.apk.
表明的是相应的用户/用户组及其余人对此文件的访问权限,与此文件运行起来具备的权限彻底不相关。android
好比上面的例子只能说明system用户拥有对此文件的读写执行权限;system组的用户对此文件拥有读、执行权限;其余人对此文件只具备执行权限。而test.apk运行起来后能够干哪些事情,跟这个就不相关了。
千万不要看apk文件系统上属于system/system用户及用户组,或者root/root用户及用户组,就认为apk具备system或root权限。apk程序是运行在虚拟机上的,对应的是Android独特的权限机制,只有体现到文件系统上时才使用linux的权限设置。安全
(二)Android的权限规则app
(1)Android中的apk必须签名
这种签名不是基于权威证书的,不会决定某个应用允不容许安装,而是一种自签名证书。
重要的是,android系统有的权限是基于签名的。好比:system等级的权限有专门对应的签名,签名不对,权限也就获取不到。eclipse
默认生成的APK文件是debug签名的。获取system权限时用到的签名见后面描述。ide
(2)基于UserID的进程级别的安全机制
进程有独立的地址空间,进程与进程间默认是不能互相访问的,Android经过为每个apk分配惟一的linux userID来实现,名称为"app_"加一个数字,好比app_43不一样的UserID,运行在不一样的进程,因此apk之间默认便不能相互访问。函数
Android提供了以下的一种机制,可使两个apk打破前面讲的这种壁垒。
在AndroidManifest.xml中利用sharedUserId属性给不一样的package分配相同的userID,经过这样作,两个package能够被当作同一个程序,系统会分配给两个程序相同的UserID。固然,基于安全考虑,两个apk须要相同的签名,不然没有验证也就没有意义了。工具
(3)默认apk生成的数据对外是不可见的
实现方法是:Android会为程序存储的数据分配该程序的UserID。
借助于Linux严格的文件系统访问权限,便实现了apk之间不能相互访问似有数据的机制。
例:个人应用建立的一个文件,默认权限以下,能够看到只有UserID为app_21的程序才能读写该文件。ui
-rw------- app_21 app_21 87650 2000-01-01 09:48 test.txt
如何对外开放?
<1> 使用MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE标记。
When creating a new file with getSharedPreferences(String, int), openFileOutput(String, int), or openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), you can use the MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE flags to allow any other package to read/write the file. When setting these flags, the file is still owned by your application, but its global read and/or write permissions have been set appropriately so any other application can see it.
(4)AndroidManifest.xml中的显式权限声明
Android默认应用是没有任何权限去操做其余应用或系统相关特性的,应用在进行某些操做时都须要显式地去申请相应的权限。
通常如下动做时都须要申请相应的权限:
A particular permission may be enforced at a number of places during your program's operation:
At the time of a call into the system, to prevent an application from executing certain functions.When starting an activity, to prevent applications from launching activities of other applications.Both sending and receiving broadcasts, to control who can receive your broadcast or who can send a broadcast to you.When accessing and operating on a content provider.Binding or starting a service.
在应用安装的时候,package installer会检测该应用请求的权限,根据该应用的签名或者提示用户来分配相应的权限。
在程序运行期间是不检测权限的。若是安装时权限获取失败,那执行就会出错,不会提示用户权限不够。
大多数状况下,权限不足致使的失败会引起一个 SecurityException,会在系统log(system log)中有相关记录。
(5)权限继承/UserID继承
当咱们遇到apk权限不足时,咱们有时会考虑写一个linux程序,而后由apk调用它去完成某个它没有权限完成的事情,很遗憾,这种方法是行不通的。
前面讲过,android权限是在进程层面的,也就是说一个apk应用启动的子进程的权限不可能超越其父进程的权限(即apk的权限),
即便单独运行某个应用有权限作某事,但若是它是由一个apk调用的,那权限就会被限制。
实际上,android是经过给子进程分配父进程的UserID实现这一机制的。
(三)常见权限不足问题分析
首先要知道,普通apk程序是运行在非root、非system层级的,也就是说看要访问的文件的权限时,看的是最后三位。
另外,经过system/app安装的apk的权限通常比直接安装或adb install安装的apk的权限要高一些。
言归正传,运行一个android应用程序过程当中遇到权限不足,通常分为两种状况:
(1)Log中可明显看到权限不足的提示。
此种状况通常是AndroidManifest.xml中缺乏相应的权限设置,好好查找一番权限列表,应该就可解决,是最易处理的状况。
有时权限都加上了,但仍是报权限不足,是什么状况呢?
Android系统有一些API及权限是须要apk具备必定的等级才能运行的。
好比 SystemClock.setCurrentTimeMillis()修改系统时间,WRITE_SECURE_SETTINGS权限好像都是须要有system级的权限才行。
也就是说UserID是system.
(2)Log里没有报权限不足,而是一些其余Exception的提示,这也有多是权限不足形成的。
好比:咱们常会想读/写一个配置文件或其余一些不是本身建立的文件,常会报java.io.FileNotFoundException错误。
系统认为比较重要的文件通常权限设置的也会比较严格,特别是一些很重要的(配置)文件或目录。
如
-r--r----- bluetooth bluetooth 935 2010-07-09 20:21 dbus.conf drwxrwx--x system system 2010-07-07 02:05 data
dbus.conf好像是蓝牙的配置文件,从权限上来看,根本就不可能改动,非bluetooth用户连读的权利都没有。
/data目录下存的是全部程序的私有数据,默认状况下android是不容许普通apk访问/data目录下内容的,经过data目录的权限设置可知,其余用户没有读的权限。
因此adb普通权限下在data目录下敲ls命令,会获得opendir failed, Permission denied的错误,经过代码file.listfiles()也没法得到data目录下的内容。
上面两种状况,通常都须要提高apk的权限,目前我所知的apk能提高到的权限就是system(具体方法见:如何使Android应用程序获取系统权限),
1.通常权限的添加
通常状况下,设定apk的权限,可在AndroidManifest.xml中添加android:sharedUserId="android.uid.xxx>
例如: 给apk添加system权限
<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... ... android:sharedUserId="android.uid.system">
同时还须要在对应的Android.mk中添加LOCAL_CERTIFICATE := platform这一项。即用系统的签名,经过这种方式只能使apk的权限升级到system级别,系统中要求root权限才能访问的文件,apk仍是不能访问。
好比在android 的API中有提供 SystemClock.setCurrentTimeMillis()函数来修改系统时间,这个函数须要root权限或者运行于系统进程中才能够用。
第一个方法简单点,不过须要在Android系统源码的环境下用make来编译:
1. 在应用程序的AndroidManifest.xml中的manifest节点中加入android:sharedUserId="android.uid.system"这个属性。
2. 修改Android.mk文件,加入LOCAL_CERTIFICATE := platform这一行
3. 使用mm命令来编译,生成的apk就有修改系统时间的权限了。
第二个方法是直接把eclipse编出来的apk用系统的签名文件签名
1. 加入android:sharedUserId="android.uid.system"这个属性。
2. 使用eclipse编译出apk文件。
3. 使用目标系统的platform密钥来从新给apk文件签名。首先找到密钥文件,在android源码目录中的位置是"build/target/product/security",
下面的platform.pk8和platform.x509.pem两个文件。而后用Android提供的Signapk工具来签名,signapk的源代码是在"build/tools/signapk"下,
编译后在out/host/linux-x86/framework下,用法为java -jar signapk.jar platform.x509.pem platform.pk8 input.apk output.apk"。
加入android:sharedUserId="android.uid.system"这个属性。经过Shared User id,拥有同一个User id的多个APK能够配置成运行在同一个进程中。那么把程序的UID配成android.uid.system,也就是要让程序运行在系统进程中,这样就有权限来修改系统时间了。
只是加入UID还不够,若是这时候安装APK的话发现没法安装,提示签名不符,缘由是程序想要运行在系统进程中还要有目标系统的platform key,就是上面第二个方法提到的platform.pk8和platform.x509.pem两个文件。用这两个key签名后apk才真正能够放入系统进程中。第一个方法中加入LOCAL_CERTIFICATE := platform其实就是用这两个key来签名。
这也有一个问题,就是这样生成的程序只有在原始的Android系统或者是本身编译的系统中才能够用,由于这样的系统才能够拿到platform.pk8和platform.x509.pem两个文件。要是别家公司作的Android上连安装都安装不了。试试原始的Android中的key来签名,程序在模拟器上运行OK,不过放到G3上安装直接提示"Package ... has no signatures that match those in shared user android.uid.system",这样也是保护了系统的安全。
---------------------
做者:koozxcv
来源:CSDN
原文:https://blog.csdn.net/koozxcv/article/details/50835601