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

Commit 46ccaf46 authored by Robert Horvath's avatar Robert Horvath
Browse files

LowPowerStandby: Add APIs to get/set custom Policy

The Low Power Standby Policy declares:
- Packages (by package name) that should be exempt from
  Low Power Standby restrictions
- Reasons why an app may be dynamically exempt from Low Power Standby
  restrictions.
- Features apps are allowed to use during Low Power Standby.
  The features are Strings, so that vendors can define custom features
  for functionality that may not always be available or allowed in
  all Low Power Standby policies.

The existing exemption for active Voice Interaction Sessions is migrated
to use a predefined allow-reason, and enabled in the default policy.
When a policy without the VIS allow-reason is set, then apps having an
active VIS are no longer exempted from Low Power Standby restrictions.

Bug: 234002812
Test: atest LowPowerStandbyControllerTest LowPowerStandbyTest
Change-Id: I8747ae5b49613122e922aae7a917cbd2771ae091
parent d2267f07
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -32831,9 +32831,12 @@ package android.os {
    method public int getCurrentThermalStatus();
    method public int getLocationPowerSaveMode();
    method public float getThermalHeadroom(@IntRange(from=0, to=60) int);
    method public boolean isAllowedInLowPowerStandby(int);
    method public boolean isAllowedInLowPowerStandby(@NonNull String);
    method public boolean isBatteryDischargePredictionPersonalized();
    method public boolean isDeviceIdleMode();
    method public boolean isDeviceLightIdleMode();
    method public boolean isExemptFromLowPowerStandby();
    method public boolean isIgnoringBatteryOptimizations(String);
    method public boolean isInteractive();
    method public boolean isLowPowerStandbyEnabled();
@@ -32856,6 +32859,8 @@ package android.os {
    field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1
    field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0
    field public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4; // 0x4
    field public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1; // 0x1
    field public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN = "com.android.lowpowerstandby.WAKE_ON_LAN";
    field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000
    field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1
    field public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // 0x20
+11 −0
Original line number Diff line number Diff line
@@ -10159,6 +10159,7 @@ package android.os {
    method @RequiresPermission(allOf={android.Manifest.permission.READ_DREAM_STATE, android.Manifest.permission.WRITE_DREAM_STATE}) public void dream(long);
    method @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public boolean forceSuspend();
    method @NonNull public android.os.BatterySaverPolicyConfig getFullPowerSavePolicy();
    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public android.os.PowerManager.LowPowerStandbyPolicy getLowPowerStandbyPolicy();
    method public int getPowerSaveModeTrigger();
    method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplayAvailable();
    method @RequiresPermission(android.Manifest.permission.READ_DREAM_STATE) public boolean isAmbientDisplaySuppressed();
@@ -10171,9 +10172,11 @@ package android.os {
    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setFullPowerSavePolicy(@NonNull android.os.BatterySaverPolicyConfig);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public void setLowPowerStandbyActiveDuringMaintenance(boolean);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public void setLowPowerStandbyEnabled(boolean);
    method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER}) public void setLowPowerStandbyPolicy(@Nullable android.os.PowerManager.LowPowerStandbyPolicy);
    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.POWER_SAVER}) public boolean setPowerSaveModeEnabled(boolean);
    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void suppressAmbientDisplay(@NonNull String, boolean);
    method @RequiresPermission(anyOf={android.Manifest.permission.DEVICE_POWER, android.Manifest.permission.USER_ACTIVITY}) public void userActivity(long, int, int);
    field @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY) public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED = "android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";
    field public static final int POWER_SAVE_MODE_TRIGGER_DYNAMIC = 1; // 0x1
    field public static final int POWER_SAVE_MODE_TRIGGER_PERCENTAGE = 0; // 0x0
    field public static final String REBOOT_USERSPACE = "userspace";
