也许你在在过去10年间在各大网络论坛上经常会见到Android 手机用户和 iPhone 手机用户(“狗粉”和“果粉”?)在吵架,其中最重要的一个争论点就是“Android 手机用久了就会卡”。不过吵来吵去,大家都只有各自的立场,很少见到有理有据使人信服的辩论。为了给这些火气很大的“辩手”一个范例,今天我们就来介绍一篇科学地论证 Android 手机随着使用而(为什么)变慢的研究论文 Aging or Glitching? What Leads to Poor Android Responsiveness and What Can We Do About It?
要进行辩论(开喷),首先要有严格的定义,来自清华大学的作者在这篇论文中首先就把 Android 系统常见的一些让用户觉得很不爽的“卡顿”现象——系统和应用中常见的延迟(poor responsiveness) 进行了列举,这里包括 slow rendering(SR)、frozen frames(FF)、Application Not Responding(ANR)和 System Not Responding(SNR)。熟悉这几个缩写,对阅读整篇论文非常关键。
当然,光是定义常见的一些“卡顿”现象,从逻辑上并不能证明因果性(除非你坚持搞饭圈那一套),因此作者开发了一套非常细粒度的系统监控框架,对多个关键系统功能进行了插桩,监控各种系统指标(比如 CPU 占用率、内存消耗和系统 I/O 活动等)。除了上述的测量活动,作者还和小米公司开展了合作,征集了30000多名用户参加了相关的测试,毕竟这些延迟和卡顿事件没那么容易发现。
作为科学研究,论文最后当然要对 poor responsiveness 进行分析,挖掘到底是什么原因导致了这些糟糕的用户体验。接下来,我们就深入到文章中去看看细节。
首先,作者的细粒度分析框架分别对不同类型的 poor responsiveness 进行了测试。针对导致 SR 和 FF 的原因的分析流程如下图所示。作者发明了一个叫做 buffer-aware hierarchical timing correlation root cause analysis(读起来略有点拗口)的方法,简单地说,就是关注 SurfaceFlinger
这个负责显示的服务进程,同时记录相关的系统事件。这种方法可以区分出不同的延迟类型,例如对于那些延迟是由于线程调度等待(thread idling)引起的类型,基本上可以认为是 ARM 多核调度的大小核调度失误——把图形界面的渲染丢到了一个比较慢的小核。而如果没发现什么特别的系统事件导致延迟,那么大概率是 app 本身的 UI 设计太复杂导致的(开发者出来接锅)。
针对 ANR 和 SNR 的测试流程如下图所示,主要关注的是 app 的 call stack 以及可能导致死锁的互斥变量的使用情况。这部分写得有点复杂,不是很容易看懂。。。
由于是和小米进行合作,整个实验主要是基于小米的各种手机来进行测试的(如下表所示),Android 系统的版本从7.0到9.0,手机的型号也比较古老(当然这篇论文的主要工作是2021年前后做的)。
在实验结果的基础上,作者对各种导致手机运行延迟的可能性进行了分析,首先是针对硬件配置,作者指出,虽然很多厂商会说“better hardware helps improve software responsiveness”,但是“高配置的旗舰手机更不容易卡顿”这种结论可能仅仅适用于 SR 和 FF,而并没有什么证据表明硬件配置高的 Android 手机就能降低 ANR 和 SNR;实际上,Android 系统版本和 APP 的代码质量可能才是真正的影响因素。例如 Gmail 这个一个标志性的 APP,作者发现它在 UI 渲染的时候存在一种叫做 redundant UI rendering(RUIR)的问题(通俗一点说就是在显示界面的时候,如果顶层的内容会遮挡住底层的,那么实际上你并不需要去把底层的内容也渲染一遍,但是如果你这么做了,就是在执行冗余操作)。
当然,除了 UI 渲染等软件问题,确实有一些硬件因素导致了手机的运行延迟。这其中除了内存不足(当然这个是不是也要归咎于现在随便一个什么 APP 都是内存杀手)以外,最著名的就是针对手机 flash 存储的 Write Amplification Mitigation(WAM)问题(在本文调查的 ANR 中,有35%是因为 WAM 引起的)。所谓的 WAM 就是因为 flash 存储介质的读写通常是按照 4KB 为基本单位来操作的,如果你要改写哪怕一个比特的信息,你也要整体去写一个 4KB 的块(先读出上面的数据,然后把这个块擦除,最后再把修改后的数据写回去)。这时候就会考验 flash 设计厂商的软件算法功力,怎么去利用更多的存储块,而不是反复去擦写特定的块。当然,如果你把整个 flash 空间用光了,当然就会面临比较严重的 WAM 问题,这也是所谓的“高端手机更不容易卡”的一个“逻辑”。
作者还发现,大概是因为复杂性的原因,大部分的 ANR 都是由那些最流行的 APP 引起的:在调查中,作者针对1446个 APP 观察到的 50147起 ANR 事件中,60%的事件(30489起)都是由 top 10 的 APP 引起的(仅仅是所有 APP 的0.7%),而剩余的99.3%的 APP(1436个)全部加起来才导致了剩余的40%的 ANR 事件,所以你能说这到底是手机厂商的锅,还是这些 APP 大厂的代码烂呢?
论文:https://www.thucloud.com/zhenhua/papers/TMC'23%20Poor%20Android%20Responsiveness.pdf