Merge "Make SystemHealthManager.takeUidSnapshot call async" into main
diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java
index 322a8e6..deabfed 100644
--- a/core/java/android/os/health/SystemHealthManager.java
+++ b/core/java/android/os/health/SystemHealthManager.java
@@ -33,13 +33,16 @@
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;
/**
@@ -67,6 +70,14 @@
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.
@@ -111,12 +122,19 @@
* @see Process#myUid() Process.myUid()
*/
public HealthStats takeUidSnapshot(int uid) {
- try {
- final HealthStatsParceler parceler = mBatteryStats.takeUidSnapshot(uid);
- return parceler.getHealthStats();
- } catch (RemoteException ex) {
- throw new RuntimeException(ex);
+ if (!Flags.onewayBatteryStatsService()) {
+ try {
+ final HealthStatsParceler parceler = mBatteryStats.takeUidSnapshot(uid);
+ return parceler.getHealthStats();
+ } catch (RemoteException ex) {
+ throw ex.rethrowFromSystemServer();
+ }
}
+ final HealthStats[] result = takeUidSnapshots(new int[]{uid});
+ if (result != null && result.length >= 1) {
+ return result[0];
+ }
+ return null;
}
/**
@@ -144,17 +162,61 @@
* other than its own.
*/
public HealthStats[] takeUidSnapshots(int[] uids) {
- 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++) {
- results[i] = parcelers[i].getHealthStats();
+ if (!Flags.onewayBatteryStatsService()) {
+ try {
+ final HealthStatsParceler[] parcelers = mBatteryStats.takeUidSnapshots(uids);
+ 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 ex.rethrowFromSystemServer();
}
- return results;
- } catch (RemoteException ex) {
- throw new RuntimeException(ex);
}
+
+ 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;
}
/**
diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index 99b3f9a..ebcae27 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -21,6 +21,7 @@
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;
@@ -33,6 +34,9 @@
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")
@@ -256,6 +260,9 @@
@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")
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 7c0325e..d642b02 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -60,6 +60,7 @@
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;
@@ -71,6 +72,7 @@
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;
@@ -3337,6 +3339,59 @@
}
}
+ /**
+ * 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();
diff --git a/services/core/java/com/android/server/power/stats/flags.aconfig b/services/core/java/com/android/server/power/stats/flags.aconfig
index 9283fe9..6a5a7ac 100644
--- a/services/core/java/com/android/server/power/stats/flags.aconfig
+++ b/services/core/java/com/android/server/power/stats/flags.aconfig
@@ -37,3 +37,13 @@
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
+ }
+}