理解和检测安卓应用中系统设置相关的缺陷

Posted on
Software Analyze and Testing

本文是论文Understanding and Finding System Setting-Related Defects in Android Apps的总结笔记,作者是Jingling Sun。

总览

安卓系统提供了很多用户可以更改的系统配置,比如网络连接、飞行模式、静音、系统语言等。这些系统配置的变更,可能会影响到app的表现形式。但如果app对这些变更处理不当,可能使app存在缺陷(简称为设置缺陷)。这些缺陷可能引发UI错误、功能失效甚至是崩溃,从而影响用户体验。而目前的软件测试方法并不能系统地找到这些设置缺陷。

本文主要从两个方面研究设置缺陷:一方面,本文收集了180个开源安卓app的1074个设置缺陷,并探究它们的影响(impact)、根本原因(root causes)和后果(consequence)。另一方面,构建了一个端到端的测试工具(SetDroid)对26个流行的开源项目进行测试,并找到了42个设置缺陷(33个被确认,21个被修复)。同时,对5个流行的工业软件开展测试,找到了17个设置缺陷(全部被确认和修复)。

本文的核心思想是,所有的软件应该针对系统设置的变化,自动地做出相应的改变,并且:

  1. 系统设置还原后,能够恢复到原来的状态。
  2. 在不还原的情况下,能够体现出不同设置下的差异。

以实际的app为例,来解释设置缺陷是如何引发错误的:

  • Wordpress

    1. 当用户在发表一篇博客时开启飞行模式,则发送的操作会一直保持在等待状态,即使飞行模式已经被关闭且网络恢复了。
    2. 在飞行模式下发送草稿后,app将会在下一次开启时崩溃。
  • NextCloud

    在用户开启了系统的省电模式后,它的自动上传功能会变得无法使用,即使用户已经把app加入了省电模式的白名单。

目前的方法中,大多没有系统地研究这些缺陷,而是专注于某些特定的系统设置(如权限、屏幕方向)。另外,一些SOTA的通用测试技术只在app内部做测试,很少考虑到系统设置的影响;或是只研究引发程序崩溃的缺陷,而没有探测那些不会引发崩溃的缺陷(non-crash defects)。所以本文的工作亮点为:

  • 针对大部分的系统设置进行研究
  • 考虑系统设置对app的影响
  • 不仅检测引发崩溃的缺陷,还检测不会引发崩溃的缺陷

为了达到这些目的,本文主要针对三个研究问题进行探究和分析:

  • RQ1(impact):设置缺陷是否会广泛影响app的使用?
  • RQ2(root cause):引起这些缺陷的主要原因有哪些?
  • RQ3(consequences):这些缺陷主要引发什么后果?这些后果是以什么形式展示的?

经验研究方法

收集和总结设置类别

本文根据安卓文档和主流的安卓系统,总结了9个主要的设置类别,并使用一些常见的关键词来描述它们。这些关键词从一些bug报告和安卓SDK API中提炼而来,具体关键词如表所示:

Setting Categories Keywords Description
Network and connect Bluetooth, WLAN, NFC, internet, network, hot-spot, mobile, wifi, airplane 管理设备的网络模式(Wi-Fi、移动数据或飞行模式)或是和别的设备的连接(蓝牙)
Location and security location, device only, phone only, GPS, high accuracy, screen lock, fingerprint 管理设备的安全设置(如何解锁)、定位及对应的三种定位方式(使用网络和GPS、只使用网络、只是用GPS)
Sound vibrate, ringtone, do not disturb, silent 管理设备的声音(如禁音状态)
Battery power save, battery 管理省电模式,或为各app加入省电模式白名单
Display orientation, vertical, horizontal, split screen, Multi-window, screen resolution, brightness, landscape, portrait, rotate 管理设备的显示,如亮度、字体和屏幕方向
Apps and notifications permission, disable, notification 管理运行时的权限、以及app是否能够给用户发送通知
Developer developer option, keep activity 模拟特定环境的告诫设置,如强制right to left布局方向
Accessibility accessibility, talkback, text-to-speech, color correction, color inversion, high contrast text 辅助功能,如调整对比度、打开屏幕阅读器
Other settings setting, preference, date, time, time zone, hour format, date&time, reading mode, car mode, one-handed mode, dark mode, game mode, night mode, theme, language 改变语言、系统时间、输入方式、系统时间格式、主题等

收集设置缺陷的bug reports

