Android BatteryStats服务功耗统计流程详解

2023-11-14


2023-06-17 17:27


简介

BatteryStatsService和BatterStatsImpl是系统中用于估算电流消耗的关键对象,能够估算并存储软件功耗和硬件功耗。其中主要流程分为事件回调时记录耗电信息、触发读取时计算并统计耗电信息两大流程。本文介绍耗电信息的读取和统计过程。

BatteryStatsService和BatteryStatsImpl

BatteryStatsService提供App和硬件的功耗,是通过BatteryStatsImpl的接口getUidStats()方法取得的,在分析该方法的流程前先简单介绍一些关键成员。

BatteryStatsHelper关键成员:

  1. BatterySipper:按照Uid和drain type来过滤存储的功耗记录,从BatteryStatsImpl中提取。可以理解为从系统记录的全部功耗信息中,按照Uid和Drain type提取出来。其中Drain type是耗电类型,如屏幕耗电、Wi-Fi耗电、App耗电等
  2. mUsageList:以BatterySipper的形式记录各Uid的功耗
  3. mWifiSippers、mBluetoothSippers:Wi-Fi、蓝牙专用的功耗记录(也是BatterySipper的形式)
  4. mUserSippers:mUsageList只存储refresh方法传入的参数内的uid的耗电。当uid不在refresh方法指定的uid范围内时,不存储到mUsageList而是存储到这里
  5. mMobilemsppList:各App的milliseconds per packets:各App的每个数据包的平均时间
  6. mRawRealtimeUs mRawUptimeUs : refresh()调进来的传入的elapsed time和uptime
  7. mBatteryUptimeUs mBatteryRealtimeUs mRaw*timeUs下当前battery*time
  8. mTypeBatteryUptimeUs mTypeBatteryRealtimeUs:当前版本的Android只支持上一次充满电后的记录,因此等同于mBattery*timeUs
  9. mBatteryTimeRemainingUs 根据上一次充满电后的掉电量/掉电时间估算出来还需要多久用光电池
  10. mChargeTimeRemainingUs 根据充电量/充电时间估算出来的还需要多久充满电池
  11. mMinDrainedPower mMaxDraingedPower 上次充电后的最小/最大的一次掉电量范围
  12. BatteryStatsImpl.TimeBase:拔掉电源、熄屏等各有一个TimeBase,封装了成员用于计算这些事件后的事件

BatteryStatsHelper.refreshStats:获取功耗记录主入口

refreshStats()方法用于获取系统记录的耗电情况,流程如下。

  1. 功耗记录是借助Binder从BatteryStatsService获取的:BatteryStatsService.getStats()->getActiveStatistics()获取BatteryStatsImpl(binder parcel传递)
  2. 调用processAppusage计算各Uid App的电耗
  3. 调用processMiscUsage()计算硬件功耗
  4. 计算mUsageList内记录的最高功耗到mMaxRealPower、mMaxPower
  5. 计算mUsageList内记录的各Uid的总功耗到mComputedPower、mTotalPower
  6. 根据mMinDrainedPower和mMaxDrainedPower,确定UNAACCOUNTED、OVERCOUNTED的电耗量,更新mTotalPower和mMaxPower,将over count和un count的电耗量加入到mUsageList中
  7. 进行电耗摊派。部分电耗属于系统需要隐藏的(shouldHideSipper),或者是要分摊给Uid们的。其中,要分摊的种类是需要隐藏的种类的子集,也就是说部分需要隐藏的电耗是不需要摊派的(或者之前已经摊派了,不用重复分摊)。其中屏幕功耗的分摊方式是,根据几个sipper的前台时间来算比例,根据前台时间的多少来承担对应比例的屏幕功耗,将屏幕功耗按前台时间分出去;承担了屏幕功耗的sipper会将自己分担的屏幕功耗记录到proportionalSmearMah,并调用sumPower()更新自己的总功耗
  8. 至此,详细功耗信息就记录到了mUsageList中了,通过BatteryStatsHelper.getUsageList()即可取得,遍历该集合的BatterySipper即可取得各uid的耗电记录

