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

Commit 01b2e17c authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Copy the list before passing to deliverAlarms

Downstream code from deliverAlarmsLocked can cause removeLocked or
removeImpl to be called which changes the size of the list.

Test: atest FrameworksMockingServicesTests:com.android.server.alarm

Bug: 175701084
Change-Id: I5228c323bb9698864c467e9e4c400459ca404b3c
Merged-In: I5228c323bb9698864c467e9e4c400459ca404b3c
parent 2e3b8fef
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -3369,7 +3369,8 @@ class AlarmManagerService extends SystemService {
                    if (mMaxDelayTime < thisDelayTime) {
                        mMaxDelayTime = thisDelayTime;
                    }
                    deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
                    final ArrayList<Alarm> triggerList = new ArrayList<>(mPendingNonWakeupAlarms);
                    deliverAlarmsLocked(triggerList, nowELAPSED);
                    mPendingNonWakeupAlarms.clear();
                }
                if (mNonInteractiveStartTime > 0) {
+33 −0
Original line number Diff line number Diff line
@@ -100,6 +100,7 @@ import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;

import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;

@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -1077,6 +1078,38 @@ public class AlarmManagerServiceTest {
        }
    }

    /**
     * This tests that all non wakeup alarms are sent even when the mPendingNonWakeupAlarms gets
     * modified before the send is complete. This avoids bugs like b/175701084.
     */
    @Test
    public void allNonWakeupAlarmsSentAtomically() throws Exception {
        final int numAlarms = 5;
        final AtomicInteger alarmsFired = new AtomicInteger(0);
        for (int i = 0; i < numAlarms; i++) {
            final IAlarmListener listener = new IAlarmListener.Stub() {
                @Override
                public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
                    alarmsFired.incrementAndGet();
                    mService.mPendingNonWakeupAlarms.clear();
                }
            };
            setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + i + 5, listener);
        }
        doReturn(true).when(mService).checkAllowNonWakeupDelayLocked(anyLong());
        // Advance time past all expirations.
        mNowElapsedTest += numAlarms + 5;
        mTestTimer.expire();
        assertEquals(numAlarms, mService.mPendingNonWakeupAlarms.size());

        // All of these alarms should be sent on interactive state change to true
        mService.interactiveStateChangedLocked(false);
        mService.interactiveStateChangedLocked(true);

        assertEquals(numAlarms, alarmsFired.get());
        assertEquals(0, mService.mPendingNonWakeupAlarms.size());
    }

    @Test
    public void alarmCountOnPendingNonWakeupAlarmsRemoved() throws Exception {
        final int numAlarms = 10;