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
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 651f941..7cdcc01 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3369,7 +3369,8 @@
                     if (mMaxDelayTime < thisDelayTime) {
                         mMaxDelayTime = thisDelayTime;
                     }
-                    deliverAlarmsLocked(mPendingNonWakeupAlarms, nowELAPSED);
+                    final ArrayList<Alarm> triggerList = new ArrayList<>(mPendingNonWakeupAlarms);
+                    deliverAlarmsLocked(triggerList, nowELAPSED);
                     mPendingNonWakeupAlarms.clear();
                 }
                 if (mNonInteractiveStartTime > 0) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 7bd0201..bcc111f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -100,6 +100,7 @@
 import org.mockito.quality.Strictness;
 
 import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
 
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -1077,6 +1078,38 @@
         }
     }
 
+    /**
+     * 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;