processAppUsage():读取并按uid来计算App耗电

该方法根据uid和drain type来统计App的耗电情况。

  1. BatteryStatsImpl.getUsageStats()取得所有Uid,遍历processAppUsage()传入指定的需要统计的uid
  2. 创建BatterySipper;BatterySipper用于提取Uid里面指定消耗类型;因为Uid里面记录了App、硬件等不同类型的消耗,这里只统计App自己的消耗(排除硬件);Sipper的作用其实就是从Uid里面提取Type对应的数据并存储下来
  3. 通过几大类的PowerCalculator.calculateApp()将Uid内的信息提取出来,进行计算,将数据存储进sipper
  4. 最后调用sipper.sumPower()将几大类的功耗全部加起来得到总功耗
  5. 接着当这个Uid sumpower > 0时,就根据uid来添加到对应的sipper集合中。
    1. Wifi、蓝牙对应的Uid会独立存储在它们的特定的sipper集合
    2. 当该Uid不是processAppUsage()参数指定的要读取的uid时、且该UID是App的Uid(≥FISTST_APPLICATION_UID)时,存储到mUserSippers中
    3. 都不是时,存储到mUsageList这个sipper集合中
    4. UID == 0(ROOT)时,处理为uid为0的实体的Wakelock的功耗,相当于将uid为0的drain type为App的情况算作系统的唤醒功耗(设备唤醒的时间可能比屏幕亮起时间和应用程序唤醒锁定时间要长。如果可能,将此余数分配给操作系统);记录到uid为0的drain type为app的记录时,表明应用可能都已经停止耗电,但系统还有服务或逻辑在运行,或进入睡眠前的一段间隔,这些内容会算作系统的功耗,并在Uid记录中体现

PowerCalculator:9大耗电类别计算App耗电

PowerCalculator是abstract类,用于App的9大类别的耗电计算,分别为:CPU、WakeLock、移动网络、Wifi、蓝牙、传感器、摄像头、闪光灯、媒体:9大类。

主要方法:

  1. reset():清除掉本计算器内的所有状态和数据
  2. calculateApp(BatterySipper,BatteryStats.Uid,rawRealtimeUs,rawUptimeUs,statsType):计算App在这个类别下消耗的电量;其中sipper用于从Uid提取对应的信息,可以理解成一个提供过滤能力的吸管,用于存储返回给调用者的信息,包括类型、uid、各项细节功耗值;real/upTime:系统当前的real time和uptime;realtime就是linux系统记录的系统启动以来经过的时间,uptime是realtime去掉休眠的时间;statsType是如何统计,Android Q以后只有一种方式:从上一次充满电后开始的所有数据
  3. calculateRemaining(),参数与calApp()完全一致;作用是当Uid内部记录的电量消耗不能全部算给App时,剩余的电量消耗

class Uid

BatteryStats有个内部类Uid,它封装了各uid(应用、系统等)以及它们的运行时长、耗电信息、网络收发情况、CPU时间等等一切和功耗有关的信息。各个PowerCalculator基于这个对象内存储的数据来进行计算。

CpuPowerCalculator:计算App消耗在CPU上的功耗

BatterySipper与CPU相关的主要是:cpuTimeMs、cpuFgTimeMs、cpuPowerMah、packageWithHighestDrain,CpuPowerCalculator主要就是读取并计算这些值,存储到上述sipper的这些成员中,最后存储到mUsageList或mUserSippers。

