• Android权限机制(三) 针对权限控制如何设计App


    随着Android 5.0的到来,原生的权限管理控制功能AppOps终于登场(虽然4.3的代码中已经包含)。

    它的使用路径是Settings -> Security -> AppOps(有些厂商的ROM可能依然屏蔽着,或名字被修改)

    AppOps引进的一个新概念"Ops",也就是"Operations"操作。
    之前的第三方应用(如LBE)和手机厂商ROM(三星、MIUI),都实现了类似功能,但强调的是permission权限。
    而在AppOps中,ops操作是映射到permission的(一般是1:1,但不是所有op都有对应的permission)
    (见AppOpsManager.java的sOpToSwitch和sOpPerms数组)

    在经历了工信部新版本的入网信息安全标准,以及各大运营商越来越详细的安全功能要求之后,
    像AppOps这种权限/操作控制功能(以及更底层的SELinux/SEAndroid)将会是标配。
    所以,我们来了解一下,开发者如何针对这些控制,设计开发出稳定的App。

    1. 假定app用到的权限会被禁用
    开发过程中,当调用到需要权限的API时候,一定要考虑两个问题:“这个API调用一定会成功吗?”“如果调用失败该怎么处理?”
    权限控制的方法有很多,比如《Android权限机制(二) 权限控制的设计》中提到的,通过让checkPermission()返回false,这会导致Framework层抛出SecurityException。
    所以要try/catch来处理,防止App因此crash。

    ContentResolver resolver = getContentResolver();
    try {
    	Cursor cur = resolver.query( 
    			ContactsContract.Contacts.CONTENT_URI, 
    			null, 
    			null, 
    			null, 
    			ContactsContract.Contacts.DISPLAY_NAME 
    					+ " COLLATE LOCALIZED ASC");
    } catch (SecurityException e) {
    	Log.e("query", "permission denied");
    }


    另外一种控制方法就如AppOps、CyanogenMod或XPosed,在调用此类API的时候返回空/假数据,所以调用完API要检查得到的结果是否有效。

    LocationManager lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
    
    boolean isNetworkEnabled = lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    Log.i("test", "isNetworkEnabled = " + isNetworkEnabled);
    
    if (isNetworkEnabled) {
    	Location location = lm.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
    	Log.i("test", "location = " + location);
    }
    //权限被阻拦的log:
    20:09:45.985: I/test(30816): isNetworkEnabled = true
    20:09:45.985: I/test(30816): location = null
    //权限不被阻拦的log:
    20:12:07.955: I/test(31132): isNetworkEnabled = true
    20:12:07.955: I/test(31132): location = Location[network *,* acc=104 et=+46m11s701ms]


    2. 减少不必要的权限申请
    权限的控制,其实就是涉及到的就是manifest中申请的权限,以及运行中调用需要权限的API。
    可能有人会问,不申请这些权限,怎么达到我想要的功能?
    其实有很多种方法,比如参考《你的Android应用完全不需要那么多的权限》。把需要权限的操作交给系统app去做,是个稳妥的选择。
    更有创意的,参考最近知乎一条很有意思的提问,《搜狗号码通 lite 是如何在不越狱的情况下判定骚扰电话的?》。绕开权限控制的方法有很多。

    3. 其他的权限控制方法
    比如"android.permission.INTERNET"之类的底层权限,并不是在调用API做的检查,而是通过将进程添加进inet用户组来达到允许联网的效果。(/system/netd/include/Permisson.h, /system/netd/server/NetworkController.cpp)。
    这就是为什么没有添加这个权限,在Java或NDK下都联网失败的原因。

    还有就是在4.3引入,在4.4中强制打开的SELinux/SEAndroid。

    虽然SELinux在桌面Linux上被很多人吐槽,但是在服务器和Android中,却运行得很好。
    简单来说,移植到Android的SELinux(SEAndroid)是在Linux userspace和kernel共同完成的MAC控制的安全功能,
    它可以由管理员/手机厂商的push来配置sepolicy(安全策略)。
    常见的由SELinux阻拦导致的错误可以是open()的时候被permission denied。这往往是尝试打开某些系统目录下文件导致的。

    总结
    在编写App(包括NDK)的时候,一定要有权限被禁用的意识,多考虑可能因此发生的情况。
    此外,要知道不同手机厂商ROM对于权限控制功能的实现以及对于sepolicy的配置不尽相同。
    有可能这个手机上运行成功,那个手机上就出错了。
    因此,多买些手机,多换几个版本,做详尽的测试吧!

  • 相关阅读:
    通道的理解
    系统安装-老毛桃
    ppt文字变图形
    关于android出现不能下载相关依赖包,解决办法
    关于字体图标的问题
    初始化小程序的第一个问题
    css盒子垂直居中的5种方式
    关于网页图标的引用--bootstrap4和ElementUI
    安装vue-cli缓慢问题
    基于SSM在线考试系统的核心功能,随机组卷的实现
  • 原文地址:https://www.cnblogs.com/jacobchen/p/4148762.html
Copyright © 2020-2023  润新知