Android权限管理

本篇文章来自网上的很多文章,留着备份,日后整理。
 
Android的权限系统是基于Linux,但又增加了很多自己的控制模块。
总体上来说,其分为以下几部分权限系统:
1. userid : 继承于linux,对于多个app,通过shareuid的方式可以使用同一个userid,主要承担一些目录访问权限之类的工作,比如私有目录只能由同一uid应用访问
2. 安装level:system level or app level,这个是根据应用的安装位置决定的,在system/app下安装的应用就是system level,在权限访问中会得到更多的权限,比如静默安装应用的权限等
3. permission : 这个是最主要的权限控制,一般开发者开发应用主要是接触这个部分,在这部分中,会根据应用在AndroidManifest.xml中声明的use-permission而在访问相应api或资源时判断其是否有访问权限,比如常用的android.permission.INTERNET等
4. signature: 签名,是Android权限系统中的重要组成部分,对于系统签名的应用,会有一些特殊的功能,而shareuid等特性也是需要同一签名作为基础。此外,permission在设置/自定义其权限时也经常会使用到签名,比如控制只有我自己的应用才可以访问我自己定义的公开api
除此以外,其实Android在uid的里面设置了一些预定义有特殊功能的uid,比如system/media等,在配置其system level的services的时候会用到。
 
 
安装在设备中的每一个apk文件,Android给每个APK进程分配一个单独的用户空间,其manifest中的userid就是对应一个Linux用户都会被分配到一个属于自己的统一的Linux用户ID,并且为它创建一个沙箱,以防止影响其他应用程序(或者其他应用程序影响它)。用户ID 在应用程序安装到设备中时被分配,并且在这个设备中保持它的永久性。

通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中.所以默认就是可以互相访问任意数据. 也可以配置成运行成不同的进程, 同时可以访问其他APK的数据目录下的数据库和文件.就像访问本程序的数据一样.

对于一个APK来说,如果要使用某个共享UID的话,必须做三步:

1、在Manifest节点中增加android:sharedUserId属性。

2、在Android.mk中增加LOCAL_CERTIFICATE的定义。

如果增加了上面的属性但没有定义与之对应的LOCAL_CERTIFICATE的话,APK是安装不上去的。提示错误是:Package com.test.MyTest has no signatures that match those in shared user android.uid.system; ignoring!也就是说,仅有相同签名和相同sharedUserID标签的两个应用程序签名都会被分配相同的用户ID。例如所有和media/download相关的APK都使用android.media作为sharedUserId的话,那么它们必须有相同的签名media。

3、把APK的源码放到packages/apps/目录下,用mm进行编译。

举例说明一下。

系统中所有使用android.uid.system作为共享UID的APK,都会首先在manifest节点中增加android:sharedUserId="android.uid.system",然后在Android.mk中增加LOCAL_CERTIFICATE := platform。可以参见Settings等

系统中所有使用android.uid.shared作为共享UID的APK,都会在manifest节点中增加android:sharedUserId="android.uid.shared",然后在Android.mk中增加LOCAL_CERTIFICATE := shared。可以参见Launcher等

系统中所有使用android.media作为共享UID的APK,都会在manifest节点中增加android:sharedUserId="android.media",然后在Android.mk中增加LOCAL_CERTIFICATE := media。可以参见Gallery等。

另外,应用创建的任何文件都会被赋予应用的用户标识,并且正常情况下不能被其他包访问。当通过getSharedPreferences(String,int)、openFileOutput(String、int)或者openOrCreate Database(String、int、SQLiteDatabase.CursorFactory)创建一个新文件时,开发者可以同时或分别使用MODE_WORLD_READABLE和MODE_WORLD_RITEABLE标志允许其他包读/写此文件。当设置了这些标志后,这个文件仍然属于自己的应用程序,但是它的全局读/写和读/写权限已经设置,所以其他任何应用程序可以看到它。

关于签名:

build/target/product/security目录中有四组默认签名供Android.mk在编译APK使用:

1、testkey:普通APK,默认情况下使用。

2、platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。

3、shared:该APK需要和home/contacts进程共享数据。

4、media:该APK是media/download系统中的一环。

应用程序的Android.mk中有一个LOCAL_CERTIFICATE字段,由它指定用哪个key签名,未指定的默认用testkey.

 

 

对于使用eclipse编译的apk,可以使用signapk.jar来手动进行签名,其源码在build/tools/signapk下,编译后在out/host/linux-x86/framework/signapk.jar,也可以从网上下载。使用方法,以platform为例:java -jar ./signapk platform.x509.pem platform.pk8 input.apk output.apk  (platform.x509.pem platform.pk8在build/target/product/security获取)

 

我们经常在一个activity中去start另一个activity,或者与另一个acitivity的结果进行交互(startActivityForResult)。但有没有想过可能会出现的permission问题呢?如果你遇到了permission denial的Exception,那么你需要读读这篇文章啦。

         我们在同一个application内部,可以随意的startActivity from Activity A to Activity B,而官方的文档中说startActivity可能会报NotFoundException,表示被start的Activity不存在。因此,我们很容易忽略另一个可能的Exception,Permission Denial。

          当我们在不同的application中,如application A中的Activity去start一个application B中的Activity,也许你什么Exception都不会得到,也可能会直接Force Close掉。因为再Start Activity时,代码是有去检验permission的。

        如下情况,可以成功startActivity而不会得到permission denial

1、同一个application下

2、Uid相同

3、permission匹配

4、目标Activity的属性Android:exported=”true”

5、目标Activity具有相应的IntentFilter,存在Action动作或其他过滤器并且没有设置exported=false

6、启动者的Pid是一个System Server的Pid

7、启动者的Uid是一个System Uid(Android规定android.system.uid=1000,具有该Uid的application,我们称之为获得Root权限)

          如果上述调节,满足一条,一般即可(与其他几条不发生强制设置冲突),否则,将会得到Permission Denial的Exception而导致Force Close。

         现在,我来解释一下Uid机制

        众所周知,Pid是进程ID,Uid是用户ID,只是Android和计算机不一样,计算机每个用户都具有一个Uid,哪个用户start的程序,这个程序的Uid就是那个那个用户,而Android中每个程序都有一个Uid,默认情况下,Android会给每个程序分配一个普通级别互不相同的 Uid,如果用互相调用,只能是Uid相同才行,这就使得共享数据具有了一定安全性,每个软件之间是不能随意获得数据的。而同一个application 只有一个Uid,所以application下的Activity之间不存在访问权限的问题。

       如果你需要做一个application,将某些服务service,provider或者activity等的数据,共享出来怎么办,三个办法。

      1、完全暴露,这就是android:exported=”true”的作用,而一旦设置了intentFilter之后,exported就默认被设置为true了,除非再强制设为false。当然,对那些没有intentFilter的程序体,它的exported属性默认仍然是false,也就不能共享出去。

      2、权限提示暴露,这就是为什么经常要设置usePermission的原因,如果人家设置了 android:permission=”xxx.xxx.xx”那么,你就必须在你的application的Manufest中 usepermission xxx.xxx.xx才能访问人家的东西。

      3、私有暴露,假如说一个公司做了两个产品,只想这两个产品之间可互相调用,那么这个时候就必须使用shareUserID将两个软件的Uid强制设置为一样的。这种情况下必须使用具有该公司签名的签名文档才能,如果使用一个系统自带软件的ShareUID,例如Contact,那么无须第三方签名。

      这种方式保护了第三方软件公司的利益于数据安全。

      当然如果一个activity是又system process跑出来的,那么它就可以横行霸道,任意权限,只是你无法开发一个第三方application具有系统的Pid(系统Pid不固定),但是你完全可以开发一个具有系统Uid的程序,对系统中的所有程序任意访问,只需再Manufest中声明shareUserId为 android.system.uid即可,生成的文件也必须经过高权限签名才行,一般不具备这种审核条件的application,google不会提供给你这样的签名文件。当然你是在编译自己的系统的话,想把它作成系统软件程序,只需在Android.mk中声明 Certificate:platform则可以了,既采用系统签名。这个系统Uid的获得过程,我们把它叫做获得Root权限的过程。所以很多第三方系统管理软件就是有Root权限的软件,因为他需要对系统有任意访问的权限。那么它的Root签名则需要和编译的系统一致,例如官方的系统得用官方的签名文件,CM的系统就得用CM的签名文件

 

