Loading core/java/android/os/health/SystemHealthManager.java +75 −13 Original line number Diff line number Diff line Loading @@ -33,13 +33,16 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.SynchronousResultReceiver; import com.android.internal.app.IBatteryStats; import com.android.server.power.optimization.Flags; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; /** Loading Loading @@ -67,6 +70,14 @@ public class SystemHealthManager { private final IPowerStatsService mPowerStats; private List<PowerMonitor> mPowerMonitorsInfo; private final Object mPowerMonitorsLock = new Object(); private static final long TAKE_UID_SNAPSHOT_TIMEOUT_MILLIS = 10_000; private static class PendingUidSnapshots { public int[] uids; public SynchronousResultReceiver resultReceiver; } private final PendingUidSnapshots mPendingUidSnapshots = new PendingUidSnapshots(); /** * Construct a new SystemHealthManager object. Loading Loading @@ -111,12 +122,19 @@ public class SystemHealthManager { * @see Process#myUid() Process.myUid() */ public HealthStats takeUidSnapshot(int uid) { if (!Flags.onewayBatteryStatsService()) { try { final HealthStatsParceler parceler = mBatteryStats.takeUidSnapshot(uid); return parceler.getHealthStats(); } catch (RemoteException ex) { throw new RuntimeException(ex); throw ex.rethrowFromSystemServer(); } } final HealthStats[] result = takeUidSnapshots(new int[]{uid}); if (result != null && result.length >= 1) { return result[0]; } return null; } /** Loading Loading @@ -144,19 +162,63 @@ public class SystemHealthManager { * other than its own. */ public HealthStats[] takeUidSnapshots(int[] uids) { if (!Flags.onewayBatteryStatsService()) { try { final HealthStatsParceler[] parcelers = mBatteryStats.takeUidSnapshots(uids); final HealthStats[] results = new HealthStats[uids.length]; final int N = uids.length; for (int i = 0; i < N; i++) { final int count = uids.length; final HealthStats[] results = new HealthStats[count]; for (int i = 0; i < count; i++) { results[i] = parcelers[i].getHealthStats(); } return results; } catch (RemoteException ex) { throw new RuntimeException(ex); throw ex.rethrowFromSystemServer(); } } SynchronousResultReceiver resultReceiver; synchronized (mPendingUidSnapshots) { if (Arrays.equals(mPendingUidSnapshots.uids, uids)) { resultReceiver = mPendingUidSnapshots.resultReceiver; } else { mPendingUidSnapshots.uids = Arrays.copyOf(uids, uids.length); mPendingUidSnapshots.resultReceiver = resultReceiver = new SynchronousResultReceiver("takeUidSnapshots"); try { mBatteryStats.takeUidSnapshotsAsync(uids, resultReceiver); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } } SynchronousResultReceiver.Result result; try { result = resultReceiver.awaitResult(TAKE_UID_SNAPSHOT_TIMEOUT_MILLIS); } catch (TimeoutException e) { throw new RuntimeException(e); } finally { synchronized (mPendingUidSnapshots) { if (mPendingUidSnapshots.resultReceiver == resultReceiver) { mPendingUidSnapshots.uids = null; mPendingUidSnapshots.resultReceiver = null; } } } final HealthStats[] results = new HealthStats[uids.length]; if (result.bundle != null) { HealthStatsParceler[] parcelers = result.bundle.getParcelableArray( IBatteryStats.KEY_UID_SNAPSHOTS, HealthStatsParceler.class); if (parcelers != null && parcelers.length == uids.length) { for (int i = 0; i < parcelers.length; i++) { results[i] = parcelers[i].getHealthStats(); } } } return results; } /** * Asynchronously retrieves a list of supported {@link PowerMonitor}'s, which include raw ODPM * (on-device power rail monitor) rails and modeled energy consumers. If ODPM is unsupported Loading core/java/com/android/internal/app/IBatteryStats.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.BluetoothBatteryStats; import android.os.ParcelFileDescriptor; import android.os.ResultReceiver; import android.os.WakeLockStats; import android.os.WorkSource; import android.os.connectivity.CellularBatteryStats; Loading @@ -33,6 +34,9 @@ import android.telephony.ModemActivityInfo; import android.telephony.SignalStrength; interface IBatteryStats { /** @hide */ const String KEY_UID_SNAPSHOTS = "uid_snapshots"; // These first methods are also called by native code, so must // be kept in sync with frameworks/native/libs/binder/include_batterystats/batterystats/IBatteryStats.h @EnforcePermission("UPDATE_DEVICE_STATS") Loading Loading @@ -256,6 +260,9 @@ interface IBatteryStats { @PermissionManuallyEnforced HealthStatsParceler[] takeUidSnapshots(in int[] uid); @PermissionManuallyEnforced oneway void takeUidSnapshotsAsync(in int[] uid, in ResultReceiver result); @EnforcePermission("UPDATE_DEVICE_STATS") oneway void noteBluetoothControllerActivity(in BluetoothActivityEnergyInfo info); @EnforcePermission("UPDATE_DEVICE_STATS") Loading services/core/java/com/android/server/am/BatteryStatsService.java +55 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.Binder; import android.os.BluetoothBatteryStats; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; Loading @@ -71,6 +72,7 @@ import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.SystemClock; import android.os.Trace; Loading Loading @@ -3337,6 +3339,59 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } /** * Gets a snapshot of the system health for a number of uids. */ @Override public void takeUidSnapshotsAsync(int[] requestUids, ResultReceiver resultReceiver) { if (!onlyCaller(requestUids)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BATTERY_STATS, null); } Future future; if (shouldCollectExternalStats()) { future = mWorker.scheduleSync("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL); } else { future = null; } mHandler.post(() -> { if (future != null) { try { // Worker uses a separate thread pool, so waiting here won't cause a deadlock future.get(); } catch (InterruptedException | ExecutionException e) { Slog.e(TAG, "Sync failed", e); } } final long ident = Binder.clearCallingIdentity(); int i = -1; try { final int count = requestUids.length; final HealthStatsParceler[] results = new HealthStatsParceler[count]; synchronized (mStats) { for (i = 0; i < count; i++) { results[i] = getHealthStatsForUidLocked(requestUids[i]); } } Bundle resultData = new Bundle(1); resultData.putParcelableArray(IBatteryStats.KEY_UID_SNAPSHOTS, results); resultReceiver.send(0, resultData); } catch (Exception ex) { if (DBG) { Slog.d(TAG, "Crashed while returning results for takeUidSnapshots(" + Arrays.toString(requestUids) + ") i=" + i, ex); } throw ex; } finally { Binder.restoreCallingIdentity(ident); } }); } private boolean shouldCollectExternalStats() { return (SystemClock.elapsedRealtime() - mWorker.getLastCollectionTimeStamp()) > mStats.getExternalStatsCollectionRateLimitMs(); Loading services/core/java/com/android/server/power/stats/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -37,3 +37,13 @@ flag { description: "Feature flag for streamlined misc (excluding CPU, Cell, Wifi, BT) battery stats" bug: "333941740" } flag { name: "oneway_battery_stats_service" namespace: "backstage_power" description: "Bugfix flag for locking issues and watchdog kills in BatteryStatsService" bug: "330792526" metadata { purpose: PURPOSE_BUGFIX } } Loading
core/java/android/os/health/SystemHealthManager.java +75 −13 Original line number Diff line number Diff line Loading @@ -33,13 +33,16 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.SynchronousResultReceiver; import com.android.internal.app.IBatteryStats; import com.android.server.power.optimization.Flags; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; /** Loading Loading @@ -67,6 +70,14 @@ public class SystemHealthManager { private final IPowerStatsService mPowerStats; private List<PowerMonitor> mPowerMonitorsInfo; private final Object mPowerMonitorsLock = new Object(); private static final long TAKE_UID_SNAPSHOT_TIMEOUT_MILLIS = 10_000; private static class PendingUidSnapshots { public int[] uids; public SynchronousResultReceiver resultReceiver; } private final PendingUidSnapshots mPendingUidSnapshots = new PendingUidSnapshots(); /** * Construct a new SystemHealthManager object. Loading Loading @@ -111,12 +122,19 @@ public class SystemHealthManager { * @see Process#myUid() Process.myUid() */ public HealthStats takeUidSnapshot(int uid) { if (!Flags.onewayBatteryStatsService()) { try { final HealthStatsParceler parceler = mBatteryStats.takeUidSnapshot(uid); return parceler.getHealthStats(); } catch (RemoteException ex) { throw new RuntimeException(ex); throw ex.rethrowFromSystemServer(); } } final HealthStats[] result = takeUidSnapshots(new int[]{uid}); if (result != null && result.length >= 1) { return result[0]; } return null; } /** Loading Loading @@ -144,19 +162,63 @@ public class SystemHealthManager { * other than its own. */ public HealthStats[] takeUidSnapshots(int[] uids) { if (!Flags.onewayBatteryStatsService()) { try { final HealthStatsParceler[] parcelers = mBatteryStats.takeUidSnapshots(uids); final HealthStats[] results = new HealthStats[uids.length]; final int N = uids.length; for (int i = 0; i < N; i++) { final int count = uids.length; final HealthStats[] results = new HealthStats[count]; for (int i = 0; i < count; i++) { results[i] = parcelers[i].getHealthStats(); } return results; } catch (RemoteException ex) { throw new RuntimeException(ex); throw ex.rethrowFromSystemServer(); } } SynchronousResultReceiver resultReceiver; synchronized (mPendingUidSnapshots) { if (Arrays.equals(mPendingUidSnapshots.uids, uids)) { resultReceiver = mPendingUidSnapshots.resultReceiver; } else { mPendingUidSnapshots.uids = Arrays.copyOf(uids, uids.length); mPendingUidSnapshots.resultReceiver = resultReceiver = new SynchronousResultReceiver("takeUidSnapshots"); try { mBatteryStats.takeUidSnapshotsAsync(uids, resultReceiver); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } } SynchronousResultReceiver.Result result; try { result = resultReceiver.awaitResult(TAKE_UID_SNAPSHOT_TIMEOUT_MILLIS); } catch (TimeoutException e) { throw new RuntimeException(e); } finally { synchronized (mPendingUidSnapshots) { if (mPendingUidSnapshots.resultReceiver == resultReceiver) { mPendingUidSnapshots.uids = null; mPendingUidSnapshots.resultReceiver = null; } } } final HealthStats[] results = new HealthStats[uids.length]; if (result.bundle != null) { HealthStatsParceler[] parcelers = result.bundle.getParcelableArray( IBatteryStats.KEY_UID_SNAPSHOTS, HealthStatsParceler.class); if (parcelers != null && parcelers.length == uids.length) { for (int i = 0; i < parcelers.length; i++) { results[i] = parcelers[i].getHealthStats(); } } } return results; } /** * Asynchronously retrieves a list of supported {@link PowerMonitor}'s, which include raw ODPM * (on-device power rail monitor) rails and modeled energy consumers. If ODPM is unsupported Loading
core/java/com/android/internal/app/IBatteryStats.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.BluetoothBatteryStats; import android.os.ParcelFileDescriptor; import android.os.ResultReceiver; import android.os.WakeLockStats; import android.os.WorkSource; import android.os.connectivity.CellularBatteryStats; Loading @@ -33,6 +34,9 @@ import android.telephony.ModemActivityInfo; import android.telephony.SignalStrength; interface IBatteryStats { /** @hide */ const String KEY_UID_SNAPSHOTS = "uid_snapshots"; // These first methods are also called by native code, so must // be kept in sync with frameworks/native/libs/binder/include_batterystats/batterystats/IBatteryStats.h @EnforcePermission("UPDATE_DEVICE_STATS") Loading Loading @@ -256,6 +260,9 @@ interface IBatteryStats { @PermissionManuallyEnforced HealthStatsParceler[] takeUidSnapshots(in int[] uid); @PermissionManuallyEnforced oneway void takeUidSnapshotsAsync(in int[] uid, in ResultReceiver result); @EnforcePermission("UPDATE_DEVICE_STATS") oneway void noteBluetoothControllerActivity(in BluetoothActivityEnergyInfo info); @EnforcePermission("UPDATE_DEVICE_STATS") Loading
services/core/java/com/android/server/am/BatteryStatsService.java +55 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ import android.os.BatteryUsageStats; import android.os.BatteryUsageStatsQuery; import android.os.Binder; import android.os.BluetoothBatteryStats; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; Loading @@ -71,6 +72,7 @@ import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.SystemClock; import android.os.Trace; Loading Loading @@ -3337,6 +3339,59 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } /** * Gets a snapshot of the system health for a number of uids. */ @Override public void takeUidSnapshotsAsync(int[] requestUids, ResultReceiver resultReceiver) { if (!onlyCaller(requestUids)) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BATTERY_STATS, null); } Future future; if (shouldCollectExternalStats()) { future = mWorker.scheduleSync("get-health-stats-for-uids", BatteryExternalStatsWorker.UPDATE_ALL); } else { future = null; } mHandler.post(() -> { if (future != null) { try { // Worker uses a separate thread pool, so waiting here won't cause a deadlock future.get(); } catch (InterruptedException | ExecutionException e) { Slog.e(TAG, "Sync failed", e); } } final long ident = Binder.clearCallingIdentity(); int i = -1; try { final int count = requestUids.length; final HealthStatsParceler[] results = new HealthStatsParceler[count]; synchronized (mStats) { for (i = 0; i < count; i++) { results[i] = getHealthStatsForUidLocked(requestUids[i]); } } Bundle resultData = new Bundle(1); resultData.putParcelableArray(IBatteryStats.KEY_UID_SNAPSHOTS, results); resultReceiver.send(0, resultData); } catch (Exception ex) { if (DBG) { Slog.d(TAG, "Crashed while returning results for takeUidSnapshots(" + Arrays.toString(requestUids) + ") i=" + i, ex); } throw ex; } finally { Binder.restoreCallingIdentity(ident); } }); } private boolean shouldCollectExternalStats() { return (SystemClock.elapsedRealtime() - mWorker.getLastCollectionTimeStamp()) > mStats.getExternalStatsCollectionRateLimitMs(); Loading
services/core/java/com/android/server/power/stats/flags.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -37,3 +37,13 @@ flag { description: "Feature flag for streamlined misc (excluding CPU, Cell, Wifi, BT) battery stats" bug: "333941740" } flag { name: "oneway_battery_stats_service" namespace: "backstage_power" description: "Bugfix flag for locking issues and watchdog kills in BatteryStatsService" bug: "330792526" metadata { purpose: PURPOSE_BUGFIX } }