• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 package com.android.server.wifi;
17 
18 import android.hardware.wifi.V1_0.IWifiApIface;
19 import android.hardware.wifi.V1_0.IWifiChip;
20 import android.hardware.wifi.V1_0.IWifiChipEventCallback;
21 import android.hardware.wifi.V1_0.IWifiIface;
22 import android.hardware.wifi.V1_0.IWifiRttController;
23 import android.hardware.wifi.V1_0.IWifiRttControllerEventCallback;
24 import android.hardware.wifi.V1_0.IWifiStaIface;
25 import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback;
26 import android.hardware.wifi.V1_0.IfaceType;
27 import android.hardware.wifi.V1_0.RttBw;
28 import android.hardware.wifi.V1_0.RttConfig;
29 import android.hardware.wifi.V1_0.RttPeerType;
30 import android.hardware.wifi.V1_0.RttPreamble;
31 import android.hardware.wifi.V1_0.RttResponder;
32 import android.hardware.wifi.V1_0.RttResult;
33 import android.hardware.wifi.V1_0.RttType;
34 import android.hardware.wifi.V1_0.StaBackgroundScanBucketEventReportSchemeMask;
35 import android.hardware.wifi.V1_0.StaBackgroundScanBucketParameters;
36 import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
37 import android.hardware.wifi.V1_0.StaLinkLayerRadioStats;
38 import android.hardware.wifi.V1_0.StaLinkLayerStats;
39 import android.hardware.wifi.V1_0.StaRoamingConfig;
40 import android.hardware.wifi.V1_0.StaRoamingState;
41 import android.hardware.wifi.V1_0.StaScanData;
42 import android.hardware.wifi.V1_0.StaScanDataFlagMask;
43 import android.hardware.wifi.V1_0.StaScanResult;
44 import android.hardware.wifi.V1_0.WifiBand;
45 import android.hardware.wifi.V1_0.WifiChannelWidthInMhz;
46 import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
47 import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
48 import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags;
49 import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
50 import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
51 import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
52 import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
53 import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
54 import android.hardware.wifi.V1_0.WifiInformationElement;
55 import android.hardware.wifi.V1_0.WifiStatus;
56 import android.hardware.wifi.V1_0.WifiStatusCode;
57 import android.net.apf.ApfCapabilities;
58 import android.net.wifi.RttManager;
59 import android.net.wifi.RttManager.ResponderConfig;
60 import android.net.wifi.ScanResult;
61 import android.net.wifi.WifiInfo;
62 import android.net.wifi.WifiLinkLayerStats;
63 import android.net.wifi.WifiManager;
64 import android.net.wifi.WifiScanner;
65 import android.net.wifi.WifiSsid;
66 import android.net.wifi.WifiWakeReasonAndCounts;
67 import android.os.Handler;
68 import android.os.Looper;
69 import android.os.RemoteException;
70 import android.util.MutableBoolean;
71 import android.util.MutableInt;
72 
73 import com.android.internal.annotations.VisibleForTesting;
74 import com.android.internal.util.ArrayUtils;
75 import com.android.server.connectivity.KeepalivePacketData;
76 import com.android.server.wifi.util.BitMask;
77 import com.android.server.wifi.util.NativeUtil;
78 
79 import java.util.ArrayList;
80 import java.util.Set;
81 
82 /**
83  * Vendor HAL via HIDL
84  */
85 public class WifiVendorHal {
86 
87     private static final WifiLog sNoLog = new FakeWifiLog();
88 
89     /**
90      * Chatty logging should use mVerboseLog
91      */
92     @VisibleForTesting
93     WifiLog mVerboseLog = sNoLog;
94 
95     /**
96      * Errors should use mLog
97      */
98     @VisibleForTesting
99     WifiLog mLog = new LogcatLog("WifiVendorHal");
100 
101     /**
102      * Enables or disables verbose logging
103      *
104      * @param verbose - with the obvious interpretation
105      */
enableVerboseLogging(boolean verbose)106     public void enableVerboseLogging(boolean verbose) {
107         synchronized (sLock) {
108             if (verbose) {
109                 mVerboseLog = mLog;
110                 enter("verbose=true").flush();
111             } else {
112                 enter("verbose=false").flush();
113                 mVerboseLog = sNoLog;
114             }
115         }
116     }
117 
118     /**
119      * Checks for a successful status result.
120      *
121      * Failures are logged to mLog.
122      *
123      * @param status is the WifiStatus generated by a hal call
124      * @return true for success, false for failure
125      */
ok(WifiStatus status)126     private boolean ok(WifiStatus status) {
127         if (status.code == WifiStatusCode.SUCCESS) return true;
128 
129         Thread cur = Thread.currentThread();
130         StackTraceElement[] trace = cur.getStackTrace();
131 
132         mLog.err("% failed %")
133                 .c(niceMethodName(trace, 3))
134                 .c(status.toString())
135                 .flush();
136 
137         return false;
138     }
139 
140     /**
141      * Logs if the argument is false.
142      *
143      * Always returns its argument.
144      */
boolResult(boolean result)145     private boolean boolResult(boolean result) {
146         if (mVerboseLog == sNoLog) return result;
147         // Currently only seen if verbose logging is on
148 
149         Thread cur = Thread.currentThread();
150         StackTraceElement[] trace = cur.getStackTrace();
151 
152         mVerboseLog.err("% returns %")
153                 .c(niceMethodName(trace, 3))
154                 .c(result)
155                 .flush();
156 
157         return result;
158     }
159 
160     /**
161      * Logs at method entry
162      *
163      * @param format string with % placeholders
164      * @return LogMessage formatter (remember to .flush())
165      */
enter(String format)166     private WifiLog.LogMessage enter(String format) {
167         if (mVerboseLog == sNoLog) return sNoLog.info(format);
168         Thread cur = Thread.currentThread();
169         StackTraceElement[] trace = cur.getStackTrace();
170         return mVerboseLog.trace("% " + format).c(trace[3].getMethodName());
171     }
172 
173     /**
174      * Gets the method name and line number from a stack trace.
175      *
176      * Attempts to skip frames created by lambdas to get a human-sensible name.
177      *
178      * @param trace, fo example obtained by Thread.currentThread().getStackTrace()
179      * @param start  frame number to log, typically 3
180      * @return string cotaining the method name and line number
181      */
niceMethodName(StackTraceElement[] trace, int start)182     private static String niceMethodName(StackTraceElement[] trace, int start) {
183         if (start >= trace.length) return "";
184         StackTraceElement s = trace[start];
185         String name = s.getMethodName();
186         if (name.contains("lambda$")) {
187             // Try to find a friendlier method name
188             String myFile = s.getFileName();
189             if (myFile != null) {
190                 for (int i = start + 1; i < trace.length; i++) {
191                     if (myFile.equals(trace[i].getFileName())) {
192                         name = trace[i].getMethodName();
193                         break;
194                     }
195                 }
196             }
197         }
198         return (name + "(l." + s.getLineNumber() + ")");
199     }
200 
201     // Vendor HAL HIDL interface objects.
202     private IWifiChip mIWifiChip;
203     private IWifiStaIface mIWifiStaIface;
204     private IWifiApIface mIWifiApIface;
205     private IWifiRttController mIWifiRttController;
206     private final HalDeviceManager mHalDeviceManager;
207     private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
208     private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
209     private final IWifiChipEventCallback mIWifiChipEventCallback;
210     private final RttEventCallback mRttEventCallback;
211 
212     // Plumbing for event handling.
213     //
214     // Being final fields, they can be accessed without synchronization under
215     // some reasonable assumptions. See
216     // https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5
217     private final Looper mLooper;
218     private final Handler mHalEventHandler;
219 
WifiVendorHal(HalDeviceManager halDeviceManager, Looper looper)220     public WifiVendorHal(HalDeviceManager halDeviceManager,
221                          Looper looper) {
222         mHalDeviceManager = halDeviceManager;
223         mLooper = looper;
224         mHalEventHandler = new Handler(looper);
225         mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener();
226         mIWifiStaIfaceEventCallback = new StaIfaceEventCallback();
227         mIWifiChipEventCallback = new ChipEventCallback();
228         mRttEventCallback = new RttEventCallback();
229     }
230 
231     // TODO(mplass): figure out where we need locking in hidl world. b/33383725
232     public static final Object sLock = new Object();
233 
handleRemoteException(RemoteException e)234     private void handleRemoteException(RemoteException e) {
235         String methodName = niceMethodName(Thread.currentThread().getStackTrace(), 3);
236         mVerboseLog.err("% RemoteException in HIDL call %").c(methodName).c(e.toString()).flush();
237         clearState();
238     }
239 
240     private WifiNative.VendorHalDeathEventHandler mDeathEventHandler;
241 
242     /**
243      * Initialize the Hal device manager and register for status callbacks.
244      *
245      * @param handler Handler to notify if the vendor HAL dies.
246      * @return true on success, false otherwise.
247      */
initialize(WifiNative.VendorHalDeathEventHandler handler)248     public boolean initialize(WifiNative.VendorHalDeathEventHandler handler) {
249         synchronized (sLock) {
250             mHalDeviceManager.initialize();
251             mHalDeviceManager.registerStatusListener(mHalDeviceManagerStatusCallbacks, mLooper);
252             mDeathEventHandler = handler;
253             return true;
254         }
255     }
256 
257     /**
258      * Returns whether the vendor HAL is supported on this device or not.
259      */
isVendorHalSupported()260     public boolean isVendorHalSupported() {
261         synchronized (sLock) {
262             return mHalDeviceManager.isSupported();
263         }
264     }
265 
266     /**
267      * Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
268      *
269      * @return true for success
270      */
startVendorHalAp()271     public boolean startVendorHalAp() {
272         return startVendorHal(AP_MODE);
273     }
274 
275     /**
276      * Bring up the HIDL Vendor HAL and configure for STA (Station) mode
277      *
278      * @return true for success
279      */
startVendorHalSta()280     public boolean startVendorHalSta() {
281         return startVendorHal(STA_MODE);
282     }
283 
284     public static final boolean STA_MODE = true;
285     public static final boolean AP_MODE = false;
286 
287     /**
288      * Bring up the HIDL Vendor HAL and configure for STA mode or AP mode.
289      *
290      * @param isStaMode true to start HAL in STA mode, false to start in AP mode.
291      */
startVendorHal(boolean isStaMode)292     public boolean startVendorHal(boolean isStaMode) {
293         synchronized (sLock) {
294             if (mIWifiStaIface != null) return boolResult(false);
295             if (mIWifiApIface != null) return boolResult(false);
296             if (!mHalDeviceManager.start()) {
297                 return startFailedTo("start the vendor HAL");
298             }
299             IWifiIface iface;
300             if (isStaMode) {
301                 mIWifiStaIface = mHalDeviceManager.createStaIface(null, null);
302                 if (mIWifiStaIface == null) {
303                     return startFailedTo("create STA Iface");
304                 }
305                 iface = (IWifiIface) mIWifiStaIface;
306                 if (!registerStaIfaceCallback()) {
307                     return startFailedTo("register sta iface callback");
308                 }
309                 mIWifiRttController = mHalDeviceManager.createRttController(iface);
310                 if (mIWifiRttController == null) {
311                     return startFailedTo("create RTT controller");
312                 }
313                 if (!registerRttEventCallback()) {
314                     return startFailedTo("register RTT iface callback");
315                 }
316                 enableLinkLayerStats();
317             } else {
318                 mIWifiApIface = mHalDeviceManager.createApIface(null, null);
319                 if (mIWifiApIface == null) {
320                     return startFailedTo("create AP Iface");
321                 }
322                 iface = (IWifiIface) mIWifiApIface;
323             }
324             mIWifiChip = mHalDeviceManager.getChip(iface);
325             if (mIWifiChip == null) {
326                 return startFailedTo("get the chip created for the Iface");
327             }
328             if (!registerChipCallback()) {
329                 return startFailedTo("register chip callback");
330             }
331             mLog.i("Vendor Hal started successfully");
332             return true;
333         }
334     }
335 
336     /**
337      * Logs a message and cleans up after a failing start attempt
338      *
339      * The lock should be held.
340      * @param message describes what was being attempted
341      * @return false
342      */
startFailedTo(String message)343     private boolean startFailedTo(String message) {
344         mVerboseLog.err("Failed to %. Vendor Hal start failed").c(message).flush();
345         mHalDeviceManager.stop();
346         clearState();
347         return false;
348     }
349 
350     /**
351      * Registers the sta iface callback.
352      */
registerStaIfaceCallback()353     private boolean registerStaIfaceCallback() {
354         synchronized (sLock) {
355             if (mIWifiStaIface == null) return boolResult(false);
356             if (mIWifiStaIfaceEventCallback == null) return boolResult(false);
357             try {
358                 WifiStatus status =
359                         mIWifiStaIface.registerEventCallback(mIWifiStaIfaceEventCallback);
360                 return ok(status);
361             } catch (RemoteException e) {
362                 handleRemoteException(e);
363                 return false;
364             }
365         }
366     }
367 
368     /**
369      * Registers the sta iface callback.
370      */
registerChipCallback()371     private boolean registerChipCallback() {
372         synchronized (sLock) {
373             if (mIWifiChip == null) return boolResult(false);
374             if (mIWifiChipEventCallback == null) return boolResult(false);
375             try {
376                 WifiStatus status = mIWifiChip.registerEventCallback(mIWifiChipEventCallback);
377                 return ok(status);
378             } catch (RemoteException e) {
379                 handleRemoteException(e);
380                 return false;
381             }
382         }
383     }
384 
385     /**
386      * Registers RTT event callback. Returns whether the registration is successful.
387      */
registerRttEventCallback()388     private boolean registerRttEventCallback() {
389         synchronized (sLock) {
390             if (mIWifiRttController == null) return boolResult(false);
391             try {
392                 WifiStatus status = mIWifiRttController.registerEventCallback(mRttEventCallback);
393                 return ok(status);
394             } catch (RemoteException e) {
395                 handleRemoteException(e);
396                 return false;
397             }
398         }
399     }
400 
401     /**
402      * Stops the HAL
403      */
stopVendorHal()404     public void stopVendorHal() {
405         synchronized (sLock) {
406             mHalDeviceManager.stop();
407             clearState();
408             mLog.i("Vendor Hal stopped");
409         }
410     }
411 
412     /**
413      * Clears the state associated with a started Iface
414      *
415      * Caller should hold the lock.
416      */
clearState()417     private void clearState() {
418         mIWifiChip = null;
419         mIWifiStaIface = null;
420         mIWifiApIface = null;
421         mIWifiRttController = null;
422         mDriverDescription = null;
423         mFirmwareDescription = null;
424         mChannelsForBandSupport = null;
425     }
426 
427     /**
428      * Tests whether the HAL is running or not
429      */
isHalStarted()430     public boolean isHalStarted() {
431         // For external use only. Methods in this class should test for null directly.
432         synchronized (sLock) {
433             return (mIWifiStaIface != null || mIWifiApIface != null);
434         }
435     }
436 
437     /**
438      * Gets the scan capabilities
439      *
440      * @param capabilities object to be filled in
441      * @return true for success, false for failure
442      */
getBgScanCapabilities(WifiNative.ScanCapabilities capabilities)443     public boolean getBgScanCapabilities(WifiNative.ScanCapabilities capabilities) {
444         synchronized (sLock) {
445             if (mIWifiStaIface == null) return boolResult(false);
446             try {
447                 MutableBoolean ans = new MutableBoolean(false);
448                 WifiNative.ScanCapabilities out = capabilities;
449                 mIWifiStaIface.getBackgroundScanCapabilities((status, cap) -> {
450                             if (!ok(status)) return;
451                             mVerboseLog.info("scan capabilities %").c(cap.toString()).flush();
452                             out.max_scan_cache_size = cap.maxCacheSize;
453                             out.max_ap_cache_per_scan = cap.maxApCachePerScan;
454                             out.max_scan_buckets = cap.maxBuckets;
455                             out.max_rssi_sample_size = 0;
456                             out.max_scan_reporting_threshold = cap.maxReportingThreshold;
457                             ans.value = true;
458                         }
459                 );
460                 return ans.value;
461             } catch (RemoteException e) {
462                 handleRemoteException(e);
463                 return false;
464             }
465         }
466     }
467 
468     /**
469      * Holds the current background scan state, to implement pause and restart
470      */
471     @VisibleForTesting
472     class CurrentBackgroundScan {
473         public int cmdId;
474         public StaBackgroundScanParameters param;
475         public WifiNative.ScanEventHandler eventHandler = null;
476         public boolean paused = false;
477         public WifiScanner.ScanData[] latestScanResults = null;
478 
CurrentBackgroundScan(int id, WifiNative.ScanSettings settings)479         CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) {
480             cmdId = id;
481             param = new StaBackgroundScanParameters();
482             param.basePeriodInMs = settings.base_period_ms;
483             param.maxApPerScan = settings.max_ap_per_scan;
484             param.reportThresholdPercent = settings.report_threshold_percent;
485             param.reportThresholdNumScans = settings.report_threshold_num_scans;
486             if (settings.buckets != null) {
487                 for (WifiNative.BucketSettings bs : settings.buckets) {
488                     param.buckets.add(makeStaBackgroundScanBucketParametersFromBucketSettings(bs));
489                 }
490             }
491         }
492     }
493 
494     /**
495      * Makes the Hal flavor of WifiNative.BucketSettings
496      *
497      * @param bs WifiNative.BucketSettings
498      * @return Hal flavor of bs
499      * @throws IllegalArgumentException if band value is not recognized
500      */
501     private StaBackgroundScanBucketParameters
makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs)502             makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs) {
503         StaBackgroundScanBucketParameters pa = new StaBackgroundScanBucketParameters();
504         pa.bucketIdx = bs.bucket;
505         pa.band = makeWifiBandFromFrameworkBand(bs.band);
506         if (bs.channels != null) {
507             for (WifiNative.ChannelSettings cs : bs.channels) {
508                 pa.frequencies.add(cs.frequency);
509             }
510         }
511         pa.periodInMs = bs.period_ms;
512         pa.eventReportScheme = makeReportSchemeFromBucketSettingsReportEvents(bs.report_events);
513         pa.exponentialMaxPeriodInMs = bs.max_period_ms;
514         // Although HAL API allows configurable base value for the truncated
515         // exponential back off scan. Native API and above support only
516         // truncated binary exponential back off scan.
517         // Hard code value of base to 2 here.
518         pa.exponentialBase = 2;
519         pa.exponentialStepCount = bs.step_count;
520         return pa;
521     }
522 
523     /**
524      * Makes the Hal flavor of WifiScanner's band indication
525      *
526      * @param frameworkBand one of WifiScanner.WIFI_BAND_*
527      * @return A WifiBand value
528      * @throws IllegalArgumentException if frameworkBand is not recognized
529      */
makeWifiBandFromFrameworkBand(int frameworkBand)530     private int makeWifiBandFromFrameworkBand(int frameworkBand) {
531         switch (frameworkBand) {
532             case WifiScanner.WIFI_BAND_UNSPECIFIED:
533                 return WifiBand.BAND_UNSPECIFIED;
534             case WifiScanner.WIFI_BAND_24_GHZ:
535                 return WifiBand.BAND_24GHZ;
536             case WifiScanner.WIFI_BAND_5_GHZ:
537                 return WifiBand.BAND_5GHZ;
538             case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
539                 return WifiBand.BAND_5GHZ_DFS;
540             case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS:
541                 return WifiBand.BAND_5GHZ_WITH_DFS;
542             case WifiScanner.WIFI_BAND_BOTH:
543                 return WifiBand.BAND_24GHZ_5GHZ;
544             case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
545                 return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS;
546             default:
547                 throw new IllegalArgumentException("bad band " + frameworkBand);
548         }
549     }
550 
551     /**
552      * Makes the Hal flavor of WifiScanner's report event mask
553      *
554      * @param reportUnderscoreEvents is logical OR of WifiScanner.REPORT_EVENT_* values
555      * @return Corresponding StaBackgroundScanBucketEventReportSchemeMask value
556      * @throws IllegalArgumentException if a mask bit is not recognized
557      */
makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents)558     private int makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents) {
559         int ans = 0;
560         BitMask in = new BitMask(reportUnderscoreEvents);
561         if (in.testAndClear(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)) {
562             ans |= StaBackgroundScanBucketEventReportSchemeMask.EACH_SCAN;
563         }
564         if (in.testAndClear(WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)) {
565             ans |= StaBackgroundScanBucketEventReportSchemeMask.FULL_RESULTS;
566         }
567         if (in.testAndClear(WifiScanner.REPORT_EVENT_NO_BATCH)) {
568             ans |= StaBackgroundScanBucketEventReportSchemeMask.NO_BATCH;
569         }
570         if (in.value != 0) throw new IllegalArgumentException("bad " + reportUnderscoreEvents);
571         return ans;
572     }
573 
574     private int mLastScanCmdId; // For assigning cmdIds to scans
575 
576     @VisibleForTesting
577     CurrentBackgroundScan mScan = null;
578 
579     /**
580      * Starts a background scan
581      *
582      * Any ongoing scan will be stopped first
583      *
584      * @param settings     to control the scan
585      * @param eventHandler to call with the results
586      * @return true for success
587      */
startBgScan(WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler)588     public boolean startBgScan(WifiNative.ScanSettings settings,
589                                WifiNative.ScanEventHandler eventHandler) {
590         WifiStatus status;
591         if (eventHandler == null) return boolResult(false);
592         synchronized (sLock) {
593             if (mIWifiStaIface == null) return boolResult(false);
594             try {
595                 if (mScan != null && !mScan.paused) {
596                     ok(mIWifiStaIface.stopBackgroundScan(mScan.cmdId));
597                     mScan = null;
598                 }
599                 mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits
600                 CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings);
601                 status = mIWifiStaIface.startBackgroundScan(scan.cmdId, scan.param);
602                 if (!ok(status)) return false;
603                 scan.eventHandler = eventHandler;
604                 mScan = scan;
605                 return true;
606             } catch (RemoteException e) {
607                 handleRemoteException(e);
608                 return false;
609             }
610         }
611     }
612 
613 
614     /**
615      * Stops any ongoing backgound scan
616      */
stopBgScan()617     public void stopBgScan() {
618         WifiStatus status;
619         synchronized (sLock) {
620             if (mIWifiStaIface == null) return;
621             try {
622                 if (mScan != null) {
623                     ok(mIWifiStaIface.stopBackgroundScan(mScan.cmdId));
624                     mScan = null;
625                 }
626             } catch (RemoteException e) {
627                 handleRemoteException(e);
628             }
629         }
630     }
631 
632     /**
633      * Pauses an ongoing backgound scan
634      */
pauseBgScan()635     public void pauseBgScan() {
636         WifiStatus status;
637         synchronized (sLock) {
638             try {
639                 if (mIWifiStaIface == null) return;
640                 if (mScan != null && !mScan.paused) {
641                     status = mIWifiStaIface.stopBackgroundScan(mScan.cmdId);
642                     if (!ok(status)) return;
643                     mScan.paused = true;
644                 }
645             } catch (RemoteException e) {
646                 handleRemoteException(e);
647             }
648         }
649     }
650 
651     /**
652      * Restarts a paused background scan
653      */
restartBgScan()654     public void restartBgScan() {
655         WifiStatus status;
656         synchronized (sLock) {
657             if (mIWifiStaIface == null) return;
658             try {
659                 if (mScan != null && mScan.paused) {
660                     status = mIWifiStaIface.startBackgroundScan(mScan.cmdId, mScan.param);
661                     if (!ok(status)) return;
662                     mScan.paused = false;
663                 }
664             } catch (RemoteException e) {
665                 handleRemoteException(e);
666             }
667         }
668     }
669 
670     /**
671      * Gets the latest scan results received from the HIDL interface callback.
672      * TODO(b/35754840): This hop to fetch scan results after callback is unnecessary. Refactor
673      * WifiScanner to use the scan results from the callback.
674      */
getBgScanResults()675     public WifiScanner.ScanData[] getBgScanResults() {
676         synchronized (sLock) {
677             if (mIWifiStaIface == null) return null;
678             if (mScan == null) return null;
679             return mScan.latestScanResults;
680         }
681     }
682 
683     /**
684      * Get the link layer statistics
685      *
686      * Note - we always enable link layer stats on a STA interface.
687      *
688      * @return the statistics, or null if unable to do so
689      */
getWifiLinkLayerStats()690     public WifiLinkLayerStats getWifiLinkLayerStats() {
691         class AnswerBox {
692             public StaLinkLayerStats value = null;
693         }
694         AnswerBox answer = new AnswerBox();
695         synchronized (sLock) {
696             try {
697                 if (mIWifiStaIface == null) return null;
698                 mIWifiStaIface.getLinkLayerStats((status, stats) -> {
699                     if (!ok(status)) return;
700                     answer.value = stats;
701                 });
702             } catch (RemoteException e) {
703                 handleRemoteException(e);
704                 return null;
705             }
706         }
707         WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats(answer.value);
708         return stats;
709     }
710 
711     /**
712      * Makes the framework version of link layer stats from the hal version.
713      */
714     @VisibleForTesting
frameworkFromHalLinkLayerStats(StaLinkLayerStats stats)715     static WifiLinkLayerStats frameworkFromHalLinkLayerStats(StaLinkLayerStats stats) {
716         if (stats == null) return null;
717         WifiLinkLayerStats out = new WifiLinkLayerStats();
718         // unpopulated: out.status, out.SSID, out.BSSID
719         out.beacon_rx = stats.iface.beaconRx;
720         out.rssi_mgmt = stats.iface.avgRssiMgmt;
721         // Statistics are broken out by Wireless Multimedia Extensions categories
722         // WME Best Effort Access Category
723         out.rxmpdu_be = stats.iface.wmeBePktStats.rxMpdu;
724         out.txmpdu_be = stats.iface.wmeBePktStats.txMpdu;
725         out.lostmpdu_be = stats.iface.wmeBePktStats.lostMpdu;
726         out.retries_be = stats.iface.wmeBePktStats.retries;
727         // WME Background Access Category
728         out.rxmpdu_bk = stats.iface.wmeBkPktStats.rxMpdu;
729         out.txmpdu_bk = stats.iface.wmeBkPktStats.txMpdu;
730         out.lostmpdu_bk = stats.iface.wmeBkPktStats.lostMpdu;
731         out.retries_bk = stats.iface.wmeBkPktStats.retries;
732         // WME Video Access Category
733         out.rxmpdu_vi = stats.iface.wmeViPktStats.rxMpdu;
734         out.txmpdu_vi = stats.iface.wmeViPktStats.txMpdu;
735         out.lostmpdu_vi = stats.iface.wmeViPktStats.lostMpdu;
736         out.retries_vi = stats.iface.wmeViPktStats.retries;
737         // WME Voice Access Category
738         out.rxmpdu_vo = stats.iface.wmeVoPktStats.rxMpdu;
739         out.txmpdu_vo = stats.iface.wmeVoPktStats.txMpdu;
740         out.lostmpdu_vo = stats.iface.wmeVoPktStats.lostMpdu;
741         out.retries_vo = stats.iface.wmeVoPktStats.retries;
742         // TODO(b/36176141): Figure out how to coalesce this info for multi radio devices.
743         if (stats.radios.size() > 0) {
744             StaLinkLayerRadioStats radioStats = stats.radios.get(0);
745             out.on_time = radioStats.onTimeInMs;
746             out.tx_time = radioStats.txTimeInMs;
747             out.tx_time_per_level = new int[radioStats.txTimeInMsPerLevel.size()];
748             for (int i = 0; i < out.tx_time_per_level.length; i++) {
749                 out.tx_time_per_level[i] = radioStats.txTimeInMsPerLevel.get(i);
750             }
751             out.rx_time = radioStats.rxTimeInMs;
752             out.on_time_scan = radioStats.onTimeInMsForScan;
753         }
754         // unused: stats.timeStampInMs;
755         return out;
756     }
757 
758     @VisibleForTesting
759     boolean mLinkLayerStatsDebug = false;  // Passed to Hal
760 
761     /**
762      * Enables the linkLayerStats in the Hal.
763      *
764      * This is called unconditionally whenever we create a STA interface.
765      */
enableLinkLayerStats()766     private void enableLinkLayerStats() {
767         synchronized (sLock) {
768             try {
769                 WifiStatus status;
770                 status = mIWifiStaIface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
771                 if (!ok(status)) {
772                     mLog.e("unable to enable link layer stats collection");
773                 }
774             } catch (RemoteException e) {
775                 handleRemoteException(e);
776             }
777         }
778     }
779 
780     /**
781      * Translation table used by getSupportedFeatureSet for translating IWifiChip caps
782      */
783     private static final int[][] sChipFeatureCapabilityTranslation = {
784             {WifiManager.WIFI_FEATURE_TX_POWER_LIMIT,
785                     android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.SET_TX_POWER_LIMIT
786             },
787             {WifiManager.WIFI_FEATURE_D2D_RTT,
788                     android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2D_RTT
789             },
790             {WifiManager.WIFI_FEATURE_D2AP_RTT,
791                     android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2AP_RTT
792             }
793     };
794 
795     /**
796      * Feature bit mask translation for Chip
797      *
798      * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask
799      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
800      */
801     @VisibleForTesting
wifiFeatureMaskFromChipCapabilities(int capabilities)802     int wifiFeatureMaskFromChipCapabilities(int capabilities) {
803         int features = 0;
804         for (int i = 0; i < sChipFeatureCapabilityTranslation.length; i++) {
805             if ((capabilities & sChipFeatureCapabilityTranslation[i][1]) != 0) {
806                 features |= sChipFeatureCapabilityTranslation[i][0];
807             }
808         }
809         return features;
810     }
811 
812     /**
813      * Translation table used by getSupportedFeatureSet for translating IWifiStaIface caps
814      */
815     private static final int[][] sStaFeatureCapabilityTranslation = {
816             {WifiManager.WIFI_FEATURE_INFRA_5G,
817                     IWifiStaIface.StaIfaceCapabilityMask.STA_5G
818             },
819             {WifiManager.WIFI_FEATURE_PASSPOINT,
820                     IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT
821             },
822             {WifiManager.WIFI_FEATURE_SCANNER,
823                     IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN,
824             },
825             {WifiManager.WIFI_FEATURE_PNO,
826                     IWifiStaIface.StaIfaceCapabilityMask.PNO
827             },
828             {WifiManager.WIFI_FEATURE_TDLS,
829                     IWifiStaIface.StaIfaceCapabilityMask.TDLS
830             },
831             {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL,
832                     IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL
833             },
834             {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS,
835                     IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
836             },
837             {WifiManager.WIFI_FEATURE_RSSI_MONITOR,
838                     IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR
839             },
840             {WifiManager.WIFI_FEATURE_MKEEP_ALIVE,
841                     IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE
842             },
843             {WifiManager.WIFI_FEATURE_CONFIG_NDO,
844                     IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD
845             },
846             {WifiManager.WIFI_FEATURE_CONTROL_ROAMING,
847                     IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING
848             },
849             {WifiManager.WIFI_FEATURE_IE_WHITELIST,
850                     IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST
851             },
852             {WifiManager.WIFI_FEATURE_SCAN_RAND,
853                     IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND
854             },
855     };
856 
857     /**
858      * Feature bit mask translation for STAs
859      *
860      * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask
861      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
862      */
863     @VisibleForTesting
wifiFeatureMaskFromStaCapabilities(int capabilities)864     int wifiFeatureMaskFromStaCapabilities(int capabilities) {
865         int features = 0;
866         for (int i = 0; i < sStaFeatureCapabilityTranslation.length; i++) {
867             if ((capabilities & sStaFeatureCapabilityTranslation[i][1]) != 0) {
868                 features |= sStaFeatureCapabilityTranslation[i][0];
869             }
870         }
871         return features;
872     }
873 
874     /**
875      * Get the supported features
876      *
877      * The result may differ depending on the mode (STA or AP)
878      *
879      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
880      */
getSupportedFeatureSet()881     public int getSupportedFeatureSet() {
882         int featureSet = 0;
883         if (!mHalDeviceManager.isStarted()) {
884             return featureSet; // TODO: can't get capabilities with Wi-Fi down
885         }
886         try {
887             final MutableInt feat = new MutableInt(0);
888             synchronized (sLock) {
889                 if (mIWifiChip != null) {
890                     mIWifiChip.getCapabilities((status, capabilities) -> {
891                         if (!ok(status)) return;
892                         feat.value = wifiFeatureMaskFromChipCapabilities(capabilities);
893                     });
894                 }
895                 if (mIWifiStaIface != null) {
896                     mIWifiStaIface.getCapabilities((status, capabilities) -> {
897                         if (!ok(status)) return;
898                         feat.value |= wifiFeatureMaskFromStaCapabilities(capabilities);
899                     });
900                 }
901             }
902             featureSet = feat.value;
903         } catch (RemoteException e) {
904             handleRemoteException(e);
905             return 0;
906         }
907 
908         Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes();
909         if (supportedIfaceTypes.contains(IfaceType.STA)) {
910             featureSet |= WifiManager.WIFI_FEATURE_INFRA;
911         }
912         if (supportedIfaceTypes.contains(IfaceType.AP)) {
913             featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT;
914         }
915         if (supportedIfaceTypes.contains(IfaceType.P2P)) {
916             featureSet |= WifiManager.WIFI_FEATURE_P2P;
917         }
918         if (supportedIfaceTypes.contains(IfaceType.NAN)) {
919             featureSet |= WifiManager.WIFI_FEATURE_AWARE;
920         }
921 
922         return featureSet;
923     }
924 
925     /* RTT related commands/events */
926 
927     /**
928      * RTT (Round Trip Time) measurement capabilities of the device.
929      */
getRttCapabilities()930     public RttManager.RttCapabilities getRttCapabilities() {
931         class AnswerBox {
932             public RttManager.RttCapabilities value = null;
933         }
934         synchronized (sLock) {
935             if (mIWifiRttController == null) return null;
936             try {
937                 AnswerBox box = new AnswerBox();
938                 mIWifiRttController.getCapabilities((status, capabilities) -> {
939                     if (!ok(status)) return;
940                     mVerboseLog.info("rtt capabilites %").c(capabilities.toString()).flush();
941                     RttManager.RttCapabilities ans = new RttManager.RttCapabilities();
942                     ans.oneSidedRttSupported = capabilities.rttOneSidedSupported;
943                     ans.twoSided11McRttSupported = capabilities.rttFtmSupported;
944                     ans.lciSupported = capabilities.lciSupported;
945                     ans.lcrSupported = capabilities.lcrSupported;
946                     ans.preambleSupported = frameworkPreambleFromHalPreamble(
947                             capabilities.preambleSupport);
948                     ans.bwSupported = frameworkBwFromHalBw(capabilities.bwSupport);
949                     ans.responderSupported = capabilities.responderSupported;
950                     ans.secureRttSupported = false;
951                     ans.mcVersion = ((int) capabilities.mcVersion) & 0xff;
952                     box.value = ans;
953                 });
954                 return box.value;
955             } catch (RemoteException e) {
956                 handleRemoteException(e);
957                 return null;
958             }
959         }
960     }
961 
962     private int mRttCmdIdNext = 1;              // used to generate new command ids
963     private int mRttCmdId;                      // id of currently active request
964     // Event handler for current active RTT request.
965     private WifiNative.RttEventHandler mRttEventHandler;
966 
967     /**
968      * Receives a callback from the Hal and passes it along to our client using RttEventHandler
969      */
970     private class RttEventCallback extends IWifiRttControllerEventCallback.Stub {
971 
972         @Override
onResults(int cmdId, java.util.ArrayList<RttResult> results)973         public void onResults(int cmdId, java.util.ArrayList<RttResult> results) {
974             WifiNative.RttEventHandler eventHandler;
975             synchronized (sLock) {
976                 if (cmdId != mRttCmdId || mRttEventHandler == null) return;
977                 eventHandler = mRttEventHandler;
978                 // Reset the command id for RTT operations in WifiVendorHal.
979                 WifiVendorHal.this.mRttCmdId = 0;
980             }
981             RttManager.RttResult[] rtt = new RttManager.RttResult[results.size()];
982             for (int i = 0; i < rtt.length; i++) {
983                 rtt[i] = frameworkRttResultFromHalRttResult(results.get(i));
984             }
985             eventHandler.onRttResults(rtt);
986         }
987     }
988 
989     /**
990      * Converts a Hal RttResult to a RttManager.RttResult
991      */
992     @VisibleForTesting
frameworkRttResultFromHalRttResult(RttResult result)993     static RttManager.RttResult frameworkRttResultFromHalRttResult(RttResult result) {
994         RttManager.RttResult ans = new RttManager.RttResult();
995         ans.bssid = NativeUtil.macAddressFromByteArray(result.addr);
996         ans.burstNumber = result.burstNum;
997         ans.measurementFrameNumber = result.measurementNumber;
998         ans.successMeasurementFrameNumber = result.successNumber;
999         ans.frameNumberPerBurstPeer = result.numberPerBurstPeer;
1000         ans.status = result.status; //TODO(b/35138520) - don't assume identity translation
1001         ans.retryAfterDuration = result.retryAfterDuration;
1002         ans.measurementType = result.type;
1003         ans.rssi = result.rssi;
1004         ans.rssiSpread = result.rssiSpread;
1005         //TODO(b/35138520) Fix HAL and framework to use the same units
1006         ans.txRate = result.txRate.bitRateInKbps;
1007         ans.rxRate = result.rxRate.bitRateInKbps;
1008         ans.rtt = result.rtt;
1009         ans.rttStandardDeviation = result.rttSd;
1010         ans.rttSpread = result.rttSpread;
1011         //TODO(b/35138520) These divide-by-10s were in the legacy Hal
1012         ans.distance = result.distanceInMm / 10; // Convert cm to mm
1013         ans.distanceStandardDeviation = result.distanceSdInMm / 10; // Convert cm to mm
1014         ans.distanceSpread = result.distanceSpreadInMm / 10;
1015 
1016         ans.ts = result.timeStampInUs;
1017         ans.burstDuration = result.burstDurationInMs;
1018         ans.negotiatedBurstNum = result.negotiatedBurstNum;
1019         ans.LCI = ieFromHal(result.lci);
1020         ans.LCR = ieFromHal(result.lcr);
1021         ans.secure = false; // Not present in HIDL HAL
1022         return ans;
1023     }
1024 
1025     /**
1026      * Convert a Hal WifiInformationElement to its RttManager equivalent
1027      */
1028     @VisibleForTesting
ieFromHal( android.hardware.wifi.V1_0.WifiInformationElement ie)1029     static RttManager.WifiInformationElement ieFromHal(
1030             android.hardware.wifi.V1_0.WifiInformationElement ie) {
1031         if (ie == null) return null;
1032         RttManager.WifiInformationElement ans = new RttManager.WifiInformationElement();
1033         ans.id = ie.id;
1034         ans.data = NativeUtil.byteArrayFromArrayList(ie.data);
1035         return ans;
1036     }
1037 
1038     @VisibleForTesting
halRttConfigFromFrameworkRttParams(RttManager.RttParams params)1039     static RttConfig halRttConfigFromFrameworkRttParams(RttManager.RttParams params) {
1040         RttConfig rttConfig = new RttConfig();
1041         if (params.bssid != null) {
1042             byte[] addr = NativeUtil.macAddressToByteArray(params.bssid);
1043             for (int i = 0; i < rttConfig.addr.length; i++) {
1044                 rttConfig.addr[i] = addr[i];
1045             }
1046         }
1047         rttConfig.type = halRttTypeFromFrameworkRttType(params.requestType);
1048         rttConfig.peer = halPeerFromFrameworkPeer(params.deviceType);
1049         rttConfig.channel.width = halChannelWidthFromFrameworkChannelWidth(params.channelWidth);
1050         rttConfig.channel.centerFreq = params.frequency;
1051         rttConfig.channel.centerFreq0 = params.centerFreq0;
1052         rttConfig.channel.centerFreq1 = params.centerFreq1;
1053         rttConfig.burstPeriod = params.interval; // In 100ms units, 0 means no specific
1054         rttConfig.numBurst = params.numberBurst;
1055         rttConfig.numFramesPerBurst = params.numSamplesPerBurst;
1056         rttConfig.numRetriesPerRttFrame = params.numRetriesPerMeasurementFrame;
1057         rttConfig.numRetriesPerFtmr = params.numRetriesPerFTMR;
1058         rttConfig.mustRequestLci = params.LCIRequest;
1059         rttConfig.mustRequestLcr = params.LCRRequest;
1060         rttConfig.burstDuration = params.burstTimeout;
1061         rttConfig.preamble = halPreambleFromFrameworkPreamble(params.preamble);
1062         rttConfig.bw = halBwFromFrameworkBw(params.bandwidth);
1063         return rttConfig;
1064     }
1065 
1066     @VisibleForTesting
halRttTypeFromFrameworkRttType(int frameworkRttType)1067     static int halRttTypeFromFrameworkRttType(int frameworkRttType) {
1068         switch (frameworkRttType) {
1069             case RttManager.RTT_TYPE_ONE_SIDED:
1070                 return RttType.ONE_SIDED;
1071             case RttManager.RTT_TYPE_TWO_SIDED:
1072                 return RttType.TWO_SIDED;
1073             default:
1074                 throw new IllegalArgumentException("bad " + frameworkRttType);
1075         }
1076     }
1077 
1078     @VisibleForTesting
frameworkRttTypeFromHalRttType(int halType)1079     static int frameworkRttTypeFromHalRttType(int halType) {
1080         switch (halType) {
1081             case RttType.ONE_SIDED:
1082                 return RttManager.RTT_TYPE_ONE_SIDED;
1083             case RttType.TWO_SIDED:
1084                 return RttManager.RTT_TYPE_TWO_SIDED;
1085             default:
1086                 throw new IllegalArgumentException("bad " + halType);
1087         }
1088     }
1089 
1090     @VisibleForTesting
halPeerFromFrameworkPeer(int frameworkPeer)1091     static int halPeerFromFrameworkPeer(int frameworkPeer) {
1092         switch (frameworkPeer) {
1093             case RttManager.RTT_PEER_TYPE_AP:
1094                 return RttPeerType.AP;
1095             case RttManager.RTT_PEER_TYPE_STA:
1096                 return RttPeerType.STA;
1097             case RttManager.RTT_PEER_P2P_GO:
1098                 return RttPeerType.P2P_GO;
1099             case RttManager.RTT_PEER_P2P_CLIENT:
1100                 return RttPeerType.P2P_CLIENT;
1101             case RttManager.RTT_PEER_NAN:
1102                 return RttPeerType.NAN;
1103             default:
1104                 throw new IllegalArgumentException("bad " + frameworkPeer);
1105         }
1106     }
1107 
1108     @VisibleForTesting
frameworkPeerFromHalPeer(int halPeer)1109     static int frameworkPeerFromHalPeer(int halPeer) {
1110         switch (halPeer) {
1111             case RttPeerType.AP:
1112                 return RttManager.RTT_PEER_TYPE_AP;
1113             case RttPeerType.STA:
1114                 return RttManager.RTT_PEER_TYPE_STA;
1115             case RttPeerType.P2P_GO:
1116                 return RttManager.RTT_PEER_P2P_GO;
1117             case RttPeerType.P2P_CLIENT:
1118                 return RttManager.RTT_PEER_P2P_CLIENT;
1119             case RttPeerType.NAN:
1120                 return RttManager.RTT_PEER_NAN;
1121             default:
1122                 throw new IllegalArgumentException("bad " + halPeer);
1123 
1124         }
1125     }
1126 
1127     @VisibleForTesting
halChannelWidthFromFrameworkChannelWidth(int frameworkChannelWidth)1128     static int halChannelWidthFromFrameworkChannelWidth(int frameworkChannelWidth) {
1129         switch (frameworkChannelWidth) {
1130             case ScanResult.CHANNEL_WIDTH_20MHZ:
1131                 return WifiChannelWidthInMhz.WIDTH_20;
1132             case ScanResult.CHANNEL_WIDTH_40MHZ:
1133                 return WifiChannelWidthInMhz.WIDTH_40;
1134             case ScanResult.CHANNEL_WIDTH_80MHZ:
1135                 return WifiChannelWidthInMhz.WIDTH_80;
1136             case ScanResult.CHANNEL_WIDTH_160MHZ:
1137                 return WifiChannelWidthInMhz.WIDTH_160;
1138             case ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ:
1139                 return WifiChannelWidthInMhz.WIDTH_80P80;
1140             default:
1141                 throw new IllegalArgumentException("bad " + frameworkChannelWidth);
1142         }
1143     }
1144 
1145     @VisibleForTesting
frameworkChannelWidthFromHalChannelWidth(int halChannelWidth)1146     static int frameworkChannelWidthFromHalChannelWidth(int halChannelWidth) {
1147         switch (halChannelWidth) {
1148             case WifiChannelWidthInMhz.WIDTH_20:
1149                 return ScanResult.CHANNEL_WIDTH_20MHZ;
1150             case WifiChannelWidthInMhz.WIDTH_40:
1151                 return ScanResult.CHANNEL_WIDTH_40MHZ;
1152             case WifiChannelWidthInMhz.WIDTH_80:
1153                 return ScanResult.CHANNEL_WIDTH_80MHZ;
1154             case WifiChannelWidthInMhz.WIDTH_160:
1155                 return ScanResult.CHANNEL_WIDTH_160MHZ;
1156             case WifiChannelWidthInMhz.WIDTH_80P80:
1157                 return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
1158             default:
1159                 throw new IllegalArgumentException("bad " + halChannelWidth);
1160         }
1161     }
1162 
1163     @VisibleForTesting
halPreambleFromFrameworkPreamble(int rttManagerPreamble)1164     static int halPreambleFromFrameworkPreamble(int rttManagerPreamble) {
1165         BitMask checkoff = new BitMask(rttManagerPreamble);
1166         int flags = 0;
1167         if (checkoff.testAndClear(RttManager.PREAMBLE_LEGACY)) {
1168             flags |= RttPreamble.LEGACY;
1169         }
1170         if (checkoff.testAndClear(RttManager.PREAMBLE_HT)) {
1171             flags |= RttPreamble.HT;
1172         }
1173         if (checkoff.testAndClear(RttManager.PREAMBLE_VHT)) {
1174             flags |= RttPreamble.VHT;
1175         }
1176         if (checkoff.value != 0) {
1177             throw new IllegalArgumentException("bad " + rttManagerPreamble);
1178         }
1179         return flags;
1180     }
1181 
1182     @VisibleForTesting
frameworkPreambleFromHalPreamble(int halPreamble)1183     static int frameworkPreambleFromHalPreamble(int halPreamble) {
1184         BitMask checkoff = new BitMask(halPreamble);
1185         int flags = 0;
1186         if (checkoff.testAndClear(RttPreamble.LEGACY)) {
1187             flags |= RttManager.PREAMBLE_LEGACY;
1188         }
1189         if (checkoff.testAndClear(RttPreamble.HT)) {
1190             flags |= RttManager.PREAMBLE_HT;
1191         }
1192         if (checkoff.testAndClear(RttPreamble.VHT)) {
1193             flags |= RttManager.PREAMBLE_VHT;
1194         }
1195         if (checkoff.value != 0) {
1196             throw new IllegalArgumentException("bad " + halPreamble);
1197         }
1198         return flags;
1199     }
1200 
1201     @VisibleForTesting
halBwFromFrameworkBw(int rttManagerBandwidth)1202     static int halBwFromFrameworkBw(int rttManagerBandwidth) {
1203         BitMask checkoff = new BitMask(rttManagerBandwidth);
1204         int flags = 0;
1205         if (checkoff.testAndClear(RttManager.RTT_BW_5_SUPPORT)) {
1206             flags |= RttBw.BW_5MHZ;
1207         }
1208         if (checkoff.testAndClear(RttManager.RTT_BW_10_SUPPORT)) {
1209             flags |= RttBw.BW_10MHZ;
1210         }
1211         if (checkoff.testAndClear(RttManager.RTT_BW_20_SUPPORT)) {
1212             flags |= RttBw.BW_20MHZ;
1213         }
1214         if (checkoff.testAndClear(RttManager.RTT_BW_40_SUPPORT)) {
1215             flags |= RttBw.BW_40MHZ;
1216         }
1217         if (checkoff.testAndClear(RttManager.RTT_BW_80_SUPPORT)) {
1218             flags |= RttBw.BW_80MHZ;
1219         }
1220         if (checkoff.testAndClear(RttManager.RTT_BW_160_SUPPORT)) {
1221             flags |= RttBw.BW_160MHZ;
1222         }
1223         if (checkoff.value != 0) {
1224             throw new IllegalArgumentException("bad " + rttManagerBandwidth);
1225         }
1226         return flags;
1227     }
1228 
1229     @VisibleForTesting
frameworkBwFromHalBw(int rttBw)1230     static int frameworkBwFromHalBw(int rttBw) {
1231         BitMask checkoff = new BitMask(rttBw);
1232         int flags = 0;
1233         if (checkoff.testAndClear(RttBw.BW_5MHZ)) {
1234             flags |= RttManager.RTT_BW_5_SUPPORT;
1235         }
1236         if (checkoff.testAndClear(RttBw.BW_10MHZ)) {
1237             flags |= RttManager.RTT_BW_10_SUPPORT;
1238         }
1239         if (checkoff.testAndClear(RttBw.BW_20MHZ)) {
1240             flags |= RttManager.RTT_BW_20_SUPPORT;
1241         }
1242         if (checkoff.testAndClear(RttBw.BW_40MHZ)) {
1243             flags |= RttManager.RTT_BW_40_SUPPORT;
1244         }
1245         if (checkoff.testAndClear(RttBw.BW_80MHZ)) {
1246             flags |= RttManager.RTT_BW_80_SUPPORT;
1247         }
1248         if (checkoff.testAndClear(RttBw.BW_160MHZ)) {
1249             flags |= RttManager.RTT_BW_160_SUPPORT;
1250         }
1251         if (checkoff.value != 0) {
1252             throw new IllegalArgumentException("bad " + rttBw);
1253         }
1254         return flags;
1255     }
1256 
1257     @VisibleForTesting
halRttConfigArrayFromFrameworkRttParamsArray( RttManager.RttParams[] params)1258     static ArrayList<RttConfig> halRttConfigArrayFromFrameworkRttParamsArray(
1259             RttManager.RttParams[] params) {
1260         final int length = params.length;
1261         ArrayList<RttConfig> configs = new ArrayList<RttConfig>(length);
1262         for (int i = 0; i < length; i++) {
1263             RttConfig config = halRttConfigFromFrameworkRttParams(params[i]);
1264             if (config != null) {
1265                 configs.add(config);
1266             }
1267         }
1268         return configs;
1269     }
1270 
1271     /**
1272      * Starts a new rtt request
1273      *
1274      * @param params
1275      * @param handler
1276      * @return success indication
1277      */
requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler)1278     public boolean requestRtt(RttManager.RttParams[] params, WifiNative.RttEventHandler handler) {
1279         ArrayList<RttConfig> rttConfigs;
1280         try {
1281             rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
1282         } catch (IllegalArgumentException e) {
1283             mLog.err("Illegal argument for RTT request").c(e.toString()).flush();
1284             return false;
1285         }
1286         synchronized (sLock) {
1287             if (mIWifiRttController == null) return boolResult(false);
1288             if (mRttCmdId != 0) return boolResult(false);
1289             mRttCmdId = mRttCmdIdNext++;
1290             mRttEventHandler = handler;
1291             if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
1292             try {
1293                 WifiStatus status = mIWifiRttController.rangeRequest(mRttCmdId, rttConfigs);
1294                 if (ok(status)) return true;
1295                 mRttCmdId = 0;
1296                 return false;
1297             } catch (RemoteException e) {
1298                 handleRemoteException(e);
1299                 return false;
1300             }
1301         }
1302     }
1303 
1304     /**
1305      * Cancels an outstanding rtt request
1306      *
1307      * @param params
1308      * @return true if there was an outstanding request and it was successfully cancelled
1309      */
cancelRtt(RttManager.RttParams[] params)1310     public boolean cancelRtt(RttManager.RttParams[] params) {
1311         ArrayList<RttConfig> rttConfigs = halRttConfigArrayFromFrameworkRttParamsArray(params);
1312         synchronized (sLock) {
1313             if (mIWifiRttController == null) return boolResult(false);
1314             if (mRttCmdId == 0) return boolResult(false);
1315             ArrayList<byte[/* 6 */]> addrs = new ArrayList<byte[]>(rttConfigs.size());
1316             for (RttConfig x : rttConfigs) addrs.add(x.addr);
1317             try {
1318                 WifiStatus status = mIWifiRttController.rangeCancel(mRttCmdId, addrs);
1319                 mRttCmdId = 0;
1320                 if (!ok(status)) return false;
1321                 return true;
1322             } catch (RemoteException e) {
1323                 handleRemoteException(e);
1324                 return false;
1325             }
1326         }
1327     }
1328 
1329     private int mRttResponderCmdId = 0;
1330 
1331     /**
1332      * Get RTT responder information e.g. WiFi channel to enable responder on.
1333      *
1334      * @return info Instance of |RttResponder|, or null for error.
1335      */
getRttResponder()1336     private RttResponder getRttResponder() {
1337         class AnswerBox {
1338             public RttResponder value = null;
1339         }
1340         synchronized (sLock) {
1341             if (mIWifiRttController == null) return null;
1342             AnswerBox answer = new AnswerBox();
1343             try {
1344                 mIWifiRttController.getResponderInfo((status, info) -> {
1345                     if (!ok(status)) return;
1346                     answer.value = info;
1347                 });
1348                 return answer.value;
1349             } catch (RemoteException e) {
1350                 handleRemoteException(e);
1351                 return null;
1352             }
1353         }
1354     }
1355 
1356     /**
1357      * Convert Hal RttResponder to a framework ResponderConfig
1358      *
1359      * @param info Instance of |RttResponder|
1360      * @return framework version of same
1361      */
frameworkResponderConfigFromHalRttResponder(RttResponder info)1362     private ResponderConfig frameworkResponderConfigFromHalRttResponder(RttResponder info) {
1363         ResponderConfig config = new ResponderConfig();
1364         config.frequency = info.channel.centerFreq;
1365         config.centerFreq0 = info.channel.centerFreq0;
1366         config.centerFreq1 = info.channel.centerFreq1;
1367         config.channelWidth = frameworkChannelWidthFromHalChannelWidth(info.channel.width);
1368         config.preamble = frameworkPreambleFromHalPreamble(info.preamble);
1369         return config;
1370     }
1371 
1372     /**
1373      * Enables RTT responder role on the device.
1374      *
1375      * @return {@link ResponderConfig} if the responder role is successfully enabled,
1376      * {@code null} otherwise.
1377      */
enableRttResponder(int timeoutSeconds)1378     public ResponderConfig enableRttResponder(int timeoutSeconds) {
1379         RttResponder info = getRttResponder();
1380         synchronized (sLock) {
1381             if (mIWifiRttController == null) return null;
1382             if (mRttResponderCmdId != 0) {
1383                 mLog.e("responder mode already enabled - this shouldn't happen");
1384                 return null;
1385             }
1386             ResponderConfig config = null;
1387             int id = mRttCmdIdNext++;
1388             if (mRttCmdIdNext <= 0) mRttCmdIdNext = 1;
1389             try {
1390                 WifiStatus status = mIWifiRttController.enableResponder(
1391                         /* cmdId */id,
1392                         /* WifiChannelInfo channelHint */null,
1393                         timeoutSeconds, info);
1394                 if (ok(status)) {
1395                     mRttResponderCmdId = id;
1396                     config = frameworkResponderConfigFromHalRttResponder(info);
1397                     mVerboseLog.i("enabling rtt " + mRttResponderCmdId);
1398                 }
1399                 return config;
1400             } catch (RemoteException e) {
1401                 handleRemoteException(e);
1402                 return null;
1403             }
1404         }
1405     }
1406 
1407     /**
1408      * Disables RTT responder role.
1409      *
1410      * @return {@code true} if responder role is successfully disabled,
1411      * {@code false} otherwise.
1412      */
disableRttResponder()1413     public boolean disableRttResponder() {
1414         synchronized (sLock) {
1415             if (mIWifiRttController == null) return boolResult(false);
1416             if (mRttResponderCmdId == 0) return boolResult(false);
1417             try {
1418                 WifiStatus status = mIWifiRttController.disableResponder(mRttResponderCmdId);
1419                 mRttResponderCmdId = 0;
1420                 if (!ok(status)) return false;
1421                 return true;
1422             } catch (RemoteException e) {
1423                 handleRemoteException(e);
1424                 return false;
1425             }
1426         }
1427     }
1428 
1429     /**
1430      * Set the MAC OUI during scanning.
1431      * <p>
1432      * An OUI {Organizationally Unique Identifier} is a 24-bit number that
1433      * uniquely identifies a vendor or manufacturer.
1434      *
1435      * @param oui
1436      * @return true for success
1437      */
setScanningMacOui(byte[] oui)1438     public boolean setScanningMacOui(byte[] oui) {
1439         if (oui == null) return boolResult(false);
1440         if (oui.length != 3) return boolResult(false);
1441         synchronized (sLock) {
1442             try {
1443                 if (mIWifiStaIface == null) return boolResult(false);
1444                 WifiStatus status = mIWifiStaIface.setScanningMacOui(oui);
1445                 if (!ok(status)) return false;
1446                 return true;
1447             } catch (RemoteException e) {
1448                 handleRemoteException(e);
1449                 return false;
1450             }
1451         }
1452     }
1453 
1454     /**
1455      * Query the list of valid frequencies for the provided band.
1456      * <p>
1457      * The result depends on the on the country code that has been set.
1458      *
1459      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1460      * @return frequencies vector of valid frequencies (MHz), or null for error.
1461      * @throws IllegalArgumentException if band is not recognized.
1462      */
getChannelsForBand(int band)1463     public int[] getChannelsForBand(int band) {
1464         enter("%").c(band).flush();
1465         class AnswerBox {
1466             public int[] value = null;
1467         }
1468         synchronized (sLock) {
1469             try {
1470                 AnswerBox box = new AnswerBox();
1471                 int hb = makeWifiBandFromFrameworkBand(band);
1472                 if (mIWifiStaIface != null) {
1473                     mIWifiStaIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
1474                         if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
1475                             mChannelsForBandSupport = false;
1476                         }
1477                         if (!ok(status)) return;
1478                         mChannelsForBandSupport = true;
1479                         box.value = intArrayFromArrayList(frequencies);
1480                     });
1481                 } else if (mIWifiApIface != null) {
1482                     mIWifiApIface.getValidFrequenciesForBand(hb, (status, frequencies) -> {
1483                         if (status.code == WifiStatusCode.ERROR_NOT_SUPPORTED) {
1484                             mChannelsForBandSupport = false;
1485                         }
1486                         if (!ok(status)) return;
1487                         mChannelsForBandSupport = true;
1488                         box.value = intArrayFromArrayList(frequencies);
1489                     });
1490                 }
1491                 return box.value;
1492             } catch (RemoteException e) {
1493                 handleRemoteException(e);
1494                 return null;
1495             }
1496         }
1497     }
1498 
intArrayFromArrayList(ArrayList<Integer> in)1499     private int[] intArrayFromArrayList(ArrayList<Integer> in) {
1500         int[] ans = new int[in.size()];
1501         int i = 0;
1502         for (Integer e : in) ans[i++] = e;
1503         return ans;
1504     }
1505 
1506     /**
1507      * This holder is null until we know whether or not there is frequency-for-band support.
1508      * <p>
1509      * Set as a side-effect of getChannelsForBand.
1510      */
1511     @VisibleForTesting
1512     Boolean mChannelsForBandSupport = null;
1513 
1514     /**
1515      * Indicates whether getChannelsForBand is supported.
1516      *
1517      * @return true if it is.
1518      */
isGetChannelsForBandSupported()1519     public boolean isGetChannelsForBandSupported() {
1520         if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
1521         getChannelsForBand(WifiBand.BAND_24GHZ);
1522         if (mChannelsForBandSupport != null) return mChannelsForBandSupport;
1523         return false;
1524     }
1525 
1526     /**
1527      * Get the APF (Android Packet Filter) capabilities of the device
1528      */
getApfCapabilities()1529     public ApfCapabilities getApfCapabilities() {
1530         class AnswerBox {
1531             public ApfCapabilities value = sNoApfCapabilities;
1532         }
1533         synchronized (sLock) {
1534             try {
1535                 if (mIWifiStaIface == null) return sNoApfCapabilities;
1536                 AnswerBox box = new AnswerBox();
1537                 mIWifiStaIface.getApfPacketFilterCapabilities((status, capabilities) -> {
1538                     if (!ok(status)) return;
1539                     box.value = new ApfCapabilities(
1540                         /* apfVersionSupported */   capabilities.version,
1541                         /* maximumApfProgramSize */ capabilities.maxLength,
1542                         /* apfPacketFormat */       android.system.OsConstants.ARPHRD_ETHER);
1543                 });
1544                 return box.value;
1545             } catch (RemoteException e) {
1546                 handleRemoteException(e);
1547                 return sNoApfCapabilities;
1548             }
1549         }
1550     }
1551 
1552     private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
1553 
1554     /**
1555      * Installs an APF program on this iface, replacing any existing program.
1556      *
1557      * @param filter is the android packet filter program
1558      * @return true for success
1559      */
installPacketFilter(byte[] filter)1560     public boolean installPacketFilter(byte[] filter) {
1561         int cmdId = 0; // We only aspire to support one program at a time
1562         if (filter == null) return boolResult(false);
1563         // Copy the program before taking the lock.
1564         ArrayList<Byte> program = NativeUtil.byteArrayToArrayList(filter);
1565         enter("filter length %").c(filter.length).flush();
1566         synchronized (sLock) {
1567             try {
1568                 if (mIWifiStaIface == null) return boolResult(false);
1569                 WifiStatus status = mIWifiStaIface.installApfPacketFilter(cmdId, program);
1570                 if (!ok(status)) return false;
1571                 return true;
1572             } catch (RemoteException e) {
1573                 handleRemoteException(e);
1574                 return false;
1575             }
1576         }
1577     }
1578 
1579     /**
1580      * Set country code for this AP iface.
1581      *
1582      * @param countryCode - two-letter country code (as ISO 3166)
1583      * @return true for success
1584      */
setCountryCodeHal(String countryCode)1585     public boolean setCountryCodeHal(String countryCode) {
1586         if (countryCode == null) return boolResult(false);
1587         if (countryCode.length() != 2) return boolResult(false);
1588         byte[] code;
1589         try {
1590             code = NativeUtil.stringToByteArray(countryCode);
1591         } catch (IllegalArgumentException e) {
1592             return boolResult(false);
1593         }
1594         synchronized (sLock) {
1595             try {
1596                 if (mIWifiApIface == null) return boolResult(false);
1597                 WifiStatus status = mIWifiApIface.setCountryCode(code);
1598                 if (!ok(status)) return false;
1599                 return true;
1600             } catch (RemoteException e) {
1601                 handleRemoteException(e);
1602                 return false;
1603             }
1604         }
1605     }
1606 
1607     private WifiNative.WifiLoggerEventHandler mLogEventHandler = null;
1608 
1609     /**
1610      * Registers the logger callback and enables alerts.
1611      * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
1612      */
setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler)1613     public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
1614         if (handler == null) return boolResult(false);
1615         synchronized (sLock) {
1616             if (mIWifiChip == null) return boolResult(false);
1617             if (mLogEventHandler != null) return boolResult(false);
1618             try {
1619                 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(true);
1620                 if (!ok(status)) return false;
1621                 mLogEventHandler = handler;
1622                 return true;
1623             } catch (RemoteException e) {
1624                 handleRemoteException(e);
1625                 return false;
1626             }
1627         }
1628     }
1629 
1630     /**
1631      * Stops all logging and resets the logger callback.
1632      * This stops both the alerts and ring buffer data collection.
1633      */
resetLogHandler()1634     public boolean resetLogHandler() {
1635         synchronized (sLock) {
1636             if (mIWifiChip == null) return boolResult(false);
1637             if (mLogEventHandler == null) return boolResult(false);
1638             try {
1639                 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(false);
1640                 if (!ok(status)) return false;
1641                 status = mIWifiChip.stopLoggingToDebugRingBuffer();
1642                 if (!ok(status)) return false;
1643                 mLogEventHandler = null;
1644                 return true;
1645             } catch (RemoteException e) {
1646                 handleRemoteException(e);
1647                 return false;
1648             }
1649         }
1650     }
1651 
1652     /**
1653      * Control debug data collection
1654      *
1655      * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
1656      * @param flags              Ignored.
1657      * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
1658      * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
1659      * @param ringName           Name of the ring for which data collection is to start.
1660      * @return true for success
1661      */
startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec, int minDataSizeInBytes, String ringName)1662     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
1663                                           int minDataSizeInBytes, String ringName) {
1664         enter("verboseLevel=%, flags=%, maxIntervalInSec=%, minDataSizeInBytes=%, ringName=%")
1665                 .c(verboseLevel).c(flags).c(maxIntervalInSec).c(minDataSizeInBytes).c(ringName)
1666                 .flush();
1667         synchronized (sLock) {
1668             if (mIWifiChip == null) return boolResult(false);
1669             try {
1670                 // note - flags are not used
1671                 WifiStatus status = mIWifiChip.startLoggingToDebugRingBuffer(
1672                         ringName,
1673                         verboseLevel,
1674                         maxIntervalInSec,
1675                         minDataSizeInBytes
1676                 );
1677                 return ok(status);
1678             } catch (RemoteException e) {
1679                 handleRemoteException(e);
1680                 return false;
1681             }
1682         }
1683     }
1684 
1685     /**
1686      * Pointlessly fail
1687      *
1688      * @return -1
1689      */
getSupportedLoggerFeatureSet()1690     public int getSupportedLoggerFeatureSet() {
1691         return -1;
1692     }
1693 
1694     private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
1695 
1696     /**
1697      * Vendor-provided wifi driver version string
1698      */
getDriverVersion()1699     public String getDriverVersion() {
1700         synchronized (sLock) {
1701             if (mDriverDescription == null) requestChipDebugInfo();
1702             return mDriverDescription;
1703         }
1704     }
1705 
1706     private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
1707 
1708     /**
1709      * Vendor-provided wifi firmware version string
1710      */
getFirmwareVersion()1711     public String getFirmwareVersion() {
1712         synchronized (sLock) {
1713             if (mFirmwareDescription == null) requestChipDebugInfo();
1714             return mFirmwareDescription;
1715         }
1716     }
1717 
1718     /**
1719      * Refreshes our idea of the driver and firmware versions
1720      */
requestChipDebugInfo()1721     private void requestChipDebugInfo() {
1722         mDriverDescription = null;
1723         mFirmwareDescription = null;
1724         try {
1725             if (mIWifiChip == null) return;
1726             mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> {
1727                 if (!ok(status)) return;
1728                 mDriverDescription = chipDebugInfo.driverDescription;
1729                 mFirmwareDescription = chipDebugInfo.firmwareDescription;
1730             });
1731         } catch (RemoteException e) {
1732             handleRemoteException(e);
1733             return;
1734         }
1735         mLog.info("Driver: % Firmware: %")
1736                 .c(mDriverDescription)
1737                 .c(mFirmwareDescription)
1738                 .flush();
1739     }
1740 
1741     /**
1742      * Creates RingBufferStatus from the Hal version
1743      */
ringBufferStatus(WifiDebugRingBufferStatus h)1744     private static WifiNative.RingBufferStatus ringBufferStatus(WifiDebugRingBufferStatus h) {
1745         WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus();
1746         ans.name = h.ringName;
1747         ans.flag = frameworkRingBufferFlagsFromHal(h.flags);
1748         ans.ringBufferId = h.ringId;
1749         ans.ringBufferByteSize = h.sizeInBytes;
1750         ans.verboseLevel = h.verboseLevel;
1751         // Remaining fields are unavailable
1752         //  writtenBytes;
1753         //  readBytes;
1754         //  writtenRecords;
1755         return ans;
1756     }
1757 
1758     /**
1759      * Translates a hal wifiDebugRingBufferFlag to the WifiNative version
1760      */
frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag)1761     private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) {
1762         BitMask checkoff = new BitMask(wifiDebugRingBufferFlag);
1763         int flags = 0;
1764         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) {
1765             flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES;
1766         }
1767         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) {
1768             flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES;
1769         }
1770         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) {
1771             flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES;
1772         }
1773         if (checkoff.value != 0) {
1774             throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value);
1775         }
1776         return flags;
1777     }
1778 
1779     /**
1780      * Creates array of RingBufferStatus from the Hal version
1781      */
makeRingBufferStatusArray( ArrayList<WifiDebugRingBufferStatus> ringBuffers)1782     private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray(
1783             ArrayList<WifiDebugRingBufferStatus> ringBuffers) {
1784         WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()];
1785         int i = 0;
1786         for (WifiDebugRingBufferStatus b : ringBuffers) {
1787             ans[i++] = ringBufferStatus(b);
1788         }
1789         return ans;
1790     }
1791 
1792     /**
1793      * API to get the status of all ring buffers supported by driver
1794      */
getRingBufferStatus()1795     public WifiNative.RingBufferStatus[] getRingBufferStatus() {
1796         class AnswerBox {
1797             public WifiNative.RingBufferStatus[] value = null;
1798         }
1799         AnswerBox ans = new AnswerBox();
1800         synchronized (sLock) {
1801             if (mIWifiChip == null) return null;
1802             try {
1803                 mIWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> {
1804                     if (!ok(status)) return;
1805                     ans.value = makeRingBufferStatusArray(ringBuffers);
1806                 });
1807             } catch (RemoteException e) {
1808                 handleRemoteException(e);
1809                 return null;
1810             }
1811         }
1812         return ans.value;
1813     }
1814 
1815     /**
1816      * Indicates to driver that all the data has to be uploaded urgently
1817      */
getRingBufferData(String ringName)1818     public boolean getRingBufferData(String ringName) {
1819         enter("ringName %").c(ringName).flush();
1820         synchronized (sLock) {
1821             if (mIWifiChip == null) return boolResult(false);
1822             try {
1823                 WifiStatus status = mIWifiChip.forceDumpToDebugRingBuffer(ringName);
1824                 return ok(status);
1825             } catch (RemoteException e) {
1826                 handleRemoteException(e);
1827                 return false;
1828             }
1829         }
1830     }
1831 
1832     /**
1833      * Request vendor debug info from the firmware
1834      */
getFwMemoryDump()1835     public byte[] getFwMemoryDump() {
1836         class AnswerBox {
1837             public byte[] value;
1838         }
1839         AnswerBox ans = new AnswerBox();
1840         synchronized (sLock) {
1841             if (mIWifiChip == null) return (null);
1842             try {
1843                 mIWifiChip.requestFirmwareDebugDump((status, blob) -> {
1844                     if (!ok(status)) return;
1845                     ans.value = NativeUtil.byteArrayFromArrayList(blob);
1846                 });
1847             } catch (RemoteException e) {
1848                 handleRemoteException(e);
1849                 return null;
1850             }
1851         }
1852         return ans.value;
1853     }
1854 
1855     /**
1856      * Request vendor debug info from the driver
1857      */
getDriverStateDump()1858     public byte[] getDriverStateDump() {
1859         class AnswerBox {
1860             public byte[] value;
1861         }
1862         AnswerBox ans = new AnswerBox();
1863         synchronized (sLock) {
1864             if (mIWifiChip == null) return (null);
1865             try {
1866                 mIWifiChip.requestDriverDebugDump((status, blob) -> {
1867                     if (!ok(status)) return;
1868                     ans.value = NativeUtil.byteArrayFromArrayList(blob);
1869                 });
1870             } catch (RemoteException e) {
1871                 handleRemoteException(e);
1872                 return null;
1873             }
1874         }
1875         return ans.value;
1876     }
1877 
1878     /**
1879      * Start packet fate monitoring
1880      * <p>
1881      * Once started, monitoring remains active until HAL is unloaded.
1882      *
1883      * @return true for success
1884      */
startPktFateMonitoring()1885     public boolean startPktFateMonitoring() {
1886         synchronized (sLock) {
1887             if (mIWifiStaIface == null) return boolResult(false);
1888             try {
1889                 WifiStatus status = mIWifiStaIface.startDebugPacketFateMonitoring();
1890                 return ok(status);
1891             } catch (RemoteException e) {
1892                 handleRemoteException(e);
1893                 return false;
1894             }
1895         }
1896     }
1897 
halToFrameworkPktFateFrameType(int type)1898     private byte halToFrameworkPktFateFrameType(int type) {
1899         switch (type) {
1900             case WifiDebugPacketFateFrameType.UNKNOWN:
1901                 return WifiLoggerHal.FRAME_TYPE_UNKNOWN;
1902             case WifiDebugPacketFateFrameType.ETHERNET_II:
1903                 return WifiLoggerHal.FRAME_TYPE_ETHERNET_II;
1904             case WifiDebugPacketFateFrameType.MGMT_80211:
1905                 return WifiLoggerHal.FRAME_TYPE_80211_MGMT;
1906             default:
1907                 throw new IllegalArgumentException("bad " + type);
1908         }
1909     }
1910 
halToFrameworkRxPktFate(int type)1911     private byte halToFrameworkRxPktFate(int type) {
1912         switch (type) {
1913             case WifiDebugRxPacketFate.SUCCESS:
1914                 return WifiLoggerHal.RX_PKT_FATE_SUCCESS;
1915             case WifiDebugRxPacketFate.FW_QUEUED:
1916                 return WifiLoggerHal.RX_PKT_FATE_FW_QUEUED;
1917             case WifiDebugRxPacketFate.FW_DROP_FILTER:
1918                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER;
1919             case WifiDebugRxPacketFate.FW_DROP_INVALID:
1920                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID;
1921             case WifiDebugRxPacketFate.FW_DROP_NOBUFS:
1922                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS;
1923             case WifiDebugRxPacketFate.FW_DROP_OTHER:
1924                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER;
1925             case WifiDebugRxPacketFate.DRV_QUEUED:
1926                 return WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED;
1927             case WifiDebugRxPacketFate.DRV_DROP_FILTER:
1928                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER;
1929             case WifiDebugRxPacketFate.DRV_DROP_INVALID:
1930                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID;
1931             case WifiDebugRxPacketFate.DRV_DROP_NOBUFS:
1932                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS;
1933             case WifiDebugRxPacketFate.DRV_DROP_OTHER:
1934                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER;
1935             default:
1936                 throw new IllegalArgumentException("bad " + type);
1937         }
1938     }
1939 
halToFrameworkTxPktFate(int type)1940     private byte halToFrameworkTxPktFate(int type) {
1941         switch (type) {
1942             case WifiDebugTxPacketFate.ACKED:
1943                 return WifiLoggerHal.TX_PKT_FATE_ACKED;
1944             case WifiDebugTxPacketFate.SENT:
1945                 return WifiLoggerHal.TX_PKT_FATE_SENT;
1946             case WifiDebugTxPacketFate.FW_QUEUED:
1947                 return WifiLoggerHal.TX_PKT_FATE_FW_QUEUED;
1948             case WifiDebugTxPacketFate.FW_DROP_INVALID:
1949                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID;
1950             case WifiDebugTxPacketFate.FW_DROP_NOBUFS:
1951                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS;
1952             case WifiDebugTxPacketFate.FW_DROP_OTHER:
1953                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER;
1954             case WifiDebugTxPacketFate.DRV_QUEUED:
1955                 return WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED;
1956             case WifiDebugTxPacketFate.DRV_DROP_INVALID:
1957                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID;
1958             case WifiDebugTxPacketFate.DRV_DROP_NOBUFS:
1959                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS;
1960             case WifiDebugTxPacketFate.DRV_DROP_OTHER:
1961                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER;
1962             default:
1963                 throw new IllegalArgumentException("bad " + type);
1964         }
1965     }
1966 
1967     /**
1968      * Retrieve fates of outbound packets
1969      * <p>
1970      * Reports the outbound frames for the most recent association (space allowing).
1971      *
1972      * @param reportBufs
1973      * @return true for success
1974      */
getTxPktFates(WifiNative.TxFateReport[] reportBufs)1975     public boolean getTxPktFates(WifiNative.TxFateReport[] reportBufs) {
1976         if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
1977         synchronized (sLock) {
1978             if (mIWifiStaIface == null) return boolResult(false);
1979             try {
1980                 MutableBoolean ok = new MutableBoolean(false);
1981                 mIWifiStaIface.getDebugTxPacketFates((status, fates) -> {
1982                             if (!ok(status)) return;
1983                             int i = 0;
1984                             for (WifiDebugTxPacketFateReport fate : fates) {
1985                                 if (i >= reportBufs.length) break;
1986                                 byte code = halToFrameworkTxPktFate(fate.fate);
1987                                 long us = fate.frameInfo.driverTimestampUsec;
1988                                 byte type =
1989                                         halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
1990                                 byte[] frame =
1991                                         NativeUtil.byteArrayFromArrayList(
1992                                                 fate.frameInfo.frameContent);
1993                                 reportBufs[i++] =
1994                                         new WifiNative.TxFateReport(code, us, type, frame);
1995                             }
1996                             ok.value = true;
1997                         }
1998                 );
1999                 return ok.value;
2000             } catch (RemoteException e) {
2001                 handleRemoteException(e);
2002                 return false;
2003             }
2004         }
2005     }
2006 
2007     /**
2008      * Retrieve fates of inbound packets
2009      * <p>
2010      * Reports the inbound frames for the most recent association (space allowing).
2011      *
2012      * @param reportBufs
2013      * @return true for success
2014      */
getRxPktFates(WifiNative.RxFateReport[] reportBufs)2015     public boolean getRxPktFates(WifiNative.RxFateReport[] reportBufs) {
2016         if (ArrayUtils.isEmpty(reportBufs)) return boolResult(false);
2017         synchronized (sLock) {
2018             if (mIWifiStaIface == null) return boolResult(false);
2019             try {
2020                 MutableBoolean ok = new MutableBoolean(false);
2021                 mIWifiStaIface.getDebugRxPacketFates((status, fates) -> {
2022                             if (!ok(status)) return;
2023                             int i = 0;
2024                             for (WifiDebugRxPacketFateReport fate : fates) {
2025                                 if (i >= reportBufs.length) break;
2026                                 byte code = halToFrameworkRxPktFate(fate.fate);
2027                                 long us = fate.frameInfo.driverTimestampUsec;
2028                                 byte type =
2029                                         halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
2030                                 byte[] frame =
2031                                         NativeUtil.byteArrayFromArrayList(
2032                                                 fate.frameInfo.frameContent);
2033                                 reportBufs[i++] =
2034                                         new WifiNative.RxFateReport(code, us, type, frame);
2035                             }
2036                             ok.value = true;
2037                         }
2038                 );
2039                 return ok.value;
2040             } catch (RemoteException e) {
2041                 handleRemoteException(e);
2042                 return false;
2043             }
2044         }
2045     }
2046 
2047     /**
2048      * Start sending the specified keep alive packets periodically.
2049      *
2050      * @param slot
2051      * @param srcMac
2052      * @param keepAlivePacket
2053      * @param periodInMs
2054      * @return 0 for success, -1 for error
2055      */
startSendingOffloadedPacket( int slot, byte[] srcMac, KeepalivePacketData keepAlivePacket, int periodInMs)2056     public int startSendingOffloadedPacket(
2057             int slot, byte[] srcMac, KeepalivePacketData keepAlivePacket, int periodInMs) {
2058         enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush();
2059 
2060         ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(keepAlivePacket.data);
2061         short protocol = (short) (keepAlivePacket.protocol);
2062 
2063         synchronized (sLock) {
2064             if (mIWifiStaIface == null) return -1;
2065             try {
2066                 WifiStatus status = mIWifiStaIface.startSendingKeepAlivePackets(
2067                         slot,
2068                         data,
2069                         protocol,
2070                         srcMac,
2071                         keepAlivePacket.dstMac,
2072                         periodInMs);
2073                 if (!ok(status)) return -1;
2074                 return 0;
2075             } catch (RemoteException e) {
2076                 handleRemoteException(e);
2077                 return -1;
2078             }
2079         }
2080     }
2081 
2082     /**
2083      * Stop sending the specified keep alive packets.
2084      *
2085      * @param slot id - same as startSendingOffloadedPacket call.
2086      * @return 0 for success, -1 for error
2087      */
stopSendingOffloadedPacket(int slot)2088     public int stopSendingOffloadedPacket(int slot) {
2089         enter("slot=%").c(slot).flush();
2090 
2091         synchronized (sLock) {
2092             if (mIWifiStaIface == null) return -1;
2093             try {
2094                 WifiStatus status = mIWifiStaIface.stopSendingKeepAlivePackets(slot);
2095                 if (!ok(status)) return -1;
2096                 return 0;
2097             } catch (RemoteException e) {
2098                 handleRemoteException(e);
2099                 return -1;
2100             }
2101         }
2102     }
2103 
2104     /**
2105      * A fixed cmdId for our RssiMonitoring (we only do one at a time)
2106      */
2107     @VisibleForTesting
2108     static final int sRssiMonCmdId = 7551;
2109 
2110     /**
2111      * Our client's handler
2112      */
2113     private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler;
2114 
2115     /**
2116      * Start RSSI monitoring on the currently connected access point.
2117      *
2118      * @param maxRssi          Maximum RSSI threshold.
2119      * @param minRssi          Minimum RSSI threshold.
2120      * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
2121      * @return 0 for success, -1 for failure
2122      */
startRssiMonitoring(byte maxRssi, byte minRssi, WifiNative.WifiRssiEventHandler rssiEventHandler)2123     public int startRssiMonitoring(byte maxRssi, byte minRssi,
2124                                    WifiNative.WifiRssiEventHandler rssiEventHandler) {
2125         enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush();
2126         if (maxRssi <= minRssi) return -1;
2127         if (rssiEventHandler == null) return -1;
2128         synchronized (sLock) {
2129             if (mIWifiStaIface == null) return -1;
2130             try {
2131                 mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
2132                 WifiStatus status;
2133                 status = mIWifiStaIface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi);
2134                 if (!ok(status)) return -1;
2135                 mWifiRssiEventHandler = rssiEventHandler;
2136                 return 0;
2137             } catch (RemoteException e) {
2138                 handleRemoteException(e);
2139                 return -1;
2140             }
2141         }
2142     }
2143 
2144     /**
2145      * Stop RSSI monitoring
2146      *
2147      * @return 0 for success, -1 for failure
2148      */
stopRssiMonitoring()2149     public int stopRssiMonitoring() {
2150         synchronized (sLock) {
2151             mWifiRssiEventHandler = null;
2152             if (mIWifiStaIface == null) return -1;
2153             try {
2154                 mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
2155                 WifiStatus status = mIWifiStaIface.stopRssiMonitoring(sRssiMonCmdId);
2156                 if (!ok(status)) return -1;
2157                 return 0;
2158             } catch (RemoteException e) {
2159                 handleRemoteException(e);
2160                 return -1;
2161             }
2162         }
2163     }
2164 
2165     //TODO - belongs in NativeUtil
intsFromArrayList(ArrayList<Integer> a)2166     private static int[] intsFromArrayList(ArrayList<Integer> a) {
2167         if (a == null) return null;
2168         int[] b = new int[a.size()];
2169         int i = 0;
2170         for (Integer e : a) b[i++] = e;
2171         return b;
2172     }
2173 
2174     /**
2175      * Translates from Hal version of wake reason stats to the framework version of same
2176      *
2177      * @param h - Hal version of wake reason stats
2178      * @return framework version of same
2179      */
halToFrameworkWakeReasons( WifiDebugHostWakeReasonStats h)2180     private static WifiWakeReasonAndCounts halToFrameworkWakeReasons(
2181             WifiDebugHostWakeReasonStats h) {
2182         if (h == null) return null;
2183         WifiWakeReasonAndCounts ans = new WifiWakeReasonAndCounts();
2184         ans.totalCmdEventWake = h.totalCmdEventWakeCnt;
2185         ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt;
2186         ans.totalRxDataWake = h.totalRxPacketWakeCnt;
2187         ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt;
2188         ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt;
2189         ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt;
2190         ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt;
2191         ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt;
2192         ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra;
2193         ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na;
2194         ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns;
2195         ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt;
2196         ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt;
2197         ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt;
2198         ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType);
2199         ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType);
2200         return ans;
2201     }
2202 
2203     /**
2204      * Fetch the host wakeup reasons stats from wlan driver.
2205      *
2206      * @return the |WifiWakeReasonAndCounts| from the wlan driver, or null on failure.
2207      */
getWlanWakeReasonCount()2208     public WifiWakeReasonAndCounts getWlanWakeReasonCount() {
2209         class AnswerBox {
2210             public WifiDebugHostWakeReasonStats value = null;
2211         }
2212         AnswerBox ans = new AnswerBox();
2213         synchronized (sLock) {
2214             if (mIWifiChip == null) return null;
2215             try {
2216                 mIWifiChip.getDebugHostWakeReasonStats((status, stats) -> {
2217                     if (ok(status)) {
2218                         ans.value = stats;
2219                     }
2220                 });
2221                 return halToFrameworkWakeReasons(ans.value);
2222             } catch (RemoteException e) {
2223                 handleRemoteException(e);
2224                 return null;
2225             }
2226         }
2227     }
2228 
2229     /**
2230      * Enable/Disable Neighbour discovery offload functionality in the firmware.
2231      *
2232      * @param enabled true to enable, false to disable.
2233      */
configureNeighborDiscoveryOffload(boolean enabled)2234     public boolean configureNeighborDiscoveryOffload(boolean enabled) {
2235         enter("enabled=%").c(enabled).flush();
2236         synchronized (sLock) {
2237             if (mIWifiStaIface == null) return boolResult(false);
2238             try {
2239                 WifiStatus status = mIWifiStaIface.enableNdOffload(enabled);
2240                 if (!ok(status)) return false;
2241             } catch (RemoteException e) {
2242                 handleRemoteException(e);
2243                 return false;
2244             }
2245         }
2246         return true;
2247     }
2248 
2249     // Firmware roaming control.
2250 
2251     /**
2252      * Query the firmware roaming capabilities.
2253      *
2254      * @param capabilities object to be filled in
2255      * @return true for success; false for failure
2256      */
getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities)2257     public boolean getRoamingCapabilities(WifiNative.RoamingCapabilities capabilities) {
2258         synchronized (sLock) {
2259             if (mIWifiStaIface == null) return boolResult(false);
2260             try {
2261                 MutableBoolean ok = new MutableBoolean(false);
2262                 WifiNative.RoamingCapabilities out = capabilities;
2263                 mIWifiStaIface.getRoamingCapabilities((status, cap) -> {
2264                     if (!ok(status)) return;
2265                     out.maxBlacklistSize = cap.maxBlacklistSize;
2266                     out.maxWhitelistSize = cap.maxWhitelistSize;
2267                     ok.value = true;
2268                 });
2269                 return ok.value;
2270             } catch (RemoteException e) {
2271                 handleRemoteException(e);
2272                 return false;
2273             }
2274         }
2275     }
2276 
2277     /**
2278      * Enable/disable firmware roaming.
2279      *
2280      * @param state the intended roaming state
2281      * @return SUCCESS, FAILURE, or BUSY
2282      */
enableFirmwareRoaming(int state)2283     public int enableFirmwareRoaming(int state) {
2284         synchronized (sLock) {
2285             if (mIWifiStaIface == null) return WifiStatusCode.ERROR_NOT_STARTED;
2286             try {
2287                 byte val;
2288                 switch (state) {
2289                     case WifiNative.DISABLE_FIRMWARE_ROAMING:
2290                         val = StaRoamingState.DISABLED;
2291                         break;
2292                     case WifiNative.ENABLE_FIRMWARE_ROAMING:
2293                         val = StaRoamingState.ENABLED;
2294                         break;
2295                     default:
2296                         mLog.e("enableFirmwareRoaming invalid argument " + state);
2297                         return WifiStatusCode.ERROR_INVALID_ARGS;
2298                 }
2299 
2300                 WifiStatus status = mIWifiStaIface.setRoamingState(val);
2301                 mVerboseLog.d("setRoamingState returned " + status.code);
2302                 return status.code;
2303             } catch (RemoteException e) {
2304                 handleRemoteException(e);
2305                 return WifiStatusCode.ERROR_UNKNOWN;
2306             }
2307         }
2308     }
2309 
2310     /**
2311      * Set firmware roaming configurations.
2312      *
2313      * @param config new roaming configuration object
2314      * @return true for success; false for failure
2315      */
configureRoaming(WifiNative.RoamingConfig config)2316     public boolean configureRoaming(WifiNative.RoamingConfig config) {
2317         synchronized (sLock) {
2318             if (mIWifiStaIface == null) return boolResult(false);
2319             try {
2320                 StaRoamingConfig roamingConfig = new StaRoamingConfig();
2321 
2322                 // parse the blacklist BSSIDs if any
2323                 if (config.blacklistBssids != null) {
2324                     for (String bssid : config.blacklistBssids) {
2325                         byte[] mac = NativeUtil.macAddressToByteArray(bssid);
2326                         roamingConfig.bssidBlacklist.add(mac);
2327                     }
2328                 }
2329 
2330                 // parse the whitelist SSIDs if any
2331                 if (config.whitelistSsids != null) {
2332                     for (String ssidStr : config.whitelistSsids) {
2333                         String unquotedSsidStr = WifiInfo.removeDoubleQuotes(ssidStr);
2334 
2335                         int len = unquotedSsidStr.length();
2336                         if (len > 32) {
2337                             mLog.err("configureRoaming: skip invalid SSID %")
2338                                     .r(unquotedSsidStr).flush();
2339                             continue;
2340                         }
2341                         byte[] ssid = new byte[len];
2342                         for (int i = 0; i < len; i++) {
2343                             ssid[i] = (byte) unquotedSsidStr.charAt(i);
2344                         }
2345                         roamingConfig.ssidWhitelist.add(ssid);
2346                     }
2347                 }
2348 
2349                 WifiStatus status = mIWifiStaIface.configureRoaming(roamingConfig);
2350                 if (!ok(status)) return false;
2351             } catch (RemoteException e) {
2352                 handleRemoteException(e);
2353                 return false;
2354             } catch (IllegalArgumentException e) {
2355                 mLog.err("Illegal argument for roaming configuration").c(e.toString()).flush();
2356                 return false;
2357             }
2358             return true;
2359         }
2360     }
2361 
2362     /**
2363      * Method to mock out the V1_1 IWifiChip retrieval in unit tests.
2364      *
2365      * @return 1.1 IWifiChip object if the device is running the 1.1 wifi hal service, null
2366      * otherwise.
2367      */
getWifiChipForV1_1Mockable()2368     protected android.hardware.wifi.V1_1.IWifiChip getWifiChipForV1_1Mockable() {
2369         if (mIWifiChip == null) return null;
2370         return android.hardware.wifi.V1_1.IWifiChip.castFrom(mIWifiChip);
2371     }
2372 
frameworkToHalTxPowerScenario(int scenario)2373     private int frameworkToHalTxPowerScenario(int scenario) {
2374         switch (scenario) {
2375             case WifiNative.TX_POWER_SCENARIO_VOICE_CALL:
2376                 return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL;
2377             default:
2378                 throw new IllegalArgumentException("bad scenario: " + scenario);
2379         }
2380     }
2381 
2382     /**
2383      * Select one of the pre-configured TX power level scenarios or reset it back to normal.
2384      * Primarily used for meeting SAR requirements during voice calls.
2385      *
2386      * @param scenario Should be one {@link WifiNative#TX_POWER_SCENARIO_NORMAL} or
2387      *        {@link WifiNative#TX_POWER_SCENARIO_VOICE_CALL}.
2388      * @return true for success; false for failure or if the HAL version does not support this API.
2389      */
selectTxPowerScenario(int scenario)2390     public boolean selectTxPowerScenario(int scenario) {
2391         synchronized (sLock) {
2392             try {
2393                 android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable();
2394                 if (iWifiChipV11 == null) return boolResult(false);
2395                 WifiStatus status;
2396                 if (scenario != WifiNative.TX_POWER_SCENARIO_NORMAL) {
2397                     int halScenario;
2398                     try {
2399                         halScenario = frameworkToHalTxPowerScenario(scenario);
2400                     } catch (IllegalArgumentException e) {
2401                         mLog.err("Illegal argument for select tx power scenario")
2402                                 .c(e.toString()).flush();
2403                         return false;
2404                     }
2405                     status = iWifiChipV11.selectTxPowerScenario(halScenario);
2406                 } else {
2407                     status = iWifiChipV11.resetTxPowerScenario();
2408                 }
2409                 if (!ok(status)) return false;
2410             } catch (RemoteException e) {
2411                 handleRemoteException(e);
2412                 return false;
2413             }
2414             return true;
2415         }
2416     }
2417 
2418     // This creates a blob of IE elements from the array received.
2419     // TODO: This ugly conversion can be removed if we put IE elements in ScanResult.
hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies)2420     private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) {
2421         if (ies == null || ies.isEmpty()) return new byte[0];
2422         ArrayList<Byte> ieBlob = new ArrayList<>();
2423         for (WifiInformationElement ie : ies) {
2424             ieBlob.add(ie.id);
2425             ieBlob.addAll(ie.data);
2426         }
2427         return NativeUtil.byteArrayFromArrayList(ieBlob);
2428     }
2429 
2430     // This is only filling up the fields of Scan Result used by Gscan clients.
hidlToFrameworkScanResult(StaScanResult scanResult)2431     private static ScanResult hidlToFrameworkScanResult(StaScanResult scanResult) {
2432         if (scanResult == null) return null;
2433         ScanResult frameworkScanResult = new ScanResult();
2434         frameworkScanResult.SSID = NativeUtil.encodeSsid(scanResult.ssid);
2435         frameworkScanResult.wifiSsid =
2436                 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(scanResult.ssid));
2437         frameworkScanResult.BSSID = NativeUtil.macAddressFromByteArray(scanResult.bssid);
2438         frameworkScanResult.level = scanResult.rssi;
2439         frameworkScanResult.frequency = scanResult.frequency;
2440         frameworkScanResult.timestamp = scanResult.timeStampInUs;
2441         frameworkScanResult.bytes = hidlIeArrayToFrameworkIeBlob(scanResult.informationElements);
2442         return frameworkScanResult;
2443     }
2444 
hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults)2445     private static ScanResult[] hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults) {
2446         if (scanResults == null || scanResults.isEmpty()) return new ScanResult[0];
2447         ScanResult[] frameworkScanResults = new ScanResult[scanResults.size()];
2448         int i = 0;
2449         for (StaScanResult scanResult : scanResults) {
2450             frameworkScanResults[i++] = hidlToFrameworkScanResult(scanResult);
2451         }
2452         return frameworkScanResults;
2453     }
2454 
2455     /**
2456      * This just returns whether the scan was interrupted or not.
2457      */
hidlToFrameworkScanDataFlags(int flag)2458     private static int hidlToFrameworkScanDataFlags(int flag) {
2459         if (flag == StaScanDataFlagMask.INTERRUPTED) {
2460             return 1;
2461         } else {
2462             return 0;
2463         }
2464     }
2465 
hidlToFrameworkScanDatas( int cmdId, ArrayList<StaScanData> scanDatas)2466     private static WifiScanner.ScanData[] hidlToFrameworkScanDatas(
2467             int cmdId, ArrayList<StaScanData> scanDatas) {
2468         if (scanDatas == null || scanDatas.isEmpty()) return new WifiScanner.ScanData[0];
2469         WifiScanner.ScanData[] frameworkScanDatas = new WifiScanner.ScanData[scanDatas.size()];
2470         int i = 0;
2471         for (StaScanData scanData : scanDatas) {
2472             int flags = hidlToFrameworkScanDataFlags(scanData.flags);
2473             ScanResult[] frameworkScanResults = hidlToFrameworkScanResults(scanData.results);
2474             frameworkScanDatas[i++] =
2475                     new WifiScanner.ScanData(cmdId, flags, scanData.bucketsScanned, false,
2476                             frameworkScanResults);
2477         }
2478         return frameworkScanDatas;
2479     }
2480 
2481     /**
2482      * Callback for events on the STA interface.
2483      */
2484     private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
2485         @Override
onBackgroundScanFailure(int cmdId)2486         public void onBackgroundScanFailure(int cmdId) {
2487             mVerboseLog.d("onBackgroundScanFailure " + cmdId);
2488             WifiNative.ScanEventHandler eventHandler;
2489             synchronized (sLock) {
2490                 if (mScan == null || cmdId != mScan.cmdId) return;
2491                 eventHandler = mScan.eventHandler;
2492             }
2493             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
2494         }
2495 
2496         @Override
onBackgroundFullScanResult( int cmdId, int bucketsScanned, StaScanResult result)2497         public void onBackgroundFullScanResult(
2498                 int cmdId, int bucketsScanned, StaScanResult result) {
2499             mVerboseLog.d("onBackgroundFullScanResult " + cmdId);
2500             WifiNative.ScanEventHandler eventHandler;
2501             synchronized (sLock) {
2502                 if (mScan == null || cmdId != mScan.cmdId) return;
2503                 eventHandler = mScan.eventHandler;
2504             }
2505             eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), bucketsScanned);
2506         }
2507 
2508         @Override
onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas)2509         public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
2510             mVerboseLog.d("onBackgroundScanResults " + cmdId);
2511             WifiNative.ScanEventHandler eventHandler;
2512             // WifiScanner currently uses the results callback to fetch the scan results.
2513             // So, simulate that by sending out the notification and then caching the results
2514             // locally. This will then be returned to WifiScanner via getScanResults.
2515             synchronized (sLock) {
2516                 if (mScan == null || cmdId != mScan.cmdId) return;
2517                 eventHandler = mScan.eventHandler;
2518                 mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
2519             }
2520             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
2521         }
2522 
2523         @Override
onRssiThresholdBreached(int cmdId, byte[ ] currBssid, int currRssi)2524         public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
2525             mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
2526             WifiNative.WifiRssiEventHandler eventHandler;
2527             synchronized (sLock) {
2528                 if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return;
2529                 eventHandler = mWifiRssiEventHandler;
2530             }
2531             eventHandler.onRssiThresholdBreached((byte) currRssi);
2532         }
2533     }
2534 
2535     /**
2536      * Callback for events on the STA interface.
2537      */
2538     private class ChipEventCallback extends IWifiChipEventCallback.Stub {
2539         @Override
onChipReconfigured(int modeId)2540         public void onChipReconfigured(int modeId) {
2541             mVerboseLog.d("onChipReconfigured " + modeId);
2542         }
2543 
2544         @Override
onChipReconfigureFailure(WifiStatus status)2545         public void onChipReconfigureFailure(WifiStatus status) {
2546             mVerboseLog.d("onChipReconfigureFailure " + status);
2547         }
2548 
onIfaceAdded(int type, String name)2549         public void onIfaceAdded(int type, String name) {
2550             mVerboseLog.d("onIfaceAdded " + type + ", name: " + name);
2551         }
2552 
2553         @Override
onIfaceRemoved(int type, String name)2554         public void onIfaceRemoved(int type, String name) {
2555             mVerboseLog.d("onIfaceRemoved " + type + ", name: " + name);
2556         }
2557 
2558         @Override
onDebugRingBufferDataAvailable( WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data)2559         public void onDebugRingBufferDataAvailable(
2560                 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
2561             //TODO(b/35875078) Reinstate logging when execessive callbacks are fixed
2562             // mVerboseLog.d("onDebugRingBufferDataAvailable " + status);
2563             mHalEventHandler.post(() -> {
2564                 WifiNative.WifiLoggerEventHandler eventHandler;
2565                 synchronized (sLock) {
2566                     if (mLogEventHandler == null || status == null || data == null) return;
2567                     eventHandler = mLogEventHandler;
2568                 }
2569                 // Because |sLock| has been released, there is a chance that we'll execute
2570                 // a spurious callback (after someone has called resetLogHandler()).
2571                 //
2572                 // However, the alternative risks deadlock. Consider:
2573                 // [T1.1] WifiDiagnostics.captureBugReport()
2574                 // [T1.2] -- acquire WifiDiagnostics object's intrinsic lock
2575                 // [T1.3]    -> WifiVendorHal.getRingBufferData()
2576                 // [T1.4]       -- acquire WifiVendorHal.sLock
2577                 // [T2.1] <lambda>()
2578                 // [T2.2] -- acquire WifiVendorHal.sLock
2579                 // [T2.3]    -> WifiDiagnostics.onRingBufferData()
2580                 // [T2.4]       -- acquire WifiDiagnostics object's intrinsic lock
2581                 //
2582                 // The problem here is that the two threads acquire the locks in opposite order.
2583                 // If, for example, T2.2 executes between T1.2 and 1.4, then T1 and T2
2584                 // will be deadlocked.
2585                 eventHandler.onRingBufferData(
2586                         ringBufferStatus(status), NativeUtil.byteArrayFromArrayList(data));
2587             });
2588         }
2589 
2590         @Override
onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData)2591         public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
2592             mVerboseLog.d("onDebugErrorAlert " + errorCode);
2593             mHalEventHandler.post(() -> {
2594                 WifiNative.WifiLoggerEventHandler eventHandler;
2595                 synchronized (sLock) {
2596                     if (mLogEventHandler == null || debugData == null) return;
2597                     eventHandler = mLogEventHandler;
2598                 }
2599                 // See comment in onDebugRingBufferDataAvailable(), for an explanation
2600                 // of why this callback is invoked without |sLock| held.
2601                 eventHandler.onWifiAlert(
2602                         errorCode, NativeUtil.byteArrayFromArrayList(debugData));
2603             });
2604         }
2605     }
2606 
2607     /**
2608      * Hal Device Manager callbacks.
2609      */
2610     public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
2611         @Override
onStatusChanged()2612         public void onStatusChanged() {
2613             boolean isReady = mHalDeviceManager.isReady();
2614             boolean isStarted = mHalDeviceManager.isStarted();
2615 
2616             mVerboseLog.i("Device Manager onStatusChanged. isReady(): " + isReady
2617                     + ", isStarted(): " + isStarted);
2618             if (!isReady) {
2619                 // Probably something unpleasant, e.g. the server died
2620                 WifiNative.VendorHalDeathEventHandler handler;
2621                 synchronized (sLock) {
2622                     clearState();
2623                     handler = mDeathEventHandler;
2624                 }
2625                 if (handler != null) {
2626                     handler.onDeath();
2627                 }
2628             }
2629         }
2630     }
2631 }
2632