Android 的权限分类

根据用户的使用过程体验,可以将 Android 涉及的权限大致分为如下三类:

(1)Android 手机所有者权限:自用户购买 Android 手机后,用户不需要输入任何密码,就具有安装一般应用软件、使用应用程序等的权限;

(2)Android root 权限:该权限为 Android 系统的最高权限,可以对所有系统中文件、数据进行任意操作。出厂时默认没有该权限,需要使用 z4Root 等软件进行获取,然而,并不鼓励进行此操作,因为可能由此使用户失去手机原厂保修的权益。同样,如果将 Android 手机进行 root 权限提升,则此后用户不需要输入任何密码,都将能以 Android root 权限来使用手机。

(3)Android 应用程序权限:Android 提供了丰富的 SDK(Software development kit),开发人员可以根据其开发 Android 中的应用程序。而应用程序对 Android 系统资源的访问需要有相应的访问权限,这个权限就称为 Android 应用程序权限,它在应用程序设计时设定,在 Android 系统中初次安装时即生效。值得注意的是:如果应用程序设计的权限大于 Android 手机所有者权限,则该应用程序无法运行。如:没有获取 Android root 权限的手机无法运行 Root Explorer,因为运行该应用程序需要 Android root 权限。


Android 系统权限定义

Android 系统在 /system/core/private/android_filesystem_config.h 头文件中对 Android 用户 / 用户组作了如下定义,且权限均基于该用户 / 用户组设置。

 #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_INPUT         1004  /* input devices */ 
 #define AID_AUDIO         1005  /* audio devices */ 
 #define AID_CAMERA        1006  /* camera devices */ 
 #define AID_LOG           1007  /* log devices */ 
 #define AID_COMPASS       1008  /* compass device */ 
 #define AID_MOUNT         1009  /* mountd socket */ 
 #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 */ 
 #define AID_VPN           1016  /*  system */ 
 #define AID_KEYSTORE      1017  /* keystore subsystem */ 
 #define AID_USB           1018  /* USB devices */ 
 #define AID_DRM           1019  /* DRM server */ 
 #define AID_DRMIO         1020  /* DRM IO server */ 
 #define AID_GPS           1021  /* GPS daemon */ 
 #define AID_NFC           1022  /* nfc subsystem */ 

 #define AID_SHELL         2000  /* adb and debug shell user */ 
 #define AID_CACHE         2001  /* cache access */ 
 #define AID_DIAG          2002  /* access to diagnostic resources */ 

 /* The 3000 series are intended for use as supplemental group id's only. 
  * They indicate special Android capabilities that the kernel is aware of. */ 
 #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_MISC          9998  /* access to misc storage */ 
 #define AID_NOBODY        9999 

 #define AID_APP          10000 /* first app user */

值得注意的是:每个应用程序在安装到 Android 系统后,系统都会为其分配一个用户 ID,如 app_4、app_11 等。以下是 Calendar 和 Terminal 软件在 Android 系统中进程浏览的结果(其中,黑色字体标明的即为应用分配的用户 ID):

 USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME 
 app_16    2855  2363  216196 20960 ffffffff afd0ee48 S com.android.providers.calendar 
 app_91    4178  2363  218872 25076 ffffffff afd0ee48 S jackpal.androidterm

在 Android 系统中,上述用户 / 用户组对文件的访问遵循 Linux 系统的访问控制原则,即根据长度为 10 个字符的权限控制符来决定用户 / 用户组对文件的访问权限。该控制符的格式遵循下列规则:

  • 第 1 个字符:表示一种特殊的文件类型。其中字符可为 d( 表示该文件是一个目录 )、b( 表示该文件是一个系统设备,使用块输入 / 输出与外界交互,通常为一个磁盘 )、c( 表示该文件是一个系统设备,使用连续的字符输入 / 输出与外界交互,如串口和声音设备 ),“.”表示该文件是一个普通文件,没有特殊属性。
  • 2 ~ 4 个字符:用来确定文件的用户 (user) 权限;
  • 5 ~ 7 个字符:用来确定文件的组 (group) 权限;
  • 8 ~ 10 个字符:用来确定文件的其它用户 (other user,既不是文件所有者,也不是组成员的用户 ) 的权限。
  • 第 2、5、8 个字符是用来控制文件的读权限的,该位字符为 r 表示允许用户、组成员或其它人可从该文件中读取数据。短线“-”则表示不允许该成员读取数据。
  • 第 3、6、9 位的字符控制文件的写权限,该位若为 w 表示允许写,若为“-”表示不允许写。
  • 第 4、7、10 位的字符用来控制文件的制造权限,该位若为 x 表示允许执行,若为“-”表示不允许执行。

