20.电量优化总结

写在前面

  前面几篇关于电量的文章,到最后也只是对于一些硬件使用的一些监控,好像没有一个明确的目标或者方向,本以为看完即可对电量优化有提升,但现实并未如此,好像懂了又好像没懂。没懂的有很多,比如怎么定义电量异常消耗,减少电量消耗只知道减少位置信息获取,wifi扫描,传感器减少使用等,...

思考

  • 1.在Android中电量消耗是如何计算的

  • 2.有没有工具可以来衡量电量消耗与使用手机

  • 3.对于电量需要监控哪些维度

  • 4.优化的指标有哪些

1.在Android中电量消耗是如何计算的

电量 = 功率 * 时间 = 电压 * 电流 * 时间 ,这个本人觉得是比较有道理的

  在Android系统中有一个power_profile.xml文件,搜索中对于该文件的描述是“系统的 设置-->电池-->使用情况中,统计的能耗的使用情况也是以power_profile.xmlvalue作为基础参数的”,该文件记录的是手机中的每个部件运行时对于的能耗值,该文件位于/system/framework/framework-res.apk这个apk中的res文件夹下。

该文件的部分信息如下(android9.0代码)

<device name="Android">
  <item name="ambient.on">0.1</item>  <!-- ~100mA -->
  <item name="screen.on">0.1</item>  <!-- ~100mA --> // 亮屏时的电流值
  <item name="screen.full">0.1</item>  <!-- ~100mA -->
  <item name="bluetooth.active">0.1</item> <!-- Bluetooth data transfer, ~10mA -->
  <item name="bluetooth.on">0.1</item>  <!-- Bluetooth on & connectable, but not connected, ~0.1mA -->
  <item name="wifi.on">0.1</item>  <!-- ~3mA -->
  <item name="wifi.active">0.1</item>  <!-- WIFI data transfer, ~200mA -->
  <item name="wifi.scan">0.1</item>  <!-- WIFI network scanning, ~100mA -->
  <item name="audio">0.1</item> <!-- ~10mA -->
  <item name="video">0.1</item> <!-- ~50mA -->
  <item name="camera.flashlight">0.1</item> <!-- Avg. power for camera flash, ~160mA -->
  <item name="camera.avg">0.1</item> <!-- Avg. power use of camera in standard usecases, ~550mA -->
  <item name="gps.on">0.1</item>  <!-- ~50mA -->
  ...
</device>

  知道了该文件,那么对应的电量计算就是 屏幕亮屏一段时间内的电量 = 100mA * 电池电压 * 使用时间,而电池电压在集成到手机内就是不变的,而且比较容易查询到,使用时间获取的话之前文章有提到,是根据接收系统广播来计算(本次息屏广播时间 - 本次亮屏广播时间),其他的硬件电量计算也类似,把所有的电量消耗加起来就可以计算出一段时间内电池电量的消耗值了。

  在系统中有一个BatteryStatsHelper.java类,该类辅助计算电量消耗,而具体的计算方式在各个PowerCalculator实现类中

public class BatteryStatsHelper {
    PowerCalculator mCpuPowerCalculator;
    PowerCalculator mWakelockPowerCalculator;
    MobileRadioPowerCalculator mMobileRadioPowerCalculator;
    PowerCalculator mWifiPowerCalculator;
    PowerCalculator mBluetoothPowerCalculator;
    PowerCalculator mSensorPowerCalculator;
    PowerCalculator mCameraPowerCalculator;
    PowerCalculator mFlashlightPowerCalculator;
    PowerCalculator mMemoryPowerCalculator;
    PowerCalculator mMediaPowerCalculator;
    ...
private void processAppUsage(SparseArray<UserHandle> asUsers) {
        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)));
            }

         
        }
    }
}


public class CameraPowerCalculator extends PowerCalculator {
    private final double mCameraPowerOnAvg;

    public CameraPowerCalculator(PowerProfile profile) {
        mCameraPowerOnAvg = profile.getAveragePower(PowerProfile.POWER_CAMERA);
    }

    @Override
    public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
                             long rawUptimeUs, int statsType) {

        // Calculate camera power usage.  Right now, this is a (very) rough estimate based on the
        // average power usage for a typical camera application.
        final BatteryStats.Timer timer = u.getCameraTurnedOnTimer();
        if (timer != null) {
            final long totalTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
            app.cameraTimeMs = totalTime;
            app.cameraPowerMah = (totalTime * mCameraPowerOnAvg) / (1000*60*60);
        } else {
            app.cameraTimeMs = 0;
            app.cameraPowerMah = 0;
        }
    }
}

总结:

1.Android 各个硬件模块的消耗功率在power_profile.xml

2.计算消耗电量方式为:功率 * 时间 = 电压 * 电流 * 时间

2.Battery Historian 检测工具

  这个工具尝试安装没有安装成功,之后又试了线上的网站分析工具https://bathist.ef.lc/结果502...,就很无奈,只能看着文章网上的文章来写这部分。

  Battery Historian 是在 Android 5.0 Lollipop(API 级别21)及更高版本的 Android 设备上检测与电池相关的信息和事件,而在此期间,该设备没有插上电源。它允许应用程序开发人员在时间轴上可视化系统和应用级别的事件,并使用平移和缩放功能,在设备最后一次完全充电之后,可以轻松地查看各种聚合统计信息,可以选择一个应用程序,检查所选择的应用程序对电池指标的影响。此外,它还允许对两个错误报告进行 A/B 比较,突出显示了关键电池相关指标的差异。

  简言之就是可以记录下一段时间内手机的状态和电量消耗情况即手机哪个部分干了什么导致电量消耗的工具,记录的内容有息亮屏,CPU运行,内核,GPS 运行,WIFI、蓝牙扫描,电池低电量等等的状态。

  • 使用步骤:

  • 1.在检测手机电量前将之前的信息清空:adb shell dumpsys batterystats --reset

  • 2.开始记录数据:adb shell dumpsys batterystats --enable full-wake-history

    • 分为亮屏时操作app(WIFI,位置,相机,音乐或视频格外注意)和息屏一段时间内的后台测试(看看有哪些不合理的动作出现)
  • 3.拉取记录的数据:adb shell dempsys batterystats > 文件保存路径/文件名

  • 4.将文件上传到自己搭建或线上平台开始分析,类似与下图

Battery_Historian_use.png

图中的数据就不分析了,参考这篇文章(毕竟图都是这里偷的)电量分析工具 Battery Historian 的配置及使用

该工具可以很好的表现出电量消耗的原因在哪里,适合在上线前检测代码有哪里写的不规范

3.对于电量需要监控哪些维度

  结合matrix中的内容,监控电量的维度有那么几方面

1.在测前台的时候不要忘记运行在后台的检测

2.记录下硬件模块的调用(亮息屏,WIFI、蓝牙扫描,获取定位信息,闹钟,是否移动网等)

3.后台工作调度 :JobAlarmsWorkManagerWakeLock

而该额外记录的信息应该有堆栈信息,是否充电,是否处于低电量,前后台时间,CPU状态等

4.优化的指标

优化的思路应该是减少不必要的硬件模块的调用,在息屏时减少不必要的后台运行,将后台运行合并延迟到一个合适的时机

1.优化后台耗电,减少使用不必要的WakeLock 、获取位置、WIFI和蓝牙扫描等

2.传输大数据时尽量在充电或者WIFI情况下

3.定位选择低精度,网络定位代替GPS,减少频率

4.在进入后台时,app主动释放一些与界面有关的东西,如动画等

5.减少使用硬件传感器的频率

写在最后

  其实 Android 在最近的版本中对于后台的限制也越来越严苛,在 Android O 中限制了后台执行和后台位置及更多的优化了省电功能,在 Android P 中提出应该待机分组(按 app 的使用将 app 分为活跃组-正在使用、工作组-应该频率很高、常用组-经常但不是每天用及少用组-偶尔使用,对于不同分组的 app 有不一样的限制使用方法),更加严格的 app 后台使用限制及省电模式。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容