calculateApp:

  1. 调用Uid的方法取得Uid记录的uid对应的CPU时间(分不同的cluster(簇,不同的簇,因大小核、架构而功耗不一样)、不同的CPU速度),将这些数据与power_profile.xml记录的硬件功耗相乘后相加,得到Uid在CPU上消耗的时间和电量。其中CPU电量的计算公式是:总电耗=总CPU时间*CPU激活状态下的功耗 + 各频率运行时长*各频率对应额外运行功耗
  2. 一个uid可以有多个进程,Uid.Proc对象表示一个进程的唤醒时长等统计信息,同一个uid的进程的信息对应的若干Proc存储在Uid内的ArrayMap中;取得Uid内所有Proc的foreground time求和得到uid对应的总的cpuFdTimeMs,存入sipper;并总时间(user time、system time、fg time)最大的Proc存储到sipper的packageWithHighestDrain用于表示该Uid下CPU消耗最大的Proc

calculateRemaining:空实现

WakeLockPowerCalculator:计算App持有唤醒锁的时间和功耗

calculateApp:

  1. WakeLock专门存储于一个集合,用Uid.Wakelock表示,里面记录的Wake time取出后累加记录到sipper的wakeLockTimeMs
  2. 电量计算公式为:wakeLockTimeMs * CPU idle电耗

calculateRemaining:

  1. calculateApp只统计了Uid自己的wakelock时长对应的电耗,当Uid内记录的电池时间大于sum(WakeLockTime + ScreenOnTime)时,大于的部分算作app wake,同样算入wakeLockTimeMs、及对应电耗

MobileRationPowerCalculator:计算App进行的移动网络射频功耗

calculateApp:根据App收发的数据包数量结合power_profile计算电耗

calculateRemaining:根据信号强度、扫描次数结合power_profile计算电耗

WifiPowerCalculator:计算App进行的Wifi收发功耗

calculateApp:根据收发时长、空闲时长结合power_profile计算电耗;获取Uid存储的收发字节数、数据包数量存储到sipper

MediaPowerCalculator:计算App音视频功耗

calculateApp:Audio、Video时长*对应功耗得出电耗

processMiscUsage():统计硬件功耗

该方法用于统计硬件的功耗,与App功耗一致,都是根据Uid、Drain type借助sipper来计算的。

addUserUsage

前面统计App用量时提到,如果不是App的uid或没有在refreshStats方法传入的参数中没包含这个uid,那么不会存到mUsageList里面,而是在mUserSippers内;这个方法将mUserSippers内的DrainType为User的sipper提取出来放入mUsageList内。

注意前面processAppUsage处理的DrainType是APP,这里是USER。

addPhoneUsage

添加"Phone On"类型的功耗;这里统计的是Ratio功能active的功耗,可以认为是不开飞行模式时、上了基站的通话网络情况下功耗;形象理解为:设备正常放着,不进行基带射频、扫描、上网、通话时的功耗

addScreenUsage

添加屏幕的功耗,DrainType.Screen加入到mUsageList

addAmbientDisplayUsage

添加屏幕微光情况下的功耗(Display Doze),DrainType.Ambient加入到mUsageList

addWiFiUsage

统计除分摊给App以外的剩余Wifi消耗,从mWifiSippers中提取,以DrainType.WIFI的新的sipper加入到mUsageList。

addBluetoothUsage

蓝牙消耗的电量不会像WiFi一样会分摊给各个使用的App,它没有进行摊派全部统计在这里。该方法统计蓝牙的整体消耗;同WIFI,DrainType.BLUETOOTH加入mUsageList

addMemoryUsage

类似蓝牙的情况

addIdleUsage

统计设备休眠、空闲时的AP(App Processor,即CPU)的功耗——也就是说,不包含BP(基带)的功耗,由于外设已经关闭或挂起、系统已经休眠,可以认为是深度待机状态下的整机功耗,可以说是开机状态下设备的最低功耗了

DrainType.IDLE sipper加入到mUsageList

addRadioUsage

射频也和Wifi一样进行了摊派,同样是将没有摊派出去的独立出来到DrainType.CELL。其中,射频会额外关注信号强度,信号强度对射频功率、模组功耗影响大,进而影响对电耗的估算