@@ -10188,6 +10191,14 @@ package android.os {
    field public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1; // 0x1
  }
  public static final class PowerManager.LowPowerStandbyPolicy {
    ctor public PowerManager.LowPowerStandbyPolicy(@NonNull String, @NonNull java.util.Set<java.lang.String>, int, @NonNull java.util.Set<java.lang.String>);
    method @NonNull public java.util.Set<java.lang.String> getAllowedFeatures();
    method public int getAllowedReasons();
    method @NonNull public java.util.Set<java.lang.String> getExemptPackages();
    method @NonNull public String getIdentifier();
  }
  @Deprecated public class PowerWhitelistManager {
    method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull String);
    method @Deprecated @RequiresPermission(android.Manifest.permission.DEVICE_POWER) public void addToWhitelist(@NonNull java.util.List<java.lang.String>);
+18 −0
Original line number Diff line number Diff line
@@ -68,11 +68,29 @@ interface IPowerManager
    boolean isBatteryDischargePredictionPersonalized();
    boolean isDeviceIdleMode();
    boolean isLightDeviceIdleMode();
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER })")
    boolean isLowPowerStandbySupported();
    boolean isLowPowerStandbyEnabled();
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER })")
    void setLowPowerStandbyEnabled(boolean enabled);
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER })")
    void setLowPowerStandbyActiveDuringMaintenance(boolean activeDuringMaintenance);
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER })")
    void forceLowPowerStandbyActive(boolean active);
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER })")
    void setLowPowerStandbyPolicy(in @nullable LowPowerStandbyPolicy policy);
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_LOW_POWER_STANDBY, android.Manifest.permission.DEVICE_POWER })")
    LowPowerStandbyPolicy getLowPowerStandbyPolicy();
    boolean isExemptFromLowPowerStandby();
    boolean isReasonAllowedInLowPowerStandby(int reason);
    boolean isFeatureAllowedInLowPowerStandby(String feature);

    parcelable LowPowerStandbyPolicy {
        String identifier;
        List<String> exemptPackages;
        int allowedReasons;
        List<String> allowedFeatures;
    }

    @UnsupportedAppUsage
    void reboot(boolean confirm, String reason, boolean wait);
+261 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.content.Context;
import android.service.dreams.Sandman;
import android.sysprop.InitProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.Display;
@@ -44,7 +45,10 @@ import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;

