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
This commit is contained in:
@@ -3061,7 +3061,8 @@ public 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) {
|
||||
|
||||
@@ -121,6 +121,7 @@ import org.mockito.stubbing.Answer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -1133,6 +1134,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;
|
||||
|
||||
Reference in New Issue
Block a user