举个例子,“drwxrwxr--  2 root   root    4096  2 月 11 10:36 lu”表示的访问控制权限(黑色字体标明)为:因为 lu 的第 1 个位置的字符是 d,所以由此知道 lu 是一个目录。第 2 至 4 位置上的属性是 rwx,表示用户 root 拥有权限列表显示 lu 中所有的文件、创建新文件或者删除 lu 中现有的文件,或者将 lu 作为当前工作目录。第 5 至 7 个位置上的权限是 rwx,表示 root 组的成员拥有和 root 一样的权限。第 8 至 10 位上的权限仅是 r--,表示不是 root 的用户及不属于 root 组的成员只有对 lu 目录列表的权限。这些用户不能创建或者删除 lu 中的文件、执行 junk 中的可执行文件,或者将 junk 作为他们的当前工作目录。


Android 应用程序权限申请

每个应用程序的 APK 包里面都包含有一个 AndroidMainifest.xml 文件,该文件除了罗列应用程序运行时库、运行依赖关系等之外,还会详细地罗列出该应用程序所需的系统访问。程序员在进行应用软件开发时,需要通过设置该文件的 uses-permission 字段来显式地向 Android 系统申请访问权限。

AndroidMainifest.xml 文件用途

AndroidManifest.xml 主要包含以下功能:

  1. 说明 application 的 java 数据包,数据包名是 application 的唯一标识;
  2. 描述 application 的 component;
  3. 说明 application 的 component 运行在哪个 process 下;
  4. 声明 application 所必须具备的权限,用以访问受保护的部分 API,以及与其他 application 的交互;
  5. 声明 application 其他的必备权限,用以 component 之间的交互;
  6. 列举 application 运行时需要的环境配置信息,这些声明信息只在程序开发和测试时存在,发布前将被删除;
  7. 声明 application 所需要的 Android API 的最低版本级别,例如 1.0,1.1,1.5;
  8. 列举 application 所需要链接的库;

AndroidManifest.xml 文件的结构及元素

AndroidManifest.xml 文件的结构、元素,以及元素的属性,可以在 Android SDK 文档中查看详细说明。而在看这些众多的元素以及元素的属性前,需要先了解一下这些元素在命名、结构等方面的规则:

  1. 元素:在所有的元素中只有 是必需的,且只能出现一次。如果一个元素包含有其他子元素,必须通过子元素的属性来设置其值。处于同一层次的元素,这些元素的说明是没有顺序的。
  2. 属性:按照常理,所有的属性都是可选的,但是有些属性是必须设置的。那些真正可选的属性,即使不存在,其也有默认的数值项说明。除了根元素 的属性,所有其他元素属性的名字都是以 android: 前缀的;
  3. 定义类名:所有的元素名都对应其在 SDK 中的类名,如果你自己定义类名,必须包含类的数据包名,如果类与 application 处于同一数据包中,可以直接简写为“.”;
  4. 多数值项:如果某个元素有超过一个数值,这个元素必须通过重复的方式来说明其某个属性具有多个数值项,且不能将多个数值项一次性说明在一个属性中;
  5. 资源项说明:当需要引用某个资源时,其采用如下格式:@[package:]type:name。例如
  6. 字符串值:类似于其他语言,如果字符中包含有字符“\”,则必须使用转义字符“\\”;

下面结合 cookie 实例中的 AndroidManifest.xml 文件来说明一下,原 XML 文件如下:

  
  
  
  
  
  
  
  
  
  
  
 