总结

BatteryStatsService从系统各服务、驱动节点、Linux文件系统节点中取得的数据,在需要时,通过BatteryStatsImpl.refresh()取出、过滤、计算。其中,按照App电耗、硬件电耗两大部分来分别计算。耗电信息从Uid中取得,经过PowerCalculator处理后放入BatterySipper。一些类别的硬件电耗会分摊到使用它的几个App中,最终会以uid和Drain Type的形式来存储到多个BatterySipper中,交给调用者完成整个功耗信息获取过程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android BatteryStats服务功耗统计流程详解 的相关文章

  • 如何在 Android 中保存相机的临时照片?

    在尝试从相机拍照并将其保存到应用程序的缓存文件夹中时 我没有得到任何可见的结果 应用程序不会崩溃 但在 LogCat 上 当我尝试将 ImageView src 字段设置为刚刚获取的文件的 URI 时 我收到此消息 09 17 14 03
  • Android 30+ 中的视频捕获意图 - 只有所有者才能与待处理项目交互

    我正在尝试在我的应用程序上捕获视频 它可以在 android API 30 以下运行 但不能在 30 以上运行 似乎在 sdk 30 之后 android 不允许完全读取外部存储 作用域存储 我目前遇到这个错误 java lang Ille
  • Android 后退按钮无法与 Flutter 选项卡内的导航器配合使用

    我需要在每个选项卡内有一个导航器 因此当我推送新的小部件时 选项卡栏会保留在屏幕上 代码运行得很好 但是 android 后退按钮正在关闭应用程序而不是运行 Navigator pop import package flutter mate
  • 无法获取log.d或输出Robolectrict + gradle

    有没有人能够将 System out 或 Log d 跟踪从 robolectric 测试输出到 gradle 控制台 我在用Robolectric Gradle 测试插件 https github com robolectric robo
  • Android Activity 生命周期函数基础知识

    我正在测试这段代码 它显示活动所处的状态 public class Activity101Activity extends Activity String tag Lifecycle Called when the activity is
  • 当文本输入聚焦在 React Native for Android 的底部工作表上时,视图移出屏幕

    我正在使用图书馆 https github com osdnk react native reanimated bottom sheet https github com osdnk react native reanimated bott
  • 在画布上绘图

    我正在编写一个 Android 应用程序 它可以在视图的 onDraw 事件上直接绘制到画布上 我正在绘制一些涉及单独绘制每个像素的东西 为此我使用类似的东西 for int x 0 x lt xMax x for int y 0 y lt
  • 在 HTTPResponse Android 中跟踪重定向

    我需要遵循 HTTPost 给我的重定向 当我发出 HTTP post 并尝试读取响应时 我得到重定向页面 html 我怎样才能解决这个问题 代码 public void parseDoc final HttpParams params n
  • 带有 EditText 和 Spinner 的对话框

    我有一个按钮 单击后会弹出一个对话框 我希望对话框有一个EditText and a Spinner对话框内 我不知道如何设置它的视图 我有一个代码AlertDialog它有效 只是EditText and Spinner我需要将其放入其中
  • 如何使用 Cordova 获取当前安装的应用程序的版本?

    我已经找到了应用程序可用性插件 https github com ohh2ahh AppAvailability它主要检查用户是否在其设备上安装了某个应用程序 是否有可能获得应用程序的当前版本 开发者名称 重要 以及所有可能的信息 一般来说
  • 在gradle插件中获取应用程序变体的包名称

    我正在构建一个 gradle 插件 为每个应用程序变体添加一个新任务 此新任务需要应用程序变体的包名称 这是我当前的代码 它停止使用最新版本的 android gradle 插件 private String getPackageName
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • Google 云端硬盘身份验证异常 - 需要许可吗? (v2)

    我一直在尝试将 Google Drive v2 添加到我的 Android 应用程序中 但无法获得授权 我收到 UserRecoverableAuthIOException 并显示消息 NeedPermission 我感觉 Google A
  • 如何发布Android .aar源以使Android Studio自动找到它们?

    我正在将库发布到内部 Sonatype Nexus 存储库 Android Studio 有一个功能 可以自动查找通过 gradle 引用的库的正确源 我将 aar 的源代码作为单独的 jar 发布到 Nexus 但 Android Stu
  • 在 android DatePickerDialog 中将语言设置为法语

    有什么办法可以让日期显示在DatePickerDialog用法语 我已经搜索过这个但没有找到结果 这是我的代码 Calendar c Calendar getInstance picker new DatePickerDialog Paym
  • Android Studio - Windows 7 上的 Android SDK 问题

    我对 Google i o 2013 上发布的最新开发工具 Android Studio 有疑问 我已经成功安装了该程序并且能够正常启动 我可以导入现有项目并对其进行编辑 但是 当我尝试单击 SDK 管理器图标或 AVD 管理器图标时 或者
  • .isProviderEnabled(LocationManager.NETWORK_PROVIDER) 在 Android 中始终为 true

    我不知道为什么 但我的变量isNetowrkEnabled总是返回 true 我的设备上是否启用互联网并不重要 这是我的GPSTracker class public class GPSTracker extends Service imp
  • 在activity_main.xml中注释

    我是安卓新手 据我所知 XML 中的注释与 HTML 中的注释相同 使用 形式 我想在 Android 项目的 Activity main xml 配置文件中写一些注释 但它给了我错误 值得注意的是 我使用的是 Eclipse 但目前 我直
  • Firebase 添加新节点

    如何将这些节点放入用户节点中 并创建另一个节点来存储帖子 我的数据库参考 databaseReference child user getUid setValue userInformations 您需要使用以下代码 databaseRef
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分