收集设置缺陷的bug reports分为三个阶段:

  1. App收集

    基于Github收集开源安卓App,使用他们的源代码、错误和缺陷的描述、复现步骤、修复补丁和话题讨论。具体来说:

    • 使用Github的REST API获取所有的安卓项目,并选取在Google Play和F-Droid上架的App,最终收集到1728个项目。
    • 选取包含200个以上已被Closed的issues或bug reports的项目,筛选出215个项目。
    • 人工筛除其中的第三方库(这些库的demo上架了商店),最终筛选出180个项目。
    • 对收集到的项目,用箱型图描述了Star和Issue个数的分布,并统计它们的安装次数和项目类别。结果显示,收集到的项目覆盖了多个热门程度和软件类别。

  2. 问题报告(Bug Reports)收集

    本文从180个app中收集了177,769个问题报告,基于三个关键词集,筛选出包含这些关键词的问题报告

    • 设置关键词(Setting keywords):至少包含表格中一个关键词的问题报告,这些关键词可以是大写、缩写和不同时态的。
    • 缺陷或失败的关键词(Defect/failure keywords):包含crash、exception、bug、issue关键词的问题报告,表明该问题报告用于描述app中出现的问题。
    • 复现关键词(Reproducing keywords):使用关键词”repro“、”STR“、”record“来筛选问题报告,这些关键词表明问题报告中包含一些问题的复现步骤,这样可以帮助我们确认这些它是否涉及设置缺陷,也可以让我们定位到缺陷出现的原因。

    通过该步骤,总共筛选出了11,656个问题报告。

  3. 数据集构建

    为了回答三个研究问题,本文人为地检查了11,656个问题报告,并按照以下两个规则进行筛选:

    • 报告人或开发者明确指出,更改系统设置是引发问题的必要条件。
    • 对于没有明确线索的问题报告,本文复现了这些步骤来确定它是否和设置缺陷相关,同时也剔除了那些只包含“设置”字眼的问题报告。

    最终,本文筛选出1,074个问题报告作为数据集,其中482个已经被修复并关闭。每个问题报告都反映了某种设置缺陷。

对于各研究问题的分析方法

为了提升研究的准确性和客观性,本文的4位作者都参与了数据收集、分类、人工分析和交叉验证的过程。

  • 对于RQ1,本文重点关注的是:

    1. 每个软件使用中所涉及的系统设置,即各种系统设置对软件的影响程度。
    2. 每个软件设计哪些设置缺陷,即设置缺陷对软件的影响程度。

    在移动端开发中,SDK会为开发者提供每种系统设置涉及的类、方法、变量和回调函数等接口。通过统计开源软件中这些接口的使用情况,来判断这些软件是否有依赖于系统设置。

  • 对于RQ2,本文重点关注的是482个已被修复的问题报告,从中提取出产生问题的根本原因和解决方法。

  • 对于RQ3,针对1,074个问题报告,分析它们产生的后果,并且在需要的时候复现这些问题来观察结果。

对于研究问题的分析结果

RQ1:设置缺陷的影响

如上文所述,对于此问题,本文聚焦于:

  1. App中对于设置的使用情况
  2. 设置缺陷对app的影响

本文基于180个筛选后的app,为每种设置类别统计了

  1. 涉及各种设置类型的app数量(Apps using settings):

    当软件使用了某种设置类型的API,则认为它涉及了该设置类型,此处一个软件可能涉及到多个设置类型。值得一提的是,有些没有显式的API的系统设置(如Developer和Accessibility)没有被统计进去,故此处的统计结果是一个下限值。

  2. 受到设置缺陷影响的app数量(Apps were affected):

    当软件的对应的bug reports中提到了某个设置类型的关键词,则认为这个软件受到了这种设置缺陷的影响。

  3. 设置缺陷数(Setting Defects):

    对于所有bug reports,检查它们描述中所涉及的是哪一个设置类型,并为每个设置类型统计数量。

设置类型(Setting categories) # Apps using settings # Apps were affected # Setting Defects
Network and connect 86 68 326
Location and security 47 10 14
Sound 67 16 50
Battery 57 10 18
Display 109 78 226
Apps and notification 134 49 121
Others - - 319
# Total 171 162 1,074

表格中,App using settings和Apps were affected的Total行表示所涉及的app总数,并不是单纯的将该列相加。通过表格我们可以观察到以下情况:

  1. 95%(171/180)的软件涉及到了至少一种设置类型,这些类型中”Apps and notification”的数量最多,因为大多软件都涉及到了权限使用和通知。
  2. 大多数的软件都至少受一种设置缺陷的影响,占比达到了90%(162/180)。其中“Display”、“Network and connect”、“Apps and notifications”的影响范围最广。
  3. 在所有的设置缺陷中,“Display”、“Network and connect”、“Apps and notifications”类型出现的最多,因此这些设置类型最容易引发设置缺陷。

