运用PowerHint改进Android系统性能表现
背景介绍
公司需要改进既有的Android产品的整体用户操作体验,简单来说,就是在无法修改集成的第三方应用的前提下,想办法让用户操作系统的基本功能更加流程。 系统是Android 8.0,2xA73大核+2xA53小核,最高频率1.5GHz,内存和存储配置为2G DDR + 64G eMMC
可选方案
首先,主板本身的硬件配置无法变更,那么能修改的只有软件代码。 其次,跑在板子上的第三方应用我们无法修改。那么能够修改的只有系统层级的代码。 最后,要改善用户操作的体验,可以理解为让用户操作的响应更快。将目标分解,不外乎于用户打开应用速度更快、常用应用前后台切换不要重启、核心应用减少卡顿。 综上,我们的工作范围就可以圈定在:
- 感知用户打开应用的操作,并找到方法让后续应用开启过程耗时减少。
- 找到方法让更多的用户应用能在后台存活。
- 找到方法让核心应用使用时更为流畅。
凭借经验,一般可以类似下述手法实现上述需求(另一方面也可通过systrace分析具体卡顿点进行解决,不在本文讨论):
- 找到用户打开应用在系统中的必经之路,在应用开始启动前做类似cpu/gpu提频、后台无用进程清理、刷新率提升等动作;
- 在应用切到后台时做无UI进程清理释放内存、drop cache释放内存等动作;
- 在用户处于核心应用时判断用户操作进行进程绑定CPU大核、cpu提频、gpu提频等操作。
根据过往的经验,完成上述手法需要在framework中进行不少修改,包括在Activity启动路径打点、用户操作UserActivity打点、前后台切换打点等,是否有一种更加优美、更少侵入式修改的方案可以完成上述改动呢? 这就引出了本篇文章介绍的PowerHint 接口。
PowerHint介绍
在电池类智能设备中,一个永恒的问题就是如何平衡功耗与性能,安卓的手机/平板等设备也不例外,安卓系统也针对这组矛盾做了非常多功课。 但是做为一个开放的生态系统,不同的芯片厂家、整机厂家总会有不同的调校偏好(比如有些设备是常供电设备,那么就可以无需考虑功耗问题而保障性能),所以安卓在系统中也给芯片/整机厂家进行客制化响应预留了软件架构,即PowerHAL ,其接口位于Android\hardware\interfaces\power\1.0\ 之中。 先看下接口定义
package android.hardware.power@1.0;
interface IPower {
setInteractive(bool interactive);
powerHint(PowerHint hint, int32_t data);
setFeature(Feature feature, bool activate);
getPlatformLowPowerStats()
generates (vec<PowerStatePlatformSleepState> states, Status retval);
};
可以看到,主要有两个接口,其一是setInteractive() ,其在系统开屏/关屏时触发调用,用于让设备厂商去响应进行能耗调节;其二是powerHint() ,其在系统的各种时机触发,也是用于让设备厂商获知当前系统状态,进行能耗调节。为了实现本文上述的目标,我们将重点放在powerHint 接口,下面看下安卓定义了多少种Hint状态。
enum PowerHint : uint32_t {
VSYNC = 0x00000001,
INTERACTION = 0x00000002,
VIDEO_ENCODE = 0x00000003,
VIDEO_DECODE = 0x00000004,
LOW_POWER = 0x00000005,
SUSTAINED_PERFORMANCE = 0x00000006,
VR_MODE = 0x00000007,
LAUNCH = 0x00000008,
};
可以看到,安卓系统已经做好了多种不同的事件定义等待制造商进行实现并响应。包括应用响应VSYNC信号、应用即将被启动、用户与设备进行交互,并且不同的事件响应是携带不同参数用于指定事件的起始/结束、持续时间等。 在注释中,安卓系统也明确写出,设备制造商应当实现这些事件的响应,快速调节CPU、GPU、ddr speed、io等多维度参数让设备整体硬件性能动态拉升到符合预期的状态,并在事件结束后将参数恢复。这样一来,相当于系统在需要执行一些重要任务时提前告知硬件提升频率(耗能提升),任务结束后告知硬件降低频率(耗能下降),如此就实现了能耗与性能的一种均衡。 那么这种策略与芯片自身的DVFS(动态电压频率调整) 有何区别?我认为区别在于DVFS 属于后调节,也就是说当前已经有了一个重任务在执行,DVFS 才会逐步感知并提升频率,而上述PowerHint 属于前调节,也就是系统知道马上要有一个重任务到来,告知硬件进行调频。显然,PowerHint 这种方式能够更快速地让硬件进行响应,减少了使用DVFS 调节逐步反应的时间,达到了更优体验。针对华为的Turbo 技术比较可信的猜测就是结合了DVFS 和AI驱动的前置调节,达到了其宣传中的体验。
可用范围
通过上述分析,针对前文的三个优化工作,可以逐个分析。
- 感知用户打开应用的操作,并找到方法让后续应用开启过程耗时减少。
- 找到方法让更多的用户应用能在后台存活。
- 找到方法让核心应用使用时更为流畅。
针对第一点,安卓在PowerManagerService 的函数userActivity 触发流程中,会调用powerHintInternal(PowerHint.INTERACTION, 0) ,对照上文的介绍,可以知道此时就是安卓系统告知硬件当下有用户操作,0的含义是由实现者自行决定硬件调频时间。那么我们实现PowerHAL 中此函数,响应该case,对CPU/GPU进行锁最高频操作,并保持一定时间(如1s)后还原。如此一来,就实现了用户触屏点击某个应用图标后,应用启动之前 cpu/gpu已经拉满,从而让后续启动过程得到更快速响应,达到整个启动过程耗时减少的目的。 针对第二点,可以实现LAUNCH 这个case,当任意具备页面的应用开始被启动时,触发一些 drop cache memory、清理无用进程的工作,减少启动至AMS 流程后被动的oom adj 触发可能性,也为应用预留更多内存空间。 针对第三点,可以结合LAUNCH 和INTERACTION 两个case做联合判断,进行后台清理和提频。当然这里有个问题在于如何识别当前应用为我们标记的核心应用?在PowerHint 架构中是无法通过参数获取该信息的,可以写一个服务实现AccessibilityService 组件,在其中可以监听系统Activity 切换,从而将当前应用信息进行保存(比如存至property中),在PowerHAL 实现中进行读取做结合判断。
总结
有时安卓系统本身已经为设备制造商做好了足够的预留,只是我们不一定能够准确找到并合理使用,才导致很多时间做了非常多侵入式修改,为自己日后做移植开发增加了额外工作量。通过合理实现原生架构,完全可以更简洁优美地达到目标。 当然上述通过PowerHAL 架构做性能调优的一个重要前提是所用芯片具备这样的调节能力。如果用的芯片根本没有调频这种能力,那通过此架构来动态调频也无从谈起了。主芯片如此,外围的ddr、emmc/ufs 是否具备频率等级调整也是影响上述调节最终效果的重要因素。 在本文所用的板卡系统上,通过上述的方式,整体应用启动耗时、核心应用操作流程耗时客观数据有了20%左右的提升,代码模块化良好,无额外侵入,能够快速移植至其他同类芯片方案,效果符合预期。
|