随机推荐

  • JUST技术:利用迁移学习生成新城市的轨迹

    市民的出行轨迹数据无论是对于城市管理 规划 还是商业活动 都是重要的参考信息 然而 获取一个城市的人群轨迹数据却非常困难 在今年4月份召开的国际顶级互联网会议WWW 2020 CCF A类 上 京东城市报告了被会议收录的论文 What is
  • 解决安装强化学习库gymnasium,box2d安装报错的问题

    gymnasium是强化学习的库 比较难安装 一 安装方法 安装Gymnasium 一定要all 这样可以安装所有依赖 pip install gymnasium all pip install gymnasium all 二 报错信息一
  • Docker安装记录

    1 卸载旧版本 yum remove docker docker client docker client latest docker common docker latest docker latest logrotate docker
  • Git版本控制

    Git 版本控制 什么是版本控制 版本控制是一种开发的过程中用于管理我们对文件 目录或工程等内容的修改历史 方便查看更改历史记录 备份以便恢复以前的版本的软件工程技术 实现跨区域多人协同开发 追踪和机载一个或者多个文件的历史记录 组织和保护
  • 成功解决VMware安装操作系统出现分辨率的问题

    文章目录 问题重现 问题原因 问题解决 方法一 拓展 1 电脑分辨率 2 xrandr命令 3 查询后如果没有合适的分辨率解决方案 参考资料 问题重现 如下图 在VMware16上安装ubuntu操作系统的时候 出现分辨率问题 导致底部的按
  • < 面试知识点:什么是 Node.js ?有哪些优缺点?应用场景? >

    文章目录 一 什么是 Node js 二 Node js 有哪些优缺点 三 Node js 能做什么 四 Node js 的 模块系统 五 Node js 应用场景 参考文献 往期内容 一 什么是 Node js Node js 是一个开源
  • 微信小程序如何获取微信昵称和头像

  • MySQL 高可用:mysql+mycat实现数据库分片(分库分表)

    什么是MYCAT 一个彻底开源的 面向企业应用开发的大数据库集群 支持事务 ACID 可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库 用来替代昂贵的Oracle集群 一个融合内存缓存技术 NoSQL技术 HDFS
  • Docker入门命令详解

    目录 一 Docker 简介 1 Docker引擎 2 Docker客户端 3 Docker镜像 4 Docker容器 5 Docker镜像注册中心 二 Docker的特点 1 快速运行 2 节省资源 3 便于交付 4 容易管理 三 Doc
  • C语言有小数乘法,十道小数乘小数的乘法竖式计算并有答案

    十道小数乘小数的乘法竖式计算并有答案以下文字资料是由 历史新知网www lishixinzhi com 小编为大家搜集整理后发布的内容 让我们赶快一起来看一下吧 十道小数乘小数的乘法竖式计算并有答案 6 5 8 4 56 1 3 3 2 2
  • C#实现串口通信

    背景 在工业控制中 工控机 一般都基于Windows平台 经常需要与智能仪表通过串口进行通信 串口通信方便易行 应用广泛 一般情况下 工控机和各智能仪表通过RS485总线进行通信 RS485的通信方式是半双工的 在Win32下 可以使用两种
  • 04_两种常见的网页反爬措施及应对方法

    一 封禁IP地址反爬 1 应对思路 理解这种反爬方法的含义 当我们用自己电脑的ip地址短时间 高频率访问某个具有此类反爬设置的网站 这种网站就会把我们的ip地址封禁 一般都是封24小时或者其他时间 解决方案 通过代理ip访问 这种方式只不过
  • SQL 语句 最大长度限制 DB2如何修改最大长度限制

    home datamart db2 get db cfg grep HEAP Sort heap thres for shared sorts 4KB SHEAPTHRES SHR AUTOMATIC Sort list heap 4KB
  • PhotonServer介绍

    官网 On Premises Cross Platform Multiplayer Game Backend Photon Engine Photon为您完全封装了每个客户端平台的复杂网络层 Photon Server支持可靠的UDP TC
  • 作为一个编程新手,我再也不怕Flink迷了我的眼!

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由kyledong 发表于云 社区专栏 使用 Flink 编写处理逻辑时 新手总是容易被林林总总的概念所混淆 为什么 Flink 有那么多的类型声明方式 BasicTypeInf
  • 基于Qt的OpenGL编程(3.x以上GLSL可编程管线版)---(十五)obj模型加载

    Vries的原教程里 对于模型载入 使用的是一种非常流行的模型加载库Assimp 可以方便的加载obj fbx 3ds等常见的模型格式文件 在visual studio2015里 我照原教程进行了Assimp的配置 程序成功运行 在Qt中
  • 整蛊小程序(关机程序)

    关机小程序 简介 启动程序 执行关机 输入 我是猪 则关机停止 否则一直提醒 直到时间结束 关机启动 关闭窗口没有作用 先上代码 include
  • openGauss数据库基本操作(超详细)

    openGauss数据库常用操作命令 超详细 1 以操作系统用户omm登录数据库主节点 su omm 1 1 启动服务 分布式openGauss gs om t start 启动服务 gs om t restart 重启服务 集中式open
  • 【AI实时变声器,声音甜甜的小姐姐背后竟是抠脚大汉】

    前言 这是一款基于AI算法的实时变声器 如果你不懂AI也没事 直接使用我提供的一键安装包 链接 https pan baidu com s 1f3X6JdBVOgeTNPf0B3CRKg 提取码 k5v2 变声器安装使用 有两款变声器 都是
  • Android BatteryStats服务功耗统计流程详解

    2023 06 17 17 27 简介 BatteryStatsService和BatterStatsImpl是系统中用于估算电流消耗的关键对象 能够估算并存储软件功耗和硬件功耗 其中主要流程分为事件回调时记录耗电信息 触发读取时计算并统计