1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <general_test/basic_ble_test.h>
18 
19 #include <shared/send_message.h>
20 
21 #include "chre/util/nanoapp/ble.h"
22 #include "chre/util/time.h"
23 #include "chre_api/chre.h"
24 
25 /*
26  * Test to check expected functionality of the CHRE BLE APIs.
27  */
28 namespace general_test {
29 
30 using chre::createBleScanFilterForKnownBeacons;
31 using chre::ble_constants::kNumScanFilters;
32 using nanoapp_testing::sendFatalFailureToHost;
33 
34 namespace {
35 const uint32_t gFlushCookie = 0;
36 constexpr uint32_t kGoodReservedValue = 0;
37 constexpr uint8_t kMaxReportAdvertisingSid = 0x0f;
38 }  // namespace
39 
testScanSessionAsync(bool supportsBatching,bool supportsFiltering)40 void testScanSessionAsync(bool supportsBatching, bool supportsFiltering) {
41   uint32_t reportDelayMs = supportsBatching ? 1000 : 0;
42 
43   struct chreBleScanFilter filter;
44   chreBleGenericFilter uuidFilters[kNumScanFilters];
45   if (supportsFiltering) {
46     createBleScanFilterForKnownBeacons(filter, uuidFilters, kNumScanFilters);
47   }
48 
49   if (!chreBleStartScanAsync(CHRE_BLE_SCAN_MODE_FOREGROUND /* mode */,
50                              reportDelayMs,
51                              supportsFiltering ? &filter : nullptr)) {
52     sendFatalFailureToHost("Failed to start a BLE scan in the foreground");
53   }
54 }
55 
BasicBleTest()56 BasicBleTest::BasicBleTest()
57     : Test(CHRE_API_VERSION_1_7),
58       mFlushWasCalled(false),
59       mSupportsBatching(false) {}
60 
setUp(uint32_t messageSize,const void *)61 void BasicBleTest::setUp(uint32_t messageSize, const void * /* message */) {
62   if (messageSize != 0) {
63     sendFatalFailureToHost("Expected 0 byte message, got more bytes:",
64                            &messageSize);
65   }
66 
67   mSupportsBatching =
68       isCapabilitySet(CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING);
69   mSupportsFiltering =
70       isFilterCapabilitySet(CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA) &&
71       isFilterCapabilitySet(CHRE_BLE_FILTER_CAPABILITIES_RSSI);
72 
73   if (!isCapabilitySet(CHRE_BLE_CAPABILITIES_SCAN)) {
74     mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_SCAN);
75     mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_FLUSH);
76     return;
77   }
78 
79   testScanSessionAsync(mSupportsBatching, mSupportsFiltering);
80   if (!mSupportsBatching) {
81     mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_FLUSH);
82   }
83 }
84 
handleBleAsyncResult(const chreAsyncResult * result)85 void BasicBleTest::handleBleAsyncResult(const chreAsyncResult *result) {
86   if (result == nullptr || !result->success) {
87     sendFatalFailureToHost("Received unsuccessful BLE async result");
88   }
89 
90   switch (result->requestType) {
91     case CHRE_BLE_REQUEST_TYPE_START_SCAN:
92       // Wait one second to allow any advertisement events to propagate
93       // and be verified by handleAdvertisementEvent.
94       if (chreTimerSet(chre::kOneSecondInNanoseconds, nullptr, true) ==
95           CHRE_TIMER_INVALID) {
96         sendFatalFailureToHost(
97             "Failed to start a timer after BLE started scanning");
98       }
99       break;
100     case CHRE_BLE_REQUEST_TYPE_FLUSH:
101       if (result->cookie != &gFlushCookie) {
102         sendFatalFailureToHost("Cookie values do not match");
103       }
104       break;
105     case CHRE_BLE_REQUEST_TYPE_STOP_SCAN:
106       mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_SCAN);
107       break;
108     default:
109       sendFatalFailureToHost("Unexpected request type");
110       break;
111   }
112 }
113 
handleAdvertisementEvent(const chreBleAdvertisementEvent * event)114 void BasicBleTest::handleAdvertisementEvent(
115     const chreBleAdvertisementEvent *event) {
116   if (event == nullptr) {
117     sendFatalFailureToHost("Invalid chreBleAdvertisementEvent");
118   } else if (event->reserved != kGoodReservedValue) {
119     sendFatalFailureToHost("chreBleAdvertisementEvent: reserved != 0");
120   } else {
121     for (uint16_t i = 0; i < event->numReports; ++i) {
122       const struct chreBleAdvertisingReport &report = event->reports[i];
123       if (report.advertisingSid != CHRE_BLE_ADI_NONE &&
124           report.advertisingSid > kMaxReportAdvertisingSid) {
125         sendFatalFailureToHost(
126             "chreBleAdvertisingReport: advertisingSid is invalid");
127       } else if (report.reserved != kGoodReservedValue) {
128         sendFatalFailureToHost("chreBleAdvertisingReport: reserved is invalid");
129       }
130     }
131   }
132 }
133 
handleTimerEvent()134 void BasicBleTest::handleTimerEvent() {
135   if (mSupportsBatching) {
136     if (!chreBleFlushAsync(&gFlushCookie)) {
137       sendFatalFailureToHost("Failed to BLE flush");
138     }
139     mFlushWasCalled = true;
140   } else {
141     if (chreBleFlushAsync(&gFlushCookie)) {
142       sendFatalFailureToHost(
143           "chreBleFlushAsync should return false if batching is not supported");
144     }
145 
146     if (!chreBleStopScanAsync()) {
147       sendFatalFailureToHost("Failed to stop a BLE scan session");
148     }
149   }
150 }
151 
handleEvent(uint32_t,uint16_t eventType,const void * eventData)152 void BasicBleTest::handleEvent(uint32_t /* senderInstanceId */,
153                                uint16_t eventType, const void *eventData) {
154   switch (eventType) {
155     case CHRE_EVENT_BLE_ASYNC_RESULT:
156       handleBleAsyncResult(static_cast<const chreAsyncResult *>(eventData));
157       break;
158     case CHRE_EVENT_BLE_FLUSH_COMPLETE:
159       if (!mFlushWasCalled) {
160         sendFatalFailureToHost(
161             "Received CHRE_EVENT_BLE_FLUSH_COMPLETE event when "
162             "chreBleFlushAsync was not called");
163       }
164       if (!chreBleStopScanAsync()) {
165         sendFatalFailureToHost("Failed to stop a BLE scan session");
166       }
167       mTestSuccessMarker.markStageAndSuccessOnFinish(
168           BASIC_BLE_TEST_STAGE_FLUSH);
169       break;
170     case CHRE_EVENT_BLE_ADVERTISEMENT:
171       handleAdvertisementEvent(
172           static_cast<const chreBleAdvertisementEvent *>(eventData));
173       break;
174     case CHRE_EVENT_BLE_BATCH_COMPLETE:
175       // Ignore the event only if we support batching.
176       // Otherwise, it is an unexpected event.
177       if (!mSupportsBatching) {
178         unexpectedEvent(eventType);
179       }
180       break;
181     case CHRE_EVENT_TIMER:
182       handleTimerEvent();
183       break;
184     default:
185       unexpectedEvent(eventType);
186       break;
187   }
188 }
189 
190 }  // namespace general_test
191