Loading core/java/com/android/internal/os/BatteryStatsImpl.java +170 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.net.NetworkStats; import android.net.Uri; import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.BatteryProperty; import android.os.BatteryStats; import android.os.Binder; import android.os.Build; Loading @@ -54,6 +55,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.os.WorkSource.WorkChain; Loading Loading @@ -144,6 +146,14 @@ import java.util.concurrent.locks.ReentrantLock; public class BatteryStatsImpl extends BatteryStats { private static final String TAG = "BatteryStatsImpl"; private static final boolean DEBUG = false; // TODO(b/169376495): STOPSHIP if true private static final boolean DEBUG_FOREGROUND_STATS = true; private static final boolean ENABLE_FOREGROUND_STATS_COLLECTION = DEBUG_FOREGROUND_STATS && SystemProperties.getBoolean( "debug.battery_foreground_stats_collection", false); public static final boolean DEBUG_ENERGY = false; private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY; private static final boolean DEBUG_BINDER_STATS = false; Loading Loading @@ -739,6 +749,37 @@ public class BatteryStatsImpl extends BatteryStats { long mTrackRunningHistoryElapsedRealtimeMs = 0; long mTrackRunningHistoryUptimeMs = 0; private static final int FOREGROUND_UID_INITIAL_CAPACITY = 10; private static final int INVALID_UID = -1; private final IntArray mForegroundUids = ENABLE_FOREGROUND_STATS_COLLECTION ? new IntArray(FOREGROUND_UID_INITIAL_CAPACITY) : null; // Last recorded battery energy capacity. // This is used for computing foregrund power per application. // See: PowerForUid below private long mLastBatteryEnergyCapacityNWh = 0; private static final class PowerForUid { public long energyNwh = 0; // Same as energyNwh, but not tracked for the first 2 minutes; public long filteredEnergyNwh = 0; public double totalHours = 0; public long baseTimeMs = 0; double computePower() { // units in nW return totalHours != 0 ? energyNwh / totalHours : -1.0; } double computeFilteredPower() { // units in nW return totalHours != 0 ? filteredEnergyNwh / totalHours : -1.0; } } private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION ? new HashMap<>() : null; final BatteryStatsHistory mBatteryStatsHistory; final HistoryItem mHistoryCur = new HistoryItem(); Loading Loading @@ -1026,6 +1067,8 @@ public class BatteryStatsImpl extends BatteryStats { private int mNumConnectivityChange; private int mBatteryVolt = -1; private int mBatteryCharge = -1; private int mEstimatedBatteryCapacity = -1; private int mMinLearnedBatteryCapacity = -1; Loading Loading @@ -4154,6 +4197,49 @@ public class BatteryStatsImpl extends BatteryStats { // TODO(b/155216561): It is possible for isolated uids to be in a higher // state than its parent uid. We should track the highest state within the union of host // and isolated uids rather than only the parent uid. int uidState = mapToInternalProcessState(state); boolean isForeground = (uidState == Uid.PROCESS_STATE_TOP) || (uidState == Uid.PROCESS_STATE_FOREGROUND); if (ENABLE_FOREGROUND_STATS_COLLECTION) { boolean previouslyInForegrond = false; for (int i = 0; i < mForegroundUids.size(); i++) { if (mForegroundUids.get(i) == uid) { previouslyInForegrond = true; if (!isForeground) { // If we were previously in the foreground, remove the uid // from the foreground set and dirty the slot. mForegroundUids.set(i, INVALID_UID); final PowerForUid pfu = mUidToPower.computeIfAbsent(uid, unused -> new PowerForUid()); pfu.baseTimeMs = 0; break; } } } if (!previouslyInForegrond && isForeground) { boolean addedToForeground = false; // Check if we have a free slot to clobber... for (int i = 0; i < mForegroundUids.size(); i++) { if (mForegroundUids.get(i) == INVALID_UID) { addedToForeground = true; mForegroundUids.set(i, uid); break; } } // ...if not, append to the end of the array. if (!addedToForeground) { mForegroundUids.add(uid); } } } FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid, ActivityManager.processStateAmToProto(state)); getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) Loading Loading @@ -12968,6 +13054,7 @@ public class BatteryStatsImpl extends BatteryStats { doWrite = true; resetAllStatsLocked(mSecUptime, mSecRealtime); if (chargeUAh > 0 && level > 0) { mBatteryCharge = chargeUAh; // Only use the reported coulomb charge value if it is supported and reported. mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0)); } Loading Loading @@ -13140,6 +13227,47 @@ public class BatteryStatsImpl extends BatteryStats { startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } if (ENABLE_FOREGROUND_STATS_COLLECTION) { mBatteryVolt = volt; if (onBattery) { final long energyNwh = (volt * (long) chargeUAh); final long energyDelta = mLastBatteryEnergyCapacityNWh - energyNwh; for (int i = 0; i < mForegroundUids.size(); i++) { final int uid = mForegroundUids.get(i); if (uid == INVALID_UID) { continue; } final PowerForUid pfu = mUidToPower .computeIfAbsent(uid, unused -> new PowerForUid()); if (pfu.baseTimeMs <= 0) { pfu.baseTimeMs = currentTimeMs; } else { // Check if mLastBatteryEnergyCapacityNWh > energyNwh, // to make sure we only count discharges if (energyDelta > 0) { pfu.energyNwh += energyDelta; // Convert from milliseconds to hours // 1000 ms per second * 3600 seconds per hour pfu.totalHours += ((double) (currentTimeMs - pfu.baseTimeMs) / (1.0 * 1000 * 60 * 60)); // Now convert from 2 minutes to hours // 2 minutes = 1/30 of an hour if (pfu.totalHours > (2.0 / 60)) { pfu.filteredEnergyNwh += energyDelta; } } pfu.baseTimeMs = currentTimeMs; } } mLastBatteryEnergyCapacityNWh = energyNwh; } else if (onBattery != mOnBattery) { // Transition to onBattery = false mUidToPower.values().forEach(v -> v.baseTimeMs = 0); } } mCurrentBatteryLevel = level; if (mDischargePlugLevel < 0) { mDischargePlugLevel = level; Loading Loading @@ -16056,6 +16184,48 @@ public class BatteryStatsImpl extends BatteryStats { } public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) { if (ENABLE_FOREGROUND_STATS_COLLECTION) { long actualCharge = -1; long actualEnergy = -1; try { IBatteryPropertiesRegistrar registrar = IBatteryPropertiesRegistrar.Stub.asInterface( ServiceManager.getService("batteryproperties")); if (registrar != null) { BatteryProperty prop = new BatteryProperty(); if (registrar.getProperty( BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER, prop) == 0) { actualCharge = prop.getLong(); } prop = new BatteryProperty(); if (registrar.getProperty( BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER, prop) == 0) { actualEnergy = prop.getLong(); } } } catch (RemoteException e) { // Ignore. } pw.printf("ActualCharge (uAh): %d\n", (int) actualCharge); pw.printf("ActualEnergy (nWh): %d\n", actualEnergy); pw.printf("mBatteryCharge (uAh): %d\n", mBatteryCharge); pw.printf("mBatteryVolts (mV): %d\n", mBatteryVolt); pw.printf("est energy (nWh): %d\n", mBatteryVolt * (long) mBatteryCharge); pw.printf("mEstimatedBatteryCapacity (mAh): %d\n", mEstimatedBatteryCapacity); pw.printf("mMinLearnedBatteryCapacity (uAh): %d\n", mMinLearnedBatteryCapacity); pw.printf("mMaxLearnedBatteryCapacity (uAh): %d\n", mMaxLearnedBatteryCapacity); pw.printf("est. capacity: %f\n", (float) actualCharge / (mEstimatedBatteryCapacity * 1000)); pw.printf("mCurrentBatteryLevel: %d\n", mCurrentBatteryLevel); pw.println("Total Power per app:"); mUidToPower.entrySet().forEach(e -> pw.printf("Uid: %d, Total watts (nW): %f\n", e.getKey(), e.getValue().computePower())); pw.println("Total Power per app after first 2 minutes initial launch:"); mUidToPower.entrySet().forEach(e -> pw.printf("Uid: %d, Total watts (nW): %f\n", e.getKey(), e.getValue().computeFilteredPower())); } if (DEBUG) { pw.println("mOnBatteryTimeBase:"); mOnBatteryTimeBase.dump(pw, " "); Loading
core/java/com/android/internal/os/BatteryStatsImpl.java +170 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.net.NetworkStats; import android.net.Uri; import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.BatteryProperty; import android.os.BatteryStats; import android.os.Binder; import android.os.Build; Loading @@ -54,6 +55,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.WorkSource; import android.os.WorkSource.WorkChain; Loading Loading @@ -144,6 +146,14 @@ import java.util.concurrent.locks.ReentrantLock; public class BatteryStatsImpl extends BatteryStats { private static final String TAG = "BatteryStatsImpl"; private static final boolean DEBUG = false; // TODO(b/169376495): STOPSHIP if true private static final boolean DEBUG_FOREGROUND_STATS = true; private static final boolean ENABLE_FOREGROUND_STATS_COLLECTION = DEBUG_FOREGROUND_STATS && SystemProperties.getBoolean( "debug.battery_foreground_stats_collection", false); public static final boolean DEBUG_ENERGY = false; private static final boolean DEBUG_ENERGY_CPU = DEBUG_ENERGY; private static final boolean DEBUG_BINDER_STATS = false; Loading Loading @@ -739,6 +749,37 @@ public class BatteryStatsImpl extends BatteryStats { long mTrackRunningHistoryElapsedRealtimeMs = 0; long mTrackRunningHistoryUptimeMs = 0; private static final int FOREGROUND_UID_INITIAL_CAPACITY = 10; private static final int INVALID_UID = -1; private final IntArray mForegroundUids = ENABLE_FOREGROUND_STATS_COLLECTION ? new IntArray(FOREGROUND_UID_INITIAL_CAPACITY) : null; // Last recorded battery energy capacity. // This is used for computing foregrund power per application. // See: PowerForUid below private long mLastBatteryEnergyCapacityNWh = 0; private static final class PowerForUid { public long energyNwh = 0; // Same as energyNwh, but not tracked for the first 2 minutes; public long filteredEnergyNwh = 0; public double totalHours = 0; public long baseTimeMs = 0; double computePower() { // units in nW return totalHours != 0 ? energyNwh / totalHours : -1.0; } double computeFilteredPower() { // units in nW return totalHours != 0 ? filteredEnergyNwh / totalHours : -1.0; } } private final HashMap<Integer, PowerForUid> mUidToPower = ENABLE_FOREGROUND_STATS_COLLECTION ? new HashMap<>() : null; final BatteryStatsHistory mBatteryStatsHistory; final HistoryItem mHistoryCur = new HistoryItem(); Loading Loading @@ -1026,6 +1067,8 @@ public class BatteryStatsImpl extends BatteryStats { private int mNumConnectivityChange; private int mBatteryVolt = -1; private int mBatteryCharge = -1; private int mEstimatedBatteryCapacity = -1; private int mMinLearnedBatteryCapacity = -1; Loading Loading @@ -4154,6 +4197,49 @@ public class BatteryStatsImpl extends BatteryStats { // TODO(b/155216561): It is possible for isolated uids to be in a higher // state than its parent uid. We should track the highest state within the union of host // and isolated uids rather than only the parent uid. int uidState = mapToInternalProcessState(state); boolean isForeground = (uidState == Uid.PROCESS_STATE_TOP) || (uidState == Uid.PROCESS_STATE_FOREGROUND); if (ENABLE_FOREGROUND_STATS_COLLECTION) { boolean previouslyInForegrond = false; for (int i = 0; i < mForegroundUids.size(); i++) { if (mForegroundUids.get(i) == uid) { previouslyInForegrond = true; if (!isForeground) { // If we were previously in the foreground, remove the uid // from the foreground set and dirty the slot. mForegroundUids.set(i, INVALID_UID); final PowerForUid pfu = mUidToPower.computeIfAbsent(uid, unused -> new PowerForUid()); pfu.baseTimeMs = 0; break; } } } if (!previouslyInForegrond && isForeground) { boolean addedToForeground = false; // Check if we have a free slot to clobber... for (int i = 0; i < mForegroundUids.size(); i++) { if (mForegroundUids.get(i) == INVALID_UID) { addedToForeground = true; mForegroundUids.set(i, uid); break; } } // ...if not, append to the end of the array. if (!addedToForeground) { mForegroundUids.add(uid); } } } FrameworkStatsLog.write(FrameworkStatsLog.UID_PROCESS_STATE_CHANGED, uid, ActivityManager.processStateAmToProto(state)); getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs) Loading Loading @@ -12968,6 +13054,7 @@ public class BatteryStatsImpl extends BatteryStats { doWrite = true; resetAllStatsLocked(mSecUptime, mSecRealtime); if (chargeUAh > 0 && level > 0) { mBatteryCharge = chargeUAh; // Only use the reported coulomb charge value if it is supported and reported. mEstimatedBatteryCapacity = (int) ((chargeUAh / 1000) / (level / 100.0)); } Loading Loading @@ -13140,6 +13227,47 @@ public class BatteryStatsImpl extends BatteryStats { startRecordingHistory(elapsedRealtimeMs, uptimeMs, true); } } if (ENABLE_FOREGROUND_STATS_COLLECTION) { mBatteryVolt = volt; if (onBattery) { final long energyNwh = (volt * (long) chargeUAh); final long energyDelta = mLastBatteryEnergyCapacityNWh - energyNwh; for (int i = 0; i < mForegroundUids.size(); i++) { final int uid = mForegroundUids.get(i); if (uid == INVALID_UID) { continue; } final PowerForUid pfu = mUidToPower .computeIfAbsent(uid, unused -> new PowerForUid()); if (pfu.baseTimeMs <= 0) { pfu.baseTimeMs = currentTimeMs; } else { // Check if mLastBatteryEnergyCapacityNWh > energyNwh, // to make sure we only count discharges if (energyDelta > 0) { pfu.energyNwh += energyDelta; // Convert from milliseconds to hours // 1000 ms per second * 3600 seconds per hour pfu.totalHours += ((double) (currentTimeMs - pfu.baseTimeMs) / (1.0 * 1000 * 60 * 60)); // Now convert from 2 minutes to hours // 2 minutes = 1/30 of an hour if (pfu.totalHours > (2.0 / 60)) { pfu.filteredEnergyNwh += energyDelta; } } pfu.baseTimeMs = currentTimeMs; } } mLastBatteryEnergyCapacityNWh = energyNwh; } else if (onBattery != mOnBattery) { // Transition to onBattery = false mUidToPower.values().forEach(v -> v.baseTimeMs = 0); } } mCurrentBatteryLevel = level; if (mDischargePlugLevel < 0) { mDischargePlugLevel = level; Loading Loading @@ -16056,6 +16184,48 @@ public class BatteryStatsImpl extends BatteryStats { } public void dumpLocked(Context context, PrintWriter pw, int flags, int reqUid, long histStart) { if (ENABLE_FOREGROUND_STATS_COLLECTION) { long actualCharge = -1; long actualEnergy = -1; try { IBatteryPropertiesRegistrar registrar = IBatteryPropertiesRegistrar.Stub.asInterface( ServiceManager.getService("batteryproperties")); if (registrar != null) { BatteryProperty prop = new BatteryProperty(); if (registrar.getProperty( BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER, prop) == 0) { actualCharge = prop.getLong(); } prop = new BatteryProperty(); if (registrar.getProperty( BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER, prop) == 0) { actualEnergy = prop.getLong(); } } } catch (RemoteException e) { // Ignore. } pw.printf("ActualCharge (uAh): %d\n", (int) actualCharge); pw.printf("ActualEnergy (nWh): %d\n", actualEnergy); pw.printf("mBatteryCharge (uAh): %d\n", mBatteryCharge); pw.printf("mBatteryVolts (mV): %d\n", mBatteryVolt); pw.printf("est energy (nWh): %d\n", mBatteryVolt * (long) mBatteryCharge); pw.printf("mEstimatedBatteryCapacity (mAh): %d\n", mEstimatedBatteryCapacity); pw.printf("mMinLearnedBatteryCapacity (uAh): %d\n", mMinLearnedBatteryCapacity); pw.printf("mMaxLearnedBatteryCapacity (uAh): %d\n", mMaxLearnedBatteryCapacity); pw.printf("est. capacity: %f\n", (float) actualCharge / (mEstimatedBatteryCapacity * 1000)); pw.printf("mCurrentBatteryLevel: %d\n", mCurrentBatteryLevel); pw.println("Total Power per app:"); mUidToPower.entrySet().forEach(e -> pw.printf("Uid: %d, Total watts (nW): %f\n", e.getKey(), e.getValue().computePower())); pw.println("Total Power per app after first 2 minutes initial launch:"); mUidToPower.entrySet().forEach(e -> pw.printf("Uid: %d, Total watts (nW): %f\n", e.getKey(), e.getValue().computeFilteredPower())); } if (DEBUG) { pw.println("mOnBatteryTimeBase:"); mOnBatteryTimeBase.dump(pw, " ");