[Android Pro] android 4.4 Android原生权限管理:AppOps

 reference : http://m.blog.csdn.net/blog/langzxz/45308199

 reference : http://blog.csdn.net/hyhyl1990/article/details/46842915

 Android原生是有应用程序权限管理的,即是AppOps,只是Google把它默认隐藏了。

本文对AppOps机制做一简要的分析和描述。

1.     AppOps 简介

      AppOps全称是 Application Operations,类似我们平时常说的应用程序的操作(权限)管理。AppOps是Google原生Android包含的功能,但是Google在每次版本更新时都会隐藏掉AppOps的入口。

     在今年的Google IO大会上,Google透露Android M ( Android 6.0 )会加入Application Permission Manage的功能,该功能应该就是基于AppOps实现的。

    注意:AppOps虽然涵盖了 App的权限管理,但是Google原生的设计并不仅仅是对“权限”的管理,而是对App的“动作”的管理。我们平时讲的权限管理多是针对具体的权限(App开发者在Manifest里申请的权限),而AppOps所管理的是所有可能涉及用户隐私和安全的操作,包括 access notification, keep weak lock,  activate vpn, display toast 等等,有些操作是不需要Manifest里申请权限的。

2.      功能效果

Setting UI:

AppOps的权限设置是在系统的Settings App里, Settings -> Security -> AppOps.

点击某一app,可以查看该app的权限管理详情

 

3.     AppOps总体概览

核心服务:  AppOpsService

系统服务,系统启动时该服务会启动运行。

参考以下ActivityManagerService.java,ActivityManagerService启动过程中:

配置文件:appops.xml  appops_policy.xml

Appops.xml位于 /data/system/目录下,存储各个app的权限设置和操作信息。

Appops_policy.xml位于 /system/etc/目录下,该文件只在appops strict mode enable时才会存在和使用。(根据源码的描述是这样的,还没有具体分析内容)

API接口: AppOpsManager

AppOpsService实现了大部分的核心功能逻辑,但它不能被其他模块直接调用访问,而是通过AppOpsManager提供访问接口。

 

UI层:AppOpsSummary,AppOpsCategory等

上传UI显示以及基本逻辑处理。

4.      结构图

AppOps整体的工作框架基本如下:

 

 

 

 

Setting UI通过AppOpsManager与AppOpsService 交互,给用户提供入口管理各个app的操作。

AppOpsService具体处理用户的各项设置,用户的设置项存储在 /data/system/appops.xml文件中。

AppOpsService也会被注入到各个相关的系统服务中,进行权限操作的检验。

各个权限操作对应的系统服务(比如定位相关的Location Service,Audio相关的Audio Service等)中注入AppOpsService的判断。如果用户做了相应的设置,那么这些系统服务就要做出相应的处理。

(比如,LocationManagerSerivce的定位相关接口在实现时,会有判断调用该接口的app是否被用户设置成禁止该操作,如果有该设置,就不会继续进行定位。)

 

5.      相关API接口

尽管在Android SDK里能够看到部分AppOps的API接口,但是Google对此解释的很清楚:

This API is not generally intended for third party application developers; most features are only available to system applications. Obtain an instance of it throughContext.getSystemService withContext.APP_OPS_SERVICE.

 

即是说,这些API不是让第三方app使用的,而是供系统应用调用的。

使用Android SDK开发应用,如果要调用这些api的话,也会编译不通过。

但是想使用的话,可以尝试把Android源码里 AppOpsManager.java打包一下,把jar包导入自己的工程,就可以使用了。

部分重要的API接口如下:

 int checkOp(String op, int uid, String packageName)

 Op对应一个权限操作,该接口来检测应用是否具有该项操作权限。

 int noteOp(String op, int uid, String packageName)

 和checkOp基本相同,但是在检验后会做记录。

 int checkOpNoThrow(String op, int uid, String packageName)

 

 和checkOp类似,但是权限错误,不会抛出SecurityException,而是返回AppOpsManager.MODE_ERRORED.

  intnoteOpNoThrow(String op, int uid, String packageName)

 

  类似noteOp,但不会抛出SecurityException。

 

  void setMode ( int code, int uid, String packageName, int mode)

  这个是我们最需要的方法,改变app的权限设置,但偏偏被google隐藏了。

  code代表具体的操作权限, mode代表要更改成的类型(允许 /禁止 / 提示)

 

正常情况下(如果OEM厂商没有做特殊处理),把AppOpsManager.java打包,引入jar包到工程内,是可以使用上述API接口的,

也即是可以自行设计UI,提供入口来改变app权限。

 

具体权限对应的code,可以查看AppOpsManager.java源码里的描述

 

AppOpsManager 是在是在Android 4.4版本支持的 (api 19)。获得他实例的方法是

Context.getSystemService(Context.APP_OPS_SERVICE)

APP_OPS_SERVICE 的值是 “appops”
AppOpsManager类里有一函数 int checkOp(String op, int uid, String packageName)

public int checkOp(String op, int uid, String packageName) {
     return checkOp(strOpToOp(op), uid, packageName);
}
public static int strOpToOp(String op) {
     Integer val = sOpStrToOp.get(op);
     if (val == null) {
         throw new IllegalArgumentException("Unknown operation string: " + op);
     }
     return val;
}  

功能就是快速检测某个应用是否具有某些权限,看上面的源码可知道最终调用了下面的代码

public int checkOp(int op, int uid, String packageName) {
     try {
          int mode = mService.checkOperation(op, uid, packageName);
          if (mode == MODE_ERRORED) {
             throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
          }
          return mode;
      } catch (RemoteException e) {
      }
      return MODE_IGNORED;
}

op 的值是 0 ~ 47,其中0代表粗略定位权限,1代表精确定位权限,24代表悬浮窗权限。
   uid 当前应用用到的uid ,可通过 Binder.getCallingUid()获得。
   packageName 应用程序的包名,通过getPackageName获得。

通过上面的知识,写一函数 用来判断 程序是否具有某些权限的函数

private static int checkOp(Context context, int op){
        final int version = Build.VERSION.SDK_INT;
        if (version >= 19){
            Object object = context.getSystemService("appops");
            Class c = object.getClass();
            try {          
                Class[] cArg = new Class[3];
                cArg[0] = int.class;
                cArg[1] = int.class;
                cArg[2] = String.class;
                Method lMethod = c.getDeclaredMethod("checkOp", cArg);
                return (Integer) lMethod.invoke(object, op, Binder.getCallingUid(), context.getPackageName());
            } catch(NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }        
        }
        return -1;
    }

调用上面的函数,返回 0 就代表有权限,1代表没有权限,-1函数出错啦


posted @ 2015-12-01 12:11  demoblog  阅读(2293)  评论(0编辑  收藏  举报