Update alarm_unregister_processing_queue() to cancel scheduled alarms

Update the alarm_unregister_processing_queue() implementation
so it cancels all alarms that are scheduled on the corresponding
queue.
This fixes a race condition during Bluetooth shutdown: if an alarm
expires right after an alarm processing queue is invalidated,
the alarm processing would try to use the invalidated queue.

Added the corresponding unit tests.

Also, added a missing call to alarm_unregister_processing_queue().

Bug: 26982349
Change-Id: I09a111e8080b6dbc354dffa03a487f7a8c578ce6
diff --git a/osi/test/alarm_test.cpp b/osi/test/alarm_test.cpp
index 954468c..e4436aa 100644
--- a/osi/test/alarm_test.cpp
+++ b/osi/test/alarm_test.cpp
@@ -336,6 +336,123 @@
   thread_free(thread);
 }
 
+// Test whether unregistering a processing queue cancels all timers using
+// that queue.
+TEST_F(AlarmTest, test_unregister_processing_queue) {
+  alarm_t *alarms[100];
+  fixed_queue_t *queue = fixed_queue_new(SIZE_MAX);
+  thread_t *thread =
+    thread_new("timers.test_unregister_processing_queue.thread");
+
+  alarm_register_processing_queue(queue, thread);
+
+  for (int i = 0; i < 100; i++) {
+    const std::string alarm_name =
+      "alarm_test.test_unregister_processing_queue[" +
+      std::to_string(i) + "]";
+    alarms[i] = alarm_new(alarm_name.c_str());
+  }
+
+  // Schedule half of the timers to expire soon, and the rest far in the future
+  for (int i = 0; i < 50; i++) {
+    alarm_set_on_queue(alarms[i], 100, ordered_cb, INT_TO_PTR(i), queue);
+  }
+  for (int i = 50; i < 100; i++) {
+    alarm_set_on_queue(alarms[i], 1000 * 1000, ordered_cb, INT_TO_PTR(i), queue);
+  }
+
+  // Wait until half of the timers have expired
+  for (int i = 1; i <= 50; i++) {
+    semaphore_wait(semaphore);
+    EXPECT_GE(cb_counter, i);
+  }
+  EXPECT_EQ(cb_counter, 50);
+  EXPECT_EQ(cb_misordered_counter, 0);
+
+  // Test that only the expired timers are not scheduled
+  for (int i = 0; i < 50; i++) {
+    EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+  }
+  for (int i = 50; i < 100; i++) {
+    EXPECT_TRUE(alarm_is_scheduled(alarms[i]));
+  }
+
+  alarm_unregister_processing_queue(queue);
+
+  // Test that none of the timers are scheduled
+  for (int i = 0; i < 100; i++) {
+    EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+  }
+
+  for (int i = 0; i < 100; i++) {
+    alarm_free(alarms[i]);
+  }
+
+  EXPECT_FALSE(WakeLockHeld());
+
+  fixed_queue_free(queue, NULL);
+  thread_free(thread);
+}
+
+// Test whether unregistering a processing queue cancels all periodic timers
+// using that queue.
+TEST_F(AlarmTest, test_periodic_unregister_processing_queue) {
+  alarm_t *alarms[5];
+  fixed_queue_t *queue = fixed_queue_new(SIZE_MAX);
+  thread_t *thread =
+    thread_new("timers.test_periodic_unregister_processing_queue.thread");
+
+  alarm_register_processing_queue(queue, thread);
+
+  for (int i = 0; i < 5; i++) {
+    const std::string alarm_name =
+      "alarm_test.test_periodic_unregister_processing_queue[" +
+      std::to_string(i) + "]";
+    alarms[i] = alarm_new_periodic(alarm_name.c_str());
+  }
+
+  // Schedule each of the timers with different period
+  for (int i = 0; i < 5; i++) {
+    alarm_set_on_queue(alarms[i], 20 + i, cb, INT_TO_PTR(i), queue);
+  }
+  EXPECT_EQ(cb_counter, 0);
+  EXPECT_TRUE(WakeLockHeld());
+
+  for (int i = 1; i <= 20; i++) {
+    semaphore_wait(semaphore);
+
+    EXPECT_GE(cb_counter, i);
+    EXPECT_TRUE(WakeLockHeld());
+  }
+
+  // Test that all timers are still scheduled
+  for (int i = 0; i < 5; i++) {
+    EXPECT_TRUE(alarm_is_scheduled(alarms[i]));
+  }
+
+  alarm_unregister_processing_queue(queue);
+
+  int saved_cb_counter = cb_counter;
+
+  // Test that none of the timers are scheduled
+  for (int i = 0; i < 5; i++) {
+    EXPECT_FALSE(alarm_is_scheduled(alarms[i]));
+  }
+
+  // Sleep for 500ms and test again that the cb_counter hasn't been modified
+  usleep(500 * 1000);
+  EXPECT_TRUE(cb_counter == saved_cb_counter);
+
+  for (int i = 0; i < 5; i++) {
+    alarm_free(alarms[i]);
+  }
+
+  EXPECT_FALSE(WakeLockHeld());
+
+  fixed_queue_free(queue, NULL);
+  thread_free(thread);
+}
+
 // Try to catch any race conditions between the timer callback and |alarm_free|.
 TEST_F(AlarmTest, test_callback_free_race) {
   for (int i = 0; i < 1000; ++i) {