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

Commit 2c3ba852 authored by Fiona Campbell's avatar Fiona Campbell
Browse files

Create Sleeplocks API

- expose sleeplock class in powermanager
- expose goToSleep() as a testApi
- config.xml for max timeout
- config.xml for to allow usage of sleeplocks
- create and use permissions

Bug: 432748764
Flag: com.android.server.power.feature.flags.partial_sleep_wakelocks
Test: atest PowerServiceTests

Change-Id: Ia7df374484a9d56092665acb77e4c6d3bbfef87f
parent 3d57c36d
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ package android {
    field public static final String ACCESS_TV_TUNER = "android.permission.ACCESS_TV_TUNER";
    field public static final String ACCESS_ULTRASOUND = "android.permission.ACCESS_ULTRASOUND";
    field public static final String ACCESS_VIBRATOR_STATE = "android.permission.ACCESS_VIBRATOR_STATE";
    field @FlaggedApi("com.android.server.power.feature.flags.partial_sleep_wakelocks") public static final String ACQUIRE_SLEEP_LOCK = "android.permission.ACQUIRE_SLEEP_LOCK";
    field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
    field public static final String ADD_ALWAYS_UNLOCKED_DISPLAY = "android.permission.ADD_ALWAYS_UNLOCKED_DISPLAY";
    field @FlaggedApi("android.companion.virtualdevice.flags.vdm_mirror_display_permission") public static final String ADD_MIRROR_DISPLAY = "android.permission.ADD_MIRROR_DISPLAY";
@@ -11807,6 +11808,7 @@ package android.os {
    method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressedForToken(@NonNull String);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public boolean isLowPowerStandbySupported();
    method @NonNull @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS) public android.os.PowerManager.LowPowerStandbyPortsLock newLowPowerStandbyPortsLock(@NonNull java.util.List<android.os.PowerManager.LowPowerStandbyPortDescription>);
    method @FlaggedApi("com.android.server.power.feature.flags.partial_sleep_wakelocks") @NonNull @RequiresPermission(android.Manifest.permission.ACQUIRE_SLEEP_LOCK) public android.os.PowerManager.SleepLock newSleepLock(int, @NonNull String) throws java.lang.RuntimeException;
    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSaveEnabled(boolean);
    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setAdaptivePowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
    method @RequiresPermission(anyOf={android.Manifest.permission.BATTERY_PREDICTION, android.Manifest.permission.DEVICE_POWER}) public void setBatteryDischargePrediction(@NonNull java.time.Duration, boolean);
@@ -11861,6 +11863,12 @@ package android.os {
    method @RequiresPermission(android.Manifest.permission.SET_LOW_POWER_STANDBY_PORTS) public void release();
  }
  @FlaggedApi("com.android.server.power.feature.flags.partial_sleep_wakelocks") public final class PowerManager.SleepLock {
    method @RequiresPermission(android.Manifest.permission.ACQUIRE_SLEEP_LOCK) public void acquire(long);
    method public boolean isHeld();
    method @RequiresPermission(android.Manifest.permission.ACQUIRE_SLEEP_LOCK) public void release();
  }
  @FlaggedApi("com.android.server.power.optimization.power_monitor_api") public final class PowerMonitorReadings {
    method @FlaggedApi("android.permission.flags.fine_power_monitor_permission") public int getGranularity();
    field @FlaggedApi("android.permission.flags.fine_power_monitor_permission") public static final int GRANULARITY_FINE = 1; // 0x1
+1 −0
Original line number Diff line number Diff line
@@ -2585,6 +2585,7 @@ package android.os {
  public final class PowerManager {
    method public boolean areAutoPowerSaveModesEnabled();
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public void forceLowPowerStandbyActive(boolean);
    method @FlaggedApi("com.android.server.power.feature.flags.partial_sleep_wakelocks") @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void goToSleep(long, int, int);
    method @FlaggedApi("android.os.battery_saver_supported_check_api") public boolean isBatterySaverSupported();
    method public boolean isInteractive(int);
    field public static final String ACTION_ENHANCED_DISCHARGE_PREDICTION_CHANGED = "android.os.action.ENHANCED_DISCHARGE_PREDICTION_CHANGED";
+143 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.os;

import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;

import static com.android.server.power.feature.flags.Flags.FLAG_PARTIAL_SLEEP_WAKELOCKS;
import static com.android.server.power.feature.flags.Flags.FLAG_SHUTDOWN_SYSTEM_API;

import android.Manifest.permission;
@@ -38,7 +39,6 @@ import android.annotation.TestApi;
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.IScreenTimeoutPolicyListener;
import android.service.dreams.Sandman;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -46,6 +46,7 @@ import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.Display;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;

@@ -1654,6 +1655,9 @@ public final class PowerManager {
     *
     * @hide Requires signature permission.
     */
    @TestApi
    @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
    @FlaggedApi(FLAG_PARTIAL_SLEEP_WAKELOCKS)
    @UnsupportedAppUsage
    public void goToSleep(long time, int reason, int flags) {
        try {
@@ -2072,6 +2076,144 @@ public final class PowerManager {
        }
    }

    /**
     * Creates a new sleep lock, which is a wake lock that holds a {@link #PARTIAL_SLEEP_WAKE_LOCK}.
     * <p>
     * A sleep lock is a specialized, non-reference-counted wake lock that keeps the CPU running
     * and keeps the display(s) off. When a sleep lock is held, it supersedes all other
     * wake locks, meaning they will be ignored.
     * </p><p>
     * Since this is a non-reference-counted lock, a single call to {@link SleepLock#release()}
     * is sufficient to release it, regardless of how many times {@link SleepLock#acquire(long)}
     * was called.
     * </p><p>
     * Call {@link SleepLock#acquire(long)} with a timeout on the returned object to acquire the
     * sleep lock, and {@link SleepLock#release()} to release it when you are done. It is important
     * to release the lock as soon as the work is complete.
     * </p>
     *
     * @param displayId The ID of the display with which this sleep lock is associated. The lock
     *                  will apply to the display group of this display. Use
     *                  {@link android.view.Display#DEFAULT_DISPLAY} for the default display.
     * @param tag A tag for debugging purposes. Follow the naming conventions described in
     *            {@link #newWakeLock(int, String)}.
     * @return A new {@link SleepLock} object.
     * @throws RuntimeException if partial sleep wake locks are not enabled on the device.
     *
     * @see SleepLock
     * @see #PARTIAL_SLEEP_WAKE_LOCK
     * @hide
     */
    @FlaggedApi(FLAG_PARTIAL_SLEEP_WAKELOCKS)
    @SystemApi
    @NonNull
    @RequiresPermission(permission.ACQUIRE_SLEEP_LOCK)
    public SleepLock newSleepLock(int displayId, @NonNull String tag) throws RuntimeException {
        if (!mContext.getResources().getBoolean(R.bool.config_allowPartialSleepWakeLocks)) {
            throw new RuntimeException("Partial Sleep WakeLocks are not allowed on this device "
                    + "due to the configuration");
        }

        return new SleepLock(displayId, tag);
    }

    /**
     * A specialized, non-reference-counted wake lock that keeps the CPU running
     * and keeps the display(s) off.
     * <p>
     * An instance of this class can be obtained by calling
     * {@link PowerManager#newSleepLock(int, String)}.
     * </p><p>
     * When a sleep lock is held, it supersedes all other wake locks, meaning they will be ignored.
     * Since this is a non-reference-counted lock, a single call to {@link #release()}
     * is sufficient to release it.
     * </p><p>
     * Use {@link #acquire(long)} to acquire the lock and {@link #release()} to release it.
     * Use {@link #release()} to check whether the wakelock is currently held.
     * </p>
     *
     * @see #newSleepLock(int, String)
     * @hide
     */
    @FlaggedApi(FLAG_PARTIAL_SLEEP_WAKELOCKS)
    @SystemApi
    @SuppressLint("NotCloseable")
    public final class SleepLock {
        private static final int SLEEP_LOCK = PowerManager.PARTIAL_SLEEP_WAKE_LOCK;
        @NonNull
        private final String mTag;
        private final int mDisplayId;
        private final int mDefaultTimeoutMillis;
        @NonNull
        private final WakeLock mWakelock;

        /**
         *
         * @param displayId The ID of the display with which this sleep lock is associated. The lock
         *                  will apply to the display group of this display. Use
         *                  {@link android.view.Display#DEFAULT_DISPLAY} for the default display.
         * @param tag A tag for debugging purposes. Follow the naming conventions described in
         *            {@link #newWakeLock(int, String)}.
         *
         * @hide
         */
        public SleepLock(int displayId, @NonNull String tag) {
            mDisplayId = displayId;
            mTag = tag;
            mDefaultTimeoutMillis = mContext.getResources().getInteger(
                    R.integer.config_maximumPartialSleepWakeLockDuration);
            mWakelock = new WakeLock(SLEEP_LOCK, mTag, mContext.getOpPackageName(), mDisplayId);
        }

        /**
         * Acquires the sleep lock for a given timeout.
         * <p>
         * The lock is automatically released after the specified timeout expires.
         * </p><p>
         * The requested timeout may be capped at a system-defined maximum value to
         * prevent the lock from being held indefinitely.
         * </p>
         *
         * @param timeoutMillis The amount of time to hold the lock for, in milliseconds.
         */
        @RequiresPermission(permission.ACQUIRE_SLEEP_LOCK)
        public void acquire(long timeoutMillis) {
            mWakelock.acquire(Math.min(timeoutMillis, mDefaultTimeoutMillis));
        }


        /**
         * Releases the sleep lock.
         */
        @RequiresPermission(permission.ACQUIRE_SLEEP_LOCK)
        public void release() {
            try {
                mWakelock.release();
            } catch (RuntimeException ignore) {
                // wakelock already released by system due to timeout
            }
        }

        /**
         * Returns whether the sleep lock has been acquired but not yet released.
         *
         * @return {@code true} if the lock is held, {@code false} otherwise.
         */
        public boolean isHeld() {
            return mWakelock.isHeld();
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public String toString() {
            return "mTag: " + mTag + ", mDisplayId: " + mDisplayId + ", mDefaultTimeoutMillis: "
                    + mDefaultTimeoutMillis + ", mWakelock: " + mWakelock;
        }
    }


    /**
     * Reboot the device. Will not return if the reboot is successful.
     * <p>
+1 −0
Original line number Diff line number Diff line
@@ -190,6 +190,7 @@ android_app {
        "aconfig_trade_in_mode_flags",
        "com.android.media.flags.projection-aconfig",
        "surfaceflinger_flags",
        "power_flags",
    ],
}

+12 −0
Original line number Diff line number Diff line
@@ -2795,6 +2795,18 @@
        android:description="@string/permdesc_wakeLock"
        android:protectionLevel="normal|instant" />
    <!--
    @SystemApi
    @FlaggedApi(com.android.server.power.feature.flags.Flags.FLAG_PARTIAL_SLEEP_WAKELOCKS)
    Allows an application to create and acquire partial sleep wakelocks with
    {@link android.os.PowerManager#newSleeplock}.
    <p> Protection level: signature
    @hide
    -->
    <permission android:name="android.permission.ACQUIRE_SLEEP_LOCK"
        android:protectionLevel="signature"
        android:featureFlag="com.android.server.power.feature.flags.partial_sleep_wakelocks"/>
    <!-- Allows using the device's IR transmitter, if available.
         <p>Protection level: normal
    -->
Loading