Android中常用权限列表

由于自己在做的项目的关系,把Android平台中权限的中文对应整理了一下。现发布于此以方便有需要的人。

精准的 (GPS) 位置|ACCESS_FINE_LOCATION
(基于网络的)粗略位置|ACCESS_COARSE_LOCATION
完全的互联网访问权限|INTERNET
修改/删除 USB 存储设备的内容修改/删除 SD 卡的内容|WRITE_EXTERNAL_STORAGE
阻止设备进入休眠状态|WAKE_LOCK
查看 Wi-Fi 状态|ACCESS_WIFI_STATE
查看网络状态|ACCESS_NETWORK_STATE
设置壁纸|SET_WALLPAPER
拍摄照片和视频|CAMERA
读取手机状态和身份|READ_PHONE_STATE
发现已知帐户|GET_ACCOUNTS
控制振动器|VIBRATE
直接拨打电话号码|CALL_PHONE
发送短信|SEND_SMS
接收短信|RECEIVE_SMS
接收彩信|RECEIVE_MMS
读取短信或彩信|READ_SMS
编辑短信或彩信|WRITE_SMS
读取联系人数据|READ_CONTACTS
写入联系人数据|WRITE_CONTACTS
更改网络连接|CHANGE_NETWORK_STATE
修改全局系统设置|WRITE_SETTINGS
停用键锁|DISABLE_KEYGUARD
检索正在运行的应用程序|GET_TASKS
开机时自动启动|RECEIVE_BOOT_COMPLETED
终止后台进程|KILL_BACKGROUND_PROCESSES
重启程序|RESTART_PACKAGES
发送置顶广播消息|BROADCAST_STICKY
安装 DRM 内容。|INSTALL_DRM
读取日历活动|READ_CALENDAR
控制闪光灯|FLASHLIGHT
使用帐户的身份验证凭据|USE_CREDENTIALS
管理帐户列表|MANAGE_ACCOUNTS
录音|RECORD_AUDIO
更改您的音频设置|MODIFY_AUDIO_SETTINGS
读取同步设置|READ_SYNC_SETTINGS
写入同步设置|WRITE_SYNC_SETTINGS
更改 Wi-Fi 状态|CHANGE_WIFI_STATE
写入订阅的供稿|SUBSCRIBED_FEEDS_WRITE
读取订阅的供稿|SUBSCRIBED_FEEDS_READ
读取同步统计信息|READ_SYNC_STATS
作为帐户身份验证程序|AUTHENTICATE_ACCOUNTS
作为 AccountManagerService|ACCOUNT_MANAGER
创建蓝牙连接|BLUETOOTH
蓝牙管理|BLUETOOTH_ADMIN
显示系统级警报|SYSTEM_ALERT_WINDOW
访问登记属性|ACCESS_CHECKIN_PROPERTIES
访问额外的位置信息提供程序命令|ACCESS_LOCATION_EXTRA_COMMANDS
用于测试的模拟位置源|ACCESS_MOCK_LOCATION
访问 SurfaceFlinger|ACCESS_SURFACE_FLINGER
修改电池统计信息|BATTERY_STATS
选择窗口小部件|BIND_APPWIDGET
与设备管理器交互|BIND_DEVICE_ADMIN
绑定至输入法|BIND_INPUT_METHOD
绑定到壁纸|BIND_WALLPAPER
永久停用手机|BRICK
发送包删除的广播|BROADCAST_PACKAGE_REMOVED
发送可通过短信接收的广播消息|BROADCAST_SMS
发送 WAP 一键接收广播消息|BROADCAST_WAP_PUSH
直接拨打任何电话号码|CALL_PRIVILEGED
启用或停用应用程序组件|CHANGE_COMPONENT_ENABLED_STATE
更改用户界面设置|CHANGE_CONFIGURATION
允许接收 Wi-Fi 多播消息|CHANGE_WIFI_MULTICAST_STATE
删除所有应用程序缓存数据|CLEAR_APP_CACHE
删除其他应用程序的数据|CLEAR_APP_USER_DATA
控制位置更新通知|CONTROL_LOCATION_UPDATES
删除其他应用程序的缓存|DELETE_CACHE_FILES
删除应用程序|DELETE_PACKAGES
设备开机或关机|DEVICE_POWER
读取/写入诊断所拥有的资源|DIAGNOSTIC
检索系统内部状态|DUMP
展开/收拢状态栏|EXPAND_STATUS_BAR
在出厂测试模式下运行|FACTORY_TEST
强制应用程序关闭|FORCE_BACK
计算应用程序存储空间|GET_PACKAGE_SIZE
全局搜索|GLOBAL_SEARCH
测试硬件|HARDWARE_TEST
按键和控制按钮|INJECT_EVENTS
允许安装位置信息提供程序|INSTALL_LOCATION_PROVIDER
直接安装应用程序|INSTALL_PACKAGES
显示未授权的窗口|INTERNAL_SYSTEM_WINDOW
管理应用程序令牌|MANAGE_APP_TOKENS
恢复出厂设置|MASTER_CLEAR
修改手机状态|MODIFY_PHONE_STATE
格式化外部存储设备|MOUNT_FORMAT_FILESYSTEMS
装载和卸载文件系统|MOUNT_UNMOUNT_FILESYSTEMS
控制近距离通信|NFC
让应用程序始终运行|PERSISTENT_ACTIVITY
拦截外拨电话|PROCESS_OUTGOING_CALLS
读取帧缓冲区|READ_FRAME_BUFFER
记录您键入的内容和执行的操作|READ_INPUT_STATE
查阅敏感日志数据|READ_LOGS
强行重新启动设备|REBOOT
接收 WAP|RECEIVE_WAP_PUSH
对正在运行的应用程序重新排序|REORDER_TASKS
监控所有应用程序的启动|SET_ACTIVITY_WATCHER
在闹钟中设置警报|SET_ALARM
关闭所有后台应用程序|SET_ALWAYS_FINISH
修改全局动画速度|SET_ANIMATION_SCALE
启用应用程序调试|SET_DEBUG_APP
更改屏幕显示方向|SET_ORIENTATION
设置首选应用程序|SET_PREFERRED_APPLICATIONS
限制运行的进程个数|SET_PROCESS_LIMIT
设置时间|SET_TIME
设置时区|SET_TIME_ZONE
设置有关壁纸大小的提示|SET_WALLPAPER_HINTS
向应用程序发送 Linux 信号|SIGNAL_PERSISTENT_PROCESSES
停用或修改状态栏|STATUS_BAR
更新设备状态|UPDATE_DEVICE_STATS
拨打/接听互联网通话|USE_SIP
编写“接入点名称”设置|WRITE_APN_SETTINGS
添加或修改日历活动以及向邀请对象发送电子邮件|WRITE_CALENDAR
修改 Google 地图|WRITE_GSERVICES
修改安全系统设置|WRITE_SECURE_SETTINGS
修改全局系统设置|WRITE_SETTINGS
发送下载通知。|SEND_DOWNLOAD_COMPLETED_INTENTS
部分关闭|SHUTDOWN
读取浏览器的历史记录和书签|READ_HISTORY_BOOKMARKS
写入浏览器的历史记录和书签|WRITE_HISTORY_BOOKMARKS
写入用户定义的词典|WRITE_USER_DICTIONARY
强行停止其他应用程序|FORCE_STOP_PACKAGES
更新组件使用情况统计信息|PACKAGE_USAGE_STATS
移动应用程序资源|MOVE_PACKAGE
访问下载管理器。|ACCESS_DOWNLOAD_MANAGER
写入用户定义的词典|READ_USER_DICTIONARY

