Android App耗电量统计
还没有完成的,初稿
App耗电量统计:源码
- PowerUsageSummary.java 继承PowerUsageBase.java类
BatteryHistoryPreference类--sp 获取耗电量历史(读取sp文件)--sp文件数据来自xml文件(power_usage_summary.xml)
PreferenceGroup类--统计所有App耗电量同historyrefreshStats()方法刷新耗电量状态:内部有以下几个类(BatteryStatsHelper.java)获取
1.PowerProfile:提供部件电流数值。
2.BatteryStats:App各部件运行时间。(获取封装在BatteryStatsHelper类中具体看下面)
final BatteryStats stats = mStatsHelper.getStats();
3.根据BatteryStatsHelper类中统计
- App耗电量统计:processAppUsage()
- 硬件耗电量统计:processMiscUsage()
获取耗电量更新SP数据: mAppListGroup.addPreference(pref);
- PowerProfile.java
(1)Android部件电流信息存于:power_profile.xml
(2)每个OEM厂商有私有power_profile.xml
(3)PowerProfile读取power_profile.xml,并提供API访问部件电流数值。
/*** Reports power consumption values for various device activities. Reads values from an XML file.* Customize the XML file for different devices.* [hidden]*/
38public class PowerProfile {private void readPowerValuesFromXml(Context context) {int id = com.android.internal.R.xml.power_profile;//xml文件power_profile.xml//下面就是xml解析了根据下面定义节点获取值://private static final String TAG_DEVICE = "device";//private static final String TAG_ITEM = "item";//private static final String TAG_ARRAY = "array";//private static final String TAG_ARRAYITEM = "value";//private static final String ATTR_NAME = "name";....
最后添加数据到sPowerMap (一个HashMap) sPowerMap.put(key, (double) value); key是各部件名称。value是各部件的电流值
}
}
//power_profile.xml 各部件定义的电流值 屏幕 cpu 蓝牙 wifi gps等等
<device name="Android"> <item name="none">0item> <item name="screen.on">100item> <item name="screen.full">200item> <item name="bluetooth.active">90.5item> <item name="bluetooth.on">2.5item> <item name="wifi.on">1.25item> <item name="wifi.active">130item> <item name="wifi.scan">100item> <item name="dsp.audio">30.5item> <item name="dsp.video">72.5item> <item name="radio.active">135item> <item name="radio.scanning">5.3item> <item name="gps.on">30item> <array name="radio.on"> <value>3.5value> <value>2.4value> array> <array name="cpu.speeds"> <value>624000value> <value>699563value> <value>799500value> <value>899438value> <value>999375value> <value>1099313value> <value>1199250value> <value>1299188value> <value>1399125value> <value>1499063value> <value>1599000value> array> <item name="cpu.idle">2.2item> <array name="cpu.active">//各个cpu频段的功耗 <value>54value> <value>63value> <value>72value> <value>80value> <value>90value> <value>100value> <value>109value> <value>115value> <value>121value> <value>127value> <value>135value> array> <item name="battery.capacity">2000item>
device>
- BatteryStats.java 抽象类implements Parcelable(android 序列化)
/*** 统计电池各部件使用情况,时间以微秒为单位* A class providing access to battery usage statistics, including information on* wakelocks, processes, packages, and services. All times are represented in microseconds* except where indicated otherwise. * @hide*/
public abstract class BatteryStats implements Parcelable {private static final String TAG = "BatteryStats";private static final boolean LOCAL_LOGV = false;/** @hide */public static final String SERVICE_NAME = "batterystats";....
}
- BatteryStatsHelper.java Android BatteryStatsHelper深入理解(and5.1)
作用:主要是统计各个应用,多用户的每个用户,以及蓝牙,屏幕等耗电统计
BatteryStatsHelper 的实例在PowerUsageBase类初始化:
@Overridepublic void onAttach(Activity activity) {super.onAttach(activity);mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE);mStatsHelper = new BatteryStatsHelper(activity, true);//实例化}
BatteryStatsHelper.java 类内部方法
public void create(BatteryStats stats) { mPowerProfile = new PowerProfile(mContext); mStats = stats;
} public void create(Bundle icicle) { if (icicle != null) { mStats = sStatsXfer; mBatteryBroadcast = sBatteryBroadcastXfer; } mBatteryInfo = IBatteryStats.Stub.asInterface( ServiceManager.getService(BatteryStats.SERVICE_NAME)); //aidl服务 SERVICE_NAME = "batterystats";;mPowerProfile = new PowerProfile(mContext); //从power_profile.xml读取的各个器件的电源消耗参数具体查看上面详解这个类的链接
}
在PowerUsageSummary类分析获取App各部件运行时间 调用BatteryStats stats = mStatsHelper.getStats();
public BatteryStats getStats() {if (mStats == null) {load(); //如果mStats为空 调用load方法否则返回mStats}return mStats;}private void load() {if (mBatteryInfo == null) {//mBatteryInfo空判断在Create里面初始化了return;}mStats = getStats(mBatteryInfo); //调用getStats,返回BatteryStatsImpl实现类if (mCollectBatteryBroadcast) {mBatteryBroadcast = mContext.registerReceiver(null,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));//注册监听电量改变广播}}private static BatteryStatsImpl getStats(IBatteryStats service) {try {ParcelFileDescriptor pfd = service.getStatisticsStream();//BatteryStatsService服务类:收集所有消耗电池信息 调用updateExternalStatsSync()从外部获取数据来源(无线控制器,bluetooth芯片组)和更新batterystats信息。if (pfd != null) {try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {//下面读取序列化反序列化获取batterystats数据byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));Parcel parcel = Parcel.obtain();parcel.unmarshall(data, 0, data.length);parcel.setDataPosition(0);BatteryStatsImpl stats = com.android.internal.os.BatteryStatsImpl.CREATOR.createFromParcel(parcel);return stats;} catch (IOException e) {Log.w(TAG, "Unable to read statistics stream", e);}}} catch (RemoteException e) {Log.w(TAG, "RemoteException:", e);}return new BatteryStatsImpl();}
接下来就是refreshState更新电池最新状态的,statsType是指充电状态还是非充电状态,asUsers指的是userId(多用户)
public void refreshStats(int statsType, List asUsers) { final int n = asUsers.size(); SparseArray users = new SparseArray(n); for (int i = 0; i < n; ++i) { UserHandle userHandle = asUsers.get(i); users.put(userHandle.getIdentifier(), userHandle); } refreshStats(statsType, users);
} /** * Refreshes the power usage list. */
public void refreshStats(int statsType, SparseArray asUsers) { refreshStats(statsType, asUsers, SystemClock.elapsedRealtime() * 1000, SystemClock.uptimeMillis() * 1000);
}
refreshStats方法:processAppUsage()计算每个uid的耗电情况, processMiscUsage();//计算比如屏幕、wifi、蓝牙等耗电
public void refreshStats(int statsType, SparseArray asUsers, long rawRealtimeUs,long rawUptimeUs) {.........processAppUsage(asUsers);//计算每个uid的耗电情况包含:CPU Wakelock WIFI 蓝牙 传感器 Camera FlashLight MobileRadio......processMiscUsage();//计算比如屏幕、wifi、蓝牙等耗电......}processAppUsage(asUsers){mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Cpu耗电量计算mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Wakelock耗电量计算mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App MobileRadio耗电量计算mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App WIFI耗电量计算mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App 蓝牙耗电量计算mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App 传感器耗电量计算mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Camera耗电量计算mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);//每个App Flashlight耗电量计算}private void processMiscUsage() {addUserUsage();addPhoneUsage();addScreenUsage();addWiFiUsage();addBluetoothUsage();addIdleUsage(); // Not including cellular idle power// Don't compute radio usage if it's a wifi-only deviceif (!mWifiOnly) {addRadioUsage();}}
- BatteryEntry.java
看源码解释:相当于bean耗电量数据(package name , icon , iconId; // For passing to the detail screen.)
内部维护一个 NameAndIconLoader线程去加载BatteryEntry数据。
/**
41 * Wraps the power usage data of a BatterySipper with information about package name
42 * and icon image.
43 */
构造函数统计硬件软件App信息:
public BatteryEntry(Context context, Handler handler, UserManager um, BatterySipper sipper) {
130 sHandler = handler;
131 this.context = context;
132 this.sipper = sipper;
133 switch (sipper.drainType) {
134 case IDLE:
135 name = context.getResources().getString(R.string.power_idle);
136 iconId = R.drawable.ic_settings_phone_idle;
137 break;
138 case CELL:
139 name = context.getResources().getString(R.string.power_cell);
140 iconId = R.drawable.ic_settings_cell_standby;
141 break;
142 case PHONE://通话
143 name = context.getResources().getString(R.string.power_phone);
144 iconId = R.drawable.ic_settings_voice_calls;
145 break;
146 case WIFI://wifi
147 name = context.getResources().getString(R.string.power_wifi);
148 iconId = R.drawable.ic_settings_wireless;
149 break;
150 case BLUETOOTH://蓝牙
151 name = context.getResources().getString(R.string.power_bluetooth);
152 iconId = R.drawable.ic_settings_bluetooth;
153 break;
154 case SCREEN://屏幕
155 name = context.getResources().getString(R.string.power_screen);
156 iconId = R.drawable.ic_settings_display;
157 break;
158 case FLASHLIGHT:
159 name = context.getResources().getString(R.string.power_flashlight);
160 iconId = R.drawable.ic_settings_display;
161 break;
162 case APP:
163 name = sipper.packageWithHighestDrain;
164 break;
165 case USER: {
166 UserInfo info = um.getUserInfo(sipper.userId);
167 if (info != null) {
168 icon = Utils.getUserIcon(context, um, info);
169 name = Utils.getUserLabel(context, info);
170 } else {
171 icon = null;
172 name = context.getResources().getString(
173 R.string.running_process_item_removed_user_label);
174 }
175 } break;
176 case UNACCOUNTED:
177 name = context.getResources().getString(R.string.power_unaccounted);
178 iconId = R.drawable.ic_power_system;
179 break;
180 case OVERCOUNTED:
181 name = context.getResources().getString(R.string.power_overcounted);
182 iconId = R.drawable.ic_power_system;
183 break;
184 case CAMERA:
185 name = context.getResources().getString(R.string.power_camera);
186 iconId = R.drawable.ic_settings_camera;
187 break;
188 }
189 if (iconId > 0) {
190 icon = context.getDrawable(iconId);
191 }
192 if ((name == null || iconId == 0) && this.sipper.uidObj != null) {
193 getQuickNameIconForUid(this.sipper.uidObj.getUid());
194 }
195 }
总结:
1.Android电量消耗统计在:BatteryStatsHelper类
2.getPowerProfile() 获取PowerProfile,PowerProfile类是(读取power_profile.xml文件)获取Android各部件电流值
3.getStats()获取BatteryStats(App各部件运行时间微秒为单位),通过BatteryStatsService服务类:收集所有消耗电池信息 调用updateExternalStatsSync()从外部获取数据来源(无线控制器,bluetooth芯片组)和更新batterystats信息。
4.refreshState更新电池最新状态
- processAppUsage() :App耗电量统计
- processMiscUsage() :硬件耗电量统计
参考:http://www.cnblogs.com/hyddd/p/4402621.html
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
