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

Commit 39846a14 authored by Suprabh Shukla's avatar Suprabh Shukla Committed by Automerger Merge Worker
Browse files

Merge "Add an API for a prioritized alarm" into sc-dev am: ea1decfc

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13976105

Change-Id: Iae5005992b3f1a7a6edad700b314cd0ed57e10cf
parents 82c2ccfd ea1decfc
Loading
Loading
Loading
Loading
+83 −16
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.app;

import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SystemApi;
@@ -29,6 +30,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
@@ -42,7 +44,9 @@ import com.android.i18n.timezone.ZoneInfoDb;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.Objects;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;

/**
 * This class provides access to the system alarm services.  These allow you
@@ -193,6 +197,15 @@ public class AlarmManager {
     */
    public static final int FLAG_ALLOW_WHILE_IDLE_COMPAT = 1 << 5;

    /**
     * Flag for alarms: Used to mark prioritized alarms. These alarms will get to execute while idle
     * and can be sent separately from other alarms that may be already due at the time.
     * These alarms can be set via
     * {@link #setPrioritized(int, long, long, String, Executor, OnAlarmListener)}
     * @hide
     */
    public static final int FLAG_PRIORITIZE = 1 << 6;

    /**
     * For apps targeting {@link Build.VERSION_CODES#S} or above, APIs
     * {@link #setExactAndAllowWhileIdle(int, long, PendingIntent)} and
@@ -227,15 +240,15 @@ public class AlarmManager {

    final class ListenerWrapper extends IAlarmListener.Stub implements Runnable {
        final OnAlarmListener mListener;
        Handler mHandler;
        Executor mExecutor;
        IAlarmCompleteListener mCompletion;

        public ListenerWrapper(OnAlarmListener listener) {
            mListener = listener;
        }

        public void setHandler(Handler h) {
           mHandler = h;
        void setExecutor(Executor e) {
            mExecutor = e;
        }

        public void cancel() {
@@ -250,7 +263,7 @@ public class AlarmManager {
        public void doAlarm(IAlarmCompleteListener alarmManager) {
            mCompletion = alarmManager;

            mHandler.post(this);
            mExecutor.execute(this);
        }

        @Override
@@ -368,7 +381,7 @@ public class AlarmManager {
     */
    public void set(@AlarmType int type, long triggerAtMillis, PendingIntent operation) {
        setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null,
                null, null, null);
                (Handler) null, null, null);
    }

    /**
@@ -457,7 +470,7 @@ public class AlarmManager {
    public void setRepeating(@AlarmType int type, long triggerAtMillis,
            long intervalMillis, PendingIntent operation) {
        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation,
                null, null, null, null, null);
                null, null, (Handler) null, null, null);
    }

    /**
@@ -507,7 +520,7 @@ public class AlarmManager {
    public void setWindow(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
            PendingIntent operation) {
        setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, operation,
                null, null, null, null, null);
                null, null, (Handler) null, null, null);
    }

    /**
@@ -525,6 +538,53 @@ public class AlarmManager {
                targetHandler, null, null);
    }

    /**
     * Schedule an alarm that is prioritized by the system while the device is in power saving modes
     * such as battery saver and device idle (doze).
     *
     * <p>
     * Apps that use this are not guaranteed to get all alarms as requested during power saving
     * modes, i.e. the system may still impose restrictions on how frequently these alarms will go
     * off for a particular application, like requiring a certain minimum duration be elapsed
     * between consecutive alarms. This duration will be normally be in the order of a few minutes.
     *
     * <p>
     * When the system wakes up to deliver these alarms, it may not deliver any of the other pending
     * alarms set earlier by the calling app, even the special ones set via
     * {@link #setAndAllowWhileIdle(int, long, PendingIntent)} or
     * {@link #setExactAndAllowWhileIdle(int, long, PendingIntent)}. So the caller should not
     * expect these to arrive in any relative order to its other alarms.
     *
     * @param type type of alarm
     * @param windowStartMillis The earliest time, in milliseconds, that the alarm should
     *        be delivered, expressed in the appropriate clock's units (depending on the alarm
     *        type).
     * @param windowLengthMillis The length of the requested delivery window,
     *        in milliseconds.  The alarm will be delivered no later than this many
     *        milliseconds after {@code windowStartMillis}.  Note that this parameter
     *        is a <i>duration,</i> not the timestamp of the end of the window.
     * @param tag string describing the alarm, used for logging and battery-use
     *         attribution
     * @param listener {@link OnAlarmListener} instance whose
     *         {@link OnAlarmListener#onAlarm() onAlarm()} method will be
     *         called when the alarm time is reached.  A given OnAlarmListener instance can
     *         only be the target of a single pending alarm, just as a given PendingIntent
     *         can only be used with one alarm at a time.
     * @param executor {@link Executor} on which to execute the listener's onAlarm()
     *         callback.
     * @hide
     */
    @SystemApi
    @RequiresPermission(Manifest.permission.SCHEDULE_PRIORITIZED_ALARM)
    public void setPrioritized(@AlarmType int type, long windowStartMillis, long windowLengthMillis,
            @NonNull String tag, @NonNull Executor executor, @NonNull OnAlarmListener listener) {
        Objects.requireNonNull(executor);
        Objects.requireNonNull(tag);
        Objects.requireNonNull(listener);
        setImpl(type, windowStartMillis, windowLengthMillis, 0, FLAG_PRIORITIZE, null, listener,
                tag, executor, null, null);
    }

    /**
     * Schedule an alarm to be delivered precisely at the stated time.
     *
@@ -565,7 +625,7 @@ public class AlarmManager {
     */
    @RequiresPermission(value = Manifest.permission.SCHEDULE_EXACT_ALARM, conditional = true)
    public void setExact(@AlarmType int type, long triggerAtMillis, PendingIntent operation) {
        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, operation, null, null, null,
        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, operation, null, null, (Handler) null,
                null, null);
    }

