前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >论Android适配踩到的坑

论Android适配踩到的坑

作者头像
腾讯移动品质中心TMQ
发布2018-02-02 16:13:45
1.4K0
发布2018-02-02 16:13:45
举报

说起Android适配,恐怕是每一个Android开发/测试工程师心里的痛,且不论Android设备品牌众多、分辨率各异等痛点,单论Android版本的繁多也会提高Android APP的开发/测试成本。如果能了解Android版本之间的变更差异,会让开发/测试事半功倍。本文即是从这个角度出发,给读者带来一点福利。

故事的开始,须先来说说本文的主角:腾讯路宝,是一款驾车导航APP,腾讯MIG地图平台部打造出品的一款为广大驾车用户提供精准导航和路况的产品。

以下故事就是发生在这款APP上的,且等我慢慢叙来:

一、起因

腾讯路宝Android3.0.0版本从灰度测试开始,就有少量用户反馈:

下载离线地图后,默认存储到“手机”,但不能切换到外置存储卡上,提示如下:

测试这边用了手里的设备都无法复现此问题,开发做了用户回访,发现腾讯地图是可以切换存储位置到外置sd卡上,所以初步排除了“用户sd卡不可用”的异常,但是因为用户的机型拿不到,所以测试找了同款机型(红米NOTE Android4.4.2和Android4.2.2)做测试,都无法复现此问题。

有了上文提到的现象,那么我们就来研究下解决方案:

二、解决方案

仔细研究手腾讯地图的源码,发现腾讯地图在做切换存储位置到外置sd卡时,是将已下载的离线地图连同目录一起移动到了/xx/A/是腾讯地图存储已下载离线地图文件的目录;

而腾讯路宝则是存储到了/yy/B/是腾讯路宝存储已下载离线地图文件的目录;

对比了这个区别之后,路宝开发将路宝代码中的存储目录也移动了下,即做切换存储位置到外置sd卡时,将其保存在/xx/B/目录下,即前半部分路径与腾讯地图相同、后半部分为各自包路径,经测试验证,问题得到解决。

在解决此问题的时候还没有找到发生此bug的根本原因,为了确认问题解决的是否彻底,我利用众测平台,进行了一轮众测,众测结论表明,众测用户中之前能复现此bug的机型上,问题也得到了解决。

问题得到了解决和验证,欢呼之余又陷入了沉思,因为原因我们并未得知,于是就有了下文:

三、根因分析

经过测试人员验证,在之前能复现此bug的机型上,用修改过的包再测试,问题确实得到了解决,但是这个问题为什么会发生、以及测试人员为什么之前测试的过程中没有发现这个bug呢?以及这类问题我们之后的测试过程中如何规避呢?一系列的问题迫使我们进一步深入研究这个bug的根因。

1、首先我们分析了路宝APP的用户反馈、众测用户反馈的机型,发现都是Android4.4的机型,有三星Note3 Android4.4.2、红米Note Android4.4.2,然后度娘Google Android4.4机型的特性,发现:

KitKat(即Android4.4系统版本)之后的版本,Google更改了用户对外置SDcard(Secondary Storage)的写入的权限;

以前我们可以直接获取WRITE_EXTERNAL_STORAGE和READ_EXTERNAL_STORAGE权限来直接操作Sdcard,现在则不能,其目的是软件卸载时能将该软件创建的文件全部删除。

在KitKat之前的Android版本会给应用程序单独分出一块外部存储空间(external storage),这块存储空间可能在sdcard(可插拔的外置sdcard)上,也可能在仅仅是在设备内部的闪存上,我们要获得WRITE_EXTERNAL_STORAGE权限才能对这块空间进行访问,如果只是读取内容则不需要权限。

在4.4 KitKat及之后的版本中,Google做了两个变化:1、进行读取时需要READ_EXTERNAL_STORAGE权限;2、访问应用所属的目录下(如:android/data/[package name])存储的数据是不需要任何权限的。

根据这个定义就能解释这个bug了吗?当然不能,测试手里就有三星Note3 Android4.4.2这款机型,但完全不能复现这个bug。

冥冥之中老天助我,在跟开发沟通其他bug的同时,发现另一个开发手里的三星Note3能复现此bug,欣喜若狂,遂借来进行比对分析。

2、继续跟踪中,既然上面提到了Android4.4系统版本禁止第三方APP对外置sdcard的写权限,那么我们分析下测试手里的Note3 Android4.4.2这款未出现bug的机型的Android系统的权限管理文件/system/etc/permissions/platform.xml,截图如下:

再分析从开发借来的三星Note3,也是Android4.4.2系统,其权限管理文件platform.xml截图如下:

恩,区别有了,少了<group gid="media_rw" />一行,但是这行又对bug产生了什么具体的影响呢?

3、与开发人员沟通,开发在试图获取外置sdcard是否有可写权限时,是判断了/storage/extSdCard这个目录,那么我们就顺藤摸瓜,来看下这个目录在Android系统下的权限吧,如下:

先连接设备,通过mount命令查看挂载的文件系统(跟外置sdcard相关的),如下:

/dev/block/vold/179:65 /mnt/media_rw/extSdCard vfat rw,dirsync,nosuid,nodev,noexec,noatime,nodiratime,uid=1023,gid=1023,fmask=0007,dmask=0007,allow_utime=0020,codepage=cp437,iocharset=iso88

