专栏名称: 郭霖
Android技术分享平台,每天都有优质技术文章推送。你还可以向公众号投稿,将自己总结的技术心得分享给大家。
目录
相关文章推荐
开发者全社区  ·  裸辞1天 vs 裸辞10天 vs 裸辞30天 ·  21 小时前  
开发者全社区  ·  梁文锋的流量密码 ·  昨天  
开发者全社区  ·  86岁范大师北大携35岁新夫人公开露面 ·  2 天前  
开发者全社区  ·  章泽天那个时候好嫩啊! ·  3 天前  
51好读  ›  专栏  ›  郭霖

Android M一一WRITE_SETTINGS权限的一个BUG

郭霖  · 公众号  · android  · 2016-11-28 08:00

正文

今日科技快讯

近日,京东对外发布“京东物流”品牌标识,正式宣布京东物流将以品牌化运营的方式全面对社会商家开放。京东物流将向社会开放三大服务体系,即仓配一体化的供应链服务、京东快递服务和京东物流云服务。对消费者来说,未来,无论在京东第三方商家还是其它购物平台购物,都能享受到与京东自营物流同等服务。

作者简介

又是新的一周,又跟大家见面啦!今天带来 Epeius 投稿 ,不同于以往的技术分享,本篇算是“找茬”的文章,具体是什么BUG,还不知道的朋友赶快看看吧~

Epeius 的博客地址:

http://www.jianshu.com/users/b955c1cec2f9

运行时权限

Android 6.0,代号 Marshmallow,自发布伊始,其主要的特征运行时权限就很受关注。因为这一特征不仅改善了用户对于应用的使用体验,还使得应用开发者在实践开发中需要做出改变。

Android中有很多权限,但并非所有的权限都是敏感权限,于是6.0系统就对权限进行了分类,一般为下述几类:

  • 正常(Normal Protection)权限

  • 危险(Dangerous)权限

  • 特殊(Particular)权限

  • 其他权限(一般很少用到)

危险权限实际上才是运行时权限主要处理的对象,这些权限可能引起隐私问题或者影响其他程序运行。Android 6.0发布这么久了,各大厂商也基本已经发布更新,很多应用也都已经适配到 targetSdk23,相信大家对运行时权限都已经有所了解,这里就不多说了。

Android 6.0中,除了危险权限不再在安装后授予,还有两个特殊权限: SYSTEM_ALERT_WINDOW (设置悬浮窗,进行一些黑科技)和 WRITE_SETTINGS (修改系统设置)。这里我们只关注WRITE_SETTINGS权限。

WRITE_SETTINGS

首先看下API文档是怎么说的:

Note:

If the app targets API level 23 or higher, the app user must explicitly grant this permission to the app through a permission management screen.

The app requests the user's approval by sending an intent with action ACTION_MANAGE_WRITE_SETTINGS .

The app can check whether it has this authorization by calling Settings.System.canWrite() .

也就是说,关于 WRITE_SETTINGS 权限的授权,做法是使用 startActivityForResult ,启动系统设置的授权界面来完成。我们来看看示例代码如何来请求 WRITE_SETTINGS 权限


上述代码需要注意的是:

  • 使用Action Settings.ACTION_MANAGE_WRITE_SETTINGS启动隐式Intent

  • 使用"package:" + getPackageName()携带App的包名信息

  • 使用Settings.System.canWrite方法检测授权结果

关于WRITE_SETTINGS权限,比较少应用会用到,一般也不建议应用申请,不然Android M也不会设立这道障碍,比危险权限的申请还要复杂。

但是,偏偏有应用要申请。不过还真是要感谢这个应用,不然我们也不会这么顺利就发现了这个BUG。

BUG现场

如下图。MM商场安装完成后启动,然后就跳到这个界面申请 允许修改系统设置 。这时候理论上是没有这个权限的,但是弹出来的界面却显示已经打开了 允许修改系统设置 这个开关;不做任何更改退出这个界面,MM商场会重复跳转到这个申请界面;这说明MM商场也检测到自己并没有被授予 WRITE_SETTINGS 权限。

到底有没有,我们来一看究竟。首先查看系统内已安装的三方应用:

adb shell pm list package -3

找到MM商场的包名,dump一下应用信息:

adb shell dumpsys package com.aspire.mm

如图:

targetSdk

requested permissions

runtime permissions

可以看到:

  • MM商店的targetSdk=23;

  • requested permissions下面有 WRITE_SETTINGS 权限;

  • 但是install permissions和runtime permissions下面并没有找到 WRITE_SETTINGS 权限。

说明MM商店应用还没有被授予此权限,那为什么申请此权限时弹出的界面显示,switch开关状态是开着的呢?很明显这是一个bug!

为了验证这个想法,我们来看看源码。

源码里面有真相

从WRITE_SETTINGS的API Reference里我们可以看到:

The app can check whether it has this authorization by calling Settings.System.canWrite() .

应用是通过 Settings.System.canWrite() .来判断自己是否已经被授予了该权限。我们找到源码,开启顺藤摸瓜模式:

这里会调用 AppOpsManager.checkOpNoThrow 获取当前的ops状态,继续跟踪下去:

最终,这里拿到的是 OP_WRITE_SETTINGS 的默认状态 MODE_DEFAULT

但此时应用的 WRITE_SETTINGS 权限也没有授予, canWrite 当然返回的是 false 了。

这样就说明应用自身判断是否具有 WRITE_SETTINGS 权限的逻辑是没错的,那就是说很可能是Settings App里面可修改系统设置界面的switch开关状态是错误的,我们继续看源码。

抽丝剥茧,找到根源

之前我们已经知道,应用是通过使用 Settings.ACTION_MANAGE_WRITE_SETTINGS 来启动的设置界面,我们从这里入手,找到这个设置界面的代码。我们在源码全局搜索这个action:

最终指向的都是 WriteSettingsDetails.java ,找到switch开关初始化的地方:

这里我们注意到,调用了super的 getPermissionInfo 方法:

再看for循环里面的这段:

这时候传入的 mPermissions 到底是什么呢?看 AppStateAppOpsBridge 的构造函数:

前面我们知道, AppStateWriteSettingsBridge 继承自 AppStateAppOpsBridge

我就纳闷了,这个类名写得清清楚楚, AppStateWriteSettingsBridge ,跟 CHANGE_NETWORK_STATE 有半毛钱关系呀?这里很明显是个疑点。我们再看看 getPermissionInfo 里面的逻辑:

如果 doseAnyPermissionMatch 这个条件命中了, permissionState . staticPermissionGranted 就设为 true ,然后就直接 break 跳出循环了!

等等!如果这个应用同时申请了 CHANGE_NETWORK_STATE WRITE_SETTINGS 权限,并且 CHANGE_NETWORK_STATE 的权限安装后就会授予,那这里的判断就出问题了,就会跳过 WRITE_SETTINGS 的判断,直接将 permissionState.staticPermissionGranted 设为 true







请到「今天看啥」查看全文


推荐文章
开发者全社区  ·  裸辞1天 vs 裸辞10天 vs 裸辞30天
21 小时前
开发者全社区  ·  梁文锋的流量密码
昨天
开发者全社区  ·  86岁范大师北大携35岁新夫人公开露面
2 天前
开发者全社区  ·  章泽天那个时候好嫩啊!
3 天前