@@ -645,7 +705,7 @@ public class AlarmManager {
    @RequiresPermission(Manifest.permission.SCHEDULE_EXACT_ALARM)
    public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) {
        setImpl(RTC_WAKEUP, info.getTriggerTime(), WINDOW_EXACT, 0, 0, operation,
                null, null, null, null, info);
                null, null, (Handler) null, null, info);
    }

    /** @hide */
@@ -654,7 +714,7 @@ public class AlarmManager {
    public void set(@AlarmType int type, long triggerAtMillis, long windowMillis,
            long intervalMillis, PendingIntent operation, WorkSource workSource) {
        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, operation, null, null,
                null, workSource, null);
                (Handler) null, workSource, null);
    }

    /**
@@ -698,6 +758,15 @@ public class AlarmManager {
            long intervalMillis, int flags, PendingIntent operation, final OnAlarmListener listener,
            String listenerTag, Handler targetHandler, WorkSource workSource,
            AlarmClockInfo alarmClock) {
        final Handler handlerToUse = (targetHandler != null) ? targetHandler : mMainThreadHandler;
        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, flags, operation, listener,
                listenerTag, new HandlerExecutor(handlerToUse), workSource, alarmClock);
    }

    private void setImpl(@AlarmType int type, long triggerAtMillis, long windowMillis,
            long intervalMillis, int flags, PendingIntent operation, final OnAlarmListener listener,
            String listenerTag, Executor targetExecutor, WorkSource workSource,
            AlarmClockInfo alarmClock) {
        if (triggerAtMillis < 0) {
            /* NOTYET
            if (mAlwaysExact) {
@@ -726,9 +795,7 @@ public class AlarmManager {
                    sWrappers.put(listener, new WeakReference<>(recipientWrapper));
                }
            }

            final Handler handler = (targetHandler != null) ? targetHandler : mMainThreadHandler;
            recipientWrapper.setHandler(handler);
            recipientWrapper.setExecutor(targetExecutor);
        }

        try {
@@ -834,7 +901,7 @@ public class AlarmManager {
    public void setInexactRepeating(@AlarmType int type, long triggerAtMillis,
            long intervalMillis, PendingIntent operation) {
        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, 0, operation, null,
                null, null, null, null);
                null, (Handler) null, null, null);
    }

    /**
@@ -884,7 +951,7 @@ public class AlarmManager {
    public void setAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
            PendingIntent operation) {
        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, 0, FLAG_ALLOW_WHILE_IDLE,
                operation, null, null, null, null, null);
                operation, null, null, (Handler) null, null, null);
    }

    /**
@@ -945,7 +1012,7 @@ public class AlarmManager {
    public void setExactAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
            PendingIntent operation) {
        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_ALLOW_WHILE_IDLE, operation,
                null, null, null, null, null);
                null, null, (Handler) null, null, null);
    }

    /**
+77 −6
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_COMPAT;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
import static android.app.AlarmManager.FLAG_IDLE_UNTIL;
import static android.app.AlarmManager.FLAG_PRIORITIZE;
import static android.app.AlarmManager.FLAG_WAKE_FROM_IDLE;
import static android.app.AlarmManager.INTERVAL_DAY;
import static android.app.AlarmManager.INTERVAL_HOUR;
@@ -100,6 +101,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;

@@ -221,6 +223,7 @@ public class AlarmManagerService extends SystemService {
    AlarmHandler mHandler;
    AppWakeupHistory mAppWakeupHistory;
    AppWakeupHistory mAllowWhileIdleHistory;
    private final SparseLongArray mLastPriorityAlarmDispatch = new SparseLongArray();
    ClockReceiver mClockReceiver;
    final DeliveryTracker mDeliveryTracker = new DeliveryTracker();
    IBinder.DeathRecipient mListenerDeathRecipient;
@@ -432,6 +435,8 @@ public class AlarmManagerService extends SystemService {

        @VisibleForTesting
        static final String KEY_CRASH_NON_CLOCK_APPS = "crash_non_clock_apps";
        @VisibleForTesting
        static final String KEY_PRIORITY_ALARM_DELAY = "priority_alarm_delay";

        private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
        private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
@@ -470,6 +475,8 @@ public class AlarmManagerService extends SystemService {
        // TODO (b/171306433): Change to true by default.
        private static final boolean DEFAULT_CRASH_NON_CLOCK_APPS = false;

        private static final long DEFAULT_PRIORITY_ALARM_DELAY = 9 * 60_000;

        // Minimum futurity of a new alarm
        public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;

@@ -525,6 +532,12 @@ public class AlarmManagerService extends SystemService {
         */
        public boolean CRASH_NON_CLOCK_APPS = DEFAULT_CRASH_NON_CLOCK_APPS;

        /**
         * Minimum delay between two slots that an app can get for their prioritized alarms, while
         * the device is in doze.
         */
        public long PRIORITY_ALARM_DELAY = DEFAULT_PRIORITY_ALARM_DELAY;

        private long mLastAllowWhileIdleWhitelistDuration = -1;

        Constants() {
@@ -662,6 +675,10 @@ public class AlarmManagerService extends SystemService {
                            CRASH_NON_CLOCK_APPS = properties.getBoolean(KEY_CRASH_NON_CLOCK_APPS,
                                    DEFAULT_CRASH_NON_CLOCK_APPS);
                            break;
                        case KEY_PRIORITY_ALARM_DELAY:
                            PRIORITY_ALARM_DELAY = properties.getLong(KEY_PRIORITY_ALARM_DELAY,
                                    DEFAULT_PRIORITY_ALARM_DELAY);
                            break;
                        default:
                            if (name.startsWith(KEY_PREFIX_STANDBY_QUOTA) && !standbyQuotaUpdated) {
                                // The quotas need to be updated in order, so we can't just rely
@@ -809,6 +826,11 @@ public class AlarmManagerService extends SystemService {
            pw.print(KEY_CRASH_NON_CLOCK_APPS, CRASH_NON_CLOCK_APPS);
            pw.println();

            pw.print(KEY_PRIORITY_ALARM_DELAY);
            pw.print("=");
            TimeUtils.formatDuration(PRIORITY_ALARM_DELAY, pw);
            pw.println();

            pw.decreaseIndent();
        }

@@ -1794,6 +1816,11 @@ public class AlarmManagerService extends SystemService {
                batterySaverPolicyElapsed = mAllowWhileIdleHistory.getNthLastWakeupForPackage(
                        alarm.sourcePackage, userId, quota) + window;
            }
        } else if ((alarm.flags & FLAG_PRIORITIZE) != 0) {
            final long lastDispatch = mLastPriorityAlarmDispatch.get(alarm.creatorUid, 0);
            batterySaverPolicyElapsed = (lastDispatch == 0)
                    ? nowElapsed
                    : lastDispatch + mConstants.PRIORITY_ALARM_DELAY;
        } else {
            // Not allowed.
            batterySaverPolicyElapsed = nowElapsed + INDEFINITE_DELAY;
@@ -1849,6 +1876,12 @@ public class AlarmManagerService extends SystemService {
                        alarm.sourcePackage, userId, quota) + window;
                deviceIdlePolicyTime = Math.min(whenInQuota, mPendingIdleUntil.getWhenElapsed());
            }
        } else if ((alarm.flags & FLAG_PRIORITIZE) != 0) {
            final long lastDispatch = mLastPriorityAlarmDispatch.get(alarm.creatorUid, 0);
            final long whenAllowed = (lastDispatch == 0)
                    ? nowElapsed
                    : lastDispatch + mConstants.PRIORITY_ALARM_DELAY;
            deviceIdlePolicyTime = Math.min(whenAllowed, mPendingIdleUntil.getWhenElapsed());
        } else {
            // Not allowed.
            deviceIdlePolicyTime = mPendingIdleUntil.getWhenElapsed();
@@ -2025,7 +2058,12 @@ public class AlarmManagerService extends SystemService {
            // make sure the caller is allowed to use the requested kind of alarm, and also
            // decide what quota and broadcast options to use.
            Bundle idleOptions = null;
            if (exact || allowWhileIdle) {
            if ((flags & FLAG_PRIORITIZE) != 0) {
                getContext().enforcePermission(
                        Manifest.permission.SCHEDULE_PRIORITIZED_ALARM,
                        Binder.getCallingPid(), callingUid, "AlarmManager.setPrioritized");
                flags &= ~(FLAG_ALLOW_WHILE_IDLE | FLAG_ALLOW_WHILE_IDLE_COMPAT);
            } else if (exact || allowWhileIdle) {
                final boolean needsPermission;
                boolean lowerQuota;
                if (CompatChanges.isChangeEnabled(AlarmManager.REQUIRE_EXACT_ALARM_PERMISSION,
@@ -2107,6 +2145,7 @@ public class AlarmManagerService extends SystemService {
                flags |= FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
                flags &= ~FLAG_ALLOW_WHILE_IDLE;
                flags &= ~FLAG_ALLOW_WHILE_IDLE_COMPAT;
                flags &= ~FLAG_PRIORITIZE;
                idleOptions = null;
            }

@@ -2489,6 +2528,19 @@ public class AlarmManagerService extends SystemService {
            pw.println("Allow while idle history:");
            mAllowWhileIdleHistory.dump(pw, nowELAPSED);

            if (mLastPriorityAlarmDispatch.size() > 0) {
                pw.println("Last priority alarm dispatches:");
                pw.increaseIndent();
                for (int i = 0; i < mLastPriorityAlarmDispatch.size(); i++) {
                    pw.print("UID: ");
                    UserHandle.formatUid(pw, mLastPriorityAlarmDispatch.keyAt(i));
                    pw.print(": ");
                    TimeUtils.formatDuration(mLastPriorityAlarmDispatch.valueAt(i), nowELAPSED, pw);
                    pw.println();
                }
                pw.decreaseIndent();
            }

            if (mLog.dump(pw, "Recent problems:")) {
                pw.println();
            }
@@ -3303,6 +3355,11 @@ public class AlarmManagerService extends SystemService {
                mPendingBackgroundAlarms.removeAt(i);
            }
        }
        for (int i = mLastPriorityAlarmDispatch.size() - 1; i >= 0; i--) {
            if (UserHandle.getUserId(mLastPriorityAlarmDispatch.keyAt(i)) == userHandle) {
                mLastPriorityAlarmDispatch.removeAt(i);
            }
        }
        if (mNextWakeFromIdle != null && whichAlarms.test(mNextWakeFromIdle)) {
            mNextWakeFromIdle = mAlarmStore.getNextWakeFromIdleAlarm();
            if (mPendingIdleUntil != null) {
@@ -4103,6 +4160,7 @@ public class AlarmManagerService extends SystemService {
            IntentFilter sdFilter = new IntentFilter();
            sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
            sdFilter.addAction(Intent.ACTION_USER_STOPPED);
            sdFilter.addAction(Intent.ACTION_UID_REMOVED);
            getContext().registerReceiver(this, sdFilter);
        }

@@ -4132,6 +4190,9 @@ public class AlarmManagerService extends SystemService {
                            mAllowWhileIdleHistory.removeForUser(userHandle);
                        }
                        return;
                    case Intent.ACTION_UID_REMOVED:
                        mLastPriorityAlarmDispatch.delete(uid);
                        return;
                    case Intent.ACTION_PACKAGE_REMOVED:
                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                            // This package is being updated; don't kill its alarms.
@@ -4522,11 +4583,11 @@ public class AlarmManagerService extends SystemService {
            if (inflight.isBroadcast()) {
                notifyBroadcastAlarmPendingLocked(alarm.uid);
            }
            if (isAllowedWhileIdleRestricted(alarm)) {
            final boolean doze = (mPendingIdleUntil != null);
            final boolean batterySaver = (mAppStateTracker != null
                    && mAppStateTracker.isForceAllAppsStandbyEnabled());
            if (doze || batterySaver) {
                if (isAllowedWhileIdleRestricted(alarm)) {
                    // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm while the
                    // device was in doze or battery saver.
                    mAllowWhileIdleHistory.recordAlarmForPackage(alarm.sourcePackage,
@@ -4538,6 +4599,16 @@ public class AlarmManagerService extends SystemService {
                        return (doze && adjustDeliveryTimeBasedOnDeviceIdle(a))
                                || (batterySaver && adjustDeliveryTimeBasedOnBatterySaver(a));
                    });
                } else if ((alarm.flags & FLAG_PRIORITIZE) != 0) {
                    mLastPriorityAlarmDispatch.put(alarm.creatorUid, nowELAPSED);
                    mAlarmStore.updateAlarmDeliveries(a -> {
                        if (a.creatorUid != alarm.creatorUid
                                || (alarm.flags & FLAG_PRIORITIZE) == 0) {
                            return false;
                        }
                        return (doze && adjustDeliveryTimeBasedOnDeviceIdle(a))
                                || (batterySaver && adjustDeliveryTimeBasedOnBatterySaver(a));
                    });
                }
                if (RECORD_DEVICE_IDLE_ALARMS) {
                    IdleDispatchEntry ent = new IdleDispatchEntry();
+2 −0
Original line number Diff line number Diff line
@@ -244,6 +244,7 @@ package android {
    field public static final String REVIEW_ACCESSIBILITY_SERVICES = "android.permission.REVIEW_ACCESSIBILITY_SERVICES";
    field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS";
    field public static final String ROTATE_SURFACE_FLINGER = "android.permission.ROTATE_SURFACE_FLINGER";
    field public static final String SCHEDULE_PRIORITIZED_ALARM = "android.permission.SCHEDULE_PRIORITIZED_ALARM";
    field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS";
    field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION";
    field public static final String SEND_CATEGORY_CAR_NOTIFICATIONS = "android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS";
@@ -423,6 +424,7 @@ package android.app {
  public class AlarmManager {
    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource);
    method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public void set(int, long, long, long, android.app.AlarmManager.OnAlarmListener, android.os.Handler, android.os.WorkSource);
    method @RequiresPermission(android.Manifest.permission.SCHEDULE_PRIORITIZED_ALARM) public void setPrioritized(int, long, long, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.app.AlarmManager.OnAlarmListener);
  }
  public class AppOpsManager {
+9 −0
Original line number Diff line number Diff line
@@ -4003,6 +4003,15 @@
    <permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
        android:protectionLevel="signature" />

    <!-- Allows an app to schedule a prioritized alarm that can be used to perform
         background work even when the device is in doze.
         <p>Not for use by third-party applications.
         @hide
         @SystemApi
     -->
    <permission android:name="android.permission.SCHEDULE_PRIORITIZED_ALARM"
                android:protectionLevel="signature|privileged"/>

    <!-- Allows an app to use exact alarm scheduling APIs to perform timing
         sensitive background work.
     -->
+93 −0

File changed.

Preview size limit exceeded, changes collapsed.