除了头部的 XML 信息说明外,首先是 manifest 项(也就是根节点),其属性包括:schemas URL 地址、包名(moandroid.cookie),以及程序的版本说明。其次是 manifest 的子节点 application,其属性包括:程序图标、程序名称。前面带有 @ 表示引用资源,例如:@drawable/icon 表示引用的是 drawable 资源中的 icon,可以在其源工程的 res/drawable 中找到。然后就是 application 的子节点 activity,其属性包括:activity 的名称、activity 的标签名,其子节点 intent-filter 则是对 activity 的说明。

而在 intent-filter 中,action android:name=”android.intent.action.MAIN”和 category android:name=”android.intent.category.LAUNCHER”用以说明程序启动时的入口 activity 是哪个。如果这两个属性值中分别含有 MAIN 和 LAUNCHER,则说明它就是启动程序时的入口活动。uses-sdk android:minSdkVersion=”3 ″说明程序使用的 Android SDK 的最低版本,其中 1 表示 Android 1.0,2 表示 Android 1.1,而 3 则表示 Android 1.5。

如何进行应用程序权限申请

如下所示,文中黑体标记的部分为应用程序权限申请内容:

  
  
    
        
             
                 
                 
             
         
    
 
 

如上述文件描述中加下划线的斜体部分,该文件的作用是说明该软件需要发送短信的功能。

Android 定义了百余种 permission,可供开发人员使用,具体详见网址:http://developers.androidcn.com/reference/android/Manifest.permission.html。

在文件中,用户还可以自定义权限。permission 就是自定义权限的声明,可以用来限制 app 中特殊组件,特性与 app 内部或者和其他 app 之间访问。写了一个引用自定义权限的例子,在安装 app 的时候,提示权限:

定义权限如下:

 

声明的含义如下;

android:label:权限名字,显示给用户的,值可是一个 string 数据,例如这里的“自定义权限”。

android:description:比 label 更长的对权限的描述。值是通过 resource 文件中获取的,不能直接写 string 值,例如这里的”@string/test”。

android:name:权限名字,如果其他 app 引用该权限需要填写这个名字。

android:protectionLevel:权限级别,分为 4 个级别:

  • normal:低风险权限,在安装的时候,系统会自动授予权限给 application。
  • dangerous:高风险权限,系统不会自动授予权限给 app,在用到的时候,会给用户提示。
  • signature:签名权限,在其他 app 引用声明的权限的时候,需要保证两个 app 的签名一致。这样系统就会自动授予权限给第三方 app,而不提示给用户。
  • signatureOrSystem:这个权限是引用该权限的 app 需要有和系统同样的签名才能授予的权限,一般不推荐使用。

值得注意的是:通过测试发现一种特殊的情况,应用程序可以在程序运行时申请 root 权限,如下图,在使用 Android Terminal Emulator 时尝试使用 su 命令切换到 root 用户。若用户已通过 hacking 的方式使得 Android 系统获得了 root 权限,则可以允许该程序以 root 用户权限执行;反之即算用户选择“允许”,也不能使程序以 root 用户权限执行。

图 3. Android 用户权限赋予示意图
图 3. Android 用户权限赋予示意图

Android 系统对应用程序权限申请的处理方式分析

对 Android 源代码中的如下文件进行分析:

  • InstallAppProgress.java:其路径为 \packages\apps\PackageInstaller\src\com\android\packageinstaller\InstallAppProgress.java;
  • PackageInstallerActivity.java:其路径为 \packages\apps\PackageInstaller\src\com\android\packageinstaller\PackageInstallerActivity.java;
  • AppSecurityPermissions.java:其路径为 \frameworks\base\core\java\android\widget\AppSecurityPermissions.java

总结得出如下图所示的 Android 系统对应用程序授权申请的处理流程:

  • 进入处理应用程序授权申请的入口函数;
  • 系统从被安装应用程序的 AndroidManifest.xml 文件中获取该应用正常运行需申请的权限列表;
  • 显示对话框,请求用户确认是否满足这些权限需求;
  • 若同意,则应用程序正常安装,并被赋予相应的权限;若否定,则应用程序不被安装。系统仅提供给用户选择“是”或者“否”的权利,没有选择其中某些权限进行授权的权利。
