1 /*
2 * Copyright (C) 2017 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 <chre.h>
18 #include <cinttypes>
19
20 #include "chre/util/nanoapp/log.h"
21 #include "chre/util/time.h"
22 #include "chre/util/nanoapp/wifi.h"
23
24 #define LOG_TAG "[WifiWorld]"
25
26 //#define WIFI_WORLD_VERBOSE_WIFI_RESULT_LOGS
27
28 #ifdef CHRE_NANOAPP_INTERNAL
29 namespace chre {
30 namespace {
31 #endif // CHRE_NANOAPP_INTERNAL
32
33 //! A dummy cookie to pass into the configure scan monitoring async request.
34 const uint32_t kScanMonitoringCookie = 0x1337;
35
36 //! A dummy cookie to pass into request scan async.
37 const uint32_t kOnDemandScanCookie = 0xcafe;
38
39 //! The interval for on-demand wifi scans.
40 const Nanoseconds kWifiScanInterval = Nanoseconds(Seconds(10));
41
42 //! A handle for the cyclic timer to request periodic on-demand wifi-scans.
43 uint32_t gWifiScanTimerHandle;
44
45 namespace {
46
47 /**
48 * Logs a CHRE wifi scan result.
49 *
50 * @param result the scan result to log.
51 */
logChreWifiResult(const chreWifiScanResult & result)52 void logChreWifiResult(const chreWifiScanResult& result) {
53 const char *ssidStr = "<non-printable>";
54 char ssidBuffer[kMaxSsidStrLen];
55 if (result.ssidLen == 0) {
56 ssidStr = "<empty>";
57 } else if (parseSsidToStr(ssidBuffer, kMaxSsidStrLen,
58 result.ssid, result.ssidLen)) {
59 ssidStr = ssidBuffer;
60 }
61
62 const char *bssidStr = "<non-printable>";
63 char bssidBuffer[kBssidStrLen];
64 if (parseBssidToStr(result.bssid, bssidBuffer, kBssidStrLen)) {
65 bssidStr = bssidBuffer;
66 }
67
68 LOGI("Found network with SSID: %s", ssidStr);
69 #ifdef WIFI_WORLD_VERBOSE_WIFI_RESULT_LOGS
70 LOGI(" age (ms): %" PRIu32, result.ageMs);
71 LOGI(" capability info: %" PRIx16, result.capabilityInfo);
72 LOGI(" bssid: %s", bssidStr);
73 LOGI(" flags: %" PRIx8, result.flags);
74 LOGI(" rssi: %" PRId8 "dBm", result.rssi);
75 LOGI(" band: %s (%" PRIu8 ")", parseChreWifiBand(result.band), result.band);
76 LOGI(" primary channel: %" PRIu32, result.primaryChannel);
77 LOGI(" center frequency primary: %" PRIu32, result.centerFreqPrimary);
78 LOGI(" center frequency secondary: %" PRIu32, result.centerFreqSecondary);
79 LOGI(" channel width: %" PRIu8, result.channelWidth);
80 LOGI(" security mode: %" PRIx8, result.securityMode);
81 #endif // WIFI_WORLD_VERBOSE_WIFI_RESULT_LOGS
82 }
83
84 /**
85 * Handles the result of an asynchronous request for a wifi resource.
86 *
87 * @param result a pointer to the event structure containing the result of the
88 * request.
89 */
handleWifiAsyncResult(const chreAsyncResult * result)90 void handleWifiAsyncResult(const chreAsyncResult *result) {
91 if (result->requestType == CHRE_WIFI_REQUEST_TYPE_CONFIGURE_SCAN_MONITOR) {
92 if (result->success) {
93 LOGI("Successfully requested wifi scan monitoring");
94 } else {
95 LOGI("Error requesting wifi scan monitoring with %" PRIu8,
96 result->errorCode);
97 }
98
99 if (result->cookie != &kScanMonitoringCookie) {
100 LOGE("Scan monitoring request cookie mismatch");
101 }
102 } else if (result->requestType == CHRE_WIFI_REQUEST_TYPE_REQUEST_SCAN) {
103 if (result->success) {
104 LOGI("Successfully requested an on-demand wifi scan");
105 } else {
106 LOGE("Error requesting an on-demand wifi scan with %" PRIu8,
107 result->errorCode);
108 }
109
110 if (result->cookie != &kOnDemandScanCookie) {
111 LOGE("On-demand scan cookie mismatch");
112 }
113 }
114 }
115
116 /**
117 * Handles a wifi scan event.
118 *
119 * @param event a pointer to the details of the wifi scan event.
120 */
handleWifiScanEvent(const chreWifiScanEvent * event)121 void handleWifiScanEvent(const chreWifiScanEvent *event) {
122 for (uint8_t i = 0; i < event->resultCount; i++) {
123 const chreWifiScanResult& result = event->results[i];
124 logChreWifiResult(result);
125 }
126 }
127
128 /**
129 * Handles a timer event.
130 *
131 * @param eventData The cookie passed to the timer request.
132 */
handleTimerEvent(const void * eventData)133 void handleTimerEvent(const void *eventData) {
134 const uint32_t *timerHandle = static_cast<const uint32_t *>(eventData);
135 if (*timerHandle == gWifiScanTimerHandle) {
136 if (chreWifiRequestScanAsyncDefault(&kOnDemandScanCookie)) {
137 LOGI("Requested a wifi scan successfully");
138 } else {
139 LOGE("Failed to request a wifi scan");
140 }
141 } else {
142 LOGE("Received invalid timer handle");
143 }
144 }
145
146 } // namespace
147
nanoappStart()148 bool nanoappStart() {
149 LOGI("App started as instance %" PRIu32, chreGetInstanceId());
150
151 const char *wifiCapabilitiesStr;
152 uint32_t wifiCapabilities = chreWifiGetCapabilities();
153 switch (wifiCapabilities) {
154 case CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN
155 | CHRE_WIFI_CAPABILITIES_SCAN_MONITORING:
156 wifiCapabilitiesStr = "ON_DEMAND_SCAN | SCAN_MONITORING";
157 break;
158 case CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN:
159 wifiCapabilitiesStr = "ON_DEMAND_SCAN";
160 break;
161 case CHRE_WIFI_CAPABILITIES_SCAN_MONITORING:
162 wifiCapabilitiesStr = "SCAN_MONITORING";
163 break;
164 case CHRE_WIFI_CAPABILITIES_NONE:
165 wifiCapabilitiesStr = "NONE";
166 break;
167 default:
168 wifiCapabilitiesStr = "INVALID";
169 }
170
171 LOGI("Detected WiFi support as: %s (%" PRIu32 ")",
172 wifiCapabilitiesStr, wifiCapabilities);
173
174 if (wifiCapabilities & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) {
175 if (chreWifiConfigureScanMonitorAsync(true, &kScanMonitoringCookie)) {
176 LOGI("Scan monitor enable request successful");
177 } else {
178 LOGE("Error sending scan monitoring request");
179 }
180 }
181
182 if (wifiCapabilities & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) {
183 // Schedule a timer to send an active wifi scan.
184 gWifiScanTimerHandle = chreTimerSet(kWifiScanInterval.toRawNanoseconds(),
185 &gWifiScanTimerHandle /* data */,
186 false /* oneShot */);
187 if (gWifiScanTimerHandle == CHRE_TIMER_INVALID) {
188 LOGE("Failed to set periodic scan timer");
189 } else {
190 LOGI("Set a timer to request periodic WiFi scans");
191 }
192 }
193
194 return true;
195 }
196
nanoappHandleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)197 void nanoappHandleEvent(uint32_t senderInstanceId,
198 uint16_t eventType,
199 const void *eventData) {
200 switch (eventType) {
201 case CHRE_EVENT_WIFI_ASYNC_RESULT:
202 handleWifiAsyncResult(static_cast<const chreAsyncResult *>(eventData));
203 break;
204 case CHRE_EVENT_WIFI_SCAN_RESULT:
205 handleWifiScanEvent(static_cast<const chreWifiScanEvent *>(eventData));
206 break;
207 case CHRE_EVENT_TIMER:
208 handleTimerEvent(eventData);
209 break;
210 default:
211 LOGW("Unhandled event type %" PRIu16, eventType);
212 }
213 }
214
nanoappEnd()215 void nanoappEnd() {
216 LOGI("Wifi world app stopped");
217 }
218
219 #ifdef CHRE_NANOAPP_INTERNAL
220 } // anonymous namespace
221 } // namespace chre
222
223 #include "chre/util/nanoapp/app_id.h"
224 #include "chre/platform/static_nanoapp_init.h"
225
226 CHRE_STATIC_NANOAPP_INIT(WifiWorld, chre::kWifiWorldAppId, 0);
227 #endif // CHRE_NANOAPP_INTERNAL
228