Android开发-API指南-系统权限

时间:2022-09-30 10:21:47

System Permissions

英文原文:http://developer.android.com/guide/topics/security/permissions.html

采集日期:2014-5-7
搬迁自原博客:http://blog.sina.com.cn/s/blog_48d491300101hcbh.html

Android 是权限隔离的操作系统,每个应用程序都以唯一的系统标识符(Linux 用户 ID 和组 ID)运行。
系统的某些部分也由唯一的标识符相分隔。 因此,Linux 可以将应用程序相互隔离,也与系统隔离。

更精细的安全措施则由“权限”机制来提供,这种机制可以对某个进程可执行的特定操作进行限制, 以及由 URI
前缀机制对点对点访问某部分数据进行授权。

本文描述了开发人员使用 Android 安全特性的方法。 更为宏观的 Android
安全性概述
在 Android Open Source Project 中给出描述。

安全架构


设计 Android 安全架构时有一条核心思想,就是默认情况下所有应用程序都无权执行妨碍其他应用程序、操作系统或用户的任何操作。
这些操作包括:读写用户私有数据(比如通讯录或 email)、读写其他应用程序的文件、访问网络、保持设备唤醒状态等等。

因为每个 Android 应用程序都是在各自的进程沙盒中运行,所以必须公开需共享的资源和数据。
为了获得这些不由基本沙盒提供的额外功能,需通过声明所需的permissions来实现。
应用程序首先要静态声明所需的权限,然后 Android 系统会在安装时交由用户许可。 Android
不提供动态授权机制(运行时授权),因为这会让用户体验变得更复杂,不利于系统的安全。

应用程序沙盒不依赖于任何编译应用程序所用到的技术。 特别是 Dalvik VM
的边界并不安全,任何应用程序都可以运行本地原生(native)代码(参阅 Android NDK)。
所有的应用程序— Java、原生或混合代码 — 都以同样的方式运行于沙盒中,每个程序的安全等级都是同等的。

应用程序签名


所有的 APK (.apk 文件)都必须经由某个证书签名。
该证书的私钥由开发者持有,标识了应用程序的作者。
证书需要经过认证机构签发,它拥有完全许可,典型的用途是用于应用程序自身签名认证。 使用 Android
证书的目的是为了区分应用程序的作者。 利用证书,系统可以允许或拒绝应用程序访问 签名级别的权限
申请与其他应用程序相同的
Linux ID

用户 ID 和文件访问


在安装时, Android 会为每个程序包分配一个唯一的 Linux 用户 ID 。 在当前设备该程序包的生存期内,这个 ID
维持不变。 在不同的设备上,同一个包可能会拥有不同的 UID,但重要的是每个设备上的包 UID 都是唯一的。

因为安全限制是在进程级别生效的,而两个包的 Linux 用户是不同的,所以两个包的代码通常无论如何都不会运行于同一个进程中。
你可以在每个包的 AndroidManifest.xml 中的 manifest 标签内应用 sharedUserId 属性,给这些包赋予同样的用户 ID。
这样,在安全层面这些包被视为同一个应用程序,拥有同样的用户 ID 和文件访问权限。
请记住,为了保证安全性,仅当两个应用程序签名相同时(且申请同样的 sharedUserId )才会被赋予相同的用户ID。

应用程序保存的所有数据都会被赋予自身的用户 ID,通常是不允许其他程序包来访问的。 当通过 getSharedPreferences(String, int)openFileOutput(String, int)openOrCreateDatabase(String, int,
SQLiteDatabase.CursorFactory)
新建文件时,你都可以用 MODE_WORLD_READABLE 和/或 MODE_WORLD_WRITEABLE 标记来允许其他程序包对该文件的读写。
设置了这两个标记之后,该文件的拥有者仍然是你的应用程序,但它被设为全局读写权限,也就可以被所有其他应用程序访问。

使用权限


基本的 Android 应用程序默认是没有任何权限的。 这就是说,它不能做任何妨碍用户体验的事,也不能访问设备上的任何数据。
为了使用受保护的设备功能,你必须在AndroidManifest.xml中包含一个或多个
标签,以便声明所需的权限。

例如,如果应用程序需要监视 SMS 短信的接收,就应该指定:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.RECEIVE_SMS" />
...
</manifest>

在安装时,根据对程序签名的检查情况和用户对所声明权限的反馈,安装工具将会把申请的权限授予应用程序。 在应用程序运行时,不会再要求用户对权限进行校验。 要么是在安装时已被赋予某个权限,应用程序可以按照预期使用相应的功能; 要么就是没有被授权,使用这些功能时就会直接失败,且不会给用户任何提示。