@@ -2343,6 +2347,93 @@ public final class PowerManager {
        }
    }

    /**
     * Sets the current Low Power Standby policy.
     *
     * When the policy changes {@link #ACTION_LOW_POWER_STANDBY_POLICY_CHANGED} is broadcast to
     * registered receivers.
     *
     * @param policy The policy to set. If null, resets to the default policy.
     * @see #getLowPowerStandbyPolicy
     * @hide
     */
    @SystemApi
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MANAGE_LOW_POWER_STANDBY,
            android.Manifest.permission.DEVICE_POWER
    })
    public void setLowPowerStandbyPolicy(@Nullable LowPowerStandbyPolicy policy) {
        try {
            mService.setLowPowerStandbyPolicy(LowPowerStandbyPolicy.toParcelable(policy));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Get the current Low Power Standby policy.
     *
     * When the policy changes {@link #ACTION_LOW_POWER_STANDBY_POLICY_CHANGED} is broadcast to
     * registered receivers.
     *
     * @see #setLowPowerStandbyPolicy
     * @hide
     */
    @SystemApi
    @Nullable
    @RequiresPermission(anyOf = {
            android.Manifest.permission.MANAGE_LOW_POWER_STANDBY,
            android.Manifest.permission.DEVICE_POWER
    })
    public LowPowerStandbyPolicy getLowPowerStandbyPolicy() {
        try {
            return LowPowerStandbyPolicy.fromParcelable(mService.getLowPowerStandbyPolicy());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns true if the calling package is exempt from Low Power Standby restrictions or
     * Low Power Standby is disabled (so Low Power Standby does not restrict apps),
     * false otherwise.
     */
    public boolean isExemptFromLowPowerStandby() {
        try {
            return mService.isExemptFromLowPowerStandby();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns true if Low Power Standby is disabled (so Low Power Standby does not restrict apps),
     * or apps may be automatically exempt from Low Power Standby restrictions for the given reason.
     *
     * The system may exempt apps from Low Power Standby restrictions when using allowed features.
     * For example, if {@link #LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION} is allowed,
     * then apps with active voice interaction sessions are exempt from restrictions.
     */
    public boolean isAllowedInLowPowerStandby(@LowPowerStandbyAllowedReason int reason) {
        try {
            return mService.isReasonAllowedInLowPowerStandby(reason);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Returns true if Low Power Standby is disabled (so Low Power Standby does not restrict apps),
     * or apps are allowed to use a given feature during Low Power Standby.
     */
    public boolean isAllowedInLowPowerStandby(@NonNull String feature) {
        try {
            return mService.isFeatureAllowedInLowPowerStandby(feature);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Return whether the given application package name is on the device's power allowlist.
     * Apps can be placed on the allowlist through the settings UI invoked by
@@ -2839,6 +2930,176 @@ public final class PowerManager {
    public static final String ACTION_LOW_POWER_STANDBY_ENABLED_CHANGED =
            "android.os.action.LOW_POWER_STANDBY_ENABLED_CHANGED";

    /**
     * Intent that is broadcast when Low Power Standby is enabled or disabled.
     * This broadcast is only sent to registered receivers.
     *
     * @see #getLowPowerStandbyPolicy
     * @see #setLowPowerStandbyPolicy
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.MANAGE_LOW_POWER_STANDBY)
    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_LOW_POWER_STANDBY_POLICY_CHANGED =
            "android.os.action.LOW_POWER_STANDBY_POLICY_CHANGED";

    /**
     * Signals that wake-on-lan/wake-on-wlan is allowed in Low Power Standby.
     *
     * @see #isAllowedInLowPowerStandby(String)
     */
    public static final String LOW_POWER_STANDBY_FEATURE_WAKE_ON_LAN =
            "com.android.lowpowerstandby.WAKE_ON_LAN";

    /**
     * @hide
     */
    @IntDef(prefix = { "LOW_POWER_STANDBY_ALLOWED_REASON_" }, flag = true, value = {
            LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface LowPowerStandbyAllowedReason {
    }

    /**
     * Exempts active Voice Interaction Sessions in Low Power Standby.
     *
     * @see #isAllowedInLowPowerStandby(int)
     */
    public static final int LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION = 1 << 0;

    /** @hide */
    public static String lowPowerStandbyAllowedReasonsToString(
            @LowPowerStandbyAllowedReason int allowedReasons) {
        ArrayList<String> allowedStrings = new ArrayList<>();
        if ((allowedReasons & LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION) != 0) {
            allowedStrings.add("ALLOWED_REASON_VOICE_INTERACTION");
            allowedReasons &= ~LOW_POWER_STANDBY_ALLOWED_REASON_VOICE_INTERACTION;
        }
        if (allowedReasons != 0) {
            allowedStrings.add(String.valueOf(allowedReasons));
        }
        return String.join(",", allowedStrings);
    }

    /**
     * Policy that defines the restrictions enforced by Low Power Standby.
     *
     * @hide
     */
    @SystemApi
    public static final class LowPowerStandbyPolicy {
        /** Name of the policy, used for debugging & metrics */
        @NonNull
        private final String mIdentifier;

        /** Packages that are exempt from Low Power Standby restrictions. */
        @NonNull
        private final Set<String> mExemptPackages;

        /**
         * Reasons that this policy allows apps to be automatically exempted
         * from Low Power Standby restrictions for.
         */
        @LowPowerStandbyAllowedReason
        private final int mAllowedReasons;

        /** Features that are allowed to be used in Low Power Standby. */
        @NonNull
        private final Set<String> mAllowedFeatures;

        public LowPowerStandbyPolicy(@NonNull String identifier,
                @NonNull Set<String> exemptPackages,
                @LowPowerStandbyAllowedReason int allowedReasons,
                @NonNull Set<String> allowedFeatures) {
            Objects.requireNonNull(identifier);
            Objects.requireNonNull(exemptPackages);
            Objects.requireNonNull(allowedFeatures);

            mIdentifier = identifier;
            mExemptPackages = Collections.unmodifiableSet(exemptPackages);
            mAllowedReasons = allowedReasons;
            mAllowedFeatures = Collections.unmodifiableSet(allowedFeatures);
        }

        @NonNull
        public String getIdentifier() {
            return mIdentifier;
        }

        @NonNull
        public Set<String> getExemptPackages() {
            return mExemptPackages;
        }

        @LowPowerStandbyAllowedReason
        public int getAllowedReasons() {
            return mAllowedReasons;
        }

        @NonNull
        public Set<String> getAllowedFeatures() {
            return mAllowedFeatures;
        }

        @Override
        public String toString() {
            return "Policy{"
                    + "mIdentifier='" + mIdentifier + '\''
                    + ", mExemptPackages=" + String.join(",", mExemptPackages)
                    + ", mAllowedReasons=" + lowPowerStandbyAllowedReasonsToString(mAllowedReasons)
                    + ", mAllowedFeatures=" + String.join(",", mAllowedFeatures)
                    + '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof LowPowerStandbyPolicy)) return false;
            LowPowerStandbyPolicy that = (LowPowerStandbyPolicy) o;
            return mAllowedReasons == that.mAllowedReasons && Objects.equals(mIdentifier,
                    that.mIdentifier) && Objects.equals(mExemptPackages, that.mExemptPackages)
                    && Objects.equals(mAllowedFeatures, that.mAllowedFeatures);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mIdentifier, mExemptPackages, mAllowedReasons,
                    mAllowedFeatures);
        }

        /** @hide */
        public static IPowerManager.LowPowerStandbyPolicy toParcelable(
                LowPowerStandbyPolicy policy) {
            if (policy == null) {
                return null;
            }

            IPowerManager.LowPowerStandbyPolicy parcelablePolicy =
                    new IPowerManager.LowPowerStandbyPolicy();
            parcelablePolicy.identifier = policy.mIdentifier;
            parcelablePolicy.exemptPackages = new ArrayList<>(policy.mExemptPackages);
            parcelablePolicy.allowedReasons = policy.mAllowedReasons;
            parcelablePolicy.allowedFeatures = new ArrayList<>(policy.mAllowedFeatures);
            return parcelablePolicy;
        }

        /** @hide */
        public static LowPowerStandbyPolicy fromParcelable(
                IPowerManager.LowPowerStandbyPolicy parcelablePolicy) {
            if (parcelablePolicy == null) {
                return null;
            }

            return new LowPowerStandbyPolicy(
                    parcelablePolicy.identifier,
                    new ArraySet<>(parcelablePolicy.exemptPackages),
                    parcelablePolicy.allowedReasons,
                    new ArraySet<>(parcelablePolicy.allowedFeatures));
        }
    }

    /**
     * Constant for PreIdleTimeout normal mode (default mode, not short nor extend timeout) .
     * @hide
+22 −1
Original line number Diff line number Diff line
@@ -469,5 +469,26 @@ message LowPowerStandbyControllerDumpProto {
    // Set of app ids that are exempt form low power standby
    repeated int32 allowlist = 10;

    // Next tag: 11
    // The active policy specifying exemptions
    optional LowPowerStandbyPolicyProto policy = 11;

    // Next tag: 12
}

message LowPowerStandbyPolicyProto {
    option (.android.msg_privacy).dest = DEST_AUTOMATIC;

    // Name of the policy
    optional string identifier = 1;

    // Packages that are exempt from Low Power Standby restrictions
    repeated string exempt_packages = 2;

    // Exemption reasons that this policy allows
    optional int32 allowed_reasons = 3;

    // Features that this policy allows to be used
    repeated string allowed_features = 4;

    // Next tag: 5
}
Loading