安全性和许可

Android是一个权限分离(privilege-separated)的操作系统,其中的每一个运行的程序有一个单独的系统识别(identity)(Linux 用户ID及组ID)。此外系统的不同部分也被分入了不同的识别。通过这种方式Linux使不同的程序和系统之间相互独立。

其他的高级安全特性也由一种称为“权限”的机制所提供,它强行规定了一个进程可以执行哪些特定操作,同时URI级别的权限(per-URI permission)担保了对于特定数据片段的ad-hoc访问。

安全构架

Android安全构架的一个中心设计要点就是默认来说没有程序有进行任何可能对其他程序、操作系统或是用户产生负面影响的任何操作的许可(permission)。这包括了读写用户私人数据(例如通讯录或是电子邮件),读写其他程序的文件,执行网络接入或保持设备不进入睡眠状态等。

因为内核将程序通过沙盒分离,所以程序必须显式地共享资源及数据。它们通过声明许可来获取它们所需的没有通过基本沙盒提供的额外功能。程序静态地声明它们所需的许可,Android系统将在程序安装时向用户征求许可。Android没有动态(在运行时)担保许可的机制,因为这将使安全性受损,使得用户体验变糟。

只有内核负责将程序通过沙盒与其他程序分离。尤其要注意Dalvik VM以及任何可以运行原生代码(native code)的程序(参见Android NDK)并不是安全边界。所有类型的程序——Java,原生(native)或是混合(hybrid)——都以同样方式被沙盒化,相互之间拥有相同的级别的安全性。

应用程序签名

所有的Android应用程序(.apk文件)必须用一个开发者拥有其私钥的认证(certificate)来进行签名。该认证用于识别应用程序的权限。一个认证不需要由认证权威来进行签名:Android程序完全可以,而且通常也会,使用自签名的认证。Android的认证的目的是为了识别应用程序作者。这使得系统可以允许或是拒绝程序获取签名级别(signature-level)的许可以及程序希望获取“相同作者程序”的Linux识别的请求。

用户ID与文件读取

在安装时,Android分给每一个包(package)一个独自的Linux用户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文件中包含一个或更多的<uses-permission>标签来申明程序所需的许可。

例如,一个需要监视收到的短信的程序应该指定:

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