通常授权失败会导致向应用程序抛出 SecurityException。 但是这并不是每次都会发生。比如,在向每个接收器分发数据时 sendBroadcast(Intent) 方法会检查权限,但这时调用已经返回了,因此你就无法收到授权失败的异常。 不过,几乎所有情况下,授权失败都会记入系统日志。

正常情况下(比如从 Google Play Store 安装应用程序时),只要用户不同意任一权限请求,应用程序就不会安装。 因此,通常你不必担心授权不足导致的运行失败,因为只要安装成功就表示应用程序已经获得了足够的授权。

Android 系统可提供的权限都在 Manifest.permission 中给出了。 应用程序还可以定义并启用自定义的权限,因此这份清单无法列举所有的权限。

权限控制可以在程序运行过程中的很多场合生效:

  • 执行系统调用时,阻止应用程序执行某些操作。
  • 启动 Activity 时,阻止应用程序打开其他应用程序的 Activity。
  • 发送和接收广播时,控制谁可接收你的广播,或谁可向你发送广播。
  • 访问和操作 Content Provider 时。
  • 绑定或启动服务时。

提醒: 随着时间的推移,系统可能会对某些 API 的使用新增一些限制,你的应用程序必须申请一些以前不收限制的权限。 因为已有的应用程序认为这些 API 应是可以*访问的,为了避免在新版本系统中的运行中止, Android 可能会在这些应用程序的 manifest 中加入新权限的申请。 根据 targetSdkVersion 属性值,Android 可以确定应用程序是否可能需要这些新权限。 如果该属性值低于引入某权限时的版本,那么 Android 就会加入这个权限。

例如, WRITE_EXTERNAL_STORAGE 权限是从 API 级别 4 开始加入的,用于访问共享存储。 如果你的 targetSdkVersion 是 3 以下,则在更高版本的 Android 中会把该权限申请加入应用程序中。

请注意,如果执行了权限的添加工作,在 Google Play 中就会显示你的应用程序需要这些权限,即使应用程序实际上不需要用到。

为了避免这一点并去除不需要的默认权限,请把 targetSdkVersion 维持更新为尽可能高的版本。 关于每个版本加入的权限,可以参阅文档 Build.VERSION_CODES

声明和应用权限


为了应用自定义的权限,首先必须在AndroidManifest.xml 中声明 一个或多个 < permission > 标签。

例如,某个应用程序需要对可以启动其 Activity 的对象进行控制,该操作权限的声明可以如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.me.app.myapp" >
<permission android:name="com.me.app.myapp.permission.DEADLY_ACTIVITY"
android:label="@string/permlab_deadlyActivity"
android:description="@string/permdesc_deadlyActivity"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous" />
...
</manifest>

< protectionLevel > 属性是必填项,这会告知系统用户如何获知应用程序需要的权限,或者谁可以拥有这个权限,在链接文档里有详细说明。

< permissionGroup > 属性是可选项,仅用于帮助系统向用户显示该权限。 通常应该将本属性设为标准系统组(在 android.Manifest.permission_group 中列出),设为自定义值的场合较为少见。 最好是使用已有的组,这可以简化权限的用户界面。

请注意,应该同时给出权限的标题和描述部分。 这两部分都是字符串资源,用户查看权限列表时 (android:label) 或者权限详情时 (android:description) 就可以看到。 标题部分应该由简短的几个单词组成,描述该权限要保护的关键功能。 描述部分应该是几句话,描述了权限拥有者可进行的操作。 按照惯例,描述信息包含两句话,第一句描述权限,第二句警示用户获得授权后的应用程序可能会具有的破坏性。

以下是 CALL_PHONE 权限的描述信息举例:

<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the application to call
phone numbers without your intervention. Malicious applications may
cause unexpected calls on your phone bill. Note that this does not
allow the application to call emergency numbers.</string>

通过“设置”应用和命令 adb shell pm list permissions,你可以查看当前系统中已定义的权限。 在Settings > Applications 中可以打开“设置”应用。 选中一个应用程序,打开下拉项可以查看它所用到的权限。 对于开发人员而言,adb '-s' 选项可以用类似用户见到的格式把权限显示出来:

$ adb shell pm list permissions -s
All Permissions: Network communication: view Wi-Fi state, create Bluetooth connections, full
Internet access, view network state Your location: access extra location provider commands, fine (GPS) location,
mock location sources for testing, coarse (network-based) location Services that cost you money: send SMS messages, directly call phone numbers ...

在 AndroidManifest.xml 中应用权限

高级权限可以通过AndroidManifest.xml实现控制,这些权限可以限制对系统级、应用级的全局性组件的访问。 这些权限的请求都包含在相应组件的 android:permission 属性中,访问控制通过权限的名称来识别。

