

PowerUsageSummary.java源码分析 - 春告鳥
source link: https://www.cnblogs.com/Cl0ud/p/17044945.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

PowerUsageSummary.java源码分析 - 春告鳥 - 博客园
在在线网站http://androidxref.com/上对Android版本6.0.1_r10源码进行分析
官方手机的应用耗电排行具体实现位置在:/packages/apps/Settings/src/com/android/settings/fuelgauge/PowerUsageSummary.java
PowerUsageSummary
类的作用是筛选耗电量最多的前十个应用并且展示
开始的一部分的UI界面的创建和一些常量的定义,比如:
USE_FAKE_DATA
,定义是否要使用假数据;private BatteryHistoryPreference mHistPref;
BatteryHistoryPreference类获取耗电量历史数据(读取sp文件)
sp文件数据来自power_usage_summary.xml
文件
PreferenceGroup
类:统计所有APP耗电量
主要目光放在refreshStats
方法里
跟进父类方法
BatteryStats.STATS_SINCE_CHARGED
传入的是我们的计算规则
- STATS_SINCE_CHARGED 上次充满电后数据
- STATS_SINCE_UNPLUGGED 拔掉USB线后的数据
mUm.getUserProfiles()
是传入的多用户
这也是由Android的安全机制导致的,即多用户下的多应用
mStatsHelper.refreshStats
方法现在我们只要知道是刷新当前的电量统计的就行
然后是一些UI的刷新,该部分略过
可以看到mStatsHelper
无处不在,实际上电量统计的核心实现就是该部分实现的
mStatsHelper.getPowerProfile()
获取电源的配置信息,浅跟进一下
初始化是在这里
可以看到这里有一段注释: Read the XML file for the given profile (normally only one perdevice
跟进readPowerValuesFromXml
方法,其实这个方法就是用来解析power_profile.xml
文件的,该文件在源码中的位置为 /frameworks/base/core/res/res/xml/power_profile.xml
,power_profile.xml
是一个可配置的功耗数据文件
private void readPowerValuesFromXml(Context context) { int id = com.android.internal.R.xml.power_profile; final Resources resources = context.getResources(); XmlResourceParser parser = resources.getXml(id); boolean parsingArray = false; ArrayList<Double> array = new ArrayList<Double>(); String arrayName = null;
try { // ....
在这里需要提一下Android中对于应用和硬件的耗电量计算方式:
有一张“价格表”,记录每种硬件1秒钟耗多少电。有一张“购物清单”,记录apk使用了哪几种硬件,每种硬件用了多长时间。假设某个应用累计使用了60秒的cpu,cpu1秒钟耗1mAh,那这个应用就消耗了60mAh的电
这里的价格表就是我们找到的power_profile.xml
文件,手机的硬件是各不相同的,所以每一款手机都会有一张自己的"价格表",这张表的准确性由手机厂商负责。
这也是为什么我们碰到读取xml文件的时候注释里面会有normally only one perdevice
如果我们想要看自己手机的power_profile.xml文件咋办,它会存储在手机的/system/framework/framework-res.apk
路径中,我们可以将它pull出来,通过反编译的手法获得power_profile.xml
文件
mStatsHelper.getStats()
返回BatteryStats
对象,跟进可以发现实际上返回的是BatteryStatsImpl
,它描述了所有与电量消耗有关的信息
见名知意,获取设备的平均耗电量,用于与阈值进行对比
这部分看上去是界面和主题的显示
检查消耗的电量是否大于阈值,以及是否使用假数据,否则不显示应用耗电量
根据UID进行合并分组
其中getCoalescedUsageList
方法对UID进行分组
getFakeStats()
方法返回一堆假数据
private static List<BatterySipper> getFakeStats() { ArrayList<BatterySipper> stats = new ArrayList<>(); float use = 5; for (DrainType type : DrainType.values()) { if (type == DrainType.APP) { continue; } stats.add(new BatterySipper(type, null, use)); use += 5; } stats.add(new BatterySipper(DrainType.APP, new FakeUid(Process.FIRST_APPLICATION_UID), use)); stats.add(new BatterySipper(DrainType.APP, new FakeUid(0), use));
// Simulate dex2oat process. BatterySipper sipper = new BatterySipper(DrainType.APP, new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID)), 10.0f); sipper.packageWithHighestDrain = "dex2oat"; stats.add(sipper);
sipper = new BatterySipper(DrainType.APP, new FakeUid(UserHandle.getSharedAppGid(Process.FIRST_APPLICATION_UID + 1)), 10.0f); sipper.packageWithHighestDrain = "dex2oat"; stats.add(sipper);
sipper = new BatterySipper(DrainType.APP, new FakeUid(UserHandle.getSharedAppGid(Process.LOG_UID)), 9.0f); stats.add(sipper);
return stats; }
mStatsHelper.getUsageList()
返回BatterySipper数组,每个BatterySipper代表一个应用(uid)的消耗的电量信息
在BatteryStatsHelper.java
中的refreshStats
方法中对mUsageList
进行了赋值,这部分的具体操作在分析BatteryStatsHelper.java
的时候再提
这里的mStatsType
值为
这里我们前面提过,含义是
- STATS_SINCE_CHARGED 上次充满电后数据
- STATS_SINCE_UNPLUGGED 拔掉USB线后的数据
所以这段的含义是获取上次充满电之后的电量消耗
接下来遍历BatterySipper,对每一个UID代表的APP的耗电量进行过滤
如果耗电功率小于阈值则不进行显示
获取设备总耗电量
计算占用总耗电量的百分比
如果比例小于0.5,则不进行下一步操作
对某些情况进行过滤
进行UI界面的更新,其中也包含了获取应用的icon图标
获取当前应用的最大百分比,以及占总数的百分比
其中这里对显示的数量进行了限制
MAX_ITEMS_TO_LIST
的赋值
循环外有对addedSome
的判断
实际上就是判断是不是有符合要求的耗电应用,如果没有的话,就显示一条提示信息
这部分就是PowerUsageSummary.java
文件获取Settings电池中显示的应用耗电量信息,根据我们上面的分析,实际上控制上面的continue就能获取全部已安装应用的耗电量。在Android的不同API版本中,会有一些适配的工作量
关于申请权限,普通应用是没有办法获取到应用耗电量信息的,系统会抛出异常
java.lang.SecurityException: uid 10089 does not have android.permission.BATTERY_STATS.
如果想要进行相关API的调用,首先应用需要配置android.uid.system
成为系统应用,并且进行系统签名,才能够拥有相关权限,本地编译的话需要调用Android的internal
接口,我使用的是替换本地android.jar才可以正常打包出apk文件
本地编写了一个获取Android应用耗电量的demo,运行截图如下
建了一个微信的安全交流群,欢迎添加我微信备注进群
,一起来聊天吹水哇,以及一个会发布安全相关内容的公众号,欢迎关注 😃
__EOF__
Recommend
-
73
objcoding 源码解读 正文 ...
-
11
java源码分析之HashMap - JackPeng博客 在Java集合类中最常用的除了ArrayList外,就是HashMap了。本文尽自己所能,尽量详细的解释HashMap的源码。一山还有一山高,有不足之处请之处,定感谢指定并及时修正。 在看HashMap源码之前先复习一下数据结构...
-
7
安全岗春招面经总结 五一过后,春招就差不多结束了,今年...
-
4
对Github指定类目的内容进行监控和推送 - 春告鳥 - 博客园 很久之前看到HACK学习呀有一个Github 安全搬运工的系列文章,个...
-
8
如果想要对针对WiFi的攻击进行监测,就需要定期获取WiFi的运行状态,例如WiFi的SSID,WiFi强度,是否开放,加密方式等信息,在Android中通过WiFiManager来实现 WiFiManager简介 WiFiManager这个类是Android暴露给开发者使用的...
-
7
在分析PowerUsageSummary的时候,其实可以发现主要获取应用和服务电量使用情况的实现是在BatteryStatsHelper.java中 还是在线网站http://androidxref.com/上对Android版本6.0.1_r10源码进行分析 具体位置在 /frameworks/bas...
-
4
nmap脚本详解 - 春告鳥 - 博客园 nmap --script 我们通过nmap script来大幅扩展nmap的功能,nmap具...
-
6
极客大赛的碎碎念 - 春告鳥 - 博客园 公司的应届生都会参加极客大赛,简单来说就是会给出各个部门根据自身业务而出的题目,参赛者从题...
-
11
[安全开发] SQL注入扫描(一股子GPT味~) 实际上大部分都是它写的,它真我哭 SQL注入扫描就是一种...
-
5
xpoc漏洞使用与编写 浅尝 下载地址 https://github.com/chaiti...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK