还没有完成的,初稿
App耗电量统计:源码
BatteryHistoryPreference类--sp 获取耗电量历史(读取sp文件)--sp文件数据来自xml文件(power_usage_summary.xml)
PreferenceGroup类--统计所有App耗电量同history
refreshStats()方法刷新耗电量状态:内部有以下几个类(BatteryStatsHelper.java)获取
1.PowerProfile:提供部件电流数值。
2.BatteryStats:App各部件运行时间。(获取封装在BatteryStatsHelper类中具体看下面)
final BatteryStats stats = mStatsHelper.getStats();
3.根据BatteryStatsHelper类中统计
- App耗电量统计:processAppUsage()
- 硬件耗电量统计:processMiscUsage()
获取耗电量更新SP数据: mAppListGroup.addPreference(pref);
(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>
/**
* 统计电池各部件使用情况,时间以微秒为单位
* 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";
....
}
@Override
public 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 device
if (!mWifiOnly) {
addRadioUsage();
}
}
看源码解释:相当于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