Activity 权限(应用于标签 < activity > )限制了谁可以启动该 Activity。在 Context.startActivity()Activity.startActivityForResult() 时将检查此权限。如果调用者没有请求此权限,则会在调用时抛出 SecurityException

Service 权限(应用于标签 < service > )限制了谁可以启动或绑定该服务。在 Context.startService()Context.stopService()Context.bindService() 时,将会检查此权限。如果调用者没有请求该权限,则会在调用时抛出 SecurityException

BroadcastReceiver 权限(应用于标签 < receiver > )限制了谁可以向该接收器发送广播。在 Context.sendBroadcast() 返回之后,系统会尝试把已提交的广播向给定的接收器分发,这时将会检查此权限。 因此,授权失败会向调用者抛出异常,Intent 也就不会被分发。 同样,可以在 code>Context.registerReceiver() 上应用权限,用于控制谁可以向程序动态注册的接收器发送广播。 再换一种方式,在调用 Context.sendBroadcast() 时也可以应用权限控制,用于限制哪些 BroadcastReceiver 对象可以接收广播(详见下文)。

ContentProvider 权限(应用于标签 < provider > )限制了谁可以访问 ContentProvider 中的数据。(Content Provider 还拥有一个重要的安全特性,叫做URI permissions,这稍后会讨论。) 与其他组件不同,这里可以分别设置两个独立的属性: android:readPermission 限制谁可以从该 Provider 中读取数据,而 android:writePermission 限制谁可以写入数据。 请注意,如果 Provider 同时受到读和写权限的保护,那么拥有写权限并不意味着可以从中读取数据。 首先在获取 Provider 时将会检查该权限(如果两个权限都没有,将会抛出 SecurityException), 在执行读写操作时也会进行检查。使用 ContentResolver.query() 时需要拥有读取权限,使用 ContentResolver.insert()ContentResolver.update()ContentResolver.delete() 时则需要写入权限。 在上述场合,未获得授权将会在调用时抛出 SecurityException

发送广播时应用权限

除了能够限制谁可以向已注册的 BroadcastReceiver 发送 Intent 之外(如上所述),你还可以在发送广播时设定一个权限。 通过在调用 Context.sendBroadcast() 时带入一个权限名称,就可以要求接收器必须拥有该权限才能接收到广播。

请注意,广播的接收者和发送者都可以要求设置权限。 如果两者都设置了权限,则两边的授权都必须通过后 Intent 才能分发成功。

其他权限应用

在调用服务时,可以*实现精细的权限控制,精确到每一次调用。 这是通过 Context.checkCallingPermission() 方法来完成的。 在调用时带入某个权限名称,该方法就会返回一个整数,指明当前进程是否已获得此权限。 请注意,这只适用于执行来自其他进程的调用,通常是通过服务公布的 IDL 接口,或者某些向其他进程提供的途径。

检查权限的途径还有几种。 如果你知道其他进程的 PID,就可以用 Context 方法 Context.checkPermission(String, int, int) 检查基于 PID 的权限。 如果你知道其他应用程序的包名称,就可以直接调用 PackageManager 的 PackageManager.checkPermission(String, String) 方法来确认某个包是否被授予了某个特定权限。

URI 权限


在使用 Content Provider 的时候,前面介绍的标准权限体系往往是不够用的。 Content Provider 可能需要用读写权限来保护自己,而它的客户端程序也需要将某些特定的 URI 传递给其他应用程序以便处理。 典型的例子就是邮件程序中的附件。 邮件是敏感的用户数据,所以对邮件的访问应该收到权限的保护。 如果把某个指向图片附件的 URI 发送给图片浏览程序,图片浏览程序是无权打开这些附件的,因为它没有访问所有 e-mail 的权限。

解决这一问题的办法就是使用 URI 前缀权限:在启动 Activity 或向 Activity 返回结果时,调用者可以设置 Intent.FLAG_GRANT_READ_URI_PERMISSION 和/或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION。 这样就会给接收方 Activity 赋予访问 Intent 里指定 URI 数据的权限,并与是否有权访问 Intent 对应 Content Provider 中的数据无关。

上述机制实现了一种通用的功能性授权模式,即由用户交互操作(打开附件、从通讯录中选择联系人等)驱动的点对点精细授权。 在 Android 平台中,应用程序需要考虑的权限如此之少,恐怕要归功与此,只需要那些与程序行为直接相关的权限就够用了。

不过,精细化的 URI 授权需要对应 Content Provider 的合作才能生效。 强烈建议 Content Provider 实现这种授权功能,并通过 android:grantUriPermissions 属性或 标签进行声明

更多信息请参阅 Context.grantUriPermission()Context.revokeUriPermission()Context.checkUriPermission() 方法。

后续阅读:

隐含了特性需求的权限
某些权限隐含了对设备的特性要求,包括硬件和软件特性。
< uses-permission >
用于声明系统权限需求的 manifest 标签的参考文档。
Manifest.permission
所有系统权限的 API 参考文档。

还可能感兴趣:

设备兼容性
介绍了各种设备上运行的 Android,以及如何针对每种设备优化应用程序、如何根据设备的不同限制应用程序的运行。
Android 安全性概述
详细讨论了 Android 平台的安全模型。

Android开发-API指南-系统权限的更多相关文章

  1. 【最后一篇API译文】Android开发-API指南- Contacts Provider

    Contacts Provider 今年加入了某字幕组,加之杂事颇多,许久未添新文了,惭愧之极. 在听闻 Google 即将重返中国后,近日忽又发现官方网站正在放出 API 中文版,比如本文.当然不是 ...

  2. Android开发-API指南-创建 Content Provider

    Creating a Content Provider 英文原文:http://developer.android.com/guide/topics/providers/content-provide ...

  3. Android开发-API指南-&lt&semi;provider&gt&semi;

    <provider> 英文原文:http://developer.android.com/guide/topics/manifest/provider-element.html 采集(更新 ...

  4. Android开发-API指南-应用程序开发基础

    Application Fundamentals 英文原文:http://developer.android.com/guide/components/fundamentals.html 采集(更新) ...

  5. Android开发-API指南-&lt&semi;uses-sdk&gt&semi;

    <uses-sdk> 英文原文:http://developer.android.com/guide/topics/manifest/uses-sdk-element.html 采集(更新 ...

  6. Android开发-API指南-Intent和Intent过滤器

    Intents and Intent Filters 英文原文:http://developer.android.com/guide/components/intents-filters.html 采 ...

  7. Android开发-API指南-Manifest介绍

    App Manifest 英文原文:http://developer.android.com/guide/topics/manifest/manifest-intro.html 采集(更新)日期:20 ...

  8. Android开发-API指南-设备兼容性

    Device Compatibility 英文原文:http://developer.android.com/guide/practices/compatibility.html 采集日期:2014- ...

  9. Android开发-API指南-Android简介

    Introduction to Android 英文原文:http://developer.android.com/intl/zh-cn/guide/index.html 采集日期:2014-4-16 ...

随机推荐

  1. 【转】【翻译】对响应式SVG的再思考

    来源: http://www.w3ctech.com/topic/1555 原文地址:http://www.smashingmagazine.com/2014/03/rethinking-respon ...

  2. Handler消息机制与Binder IPC机制完全解析

    1.Handler消息机制 序列 文章 0 Android消息机制-Handler(framework篇) 1 Android消息机制-Handler(native篇) 2 Android消息机制-H ...

  3. &lbrack;原&rsqb;如何在Android用FFmpeg&plus;SDL2&period;0解码显示图像

    如何在Android上使用FFmpeg解码图像参考文章[原]如何在Android用FFmpeg解码图像 ,如何在Android上使用SDL2.0来显示图像参考[原]零基础学习SDL开发之在Androi ...

  4. spring中的 classpath&ast; 存在可移植性问题

    classpath* 的可移植性问题,许多人都应该遇到过了.下面就是一个例子(使用的是spring4.1.5和mybatis3.2.8): <bean id="sqlSessionFa ...

  5. POJ 2455Secret Milking Machine(二分&plus;网络流之最大流)

    题目地址:POJ2455 手残真浪费时间啊..又拖到了今天才找出了错误..每晚两道题不知不觉又变回了每晚一道题...sad.. 第一次在isap中忘记调用bfs,第二次则是遍历的时候竟然是从1開始遍历 ...

  6. session校验是否登录

    由于一个网站要有好多页面,如果每个页面都写上检验session是否为空,太麻烦了,所以写个工具类,就方便了. 1首先创建一个类库Common 2,然后在这个类库添加引用 3在Common继承 :Sys ...

  7. 201521123079《Java程序设计》第2周学习总结

    1. 本周学习总结 学会String类和StringBuilder类的一些用法. 学会使用码云管理代码,会将码云上的代码和本地仓库关联 2. 书面作业 Q1.使用Eclipse关联jdk源代码,并查看 ...

  8. 查看linux的进程到底用了多少内存

    1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有    (1). ps aux:      其中  VSZ(或VSS)列 表示,程序占用了多少虚拟内存.          ...

  9. Maven私库安装与配置

    Maven私库安装与配置 https://www.cnblogs.com/dengyulinBlog/p/6398310.html

  10. 一次Win10安装体验

    我下载的是win10 Build 14279版本.http://www.iwin10.com/xiazai/1071.html 下载之后就直接拷到U盘安装了. 安装完之后发现(因为我是分区成了两个)我 ...