RQ2:引发设置缺陷的根本原因

本文分析了482个已修复的bug reports,并总结了几种常见的引发原因:

Root causes # Bug Reports
回调函数实现不当(Incorrect callback implementations) 164
缺少对设置的检查(Lack of setting checks) 143
没有适配用户界面(Fail to adapt user interfaces) 103
没有考虑安卓版本(Lack of considering Android versions) 27
多个设置之间的影响(Mutual influence between settings) 12
其它 33
  1. 回调函数实现不当:

    当系统设置发生改变时,程序会调用相应的回调函数,如果这些回调函数中没有处理好相应的逻辑,可能会引发错误。

    如AnkiDroid中,当用户请求存储权限的时候,屏幕右上角菜单中的按钮会消失,在用户完成请求后,应该要重新绘制这个按钮。

  2. 缺少对设置的检查:

    当某些设置影响到软件的功能时,开发者应该在实现这些功能时检查这些设置的状态,否则当设置变更时,软件并不会发生相应改变。

    如NextCloud中,自动上传功能是否开启取决于系统是否进入省电模式。而安卓系统中省电模式拥有白名单功能,在白名单内的软件并不会受省电模式关闭的影响。而NextCloud只判断了系统是否进入省电模式,而没有判断软件是否在白名单内。因此即使软件在白名单中,还是无法开启自动上传功能:

  3. 没有适配用户界面:

    一些设置(如多窗口模式、系统语言、字体大小、dark mode等)会影响UI布局,如果app不能很好的适配这些改变,则会引发界面显示问题(组件显示不全、文本重叠等)。另外本文观察到,这些问题大多可以通过修改XML布局的方式解决,而不是修改源代码。

  4. 多个设置之间的影响:

    一些设置之间可能存在显式或隐式的影响,比如定位功能可以通过GPS或网络、或是两者同时实现。

    一个显式的例子是,在Common中,如果在离线状态下打开app会引发崩溃,因为它在启动时通过网络来获取定位,在离线状态下这个函数会返回NULL值,这个值会被另一个获取定位的函数使用,从而引发崩溃。

    一个隐式的例子是,当省电模式开启时,定位、网络和动画的功能会被影响,比如Clover在省电模式中,某个动画会被自动关闭,从而引发线程阻塞,使得软件崩溃

  5. 没有考虑安卓版本:

    不同版本的安卓系统拥有不同的机制,比如某些版本中,对于一些功能可能会有额外的权限要求,如果没有加以控制会引发程序崩溃。

    比如OpenLauncher中,当勿扰模式开启时会引发崩溃,因为在Nougat版本中,开启勿扰模式时会调用AudioManager的方法,而在调用该方法前需要获得ACCESS_NOTIFICATION_POLICY权限,故此时需要提前检查安卓的版本来考虑是否获取权限。

RQ3:设置缺陷引发的后果

本文从1,074个bug reports中总结了四种主要的后果:

  1. 崩溃(315条):

    崩溃是占比最大的后果,一些软件崩溃可以通过重启解决,一些则无法解决,只能重新安装软件。

    如在OpenFoodFacts中,当系统切换到海地语后,软件再也无法打开。

  2. 不响应设置变化(285条):

    在设置变化后,软件并没有做出相应的改变。主要原因是开发者并没有考虑到一些设置改变带来的后果,所以没有做相应的适配。

    如Signal中,当用户打开勿扰模式后,该软件的通知仍然会发出声音。又如一些软件在更改系统语言后,内容不会翻译或是只有部分翻译。

  3. UI显示问题(218条):

    在改变一些影响显示的设置(如语言、主题)后,软件并不能正确地展示UI。

    如邮箱软件K-9,当用户切换到黑暗模式后,邮件内容引用部分的字体依然保持黑色,导致用户无法看到其中的内容。

  4. 功能不可用(197条):

    当某些设置改变后,软件中的一些功能并不能达到预期的效果。同时,由于开发者没有意识到这些问题的原因,不会对该现象给出提示,或是会给出一些令人困扰的提示,影响用户的使用。

    如syncthing中,当省电模式开启时,会导致后台同步功能无法使用,而syncthing没有提示用户省电模式会对同步功能造成影响。

    类似的情况还有app卡死、黑屏、无限读取、无法刷新等问题。

检测app中的设置缺陷(基于SETDROID)

蜕变模糊测试

