注:本文是根据Android 5.0的代码为基础
Appops是Application Operations的简称,是关于应用权限管理的一套方案,但这里的应用指的是系统应用,这些API不对第三方应用开放。Google从4.3开始推出Appops, 但一直到最新的Android N都没有在Settings里面开放Appops的入口,但这套方案却一直在后台默默的运行着。
<Preference android:key="manage_device_admin"
android:title="@string/manage_device_admin"
android:summary="@string/manage_device_admin_summary"
android:persistent="false" />
+ <Preference android:key="app_ops_summary"
+ android:title="@string/app_ops_settings"
+ android:summary="@string/app_ops_settings_summary"
+ android:persistent="false"/>
添加相应处理代码
在./packages/apps/Settings/src/com/android/settings/SecuritySettings.java的onPreferenceTreeClick方法中添加相应的处理函数即可。此处就不贴具体代码了。
/frameworks/base/core/java/android/app/AppOpsManager.java
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
* allowed to perform the given operation.
*/
public static final int MODE_ALLOWED = 0;
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller is
* not allowed to perform the given operation, and this attempt should
* silently fail (it should not cause the app to crash).
*/
public static final int MODE_IGNORED = 1;
/**
* Result from {@link #checkOpNoThrow}, {@link #noteOpNoThrow}, {@link #startOpNoThrow}: the
* given caller is not allowed to perform the given operation, and this attempt should
* cause it to have a fatal error, typically a {@link SecurityException}.
*/
public static final int MODE_ERRORED = 2;
/**
* Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}: the given caller should
* use its default security check. This mode is not normally used; it should only be used
* with appop permissions, and callers must explicitly check for it and deal with it.
*/
public static final int MODE_DEFAULT = 3;
/**
* @hide Result from {@link #checkOp}, {@link #noteOp}, {@link #startOp}:
* AppOps Service should show a dialog box on screen to get user
* permission.
*/
public static final int MODE_ASK = 4;
可以看到Appops的两个重要组成部分是AppOpsManager和AppOpsService,它们是典型的客户端和服务端设计,通过Binder跨进程调用。
AppOpsManager提供标准的API供APP调用,但google有明确说明,大部分只针对系统应用。
/frameworks/base/core/java/android/app/AppOpsManager.java
/**
* API for interacting with "application operation" tracking.
*
* This API is not generally intended for third party application developers; most
* features are only available to system applications. Obtain an instance of it through
* {@link Context#getSystemService(String) Context.getSystemService} with
* {@link Context#APP_OPS_SERVICE Context.APP_OPS_SERVICE}.
*/
public class AppOpsManager {
AppOpsService是做最终检查的系统服务,它的注册名字是appops, 应用可以类似于
mAppOps=(AppOpsManager)getContext().getSystemService(Context.APP_OPS_SERVICE);的方式来获取这个服务。
当用户想要改变(比如禁止)某个应用的某个权限,通过AppOpsDetails.java调用AppOpsManager的setMode方法,进而调用AppOpsService的setMode方法,最后会把修改的值记录到/data/system/appops.xml中.
比如,当在Settings中禁掉Gallery的Camera权限,Appops会把记录 (26就是代表的Camera权限,1代表禁止)记录到appops.xml文件中,各种权限对应的值在AppOpsManager.java中查看
/frameworks/base/core/java/android/app/AppOpsManager.java
/** @hide */
public static final int OP_SYSTEM_ALERT_WINDOW = 24;
/** @hide */
public static final int OP_ACCESS_NOTIFICATIONS = 25;
/** @hide */
public static final int OP_CAMERA = 26;
appops.xml中gallery相关的值前后变化如下
当应用需要去检查某个权限的时候,会调用checkOp或者noteOp去读取/data/system/appops.xml里面对应的值。
接口在AppOpsManager.java中,但大部分只针对系统应用。
public int checkOp(String op, int uid, String packageName)
检查某个应用(packageName)是否具有某个权限(op)
public int checkOpNoThrow(String op, int uid, String packageName)
同checkOp,但出错不会报异常,返回MODE_ERRORED
public int noteOp(String op, int uid, String packageName)
检查某个应用(packageName)是否具有某个权限(op),同时会做记录
public int noteOpNoThrow(String op, int uid, String packageName)
同checkOp,但出错不会报异常,返回MODE_ERRORED
/* @hide /
public void setMode(int code, int uid, String packageName, int mode)
设置权限,code是权限的标识码,比如OP_READ_CONTACTS, mode是权限的状态,比如MODE_ALLOWED.
Android提供了命令行的方式来更改某个应用的某个权限,进入adb shell可以查看相应用法:
root@ myPhone:/ # appops
usage: adb shell appops set <PACKAGE> <OP> <allow|ignore|deny|default> [--user <USER_ID>]
<PACKAGE> an Android package name.
<OP> an AppOps operation.
<USER_ID> the user id under which the package is installed. If --user is not
specified, the current user is assumed.
我们在3.2举的例子就是一个佐证,当禁掉Gallery的Camera的权限以后,在appops.xml里面也修改了相应的记录,但是当进入Gallery以后,还是可以拍照。
这里启动camera并没有走appops的流程,而是直接发送intent去启动 Camera.
对于那些控制生效的情况,给用户的提示简直就是五花八门,有的就直接没有提示,比如禁掉dialer的READ_CONTACT权限,当进入Dialer查看联系人时,直接是显示没有联系人。
又比如当禁止掉Camera的Camera权限,当启动Camera的时候,直接提示错误,让一般用户不知所以然。
Appops从Android 4.3就已经在后台运行,一直到即将推出的Android N也没有在Settings中打开入口,可以看出,这套方案并不是非常成熟。当然,整体的设计还是非常出色,值得我们借鉴。