Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 667df8bb authored by Dmitri Plotnikov's avatar Dmitri Plotnikov Committed by Android (Google) Code Review
Browse files

Merge "Make SystemHealthManager.takeUidSnapshot call async" into main

parents bf23bfff c0d8b4eb
Loading
Loading
Loading
Loading
+75 −13
Original line number Diff line number Diff line
@@ -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;

/**
@@ -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.
@@ -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;
    }

    /**
@@ -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
+7 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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")
@@ -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")
+55 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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();
+10 −0
Original line number Diff line number Diff line
@@ -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
    }
}