图 4. Android 用户权限赋予示意图
图 4. Android 用户权限赋予示意图
 
 

一. 权限(permission)

权限用来描述是否拥有做某件事的权力。Android系统中权限分为普通级别(Normal),危险级别(dangerous),签名级别(signature)和系统/签名级别(signature or system)。系统中所有预定义的权限根据作用的不同,分别属于不同的级别。
对于普通和危险级别的权限,我们称之为低级权限,应用申请即授予。其他两级权限,我们称之为高级权限或系统权限,应用拥有platform级别的认证才能申请。当应用试图在没有权限的情况下做受限操作,应用将被系统杀掉以警示。
系统应用可以使用任何权限。权限的声明者可无条件使用该权限。
目前Android系统定义了许多权限,通过SDK文档用户可以查询到哪些操作需要哪些权限,然后按需申请。
为了执行你自己的权限,你必须首先在你的AndroidManifest.xml中使用一个或多个 标签声明。例如,一个应用程序想用控制谁能启动一个activities,它可以为声明一个做这个操作的许可,如下:


二 .使用权限

应用需要的权限应当在users-permission属性中申请,所申请的权限应当被系统或某个应用所定义,否则视为无效申请。同时,使用权限的申请需要遵循权限授予条件,非platform认证的应用无法申请高级权限。

所以,程序间访问权限大致分为两种:
 第一种低级点的(permission的protectlevel属性为normal或者dangerous),其调用者apk只需声明即可拥有其permission。
 第二种高级点的(permission的protectlevel属性为signature或者signatureorsystem),其调用者apk就需要和被调用的apk一样拥有相同的signature。


应用程序安装的时候,应用程序请求的permissions是通过package installer来批准获取的。package installer是通过检查该应用程序的签名来确定是否给予该程序request的权限。在用户使用过程中不会去检查权限,也就是说要么在安装的时候就批准该权限,使其按照设计可以使用该权限;要么就不批准,这样用户也就根本无法使用该feature,也不会有任何提示告知用户尝试失败。
例如高级权限用有system级别权限设定的api时,需要使其apk拥有system权限。比如在 android 的API中有供给SystemClock.setCurrentTimeMillis()函数来修改系统时间。有两个方法:

第一个方法简单点,不过需要在Android系统源码的情况下用make来编译:
1. 在应用程序的AndroidManifest.xml中的manifest节点中插手android:sharedUserId="android.uid.system"这个属性。
2. 修改Android.mk文件,插手LOCAL_CERTIFICATE := platform这一行
3. 使用mm命令来编译,生成的apk就有修改系统时间的职权范围了

第2个方法麻烦点,不外不消开虚拟机跑到源码情况下用make来编译:
1. 同上,插手android:sharedUserId="android.uid.system"这个属性。
2. 使用eclipse编译出apk文件,但是这个apk文件是不能用的。
3. 使用针系统的platform密码钥匙来从头给apk文件签名。signapk platform.x509.pem platform.pk8 input.apk output.apk


三. 自定义Permission

Android系统定义的权限可以在Manifest.permission中找到。任何一个程序都可以定义并强制执行自己独有的permissions,因此Manifest.permission中定义的permissions并不是一个完整的列表(即能有自定义的permissions)。
一个特定的permission可能会在程序操作的很多地方都被强制实施:
 当系统有来电的时候,用以阻止程序执行其它功能。
 当启动一个activity的时候,会阻止应用程序启动其它应用的Acitivity。
在发送和接收广播的时候,去控制谁可以接收你的广播或谁可以发送广播给你。
 当进入并操作一个content provider的时候。
当绑定或开始一个service的时候。


四.组件权限

