功耗优化 · 入门篇 · 浅析Android耗电量优化(2)

本文涉及的产品
应用实时监控服务ARMS - 应用监控,每月50GB免费额度
简介: 功耗优化 · 入门篇 · 浅析Android耗电量优化

五. APM 耗电监控建设

影响App电量的因素有: 有屏幕, GPS,CPU,Radio,Video/Audio,Wifi 或蓝牙等

  • 那么我们该如何计算耗电量呢?
  • 怎么监控多进程,前后台等不同方式监测耗电情况呢?

手机系统耗电这块我们可以根据 /system/framework/framework-res.apk 的 power_profile.xml--文件进行耗电估算,里面的 value 值代表着不同类型设备发送不同动作的耗电系数: 如下图所示:

image.png

包括: BlueTooth , Wifi, Radio ,CPU 等

手机的系统耗电量 = CPU 毫秒数* 系数 1 + 流量 Bytes*系数 2 +....,当然不同类型参数是不一样的,应用也无法获取电量的具体细节

image.png

我们可以看一下 com.android.internal.os.BatteryStatsHelper 的关键方法 processAppUsage 里面按照 不同类型分别估算了不同服务耗电情况


  private void processAppUsage(SparseArray<UserHandle> asUsers) {
        final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
        mStatsPeriod = mTypeBatteryRealtimeUs;
        BatterySipper osSipper = null;
        final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
        final int NU = uidStats.size();
        for (int iu = 0; iu < NU; iu++) {
            final Uid u = uidStats.valueAt(iu);
            final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
            mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
            mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
            mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
                    mStatsType);
            mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
            mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
                    mStatsType);
            mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
            mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
            mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs,
                    mStatsType);
            mMediaPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
            final double totalPower = app.sumPower();
            if (DEBUG && totalPower != 0) {
                Log.d(TAG, String.format("UID %d: total power=%s", u.getUid(),
                        makemAh(totalPower)));
            }
            // ----code------
    }

至此: 我们也总结出影响 App 耗电的模块有如下几种情况

image.png

APM 耗电监控的关键就是需要定义全局参数估算 Location 时间, Alarm 次数,Net 访问量,wake_lock 持有时间,CPU 耗电情况等等~

耗电监控最大的难度在于:怎样通过 Hook wake_lock 持有长和 alarm 阀值 来预判 alarm 是否在做定时的重复任务,怎样通过 Hook 代理 LOCATION_SERVICE 实现 GPS 监控 ;


怎样通过 Hook 传感器的 SENSOR_SERVICE 中的“mSensorListeners”,拿到部分信息,最后才是通过埋点方案,在申请资源的时候将堆栈信息保存起来。当我们触发某个规则上报问题的时候,可以将收集到的堆栈信息、电池是否充电、电池的健康状态,CPU 信息、应用前后台时间等辅助信息也一起带上实现

整个耗电监控架构图如下: 利用多进程收集信息然后再传递给主进程,然后对耗电进行评估,最后再决定是否上报

image.png

那么我们怎么去监测手机的电量变化情况呢?

最核心的是通过广播来实现,在 BatterMannager 有六个比较核心的字段

字段 含义
STATUS_CHARGING 表示充电状态
STATUS_DISCHARGING 放电中
STATUS_NOT_CHARGING 未充电
STATUS_FULL 电池满
BATTERY_PLUGGED_AC 表示充电类型
BATTERY_PLUGGED_USB 表示 USB

电池的健康状态 也有一些七个比较核心的参数,他们返回一个 code, 这里我们也可以看一下:

字段 含义
BATTERY_HEALTH_UNKNOWN 未知
BATTERY_HEALTH_GOOD 良好
BATTERY_HEALTH_OVERHEA 过热
BATTERY_HEALTH_DEAD 没电
BATTERY_HEALTH_OVER_VOLTAGE 过电压
BATTERY_HEALTH_UNSPECIFIED_FAILURE 未知错误
BATTERY_HEALTH_COLD 过冷


基于这几点我们可以大胆预设做一套符合企业规则的耗电 APM 体系,

监控耗电本身也会带来更多耗电,那么我们该如何持续监控电池电量变化,其实我们真实环境是我们得找到低电量状态,如果手机电量过低自动关机,电池温度异常状态下监控并将数据上报,APM 管理系统可进行统计分析后,再通知手机做出电量补救措施,那么怎么看手机充电状态呢?可以参考以下代码

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatusIntent = registerReceiver(null, ifilter);
//如果设备正在充电,可以提取当前的充电状态和充电方式(无论是通过 USB 还是交流充电器),如下所示:
// Are we charging / charged?
int status = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
        status == BatteryManager.BATTERY_STATUS_FULL;
// How are we charging?
int chargePlug = batteryStatusIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
boolean acCharge = chargePlug == BatteryManager.BATTERY_PLUGGED_AC;
if (isCharging) {
    if (usbCharge) {
        Toast.makeText(MainActivity.this, "手机正处于USB连接!", Toast.LENGTH_SHORT).show();
    } else if (acCharge) {
        Toast.makeText(MainActivity.this, "手机通过电源充电中!", Toast.LENGTH_SHORT).show();
    }
} else {
    Toast.makeText(MainActivity.this, "手机未连接USB线!", Toast.LENGTH_SHORT).show();
}

关于 Hook 方案就不多做介绍了,java 层一般使用动态代理加静态代理方案实现,其他插桩方式如: ASM,javasisit,AspectJ 亦可,native 可以考虑使用 weishu 的 arthoook 替换 native 方法,这个可以结合我的 Github 项目 BatteryCanary 进行代码分析

