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 #include <shared/send_message.h>
19
20 #include "chre/util/nanoapp/ble.h"
21 #include "chre/util/nanoapp/log.h"
22 #include "chre/util/time.h"
23 #include "chre_api/chre.h"
24
25 #define LOG_TAG "[GeneralTest][Ble]"
26 /*
27 * Test to check expected functionality of the CHRE BLE APIs.
28 */
29 namespace general_test {
30
31 using chre::createBleScanFilterForKnownBeacons;
32 using chre::ble_constants::kNumScanFilters;
33 using nanoapp_testing::sendFatalFailureToHost;
34
35 namespace {
36 const uint32_t gFlushCookie = 0;
37 constexpr uint32_t kGoodReservedValue = 0;
38 constexpr uint8_t kMaxReportAdvertisingSid = 0x0f;
39 } // namespace
40
testScanSessionAsync(bool supportsBatching,bool supportsFiltering)41 void testScanSessionAsync(bool supportsBatching, bool supportsFiltering) {
42 uint32_t reportDelayMs = supportsBatching ? 1000 : 0;
43
44 struct chreBleScanFilter filter;
45 chreBleGenericFilter uuidFilters[kNumScanFilters];
46 if (supportsFiltering) {
47 createBleScanFilterForKnownBeacons(filter, uuidFilters, kNumScanFilters);
48 }
49
50 if (!chreBleStartScanAsync(CHRE_BLE_SCAN_MODE_FOREGROUND /* mode */,
51 reportDelayMs,
52 supportsFiltering ? &filter : nullptr)) {
53 sendFatalFailureToHost("Failed to start a BLE scan in the foreground");
54 }
55 }
56
BasicBleTest()57 BasicBleTest::BasicBleTest()
58 : Test(CHRE_API_VERSION_1_7),
59 mFlushWasCalled(false),
60 mSupportsBatching(false) {}
61
setUp(uint32_t messageSize,const void *)62 void BasicBleTest::setUp(uint32_t messageSize, const void * /* message */) {
63 if (messageSize != 0) {
64 sendFatalFailureToHost("Expected 0 byte message, got more bytes:",
65 &messageSize);
66 }
67
68 mSupportsBatching =
69 isCapabilitySet(CHRE_BLE_CAPABILITIES_SCAN_RESULT_BATCHING);
70 mSupportsFiltering =
71 isFilterCapabilitySet(CHRE_BLE_FILTER_CAPABILITIES_SERVICE_DATA) &&
72 isFilterCapabilitySet(CHRE_BLE_FILTER_CAPABILITIES_RSSI);
73
74 if (!isCapabilitySet(CHRE_BLE_CAPABILITIES_SCAN)) {
75 mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_SCAN);
76 mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_FLUSH);
77 return;
78 }
79
80 testScanSessionAsync(mSupportsBatching, mSupportsFiltering);
81 if (!mSupportsBatching) {
82 mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_FLUSH);
83 }
84 }
85
handleBleAsyncResult(const chreAsyncResult * result)86 void BasicBleTest::handleBleAsyncResult(const chreAsyncResult *result) {
87 if (result == nullptr) {
88 sendFatalFailureToHost("Received null BLE async result");
89 return;
90 }
91 if (!result->success) {
92 LOGE("Received unsuccessful BLE async result, error code %" PRIu8,
93 result->errorCode);
94 sendFatalFailureToHost("Received unsuccessful BLE async result");
95 return;
96 }
97
98 switch (result->requestType) {
99 case CHRE_BLE_REQUEST_TYPE_START_SCAN:
100 // Wait one second to allow any advertisement events to propagate
101 // and be verified by handleAdvertisementEvent.
102 if (chreTimerSet(chre::kOneSecondInNanoseconds, nullptr, true) ==
103 CHRE_TIMER_INVALID) {
104 sendFatalFailureToHost(
105 "Failed to start a timer after BLE started scanning");
106 }
107 break;
108 case CHRE_BLE_REQUEST_TYPE_FLUSH:
109 if (result->cookie != &gFlushCookie) {
110 sendFatalFailureToHost("Cookie values do not match");
111 }
112 break;
113 case CHRE_BLE_REQUEST_TYPE_STOP_SCAN:
114 mTestSuccessMarker.markStageAndSuccessOnFinish(BASIC_BLE_TEST_STAGE_SCAN);
115 break;
116 default:
117 sendFatalFailureToHost("Unexpected request type");
118 break;
119 }
120 }
121
handleAdvertisementEvent(const chreBleAdvertisementEvent * event)122 void BasicBleTest::handleAdvertisementEvent(
123 const chreBleAdvertisementEvent *event) {
124 if (event == nullptr) {
125 sendFatalFailureToHost("Invalid chreBleAdvertisementEvent");
126 } else if (event->reserved != kGoodReservedValue) {
127 sendFatalFailureToHost("chreBleAdvertisementEvent: reserved != 0");
128 } else {
129 for (uint16_t i = 0; i < event->numReports; ++i) {
130 const struct chreBleAdvertisingReport &report = event->reports[i];
131 if (report.advertisingSid != CHRE_BLE_ADI_NONE &&
132 report.advertisingSid > kMaxReportAdvertisingSid) {
133 sendFatalFailureToHost(
134 "chreBleAdvertisingReport: advertisingSid is invalid");
135 } else if (report.reserved != kGoodReservedValue) {
136 sendFatalFailureToHost("chreBleAdvertisingReport: reserved is invalid");
137 }
138 }
139 }
140 }
141
handleTimerEvent()142 void BasicBleTest::handleTimerEvent() {
143 if (mSupportsBatching) {
144 if (!chreBleFlushAsync(&gFlushCookie)) {
145 sendFatalFailureToHost("Failed to BLE flush");
146 }
147 mFlushWasCalled = true;
148 } else {
149 if (chreBleFlushAsync(&gFlushCookie)) {
150 sendFatalFailureToHost(
151 "chreBleFlushAsync should return false if batching is not supported");
152 }
153
154 if (!chreBleStopScanAsync()) {
155 sendFatalFailureToHost("Failed to stop a BLE scan session");
156 }
157 }
158 }
159
handleEvent(uint32_t,uint16_t eventType,const void * eventData)160 void BasicBleTest::handleEvent(uint32_t /* senderInstanceId */,
161 uint16_t eventType, const void *eventData) {
162 switch (eventType) {
163 case CHRE_EVENT_BLE_ASYNC_RESULT:
164 handleBleAsyncResult(static_cast<const chreAsyncResult *>(eventData));
165 break;
166 case CHRE_EVENT_BLE_FLUSH_COMPLETE:
167 if (!mFlushWasCalled) {
168 sendFatalFailureToHost(
169 "Received CHRE_EVENT_BLE_FLUSH_COMPLETE event when "
170 "chreBleFlushAsync was not called");
171 }
172 if (!chreBleStopScanAsync()) {
173 sendFatalFailureToHost("Failed to stop a BLE scan session");
174 }
175 mTestSuccessMarker.markStageAndSuccessOnFinish(
176 BASIC_BLE_TEST_STAGE_FLUSH);
177 break;
178 case CHRE_EVENT_BLE_ADVERTISEMENT:
179 handleAdvertisementEvent(
180 static_cast<const chreBleAdvertisementEvent *>(eventData));
181 break;
182 case CHRE_EVENT_BLE_BATCH_COMPLETE:
183 // Ignore the event only if we support batching.
184 // Otherwise, it is an unexpected event.
185 if (!mSupportsBatching) {
186 unexpectedEvent(eventType);
187 }
188 break;
189 case CHRE_EVENT_TIMER:
190 handleTimerEvent();
191 break;
192 default:
193 unexpectedEvent(eventType);
194 break;
195 }
196 }
197
198 } // namespace general_test
199