在程序安装时,基于用户对声明了许可和/或交互的程序签名的检查,包安装器(package installer)将会认可程序所请求的许可。在程序运行时不会进行任何检查:要么在安装时许可被允许而可以如所希望的那样使用该特性,要么许可不被认可,任何使用该特性的操作将不经过用户判断而直接拒绝。

通常许可错误会导致一个SecurityException被抛回程序。然而,这也不是在所有情况下都会发生的事。例如,sendBroadcast(Intent)方法会在方法调用被返回之后检查数据被传递至每一个接收者的许可,因此即使有许可错误,也不会收到异常。不过,在绝大多数情况下,许可失败都将会被打印于系统日志上。

Android系统所提供的许可可以在Manifest.permission中找到。任何程序也可以定义并执行其自有许可,因此那并非是所有可用许可的完整列表。

一个特定的许可可以在程序执行时被执行于多个地方:

  • 在系统执行一个调用时,阻止应用程序执行某一功能。
  • 在启动一个活动时,阻止应用程序启动属于其他程序的活动。
  • 在发送和接收广播时,控制广播的接收方和发送方。
  • 在读取并操作内容提供者时。
  • 在绑定或启动一个服务时。

声明并执行许可

要执行自有许可,就必须首先在AndroidManifest.xml中通过一个或多个<permission>标签来声明它们。

例如,如果一个程序希望可以控制谁能启动它的活动,它可以像这样为这个操作声明一个许可:

<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>属性是可选的,仅仅被用来帮助系统向用户显示该许可。通常会对一个标准系统组(standard system group)(列于android.Manifest.permission_group)或在某些特殊情况下对自己定义的系统组设置该属性。推荐使用一个已有的组,以简化向用户显示的许可界面。

注意必须同时向许可提供标签(label)和描述(description)。它们是用户在查看一列许可(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>

可以通过shell指令adb shell pm list permissions来查看当前系统中所定义的许可。一般来说,’-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>标签)限制了谁可以启动相关的活动。该许可在Context.startActivity()和Activity.startActivityForResult()的过程中会被检查;如果调用者没有所需的许可,该调用将抛出SecurityException。

Service许可(应用于<service>标签)限制了谁可以启动或是绑定相关的活动。该许可在Context.startService()、Context.stopService()和Context.bindService()的过程中会被检查;如果调用者没有所需的许可,该调用将抛出SecurityException。

BroadcastReceiver许可(应用于<receiver>标签)限制了谁可以向关联的接收者发送广播。该许可在Context.sendBroadcast()返回后系统试图向给定接收者传递所请求的广播时被检查。因此,许可错误不会向调用者抛出例外;它只是不会传递该意图。同样地,该许可可以用于Context.registerReceiver()控制谁可以向一个在代码中注册的接收者发送广播。另一方面,该许可也可以用于在调用Context.sendBroadcast()时限制哪一个BroadcastReceiver对象可以被允许接收广播(见下文)。

ContentProvider许可(应用于<provider>标签)限制了谁可以读取内容提供者内的数据。(内容提供者拥有一项重要的额外安全机制,允许它们调用URI许可。这将在之后说明。)和其他组件不同,内容提供者可以设置两个不同的属性:android:readPermission限制了谁可以读取该提供者,而android:writePermission限制了谁可以进行写操作。注意,如果一个提供者同时被读和写许可所保护,仅持有写许可并不意味着就可以读取提供者的内容。许可将在第一次检索一个提供者时和对提供者执行操作时被检查(如果没有持有任何一个许可,则将会抛出一个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许可

在使用内容提供者时,至今所描述的标准许可系统常常是不足以胜任的。内容提供者可能需要读写许可以保护自己,同时它的直接客户端也需要处理其他程序的特殊URI以供执行操作。典型的例子是邮件程序中的附件。应当通过许可来保护对邮件的访问,因为这是用户敏感数据。不过,如果一个指向图像附件的URI被交给了图像查看器,该查看器将不会有打开附件的许可,因为它没有理由持有访问所有电子邮件的许可。

这个问题的解决方案是单URI许可(per-URI permission):当启动一个活动或是向一个活动返回结果时,调用者可以设置Intent.FLAG_GRANT_READ_URI_PERMISSION和/或Intent.FLAG_GRANT_WRITE_URI_PERMISSION。这将许可接收方访问Intent内的指定数据URI,而不论它是否拥有任何访问和Intent相对应的内容提供者中数据的许可。

这一机制使得常见的能力-风格模型(capability-style model)得以实现,用户交互操作(打开附件,从列表中选择联系人等)可以创建临时的细化许可权限。这是减少程序所需许可至仅有和其行为直接相关许可的工具。

然而,对细化URI许可的授权也需要一些拥有那些URI的内容提供者的配合。强烈建议内容提供者应用这一工具,通过android:grantUriPermissions属性或是<grant-uri-permissions>标签来声明它们支持这一特性。

更为详细的信息可以在Context.grantUriPermission()、Context.revokeUriPermission()和Context.checkUriPermission()方法中找到。

本作品采用知识共享 署名-非商业性使用-禁止演绎 3.0 Unported许可协议进行许可。