对于一个常规的测试用例,由测试输入(test input)和预期输出(test oracle)组成,但是很多情况下,预期输出是很难获得的(oracle problem)。

  • 蜕变测试(Metamorphic testing)基于已有的测试输入,构建新的测试输入,并且新旧输入应当有相同的输出。通过对比原始输入和构建输入的两个输出,来判断程序是否出现错误。

  • 模糊测试(Fuzzing testing)指自动地或半自动地生成随机的测试用例作为程序的输入,来测试程序是否出现问题。

本文基于模糊蜕变测试的思想,随机生成对app的操作序列$E$(体现模糊测试的思想),并在操作序列$s$中随机插入事件$<e_c,e_u>$构成新的操作序列$E’$,其中$e_c$改变了系统设置,$e_u$可能还原系统设置,也可能什么也不做。本文验证app在$E$和$E’$下的表现是否一致(体现蜕变测试的思想)。

根据本文的核心思想:

  1. 当$E$插入改变事件$e_c$和还原事件$e_u$,构成$E’$后,$E$与$E’$的表现应该是一致的。
  2. 当$E$进插入改变事件$e_c$,构成$E’$后,$E’$的表现应该与$E$有期待中的差异。

具体来说,操作序列$E$由一系列的用户操作构成(比如点击、编辑、扫屏、旋转屏幕等),我们用$E=[e_1, e_2,\dots,e_n]$表示。

$E$中的每一个事件都会使GUI的状况发生改变,我们用一个GUI分布序列$L$来表示GUI对应的变化情况:$L=[l_1, l_2,\dots,l_{n+1}]$,其中$l_i$表示在$e_{i-1}$操作后,GUI中的组件(widget)分布。

当在$E$中插入事件$<e_c,e_u>$后,得到的事件序列表示为$E’=[e’_1,\dots,e_c,\dots,e_u\dots,e’_n]$,同时对应的GUI分布序列$L=[l’_1, l’_2,\dots,l_c,\dots,l_u\dots,l’_{n+1}]$。

对于每个事件$e$,它对某个GUI组件$w$进行操作(比如事件$e$点击某个按钮$w$),我们把这种关系记为$e.w$。

通过比较$L$和$L’$的关系,对“改变设置”这一行为造成的影响进行分析。具体的比较规则有两个规则:

  • 规则1: 使用两种策略,将$<e_c,e_u>$插入到$E$中:

    1. 立即修改(Immediate setting mutation):在执行$e_c$后立即执行$e_u$,如在开启省电模式后立刻将app加入省电模式白名单。
    2. 懒修改(Lazy setting mutation):在执行$e_c$后,只在必要的时候执行$e_u$,比如关闭了软件权限后,仅在软件再次申请权限时允许。这种行为也是符合安卓用户体验设计规范的。

    若对于$E’$中的某个$e’_i$,存在$e_i’.w$不在$l’_i$中,则判定其存在设置缺陷。

  • 规则2:只将$e_c$插入到$E$中,用于验证在设置改变后,两个GUI序列是否能有期望的差异。如使用langid(一种语言区分工具)来判断在改变系统语言后,软件的语言是否发生改变。

SETDROID的设计和实现

本文设计了一个自动化GUI测试工具SETDROID,主要包含4个模块:

  1. 测试执行器(test executer)

    基于两个相同的设备A和B,同时执行以下步骤:

    1. 获得当前的GUI分布
    2. 随机选择一个可触发事件的组件,并生成事件
    3. 执行该事件

    这里使用了UI Automator test framework来执行事件和获取GUI分布。

  2. 设置变化注入器(setting change injector)

    根据本文的研究发现:

    1. 43.4%的设置缺陷,是由于在软件执行过程中改变设置引发的(而不是在开启软件前)
    2. 只有2%的设置缺陷是由于多个设置改变而引发的(其中主要是屏幕旋转和其它设置同时改变时,会引发问题)

    所以在该模块中,注入器随机在运行过程中注入单个事件$<e_c,e_u>$,如果没有产生影响,则过段时间后再随机注入,直到事件序列结束。具体注入的事件如表所示,这些事件都是根据经验选取得出的:

  3. 测试输出检查器(oracle checker)

    在测试执行器的每次执行操作后,输出检查器根据规则1和规则2来检查两个设备的状况是否符合预期。

  4. 问题报告生成器(bug report reducer)

    一旦输出检查器发现缺陷,则报告生成器会进行执行以下步骤:

    1. 检查这个缺陷是否已经被记录,若已经记录则抛弃,否则执行b。
    2. 根据该缺陷的事件序列进行多次复现,若能够稳定发生缺陷,则执行c。
    3. 记录该缺陷的事件序列和缺陷截图。

    本文将发生缺陷时的GUI分布生成为哈希编码,在步骤a中通过比较哈希编码来确定缺陷是否被记录。

