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