Snap for 10385628 from a8b6c4ca357727736da22378a26e2d5e15a19518 to udc-d1-release

Change-Id: Icbabbdfd121932e1aa53ac0edc9871b5c6e328b4
diff --git a/core/ble_request_manager.cc b/core/ble_request_manager.cc
index 811af1d..0c8605f 100644
--- a/core/ble_request_manager.cc
+++ b/core/ble_request_manager.cc
@@ -171,7 +171,7 @@
       success = updateRequests(std::move(request), hasExistingRequest,
                                &requestChanged, &requestIndex);
       if (success) {
-        if (!asyncResponsePending()) {
+        if (!mPlatformRequestInProgress) {
           if (!requestChanged) {
             handleAsyncResult(instanceId, enabled, true /* success */,
                               CHRE_ERROR_NONE);
@@ -219,6 +219,7 @@
         req.setRequestStatus(RequestStatus::PENDING_RESP);
       }
     }
+    mPlatformRequestInProgress = true;
   }
 
   return success;
@@ -266,27 +267,21 @@
     success = false;
     CHRE_ASSERT_LOG(false, "Unable to stop BLE scan");
   }
-  if (mInternalRequestPending) {
-    mInternalRequestPending = false;
-    if (!success) {
-      LOGE("Failed to resync BLE platform");
-    }
-  } else {
-    for (BleRequest &req : mRequests.getMutableRequests()) {
-      if (req.getRequestStatus() == RequestStatus::PENDING_RESP) {
-        handleAsyncResult(req.getInstanceId(), req.isEnabled(), success,
-                          errorCode);
-        if (success) {
-          req.setRequestStatus(RequestStatus::APPLIED);
-        }
+
+  mPlatformRequestInProgress = false;
+  for (BleRequest &req : mRequests.getMutableRequests()) {
+    if (req.getRequestStatus() == RequestStatus::PENDING_RESP) {
+      handleAsyncResult(req.getInstanceId(), req.isEnabled(), success,
+                        errorCode);
+      if (success) {
+        req.setRequestStatus(RequestStatus::APPLIED);
       }
     }
-
-    if (!success) {
-      mRequests.removeRequests(RequestStatus::PENDING_RESP);
-    }
   }
-  if (success) {
+
+  if (!success) {
+    mRequests.removeRequests(RequestStatus::PENDING_RESP);
+  } else {
     // No need to waste memory for requests that have no effect on the overall
     // maximal request.
     mRequests.removeDisabledRequests();
@@ -301,7 +296,7 @@
   if (mResyncPending) {
     if (success) {
       mResyncPending = false;
-    } else if (!success && !asyncResponsePending()) {
+    } else if (!success && !mPlatformRequestInProgress) {
       mResyncPending = false;
       updatePlatformRequest(true /* forceUpdate */);
     }
@@ -311,7 +306,7 @@
   // If both a resync and a setting change are pending, prioritize the resync.
   // If the resync successfully completes, the PAL will be in the correct state
   // and updatePlatformRequest will not begin a new request.
-  if (mSettingChangePending && !asyncResponsePending()) {
+  if (mSettingChangePending && !mPlatformRequestInProgress) {
     updatePlatformRequest();
     mSettingChangePending = false;
   }
@@ -374,7 +369,7 @@
 }
 
 void BleRequestManager::handleRequestStateResyncCallbackSync() {
-  if (asyncResponsePending()) {
+  if (mPlatformRequestInProgress) {
     mResyncPending = true;
   } else {
     updatePlatformRequest(true /* forceUpdate */);
@@ -476,7 +471,7 @@
 
 void BleRequestManager::onSettingChanged(Setting setting, bool /* state */) {
   if (setting == Setting::BLE_AVAILABLE) {
-    if (asyncResponsePending()) {
+    if (mPlatformRequestInProgress) {
       mSettingChangePending = true;
     } else {
       updatePlatformRequest();
@@ -492,7 +487,6 @@
 
   if (updatePlatform) {
     if (controlPlatform()) {
-      mInternalRequestPending = true;
       addBleRequestLog(CHRE_INSTANCE_ID, desiredPlatformState,
                        mRequests.getRequests().size(),
                        true /* compliesWithBleSetting */);
@@ -502,11 +496,6 @@
   }
 }
 
-bool BleRequestManager::asyncResponsePending() const {
-  return (mInternalRequestPending ||
-          mRequests.hasRequests(RequestStatus::PENDING_RESP));
-}
-
 bool BleRequestManager::validateParams(const BleRequest &request) {
   bool valid = true;
   if (request.isEnabled()) {
@@ -557,7 +546,7 @@
   debugDump.print(" Active Platform Request:\n");
   mActivePlatformRequest.logStateToBuffer(debugDump,
                                           true /* isPlatformRequest */);
-  if (asyncResponsePending()) {
+  if (mPlatformRequestInProgress) {
     debugDump.print(" Pending Platform Request:\n");
     mPendingPlatformRequest.logStateToBuffer(debugDump,
                                              true /* isPlatformRequest */);
diff --git a/core/include/chre/core/ble_request_manager.h b/core/include/chre/core/ble_request_manager.h
index adc9cd5..747b5a7 100644
--- a/core/include/chre/core/ble_request_manager.h
+++ b/core/include/chre/core/ble_request_manager.h
@@ -213,8 +213,8 @@
   // Current state of the platform.
   BleRequest mActivePlatformRequest;
 
-  // True if a request from the PAL is currently pending.
-  bool mInternalRequestPending;
+  // True if a platform request is in progress.
+  bool mPlatformRequestInProgress;
 
   // True if a state resync request is pending to be processed.
   bool mResyncPending;
@@ -396,12 +396,6 @@
   void updatePlatformRequest(bool forceUpdate = false);
 
   /**
-   * @return true if an async response is pending from BLE. This method should
-   * be used to check if a BLE platform request is in progress.
-   */
-  bool asyncResponsePending() const;
-
-  /**
    * Validates the parameters given to ensure that they can be issued to the
    * PAL.
    *
diff --git a/platform/linux/include/chre/platform/linux/pal_ble.h b/platform/linux/include/chre/platform/linux/pal_ble.h
index c67e027..1fef017 100644
--- a/platform/linux/include/chre/platform/linux/pal_ble.h
+++ b/platform/linux/include/chre/platform/linux/pal_ble.h
@@ -17,9 +17,28 @@
 #ifndef CHRE_PLATFORM_LINUX_PAL_BLE_H_
 #define CHRE_PLATFORM_LINUX_PAL_BLE_H_
 
+#include <chrono>
+
 /**
  * @return true if the BLE PAL is enabled.
  */
 bool chrePalIsBleEnabled();
 
+/**
+ * Delay starting a BLE scan. Callers should use this function to delay the BLE
+ * start scan async response until startBleScan is called.
+ *
+ * @param delay true if the scan should be delayed.
+ */
+void delayBleScanStart(bool delay);
+
+/**
+ * Starts a BLE scan. This function is intended to be used after delaying the
+ * PAL's async response via delayBleScanStart and after chrePalBleStartScan is
+ * called.
+ *
+ * @return true if the scan was start successfully.
+ */
+bool startBleScan();
+
 #endif  // CHRE_PLATFORM_LINUX_PAL_BLE_H_
\ No newline at end of file
diff --git a/platform/linux/pal_ble.cc b/platform/linux/pal_ble.cc
index f29fab1..bb4b144 100644
--- a/platform/linux/pal_ble.cc
+++ b/platform/linux/pal_ble.cc
@@ -17,6 +17,7 @@
 #include "chre/pal/ble.h"
 
 #include "chre.h"
+#include "chre/platform/linux/pal_ble.h"
 #include "chre/platform/linux/task_util/task_manager.h"
 #include "chre/util/memory.h"
 #include "chre/util/unique_ptr.h"
@@ -35,28 +36,28 @@
 const struct chrePalBleCallbacks *gCallbacks = nullptr;
 
 bool gBleEnabled = false;
+bool gDelayScanStart = false;
+std::chrono::milliseconds gScanInterval(1400);
 
-// Tasks for startScan and stopScan.
-std::optional<uint32_t> gBleStartScanTaskId;
-std::optional<uint32_t> gBleStopScanTaskId;
+// Tasks for startScan, sendAdReportEvents, and stopScan.
+std::optional<uint32_t> gBleAdReportEventTaskId;
 
-std::chrono::milliseconds scanModeToInterval(chreBleScanMode mode) {
-  std::chrono::milliseconds interval(1000);
+void updateScanInterval(chreBleScanMode mode) {
+  gScanInterval = std::chrono::milliseconds(1400);
   switch (mode) {
     case CHRE_BLE_SCAN_MODE_BACKGROUND:
-      interval = std::chrono::milliseconds(2000);
+      gScanInterval = std::chrono::milliseconds(1400);
       break;
     case CHRE_BLE_SCAN_MODE_FOREGROUND:
-      interval = std::chrono::milliseconds(1000);
+      gScanInterval = std::chrono::milliseconds(700);
       break;
     case CHRE_BLE_SCAN_MODE_AGGRESSIVE:
-      interval = std::chrono::milliseconds(500);
+      gScanInterval = std::chrono::milliseconds(100);
       break;
   }
-  return interval;
 }
 
-void startScan() {
+void sendAdReportEvents() {
   auto event = chre::MakeUniqueZeroFill<struct chreBleAdvertisementEvent>();
   auto report = chre::MakeUniqueZeroFill<struct chreBleAdvertisingReport>();
   uint8_t *data =
@@ -71,18 +72,19 @@
   gCallbacks->advertisingEventCallback(event.release());
 }
 
-void stopScan() {
-  gCallbacks->scanStatusChangeCallback(false, CHRE_ERROR_NONE);
+void stopAllTasks() {
+  if (gBleAdReportEventTaskId.has_value()) {
+    TaskManagerSingleton::get()->cancelTask(gBleAdReportEventTaskId.value());
+  }
 }
 
-void stopAllTasks() {
-  if (gBleStartScanTaskId.has_value()) {
-    TaskManagerSingleton::get()->cancelTask(gBleStartScanTaskId.value());
-  }
-
-  if (gBleStopScanTaskId.has_value()) {
-    TaskManagerSingleton::get()->cancelTask(gBleStopScanTaskId.value());
-  }
+bool startScan() {
+  stopAllTasks();
+  gCallbacks->scanStatusChangeCallback(true, CHRE_ERROR_NONE);
+  gBleEnabled = true;
+  gBleAdReportEventTaskId =
+      TaskManagerSingleton::get()->addTask(sendAdReportEvents, gScanInterval);
+  return gBleAdReportEventTaskId.has_value();
 }
 
 uint32_t chrePalBleGetCapabilities() {
@@ -98,26 +100,16 @@
 
 bool chrePalBleStartScan(chreBleScanMode mode, uint32_t /* reportDelayMs */,
                          const struct chreBleScanFilter * /* filter */) {
-  stopAllTasks();
-
-  gCallbacks->scanStatusChangeCallback(true, CHRE_ERROR_NONE);
-  gBleStartScanTaskId =
-      TaskManagerSingleton::get()->addTask(startScan, scanModeToInterval(mode));
-  if (!gBleStartScanTaskId.has_value()) {
-    return false;
+  updateScanInterval(mode);
+  if (gDelayScanStart) {
+    return true;
   }
-
-  gBleEnabled = true;
-  return true;
+  return startScan();
 }
 
 bool chrePalBleStopScan() {
   stopAllTasks();
-  gBleStopScanTaskId = TaskManagerSingleton::get()->addTask(stopScan);
-  if (!gBleStopScanTaskId.has_value()) {
-    return false;
-  }
-
+  gCallbacks->scanStatusChangeCallback(false, CHRE_ERROR_NONE);
   gBleEnabled = false;
   return true;
 }
@@ -161,6 +153,14 @@
   return gBleEnabled;
 }
 
+void delayBleScanStart(bool delay) {
+  gDelayScanStart = delay;
+}
+
+bool startBleScan() {
+  return startScan();
+}
+
 const struct chrePalBleApi *chrePalBleGetApi(uint32_t requestedApiVersion) {
   static const struct chrePalBleApi kApi = {
       .moduleVersion = CHRE_PAL_BLE_API_CURRENT_VERSION,
diff --git a/test/simulation/ble_test.cc b/test/simulation/ble_test.cc
index c1f505d..24fe044 100644
--- a/test/simulation/ble_test.cc
+++ b/test/simulation/ble_test.cc
@@ -46,27 +46,27 @@
   struct App : public TestNanoapp {
     uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI;
 
-    decltype(nanoappHandleEvent) *handleEvent =
-        [](uint32_t, uint16_t eventType, const void *eventData) {
-          switch (eventType) {
-            case CHRE_EVENT_TEST_EVENT: {
-              auto event = static_cast<const TestEvent *>(eventData);
-              switch (event->type) {
-                case GET_CAPABILITIES: {
-                  TestEventQueueSingleton::get()->pushEvent(
-                      GET_CAPABILITIES, chreBleGetCapabilities());
-                  break;
-                }
+    decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
+                                                   const void *eventData) {
+      switch (eventType) {
+        case CHRE_EVENT_TEST_EVENT: {
+          auto event = static_cast<const TestEvent *>(eventData);
+          switch (event->type) {
+            case GET_CAPABILITIES: {
+              TestEventQueueSingleton::get()->pushEvent(
+                  GET_CAPABILITIES, chreBleGetCapabilities());
+              break;
+            }
 
-                case GET_FILTER_CAPABILITIES: {
-                  TestEventQueueSingleton::get()->pushEvent(
-                      GET_FILTER_CAPABILITIES, chreBleGetFilterCapabilities());
-                  break;
-                }
-              }
+            case GET_FILTER_CAPABILITIES: {
+              TestEventQueueSingleton::get()->pushEvent(
+                  GET_FILTER_CAPABILITIES, chreBleGetFilterCapabilities());
+              break;
             }
           }
-        };
+        }
+      }
+    };
   };
 
   auto app = loadNanoapp<App>();
@@ -300,39 +300,38 @@
   CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
 
   struct App : public BleTestNanoapp {
-    decltype(nanoappHandleEvent) *handleEvent =
-        [](uint32_t, uint16_t eventType, const void *eventData) {
-          switch (eventType) {
-            case CHRE_EVENT_BLE_ASYNC_RESULT: {
-              auto *event =
-                  static_cast<const struct chreAsyncResult *>(eventData);
-              if (event->errorCode == CHRE_ERROR_NONE) {
-                uint16_t type =
-                    (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN)
-                        ? SCAN_STARTED
-                        : SCAN_STOPPED;
-                TestEventQueueSingleton::get()->pushEvent(type);
-              }
-              break;
-            }
+    decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
+                                                   const void *eventData) {
+      switch (eventType) {
+        case CHRE_EVENT_BLE_ASYNC_RESULT: {
+          auto *event = static_cast<const struct chreAsyncResult *>(eventData);
+          if (event->errorCode == CHRE_ERROR_NONE) {
+            uint16_t type =
+                (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN)
+                    ? SCAN_STARTED
+                    : SCAN_STOPPED;
+            TestEventQueueSingleton::get()->pushEvent(type);
+          }
+          break;
+        }
 
-            case CHRE_EVENT_BLE_ADVERTISEMENT: {
-              FATAL_ERROR("No advertisement expected");
-              break;
-            }
+        case CHRE_EVENT_BLE_ADVERTISEMENT: {
+          FATAL_ERROR("No advertisement expected");
+          break;
+        }
 
-            case CHRE_EVENT_TEST_EVENT: {
-              auto event = static_cast<const TestEvent *>(eventData);
-              switch (event->type) {
-                case STOP_SCAN: {
-                  const bool success = chreBleStopScanAsync();
-                  TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success);
-                  break;
-                }
-              }
+        case CHRE_EVENT_TEST_EVENT: {
+          auto event = static_cast<const TestEvent *>(eventData);
+          switch (event->type) {
+            case STOP_SCAN: {
+              const bool success = chreBleStopScanAsync();
+              TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success);
+              break;
             }
           }
-        };
+        }
+      }
+    };
   };
 
   auto app = loadNanoapp<App>();
@@ -513,44 +512,43 @@
   CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
 
   struct App : public BleTestNanoapp {
-    decltype(nanoappHandleEvent) *handleEvent =
-        [](uint32_t, uint16_t eventType, const void *eventData) {
-          switch (eventType) {
-            case CHRE_EVENT_BLE_ASYNC_RESULT: {
-              auto *event =
-                  static_cast<const struct chreAsyncResult *>(eventData);
-              if (event->errorCode == CHRE_ERROR_NONE) {
-                uint16_t type =
-                    (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN)
-                        ? SCAN_STARTED
-                        : SCAN_STOPPED;
-                TestEventQueueSingleton::get()->pushEvent(type);
-              }
-              break;
-            }
+    decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
+                                                   const void *eventData) {
+      switch (eventType) {
+        case CHRE_EVENT_BLE_ASYNC_RESULT: {
+          auto *event = static_cast<const struct chreAsyncResult *>(eventData);
+          if (event->errorCode == CHRE_ERROR_NONE) {
+            uint16_t type =
+                (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN)
+                    ? SCAN_STARTED
+                    : SCAN_STOPPED;
+            TestEventQueueSingleton::get()->pushEvent(type);
+          }
+          break;
+        }
 
-            case CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE: {
-              auto *event =
-                  static_cast<const chreUserSettingChangedEvent *>(eventData);
-              bool enabled =
-                  (event->settingState == CHRE_USER_SETTING_STATE_ENABLED);
-              TestEventQueueSingleton::get()->pushEvent(
-                  CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE, enabled);
-              break;
-            }
+        case CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE: {
+          auto *event =
+              static_cast<const chreUserSettingChangedEvent *>(eventData);
+          bool enabled =
+              (event->settingState == CHRE_USER_SETTING_STATE_ENABLED);
+          TestEventQueueSingleton::get()->pushEvent(
+              CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE, enabled);
+          break;
+        }
 
-            case CHRE_EVENT_TEST_EVENT: {
-              auto event = static_cast<const TestEvent *>(eventData);
-              switch (event->type) {
-                case STOP_SCAN: {
-                  const bool success = chreBleStopScanAsync();
-                  TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success);
-                  break;
-                }
-              }
+        case CHRE_EVENT_TEST_EVENT: {
+          auto event = static_cast<const TestEvent *>(eventData);
+          switch (event->type) {
+            case STOP_SCAN: {
+              const bool success = chreBleStopScanAsync();
+              TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success);
+              break;
             }
           }
-        };
+        }
+      }
+    };
   };
 
   auto app = loadNanoapp<App>();
@@ -631,5 +629,81 @@
   waitForEvent(CHRE_EVENT_BLE_RSSI_READ);
 }
 
+/**
+ * This test validates that a nanoapp can start call start scan twice before
+ * receiving an async response. It should invalidate its original request by
+ * calling start scan a second time.
+ */
+TEST_F(TestBase, BleStartScanTwiceBeforeAsyncResponseTest) {
+  CREATE_CHRE_TEST_EVENT(START_SCAN, 0);
+  CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1);
+  CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2);
+  CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3);
+
+  struct App : public BleTestNanoapp {
+    decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType,
+                                                   const void *eventData) {
+      switch (eventType) {
+        case CHRE_EVENT_BLE_ASYNC_RESULT: {
+          auto *event = static_cast<const struct chreAsyncResult *>(eventData);
+          uint16_t type =
+              (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN)
+                  ? SCAN_STARTED
+                  : SCAN_STOPPED;
+          TestEventQueueSingleton::get()->pushEvent(type, event->errorCode);
+          break;
+        }
+        case CHRE_EVENT_TEST_EVENT: {
+          auto event = static_cast<const TestEvent *>(eventData);
+          switch (event->type) {
+            case START_SCAN: {
+              const bool success = chreBleStartScanAsync(
+                  CHRE_BLE_SCAN_MODE_BACKGROUND, 0, nullptr);
+              TestEventQueueSingleton::get()->pushEvent(START_SCAN, success);
+              break;
+            }
+
+            case STOP_SCAN: {
+              const bool success = chreBleStopScanAsync();
+              TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success);
+              break;
+            }
+          }
+        }
+      }
+    };
+  };
+
+  auto app = loadNanoapp<App>();
+  bool success;
+
+  delayBleScanStart(true /* delay */);
+
+  sendEventToNanoapp(app, START_SCAN);
+  waitForEvent(START_SCAN, &success);
+  EXPECT_TRUE(success);
+
+  sendEventToNanoapp(app, START_SCAN);
+  waitForEvent(START_SCAN, &success);
+  EXPECT_TRUE(success);
+
+  uint8_t errorCode;
+  waitForEvent(SCAN_STARTED, &errorCode);
+  EXPECT_EQ(errorCode, CHRE_ERROR_OBSOLETE_REQUEST);
+
+  // Respond to the first scan request. CHRE will then attempt the next scan
+  // request at which point the PAL should no longer delay the response.
+  delayBleScanStart(false /* delay */);
+  EXPECT_TRUE(startBleScan());
+
+  waitForEvent(SCAN_STARTED, &errorCode);
+  EXPECT_EQ(errorCode, CHRE_ERROR_NONE);
+
+  sendEventToNanoapp(app, STOP_SCAN);
+  waitForEvent(STOP_SCAN, &success);
+  EXPECT_TRUE(success);
+  waitForEvent(SCAN_STOPPED);
+}
+
 }  // namespace
 }  // namespace chre