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


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部