/mnt/media_rw/extSdCard /storage/extSdCard sdcardfs rw,nosuid,nodev,relatime,uid=1023,gid=1023 0 0

即/storage/extSdCard挂载在了/mnt/media_rw/extSdCard下面,接下来分别查看/media_rw/extSdCard 和/storage/extSdCard的权限

root@hlte:/storage/emulated/0 # ls -ald /mnt/media_rw/extSdCard ls -ald /mnt/media_rw/extSdCard drwxrwx--- media_rw media_rw 2015-04-14 11:11 extSdCard

即/media_rw/extSdCard的组media_rw用户有全部的读写权限

root@hlte:/storage/emulated/0 # ls -ald /storage/extSdCard ls -ald /storage/extSdCard drwxrwx--x root sdcard_r 2015-04-14 11:11 extSdCard

即/storage/extSdCard的组sdcard_r用户也有全部的读写权限

这样看来,platform.xml中对WRITE_EXTERNAL_STORAGE的权限多出来的<group gid="media_rw" />也没什么区别,因为sdcard_r组就有读写权限......

4、排查暂时又没了头绪,继续求助度娘,惊喜的发现介绍如下:

在Kitkat中,sdcard_r 组有 +rwx 所有权限,实际上这是明显不对的,因为Fuse守护进程会在运行时中积极地参与修改应用的权限。

android.permission.WRITE_EXTERNAL_STORAGE权限被授给sdcard_r组和sdcard_rw组的成员,但在kitkat中认证write权限需要一些动态的检查,因此FUSE守护进程会被用来补充文件系统的权限,FUSE守护进程会强制赋予拥有特定目录的App每个权限(也就是访问自身数据存储的目录android/data/pack-agename...及一些公共目录)。对于sdcard_rw组中使用-w标志配置的非默认所有者,FUSE守护进程也会强制赋予write-protected权限。

所以当路宝APP请求/storage/extSdCard的“WRITE_EXTERNAL_STORAGE”的权限时,是有 <group gid="sdcard_r" />和<group gid="sdcard_rw" />这两个组的权限,但是这两个组在请求写外置sd卡的授权时,会被FUSE守护进程强制赋予不可写的权限,所以在开发机器上能复现这个bug,即离线地图不可切换存储位置。

以上现象在三星note3 Android4.4.2 三星原生系统上可复现。

5、这样就能解释为什么用户的机型上会出现这个问题了,兴奋之余,又有疑虑,既然用户的机型上能复现,那为什么测试的机型上就不能复现呢.....

再看下测试机型上的Android系统权限管理文件platform.xml中的权限如下:

<permission name="android.permission.WRITE_EXTERNAL_STORAGE" > <group gid="sdcard_r" /> <group gid="sdcard_rw" /> <group gid="media_rw" /> </permission>

那么问题来了,media_rw组是否受FUSE守护进程的限制呢,继续度娘,结论如下:

由此看来,虽然sdcard_r组受FUSE守护进程的限制,没有对外置sdcard的写权限,但是media_rw组有对外置sdcard全部的读写权限,且由于/storage/extSdCard是挂载/mnt/media_rw/extSdCard下的,根据linux系统取最大权限的特性,故/storage/extSdCard也有可读写外置sd卡的权限。这也就能解释为什么测试的机型上未复现此bug,且与用户复现bug的相同机型上为什么也不能复现这个bug了。

看到这里,相信你也和我一样,恍然大悟,以上看到了表象,我们再来抽象成通用理论,如下:

四、总结

总结而言,就是对于Goolge原生的Android4.4及以上的系统,都限制了第三方APP对外置sdcard的写权限,但对于不同的厂商的ROM,有对Android权限管理文件platform.xml进行了修改,加入对外置sdcard的写权限。

部分机型(GOOGLE Android原生或者未修改platform.xml中的<permission name="android.permission.WRITE_EXTERNAL_STORAGE" >的gid)且为Android4.4以上的系统能复现此问题,而测试这边为了保障测试系统版本的全面性,Android4.4以上系统均为自己刷的ROM,platform.xml中权限被修改,所以不能复现此问题。

那么以后如何规避这类问题呢:

1、加强代码review,考虑到KitKat系统的这个特性,后续需要写入外置sdcard的相关功能,均改为在外置sdcard的android/data/[package name]进行读写;

2、与适配团队沟通,他们将此功能点加入软件扫描检查点中,不符合的情况将给出警告,督促开发团队优化代码;

此问题从发现到排查,历时不短,感谢开发童鞋被我不厌其烦的骚扰后,还能一如既往的追根究底~感谢bug根因分析中jonah、lances和terry的帮助~感谢度娘~

通过以上实践经验,我们总结了第三方APP若对外置sdcard进行写操作,在Android 4.4及以上的系统一定要注意的事项,以及可以规避的方法,不知道对于正在Android开发/测试中的你,是否有帮助呢?

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-02-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯移动品质中心TMQ 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、起因
  • 二、解决方案
  • 三、根因分析
  • 四、总结
相关产品与服务
云硬盘
云硬盘(Cloud Block Storage,CBS)为您提供用于 CVM 的持久性数据块级存储服务。云硬盘中的数据自动地在可用区内以多副本冗余方式存储,避免数据的单点故障风险,提供高达99.9999999%的数据可靠性。同时提供多种类型及规格,满足稳定低延迟的存储性能要求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档