因为 在 Android P 之后,很多的 Hook 点都不支持了。 所以 APM 耗电监控变得异常艰辛曲折~

六. 总结

本文主要是通过我业余时间的技术调研,利用线下工具 Battery Historian 分析企业 app 电池发热问题,电池的信息电压温度充电状态,Device estimated power use 这几个指标是线下测试的关键指标


对于 Location 时间, Alarm 次数,Net 访问量,wake_lock 持有时间,CPU 耗电情况等等估算,我们可以埋点采集,指标采集核心思想还是 Hook 方案, APM 耗电建设是一个费力不讨好的工程,耗电监控相关代码我也从张绍文的 Matrix 仓库抽出来并进行源码分析注释,



相关实践学习
通过云拨测对指定服务器进行Ping/DNS监测
本实验将通过云拨测对指定服务器进行Ping/DNS监测,评估网站服务质量和用户体验。
相关文章
|
1月前
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
77 2
|
8天前
|
调度 Android开发 开发者
【颠覆传统!】Kotlin协程魔法:解锁Android应用极速体验,带你领略多线程优化的无限魅力!
【8月更文挑战第12天】多线程对现代Android应用至关重要,能显著提升性能与体验。本文探讨Kotlin中的高效多线程实践。首先,理解主线程(UI线程)的角色,避免阻塞它。Kotlin协程作为轻量级线程,简化异步编程。示例展示了如何使用`kotlinx.coroutines`库创建协程,执行后台任务而不影响UI。此外,通过协程与Retrofit结合,实现了网络数据的异步加载,并安全地更新UI。协程不仅提高代码可读性,还能确保程序高效运行,不阻塞主线程,是构建高性能Android应用的关键。
28 4
|
10天前
|
运维 Cloud Native Android开发
云原生之旅:容器化与微服务架构的融合之道安卓应用开发入门指南
本文将深入探讨云原生技术的核心要素——容器化和微服务架构,并揭示它们如何共同推动现代软件的开发与部署。通过实际案例分析,我们将看到这两种技术如何相辅相成,助力企业实现敏捷、可扩展的IT基础设施。文章旨在为读者提供一条清晰的道路,指引如何在云原生时代利用这些技术构建和优化应用。 本文将引导初学者了解安卓应用开发的基本概念和步骤,从安装开发环境到编写一个简单的“Hello World”程序。通过循序渐进的讲解,让读者快速掌握安卓开发的核心技能,为进一步深入学习打下坚实基础。
19 1
|
13天前
|
缓存 算法 数据库
安卓应用性能优化:一场颠覆平凡的极限挑战,拯救卡顿的惊世之战!
【8月更文挑战第7天】《安卓应用性能优化实战》
26 4
|
3天前
|
编译器 Android开发 开发者
Android经典实战之Kotlin 2.0 迁移指南:全方位优化与新特性解析
本文首发于公众号“AntDream”。Kotlin 2.0 已经到来,带来了 K2 编译器、多平台项目支持、智能转换等重大改进。本文提供全面迁移指南,涵盖编译器升级、多平台配置、Jetpack Compose 整合、性能优化等多个方面,帮助开发者顺利过渡到 Kotlin 2.0,开启高效开发新时代。
6 0
|
1月前
|
算法 Java API
Android性能优化面试题经典之ANR的分析和优化
Android ANR发生于应用无法在限定时间内响应用户输入或完成操作。主要条件包括:输入超时(5秒)、广播超时(前台10秒/后台60秒)、服务超时及ContentProvider超时。常见原因有网络、数据库、文件操作、计算任务、UI渲染、锁等待、ContentProvider和BroadcastReceiver的不当使用。分析ANR可借助logcat和traces.txt。主线程执行生命周期回调、Service、BroadcastReceiver等,避免主线程耗时操作
37 3
|
2月前
|
缓存 JSON 网络协议
Android面试题:App性能优化之电量优化和网络优化
这篇文章讨论了Android应用的电量和网络优化。电量优化涉及Doze和Standby模式,其中应用可能需要通过用户白名单或电池广播来适应限制。Battery Historian和Android Studio的Energy Profile是电量分析工具。建议减少不必要的操作,延迟非关键任务,合并网络请求。网络优化包括HTTPDNS减少DNS解析延迟,Keep-Alive复用连接,HTTP/2实现多路复用,以及使用protobuf和gzip压缩数据。其他策略如使用WebP图像格式,按网络质量提供不同分辨率的图片,以及启用HTTP缓存也是有效手段。
56 9
|
2月前
|
XML 监控 安全
Android App性能优化之卡顿监控和卡顿优化
本文探讨了Android应用的卡顿优化,重点在于布局优化。建议包括将耗时操作移到后台、使用ViewPager2实现懒加载、减少布局嵌套并利用merge标签、使用ViewStub减少资源消耗,以及通过Layout Inspector和GPU过度绘制检测来优化。推荐使用AsyncLayoutInflater异步加载布局,但需注意线程安全和不支持特性。卡顿监控方面,提到了通过Looper、ChoreographerHelper、adb命令及第三方工具如systrace和BlockCanary。总结了Choreographer基于掉帧计算和BlockCanary基于Looper监控的原理。
46 3
|
1月前
|
安全 Java 数据处理
Android多线程编程实践与优化技巧
Android多线程编程实践与优化技巧
|
2月前
|
安全 Java 数据处理
Android多线程编程实践与优化技巧
Android多线程编程实践与优化技巧