通过 AndroidManifest.xml 文件可以设置高级权限,以限制访问系统的所有组件或者使用应用程序。所有的这些请求都包含在你所需要的组件中的 android:permission属性,命名这个权限可以控制访问此组件。
1. Activity 权限 (使用 标签) 限制能够启动与 Activity 权限相关联的组件或应用程序。在 Context.startActivity() 和 Activity.startActivityForResult() 期间检查;
2.Service 权限(应用 标签)限制启动、绑定或启动和绑定关联服务的组件或应用程序。此权限在 Context.startService(), Context.stopService() 和 Context.bindService() 期间要经过检查;
3. BroadcastReceiver 权限(应用 标签)限制能够为相关联的接收者发送广播的组件或应用程序。在 Context.sendBroadcast() 返回后此权限将被检查,同时系统设法将广播递送至相关接收者。因此,权限失败将会导致抛回给调用者一个异常;它将不能递送到目的地。在相同方式下,可以使 Context.registerReceiver() 支持一个权限,使其控制能够递送广播至已登记节目接收者的组件或应用程序。其它的,当调用 Context.sendBroadcast() 以限制能够被允许接收广播的广播接收者对象一个权限(见下文)。
4. ContentProvider 权限(使用 标签)用于限制能够访问 ContentProvider 中的数据的组件或应用程序。
如果调用者没有请求权限,那么会为调用抛出一个安全异常( SecurityException )。在所有这些情况下,一个SecurityException异常从一个调用者那里抛出时不会存储请求权限结果。


五. 发送广播时支持权限

当发送一个广播时你能总指定一个请求权限,此权限除了权限执行外,其它能发送Intent到一个已注册的BroadcastReceiver的权限均可以。通过调用Context.sendBroadcast()及一些权限字符串,为了接收你的广播,你请求一个接收器应用程序必须持有那个权限。注意,接收者和广播者都能够请求一个权限。当这样的事发生了,对于Intent来说,这两个权限检查都必须通过,为了交付到共同的目的地。


六. 其它权限支持

在调用service的过程中可以设置任意的fine-grained permissions(更为细化的权限)。这是通过Context.checkCallingPermission()方法来完成的。使用一个想得到的permission string来进行呼叫,然后当该权限获批的时候可以返回给呼叫方一个Integer(没有获批也会返回一个Integer)。需要注意的是这种情况只能发生在来自另一个进程的呼叫,通常是一个service发布的IDL接口或者是其他方式提供给其他的进程。
Android提供了很多其他的方式用于检查permissions。如果你有另一个进程的pid,你就可以通过Context的方法Context.checkPermission(String, int, int)去针对那个pid去检查permission。如果你有另一个应用程序的package name,你可以直接用PackageManager的方法 PackageManager.checkPermission(String, String) 来确定该package是否已经拥有了相应的权限。


七. URI权限


到目前为止我们讨论的标准的permission系统对于content provider来说是不够的。一个content provider可能想保护它的读写权限,而同时与它对应的直属客户端也需要将特定的URI传递给其它应用程序,以便其它应用程序对该URI进行操作。一个典型的例子就是邮件程序处理带有附件的邮件。进入邮件需要使用permission来保护,因为这些是敏感的用户数据。然而,如果有一个指向图片附件的URI需要传递给图片浏览器,那个图片浏览器是不会有访问附件的权利的,因为他不可能拥有所有的邮件的访问权限。
针对这个问题的解决方案就是per-URI permission:当启动一个activity或者给一个activity返回结果的时候,呼叫方可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION . 这会使接收该intent的activity获取到进入该Intent指定的URI的权限,而不论它是否有权限进入该intent对应的content provider。


这种机制允许一个通常的capability-style模型,这种模型是以用户交互(如打开一个附件, 从列表中选择一个联系人)为驱动,特别获取fine-grained permissions(更细粒化的权限)。这是一种减少不必要权限的重要方式,这种方式主要针对的就是那些和程序的行为直接相关的权限。
这些URI permission的获取需要content provider(包含那些URI)的配合。强烈推荐在content provider中提供这种能力,并通过android:grantUriPermissions或者标签来声明支持。


八. 小结

1.拥有signature的权限是否可以不用声明就能access带normal或dangerous权限设定的数据或功能?

只要signature相同,就算不显式声明也能access设定了normal或dangerous权限设定的数据或功能。


2.若需要system级别权限使用系统api(即使用system级别的签名),如何同时使用其他signature权限设定(即使用signature级别的签名)的其他apk的功能?
拥有system级别权限的使用者可以access其他普通signature权限声明设定过的功能。
所以,设定为拥有system级别权限即可。
 

你可能感兴趣的:(Android)