xref: /aosp_15_r20/system/chre/pal/util/wifi_scan_cache.c (revision 84e339476a462649f82315436d70fd732297a399)
1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker  * Copyright (C) 2020 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker  *
4*84e33947SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker  *
8*84e33947SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker  *
10*84e33947SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker  * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker  */
16*84e33947SAndroid Build Coastguard Worker 
17*84e33947SAndroid Build Coastguard Worker #include "chre/pal/util/wifi_scan_cache.h"
18*84e33947SAndroid Build Coastguard Worker 
19*84e33947SAndroid Build Coastguard Worker #include <inttypes.h>
20*84e33947SAndroid Build Coastguard Worker 
21*84e33947SAndroid Build Coastguard Worker #include "chre/util/macros.h"
22*84e33947SAndroid Build Coastguard Worker 
23*84e33947SAndroid Build Coastguard Worker /************************************************
24*84e33947SAndroid Build Coastguard Worker  *  Constants
25*84e33947SAndroid Build Coastguard Worker  ***********************************************/
26*84e33947SAndroid Build Coastguard Worker 
27*84e33947SAndroid Build Coastguard Worker // Constants used in chreWifiScanCacheInitialAgeMsValue() and
28*84e33947SAndroid Build Coastguard Worker // chreWifiScanCacheFinalizeAgeMs()
29*84e33947SAndroid Build Coastguard Worker // These values are selected because msec = nsec / 1000000 and
30*84e33947SAndroid Build Coastguard Worker // 1000000 = 64 * 15625 = (1 << 6) * 15625
31*84e33947SAndroid Build Coastguard Worker #define CHRE_WIFI_SCAN_CACHE_AGE_MS_SHIFT (6)
32*84e33947SAndroid Build Coastguard Worker #define CHRE_WIFI_SCAN_CACHE_AGE_MS_DIVISOR (15625)
33*84e33947SAndroid Build Coastguard Worker 
34*84e33947SAndroid Build Coastguard Worker /************************************************
35*84e33947SAndroid Build Coastguard Worker  *  Prototypes
36*84e33947SAndroid Build Coastguard Worker  ***********************************************/
37*84e33947SAndroid Build Coastguard Worker 
38*84e33947SAndroid Build Coastguard Worker struct chreWifiScanCacheState {
39*84e33947SAndroid Build Coastguard Worker   //! true if the scan cache has started, i.e. chreWifiScanCacheScanEventBegin
40*84e33947SAndroid Build Coastguard Worker   //! was invoked and has not yet ended.
41*84e33947SAndroid Build Coastguard Worker   bool started;
42*84e33947SAndroid Build Coastguard Worker 
43*84e33947SAndroid Build Coastguard Worker   //! true if the current scan cache is a result of a CHRE active scan request.
44*84e33947SAndroid Build Coastguard Worker   bool scanRequestedByChre;
45*84e33947SAndroid Build Coastguard Worker 
46*84e33947SAndroid Build Coastguard Worker   //! The number of chreWifiScanResults dropped due to OOM.
47*84e33947SAndroid Build Coastguard Worker   uint16_t numWifiScanResultsDropped;
48*84e33947SAndroid Build Coastguard Worker 
49*84e33947SAndroid Build Coastguard Worker   //! Stores the WiFi cache elements
50*84e33947SAndroid Build Coastguard Worker   struct chreWifiScanEvent event;
51*84e33947SAndroid Build Coastguard Worker   struct chreWifiScanResult resultList[CHRE_PAL_WIFI_SCAN_CACHE_CAPACITY];
52*84e33947SAndroid Build Coastguard Worker 
53*84e33947SAndroid Build Coastguard Worker   //! The number of chreWifiScanEvent data pending release via
54*84e33947SAndroid Build Coastguard Worker   //! chreWifiScanCacheReleaseScanEvent().
55*84e33947SAndroid Build Coastguard Worker   uint8_t numWifiEventsPendingRelease;
56*84e33947SAndroid Build Coastguard Worker 
57*84e33947SAndroid Build Coastguard Worker   bool scanMonitoringEnabled;
58*84e33947SAndroid Build Coastguard Worker 
59*84e33947SAndroid Build Coastguard Worker   uint32_t scannedFreqList[CHRE_WIFI_FREQUENCY_LIST_MAX_LEN];
60*84e33947SAndroid Build Coastguard Worker 
61*84e33947SAndroid Build Coastguard Worker   uint64_t scanStartTimeNs;
62*84e33947SAndroid Build Coastguard Worker };
63*84e33947SAndroid Build Coastguard Worker 
64*84e33947SAndroid Build Coastguard Worker /************************************************
65*84e33947SAndroid Build Coastguard Worker  *  Global variables
66*84e33947SAndroid Build Coastguard Worker  ***********************************************/
67*84e33947SAndroid Build Coastguard Worker static const struct chrePalSystemApi *gSystemApi = NULL;
68*84e33947SAndroid Build Coastguard Worker static const struct chrePalWifiCallbacks *gCallbacks = NULL;
69*84e33947SAndroid Build Coastguard Worker 
70*84e33947SAndroid Build Coastguard Worker static struct chreWifiScanCacheState gWifiCacheState;
71*84e33947SAndroid Build Coastguard Worker 
72*84e33947SAndroid Build Coastguard Worker //! true if scan monitoring is enabled via
73*84e33947SAndroid Build Coastguard Worker //! chreWifiScanCacheConfigureScanMonitor().
74*84e33947SAndroid Build Coastguard Worker static bool gScanMonitoringEnabled;
75*84e33947SAndroid Build Coastguard Worker 
76*84e33947SAndroid Build Coastguard Worker static const uint64_t kOneMillisecondInNanoseconds = UINT64_C(1000000);
77*84e33947SAndroid Build Coastguard Worker 
78*84e33947SAndroid Build Coastguard Worker /************************************************
79*84e33947SAndroid Build Coastguard Worker  *  Private functions
80*84e33947SAndroid Build Coastguard Worker  ***********************************************/
chreWifiScanCacheIsInitialized(void)81*84e33947SAndroid Build Coastguard Worker static bool chreWifiScanCacheIsInitialized(void) {
82*84e33947SAndroid Build Coastguard Worker   return (gSystemApi != NULL && gCallbacks != NULL);
83*84e33947SAndroid Build Coastguard Worker }
84*84e33947SAndroid Build Coastguard Worker 
areAllScanEventsReleased(void)85*84e33947SAndroid Build Coastguard Worker static bool areAllScanEventsReleased(void) {
86*84e33947SAndroid Build Coastguard Worker   return gWifiCacheState.numWifiEventsPendingRelease == 0;
87*84e33947SAndroid Build Coastguard Worker }
88*84e33947SAndroid Build Coastguard Worker 
isFrequencyListValid(const uint32_t * frequencyList,uint16_t frequencyListLen)89*84e33947SAndroid Build Coastguard Worker static bool isFrequencyListValid(const uint32_t *frequencyList,
90*84e33947SAndroid Build Coastguard Worker                                  uint16_t frequencyListLen) {
91*84e33947SAndroid Build Coastguard Worker   return (frequencyListLen == 0) || (frequencyList != NULL);
92*84e33947SAndroid Build Coastguard Worker }
93*84e33947SAndroid Build Coastguard Worker 
paramsMatchScanCache(const struct chreWifiScanParams * params)94*84e33947SAndroid Build Coastguard Worker static bool paramsMatchScanCache(const struct chreWifiScanParams *params) {
95*84e33947SAndroid Build Coastguard Worker   uint64_t timeNs = gWifiCacheState.event.referenceTime;
96*84e33947SAndroid Build Coastguard Worker   bool scan_within_age =
97*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.started ||
98*84e33947SAndroid Build Coastguard Worker       (timeNs >= gSystemApi->getCurrentTime() -
99*84e33947SAndroid Build Coastguard Worker                      (params->maxScanAgeMs * kOneMillisecondInNanoseconds));
100*84e33947SAndroid Build Coastguard Worker 
101*84e33947SAndroid Build Coastguard Worker   // Perform a conservative check for the params and scan cache.
102*84e33947SAndroid Build Coastguard Worker   // TODO(b/174510035): Consider optimizing for the case for channelSet ==
103*84e33947SAndroid Build Coastguard Worker   // CHRE_WIFI_CHANNEL_SET_ALL.
104*84e33947SAndroid Build Coastguard Worker   bool params_non_dfs =
105*84e33947SAndroid Build Coastguard Worker       (params->scanType == CHRE_WIFI_SCAN_TYPE_ACTIVE) ||
106*84e33947SAndroid Build Coastguard Worker       ((params->scanType == CHRE_WIFI_SCAN_TYPE_NO_PREFERENCE) &&
107*84e33947SAndroid Build Coastguard Worker        (params->channelSet == CHRE_WIFI_CHANNEL_SET_NON_DFS));
108*84e33947SAndroid Build Coastguard Worker   bool cache_non_dfs =
109*84e33947SAndroid Build Coastguard Worker       (gWifiCacheState.event.scanType == CHRE_WIFI_SCAN_TYPE_ACTIVE) ||
110*84e33947SAndroid Build Coastguard Worker       (gWifiCacheState.event.scanType == CHRE_WIFI_SCAN_TYPE_PASSIVE);
111*84e33947SAndroid Build Coastguard Worker 
112*84e33947SAndroid Build Coastguard Worker   bool cache_all_freq = (gWifiCacheState.event.scannedFreqListLen == 0);
113*84e33947SAndroid Build Coastguard Worker   bool cache_all_ssid = (gWifiCacheState.event.ssidSetSize == 0);
114*84e33947SAndroid Build Coastguard Worker 
115*84e33947SAndroid Build Coastguard Worker   return scan_within_age && (params_non_dfs || !cache_non_dfs) &&
116*84e33947SAndroid Build Coastguard Worker          cache_all_freq && cache_all_ssid;
117*84e33947SAndroid Build Coastguard Worker }
118*84e33947SAndroid Build Coastguard Worker 
isWifiScanCacheBusy(bool logOnBusy)119*84e33947SAndroid Build Coastguard Worker static bool isWifiScanCacheBusy(bool logOnBusy) {
120*84e33947SAndroid Build Coastguard Worker   bool busy = true;
121*84e33947SAndroid Build Coastguard Worker   if (gWifiCacheState.started) {
122*84e33947SAndroid Build Coastguard Worker     if (logOnBusy) {
123*84e33947SAndroid Build Coastguard Worker       gSystemApi->log(CHRE_LOG_ERROR, "Scan cache already started");
124*84e33947SAndroid Build Coastguard Worker     }
125*84e33947SAndroid Build Coastguard Worker   } else if (!areAllScanEventsReleased()) {
126*84e33947SAndroid Build Coastguard Worker     if (logOnBusy) {
127*84e33947SAndroid Build Coastguard Worker       gSystemApi->log(CHRE_LOG_ERROR, "Scan cache events pending release");
128*84e33947SAndroid Build Coastguard Worker     }
129*84e33947SAndroid Build Coastguard Worker   } else {
130*84e33947SAndroid Build Coastguard Worker     busy = false;
131*84e33947SAndroid Build Coastguard Worker   }
132*84e33947SAndroid Build Coastguard Worker 
133*84e33947SAndroid Build Coastguard Worker   return busy;
134*84e33947SAndroid Build Coastguard Worker }
135*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheDispatchAll(void)136*84e33947SAndroid Build Coastguard Worker static void chreWifiScanCacheDispatchAll(void) {
137*84e33947SAndroid Build Coastguard Worker   gSystemApi->log(CHRE_LOG_DEBUG, "Dispatching %" PRIu8 " events",
138*84e33947SAndroid Build Coastguard Worker                   gWifiCacheState.event.resultTotal);
139*84e33947SAndroid Build Coastguard Worker   if (gWifiCacheState.event.resultTotal == 0) {
140*84e33947SAndroid Build Coastguard Worker     gWifiCacheState.event.eventIndex = 0;
141*84e33947SAndroid Build Coastguard Worker     gWifiCacheState.event.resultCount = 0;
142*84e33947SAndroid Build Coastguard Worker     gWifiCacheState.event.results = NULL;
143*84e33947SAndroid Build Coastguard Worker     gCallbacks->scanEventCallback(&gWifiCacheState.event);
144*84e33947SAndroid Build Coastguard Worker   } else {
145*84e33947SAndroid Build Coastguard Worker     uint8_t eventIndex = 0;
146*84e33947SAndroid Build Coastguard Worker     for (uint16_t i = 0; i < gWifiCacheState.event.resultTotal;
147*84e33947SAndroid Build Coastguard Worker          i += CHRE_PAL_WIFI_SCAN_CACHE_MAX_RESULT_COUNT) {
148*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.resultCount =
149*84e33947SAndroid Build Coastguard Worker           MIN(CHRE_PAL_WIFI_SCAN_CACHE_MAX_RESULT_COUNT,
150*84e33947SAndroid Build Coastguard Worker               (uint8_t)(gWifiCacheState.event.resultTotal - i));
151*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.eventIndex = eventIndex++;
152*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.results = &gWifiCacheState.resultList[i];
153*84e33947SAndroid Build Coastguard Worker 
154*84e33947SAndroid Build Coastguard Worker       // TODO(b/174511061): The current approach only works for situations where
155*84e33947SAndroid Build Coastguard Worker       // the event is released immediately. Add a way to handle this scenario
156*84e33947SAndroid Build Coastguard Worker       // (e.g. an array of chreWifiScanEvent's).
157*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.numWifiEventsPendingRelease++;
158*84e33947SAndroid Build Coastguard Worker       gCallbacks->scanEventCallback(&gWifiCacheState.event);
159*84e33947SAndroid Build Coastguard Worker       if (gWifiCacheState.numWifiEventsPendingRelease != 0) {
160*84e33947SAndroid Build Coastguard Worker         gSystemApi->log(CHRE_LOG_ERROR, "Scan event not released immediately");
161*84e33947SAndroid Build Coastguard Worker       }
162*84e33947SAndroid Build Coastguard Worker     }
163*84e33947SAndroid Build Coastguard Worker   }
164*84e33947SAndroid Build Coastguard Worker }
165*84e33947SAndroid Build Coastguard Worker 
isWifiScanResultInCache(const struct chreWifiScanResult * result,size_t * index)166*84e33947SAndroid Build Coastguard Worker static bool isWifiScanResultInCache(const struct chreWifiScanResult *result,
167*84e33947SAndroid Build Coastguard Worker                                     size_t *index) {
168*84e33947SAndroid Build Coastguard Worker   for (uint8_t i = 0; i < gWifiCacheState.event.resultTotal; i++) {
169*84e33947SAndroid Build Coastguard Worker     const struct chreWifiScanResult *cacheResult =
170*84e33947SAndroid Build Coastguard Worker         &gWifiCacheState.resultList[i];
171*84e33947SAndroid Build Coastguard Worker     // Filtering based on BSSID + SSID + frequency based on Linux cfg80211.
172*84e33947SAndroid Build Coastguard Worker     // https://github.com/torvalds/linux/blob/master/net/wireless/scan.c
173*84e33947SAndroid Build Coastguard Worker     if ((result->primaryChannel == cacheResult->primaryChannel) &&
174*84e33947SAndroid Build Coastguard Worker         (memcmp(result->bssid, cacheResult->bssid, CHRE_WIFI_BSSID_LEN) == 0) &&
175*84e33947SAndroid Build Coastguard Worker         (result->ssidLen == cacheResult->ssidLen) &&
176*84e33947SAndroid Build Coastguard Worker         (memcmp(result->ssid, cacheResult->ssid, result->ssidLen) == 0)) {
177*84e33947SAndroid Build Coastguard Worker       *index = i;
178*84e33947SAndroid Build Coastguard Worker       return true;
179*84e33947SAndroid Build Coastguard Worker     }
180*84e33947SAndroid Build Coastguard Worker   }
181*84e33947SAndroid Build Coastguard Worker 
182*84e33947SAndroid Build Coastguard Worker   return false;
183*84e33947SAndroid Build Coastguard Worker }
184*84e33947SAndroid Build Coastguard Worker 
isLowerRssiScanResultInCache(const struct chreWifiScanResult * result,size_t * index)185*84e33947SAndroid Build Coastguard Worker static bool isLowerRssiScanResultInCache(
186*84e33947SAndroid Build Coastguard Worker     const struct chreWifiScanResult *result, size_t *index) {
187*84e33947SAndroid Build Coastguard Worker   int8_t lowestRssi = result->rssi;
188*84e33947SAndroid Build Coastguard Worker   bool foundWeakerResult = false;
189*84e33947SAndroid Build Coastguard Worker   for (uint8_t i = 0; i < gWifiCacheState.event.resultTotal; i++) {
190*84e33947SAndroid Build Coastguard Worker     const struct chreWifiScanResult *cacheResult =
191*84e33947SAndroid Build Coastguard Worker         &gWifiCacheState.resultList[i];
192*84e33947SAndroid Build Coastguard Worker     // Filter based on RSSI to determine weakest result in cache.
193*84e33947SAndroid Build Coastguard Worker     if (cacheResult->rssi < lowestRssi) {
194*84e33947SAndroid Build Coastguard Worker       lowestRssi = cacheResult->rssi;
195*84e33947SAndroid Build Coastguard Worker       *index = i;
196*84e33947SAndroid Build Coastguard Worker       foundWeakerResult = true;
197*84e33947SAndroid Build Coastguard Worker     }
198*84e33947SAndroid Build Coastguard Worker   }
199*84e33947SAndroid Build Coastguard Worker 
200*84e33947SAndroid Build Coastguard Worker   return foundWeakerResult;
201*84e33947SAndroid Build Coastguard Worker }
202*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheInitialAgeMsValue()203*84e33947SAndroid Build Coastguard Worker static uint32_t chreWifiScanCacheInitialAgeMsValue() {
204*84e33947SAndroid Build Coastguard Worker   // ageMs will be finalized via chreWifiScanCacheFinalizeAgeMs() once the scan
205*84e33947SAndroid Build Coastguard Worker   // finishes, because it is relative to the scan end time that we can't know
206*84e33947SAndroid Build Coastguard Worker   // yet. Before the end of the scan, populate ageMs with the time since the
207*84e33947SAndroid Build Coastguard Worker   // start of the scan.
208*84e33947SAndroid Build Coastguard Worker   //
209*84e33947SAndroid Build Coastguard Worker   // We avoid 64-bit integer division by:
210*84e33947SAndroid Build Coastguard Worker   //  - Only considering the delta between this result and the start of the
211*84e33947SAndroid Build Coastguard Worker   //    scan, which constrains the range of expected values to what should be
212*84e33947SAndroid Build Coastguard Worker   //    only a few seconds
213*84e33947SAndroid Build Coastguard Worker   //  - Instead of directly dividing by 1000000, we first divide by 64 (right
214*84e33947SAndroid Build Coastguard Worker   //    shift by 6), then truncate to 32 bits, then later we'll do integer
215*84e33947SAndroid Build Coastguard Worker   //    division by 15625 to get milliseconds
216*84e33947SAndroid Build Coastguard Worker   //    - This works because x/1000000 = x/(64 * 15625) = (x/64)/15625
217*84e33947SAndroid Build Coastguard Worker   //    - The largest delta we can fit here is 2^32/15625 ms = 274877 ms or
218*84e33947SAndroid Build Coastguard Worker   //      about 4.5 minutes
219*84e33947SAndroid Build Coastguard Worker   uint64_t timeSinceScanStartNs =
220*84e33947SAndroid Build Coastguard Worker       (gSystemApi->getCurrentTime() - gWifiCacheState.scanStartTimeNs);
221*84e33947SAndroid Build Coastguard Worker   return (timeSinceScanStartNs >> CHRE_WIFI_SCAN_CACHE_AGE_MS_SHIFT);
222*84e33947SAndroid Build Coastguard Worker }
223*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheFinalizeAgeMs()224*84e33947SAndroid Build Coastguard Worker static void chreWifiScanCacheFinalizeAgeMs() {
225*84e33947SAndroid Build Coastguard Worker   // Convert ageMs from the chreWifiScanCacheInitialAgeMsValue() to its final,
226*84e33947SAndroid Build Coastguard Worker   // correct value using the formula derived from these steps:
227*84e33947SAndroid Build Coastguard Worker   //  ageMs = (referenceTimeNs - absoluteScanResultTimeNs) / 1000000
228*84e33947SAndroid Build Coastguard Worker   //        = (referenceTimeNs - (scanStartTimeNs + scanOffsetNs)) / 1000000
229*84e33947SAndroid Build Coastguard Worker   //        = ((referenceTimeNs - scanStartTimeNs) - scanOffsetNs) / 1000000
230*84e33947SAndroid Build Coastguard Worker   //        = (scanDuration / 64 - scanOffsetNs / 64) / 15625
231*84e33947SAndroid Build Coastguard Worker   //  ageMs = (scanDurationShifted - currentAgeMsValue) / 15625
232*84e33947SAndroid Build Coastguard Worker   uint64_t referenceTimeNs = gWifiCacheState.event.referenceTime;
233*84e33947SAndroid Build Coastguard Worker   uint64_t scanStartTimeNs = gWifiCacheState.scanStartTimeNs;
234*84e33947SAndroid Build Coastguard Worker   uint32_t scanDurationShifted =
235*84e33947SAndroid Build Coastguard Worker       (referenceTimeNs - scanStartTimeNs) >> CHRE_WIFI_SCAN_CACHE_AGE_MS_SHIFT;
236*84e33947SAndroid Build Coastguard Worker   if (referenceTimeNs < scanStartTimeNs) {
237*84e33947SAndroid Build Coastguard Worker     gSystemApi->log(CHRE_LOG_ERROR, "Invalid scan timestamp, clamping");
238*84e33947SAndroid Build Coastguard Worker     // Use a smaller number to avoid very large ageMs values
239*84e33947SAndroid Build Coastguard Worker     scanDurationShifted = 78125000;  // 5 seconds --> 5*10e9 / 64
240*84e33947SAndroid Build Coastguard Worker   }
241*84e33947SAndroid Build Coastguard Worker 
242*84e33947SAndroid Build Coastguard Worker   for (uint16_t i = 0; i < gWifiCacheState.event.resultTotal; i++) {
243*84e33947SAndroid Build Coastguard Worker     if (scanDurationShifted < gWifiCacheState.resultList[i].ageMs) {
244*84e33947SAndroid Build Coastguard Worker       gSystemApi->log(CHRE_LOG_ERROR,
245*84e33947SAndroid Build Coastguard Worker                       "Invalid result timestamp %" PRIu32 " vs. %" PRIu32,
246*84e33947SAndroid Build Coastguard Worker                       gWifiCacheState.resultList[i].ageMs, scanDurationShifted);
247*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.resultList[i].ageMs = 0;
248*84e33947SAndroid Build Coastguard Worker     } else {
249*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.resultList[i].ageMs =
250*84e33947SAndroid Build Coastguard Worker           (scanDurationShifted - gWifiCacheState.resultList[i].ageMs) /
251*84e33947SAndroid Build Coastguard Worker           CHRE_WIFI_SCAN_CACHE_AGE_MS_DIVISOR;
252*84e33947SAndroid Build Coastguard Worker     }
253*84e33947SAndroid Build Coastguard Worker   }
254*84e33947SAndroid Build Coastguard Worker }
255*84e33947SAndroid Build Coastguard Worker 
256*84e33947SAndroid Build Coastguard Worker /************************************************
257*84e33947SAndroid Build Coastguard Worker  *  Public functions
258*84e33947SAndroid Build Coastguard Worker  ***********************************************/
chreWifiScanCacheInit(const struct chrePalSystemApi * systemApi,const struct chrePalWifiCallbacks * callbacks)259*84e33947SAndroid Build Coastguard Worker bool chreWifiScanCacheInit(const struct chrePalSystemApi *systemApi,
260*84e33947SAndroid Build Coastguard Worker                            const struct chrePalWifiCallbacks *callbacks) {
261*84e33947SAndroid Build Coastguard Worker   if (systemApi == NULL || callbacks == NULL) {
262*84e33947SAndroid Build Coastguard Worker     return false;
263*84e33947SAndroid Build Coastguard Worker   }
264*84e33947SAndroid Build Coastguard Worker 
265*84e33947SAndroid Build Coastguard Worker   gSystemApi = systemApi;
266*84e33947SAndroid Build Coastguard Worker   gCallbacks = callbacks;
267*84e33947SAndroid Build Coastguard Worker   memset(&gWifiCacheState, 0, sizeof(gWifiCacheState));
268*84e33947SAndroid Build Coastguard Worker   gScanMonitoringEnabled = false;
269*84e33947SAndroid Build Coastguard Worker 
270*84e33947SAndroid Build Coastguard Worker   return true;
271*84e33947SAndroid Build Coastguard Worker }
272*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheDeinit(void)273*84e33947SAndroid Build Coastguard Worker void chreWifiScanCacheDeinit(void) {
274*84e33947SAndroid Build Coastguard Worker   gSystemApi = NULL;
275*84e33947SAndroid Build Coastguard Worker   gCallbacks = NULL;
276*84e33947SAndroid Build Coastguard Worker }
277*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheScanEventBegin(enum chreWifiScanType scanType,uint8_t ssidSetSize,const uint32_t * scannedFreqList,uint16_t scannedFreqListLength,uint8_t radioChainPref,bool scanRequestedByChre)278*84e33947SAndroid Build Coastguard Worker bool chreWifiScanCacheScanEventBegin(enum chreWifiScanType scanType,
279*84e33947SAndroid Build Coastguard Worker                                      uint8_t ssidSetSize,
280*84e33947SAndroid Build Coastguard Worker                                      const uint32_t *scannedFreqList,
281*84e33947SAndroid Build Coastguard Worker                                      uint16_t scannedFreqListLength,
282*84e33947SAndroid Build Coastguard Worker                                      uint8_t radioChainPref,
283*84e33947SAndroid Build Coastguard Worker                                      bool scanRequestedByChre) {
284*84e33947SAndroid Build Coastguard Worker   bool success = false;
285*84e33947SAndroid Build Coastguard Worker   if (chreWifiScanCacheIsInitialized()) {
286*84e33947SAndroid Build Coastguard Worker     enum chreError error = CHRE_ERROR_NONE;
287*84e33947SAndroid Build Coastguard Worker     if (!isFrequencyListValid(scannedFreqList, scannedFreqListLength)) {
288*84e33947SAndroid Build Coastguard Worker       gSystemApi->log(CHRE_LOG_ERROR, "Invalid frequency argument");
289*84e33947SAndroid Build Coastguard Worker       error = CHRE_ERROR_INVALID_ARGUMENT;
290*84e33947SAndroid Build Coastguard Worker     } else if (isWifiScanCacheBusy(true /* logOnBusy */)) {
291*84e33947SAndroid Build Coastguard Worker       error = CHRE_ERROR_BUSY;
292*84e33947SAndroid Build Coastguard Worker     } else {
293*84e33947SAndroid Build Coastguard Worker       success = true;
294*84e33947SAndroid Build Coastguard Worker       memset(&gWifiCacheState, 0, sizeof(gWifiCacheState));
295*84e33947SAndroid Build Coastguard Worker 
296*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.version = CHRE_WIFI_SCAN_EVENT_VERSION;
297*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.scanType = scanType;
298*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.ssidSetSize = ssidSetSize;
299*84e33947SAndroid Build Coastguard Worker 
300*84e33947SAndroid Build Coastguard Worker       scannedFreqListLength =
301*84e33947SAndroid Build Coastguard Worker           MIN(scannedFreqListLength, CHRE_WIFI_FREQUENCY_LIST_MAX_LEN);
302*84e33947SAndroid Build Coastguard Worker       if (scannedFreqList != NULL) {
303*84e33947SAndroid Build Coastguard Worker         memcpy(gWifiCacheState.scannedFreqList, scannedFreqList,
304*84e33947SAndroid Build Coastguard Worker                scannedFreqListLength * sizeof(uint32_t));
305*84e33947SAndroid Build Coastguard Worker       }
306*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.scannedFreqListLen = scannedFreqListLength;
307*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.radioChainPref = radioChainPref;
308*84e33947SAndroid Build Coastguard Worker 
309*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.scanRequestedByChre = scanRequestedByChre;
310*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.started = true;
311*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.scanStartTimeNs = gSystemApi->getCurrentTime();
312*84e33947SAndroid Build Coastguard Worker     }
313*84e33947SAndroid Build Coastguard Worker 
314*84e33947SAndroid Build Coastguard Worker     if (scanRequestedByChre && !success) {
315*84e33947SAndroid Build Coastguard Worker       gCallbacks->scanResponseCallback(false /* pending */, error);
316*84e33947SAndroid Build Coastguard Worker     }
317*84e33947SAndroid Build Coastguard Worker   }
318*84e33947SAndroid Build Coastguard Worker 
319*84e33947SAndroid Build Coastguard Worker   return success;
320*84e33947SAndroid Build Coastguard Worker }
321*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheScanEventAdd(const struct chreWifiScanResult * result)322*84e33947SAndroid Build Coastguard Worker void chreWifiScanCacheScanEventAdd(const struct chreWifiScanResult *result) {
323*84e33947SAndroid Build Coastguard Worker   if (!gWifiCacheState.started) {
324*84e33947SAndroid Build Coastguard Worker     gSystemApi->log(CHRE_LOG_ERROR, "Cannot add to cache before starting it");
325*84e33947SAndroid Build Coastguard Worker     return;
326*84e33947SAndroid Build Coastguard Worker   }
327*84e33947SAndroid Build Coastguard Worker 
328*84e33947SAndroid Build Coastguard Worker   size_t index;
329*84e33947SAndroid Build Coastguard Worker   if (!isWifiScanResultInCache(result, &index)) {
330*84e33947SAndroid Build Coastguard Worker     if (gWifiCacheState.event.resultTotal >=
331*84e33947SAndroid Build Coastguard Worker         CHRE_PAL_WIFI_SCAN_CACHE_CAPACITY) {
332*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.numWifiScanResultsDropped++;
333*84e33947SAndroid Build Coastguard Worker       // Determine weakest result in cache to replace with the new result.
334*84e33947SAndroid Build Coastguard Worker       if (!isLowerRssiScanResultInCache(result, &index)) {
335*84e33947SAndroid Build Coastguard Worker         return;
336*84e33947SAndroid Build Coastguard Worker       }
337*84e33947SAndroid Build Coastguard Worker     } else {
338*84e33947SAndroid Build Coastguard Worker       // Result was not already cached, add new entry to the end of the cache
339*84e33947SAndroid Build Coastguard Worker       index = gWifiCacheState.event.resultTotal;
340*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.resultTotal++;
341*84e33947SAndroid Build Coastguard Worker     }
342*84e33947SAndroid Build Coastguard Worker   }
343*84e33947SAndroid Build Coastguard Worker 
344*84e33947SAndroid Build Coastguard Worker   memcpy(&gWifiCacheState.resultList[index], result,
345*84e33947SAndroid Build Coastguard Worker          sizeof(const struct chreWifiScanResult));
346*84e33947SAndroid Build Coastguard Worker 
347*84e33947SAndroid Build Coastguard Worker   gWifiCacheState.resultList[index].ageMs =
348*84e33947SAndroid Build Coastguard Worker       chreWifiScanCacheInitialAgeMsValue();
349*84e33947SAndroid Build Coastguard Worker }
350*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheScanEventEnd(enum chreError errorCode)351*84e33947SAndroid Build Coastguard Worker void chreWifiScanCacheScanEventEnd(enum chreError errorCode) {
352*84e33947SAndroid Build Coastguard Worker   if (gWifiCacheState.started) {
353*84e33947SAndroid Build Coastguard Worker     if (gWifiCacheState.numWifiScanResultsDropped > 0) {
354*84e33947SAndroid Build Coastguard Worker       gSystemApi->log(CHRE_LOG_WARN,
355*84e33947SAndroid Build Coastguard Worker                       "Dropped total of %" PRIu32 " access points",
356*84e33947SAndroid Build Coastguard Worker                       gWifiCacheState.numWifiScanResultsDropped);
357*84e33947SAndroid Build Coastguard Worker     }
358*84e33947SAndroid Build Coastguard Worker     if (gWifiCacheState.scanRequestedByChre) {
359*84e33947SAndroid Build Coastguard Worker       gCallbacks->scanResponseCallback(
360*84e33947SAndroid Build Coastguard Worker           errorCode == CHRE_ERROR_NONE /* pending */, errorCode);
361*84e33947SAndroid Build Coastguard Worker     }
362*84e33947SAndroid Build Coastguard Worker 
363*84e33947SAndroid Build Coastguard Worker     if (errorCode == CHRE_ERROR_NONE &&
364*84e33947SAndroid Build Coastguard Worker         (gWifiCacheState.scanRequestedByChre || gScanMonitoringEnabled)) {
365*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.referenceTime = gSystemApi->getCurrentTime();
366*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.event.scannedFreqList = gWifiCacheState.scannedFreqList;
367*84e33947SAndroid Build Coastguard Worker       chreWifiScanCacheFinalizeAgeMs();
368*84e33947SAndroid Build Coastguard Worker       chreWifiScanCacheDispatchAll();
369*84e33947SAndroid Build Coastguard Worker     }
370*84e33947SAndroid Build Coastguard Worker 
371*84e33947SAndroid Build Coastguard Worker     gWifiCacheState.started = false;
372*84e33947SAndroid Build Coastguard Worker     gWifiCacheState.scanRequestedByChre = false;
373*84e33947SAndroid Build Coastguard Worker   }
374*84e33947SAndroid Build Coastguard Worker }
375*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheDispatchFromCache(const struct chreWifiScanParams * params)376*84e33947SAndroid Build Coastguard Worker bool chreWifiScanCacheDispatchFromCache(
377*84e33947SAndroid Build Coastguard Worker     const struct chreWifiScanParams *params) {
378*84e33947SAndroid Build Coastguard Worker   if (!chreWifiScanCacheIsInitialized()) {
379*84e33947SAndroid Build Coastguard Worker     return false;
380*84e33947SAndroid Build Coastguard Worker   }
381*84e33947SAndroid Build Coastguard Worker 
382*84e33947SAndroid Build Coastguard Worker   if (paramsMatchScanCache(params)) {
383*84e33947SAndroid Build Coastguard Worker     if (!isWifiScanCacheBusy(false /* logOnBusy */)) {
384*84e33947SAndroid Build Coastguard Worker       // Satisfied by cache
385*84e33947SAndroid Build Coastguard Worker       gCallbacks->scanResponseCallback(true /* pending */, CHRE_ERROR_NONE);
386*84e33947SAndroid Build Coastguard Worker       chreWifiScanCacheDispatchAll();
387*84e33947SAndroid Build Coastguard Worker       return true;
388*84e33947SAndroid Build Coastguard Worker     } else if (gWifiCacheState.started) {
389*84e33947SAndroid Build Coastguard Worker       // Will be satisfied by cache once the scan completes
390*84e33947SAndroid Build Coastguard Worker       gSystemApi->log(CHRE_LOG_INFO, "Using in-progress scan for CHRE request");
391*84e33947SAndroid Build Coastguard Worker       gWifiCacheState.scanRequestedByChre = true;
392*84e33947SAndroid Build Coastguard Worker       return true;
393*84e33947SAndroid Build Coastguard Worker     } else {
394*84e33947SAndroid Build Coastguard Worker       // Assumed: busy because !areAllScanEventsReleased()
395*84e33947SAndroid Build Coastguard Worker       // TODO(b/174511061): the current code assumes scan events are released
396*84e33947SAndroid Build Coastguard Worker       // synchronously, so this should never happen
397*84e33947SAndroid Build Coastguard Worker       gSystemApi->log(CHRE_LOG_ERROR,
398*84e33947SAndroid Build Coastguard Worker                       "Unexpected scan request while delivering results");
399*84e33947SAndroid Build Coastguard Worker       return false;
400*84e33947SAndroid Build Coastguard Worker     }
401*84e33947SAndroid Build Coastguard Worker   } else {
402*84e33947SAndroid Build Coastguard Worker     // Cache contains results from incompatible scan parameters (either too old
403*84e33947SAndroid Build Coastguard Worker     // or different scan type), so a new scan is needed
404*84e33947SAndroid Build Coastguard Worker     return false;
405*84e33947SAndroid Build Coastguard Worker   }
406*84e33947SAndroid Build Coastguard Worker }
407*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheReleaseScanEvent(struct chreWifiScanEvent * event)408*84e33947SAndroid Build Coastguard Worker void chreWifiScanCacheReleaseScanEvent(struct chreWifiScanEvent *event) {
409*84e33947SAndroid Build Coastguard Worker   if (!chreWifiScanCacheIsInitialized()) {
410*84e33947SAndroid Build Coastguard Worker     return;
411*84e33947SAndroid Build Coastguard Worker   }
412*84e33947SAndroid Build Coastguard Worker 
413*84e33947SAndroid Build Coastguard Worker   if (event != &gWifiCacheState.event) {
414*84e33947SAndroid Build Coastguard Worker     gSystemApi->log(CHRE_LOG_ERROR, "Invalid event pointer %p", event);
415*84e33947SAndroid Build Coastguard Worker   } else if (gWifiCacheState.numWifiEventsPendingRelease > 0) {
416*84e33947SAndroid Build Coastguard Worker     gWifiCacheState.numWifiEventsPendingRelease--;
417*84e33947SAndroid Build Coastguard Worker   }
418*84e33947SAndroid Build Coastguard Worker }
419*84e33947SAndroid Build Coastguard Worker 
chreWifiScanCacheConfigureScanMonitor(bool enable)420*84e33947SAndroid Build Coastguard Worker void chreWifiScanCacheConfigureScanMonitor(bool enable) {
421*84e33947SAndroid Build Coastguard Worker   if (!chreWifiScanCacheIsInitialized()) {
422*84e33947SAndroid Build Coastguard Worker     return;
423*84e33947SAndroid Build Coastguard Worker   }
424*84e33947SAndroid Build Coastguard Worker 
425*84e33947SAndroid Build Coastguard Worker   gScanMonitoringEnabled = enable;
426*84e33947SAndroid Build Coastguard Worker }
427