Loading apex/jobscheduler/framework/java/android/app/AlarmManager.java +83 −16 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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() { Loading @@ -250,7 +263,7 @@ public class AlarmManager { public void doAlarm(IAlarmCompleteListener alarmManager) { mCompletion = alarmManager; mHandler.post(this); mExecutor.execute(this); } @Override Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading @@ -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. * Loading Loading @@ -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); } Loading Loading @@ -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 */ Loading @@ -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); } /** Loading Loading @@ -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) { Loading Loading @@ -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 { Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +77 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -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 Loading Loading @@ -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(); } Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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, Loading Loading @@ -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; } Loading Loading @@ -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(); } Loading Loading @@ -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) { Loading Loading @@ -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); } Loading Loading @@ -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. Loading Loading @@ -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, Loading @@ -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(); Loading core/api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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 { Loading core/res/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -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. --> Loading services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +93 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
apex/jobscheduler/framework/java/android/app/AlarmManager.java +83 −16 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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() { Loading @@ -250,7 +263,7 @@ public class AlarmManager { public void doAlarm(IAlarmCompleteListener alarmManager) { mCompletion = alarmManager; mHandler.post(this); mExecutor.execute(this); } @Override Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading @@ -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. * Loading Loading @@ -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); } Loading Loading @@ -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 */ Loading @@ -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); } /** Loading Loading @@ -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) { Loading Loading @@ -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 { Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading Loading @@ -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); } /** Loading
apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +77 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -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 Loading Loading @@ -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(); } Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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, Loading Loading @@ -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; } Loading Loading @@ -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(); } Loading Loading @@ -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) { Loading Loading @@ -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); } Loading Loading @@ -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. Loading Loading @@ -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, Loading @@ -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(); Loading
core/api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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"; Loading Loading @@ -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 { Loading
core/res/AndroidManifest.xml +9 −0 Original line number Diff line number Diff line Loading @@ -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. --> Loading
services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +93 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes