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