SETDROID为每个app随机生成20个测试序列(每个序列包含100个事件),并在序列中插入13个事件对。每个app的每个事件对,需要花费1小时时间执行,于是总共需要13*26=338个小时执行。

评估SETDROID

本文通过解决两个问题,来对SETDROID的成效进行评估:

  • RQ4:SETDROID能否监测到未曾发现过的设置缺陷?

    本文选取了之前工作中使用的30个流行开源软件,并筛选出其中26个保持活跃的软件进行评估。根据记录的所有问题报告,人为地标记处True Positive(真实的软件错误)和False Positive(被误判的软件错误)。当发现某个TP可以复现,并且没有被在issues中被报告后,作者将它们的复现步骤和视频在issues中提出。

    同时,本文在5个工业软件(微信、QQ邮箱、TikTok、CapCut和支付宝HK)中进行测试,花费2天时间进行缺陷检测。

    从结果来看,SETDROID具有如下特性:

    • 有效性:在26个软件中,SETDROID发现了42个未曾被检测到的设置缺陷,其中33个被证实为缺陷,21个被修复,体现了SETDROID的有效性。

    • 可用性:对于规则1,83.2%(124/149)的设置缺陷被认定为真实的缺陷,未被认定的缺陷(FP,16.8%)是由于某些软件在设置变化后,会引发一些弹窗提醒等动画,所以产生了GUI不一致的情况;对于规则2,19.2%(127/662)的设置缺陷被认定为设置缺陷,未被认定的缺陷(FP,91.2%)皆为英文阅读软件,所以当改变系统语言时,文章的内容并不会被翻译,从而产生了大量的FP。但对于一些GUI上未被翻译的内容,SETDROID可以快速的识别出来,同时通过可以在检测时忽略一些特定的组件(如文章内容),来避免产生这样的情况

    • 缺陷的多样性:SETDROID在多个软件中,检测到了多种类型的设置缺陷,以及多种缺陷后果。

    • 实用性:在工业软件中,SETDROID检测出了17个设置缺陷,并且全部被对应的公司修复,这些缺陷也是不同模块引发的不同结果。

  • RQ5:SETDROID能否找到现有工具无法找到的设计缺陷?

    现有的测试工具可以分为两种:

    • 通用测试工具:专注于app内部的测试,没有和系统设置交互
    • 专用测试工具:专注于某些软件问题进行检测

    其中,PREFEST对于偏好设置引发的缺陷进行检测,同时也考虑一些系统设置(蓝牙、网络和定位);PARDROID考虑了权限设置。这些工具都只能检测到引发崩溃的缺陷。

    本文涉及了两个方式来和这些工具做对比:

    • Baseline A(随机测试):随机生成事件序列(即SETDROID中的测试执行器模块)。
    • Baseline B(随机测试+改变设置):参考PREFEST和PARDROID的测试方法,在测试的开始改变某些设置,再执行随机的事件序列。

    本文在26个开源项目中,对SETDROID在两个基线上进行对比,同时也对三个工具进行横向对比:

    • 在考虑所有设置的情况下,有:
      • 直接进行Baseline A测试,不会发生错误。
      • 执行Baseline B,会发现3个崩溃错误。
      • 使用SETDROID,会发现9个崩溃错误和33个非崩溃错误。
    • 在考虑蓝牙、网络和定位设置的情况下,有:
      • PREFEST没有发现错误。
      • SETDROID发现10个非崩溃错误。
    • 在考虑权限设置的情况下。有:
      • PARDROID发现2个崩溃错误。
      • SETDROID发现6个崩溃错误和8个非崩溃错误。

效度威胁

本研究的效度威胁主要在于所研究的软件是不具有代表性。在本文中,对于设置缺陷的分析,本文从1,728个开源软件中选取了180个进行研究,这些软件覆盖了大部分的软件类型;对于SETDROID的验证,本文选取近期工作中被大量使用的,26个活跃的开源软件,以及热度很高的工业软件开展试验。

另一个主要的效度威胁是设置关键词不完整,从而导致收集到的设置缺陷不完整。本文从安卓官方文档中尽可能地收集设置相关的关键词,同时考虑到了这些词语的不同时态等因素。

最后一个效度威胁是人为判断的主观性。本文的4个作者通过交叉验证的方式,对检查结果进行分析,从而保证了结果的准确性。