1. 电池用量时间一直为0
2. 源码跟踪
2.1 字符串位置
<string name="battery_detail_foreground" msgid="3350401514602032183">"在前台运行时"</string>
<string name="battery_detail_background" msgid="1929644393553768999">"在后台运行时"</string>
2.2 布局文件
power_usage_detail.xml
<PreferenceCategory
android:title="@string/battery_detail_info_title">
<Preference
// 前台进程运行
android:key="app_usage_foreground"
android:title="@string/battery_detail_foreground"
android:selectable="false"/>
<Preference
// 后台进程运行
android:key="app_usage_background"
android:title="@string/battery_detail_background"
android:selectable="false"/>
<Preference
// 电池耗电量
android:key="app_power_usage"
android:title="@string/battery_detail_power_usage"
android:selectable="false"/>
</PreferenceCategory>
2.3 控件定义
package com.android.settings.fuelgauge;
/**
* Power usage detail fragment for each app, this fragment contains
*
* 1. Detail battery usage information for app(i.e. usage time, usage amount)
* 2. Battery related controls for app(i.e uninstall, force stop)
*/
public class AdvancedPowerUsageDetail extends DashboardFragment implements
ButtonActionDialogFragment.AppButtonsDialogListener,
AnomalyDialogFragment.AnomalyDialogListener,
LoaderManager.LoaderCallbacks<List<Anomaly>> {
private static final String KEY_PREF_FOREGROUND = "app_usage_foreground";
private static final String KEY_PREF_BACKGROUND = "app_usage_background";
private static final String KEY_PREF_POWER_USAGE = "app_power_usage";
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mForegroundPreference = findPreference(KEY_PREF_FOREGROUND);
mBackgroundPreference = findPreference(KEY_PREF_BACKGROUND);
mPowerUsagePreference = findPreference(KEY_PREF_POWER_USAGE);
2.4 控件赋值
@VisibleForTesting
void initPreference() {
final Bundle bundle = getArguments();
final Context context = getContext();
final long foregroundTimeMs = bundle.getLong(EXTRA_FOREGROUND_TIME);
final long backgroundTimeMs = bundle.getLong(EXTRA_BACKGROUND_TIME);
final String usagePercent = bundle.getString(EXTRA_POWER_USAGE_PERCENT);
final int powerMah = bundle.getInt(EXTRA_POWER_USAGE_AMOUNT);
mForegroundPreference.setSummary(
TextUtils.expandTemplate(getText(R.string.battery_used_for),
Utils.formatElapsedTime(context, foregroundTimeMs, false)));
mBackgroundPreference.setSummary(
TextUtils.expandTemplate(getText(R.string.battery_active_for),
Utils.formatElapsedTime(context, backgroundTimeMs, false)));
mPowerUsagePreference.setSummary(
getString(R.string.battery_detail_power_percentage, usagePercent, powerMah));
}
2.5 运行时间获取 startBatteryDetailPage.args.putLong
package com.android.settings.fuelgauge;
/**
* Power usage detail fragment for each app, this fragment contains
*
* 1. Detail battery usage information for app(i.e. usage time, usage amount)
* 2. Battery related controls for app(i.e uninstall, force stop)
*/
public class AdvancedPowerUsageDetail extends DashboardFragment implements
ButtonActionDialogFragment.AppButtonsDialogListener,
AnomalyDialogFragment.AnomalyDialogListener,
LoaderManager.LoaderCallbacks<List<Anomaly>> {
@VisibleForTesting
static void startBatteryDetailPage(SettingsActivity caller, BatteryUtils batteryUtils,
PreferenceFragment fragment, BatteryStatsHelper helper, int which, BatteryEntry entry,
String usagePercent, List<Anomaly> anomalies) {
......
final Bundle args = new Bundle();
final BatterySipper sipper = entry.sipper;
final BatteryStats.Uid uid = sipper.uidObj;
final boolean isTypeApp = sipper.drainType == BatterySipper.DrainType.APP;
final long foregroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs(
BatteryUtils.StatusType.FOREGROUND, uid, which) : sipper.usageTimeMs;
final long backgroundTimeMs = isTypeApp ? batteryUtils.getProcessTimeMs(
BatteryUtils.StatusType.BACKGROUND, uid, which) : 0;
......
args.putInt(EXTRA_UID, sipper.getUid());
args.putLong(EXTRA_BACKGROUND_TIME, backgroundTimeMs);
args.putLong(EXTRA_FOREGROUND_TIME, foregroundTimeMs);
args.putString(EXTRA_POWER_USAGE_PERCENT, usagePercent);
args.putInt(EXTRA_POWER_USAGE_AMOUNT, (int) sipper.totalPowerMah);
args.putParcelableList(EXTRA_ANOMALY_LIST, anomalies);
2.6 运行时间获取 batteryUtils.getProcessTimeMs
package com.android.settings.fuelgauge;
/**
* Utils for battery operation
*/
public class BatteryUtils {
public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid,
int which) {
if (uid == null) {
return 0;
}
switch (type) {
case StatusType.SCREEN_USAGE:
return getScreenUsageTimeMs(uid, which);
case StatusType.FOREGROUND:
return getProcessForegroundTimeMs(uid, which);
case StatusType.BACKGROUND:
return getProcessBackgroundTimeMs(uid, which);
case StatusType.ALL:
return getProcessForegroundTimeMs(uid, which)
+ getProcessBackgroundTimeMs(uid, which);
}
return 0;
}
2.6 运行时间获取 BatteryUtils.getProcessForegroundTimeMs
adb shell logcat -s “BatteryUtils”
private static final String TAG = "BatteryUtils";
private long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) {
final long rawRealTimeUs = convertMsToUs(SystemClock.elapsedRealtime());
return getScreenUsageTimeMs(uid, which, rawRealTimeUs)
+ convertUsToMs(getForegroundServiceTotalTimeUs(uid, rawRealTimeUs));
}
// 屏幕使用时间
private long getScreenUsageTimeMs(BatteryStats.Uid uid, int which, long rawRealTimeUs) {
final int foregroundTypes[] = {BatteryStats.Uid.PROCESS_STATE_TOP};
Log.v(TAG, "package: " + mPackageManager.getNameForUid(uid.getUid()));
long timeUs = 0;
for (int type : foregroundTypes) {
final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, which);
Log.v(TAG, "type: " + type + " time(us): " + localTime);
timeUs += localTime;
}
Log.v(TAG, "foreground time(us): " + timeUs);
// Return the min value of STATE_TOP time and foreground activity time, since both of these
// time have some errors
return convertUsToMs(
Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)));
}
// 进程前台运行时间
@VisibleForTesting
long getForegroundServiceTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) {
final BatteryStats.Timer timer = uid.getForegroundServiceTimer();
if (timer != null) {
return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
}
return 0;
}