/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "chre/common.h" #include "inc/test_util.h" #include "test_base.h" #include #include #include "chre/core/event_loop_manager.h" #include "chre/core/settings.h" #include "chre/platform/fatal_error.h" #include "chre/platform/linux/pal_ble.h" #include "chre/util/dynamic_vector.h" #include "chre_api/chre/ble.h" #include "chre_api/chre/user_settings.h" #include "test_util.h" namespace chre { namespace { /** * This test verifies that a nanoapp can query for BLE capabilities and filter * capabilities. Note that a nanoapp does not require BLE permissions to use * these APIs. */ TEST_F(TestBase, BleCapabilitiesTest) { CREATE_CHRE_TEST_EVENT(GET_CAPABILITIES, 0); CREATE_CHRE_TEST_EVENT(GET_FILTER_CAPABILITIES, 1); class App : public TestNanoapp { public: App() : TestNanoapp( TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {} void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(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; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); uint32_t capabilities; sendEventToNanoapp(appId, GET_CAPABILITIES); waitForEvent(GET_CAPABILITIES, &capabilities); ASSERT_EQ(capabilities, CHRE_BLE_CAPABILITIES_SCAN | CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING | CHRE_BLE_CAPABILITIES_SCAN_FILTER_BEST_EFFORT); sendEventToNanoapp(appId, GET_FILTER_CAPABILITIES); waitForEvent(GET_FILTER_CAPABILITIES, &capabilities); ASSERT_EQ(capabilities, CHRE_BLE_FILTER_CAPABILITIES_RSSI | CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA); } class BleTestNanoapp : public TestNanoapp { public: BleTestNanoapp() : TestNanoapp( TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_BLE}) {} bool start() override { chreUserSettingConfigureEvents(CHRE_USER_SETTING_BLE_AVAILABLE, true /* enable */); return true; } void end() override { chreUserSettingConfigureEvents(CHRE_USER_SETTING_BLE_AVAILABLE, false /* enable */); } }; /** * This test validates the case in which a nanoapp starts a scan, receives * at least one advertisement event, and stops a scan. */ TEST_F(TestBase, BleSimpleScanTest) { 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); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(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: { TestEventQueueSingleton::get()->pushEvent( CHRE_EVENT_BLE_ADVERTISEMENT); break; } case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(eventData); switch (event->type) { case START_SCAN: { const bool success = chreBleStartScanAsync( CHRE_BLE_SCAN_MODE_AGGRESSIVE, 0, nullptr); TestEventQueueSingleton::get()->pushEvent(START_SCAN, success); break; } case STOP_SCAN: { const bool success = chreBleStopScanAsync(); TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success); break; } } break; } } } }; uint64_t appId = loadNanoapp(MakeUnique()); bool success; sendEventToNanoapp(appId, START_SCAN); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STARTED); ASSERT_TRUE(chrePalIsBleEnabled()); waitForEvent(CHRE_EVENT_BLE_ADVERTISEMENT); sendEventToNanoapp(appId, STOP_SCAN); waitForEvent(STOP_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STOPPED); ASSERT_FALSE(chrePalIsBleEnabled()); } TEST_F(TestBase, BleStopScanOnUnload) { CREATE_CHRE_TEST_EVENT(START_SCAN, 0); CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(eventData); if (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN && event->errorCode == CHRE_ERROR_NONE) { TestEventQueueSingleton::get()->pushEvent(SCAN_STARTED); } break; } case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(eventData); switch (event->type) { case START_SCAN: { const bool success = chreBleStartScanAsync( CHRE_BLE_SCAN_MODE_AGGRESSIVE, 0, nullptr); TestEventQueueSingleton::get()->pushEvent(START_SCAN, success); break; } } break; } } } }; uint64_t appId = loadNanoapp(MakeUnique()); bool success; sendEventToNanoapp(appId, START_SCAN); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STARTED); ASSERT_TRUE(chrePalIsBleEnabled()); unloadNanoapp(appId); ASSERT_FALSE(chrePalIsBleEnabled()); } /** * This test validates that a nanoapp can start a scan twice and the platform * will be enabled. */ TEST_F(TestBase, BleStartTwiceScanTest) { 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); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(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: { TestEventQueueSingleton::get()->pushEvent( CHRE_EVENT_BLE_ADVERTISEMENT); break; } case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(eventData); switch (event->type) { case START_SCAN: { const bool success = chreBleStartScanAsync( CHRE_BLE_SCAN_MODE_AGGRESSIVE, 0, nullptr); TestEventQueueSingleton::get()->pushEvent(START_SCAN, success); break; } case STOP_SCAN: { const bool success = chreBleStopScanAsync(); TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success); break; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); bool success; sendEventToNanoapp(appId, START_SCAN); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STARTED); sendEventToNanoapp(appId, START_SCAN); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STARTED); waitForEvent(CHRE_EVENT_BLE_ADVERTISEMENT); sendEventToNanoapp(appId, STOP_SCAN); waitForEvent(STOP_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STOPPED); } /** * This test validates that a nanoapp can request to stop a scan twice without * any ongoing scan existing. It asserts that the nanoapp did not receive any * advertisment events because a scan was never started. */ TEST_F(TestBase, BleStopTwiceScanTest) { CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1); CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2); CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(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_TEST_EVENT: { auto event = static_cast(eventData); switch (event->type) { case STOP_SCAN: { const bool success = chreBleStopScanAsync(); TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success); break; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); bool success; sendEventToNanoapp(appId, STOP_SCAN); waitForEvent(STOP_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STOPPED); sendEventToNanoapp(appId, STOP_SCAN); waitForEvent(STOP_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STOPPED); unloadNanoapp(appId); } /** * This test verifies the following BLE settings behavior: * 1) Nanoapp makes BLE scan request * 2) Toggle BLE setting -> disabled * 3) Toggle BLE setting -> enabled. * 4) Verify things resume. */ TEST_F(TestBase, BleSettingChangeTest) { CREATE_CHRE_TEST_EVENT(START_SCAN, 0); CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1); CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(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: { TestEventQueueSingleton::get()->pushEvent( CHRE_EVENT_BLE_ADVERTISEMENT); break; } case CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE: { auto *event = static_cast(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(eventData); switch (event->type) { case START_SCAN: { const bool success = chreBleStartScanAsync( CHRE_BLE_SCAN_MODE_AGGRESSIVE, 0, nullptr); TestEventQueueSingleton::get()->pushEvent(START_SCAN, success); break; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); bool success; sendEventToNanoapp(appId, START_SCAN); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STARTED); waitForEvent(CHRE_EVENT_BLE_ADVERTISEMENT); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::BLE_AVAILABLE, false /* enabled */); bool enabled; waitForEvent(CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE, &enabled); EXPECT_FALSE(enabled); EXPECT_FALSE( EventLoopManagerSingleton::get()->getSettingManager().getSettingEnabled( Setting::BLE_AVAILABLE)); std::this_thread::sleep_for(std::chrono::milliseconds(100)); EXPECT_FALSE(chrePalIsBleEnabled()); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::BLE_AVAILABLE, true /* enabled */); waitForEvent(CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE, &enabled); EXPECT_TRUE(enabled); EXPECT_TRUE( EventLoopManagerSingleton::get()->getSettingManager().getSettingEnabled( Setting::BLE_AVAILABLE)); waitForEvent(CHRE_EVENT_BLE_ADVERTISEMENT); EXPECT_TRUE(chrePalIsBleEnabled()); } /** * Test that a nanoapp receives a function disabled error if it attempts to * start a scan when the BLE setting is disabled. */ TEST_F(TestBase, BleSettingDisabledStartScanTest) { CREATE_CHRE_TEST_EVENT(START_SCAN, 0); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(eventData); if (event->errorCode == CHRE_ERROR_FUNCTION_DISABLED) { TestEventQueueSingleton::get()->pushEvent( CHRE_EVENT_BLE_ASYNC_RESULT); } break; } case CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE: { auto *event = static_cast(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(eventData); switch (event->type) { case START_SCAN: { const bool success = chreBleStartScanAsync( CHRE_BLE_SCAN_MODE_AGGRESSIVE, 0, nullptr); TestEventQueueSingleton::get()->pushEvent(START_SCAN, success); break; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::BLE_AVAILABLE, false /* enable */); bool enabled; waitForEvent(CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE, &enabled); EXPECT_FALSE(enabled); bool success; sendEventToNanoapp(appId, START_SCAN); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); waitForEvent(CHRE_EVENT_BLE_ASYNC_RESULT); } /** * Test that a nanoapp receives a success response when it attempts to stop a * BLE scan while the BLE setting is disabled. */ TEST_F(TestBase, BleSettingDisabledStopScanTest) { CREATE_CHRE_TEST_EVENT(SCAN_STARTED, 1); CREATE_CHRE_TEST_EVENT(STOP_SCAN, 2); CREATE_CHRE_TEST_EVENT(SCAN_STOPPED, 3); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(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(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(eventData); switch (event->type) { case STOP_SCAN: { const bool success = chreBleStopScanAsync(); TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success); break; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::BLE_AVAILABLE, false /* enable */); bool enabled; waitForEvent(CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE, &enabled); EXPECT_FALSE(enabled); bool success; sendEventToNanoapp(appId, STOP_SCAN); waitForEvent(STOP_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STOPPED); } /** * Test that a nanoapp can read RSSI successfully. */ TEST_F(TestBase, BleReadRssi) { constexpr uint16_t kConnectionHandle = 6; constexpr uint32_t kCookie = 123; CREATE_CHRE_TEST_EVENT(RSSI_REQUEST, 1); CREATE_CHRE_TEST_EVENT(RSSI_REQUEST_SENT, 2); class App : public BleTestNanoapp { void handleEvent(uint32_t, uint16_t eventType, const void *eventData) { switch (eventType) { case CHRE_EVENT_BLE_RSSI_READ: { auto *event = static_cast(eventData); if (event->result.errorCode == CHRE_ERROR_NONE) { TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_BLE_RSSI_READ); } break; } case CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE: { auto *event = static_cast(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(eventData); switch (event->type) { case RSSI_REQUEST: { const bool success = chreBleReadRssiAsync(kConnectionHandle, (void *)kCookie); TestEventQueueSingleton::get()->pushEvent(RSSI_REQUEST_SENT, success); break; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::BLE_AVAILABLE, true /* enabled */); bool enabled; waitForEvent(CHRE_EVENT_SETTING_CHANGED_BLE_AVAILABLE, &enabled); EXPECT_TRUE(enabled); bool success; sendEventToNanoapp(appId, RSSI_REQUEST); waitForEvent(RSSI_REQUEST_SENT, &success); EXPECT_TRUE(success); 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 testData { void *cookie; }; class App : public BleTestNanoapp { void handleEvent(uint32_t, uint16_t eventType, const void *eventData) { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(eventData); uint16_t type = (event->requestType == CHRE_BLE_REQUEST_TYPE_START_SCAN) ? SCAN_STARTED : SCAN_STOPPED; TestEventQueueSingleton::get()->pushEvent(type, *event); break; } case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(eventData); switch (event->type) { case START_SCAN: { auto data = static_cast(event->data); const bool success = chreBleStartScanAsyncV1_9( CHRE_BLE_SCAN_MODE_AGGRESSIVE, 0, nullptr, data->cookie); TestEventQueueSingleton::get()->pushEvent(START_SCAN, success); break; } case STOP_SCAN: { auto data = static_cast(event->data); const bool success = chreBleStopScanAsyncV1_9(data->cookie); TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success); break; } } } } } }; uint64_t appId = loadNanoapp(MakeUnique()); bool success; delayBleScanStart(true /* delay */); testData data; uint32_t cookieOne = 1; data.cookie = &cookieOne; sendEventToNanoapp(appId, START_SCAN, data); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); uint32_t cookieTwo = 2; data.cookie = &cookieTwo; sendEventToNanoapp(appId, START_SCAN, data); waitForEvent(START_SCAN, &success); EXPECT_TRUE(success); chreAsyncResult result; waitForEvent(SCAN_STARTED, &result); EXPECT_EQ(result.errorCode, CHRE_ERROR_OBSOLETE_REQUEST); EXPECT_EQ(result.cookie, &cookieOne); // 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, &result); EXPECT_EQ(result.errorCode, CHRE_ERROR_NONE); EXPECT_EQ(result.cookie, &cookieTwo); sendEventToNanoapp(appId, STOP_SCAN, data); waitForEvent(STOP_SCAN, &success); EXPECT_TRUE(success); waitForEvent(SCAN_STOPPED); } /** * This test validates that a nanoapp can call flush only when an existing scan * is enabled for the nanoapp. This test validates that batching will hold the * data and flush will send the batched data and then a flush complete event. */ TEST_F(TestBase, BleFlush) { 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); CREATE_CHRE_TEST_EVENT(CALL_FLUSH, 4); CREATE_CHRE_TEST_EVENT(SAW_BLE_AD_AND_FLUSH_COMPLETE, 5); class App : public BleTestNanoapp { public: void handleEvent(uint32_t, uint16_t eventType, const void *eventData) override { switch (eventType) { case CHRE_EVENT_BLE_ASYNC_RESULT: { auto *event = static_cast(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: { mSawBleAdvertisementEvent = true; break; } case CHRE_EVENT_BLE_FLUSH_COMPLETE: { auto *event = static_cast(eventData); mSawFlushCompleteEvent = event->success && event->cookie == &mCookie; break; } case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(eventData); switch (event->type) { case START_SCAN: { const bool success = chreBleStartScanAsync( CHRE_BLE_SCAN_MODE_AGGRESSIVE, 60000, nullptr); TestEventQueueSingleton::get()->pushEvent(START_SCAN, success); break; } case STOP_SCAN: { const bool success = chreBleStopScanAsync(); TestEventQueueSingleton::get()->pushEvent(STOP_SCAN, success); break; } case CALL_FLUSH: { const bool success = chreBleFlushAsync(&mCookie); TestEventQueueSingleton::get()->pushEvent(CALL_FLUSH, success); break; } } break; } } if (mSawBleAdvertisementEvent && mSawFlushCompleteEvent) { TestEventQueueSingleton::get()->pushEvent( SAW_BLE_AD_AND_FLUSH_COMPLETE); mSawBleAdvertisementEvent = false; mSawFlushCompleteEvent = false; } } private: uint32_t mCookie; bool mSawBleAdvertisementEvent = false; bool mSawFlushCompleteEvent = false; }; uint64_t appId = loadNanoapp(MakeUnique()); // Flushing before a scan should fail. bool success; sendEventToNanoapp(appId, CALL_FLUSH); waitForEvent(CALL_FLUSH, &success); ASSERT_FALSE(success); // Start a scan with batching. sendEventToNanoapp(appId, START_SCAN); waitForEvent(START_SCAN, &success); ASSERT_TRUE(success); waitForEvent(SCAN_STARTED); ASSERT_TRUE(chrePalIsBleEnabled()); // Call flush again multiple times and get the complete event. // We should only receive data when flush is called as the batch // delay is extremely large. constexpr uint32_t kNumFlushCalls = 3; for (uint32_t i = 0; i < kNumFlushCalls; ++i) { std::this_thread::sleep_for(std::chrono::milliseconds(250)); sendEventToNanoapp(appId, CALL_FLUSH); waitForEvent(CALL_FLUSH, &success); ASSERT_TRUE(success); // Wait for some data and a flush complete. // This ensures we receive both advertisement events // and a flush complete event. We are not guaranteed // that the advertisement events will come after // the CALL_FLUSH event or before. If they come // before, then they will be ignored. This // change allows the advertisement events to come // after during the normal expiration of the // batch timer, which is valid (call flush, get // any advertisement events, flush complete event // might get some advertisement events afterwards). waitForEvent(SAW_BLE_AD_AND_FLUSH_COMPLETE); } // Stop a scan. sendEventToNanoapp(appId, STOP_SCAN); waitForEvent(STOP_SCAN, &success); ASSERT_TRUE(success); waitForEvent(SCAN_STOPPED); ASSERT_FALSE(chrePalIsBleEnabled()); // Flushing after a scan should fail. sendEventToNanoapp(appId, CALL_FLUSH); waitForEvent(CALL_FLUSH, &success); ASSERT_FALSE(success); } } // namespace } // namespace chre