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

Commit faa198b3 authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Remove alarms of cancelled pending intents

When a pending intent is cancelled, the alarm is essentially defunct.
Keeping around this alarm takes unneeded memory and unreasonably counts
towards the per-uid cap of pending alarms.

Test: Unit test:
atest com.android.server.AlarmManagerServiceTest
Existing CTS:
atest CtsAlarmManagerTestCases

Bug: 132379078
Change-Id: I4c6d59d9ac79708d8daf40657e9773c715271f1e
parent 1f915b0d
Loading
Loading
Loading
Loading
+24 −2
Original line number Diff line number Diff line
@@ -210,6 +210,7 @@ class AlarmManagerService extends SystemService {
    IAlarmListener mTimeTickTrigger;
    PendingIntent mDateChangeSender;
    Random mRandom;
    PendingIntent.CancelListener mOperationCancelListener;
    boolean mInteractive = true;
    long mNonInteractiveStartTime;
    long mNonInteractiveTime;
@@ -1497,6 +1498,7 @@ class AlarmManagerService extends SystemService {

        synchronized (mLock) {
            mHandler = new AlarmHandler();
            mOperationCancelListener = (intent) -> removeImpl(intent, null);
            mConstants = new Constants(mHandler);
            mAppWakeupHistory = new AppWakeupHistory(Constants.DEFAULT_APP_STANDBY_WINDOW);

@@ -1748,7 +1750,9 @@ class AlarmManagerService extends SystemService {
        } else {
            maxElapsed = triggerElapsed + windowLength;
        }

        if (operation != null) {
            operation.registerCancelListener(mOperationCancelListener);
        }
        synchronized (mLock) {
            if (DEBUG_BATCH) {
                Slog.v(TAG, "set(" + operation + ") : type=" + type
@@ -1761,6 +1765,8 @@ class AlarmManagerService extends SystemService {
                        "Maximum limit of concurrent alarms " + mConstants.MAX_ALARMS_PER_UID
                                + " reached for uid: " + UserHandle.formatUid(callingUid)
                                + ", callingPackage: " + callingPackage;
                mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
                        operation).sendToTarget();
                // STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
                Slog.wtf(TAG, errorMsg);
                throw new IllegalStateException(errorMsg);
@@ -1782,6 +1788,8 @@ class AlarmManagerService extends SystemService {
            if (ActivityManager.getService().isAppStartModeDisabled(callingUid, callingPackage)) {
                Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a
                        + " -- package not allowed to start");
                mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
                        operation).sendToTarget();
                return;
            }
        } catch (RemoteException e) {
@@ -2136,10 +2144,11 @@ class AlarmManagerService extends SystemService {
                Slog.w(TAG, "remove() with no intent or listener");
                return;
            }

            synchronized (mLock) {
                removeLocked(operation, listener);
            }
            mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
                    operation).sendToTarget();
        }

        @Override
@@ -4179,6 +4188,7 @@ class AlarmManagerService extends SystemService {
        public static final int APP_STANDBY_BUCKET_CHANGED = 5;
        public static final int APP_STANDBY_PAROLE_CHANGED = 6;
        public static final int REMOVE_FOR_STOPPED = 7;
        public static final int UNREGISTER_CANCEL_LISTENER = 8;

        AlarmHandler() {
            super(Looper.myLooper());
@@ -4261,6 +4271,13 @@ class AlarmManagerService extends SystemService {
                    }
                    break;

                case UNREGISTER_CANCEL_LISTENER:
                    final PendingIntent pi = (PendingIntent) msg.obj;
                    if (pi != null) {
                        pi.unregisterCancelListener(mOperationCancelListener);
                    }
                    break;

                default:
                    // nope, just ignore it
                    break;
@@ -4716,6 +4733,11 @@ class AlarmManagerService extends SystemService {
                                        Intent.EXTRA_ALARM_COUNT, alarm.count),
                                mDeliveryTracker, mHandler, null,
                                allowWhileIdle ? mIdleOptions : null);
                        if (alarm.repeatInterval == 0) {
                            // Keep the listener for repeating alarms until they get cancelled
                            mHandler.obtainMessage(AlarmHandler.UNREGISTER_CANCEL_LISTENER,
                                    alarm.operation).sendToTarget();
                        }
                    } catch (PendingIntent.CanceledException e) {
                        if (alarm.repeatInterval > 0) {
                            // This IntentSender is no longer valid, but this
+10 −0
Original line number Diff line number Diff line
@@ -1032,6 +1032,16 @@ public class AlarmManagerServiceTest {
        assertEquals(-1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, -1));
    }

    @Test
    public void alarmCountOnPendingIntentCancel() {
        final PendingIntent pi = getNewMockPendingIntent();
        setTestAlarm(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + 123, pi);
        verify(pi).registerCancelListener(mService.mOperationCancelListener);
        assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
        mService.mOperationCancelListener.onCancelled(pi);
        assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
    }

    @After
    public void tearDown() {
        if (mMockingSession != null) {