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