• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.wifi;
17 
18 import static android.net.wifi.CoexUnsafeChannel.POWER_CAP_NONE;
19 
20 import android.annotation.NonNull;
21 import android.annotation.Nullable;
22 import android.content.Context;
23 import android.content.pm.PackageManager;
24 import android.hardware.wifi.V1_0.IWifiApIface;
25 import android.hardware.wifi.V1_0.IWifiChip;
26 import android.hardware.wifi.V1_0.IWifiChipEventCallback;
27 import android.hardware.wifi.V1_0.IWifiIface;
28 import android.hardware.wifi.V1_0.IWifiStaIface;
29 import android.hardware.wifi.V1_0.IWifiStaIfaceEventCallback;
30 import android.hardware.wifi.V1_0.IfaceType;
31 import android.hardware.wifi.V1_0.StaBackgroundScanBucketEventReportSchemeMask;
32 import android.hardware.wifi.V1_0.StaBackgroundScanBucketParameters;
33 import android.hardware.wifi.V1_0.StaBackgroundScanParameters;
34 import android.hardware.wifi.V1_0.StaLinkLayerIfaceStats;
35 import android.hardware.wifi.V1_0.StaLinkLayerRadioStats;
36 import android.hardware.wifi.V1_0.StaLinkLayerStats;
37 import android.hardware.wifi.V1_0.StaRoamingConfig;
38 import android.hardware.wifi.V1_0.StaRoamingState;
39 import android.hardware.wifi.V1_0.StaScanData;
40 import android.hardware.wifi.V1_0.StaScanDataFlagMask;
41 import android.hardware.wifi.V1_0.StaScanResult;
42 import android.hardware.wifi.V1_0.WifiDebugHostWakeReasonStats;
43 import android.hardware.wifi.V1_0.WifiDebugPacketFateFrameType;
44 import android.hardware.wifi.V1_0.WifiDebugRingBufferFlags;
45 import android.hardware.wifi.V1_0.WifiDebugRingBufferStatus;
46 import android.hardware.wifi.V1_0.WifiDebugRxPacketFate;
47 import android.hardware.wifi.V1_0.WifiDebugRxPacketFateReport;
48 import android.hardware.wifi.V1_0.WifiDebugTxPacketFate;
49 import android.hardware.wifi.V1_0.WifiDebugTxPacketFateReport;
50 import android.hardware.wifi.V1_0.WifiInformationElement;
51 import android.hardware.wifi.V1_0.WifiStatus;
52 import android.hardware.wifi.V1_0.WifiStatusCode;
53 import android.hardware.wifi.V1_2.IWifiChipEventCallback.IfaceInfo;
54 import android.hardware.wifi.V1_5.IWifiChip.MultiStaUseCase;
55 import android.hardware.wifi.V1_5.IWifiChip.UsableChannelFilter;
56 import android.hardware.wifi.V1_5.StaPeerInfo;
57 import android.hardware.wifi.V1_5.StaRateStat;
58 import android.hardware.wifi.V1_5.WifiBand;
59 import android.hardware.wifi.V1_5.WifiIfaceMode;
60 import android.hardware.wifi.V1_5.WifiUsableChannel;
61 import android.net.MacAddress;
62 import android.net.apf.ApfCapabilities;
63 import android.net.wifi.ScanResult;
64 import android.net.wifi.SoftApConfiguration;
65 import android.net.wifi.WifiAvailableChannel;
66 import android.net.wifi.WifiManager;
67 import android.net.wifi.WifiScanner;
68 import android.net.wifi.WifiSsid;
69 import android.os.Handler;
70 import android.os.RemoteException;
71 import android.os.WorkSource;
72 import android.text.TextUtils;
73 import android.util.Log;
74 import android.util.Pair;
75 import android.util.SparseArray;
76 
77 import com.android.internal.annotations.VisibleForTesting;
78 import com.android.internal.util.HexDump;
79 import com.android.modules.utils.build.SdkLevel;
80 import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener;
81 import com.android.server.wifi.WifiLinkLayerStats.ChannelStats;
82 import com.android.server.wifi.WifiLinkLayerStats.PeerInfo;
83 import com.android.server.wifi.WifiLinkLayerStats.RadioStat;
84 import com.android.server.wifi.WifiLinkLayerStats.RateStat;
85 import com.android.server.wifi.WifiNative.RxFateReport;
86 import com.android.server.wifi.WifiNative.TxFateReport;
87 import com.android.server.wifi.util.BitMask;
88 import com.android.server.wifi.util.GeneralUtil.Mutable;
89 import com.android.server.wifi.util.NativeUtil;
90 import com.android.wifi.resources.R;
91 
92 import com.google.errorprone.annotations.CompileTimeConstant;
93 
94 import java.util.ArrayList;
95 import java.util.HashMap;
96 import java.util.List;
97 import java.util.Set;
98 import java.util.stream.Collectors;
99 
100 /**
101  * Vendor HAL via HIDL
102  */
103 public class WifiVendorHal {
104 
105     private static final WifiLog sNoLog = new FakeWifiLog();
106 
107     /**
108      * Chatty logging should use mVerboseLog
109      */
110     @VisibleForTesting
111     WifiLog mVerboseLog = sNoLog;
112 
113     /**
114      * Errors should use mLog
115      */
116     @VisibleForTesting
117     WifiLog mLog = new LogcatLog("WifiVendorHal");
118 
119     /**
120      * Enables or disables verbose logging
121      *
122      * @param verbose - with the obvious interpretation
123      */
enableVerboseLogging(boolean verbose)124     public void enableVerboseLogging(boolean verbose) {
125         synchronized (sLock) {
126             if (verbose) {
127                 mVerboseLog = mLog;
128                 enter("verbose=true").flush();
129             } else {
130                 enter("verbose=false").flush();
131                 mVerboseLog = sNoLog;
132             }
133         }
134     }
135 
136     /**
137      * Checks for a successful status result.
138      *
139      * Failures are logged to mLog.
140      *
141      * @param status is the WifiStatus generated by a hal call
142      * @return true for success, false for failure
143      */
ok(WifiStatus status)144     private boolean ok(WifiStatus status) {
145         if (status.code == WifiStatusCode.SUCCESS) return true;
146 
147         Thread cur = Thread.currentThread();
148         StackTraceElement[] trace = cur.getStackTrace();
149 
150         mLog.err("% failed %")
151                 .c(niceMethodName(trace, 3))
152                 .c(status.toString())
153                 .flush();
154 
155         return false;
156     }
157 
158     /**
159      * Logs the argument along with the method name.
160      *
161      * Always returns its argument.
162      */
boolResult(boolean result)163     private boolean boolResult(boolean result) {
164         if (mVerboseLog == sNoLog) return result;
165         // Currently only seen if verbose logging is on
166 
167         Thread cur = Thread.currentThread();
168         StackTraceElement[] trace = cur.getStackTrace();
169 
170         mVerboseLog.err("% returns %")
171                 .c(niceMethodName(trace, 3))
172                 .c(result)
173                 .flush();
174 
175         return result;
176     }
177 
objResult(T obj)178     private <T> T objResult(T obj) {
179         if (mVerboseLog == sNoLog) return obj;
180         // Currently only seen if verbose logging is on
181 
182         Thread cur = Thread.currentThread();
183         StackTraceElement[] trace = cur.getStackTrace();
184 
185         mVerboseLog.err("% returns %")
186                 .c(niceMethodName(trace, 3))
187                 .c(String.valueOf(obj))
188                 .flush();
189 
190         return obj;
191     }
192 
193     /**
194      * Logs the argument along with the method name.
195      *
196      * Always returns its argument.
197      */
nullResult()198     private <T> T nullResult() {
199         if (mVerboseLog == sNoLog) return null;
200         // Currently only seen if verbose logging is on
201 
202         Thread cur = Thread.currentThread();
203         StackTraceElement[] trace = cur.getStackTrace();
204 
205         mVerboseLog.err("% returns %")
206                 .c(niceMethodName(trace, 3))
207                 .c(null)
208                 .flush();
209 
210         return null;
211     }
212 
213     /**
214      * Logs the argument along with the method name.
215      *
216      * Always returns its argument.
217      */
byteArrayResult(byte[] result)218     private byte[] byteArrayResult(byte[] result) {
219         if (mVerboseLog == sNoLog) return result;
220         // Currently only seen if verbose logging is on
221 
222         Thread cur = Thread.currentThread();
223         StackTraceElement[] trace = cur.getStackTrace();
224 
225         mVerboseLog.err("% returns %")
226                 .c(niceMethodName(trace, 3))
227                 .c(result == null ? "(null)" : HexDump.dumpHexString(result))
228                 .flush();
229 
230         return result;
231     }
232 
233     /**
234      * Logs at method entry
235      *
236      * @param format string with % placeholders
237      * @return LogMessage formatter (remember to .flush())
238      */
enter(@ompileTimeConstant final String format)239     private WifiLog.LogMessage enter(@CompileTimeConstant final String format) {
240         if (mVerboseLog == sNoLog) return sNoLog.info(format);
241         return mVerboseLog.trace(format, 1);
242     }
243 
244     /**
245      * Gets the method name and line number from a stack trace.
246      *
247      * Attempts to skip frames created by lambdas to get a human-sensible name.
248      *
249      * @param trace, fo example obtained by Thread.currentThread().getStackTrace()
250      * @param start  frame number to log, typically 3
251      * @return string containing the method name and line number
252      */
niceMethodName(StackTraceElement[] trace, int start)253     private static String niceMethodName(StackTraceElement[] trace, int start) {
254         if (start >= trace.length) return "";
255         StackTraceElement s = trace[start];
256         String name = s.getMethodName();
257         if (name.contains("lambda$")) {
258             // Try to find a friendlier method name
259             String myFile = s.getFileName();
260             if (myFile != null) {
261                 for (int i = start + 1; i < trace.length; i++) {
262                     if (myFile.equals(trace[i].getFileName())) {
263                         name = trace[i].getMethodName();
264                         break;
265                     }
266                 }
267             }
268         }
269         return (name + "(l." + s.getLineNumber() + ")");
270     }
271 
272     // Vendor HAL HIDL interface objects.
273     private IWifiChip mIWifiChip;
274     private HashMap<String, IWifiStaIface> mIWifiStaIfaces = new HashMap<>();
275     private HashMap<String, IWifiApIface> mIWifiApIfaces = new HashMap<>();
276     private static Context sContext;
277     private final HalDeviceManager mHalDeviceManager;
278     private final WifiGlobals mWifiGlobals;
279     private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
280     private final IWifiStaIfaceEventCallback mIWifiStaIfaceEventCallback;
281     private final ChipEventCallback mIWifiChipEventCallback;
282     private final ChipEventCallbackV12 mIWifiChipEventCallbackV12;
283     private final ChipEventCallbackV14 mIWifiChipEventCallbackV14;
284 
285     // Plumbing for event handling.
286     //
287     // Being final fields, they can be accessed without synchronization under
288     // some reasonable assumptions. See
289     // https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5
290     private final Handler mHalEventHandler;
291 
WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler, WifiGlobals wifiGlobals)292     public WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler,
293             WifiGlobals wifiGlobals) {
294         sContext = context;
295         mHalDeviceManager = halDeviceManager;
296         mHalEventHandler = handler;
297         mWifiGlobals = wifiGlobals;
298         mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener();
299         mIWifiStaIfaceEventCallback = new StaIfaceEventCallback();
300         mIWifiChipEventCallback = new ChipEventCallback();
301         mIWifiChipEventCallbackV12 = new ChipEventCallbackV12();
302         mIWifiChipEventCallbackV14 = new ChipEventCallbackV14();
303     }
304 
305     public static final Object sLock = new Object();
306 
handleRemoteException(RemoteException e)307     private void handleRemoteException(RemoteException e) {
308         String methodName = niceMethodName(Thread.currentThread().getStackTrace(), 3);
309         mVerboseLog.err("% RemoteException in HIDL call %").c(methodName).c(e.toString()).flush();
310         // Recovery on HAL crash will be triggered by death listener.
311     }
312 
313     private WifiNative.VendorHalDeathEventHandler mDeathEventHandler;
314 
315     /**
316      * Initialize the Hal device manager and register for status callbacks.
317      *
318      * @param handler Handler to notify if the vendor HAL dies.
319      * @return true on success, false otherwise.
320      */
initialize(WifiNative.VendorHalDeathEventHandler handler)321     public boolean initialize(WifiNative.VendorHalDeathEventHandler handler) {
322         synchronized (sLock) {
323             mHalDeviceManager.initialize();
324             mHalDeviceManager.registerStatusListener(
325                     mHalDeviceManagerStatusCallbacks, mHalEventHandler);
326             mDeathEventHandler = handler;
327             return true;
328         }
329     }
330 
331     private WifiNative.VendorHalRadioModeChangeEventHandler mRadioModeChangeEventHandler;
332 
333     /**
334      * Register to listen for radio mode change events from the HAL.
335      *
336      * @param handler Handler to notify when the vendor HAL detects a radio mode change.
337      */
registerRadioModeChangeHandler( WifiNative.VendorHalRadioModeChangeEventHandler handler)338     public void registerRadioModeChangeHandler(
339             WifiNative.VendorHalRadioModeChangeEventHandler handler) {
340         synchronized (sLock) {
341             mRadioModeChangeEventHandler = handler;
342         }
343     }
344 
345     /**
346      * Register to listen for subsystem restart events from the HAL.
347      *
348      * @param listener SubsystemRestartListener listener object.
349      */
registerSubsystemRestartListener( HalDeviceManager.SubsystemRestartListener listener)350     public void registerSubsystemRestartListener(
351             HalDeviceManager.SubsystemRestartListener listener) {
352         mHalDeviceManager.registerSubsystemRestartListener(listener, mHalEventHandler);
353     }
354 
355     /**
356      * Returns whether the vendor HAL is supported on this device or not.
357      */
isVendorHalSupported()358     public boolean isVendorHalSupported() {
359         synchronized (sLock) {
360             return mHalDeviceManager.isSupported();
361         }
362     }
363 
364     /**
365      * Returns whether the vendor HAL is ready or not.
366      */
isVendorHalReady()367     public boolean isVendorHalReady() {
368         synchronized (sLock) {
369             return mHalDeviceManager.isReady();
370         }
371     }
372 
373     /**
374      * Bring up the HIDL Vendor HAL and configure for AP (Access Point) mode
375      *
376      * @return true for success
377      */
startVendorHalAp()378     public boolean startVendorHalAp() {
379         synchronized (sLock) {
380             if (!startVendorHal()) {
381                 return false;
382             }
383             if (TextUtils.isEmpty(createApIface(null, null,
384                     SoftApConfiguration.BAND_2GHZ, false))) {
385                 stopVendorHal();
386                 return false;
387             }
388             return true;
389         }
390     }
391 
392     /**
393      * Bring up the HIDL Vendor HAL and configure for STA (Station) mode
394      *
395      * @return true for success
396      */
startVendorHalSta()397     public boolean startVendorHalSta() {
398         synchronized (sLock) {
399             if (!startVendorHal()) {
400                 return false;
401             }
402             if (TextUtils.isEmpty(createStaIface(null, null))) {
403                 stopVendorHal();
404                 return false;
405             }
406             return true;
407         }
408     }
409 
410     /**
411      * Bring up the HIDL Vendor HAL.
412      * @return true on success, false otherwise.
413      */
startVendorHal()414     public boolean startVendorHal() {
415         synchronized (sLock) {
416             if (!mHalDeviceManager.start()) {
417                 mLog.err("Failed to start vendor HAL").flush();
418                 return false;
419             }
420             mLog.info("Vendor Hal started successfully").flush();
421             return true;
422         }
423     }
424 
425 
426     /** Helper method to lookup the corresponding STA iface object using iface name. */
getStaIface(@onNull String ifaceName)427     private IWifiStaIface getStaIface(@NonNull String ifaceName) {
428         synchronized (sLock) {
429             return mIWifiStaIfaces.get(ifaceName);
430         }
431     }
432 
433     private class StaInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener {
434         private final InterfaceDestroyedListener mExternalListener;
435 
StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)436         StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) {
437             mExternalListener = externalListener;
438         }
439 
440         @Override
onDestroyed(@onNull String ifaceName)441         public void onDestroyed(@NonNull String ifaceName) {
442             synchronized (sLock) {
443                 mIWifiStaIfaces.remove(ifaceName);
444             }
445             if (mExternalListener != null) {
446                 mExternalListener.onDestroyed(ifaceName);
447             }
448         }
449     }
450 
451     /**
452      * Create a STA iface using {@link HalDeviceManager}.
453      *
454      * @param destroyedListener Listener to be invoked when the interface is destroyed.
455      * @param requestorWs Requestor worksource.
456      * @return iface name on success, null otherwise.
457      */
createStaIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs)458     public String createStaIface(@Nullable InterfaceDestroyedListener destroyedListener,
459             @NonNull WorkSource requestorWs) {
460         synchronized (sLock) {
461             IWifiStaIface iface = mHalDeviceManager.createStaIface(
462                     new StaInterfaceDestroyedListenerInternal(destroyedListener), null,
463                     requestorWs);
464             if (iface == null) {
465                 mLog.err("Failed to create STA iface").flush();
466                 return nullResult();
467             }
468             String ifaceName = mHalDeviceManager.getName((IWifiIface) iface);
469             if (TextUtils.isEmpty(ifaceName)) {
470                 mLog.err("Failed to get iface name").flush();
471                 return nullResult();
472             }
473             if (!registerStaIfaceCallback(iface)) {
474                 mLog.err("Failed to register STA iface callback").flush();
475                 return nullResult();
476             }
477             if (!retrieveWifiChip((IWifiIface) iface)) {
478                 mLog.err("Failed to get wifi chip").flush();
479                 return nullResult();
480             }
481             enableLinkLayerStats(iface);
482             mIWifiStaIfaces.put(ifaceName, iface);
483             return ifaceName;
484         }
485     }
486 
487     /**
488      * Replace the requestor worksource info for a STA iface using {@link HalDeviceManager}.
489      *
490      * @param ifaceName Name of the interface being removed.
491      * @param requestorWs Requestor worksource.
492      * @return true on success, false otherwise.
493      */
replaceStaIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)494     public boolean replaceStaIfaceRequestorWs(@NonNull String ifaceName,
495             @NonNull WorkSource requestorWs) {
496         synchronized (sLock) {
497             IWifiStaIface iface = getStaIface(ifaceName);
498             if (iface == null) return boolResult(false);
499 
500             if (!mHalDeviceManager.replaceRequestorWs(iface, requestorWs)) {
501                 mLog.err("Failed to replace requestor worksource for STA iface").flush();
502                 return boolResult(false);
503             }
504             return true;
505         }
506     }
507 
508     /**
509      * Remove a STA iface using {@link HalDeviceManager}.
510      *
511      * @param ifaceName Name of the interface being removed.
512      * @return true on success, false otherwise.
513      */
removeStaIface(@onNull String ifaceName)514     public boolean removeStaIface(@NonNull String ifaceName) {
515         synchronized (sLock) {
516             IWifiStaIface iface = getStaIface(ifaceName);
517             if (iface == null) return boolResult(false);
518             if (!mHalDeviceManager.removeIface((IWifiIface) iface)) {
519                 mLog.err("Failed to remove STA iface").flush();
520                 return boolResult(false);
521             }
522             mIWifiStaIfaces.remove(ifaceName);
523             return true;
524         }
525     }
526 
527     /** Helper method to lookup the corresponding AP iface object using iface name. */
getApIface(@onNull String ifaceName)528     private IWifiApIface getApIface(@NonNull String ifaceName) {
529         synchronized (sLock) {
530             return mIWifiApIfaces.get(ifaceName);
531         }
532     }
533 
534     private class ApInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener {
535         private final InterfaceDestroyedListener mExternalListener;
536 
ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)537         ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) {
538             mExternalListener = externalListener;
539         }
540 
541         @Override
onDestroyed(@onNull String ifaceName)542         public void onDestroyed(@NonNull String ifaceName) {
543             synchronized (sLock) {
544                 mIWifiApIfaces.remove(ifaceName);
545             }
546             if (mExternalListener != null) {
547                 mExternalListener.onDestroyed(ifaceName);
548             }
549         }
550     }
551 
getNecessaryCapabilitiesForSoftApMode(@oftApConfiguration.BandType int band)552     private long getNecessaryCapabilitiesForSoftApMode(@SoftApConfiguration.BandType int band) {
553         long caps = HalDeviceManager.CHIP_CAPABILITY_ANY;
554         if ((band & SoftApConfiguration.BAND_60GHZ) != 0) {
555             caps |= android.hardware.wifi.V1_5.IWifiChip.ChipCapabilityMask.WIGIG;
556         }
557         return caps;
558     }
559 
560     /**
561      * Create a AP iface using {@link HalDeviceManager}.
562      *
563      * @param destroyedListener Listener to be invoked when the interface is destroyed.
564      * @param requestorWs Requestor worksource.
565      * @param band The requesting band for this AP interface.
566      * @param isBridged Whether or not AP interface is a bridge interface.
567      * @return iface name on success, null otherwise.
568      */
createApIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged)569     public String createApIface(@Nullable InterfaceDestroyedListener destroyedListener,
570             @NonNull WorkSource requestorWs,
571             @SoftApConfiguration.BandType int band,
572             boolean isBridged) {
573         synchronized (sLock) {
574             IWifiApIface iface = mHalDeviceManager.createApIface(
575                     getNecessaryCapabilitiesForSoftApMode(band),
576                     new ApInterfaceDestroyedListenerInternal(destroyedListener), null,
577                     requestorWs, isBridged);
578             if (iface == null) {
579                 mLog.err("Failed to create AP iface").flush();
580                 return nullResult();
581             }
582             String ifaceName = mHalDeviceManager.getName((IWifiIface) iface);
583             if (TextUtils.isEmpty(ifaceName)) {
584                 mLog.err("Failed to get iface name").flush();
585                 return nullResult();
586             }
587             if (!retrieveWifiChip((IWifiIface) iface)) {
588                 mLog.err("Failed to get wifi chip").flush();
589                 return nullResult();
590             }
591             mIWifiApIfaces.put(ifaceName, iface);
592             return ifaceName;
593         }
594     }
595 
596     /**
597      * Replace the requestor worksource info for a AP iface using {@link HalDeviceManager}.
598      *
599      * @param ifaceName Name of the interface being removed.
600      * @param requestorWs Requestor worksource.
601      * @return true on success, false otherwise.
602      */
replaceApIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)603     public boolean replaceApIfaceRequestorWs(@NonNull String ifaceName,
604             @NonNull WorkSource requestorWs) {
605         synchronized (sLock) {
606             IWifiApIface iface = getApIface(ifaceName);
607             if (iface == null) return boolResult(false);
608 
609             if (!mHalDeviceManager.replaceRequestorWs((IWifiIface) iface, requestorWs)) {
610                 mLog.err("Failed to replace requestor worksource for AP iface").flush();
611                 return boolResult(false);
612             }
613             return true;
614         }
615     }
616 
617     /**
618      * Remove an AP iface using {@link HalDeviceManager}.
619      *
620      * @param ifaceName Name of the interface being removed.
621      * @return true on success, false otherwise.
622      */
removeApIface(@onNull String ifaceName)623     public boolean removeApIface(@NonNull String ifaceName) {
624         synchronized (sLock) {
625             IWifiApIface iface = getApIface(ifaceName);
626             if (iface == null) return boolResult(false);
627 
628             if (!mHalDeviceManager.removeIface((IWifiIface) iface)) {
629                 mLog.err("Failed to remove AP iface").flush();
630                 return boolResult(false);
631             }
632             mIWifiApIfaces.remove(ifaceName);
633             return true;
634         }
635     }
636 
637     /**
638      * Helper function to remove specific instance in bridged AP iface.
639      *
640      * @param ifaceName Name of the iface.
641      * @param apIfaceInstance The identity of the ap instance.
642      * @return true if the operation succeeded, false if there is an error in Hal.
643      */
removeIfaceInstanceFromBridgedApIface(@onNull String ifaceName, @NonNull String apIfaceInstance)644     public boolean removeIfaceInstanceFromBridgedApIface(@NonNull String ifaceName,
645             @NonNull String apIfaceInstance) {
646         try {
647             android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
648             if (iWifiChipV15 == null) return boolResult(false);
649             return ok(iWifiChipV15.removeIfaceInstanceFromBridgedApIface(
650                     ifaceName, apIfaceInstance));
651         } catch (RemoteException e) {
652             handleRemoteException(e);
653             return false;
654         }
655     }
656 
657     @NonNull
658     private ArrayList<android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel>
frameworkCoexUnsafeChannelsToHidl( @onNull List<android.net.wifi.CoexUnsafeChannel> frameworkUnsafeChannels)659             frameworkCoexUnsafeChannelsToHidl(
660                     @NonNull List<android.net.wifi.CoexUnsafeChannel> frameworkUnsafeChannels) {
661         final ArrayList<android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel> hidlList =
662                 new ArrayList<>();
663         if (!SdkLevel.isAtLeastS()) {
664             return hidlList;
665         }
666         for (android.net.wifi.CoexUnsafeChannel frameworkUnsafeChannel : frameworkUnsafeChannels) {
667             final android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel hidlUnsafeChannel =
668                     new android.hardware.wifi.V1_5.IWifiChip.CoexUnsafeChannel();
669             switch (frameworkUnsafeChannel.getBand()) {
670                 case (WifiScanner.WIFI_BAND_24_GHZ):
671                     hidlUnsafeChannel.band = WifiBand.BAND_24GHZ;
672                     break;
673                 case (WifiScanner.WIFI_BAND_5_GHZ):
674                     hidlUnsafeChannel.band = WifiBand.BAND_5GHZ;
675                     break;
676                 case (WifiScanner.WIFI_BAND_6_GHZ):
677                     hidlUnsafeChannel.band = WifiBand.BAND_6GHZ;
678                     break;
679                 case (WifiScanner.WIFI_BAND_60_GHZ):
680                     hidlUnsafeChannel.band = WifiBand.BAND_60GHZ;
681                     break;
682                 default:
683                     mLog.err("Tried to set unsafe channel with unknown band: %")
684                             .c(frameworkUnsafeChannel.getBand())
685                             .flush();
686                     continue;
687             }
688             hidlUnsafeChannel.channel = frameworkUnsafeChannel.getChannel();
689             final int powerCapDbm = frameworkUnsafeChannel.getPowerCapDbm();
690             if (powerCapDbm != POWER_CAP_NONE) {
691                 hidlUnsafeChannel.powerCapDbm = powerCapDbm;
692             } else {
693                 hidlUnsafeChannel.powerCapDbm =
694                         android.hardware.wifi.V1_5.IWifiChip.PowerCapConstant.NO_POWER_CAP;
695             }
696             hidlList.add(hidlUnsafeChannel);
697         }
698         return hidlList;
699     }
700 
frameworkCoexRestrictionsToHidl(@ifiManager.CoexRestriction int restrictions)701     private int frameworkCoexRestrictionsToHidl(@WifiManager.CoexRestriction int restrictions) {
702         int hidlRestrictions = 0;
703         if (!SdkLevel.isAtLeastS()) {
704             return hidlRestrictions;
705         }
706         if ((restrictions & WifiManager.COEX_RESTRICTION_WIFI_DIRECT) != 0) {
707             hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.WIFI_DIRECT;
708         }
709         if ((restrictions & WifiManager.COEX_RESTRICTION_SOFTAP) != 0) {
710             hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.SOFTAP;
711         }
712         if ((restrictions & WifiManager.COEX_RESTRICTION_WIFI_AWARE) != 0) {
713             hidlRestrictions |= android.hardware.wifi.V1_5.IWifiChip.CoexRestriction.WIFI_AWARE;
714         }
715         return hidlRestrictions;
716     }
717 
718     /**
719      * Set the current coex unsafe channels to avoid and their restrictions.
720      * @param unsafeChannels List of {@link android.net.wifi.CoexUnsafeChannel} to avoid.
721      * @param restrictions int containing a bitwise-OR combination of
722      *                     {@link WifiManager.CoexRestriction}.
723      * @return true if the operation succeeded, false if there is an error in Hal.
724      */
setCoexUnsafeChannels( @onNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions)725     public boolean setCoexUnsafeChannels(
726             @NonNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions) {
727         try {
728             android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
729             if (iWifiChipV15 == null) return boolResult(false);
730             return ok(iWifiChipV15.setCoexUnsafeChannels(
731                     frameworkCoexUnsafeChannelsToHidl(unsafeChannels),
732                     frameworkCoexRestrictionsToHidl(restrictions)));
733         } catch (RemoteException e) {
734             handleRemoteException(e);
735             return false;
736         }
737     }
738 
retrieveWifiChip(IWifiIface iface)739     private boolean retrieveWifiChip(IWifiIface iface) {
740         synchronized (sLock) {
741             boolean registrationNeeded = mIWifiChip == null;
742             mIWifiChip = mHalDeviceManager.getChip(iface);
743             if (mIWifiChip == null) {
744                 mLog.err("Failed to get the chip created for the Iface").flush();
745                 return false;
746             }
747             if (!registrationNeeded) {
748                 return true;
749             }
750             if (!registerChipCallback()) {
751                 mLog.err("Failed to register chip callback").flush();
752                 mIWifiChip = null;
753                 return false;
754             }
755             return true;
756         }
757     }
758 
759     /**
760      * Registers the sta iface callback.
761      */
registerStaIfaceCallback(IWifiStaIface iface)762     private boolean registerStaIfaceCallback(IWifiStaIface iface) {
763         synchronized (sLock) {
764             if (iface == null) return boolResult(false);
765             if (mIWifiStaIfaceEventCallback == null) return boolResult(false);
766             try {
767                 WifiStatus status =
768                         iface.registerEventCallback(mIWifiStaIfaceEventCallback);
769                 return ok(status);
770             } catch (RemoteException e) {
771                 handleRemoteException(e);
772                 return false;
773             }
774         }
775     }
776 
777     /**
778      * Registers the sta iface callback.
779      */
registerChipCallback()780     private boolean registerChipCallback() {
781         synchronized (sLock) {
782             if (mIWifiChip == null) return boolResult(false);
783             try {
784                 WifiStatus status;
785                 android.hardware.wifi.V1_4.IWifiChip iWifiChipV14 = getWifiChipForV1_4Mockable();
786                 android.hardware.wifi.V1_2.IWifiChip iWifiChipV12 = getWifiChipForV1_2Mockable();
787 
788                 if (iWifiChipV14 != null) {
789                     status = iWifiChipV14.registerEventCallback_1_4(mIWifiChipEventCallbackV14);
790                 } else if (iWifiChipV12 != null) {
791                     status = iWifiChipV12.registerEventCallback_1_2(mIWifiChipEventCallbackV12);
792                 } else {
793                     status = mIWifiChip.registerEventCallback(mIWifiChipEventCallback);
794                 }
795                 return ok(status);
796             } catch (RemoteException e) {
797                 handleRemoteException(e);
798                 return false;
799             }
800         }
801     }
802 
803     /**
804      * Stops the HAL
805      */
stopVendorHal()806     public void stopVendorHal() {
807         synchronized (sLock) {
808             mHalDeviceManager.stop();
809             clearState();
810             mLog.info("Vendor Hal stopped").flush();
811         }
812     }
813 
814     /**
815      * Clears the state associated with a started Iface
816      *
817      * Caller should hold the lock.
818      */
clearState()819     private void clearState() {
820         mIWifiChip = null;
821         mIWifiStaIfaces.clear();
822         mIWifiApIfaces.clear();
823         mDriverDescription = null;
824         mFirmwareDescription = null;
825     }
826 
827     /**
828      * Tests whether the HAL is started and atleast one iface is up.
829      */
isHalStarted()830     public boolean isHalStarted() {
831         // For external use only. Methods in this class should test for null directly.
832         synchronized (sLock) {
833             return (!mIWifiStaIfaces.isEmpty() || !mIWifiApIfaces.isEmpty());
834         }
835     }
836 
837     /**
838      * Gets the scan capabilities
839      *
840      * @param ifaceName Name of the interface.
841      * @param capabilities object to be filled in
842      * @return true for success, false for failure
843      */
getBgScanCapabilities( @onNull String ifaceName, WifiNative.ScanCapabilities capabilities)844     public boolean getBgScanCapabilities(
845             @NonNull String ifaceName, WifiNative.ScanCapabilities capabilities) {
846         synchronized (sLock) {
847             IWifiStaIface iface = getStaIface(ifaceName);
848             if (iface == null) return boolResult(false);
849             try {
850                 Mutable<Boolean> ans = new Mutable<>(false);
851                 WifiNative.ScanCapabilities out = capabilities;
852                 iface.getBackgroundScanCapabilities((status, cap) -> {
853                             if (!ok(status)) return;
854                             mVerboseLog.info("scan capabilities %").c(cap.toString()).flush();
855                             out.max_scan_cache_size = cap.maxCacheSize;
856                             out.max_ap_cache_per_scan = cap.maxApCachePerScan;
857                             out.max_scan_buckets = cap.maxBuckets;
858                             out.max_rssi_sample_size = 0;
859                             out.max_scan_reporting_threshold = cap.maxReportingThreshold;
860                             ans.value = true;
861                         }
862                 );
863                 return ans.value;
864             } catch (RemoteException e) {
865                 handleRemoteException(e);
866                 return false;
867             }
868         }
869     }
870 
871     /**
872      * Holds the current background scan state, to implement pause and restart
873      */
874     @VisibleForTesting
875     class CurrentBackgroundScan {
876         public int cmdId;
877         public StaBackgroundScanParameters param;
878         public WifiNative.ScanEventHandler eventHandler = null;
879         public boolean paused = false;
880         public WifiScanner.ScanData[] latestScanResults = null;
881 
CurrentBackgroundScan(int id, WifiNative.ScanSettings settings)882         CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) {
883             cmdId = id;
884             param = new StaBackgroundScanParameters();
885             param.basePeriodInMs = settings.base_period_ms;
886             param.maxApPerScan = settings.max_ap_per_scan;
887             param.reportThresholdPercent = settings.report_threshold_percent;
888             param.reportThresholdNumScans = settings.report_threshold_num_scans;
889             if (settings.buckets != null) {
890                 for (WifiNative.BucketSettings bs : settings.buckets) {
891                     param.buckets.add(makeStaBackgroundScanBucketParametersFromBucketSettings(bs));
892                 }
893             }
894         }
895     }
896 
897     /**
898      * Makes the Hal flavor of WifiNative.BucketSettings
899      *
900      * @param bs WifiNative.BucketSettings
901      * @return Hal flavor of bs
902      * @throws IllegalArgumentException if band value is not recognized
903      */
904     private StaBackgroundScanBucketParameters
makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs)905             makeStaBackgroundScanBucketParametersFromBucketSettings(WifiNative.BucketSettings bs) {
906         StaBackgroundScanBucketParameters pa = new StaBackgroundScanBucketParameters();
907         pa.bucketIdx = bs.bucket;
908         pa.band = makeWifiBandFromFrameworkBand(bs.band);
909         if (bs.channels != null) {
910             for (WifiNative.ChannelSettings cs : bs.channels) {
911                 pa.frequencies.add(cs.frequency);
912             }
913         }
914         pa.periodInMs = bs.period_ms;
915         pa.eventReportScheme = makeReportSchemeFromBucketSettingsReportEvents(bs.report_events);
916         pa.exponentialMaxPeriodInMs = bs.max_period_ms;
917         // Although HAL API allows configurable base value for the truncated
918         // exponential back off scan. Native API and above support only
919         // truncated binary exponential back off scan.
920         // Hard code value of base to 2 here.
921         pa.exponentialBase = 2;
922         pa.exponentialStepCount = bs.step_count;
923         return pa;
924     }
925 
926     /**
927      * Makes the Hal flavor of WifiScanner's band indication
928      *
929      * Note: This method is only used by background scan which does not
930      *       support 6GHz, hence band combinations including 6GHz are considered invalid
931      *
932      * @param frameworkBand one of WifiScanner.WIFI_BAND_*
933      * @return A WifiBand value
934      * @throws IllegalArgumentException if frameworkBand is not recognized
935      */
makeWifiBandFromFrameworkBand(int frameworkBand)936     private int makeWifiBandFromFrameworkBand(int frameworkBand) {
937         switch (frameworkBand) {
938             case WifiScanner.WIFI_BAND_UNSPECIFIED:
939                 return WifiBand.BAND_UNSPECIFIED;
940             case WifiScanner.WIFI_BAND_24_GHZ:
941                 return WifiBand.BAND_24GHZ;
942             case WifiScanner.WIFI_BAND_5_GHZ:
943                 return WifiBand.BAND_5GHZ;
944             case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
945                 return WifiBand.BAND_5GHZ_DFS;
946             case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS:
947                 return WifiBand.BAND_5GHZ_WITH_DFS;
948             case WifiScanner.WIFI_BAND_BOTH:
949                 return WifiBand.BAND_24GHZ_5GHZ;
950             case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
951                 return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS;
952             case WifiScanner.WIFI_BAND_6_GHZ:
953                 return WifiBand.BAND_6GHZ;
954             case WifiScanner.WIFI_BAND_24_5_6_GHZ:
955                 return WifiBand.BAND_24GHZ_5GHZ_6GHZ;
956             case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_GHZ:
957                 return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS_6GHZ;
958             case WifiScanner.WIFI_BAND_60_GHZ:
959                 return WifiBand.BAND_60GHZ;
960             case WifiScanner.WIFI_BAND_24_5_6_60_GHZ:
961                 return WifiBand.BAND_24GHZ_5GHZ_6GHZ_60GHZ;
962             case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ:
963                 return WifiBand.BAND_24GHZ_5GHZ_WITH_DFS_6GHZ_60GHZ;
964             case WifiScanner.WIFI_BAND_24_GHZ_WITH_5GHZ_DFS:
965             default:
966                 throw new IllegalArgumentException("bad band " + frameworkBand);
967         }
968     }
969 
970     /**
971      * Makes the Hal flavor of WifiScanner's report event mask
972      *
973      * @param reportUnderscoreEvents is logical OR of WifiScanner.REPORT_EVENT_* values
974      * @return Corresponding StaBackgroundScanBucketEventReportSchemeMask value
975      * @throws IllegalArgumentException if a mask bit is not recognized
976      */
makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents)977     private int makeReportSchemeFromBucketSettingsReportEvents(int reportUnderscoreEvents) {
978         int ans = 0;
979         BitMask in = new BitMask(reportUnderscoreEvents);
980         if (in.testAndClear(WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN)) {
981             ans |= StaBackgroundScanBucketEventReportSchemeMask.EACH_SCAN;
982         }
983         if (in.testAndClear(WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT)) {
984             ans |= StaBackgroundScanBucketEventReportSchemeMask.FULL_RESULTS;
985         }
986         if (in.testAndClear(WifiScanner.REPORT_EVENT_NO_BATCH)) {
987             ans |= StaBackgroundScanBucketEventReportSchemeMask.NO_BATCH;
988         }
989         if (in.value != 0) throw new IllegalArgumentException("bad " + reportUnderscoreEvents);
990         return ans;
991     }
992 
993     private int mLastScanCmdId; // For assigning cmdIds to scans
994 
995     @VisibleForTesting
996     CurrentBackgroundScan mScan = null;
997 
998     /**
999      * Starts a background scan
1000      *
1001      * Any ongoing scan will be stopped first
1002      *
1003      * @param ifaceName    Name of the interface.
1004      * @param settings     to control the scan
1005      * @param eventHandler to call with the results
1006      * @return true for success
1007      */
startBgScan(@onNull String ifaceName, WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler)1008     public boolean startBgScan(@NonNull String ifaceName,
1009                                WifiNative.ScanSettings settings,
1010                                WifiNative.ScanEventHandler eventHandler) {
1011         WifiStatus status;
1012         if (eventHandler == null) return boolResult(false);
1013         synchronized (sLock) {
1014             IWifiStaIface iface = getStaIface(ifaceName);
1015             if (iface == null) return boolResult(false);
1016             try {
1017                 if (mScan != null && !mScan.paused) {
1018                     ok(iface.stopBackgroundScan(mScan.cmdId));
1019                     mScan = null;
1020                 }
1021                 mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits
1022                 CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings);
1023                 status = iface.startBackgroundScan(scan.cmdId, scan.param);
1024                 if (!ok(status)) return false;
1025                 scan.eventHandler = eventHandler;
1026                 mScan = scan;
1027                 return true;
1028             } catch (RemoteException e) {
1029                 handleRemoteException(e);
1030                 return false;
1031             }
1032         }
1033     }
1034 
1035 
1036     /**
1037      * Stops any ongoing backgound scan
1038      *
1039      * @param ifaceName Name of the interface.
1040      */
stopBgScan(@onNull String ifaceName)1041     public void stopBgScan(@NonNull String ifaceName) {
1042         WifiStatus status;
1043         synchronized (sLock) {
1044             IWifiStaIface iface = getStaIface(ifaceName);
1045             if (iface == null) return;
1046             try {
1047                 if (mScan != null) {
1048                     ok(iface.stopBackgroundScan(mScan.cmdId));
1049                     mScan = null;
1050                 }
1051             } catch (RemoteException e) {
1052                 handleRemoteException(e);
1053             }
1054         }
1055     }
1056 
1057     /**
1058      * Pauses an ongoing backgound scan
1059      *
1060      * @param ifaceName Name of the interface.
1061      */
pauseBgScan(@onNull String ifaceName)1062     public void pauseBgScan(@NonNull String ifaceName) {
1063         WifiStatus status;
1064         synchronized (sLock) {
1065             try {
1066                 IWifiStaIface iface = getStaIface(ifaceName);
1067                 if (iface == null) return;
1068                 if (mScan != null && !mScan.paused) {
1069                     status = iface.stopBackgroundScan(mScan.cmdId);
1070                     if (!ok(status)) return;
1071                     mScan.paused = true;
1072                 }
1073             } catch (RemoteException e) {
1074                 handleRemoteException(e);
1075             }
1076         }
1077     }
1078 
1079     /**
1080      * Restarts a paused background scan
1081      *
1082      * @param ifaceName Name of the interface.
1083      */
restartBgScan(@onNull String ifaceName)1084     public void restartBgScan(@NonNull String ifaceName) {
1085         WifiStatus status;
1086         synchronized (sLock) {
1087             IWifiStaIface iface = getStaIface(ifaceName);
1088             if (iface == null) return;
1089             try {
1090                 if (mScan != null && mScan.paused) {
1091                     status = iface.startBackgroundScan(mScan.cmdId, mScan.param);
1092                     if (!ok(status)) return;
1093                     mScan.paused = false;
1094                 }
1095             } catch (RemoteException e) {
1096                 handleRemoteException(e);
1097             }
1098         }
1099     }
1100 
1101     /**
1102      * Gets the latest scan results received from the HIDL interface callback.
1103      * TODO(b/35754840): This hop to fetch scan results after callback is unnecessary. Refactor
1104      * WifiScanner to use the scan results from the callback.
1105      *
1106      * @param ifaceName Name of the interface.
1107      */
getBgScanResults(@onNull String ifaceName)1108     public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) {
1109         synchronized (sLock) {
1110             IWifiStaIface iface = getStaIface(ifaceName);
1111             if (iface == null) return null;
1112             if (mScan == null) return null;
1113             return mScan.latestScanResults;
1114         }
1115     }
1116 
1117     /**
1118      * Get the link layer statistics
1119      *
1120      * Note - we always enable link layer stats on a STA interface.
1121      *
1122      * @param ifaceName Name of the interface.
1123      * @return the statistics, or null if unable to do so
1124      */
getWifiLinkLayerStats(@onNull String ifaceName)1125     public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) {
1126         if (getWifiStaIfaceForV1_5Mockable(ifaceName) != null) {
1127             return getWifiLinkLayerStats_1_5_Internal(ifaceName);
1128         } else if (getWifiStaIfaceForV1_3Mockable(ifaceName) != null) {
1129             return getWifiLinkLayerStats_1_3_Internal(ifaceName);
1130         } else {
1131             return getWifiLinkLayerStats_internal(ifaceName);
1132         }
1133     }
1134 
getWifiLinkLayerStats_internal(@onNull String ifaceName)1135     private WifiLinkLayerStats getWifiLinkLayerStats_internal(@NonNull String ifaceName) {
1136         class AnswerBox {
1137             public StaLinkLayerStats value = null;
1138         }
1139         AnswerBox answer = new AnswerBox();
1140         synchronized (sLock) {
1141             try {
1142                 IWifiStaIface iface = getStaIface(ifaceName);
1143                 if (iface == null) return null;
1144                 iface.getLinkLayerStats((status, stats) -> {
1145                     if (!ok(status)) return;
1146                     answer.value = stats;
1147                 });
1148             } catch (RemoteException e) {
1149                 handleRemoteException(e);
1150                 return null;
1151             }
1152         }
1153         WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats(answer.value);
1154         return stats;
1155     }
1156 
getWifiLinkLayerStats_1_3_Internal(@onNull String ifaceName)1157     private WifiLinkLayerStats getWifiLinkLayerStats_1_3_Internal(@NonNull String ifaceName) {
1158         class AnswerBox {
1159             public android.hardware.wifi.V1_3.StaLinkLayerStats value = null;
1160         }
1161         AnswerBox answer = new AnswerBox();
1162         synchronized (sLock) {
1163             try {
1164                 android.hardware.wifi.V1_3.IWifiStaIface iface =
1165                         getWifiStaIfaceForV1_3Mockable(ifaceName);
1166                 if (iface == null) return null;
1167                 iface.getLinkLayerStats_1_3((status, stats) -> {
1168                     if (!ok(status)) return;
1169                     answer.value = stats;
1170                 });
1171             } catch (RemoteException e) {
1172                 handleRemoteException(e);
1173                 return null;
1174             }
1175         }
1176         WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats_1_3(answer.value);
1177         return stats;
1178     }
1179 
getWifiLinkLayerStats_1_5_Internal(@onNull String ifaceName)1180     private WifiLinkLayerStats getWifiLinkLayerStats_1_5_Internal(@NonNull String ifaceName) {
1181         class AnswerBox {
1182             public android.hardware.wifi.V1_5.StaLinkLayerStats value = null;
1183         }
1184         AnswerBox answer = new AnswerBox();
1185         synchronized (sLock) {
1186             try {
1187                 android.hardware.wifi.V1_5.IWifiStaIface iface =
1188                         getWifiStaIfaceForV1_5Mockable(ifaceName);
1189                 if (iface == null) return null;
1190                 iface.getLinkLayerStats_1_5((status, stats) -> {
1191                     if (!ok(status)) return;
1192                     answer.value = stats;
1193                 });
1194             } catch (RemoteException e) {
1195                 handleRemoteException(e);
1196                 return null;
1197             }
1198         }
1199         WifiLinkLayerStats stats = frameworkFromHalLinkLayerStats_1_5(answer.value);
1200         return stats;
1201     }
1202 
1203 
1204     /**
1205      * Makes the framework version of link layer stats from the hal version.
1206      */
1207     @VisibleForTesting
frameworkFromHalLinkLayerStats(StaLinkLayerStats stats)1208     static WifiLinkLayerStats frameworkFromHalLinkLayerStats(StaLinkLayerStats stats) {
1209         if (stats == null) return null;
1210         WifiLinkLayerStats out = new WifiLinkLayerStats();
1211         setIfaceStats(out, stats.iface);
1212         setRadioStats(out, stats.radios);
1213         setTimeStamp(out, stats.timeStampInMs);
1214         out.version = WifiLinkLayerStats.V1_0;
1215         return out;
1216     }
1217 
1218     /**
1219      * Makes the framework version of link layer stats from the hal version.
1220      */
1221     @VisibleForTesting
frameworkFromHalLinkLayerStats_1_3( android.hardware.wifi.V1_3.StaLinkLayerStats stats)1222     static WifiLinkLayerStats frameworkFromHalLinkLayerStats_1_3(
1223             android.hardware.wifi.V1_3.StaLinkLayerStats stats) {
1224         if (stats == null) return null;
1225         WifiLinkLayerStats out = new WifiLinkLayerStats();
1226         setIfaceStats(out, stats.iface);
1227         setRadioStats_1_3(out, stats.radios);
1228         setTimeStamp(out, stats.timeStampInMs);
1229         out.version = WifiLinkLayerStats.V1_3;
1230         return out;
1231     }
1232 
1233     /**
1234      * Makes the framework version of link layer stats from the hal version.
1235      */
1236     @VisibleForTesting
frameworkFromHalLinkLayerStats_1_5( android.hardware.wifi.V1_5.StaLinkLayerStats stats)1237     static WifiLinkLayerStats frameworkFromHalLinkLayerStats_1_5(
1238             android.hardware.wifi.V1_5.StaLinkLayerStats stats) {
1239         if (stats == null) return null;
1240         WifiLinkLayerStats out = new WifiLinkLayerStats();
1241         setIfaceStats_1_5(out, stats.iface);
1242         setRadioStats_1_5(out, stats.radios);
1243         setTimeStamp(out, stats.timeStampInMs);
1244         out.version = WifiLinkLayerStats.V1_5;
1245         return out;
1246     }
1247 
setIfaceStats(WifiLinkLayerStats stats, StaLinkLayerIfaceStats iface)1248     private static void setIfaceStats(WifiLinkLayerStats stats, StaLinkLayerIfaceStats iface) {
1249         if (iface == null) return;
1250         stats.beacon_rx = iface.beaconRx;
1251         stats.rssi_mgmt = iface.avgRssiMgmt;
1252         // Statistics are broken out by Wireless Multimedia Extensions categories
1253         // WME Best Effort Access Category
1254         stats.rxmpdu_be = iface.wmeBePktStats.rxMpdu;
1255         stats.txmpdu_be = iface.wmeBePktStats.txMpdu;
1256         stats.lostmpdu_be = iface.wmeBePktStats.lostMpdu;
1257         stats.retries_be = iface.wmeBePktStats.retries;
1258         // WME Background Access Category
1259         stats.rxmpdu_bk = iface.wmeBkPktStats.rxMpdu;
1260         stats.txmpdu_bk = iface.wmeBkPktStats.txMpdu;
1261         stats.lostmpdu_bk = iface.wmeBkPktStats.lostMpdu;
1262         stats.retries_bk = iface.wmeBkPktStats.retries;
1263         // WME Video Access Category
1264         stats.rxmpdu_vi = iface.wmeViPktStats.rxMpdu;
1265         stats.txmpdu_vi = iface.wmeViPktStats.txMpdu;
1266         stats.lostmpdu_vi = iface.wmeViPktStats.lostMpdu;
1267         stats.retries_vi = iface.wmeViPktStats.retries;
1268         // WME Voice Access Category
1269         stats.rxmpdu_vo = iface.wmeVoPktStats.rxMpdu;
1270         stats.txmpdu_vo = iface.wmeVoPktStats.txMpdu;
1271         stats.lostmpdu_vo = iface.wmeVoPktStats.lostMpdu;
1272         stats.retries_vo = iface.wmeVoPktStats.retries;
1273     }
1274 
setIfaceStats_1_5(WifiLinkLayerStats stats, android.hardware.wifi.V1_5.StaLinkLayerIfaceStats iface)1275     private static void setIfaceStats_1_5(WifiLinkLayerStats stats,
1276             android.hardware.wifi.V1_5.StaLinkLayerIfaceStats iface) {
1277         if (iface == null) return;
1278         setIfaceStats(stats, iface.V1_0);
1279         stats.timeSliceDutyCycleInPercent = iface.timeSliceDutyCycleInPercent;
1280         // WME Best Effort Access Category
1281         stats.contentionTimeMinBeInUsec = iface.wmeBeContentionTimeStats.contentionTimeMinInUsec;
1282         stats.contentionTimeMaxBeInUsec = iface.wmeBeContentionTimeStats.contentionTimeMaxInUsec;
1283         stats.contentionTimeAvgBeInUsec = iface.wmeBeContentionTimeStats.contentionTimeAvgInUsec;
1284         stats.contentionNumSamplesBe = iface.wmeBeContentionTimeStats.contentionNumSamples;
1285         // WME Background Access Category
1286         stats.contentionTimeMinBkInUsec = iface.wmeBkContentionTimeStats.contentionTimeMinInUsec;
1287         stats.contentionTimeMaxBkInUsec = iface.wmeBkContentionTimeStats.contentionTimeMaxInUsec;
1288         stats.contentionTimeAvgBkInUsec = iface.wmeBkContentionTimeStats.contentionTimeAvgInUsec;
1289         stats.contentionNumSamplesBk = iface.wmeBkContentionTimeStats.contentionNumSamples;
1290         // WME Video Access Category
1291         stats.contentionTimeMinViInUsec = iface.wmeViContentionTimeStats.contentionTimeMinInUsec;
1292         stats.contentionTimeMaxViInUsec = iface.wmeViContentionTimeStats.contentionTimeMaxInUsec;
1293         stats.contentionTimeAvgViInUsec = iface.wmeViContentionTimeStats.contentionTimeAvgInUsec;
1294         stats.contentionNumSamplesVi = iface.wmeViContentionTimeStats.contentionNumSamples;
1295         // WME Voice Access Category
1296         stats.contentionTimeMinVoInUsec = iface.wmeVoContentionTimeStats.contentionTimeMinInUsec;
1297         stats.contentionTimeMaxVoInUsec = iface.wmeVoContentionTimeStats.contentionTimeMaxInUsec;
1298         stats.contentionTimeAvgVoInUsec = iface.wmeVoContentionTimeStats.contentionTimeAvgInUsec;
1299         stats.contentionNumSamplesVo = iface.wmeVoContentionTimeStats.contentionNumSamples;
1300         // Peer information statistics
1301         stats.peerInfo = new PeerInfo[iface.peers.size()];
1302         for (int i = 0; i < stats.peerInfo.length; i++) {
1303             PeerInfo peer = new PeerInfo();
1304             StaPeerInfo staPeerInfo = iface.peers.get(i);
1305             peer.staCount = staPeerInfo.staCount;
1306             peer.chanUtil = staPeerInfo.chanUtil;
1307             RateStat[] rateStats = new RateStat[staPeerInfo.rateStats.size()];
1308             for (int j = 0; j < staPeerInfo.rateStats.size(); j++) {
1309                 rateStats[j] = new RateStat();
1310                 StaRateStat staRateStat = staPeerInfo.rateStats.get(j);
1311                 rateStats[j].preamble = staRateStat.rateInfo.preamble;
1312                 rateStats[j].nss = staRateStat.rateInfo.nss;
1313                 rateStats[j].bw = staRateStat.rateInfo.bw;
1314                 rateStats[j].rateMcsIdx = staRateStat.rateInfo.rateMcsIdx;
1315                 rateStats[j].bitRateInKbps = staRateStat.rateInfo.bitRateInKbps;
1316                 rateStats[j].txMpdu = staRateStat.txMpdu;
1317                 rateStats[j].rxMpdu = staRateStat.rxMpdu;
1318                 rateStats[j].mpduLost = staRateStat.mpduLost;
1319                 rateStats[j].retries = staRateStat.retries;
1320             }
1321             peer.rateStats = rateStats;
1322             stats.peerInfo[i] = peer;
1323         }
1324     }
1325 
setRadioStats(WifiLinkLayerStats stats, List<StaLinkLayerRadioStats> radios)1326     private static void setRadioStats(WifiLinkLayerStats stats,
1327             List<StaLinkLayerRadioStats> radios) {
1328         if (radios == null) return;
1329         // Do not coalesce this info for multi radio devices with older HALs.
1330         if (radios.size() > 0) {
1331             StaLinkLayerRadioStats radioStats = radios.get(0);
1332             stats.on_time = radioStats.onTimeInMs;
1333             stats.tx_time = radioStats.txTimeInMs;
1334             stats.tx_time_per_level = new int[radioStats.txTimeInMsPerLevel.size()];
1335             for (int i = 0; i < stats.tx_time_per_level.length; i++) {
1336                 stats.tx_time_per_level[i] = radioStats.txTimeInMsPerLevel.get(i);
1337             }
1338             stats.rx_time = radioStats.rxTimeInMs;
1339             stats.on_time_scan = radioStats.onTimeInMsForScan;
1340             stats.numRadios = 1;
1341         }
1342     }
1343 
1344     /**
1345      * Set individual radio stats from the hal radio stats
1346      */
setFrameworkPerRadioStatsFromHidl(int radioId, RadioStat radio, android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats)1347     private static void setFrameworkPerRadioStatsFromHidl(int radioId, RadioStat radio,
1348             android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats) {
1349         radio.radio_id = radioId;
1350         radio.on_time = hidlRadioStats.V1_0.onTimeInMs;
1351         radio.tx_time = hidlRadioStats.V1_0.txTimeInMs;
1352         radio.rx_time = hidlRadioStats.V1_0.rxTimeInMs;
1353         radio.on_time_scan = hidlRadioStats.V1_0.onTimeInMsForScan;
1354         radio.on_time_nan_scan = hidlRadioStats.onTimeInMsForNanScan;
1355         radio.on_time_background_scan = hidlRadioStats.onTimeInMsForBgScan;
1356         radio.on_time_roam_scan = hidlRadioStats.onTimeInMsForRoamScan;
1357         radio.on_time_pno_scan = hidlRadioStats.onTimeInMsForPnoScan;
1358         radio.on_time_hs20_scan = hidlRadioStats.onTimeInMsForHs20Scan;
1359         /* Copy list of channel stats */
1360         for (android.hardware.wifi.V1_3.WifiChannelStats channelStats
1361                 : hidlRadioStats.channelStats) {
1362             ChannelStats channelStatsEntry = new ChannelStats();
1363             channelStatsEntry.frequency = channelStats.channel.centerFreq;
1364             channelStatsEntry.radioOnTimeMs = channelStats.onTimeInMs;
1365             channelStatsEntry.ccaBusyTimeMs = channelStats.ccaBusyTimeInMs;
1366             radio.channelStatsMap.put(channelStats.channel.centerFreq, channelStatsEntry);
1367         }
1368     }
1369 
1370     /**
1371      * If config_wifiLinkLayerAllRadiosStatsAggregationEnabled is set to true, aggregate
1372      * the radio stats from all the radios else process the stats from Radio 0 only.
1373      */
aggregateFrameworkRadioStatsFromHidl(int radioIndex, WifiLinkLayerStats stats, android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats)1374     private static void aggregateFrameworkRadioStatsFromHidl(int radioIndex,
1375             WifiLinkLayerStats stats,
1376             android.hardware.wifi.V1_3.StaLinkLayerRadioStats hidlRadioStats) {
1377         if (!sContext.getResources()
1378                 .getBoolean(R.bool.config_wifiLinkLayerAllRadiosStatsAggregationEnabled)
1379                 && radioIndex > 0) {
1380             return;
1381         }
1382         // Aggregate the radio stats from all the radios
1383         stats.on_time += hidlRadioStats.V1_0.onTimeInMs;
1384         stats.tx_time += hidlRadioStats.V1_0.txTimeInMs;
1385         // Aggregate tx_time_per_level based on the assumption that the length of
1386         // txTimeInMsPerLevel is the same across all radios. So txTimeInMsPerLevel on other
1387         // radios at array indices greater than the length of first radio will be dropped.
1388         if (stats.tx_time_per_level == null) {
1389             stats.tx_time_per_level = new int[hidlRadioStats.V1_0.txTimeInMsPerLevel.size()];
1390         }
1391         for (int i = 0; i < hidlRadioStats.V1_0.txTimeInMsPerLevel.size()
1392                 && i < stats.tx_time_per_level.length; i++) {
1393             stats.tx_time_per_level[i] += hidlRadioStats.V1_0.txTimeInMsPerLevel.get(i);
1394         }
1395         stats.rx_time += hidlRadioStats.V1_0.rxTimeInMs;
1396         stats.on_time_scan += hidlRadioStats.V1_0.onTimeInMsForScan;
1397         stats.on_time_nan_scan += hidlRadioStats.onTimeInMsForNanScan;
1398         stats.on_time_background_scan += hidlRadioStats.onTimeInMsForBgScan;
1399         stats.on_time_roam_scan += hidlRadioStats.onTimeInMsForRoamScan;
1400         stats.on_time_pno_scan += hidlRadioStats.onTimeInMsForPnoScan;
1401         stats.on_time_hs20_scan += hidlRadioStats.onTimeInMsForHs20Scan;
1402         /* Copy list of channel stats */
1403         for (android.hardware.wifi.V1_3.WifiChannelStats channelStats
1404                 : hidlRadioStats.channelStats) {
1405             ChannelStats channelStatsEntry =
1406                     stats.channelStatsMap.get(channelStats.channel.centerFreq);
1407             if (channelStatsEntry == null) {
1408                 channelStatsEntry = new ChannelStats();
1409                 channelStatsEntry.frequency = channelStats.channel.centerFreq;
1410                 stats.channelStatsMap.put(channelStats.channel.centerFreq, channelStatsEntry);
1411             }
1412             channelStatsEntry.radioOnTimeMs += channelStats.onTimeInMs;
1413             channelStatsEntry.ccaBusyTimeMs += channelStats.ccaBusyTimeInMs;
1414         }
1415         stats.numRadios++;
1416     }
1417 
setRadioStats_1_3(WifiLinkLayerStats stats, List<android.hardware.wifi.V1_3.StaLinkLayerRadioStats> radios)1418     private static void setRadioStats_1_3(WifiLinkLayerStats stats,
1419             List<android.hardware.wifi.V1_3.StaLinkLayerRadioStats> radios) {
1420         if (radios == null) return;
1421         int radioIndex = 0;
1422         for (android.hardware.wifi.V1_3.StaLinkLayerRadioStats radioStats : radios) {
1423             aggregateFrameworkRadioStatsFromHidl(radioIndex, stats, radioStats);
1424             radioIndex++;
1425         }
1426     }
1427 
setRadioStats_1_5(WifiLinkLayerStats stats, List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios)1428     private static void setRadioStats_1_5(WifiLinkLayerStats stats,
1429             List<android.hardware.wifi.V1_5.StaLinkLayerRadioStats> radios) {
1430         if (radios == null) return;
1431         int radioIndex = 0;
1432         stats.radioStats = new RadioStat[radios.size()];
1433         for (android.hardware.wifi.V1_5.StaLinkLayerRadioStats radioStats : radios) {
1434             RadioStat radio = new RadioStat();
1435             setFrameworkPerRadioStatsFromHidl(radioStats.radioId, radio, radioStats.V1_3);
1436             stats.radioStats[radioIndex] = radio;
1437             aggregateFrameworkRadioStatsFromHidl(radioIndex, stats, radioStats.V1_3);
1438             radioIndex++;
1439         }
1440     }
1441 
setTimeStamp(WifiLinkLayerStats stats, long timeStampInMs)1442     private static void setTimeStamp(WifiLinkLayerStats stats, long timeStampInMs) {
1443         stats.timeStampInMs = timeStampInMs;
1444     }
1445 
1446     @VisibleForTesting
1447     boolean mLinkLayerStatsDebug = false;  // Passed to Hal
1448 
1449     /**
1450      * Enables the linkLayerStats in the Hal.
1451      *
1452      * This is called unconditionally whenever we create a STA interface.
1453      *
1454      * @param iface Iface object.
1455      */
enableLinkLayerStats(IWifiStaIface iface)1456     private void enableLinkLayerStats(IWifiStaIface iface) {
1457         synchronized (sLock) {
1458             try {
1459                 WifiStatus status;
1460                 status = iface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug);
1461                 if (!ok(status)) {
1462                     mLog.err("unable to enable link layer stats collection").flush();
1463                 }
1464             } catch (RemoteException e) {
1465                 handleRemoteException(e);
1466             }
1467         }
1468     }
1469 
1470     /**
1471      * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for V1.1
1472      */
1473     private static final long[][] sChipFeatureCapabilityTranslation = {
1474             {WifiManager.WIFI_FEATURE_TX_POWER_LIMIT,
1475                     android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.SET_TX_POWER_LIMIT
1476             },
1477             {WifiManager.WIFI_FEATURE_D2D_RTT,
1478                     android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2D_RTT
1479             },
1480             {WifiManager.WIFI_FEATURE_D2AP_RTT,
1481                     android.hardware.wifi.V1_1.IWifiChip.ChipCapabilityMask.D2AP_RTT
1482             }
1483     };
1484 
1485     /**
1486      * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for
1487      * additional capabilities introduced in V1.5
1488      */
1489     private static final long[][] sChipFeatureCapabilityTranslation15 = {
1490             {WifiManager.WIFI_FEATURE_INFRA_60G,
1491                     android.hardware.wifi.V1_5.IWifiChip.ChipCapabilityMask.WIGIG
1492             }
1493     };
1494 
1495     /**
1496      * Translation table used by getSupportedFeatureSet for translating IWifiChip caps for
1497      * additional capabilities introduced in V1.3
1498      */
1499     private static final long[][] sChipFeatureCapabilityTranslation13 = {
1500             {WifiManager.WIFI_FEATURE_LOW_LATENCY,
1501                     android.hardware.wifi.V1_3.IWifiChip.ChipCapabilityMask.SET_LATENCY_MODE
1502             },
1503             {WifiManager.WIFI_FEATURE_P2P_RAND_MAC,
1504                     android.hardware.wifi.V1_3.IWifiChip.ChipCapabilityMask.P2P_RAND_MAC
1505             }
1506 
1507     };
1508 
1509     /**
1510      * Feature bit mask translation for Chip V1.1
1511      *
1512      * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask
1513      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
1514      */
1515     @VisibleForTesting
wifiFeatureMaskFromChipCapabilities(int capabilities)1516     int wifiFeatureMaskFromChipCapabilities(int capabilities) {
1517         int features = 0;
1518         for (int i = 0; i < sChipFeatureCapabilityTranslation.length; i++) {
1519             if ((capabilities & sChipFeatureCapabilityTranslation[i][1]) != 0) {
1520                 features |= sChipFeatureCapabilityTranslation[i][0];
1521             }
1522         }
1523         return features;
1524     }
1525 
1526     /**
1527      * Feature bit mask translation for Chip V1.5
1528      *
1529      * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask
1530      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
1531      */
1532     @VisibleForTesting
wifiFeatureMaskFromChipCapabilities_1_5(int capabilities)1533     long wifiFeatureMaskFromChipCapabilities_1_5(int capabilities) {
1534         // First collect features from previous versions
1535         long features = wifiFeatureMaskFromChipCapabilities_1_3(capabilities);
1536 
1537         // Next collect features for V1_5 version
1538         for (int i = 0; i < sChipFeatureCapabilityTranslation15.length; i++) {
1539             if ((capabilities & sChipFeatureCapabilityTranslation15[i][1]) != 0) {
1540                 features |= sChipFeatureCapabilityTranslation15[i][0];
1541             }
1542         }
1543         return features;
1544     }
1545 
1546     /**
1547      * Feature bit mask translation for Chip V1.3
1548      *
1549      * @param capabilities bitmask defined IWifiChip.ChipCapabilityMask
1550      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
1551      */
1552     @VisibleForTesting
wifiFeatureMaskFromChipCapabilities_1_3(int capabilities)1553     long wifiFeatureMaskFromChipCapabilities_1_3(int capabilities) {
1554         // First collect features from previous versions
1555         long features = wifiFeatureMaskFromChipCapabilities(capabilities);
1556 
1557         // Next collect features for V1_3 version
1558         for (int i = 0; i < sChipFeatureCapabilityTranslation13.length; i++) {
1559             if ((capabilities & sChipFeatureCapabilityTranslation13[i][1]) != 0) {
1560                 features |= sChipFeatureCapabilityTranslation13[i][0];
1561             }
1562         }
1563         return features;
1564     }
1565 
1566     /**
1567      * Translation table used by getSupportedFeatureSet for translating IWifiStaIface caps
1568      */
1569     private static final long[][] sStaFeatureCapabilityTranslation = {
1570             {WifiManager.WIFI_FEATURE_PASSPOINT,
1571                     IWifiStaIface.StaIfaceCapabilityMask.HOTSPOT
1572             },
1573             {WifiManager.WIFI_FEATURE_SCANNER,
1574                     IWifiStaIface.StaIfaceCapabilityMask.BACKGROUND_SCAN,
1575             },
1576             {WifiManager.WIFI_FEATURE_PNO,
1577                     IWifiStaIface.StaIfaceCapabilityMask.PNO
1578             },
1579             {WifiManager.WIFI_FEATURE_TDLS,
1580                     IWifiStaIface.StaIfaceCapabilityMask.TDLS
1581             },
1582             {WifiManager.WIFI_FEATURE_TDLS_OFFCHANNEL,
1583                     IWifiStaIface.StaIfaceCapabilityMask.TDLS_OFFCHANNEL
1584             },
1585             {WifiManager.WIFI_FEATURE_LINK_LAYER_STATS,
1586                     IWifiStaIface.StaIfaceCapabilityMask.LINK_LAYER_STATS
1587             },
1588             {WifiManager.WIFI_FEATURE_RSSI_MONITOR,
1589                     IWifiStaIface.StaIfaceCapabilityMask.RSSI_MONITOR
1590             },
1591             {WifiManager.WIFI_FEATURE_MKEEP_ALIVE,
1592                     IWifiStaIface.StaIfaceCapabilityMask.KEEP_ALIVE
1593             },
1594             {WifiManager.WIFI_FEATURE_CONFIG_NDO,
1595                     IWifiStaIface.StaIfaceCapabilityMask.ND_OFFLOAD
1596             },
1597             {WifiManager.WIFI_FEATURE_CONTROL_ROAMING,
1598                     IWifiStaIface.StaIfaceCapabilityMask.CONTROL_ROAMING
1599             },
1600             {WifiManager.WIFI_FEATURE_IE_WHITELIST,
1601                     IWifiStaIface.StaIfaceCapabilityMask.PROBE_IE_WHITELIST
1602             },
1603             {WifiManager.WIFI_FEATURE_SCAN_RAND,
1604                     IWifiStaIface.StaIfaceCapabilityMask.SCAN_RAND
1605             }
1606     };
1607 
1608     /**
1609      * Feature bit mask translation for STAs
1610      *
1611      * @param capabilities bitmask defined IWifiStaIface.StaIfaceCapabilityMask
1612      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
1613      */
1614     @VisibleForTesting
wifiFeatureMaskFromStaCapabilities(int capabilities)1615     long wifiFeatureMaskFromStaCapabilities(int capabilities) {
1616         long features = 0;
1617         for (int i = 0; i < sStaFeatureCapabilityTranslation.length; i++) {
1618             if ((capabilities & sStaFeatureCapabilityTranslation[i][1]) != 0) {
1619                 features |= sStaFeatureCapabilityTranslation[i][0];
1620             }
1621         }
1622         return features;
1623     }
1624 
1625     /**
1626      * Translation table used by getSupportedFeatureSetFromPackageManager
1627      * for translating System caps
1628      */
1629     private static final Pair[] sSystemFeatureCapabilityTranslation = new Pair[] {
1630             Pair.create(WifiManager.WIFI_FEATURE_INFRA, PackageManager.FEATURE_WIFI),
1631             Pair.create(WifiManager.WIFI_FEATURE_P2P, PackageManager.FEATURE_WIFI_DIRECT),
1632             Pair.create(WifiManager.WIFI_FEATURE_AWARE, PackageManager.FEATURE_WIFI_AWARE),
1633     };
1634 
1635     /**
1636      * If VendorHal is not supported, reading PackageManager
1637      * system features to return basic capabilities.
1638      *
1639      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
1640      */
getSupportedFeatureSetFromPackageManager()1641     private long getSupportedFeatureSetFromPackageManager() {
1642         long featureSet = 0;
1643         final PackageManager pm = sContext.getPackageManager();
1644         for (Pair pair: sSystemFeatureCapabilityTranslation) {
1645             if (pm.hasSystemFeature((String) pair.second)) {
1646                 featureSet |= (long) pair.first;
1647             }
1648         }
1649         enter("System feature set: %").c(featureSet).flush();
1650         return featureSet;
1651     }
1652 
1653     /**
1654      * Get the supported features
1655      *
1656      * The result may differ depending on the mode (STA or AP)
1657      *
1658      * @param ifaceName Name of the interface.
1659      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
1660      */
getSupportedFeatureSet(@onNull String ifaceName)1661     public long getSupportedFeatureSet(@NonNull String ifaceName) {
1662         long featureSet = 0;
1663         if (!mHalDeviceManager.isStarted() || !mHalDeviceManager.isSupported()) {
1664             return getSupportedFeatureSetFromPackageManager();
1665         }
1666         try {
1667             final Mutable<Long> feat = new Mutable<>(0L);
1668             synchronized (sLock) {
1669                 android.hardware.wifi.V1_3.IWifiChip iWifiChipV13 = getWifiChipForV1_3Mockable();
1670                 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
1671                 if (iWifiChipV15 != null) {
1672                     iWifiChipV15.getCapabilities_1_5((status, capabilities) -> {
1673                         if (!ok(status)) return;
1674                         feat.value = wifiFeatureMaskFromChipCapabilities_1_5(capabilities);
1675                     });
1676                 } else if (iWifiChipV13 != null) {
1677                     iWifiChipV13.getCapabilities_1_3((status, capabilities) -> {
1678                         if (!ok(status)) return;
1679                         feat.value = wifiFeatureMaskFromChipCapabilities_1_3(capabilities);
1680                     });
1681                 } else if (mIWifiChip != null) {
1682                     mIWifiChip.getCapabilities((status, capabilities) -> {
1683                         if (!ok(status)) return;
1684                         feat.value = (long) wifiFeatureMaskFromChipCapabilities(capabilities);
1685                     });
1686                 }
1687 
1688                 IWifiStaIface iface = getStaIface(ifaceName);
1689                 if (iface != null) {
1690                     iface.getCapabilities((status, capabilities) -> {
1691                         if (!ok(status)) return;
1692                         feat.value |= wifiFeatureMaskFromStaCapabilities(capabilities);
1693                     });
1694                 }
1695             }
1696             featureSet = feat.value;
1697         } catch (RemoteException e) {
1698             handleRemoteException(e);
1699             return 0;
1700         }
1701 
1702         if (mWifiGlobals.isWpa3SaeH2eSupported()) {
1703             featureSet |= WifiManager.WIFI_FEATURE_SAE_H2E;
1704         }
1705 
1706         Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes();
1707         if (supportedIfaceTypes.contains(IfaceType.STA)) {
1708             featureSet |= WifiManager.WIFI_FEATURE_INFRA;
1709         }
1710         if (supportedIfaceTypes.contains(IfaceType.AP)) {
1711             featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT;
1712         }
1713         if (supportedIfaceTypes.contains(IfaceType.P2P)) {
1714             featureSet |= WifiManager.WIFI_FEATURE_P2P;
1715         }
1716         if (supportedIfaceTypes.contains(IfaceType.NAN)) {
1717             featureSet |= WifiManager.WIFI_FEATURE_AWARE;
1718         }
1719 
1720         return featureSet;
1721     }
1722 
1723     /**
1724      * Set Mac address on the given interface
1725      *
1726      * @param ifaceName Name of the interface
1727      * @param mac MAC address to change into
1728      * @return true for success
1729      */
setStaMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)1730     public boolean setStaMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) {
1731         byte[] macByteArray = mac.toByteArray();
1732         synchronized (sLock) {
1733             try {
1734                 android.hardware.wifi.V1_2.IWifiStaIface sta12 =
1735                         getWifiStaIfaceForV1_2Mockable(ifaceName);
1736                 if (sta12 == null) return boolResult(false);
1737                 return ok(sta12.setMacAddress(macByteArray));
1738             } catch (RemoteException e) {
1739                 handleRemoteException(e);
1740                 return false;
1741             }
1742         }
1743     }
1744 
1745     /**
1746      * Reset MAC address to factory MAC address on the given interface
1747      *
1748      * @param ifaceName Name of the interface
1749      * @return true for success
1750      */
resetApMacToFactoryMacAddress(@onNull String ifaceName)1751     public boolean resetApMacToFactoryMacAddress(@NonNull String ifaceName) {
1752         synchronized (sLock) {
1753             try {
1754                 android.hardware.wifi.V1_5.IWifiApIface ap15 =
1755                         getWifiApIfaceForV1_5Mockable(ifaceName);
1756                 if (ap15 == null) {
1757                     MacAddress mac = getApFactoryMacAddress(ifaceName);
1758                     return mac != null && setApMacAddress(ifaceName, mac);
1759                 }
1760                 return ok(ap15.resetToFactoryMacAddress());
1761             } catch (RemoteException e) {
1762                 handleRemoteException(e);
1763                 return false;
1764             }
1765         }
1766     }
1767 
1768     /**
1769      * Set Mac address on the given interface
1770      *
1771      * @param ifaceName Name of the interface
1772      * @param mac MAC address to change into
1773      * @return true for success
1774      */
setApMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)1775     public boolean setApMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) {
1776         byte[] macByteArray = mac.toByteArray();
1777         synchronized (sLock) {
1778             try {
1779                 android.hardware.wifi.V1_4.IWifiApIface ap14 =
1780                         getWifiApIfaceForV1_4Mockable(ifaceName);
1781                 if (ap14 == null) return boolResult(false);
1782                 return ok(ap14.setMacAddress(macByteArray));
1783             } catch (RemoteException e) {
1784                 handleRemoteException(e);
1785                 return false;
1786             }
1787         }
1788     }
1789 
1790     /**
1791      * Returns true if Hal version supports setMacAddress, otherwise false.
1792      *
1793      * @param ifaceName Name of the interface
1794      */
isStaSetMacAddressSupported(@onNull String ifaceName)1795     public boolean isStaSetMacAddressSupported(@NonNull String ifaceName) {
1796         synchronized (sLock) {
1797             android.hardware.wifi.V1_2.IWifiStaIface sta12 =
1798                     getWifiStaIfaceForV1_2Mockable(ifaceName);
1799             return sta12 != null;
1800         }
1801     }
1802 
1803     /**
1804      * Returns true if Hal version supports setMacAddress, otherwise false.
1805      *
1806      * @param ifaceName Name of the interface
1807      */
isApSetMacAddressSupported(@onNull String ifaceName)1808     public boolean isApSetMacAddressSupported(@NonNull String ifaceName) {
1809         synchronized (sLock) {
1810             android.hardware.wifi.V1_4.IWifiApIface ap14 =
1811                     getWifiApIfaceForV1_4Mockable(ifaceName);
1812             return ap14 != null;
1813         }
1814     }
1815 
1816     /**
1817      * Get factory MAC address of the given interface
1818      *
1819      * @param ifaceName Name of the interface
1820      * @return factory MAC address of the interface or null.
1821      */
getStaFactoryMacAddress(@onNull String ifaceName)1822     public MacAddress getStaFactoryMacAddress(@NonNull String ifaceName) {
1823         class AnswerBox {
1824             public MacAddress mac = null;
1825         }
1826         synchronized (sLock) {
1827             try {
1828                 AnswerBox box = new AnswerBox();
1829 
1830                 android.hardware.wifi.V1_3.IWifiStaIface sta13 =
1831                         getWifiStaIfaceForV1_3Mockable(ifaceName);
1832                 if (sta13 == null) return null;
1833                 sta13.getFactoryMacAddress((status, macBytes) -> {
1834                     if (!ok(status)) return;
1835                     box.mac = MacAddress.fromBytes(macBytes);
1836                 });
1837                 return box.mac;
1838             } catch (RemoteException e) {
1839                 handleRemoteException(e);
1840                 return null;
1841             }
1842         }
1843     }
1844 
1845     /**
1846      * Get factory MAC address of the given interface
1847      *
1848      * @param ifaceName Name of the interface
1849      * @return factory MAC address of the interface or null.
1850      */
getApFactoryMacAddress(@onNull String ifaceName)1851     public MacAddress getApFactoryMacAddress(@NonNull String ifaceName) {
1852         class AnswerBox {
1853             public MacAddress mac = null;
1854         }
1855         synchronized (sLock) {
1856             try {
1857                 AnswerBox box = new AnswerBox();
1858                 android.hardware.wifi.V1_4.IWifiApIface ap14 =
1859                         getWifiApIfaceForV1_4Mockable(ifaceName);
1860                 if (ap14 == null) return null;
1861                 ap14.getFactoryMacAddress((status, macBytes) -> {
1862                     if (!ok(status)) return;
1863                     box.mac = MacAddress.fromBytes(macBytes);
1864                 });
1865                 return box.mac;
1866             } catch (RemoteException e) {
1867                 handleRemoteException(e);
1868                 return null;
1869             }
1870         }
1871     }
1872 
1873     /**
1874      * Get the APF (Android Packet Filter) capabilities of the device
1875      *
1876      * @param ifaceName Name of the interface.
1877      * @return APF capabilities object.
1878      */
getApfCapabilities(@onNull String ifaceName)1879     public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) {
1880         class AnswerBox {
1881             public ApfCapabilities value = sNoApfCapabilities;
1882         }
1883         synchronized (sLock) {
1884             try {
1885                 IWifiStaIface iface = getStaIface(ifaceName);
1886                 if (iface == null) return sNoApfCapabilities;
1887                 AnswerBox box = new AnswerBox();
1888                 iface.getApfPacketFilterCapabilities((status, capabilities) -> {
1889                     if (!ok(status)) return;
1890                     box.value = new ApfCapabilities(
1891                         /* apfVersionSupported */   capabilities.version,
1892                         /* maximumApfProgramSize */ capabilities.maxLength,
1893                         /* apfPacketFormat */       android.system.OsConstants.ARPHRD_ETHER);
1894                 });
1895                 return box.value;
1896             } catch (RemoteException e) {
1897                 handleRemoteException(e);
1898                 return sNoApfCapabilities;
1899             }
1900         }
1901     }
1902 
1903     private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
1904 
1905     /**
1906      * Installs an APF program on this iface, replacing any existing program.
1907      *
1908      * @param ifaceName Name of the interface.
1909      * @param filter is the android packet filter program
1910      * @return true for success
1911      */
installPacketFilter(@onNull String ifaceName, byte[] filter)1912     public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) {
1913         int cmdId = 0; // We only aspire to support one program at a time
1914         if (filter == null) return boolResult(false);
1915         // Copy the program before taking the lock.
1916         ArrayList<Byte> program = NativeUtil.byteArrayToArrayList(filter);
1917         enter("filter length %").c(filter.length).flush();
1918         synchronized (sLock) {
1919             try {
1920                 IWifiStaIface iface = getStaIface(ifaceName);
1921                 if (iface == null) return boolResult(false);
1922                 WifiStatus status = iface.installApfPacketFilter(cmdId, program);
1923                 if (!ok(status)) return false;
1924                 return true;
1925             } catch (RemoteException e) {
1926                 handleRemoteException(e);
1927                 return false;
1928             }
1929         }
1930     }
1931 
1932     /**
1933      * Reads the APF program and data buffer on this iface.
1934      *
1935      * @param ifaceName Name of the interface
1936      * @return the buffer returned by the driver, or null in case of an error
1937      */
readPacketFilter(@onNull String ifaceName)1938     public byte[] readPacketFilter(@NonNull String ifaceName) {
1939         class AnswerBox {
1940             public byte[] data = null;
1941         }
1942         AnswerBox answer = new AnswerBox();
1943         enter("").flush();
1944         // TODO: Must also take the wakelock here to prevent going to sleep with APF disabled.
1945         synchronized (sLock) {
1946             try {
1947                 android.hardware.wifi.V1_2.IWifiStaIface ifaceV12 =
1948                         getWifiStaIfaceForV1_2Mockable(ifaceName);
1949                 if (ifaceV12 == null) return byteArrayResult(null);
1950                 ifaceV12.readApfPacketFilterData((status, dataByteArray) -> {
1951                     if (!ok(status)) return;
1952                     answer.data = NativeUtil.byteArrayFromArrayList(dataByteArray);
1953                 });
1954                 return byteArrayResult(answer.data);
1955             } catch (RemoteException e) {
1956                 handleRemoteException(e);
1957                 return byteArrayResult(null);
1958             }
1959         }
1960     }
1961 
1962     /**
1963      * Set country code for this Wifi chip
1964      *
1965      * @param countryCode - two-letter country code (as ISO 3166)
1966      * @return true for success
1967      */
setChipCountryCode(String countryCode)1968     public boolean setChipCountryCode(String countryCode) {
1969         if (countryCode == null) return boolResult(false);
1970         if (countryCode.length() != 2) return boolResult(false);
1971         byte[] code;
1972         try {
1973             code = NativeUtil.stringToByteArray(countryCode);
1974         } catch (IllegalArgumentException e) {
1975             return boolResult(false);
1976         }
1977         synchronized (sLock) {
1978             try {
1979                 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
1980                 if (iWifiChipV15 == null) return boolResult(false);
1981                 WifiStatus status = iWifiChipV15.setCountryCode(code);
1982                 if (!ok(status)) return false;
1983                 return true;
1984             } catch (RemoteException e) {
1985                 handleRemoteException(e);
1986                 return false;
1987             }
1988         }
1989     }
1990 
1991     /**
1992      * Get the names of the bridged AP instances.
1993      *
1994      * @param ifaceName Name of the bridged interface.
1995      * @return A list which contains the names of the bridged AP instances.
1996      */
1997     @Nullable
getBridgedApInstances(@onNull String ifaceName)1998     public List<String> getBridgedApInstances(@NonNull String ifaceName) {
1999         synchronized (sLock) {
2000             try {
2001                 Mutable<List<String>> instancesResp  = new Mutable<>();
2002                 android.hardware.wifi.V1_5.IWifiApIface ap15 =
2003                         getWifiApIfaceForV1_5Mockable(ifaceName);
2004                 if (ap15 == null) return null;
2005                 ap15.getBridgedInstances((status, instances) -> {
2006                     if (!ok(status)) return;
2007                     instancesResp.value = new ArrayList<>(instances);
2008                 });
2009                 return instancesResp.value;
2010             } catch (RemoteException e) {
2011                 handleRemoteException(e);
2012                 return null;
2013             }
2014         }
2015     }
2016 
2017     /**
2018      * Set country code for this AP iface.
2019      *
2020      * @param ifaceName Name of the interface.
2021      * @param countryCode - two-letter country code (as ISO 3166)
2022      * @return true for success
2023      */
setApCountryCode(@onNull String ifaceName, String countryCode)2024     public boolean setApCountryCode(@NonNull String ifaceName, String countryCode) {
2025         if (countryCode == null) return boolResult(false);
2026         if (countryCode.length() != 2) return boolResult(false);
2027         byte[] code;
2028         try {
2029             code = NativeUtil.stringToByteArray(countryCode);
2030         } catch (IllegalArgumentException e) {
2031             return boolResult(false);
2032         }
2033         synchronized (sLock) {
2034             try {
2035                 IWifiApIface iface = getApIface(ifaceName);
2036                 if (iface == null) return boolResult(false);
2037                 WifiStatus status = iface.setCountryCode(code);
2038                 if (!ok(status)) return false;
2039                 return true;
2040             } catch (RemoteException e) {
2041                 handleRemoteException(e);
2042                 return false;
2043             }
2044         }
2045     }
2046 
2047     private WifiNative.WifiLoggerEventHandler mLogEventHandler = null;
2048 
2049     /**
2050      * Registers the logger callback and enables alerts.
2051      * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
2052      */
setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler)2053     public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
2054         if (handler == null) return boolResult(false);
2055         synchronized (sLock) {
2056             if (mIWifiChip == null) return boolResult(false);
2057             if (mLogEventHandler != null) return boolResult(false);
2058             try {
2059                 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(true);
2060                 if (!ok(status)) return false;
2061                 mLogEventHandler = handler;
2062                 return true;
2063             } catch (RemoteException e) {
2064                 handleRemoteException(e);
2065                 return false;
2066             }
2067         }
2068     }
2069 
2070     /**
2071      * Stops all logging and resets the logger callback.
2072      * This stops both the alerts and ring buffer data collection.
2073      * Existing log handler is cleared.
2074      */
resetLogHandler()2075     public boolean resetLogHandler() {
2076         synchronized (sLock) {
2077             mLogEventHandler = null;
2078             if (mIWifiChip == null) return boolResult(false);
2079             try {
2080                 WifiStatus status = mIWifiChip.enableDebugErrorAlerts(false);
2081                 if (!ok(status)) return false;
2082                 status = mIWifiChip.stopLoggingToDebugRingBuffer();
2083                 if (!ok(status)) return false;
2084                 return true;
2085             } catch (RemoteException e) {
2086                 handleRemoteException(e);
2087                 return false;
2088             }
2089         }
2090     }
2091 
2092     /**
2093      * Control debug data collection
2094      *
2095      * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
2096      * @param flags              Ignored.
2097      * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
2098      * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
2099      * @param ringName           Name of the ring for which data collection is to start.
2100      * @return true for success
2101      */
startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec, int minDataSizeInBytes, String ringName)2102     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
2103                                           int minDataSizeInBytes, String ringName) {
2104         enter("verboseLevel=%, flags=%, maxIntervalInSec=%, minDataSizeInBytes=%, ringName=%")
2105                 .c(verboseLevel).c(flags).c(maxIntervalInSec).c(minDataSizeInBytes).c(ringName)
2106                 .flush();
2107         synchronized (sLock) {
2108             if (mIWifiChip == null) return boolResult(false);
2109             try {
2110                 // note - flags are not used
2111                 WifiStatus status = mIWifiChip.startLoggingToDebugRingBuffer(
2112                         ringName,
2113                         verboseLevel,
2114                         maxIntervalInSec,
2115                         minDataSizeInBytes
2116                 );
2117                 return ok(status);
2118             } catch (RemoteException e) {
2119                 handleRemoteException(e);
2120                 return false;
2121             }
2122         }
2123     }
2124 
2125     /**
2126      * Pointlessly fail
2127      *
2128      * @return -1
2129      */
getSupportedLoggerFeatureSet()2130     public int getSupportedLoggerFeatureSet() {
2131         return -1;
2132     }
2133 
2134     private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
2135 
2136     /**
2137      * Vendor-provided wifi driver version string
2138      */
getDriverVersion()2139     public String getDriverVersion() {
2140         synchronized (sLock) {
2141             if (mDriverDescription == null) requestChipDebugInfo();
2142             return mDriverDescription;
2143         }
2144     }
2145 
2146     private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
2147 
2148     /**
2149      * Vendor-provided wifi firmware version string
2150      */
getFirmwareVersion()2151     public String getFirmwareVersion() {
2152         synchronized (sLock) {
2153             if (mFirmwareDescription == null) requestChipDebugInfo();
2154             return mFirmwareDescription;
2155         }
2156     }
2157 
2158     /**
2159      * Refreshes our idea of the driver and firmware versions
2160      */
requestChipDebugInfo()2161     private void requestChipDebugInfo() {
2162         mDriverDescription = null;
2163         mFirmwareDescription = null;
2164         try {
2165             if (mIWifiChip == null) return;
2166             mIWifiChip.requestChipDebugInfo((status, chipDebugInfo) -> {
2167                 if (!ok(status)) return;
2168                 mDriverDescription = chipDebugInfo.driverDescription;
2169                 mFirmwareDescription = chipDebugInfo.firmwareDescription;
2170             });
2171         } catch (RemoteException e) {
2172             handleRemoteException(e);
2173             return;
2174         }
2175         mLog.info("Driver: % Firmware: %")
2176                 .c(mDriverDescription)
2177                 .c(mFirmwareDescription)
2178                 .flush();
2179     }
2180 
2181     /**
2182      * Creates RingBufferStatus from the Hal version
2183      */
ringBufferStatus(WifiDebugRingBufferStatus h)2184     private static WifiNative.RingBufferStatus ringBufferStatus(WifiDebugRingBufferStatus h) {
2185         WifiNative.RingBufferStatus ans = new WifiNative.RingBufferStatus();
2186         ans.name = h.ringName;
2187         ans.flag = frameworkRingBufferFlagsFromHal(h.flags);
2188         ans.ringBufferId = h.ringId;
2189         ans.ringBufferByteSize = h.sizeInBytes;
2190         ans.verboseLevel = h.verboseLevel;
2191         // Remaining fields are unavailable
2192         //  writtenBytes;
2193         //  readBytes;
2194         //  writtenRecords;
2195         return ans;
2196     }
2197 
2198     /**
2199      * Translates a hal wifiDebugRingBufferFlag to the WifiNative version
2200      */
frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag)2201     private static int frameworkRingBufferFlagsFromHal(int wifiDebugRingBufferFlag) {
2202         BitMask checkoff = new BitMask(wifiDebugRingBufferFlag);
2203         int flags = 0;
2204         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_BINARY_ENTRIES)) {
2205             flags |= WifiNative.RingBufferStatus.HAS_BINARY_ENTRIES;
2206         }
2207         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_ASCII_ENTRIES)) {
2208             flags |= WifiNative.RingBufferStatus.HAS_ASCII_ENTRIES;
2209         }
2210         if (checkoff.testAndClear(WifiDebugRingBufferFlags.HAS_PER_PACKET_ENTRIES)) {
2211             flags |= WifiNative.RingBufferStatus.HAS_PER_PACKET_ENTRIES;
2212         }
2213         if (checkoff.value != 0) {
2214             throw new IllegalArgumentException("Unknown WifiDebugRingBufferFlag " + checkoff.value);
2215         }
2216         return flags;
2217     }
2218 
2219     /**
2220      * Creates array of RingBufferStatus from the Hal version
2221      */
makeRingBufferStatusArray( ArrayList<WifiDebugRingBufferStatus> ringBuffers)2222     private static WifiNative.RingBufferStatus[] makeRingBufferStatusArray(
2223             ArrayList<WifiDebugRingBufferStatus> ringBuffers) {
2224         WifiNative.RingBufferStatus[] ans = new WifiNative.RingBufferStatus[ringBuffers.size()];
2225         int i = 0;
2226         for (WifiDebugRingBufferStatus b : ringBuffers) {
2227             ans[i++] = ringBufferStatus(b);
2228         }
2229         return ans;
2230     }
2231 
2232     /**
2233      * API to get the status of all ring buffers supported by driver
2234      */
getRingBufferStatus()2235     public WifiNative.RingBufferStatus[] getRingBufferStatus() {
2236         class AnswerBox {
2237             public WifiNative.RingBufferStatus[] value = null;
2238         }
2239         AnswerBox ans = new AnswerBox();
2240         synchronized (sLock) {
2241             if (mIWifiChip == null) return null;
2242             try {
2243                 mIWifiChip.getDebugRingBuffersStatus((status, ringBuffers) -> {
2244                     if (!ok(status)) return;
2245                     ans.value = makeRingBufferStatusArray(ringBuffers);
2246                 });
2247             } catch (RemoteException e) {
2248                 handleRemoteException(e);
2249                 return null;
2250             }
2251         }
2252         return ans.value;
2253     }
2254 
2255     /**
2256      * Indicates to driver that all the data has to be uploaded urgently
2257      */
getRingBufferData(String ringName)2258     public boolean getRingBufferData(String ringName) {
2259         enter("ringName %").c(ringName).flush();
2260         synchronized (sLock) {
2261             if (mIWifiChip == null) return boolResult(false);
2262             try {
2263                 WifiStatus status = mIWifiChip.forceDumpToDebugRingBuffer(ringName);
2264                 return ok(status);
2265             } catch (RemoteException e) {
2266                 handleRemoteException(e);
2267                 return false;
2268             }
2269         }
2270     }
2271 
2272     /**
2273      * request hal to flush ring buffers to files
2274      */
flushRingBufferData()2275     public boolean flushRingBufferData() {
2276         synchronized (sLock) {
2277             if (mIWifiChip == null) return boolResult(false);
2278             android.hardware.wifi.V1_3.IWifiChip iWifiChipV13 = getWifiChipForV1_3Mockable();
2279             if (iWifiChipV13 != null) {
2280                 try {
2281                     WifiStatus status = iWifiChipV13.flushRingBufferToFile();
2282                     return ok(status);
2283                 } catch (RemoteException e) {
2284                     handleRemoteException(e);
2285                     return false;
2286                 }
2287             }
2288             return false;
2289         }
2290     }
2291 
2292     /**
2293      * Request vendor debug info from the firmware
2294      */
getFwMemoryDump()2295     public byte[] getFwMemoryDump() {
2296         class AnswerBox {
2297             public byte[] value;
2298         }
2299         AnswerBox ans = new AnswerBox();
2300         synchronized (sLock) {
2301             if (mIWifiChip == null) return (null);
2302             try {
2303                 mIWifiChip.requestFirmwareDebugDump((status, blob) -> {
2304                     if (!ok(status)) return;
2305                     ans.value = NativeUtil.byteArrayFromArrayList(blob);
2306                 });
2307             } catch (RemoteException e) {
2308                 handleRemoteException(e);
2309                 return null;
2310             }
2311         }
2312         return ans.value;
2313     }
2314 
2315     /**
2316      * Request vendor debug info from the driver
2317      */
getDriverStateDump()2318     public byte[] getDriverStateDump() {
2319         class AnswerBox {
2320             public byte[] value;
2321         }
2322         AnswerBox ans = new AnswerBox();
2323         synchronized (sLock) {
2324             if (mIWifiChip == null) return (null);
2325             try {
2326                 mIWifiChip.requestDriverDebugDump((status, blob) -> {
2327                     if (!ok(status)) return;
2328                     ans.value = NativeUtil.byteArrayFromArrayList(blob);
2329                 });
2330             } catch (RemoteException e) {
2331                 handleRemoteException(e);
2332                 return null;
2333             }
2334         }
2335         return ans.value;
2336     }
2337 
2338     /**
2339      * Start packet fate monitoring
2340      * <p>
2341      * Once started, monitoring remains active until HAL is unloaded.
2342      *
2343      * @param ifaceName Name of the interface.
2344      * @return true for success
2345      */
startPktFateMonitoring(@onNull String ifaceName)2346     public boolean startPktFateMonitoring(@NonNull String ifaceName) {
2347         synchronized (sLock) {
2348             IWifiStaIface iface = getStaIface(ifaceName);
2349             if (iface == null) return boolResult(false);
2350             try {
2351                 WifiStatus status = iface.startDebugPacketFateMonitoring();
2352                 return ok(status);
2353             } catch (RemoteException e) {
2354                 handleRemoteException(e);
2355                 return false;
2356             }
2357         }
2358     }
2359 
halToFrameworkPktFateFrameType(int type)2360     private byte halToFrameworkPktFateFrameType(int type) {
2361         switch (type) {
2362             case WifiDebugPacketFateFrameType.UNKNOWN:
2363                 return WifiLoggerHal.FRAME_TYPE_UNKNOWN;
2364             case WifiDebugPacketFateFrameType.ETHERNET_II:
2365                 return WifiLoggerHal.FRAME_TYPE_ETHERNET_II;
2366             case WifiDebugPacketFateFrameType.MGMT_80211:
2367                 return WifiLoggerHal.FRAME_TYPE_80211_MGMT;
2368             default:
2369                 throw new IllegalArgumentException("bad " + type);
2370         }
2371     }
2372 
halToFrameworkRxPktFate(int type)2373     private byte halToFrameworkRxPktFate(int type) {
2374         switch (type) {
2375             case WifiDebugRxPacketFate.SUCCESS:
2376                 return WifiLoggerHal.RX_PKT_FATE_SUCCESS;
2377             case WifiDebugRxPacketFate.FW_QUEUED:
2378                 return WifiLoggerHal.RX_PKT_FATE_FW_QUEUED;
2379             case WifiDebugRxPacketFate.FW_DROP_FILTER:
2380                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER;
2381             case WifiDebugRxPacketFate.FW_DROP_INVALID:
2382                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID;
2383             case WifiDebugRxPacketFate.FW_DROP_NOBUFS:
2384                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS;
2385             case WifiDebugRxPacketFate.FW_DROP_OTHER:
2386                 return WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER;
2387             case WifiDebugRxPacketFate.DRV_QUEUED:
2388                 return WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED;
2389             case WifiDebugRxPacketFate.DRV_DROP_FILTER:
2390                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER;
2391             case WifiDebugRxPacketFate.DRV_DROP_INVALID:
2392                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID;
2393             case WifiDebugRxPacketFate.DRV_DROP_NOBUFS:
2394                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS;
2395             case WifiDebugRxPacketFate.DRV_DROP_OTHER:
2396                 return WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER;
2397             default:
2398                 throw new IllegalArgumentException("bad " + type);
2399         }
2400     }
2401 
halToFrameworkTxPktFate(int type)2402     private byte halToFrameworkTxPktFate(int type) {
2403         switch (type) {
2404             case WifiDebugTxPacketFate.ACKED:
2405                 return WifiLoggerHal.TX_PKT_FATE_ACKED;
2406             case WifiDebugTxPacketFate.SENT:
2407                 return WifiLoggerHal.TX_PKT_FATE_SENT;
2408             case WifiDebugTxPacketFate.FW_QUEUED:
2409                 return WifiLoggerHal.TX_PKT_FATE_FW_QUEUED;
2410             case WifiDebugTxPacketFate.FW_DROP_INVALID:
2411                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID;
2412             case WifiDebugTxPacketFate.FW_DROP_NOBUFS:
2413                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS;
2414             case WifiDebugTxPacketFate.FW_DROP_OTHER:
2415                 return WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER;
2416             case WifiDebugTxPacketFate.DRV_QUEUED:
2417                 return WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED;
2418             case WifiDebugTxPacketFate.DRV_DROP_INVALID:
2419                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID;
2420             case WifiDebugTxPacketFate.DRV_DROP_NOBUFS:
2421                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS;
2422             case WifiDebugTxPacketFate.DRV_DROP_OTHER:
2423                 return WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER;
2424             default:
2425                 throw new IllegalArgumentException("bad " + type);
2426         }
2427     }
2428 
2429     /**
2430      * Retrieve fates of outbound packets
2431      * <p>
2432      * Reports the outbound frames for the most recent association (space allowing).
2433      *
2434      * @param ifaceName Name of the interface.
2435      * @return list of TxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty
2436      * list on failure.
2437      */
getTxPktFates(@onNull String ifaceName)2438     public List<TxFateReport> getTxPktFates(@NonNull String ifaceName) {
2439         synchronized (sLock) {
2440             IWifiStaIface iface = getStaIface(ifaceName);
2441             if (iface == null) return objResult(new ArrayList<>());
2442             try {
2443                 List<TxFateReport> reportBufs = new ArrayList<>();
2444                 iface.getDebugTxPacketFates((status, fates) -> {
2445                     if (!ok(status)) return;
2446                     for (WifiDebugTxPacketFateReport fate : fates) {
2447                         if (reportBufs.size() >= WifiLoggerHal.MAX_FATE_LOG_LEN) break;
2448                         byte code = halToFrameworkTxPktFate(fate.fate);
2449                         long us = fate.frameInfo.driverTimestampUsec;
2450                         byte type = halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
2451                         byte[] frame = NativeUtil.byteArrayFromArrayList(
2452                                 fate.frameInfo.frameContent);
2453                         reportBufs.add(new TxFateReport(code, us, type, frame));
2454                     }
2455                 });
2456                 return reportBufs;
2457             } catch (RemoteException e) {
2458                 handleRemoteException(e);
2459                 return new ArrayList<>();
2460             }
2461         }
2462     }
2463 
2464     /**
2465      * Retrieve fates of inbound packets
2466      * <p>
2467      * Reports the inbound frames for the most recent association (space allowing).
2468      *
2469      * @param ifaceName Name of the interface.
2470      * @return list of RxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty
2471      * list on failure.
2472      */
getRxPktFates(@onNull String ifaceName)2473     public List<RxFateReport> getRxPktFates(@NonNull String ifaceName) {
2474         synchronized (sLock) {
2475             IWifiStaIface iface = getStaIface(ifaceName);
2476             if (iface == null) return objResult(new ArrayList<>());
2477             try {
2478                 List<RxFateReport> reportBufs = new ArrayList<>();
2479                 iface.getDebugRxPacketFates((status, fates) -> {
2480                     if (!ok(status)) return;
2481                     for (WifiDebugRxPacketFateReport fate : fates) {
2482                         if (reportBufs.size() >= WifiLoggerHal.MAX_FATE_LOG_LEN) break;
2483                         byte code = halToFrameworkRxPktFate(fate.fate);
2484                         long us = fate.frameInfo.driverTimestampUsec;
2485                         byte type = halToFrameworkPktFateFrameType(fate.frameInfo.frameType);
2486                         byte[] frame = NativeUtil.byteArrayFromArrayList(
2487                                 fate.frameInfo.frameContent);
2488                         reportBufs.add(new RxFateReport(code, us, type, frame));
2489                     }
2490                 });
2491                 return reportBufs;
2492             } catch (RemoteException e) {
2493                 handleRemoteException(e);
2494                 return new ArrayList<>();
2495             }
2496         }
2497     }
2498 
2499     /**
2500      * Start sending the specified keep alive packets periodically.
2501      *
2502      * @param ifaceName Name of the interface.
2503      * @param slot
2504      * @param srcMac
2505      * @param dstMac
2506      * @param keepAlivePacket
2507      * @param protocol
2508      * @param periodInMs
2509      * @return 0 for success, -1 for error
2510      */
startSendingOffloadedPacket( @onNull String ifaceName, int slot, byte[] srcMac, byte[] dstMac, byte[] packet, int protocol, int periodInMs)2511     public int startSendingOffloadedPacket(
2512             @NonNull String ifaceName, int slot, byte[] srcMac, byte[] dstMac,
2513             byte[] packet, int protocol, int periodInMs) {
2514         enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush();
2515 
2516         ArrayList<Byte> data = NativeUtil.byteArrayToArrayList(packet);
2517 
2518         synchronized (sLock) {
2519             IWifiStaIface iface = getStaIface(ifaceName);
2520             if (iface == null) return -1;
2521             try {
2522                 WifiStatus status = iface.startSendingKeepAlivePackets(
2523                         slot,
2524                         data,
2525                         (short) protocol,
2526                         srcMac,
2527                         dstMac,
2528                         periodInMs);
2529                 if (!ok(status)) return -1;
2530                 return 0;
2531             } catch (RemoteException e) {
2532                 handleRemoteException(e);
2533                 return -1;
2534             }
2535         }
2536     }
2537 
2538     /**
2539      * Stop sending the specified keep alive packets.
2540      *
2541      * @param ifaceName Name of the interface.
2542      * @param slot id - same as startSendingOffloadedPacket call.
2543      * @return 0 for success, -1 for error
2544      */
stopSendingOffloadedPacket(@onNull String ifaceName, int slot)2545     public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) {
2546         enter("slot=%").c(slot).flush();
2547 
2548         synchronized (sLock) {
2549             IWifiStaIface iface = getStaIface(ifaceName);
2550             if (iface == null) return -1;
2551             try {
2552                 WifiStatus status = iface.stopSendingKeepAlivePackets(slot);
2553                 if (!ok(status)) return -1;
2554                 return 0;
2555             } catch (RemoteException e) {
2556                 handleRemoteException(e);
2557                 return -1;
2558             }
2559         }
2560     }
2561 
2562     /**
2563      * A fixed cmdId for our RssiMonitoring (we only do one at a time)
2564      */
2565     @VisibleForTesting
2566     static final int sRssiMonCmdId = 7551;
2567 
2568     /**
2569      * Our client's handler
2570      */
2571     private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler;
2572 
2573     /**
2574      * Start RSSI monitoring on the currently connected access point.
2575      *
2576      * @param ifaceName        Name of the interface.
2577      * @param maxRssi          Maximum RSSI threshold.
2578      * @param minRssi          Minimum RSSI threshold.
2579      * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
2580      * @return 0 for success, -1 for failure
2581      */
startRssiMonitoring(@onNull String ifaceName, byte maxRssi, byte minRssi, WifiNative.WifiRssiEventHandler rssiEventHandler)2582     public int startRssiMonitoring(@NonNull String ifaceName, byte maxRssi, byte minRssi,
2583                                    WifiNative.WifiRssiEventHandler rssiEventHandler) {
2584         enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush();
2585         if (maxRssi <= minRssi) return -1;
2586         if (rssiEventHandler == null) return -1;
2587         synchronized (sLock) {
2588             IWifiStaIface iface = getStaIface(ifaceName);
2589             if (iface == null) return -1;
2590             try {
2591                 iface.stopRssiMonitoring(sRssiMonCmdId);
2592                 WifiStatus status;
2593                 status = iface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi);
2594                 if (!ok(status)) return -1;
2595                 mWifiRssiEventHandler = rssiEventHandler;
2596                 return 0;
2597             } catch (RemoteException e) {
2598                 handleRemoteException(e);
2599                 return -1;
2600             }
2601         }
2602     }
2603 
2604     /**
2605      * Stop RSSI monitoring
2606      *
2607      * @param ifaceName Name of the interface.
2608      * @return 0 for success, -1 for failure
2609      */
stopRssiMonitoring(@onNull String ifaceName)2610     public int stopRssiMonitoring(@NonNull String ifaceName) {
2611         synchronized (sLock) {
2612             mWifiRssiEventHandler = null;
2613             IWifiStaIface iface = getStaIface(ifaceName);
2614             if (iface == null) return -1;
2615             try {
2616                 WifiStatus status = iface.stopRssiMonitoring(sRssiMonCmdId);
2617                 if (!ok(status)) return -1;
2618                 return 0;
2619             } catch (RemoteException e) {
2620                 handleRemoteException(e);
2621                 return -1;
2622             }
2623         }
2624     }
2625 
2626     //TODO - belongs in NativeUtil
intsFromArrayList(ArrayList<Integer> a)2627     private static int[] intsFromArrayList(ArrayList<Integer> a) {
2628         if (a == null) return null;
2629         int[] b = new int[a.size()];
2630         int i = 0;
2631         for (Integer e : a) b[i++] = e;
2632         return b;
2633     }
2634 
2635     /**
2636      * Translates from Hal version of wake reason stats to the framework version of same
2637      *
2638      * @param h - Hal version of wake reason stats
2639      * @return framework version of same
2640      */
halToFrameworkWakeReasons( WifiDebugHostWakeReasonStats h)2641     private static WlanWakeReasonAndCounts halToFrameworkWakeReasons(
2642             WifiDebugHostWakeReasonStats h) {
2643         if (h == null) return null;
2644         WlanWakeReasonAndCounts ans = new WlanWakeReasonAndCounts();
2645         ans.totalCmdEventWake = h.totalCmdEventWakeCnt;
2646         ans.totalDriverFwLocalWake = h.totalDriverFwLocalWakeCnt;
2647         ans.totalRxDataWake = h.totalRxPacketWakeCnt;
2648         ans.rxUnicast = h.rxPktWakeDetails.rxUnicastCnt;
2649         ans.rxMulticast = h.rxPktWakeDetails.rxMulticastCnt;
2650         ans.rxBroadcast = h.rxPktWakeDetails.rxBroadcastCnt;
2651         ans.icmp = h.rxIcmpPkWakeDetails.icmpPkt;
2652         ans.icmp6 = h.rxIcmpPkWakeDetails.icmp6Pkt;
2653         ans.icmp6Ra = h.rxIcmpPkWakeDetails.icmp6Ra;
2654         ans.icmp6Na = h.rxIcmpPkWakeDetails.icmp6Na;
2655         ans.icmp6Ns = h.rxIcmpPkWakeDetails.icmp6Ns;
2656         ans.ipv4RxMulticast = h.rxMulticastPkWakeDetails.ipv4RxMulticastAddrCnt;
2657         ans.ipv6Multicast = h.rxMulticastPkWakeDetails.ipv6RxMulticastAddrCnt;
2658         ans.otherRxMulticast = h.rxMulticastPkWakeDetails.otherRxMulticastAddrCnt;
2659         ans.cmdEventWakeCntArray = intsFromArrayList(h.cmdEventWakeCntPerType);
2660         ans.driverFWLocalWakeCntArray = intsFromArrayList(h.driverFwLocalWakeCntPerType);
2661         return ans;
2662     }
2663 
2664     /**
2665      * Fetch the host wakeup reasons stats from wlan driver.
2666      *
2667      * @return the |WlanWakeReasonAndCounts| from the wlan driver, or null on failure.
2668      */
getWlanWakeReasonCount()2669     public WlanWakeReasonAndCounts getWlanWakeReasonCount() {
2670         class AnswerBox {
2671             public WifiDebugHostWakeReasonStats value = null;
2672         }
2673         AnswerBox ans = new AnswerBox();
2674         synchronized (sLock) {
2675             if (mIWifiChip == null) return null;
2676             try {
2677                 mIWifiChip.getDebugHostWakeReasonStats((status, stats) -> {
2678                     if (ok(status)) {
2679                         ans.value = stats;
2680                     }
2681                 });
2682                 return halToFrameworkWakeReasons(ans.value);
2683             } catch (RemoteException e) {
2684                 handleRemoteException(e);
2685                 return null;
2686             }
2687         }
2688     }
2689 
2690     /**
2691      * Enable/Disable Neighbour discovery offload functionality in the firmware.
2692      *
2693      * @param ifaceName Name of the interface.
2694      * @param enabled true to enable, false to disable.
2695      * @return true for success, false for failure
2696      */
configureNeighborDiscoveryOffload(@onNull String ifaceName, boolean enabled)2697     public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) {
2698         enter("enabled=%").c(enabled).flush();
2699         synchronized (sLock) {
2700             IWifiStaIface iface = getStaIface(ifaceName);
2701             if (iface == null) return boolResult(false);
2702             try {
2703                 WifiStatus status = iface.enableNdOffload(enabled);
2704                 if (!ok(status)) return false;
2705             } catch (RemoteException e) {
2706                 handleRemoteException(e);
2707                 return false;
2708             }
2709         }
2710         return true;
2711     }
2712 
2713     // Firmware roaming control.
2714 
2715     /**
2716      * Query the firmware roaming capabilities.
2717      *
2718      * @param ifaceName Name of the interface.
2719      * @return capabilities object on success, null otherwise.
2720      */
2721     @Nullable
getRoamingCapabilities(@onNull String ifaceName)2722     public WifiNative.RoamingCapabilities getRoamingCapabilities(@NonNull String ifaceName) {
2723         synchronized (sLock) {
2724             IWifiStaIface iface = getStaIface(ifaceName);
2725             if (iface == null) return nullResult();
2726             try {
2727                 Mutable<Boolean> ok = new Mutable<>(false);
2728                 WifiNative.RoamingCapabilities out = new WifiNative.RoamingCapabilities();
2729                 iface.getRoamingCapabilities((status, cap) -> {
2730                     if (!ok(status)) return;
2731                     out.maxBlocklistSize = cap.maxBlacklistSize;
2732                     out.maxAllowlistSize = cap.maxWhitelistSize;
2733                     ok.value = true;
2734                 });
2735                 if (ok.value) {
2736                     return out;
2737                 } else {
2738                     return null;
2739                 }
2740             } catch (RemoteException e) {
2741                 handleRemoteException(e);
2742                 return null;
2743             }
2744         }
2745     }
2746 
2747     /**
2748      * Enable/disable firmware roaming.
2749      *
2750      * @param ifaceName Name of the interface.
2751      * @param state the intended roaming state
2752      * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE,
2753      *         or SET_FIRMWARE_ROAMING_BUSY
2754      */
enableFirmwareRoaming(@onNull String ifaceName, @WifiNative.RoamingEnableState int state)2755     public @WifiNative.RoamingEnableStatus int enableFirmwareRoaming(@NonNull String ifaceName,
2756             @WifiNative.RoamingEnableState int state) {
2757         synchronized (sLock) {
2758             IWifiStaIface iface = getStaIface(ifaceName);
2759             if (iface == null) return WifiNative.SET_FIRMWARE_ROAMING_FAILURE;
2760             try {
2761                 byte val;
2762                 switch (state) {
2763                     case WifiNative.DISABLE_FIRMWARE_ROAMING:
2764                         val = StaRoamingState.DISABLED;
2765                         break;
2766                     case WifiNative.ENABLE_FIRMWARE_ROAMING:
2767                         val = StaRoamingState.ENABLED;
2768                         break;
2769                     default:
2770                         mLog.err("enableFirmwareRoaming invalid argument %").c(state).flush();
2771                         return WifiNative.SET_FIRMWARE_ROAMING_FAILURE;
2772                 }
2773                 WifiStatus status = iface.setRoamingState(val);
2774                 if (ok(status)) {
2775                     return WifiNative.SET_FIRMWARE_ROAMING_SUCCESS;
2776                 } else if (status.code == WifiStatusCode.ERROR_BUSY) {
2777                     return WifiNative.SET_FIRMWARE_ROAMING_BUSY;
2778                 } else {
2779                     return WifiNative.SET_FIRMWARE_ROAMING_FAILURE;
2780                 }
2781             } catch (RemoteException e) {
2782                 handleRemoteException(e);
2783                 return WifiNative.SET_FIRMWARE_ROAMING_FAILURE;
2784             }
2785         }
2786     }
2787 
2788     /**
2789      * Set firmware roaming configurations.
2790      *
2791      * @param ifaceName Name of the interface.
2792      * @param config new roaming configuration object
2793      * @return true for success; false for failure
2794      */
configureRoaming(@onNull String ifaceName, WifiNative.RoamingConfig config)2795     public boolean configureRoaming(@NonNull String ifaceName, WifiNative.RoamingConfig config) {
2796         synchronized (sLock) {
2797             IWifiStaIface iface = getStaIface(ifaceName);
2798             if (iface == null) return boolResult(false);
2799             try {
2800                 StaRoamingConfig roamingConfig = new StaRoamingConfig();
2801 
2802                 // parse the blacklist BSSIDs if any
2803                 if (config.blocklistBssids != null) {
2804                     for (String bssid : config.blocklistBssids) {
2805                         byte[] mac = NativeUtil.macAddressToByteArray(bssid);
2806                         roamingConfig.bssidBlacklist.add(mac);
2807                     }
2808                 }
2809 
2810                 // parse the whitelist SSIDs if any
2811                 if (config.allowlistSsids != null) {
2812                     for (String ssidStr : config.allowlistSsids) {
2813                         byte[] ssid = NativeUtil.byteArrayFromArrayList(
2814                                 NativeUtil.decodeSsid(ssidStr));
2815                         // HIDL code is throwing InvalidArgumentException when ssidWhitelist has
2816                         // SSIDs with less than 32 byte length this is due to HAL definition of
2817                         // SSID declared it as 32-byte fixed length array. Thus pad additional
2818                         // bytes with 0's to pass SSIDs as byte arrays of 32 length
2819                         byte[] ssid_32 = new byte[32];
2820                         for (int i = 0; i < ssid.length; i++) {
2821                             ssid_32[i] = ssid[i];
2822                         }
2823                         roamingConfig.ssidWhitelist.add(ssid_32);
2824                     }
2825                 }
2826 
2827                 WifiStatus status = iface.configureRoaming(roamingConfig);
2828                 if (!ok(status)) return false;
2829             } catch (RemoteException e) {
2830                 handleRemoteException(e);
2831                 return false;
2832             } catch (IllegalArgumentException e) {
2833                 mLog.err("Illegal argument for roaming configuration").c(e.toString()).flush();
2834                 return false;
2835             }
2836             return true;
2837         }
2838     }
2839 
2840     /**
2841      * Method to mock out the V1_1 IWifiChip retrieval in unit tests.
2842      *
2843      * @return 1.1 IWifiChip object if the device is running the 1.1 wifi hal service, null
2844      * otherwise.
2845      */
getWifiChipForV1_1Mockable()2846     protected android.hardware.wifi.V1_1.IWifiChip getWifiChipForV1_1Mockable() {
2847         if (mIWifiChip == null) return null;
2848         return android.hardware.wifi.V1_1.IWifiChip.castFrom(mIWifiChip);
2849     }
2850 
2851     /**
2852      * Method to mock out the V1_2 IWifiChip retrieval in unit tests.
2853      *
2854      * @return 1.2 IWifiChip object if the device is running the 1.2 wifi hal service, null
2855      * otherwise.
2856      */
getWifiChipForV1_2Mockable()2857     protected android.hardware.wifi.V1_2.IWifiChip getWifiChipForV1_2Mockable() {
2858         if (mIWifiChip == null) return null;
2859         return android.hardware.wifi.V1_2.IWifiChip.castFrom(mIWifiChip);
2860     }
2861 
2862     /**
2863      * Method to mock out the V1_3 IWifiChip retrieval in unit tests.
2864      *
2865      * @return 1.3 IWifiChip object if the device is running the 1.3 wifi hal service, null
2866      * otherwise.
2867      */
getWifiChipForV1_3Mockable()2868     protected android.hardware.wifi.V1_3.IWifiChip getWifiChipForV1_3Mockable() {
2869         if (mIWifiChip == null) return null;
2870         return android.hardware.wifi.V1_3.IWifiChip.castFrom(mIWifiChip);
2871     }
2872 
2873     /**
2874      * Method to mock out the V1_4 IWifiChip retrieval in unit tests.
2875      *
2876      * @return 1.4 IWifiChip object if the device is running the 1.4 wifi hal service, null
2877      * otherwise.
2878      */
getWifiChipForV1_4Mockable()2879     protected android.hardware.wifi.V1_4.IWifiChip getWifiChipForV1_4Mockable() {
2880         if (mIWifiChip == null) return null;
2881         return android.hardware.wifi.V1_4.IWifiChip.castFrom(mIWifiChip);
2882     }
2883 
2884     /**
2885      * Method to mock out the V1_5 IWifiChip retrieval in unit tests.
2886      *
2887      * @return 1.5 IWifiChip object if the device is running the 1.5 wifi hal service, null
2888      * otherwise.
2889      */
getWifiChipForV1_5Mockable()2890     protected android.hardware.wifi.V1_5.IWifiChip getWifiChipForV1_5Mockable() {
2891         if (mIWifiChip == null) return null;
2892         return android.hardware.wifi.V1_5.IWifiChip.castFrom(mIWifiChip);
2893     }
2894 
2895     /**
2896      * Method to mock out the V1_2 IWifiStaIface retrieval in unit tests.
2897      *
2898      * @param ifaceName Name of the interface
2899      * @return 1.2 IWifiStaIface object if the device is running the 1.2 wifi hal service, null
2900      * otherwise.
2901      */
getWifiStaIfaceForV1_2Mockable( @onNull String ifaceName)2902     protected android.hardware.wifi.V1_2.IWifiStaIface getWifiStaIfaceForV1_2Mockable(
2903             @NonNull String ifaceName) {
2904         IWifiStaIface iface = getStaIface(ifaceName);
2905         if (iface == null) return null;
2906         return android.hardware.wifi.V1_2.IWifiStaIface.castFrom(iface);
2907     }
2908 
2909     /**
2910      * Method to mock out the V1_3 IWifiStaIface retrieval in unit tests.
2911      *
2912      * @param ifaceName Name of the interface
2913      * @return 1.3 IWifiStaIface object if the device is running the 1.3 wifi hal service, null
2914      * otherwise.
2915      */
getWifiStaIfaceForV1_3Mockable( @onNull String ifaceName)2916     protected android.hardware.wifi.V1_3.IWifiStaIface getWifiStaIfaceForV1_3Mockable(
2917             @NonNull String ifaceName) {
2918         IWifiStaIface iface = getStaIface(ifaceName);
2919         if (iface == null) return null;
2920         return android.hardware.wifi.V1_3.IWifiStaIface.castFrom(iface);
2921     }
2922 
2923     /**
2924      * Method to mock out the V1_5 IWifiStaIface retrieval in unit tests.
2925      *
2926      * @param ifaceName Name of the interface
2927      * @return 1.5 IWifiStaIface object if the device is running the 1.5 wifi hal service, null
2928      * otherwise.
2929      */
getWifiStaIfaceForV1_5Mockable( @onNull String ifaceName)2930     protected android.hardware.wifi.V1_5.IWifiStaIface getWifiStaIfaceForV1_5Mockable(
2931             @NonNull String ifaceName) {
2932         IWifiStaIface iface = getStaIface(ifaceName);
2933         if (iface == null) return null;
2934         return android.hardware.wifi.V1_5.IWifiStaIface.castFrom(iface);
2935     }
2936 
getWifiApIfaceForV1_4Mockable( String ifaceName)2937     protected android.hardware.wifi.V1_4.IWifiApIface getWifiApIfaceForV1_4Mockable(
2938             String ifaceName) {
2939         IWifiApIface iface = getApIface(ifaceName);
2940         if (iface == null) return null;
2941         return android.hardware.wifi.V1_4.IWifiApIface.castFrom(iface);
2942     }
2943 
getWifiApIfaceForV1_5Mockable( String ifaceName)2944     protected android.hardware.wifi.V1_5.IWifiApIface getWifiApIfaceForV1_5Mockable(
2945             String ifaceName) {
2946         IWifiApIface iface = getApIface(ifaceName);
2947         if (iface == null) return null;
2948         return android.hardware.wifi.V1_5.IWifiApIface.castFrom(iface);
2949     }
2950 
2951     /**
2952      * sarPowerBackoffRequired_1_1()
2953      * This method checks if we need to backoff wifi Tx power due to SAR requirements.
2954      * It handles the case when the device is running the V1_1 version of WifiChip HAL
2955      * In that HAL version, it is required to perform wifi Tx power backoff only if
2956      * a voice call is ongoing.
2957      */
sarPowerBackoffRequired_1_1(SarInfo sarInfo)2958     private boolean sarPowerBackoffRequired_1_1(SarInfo sarInfo) {
2959         /* As long as no voice call is active (in case voice call is supported),
2960          * no backoff is needed */
2961         if (sarInfo.sarVoiceCallSupported) {
2962             return (sarInfo.isVoiceCall || sarInfo.isEarPieceActive);
2963         } else {
2964             return false;
2965         }
2966     }
2967 
2968     /**
2969      * frameworkToHalTxPowerScenario_1_1()
2970      * This method maps the information inside the SarInfo instance into a SAR scenario
2971      * when device is running the V1_1 version of WifiChip HAL.
2972      * In this HAL version, only one scenario is defined which is for VOICE_CALL (if voice call is
2973      * supported).
2974      * Otherwise, an exception is thrown.
2975      */
frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo)2976     private int frameworkToHalTxPowerScenario_1_1(SarInfo sarInfo) {
2977         if (sarInfo.sarVoiceCallSupported && (sarInfo.isVoiceCall || sarInfo.isEarPieceActive)) {
2978             return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL;
2979         } else {
2980             throw new IllegalArgumentException("bad scenario: voice call not active/supported");
2981         }
2982     }
2983 
2984     /**
2985      * sarPowerBackoffRequired_1_2()
2986      * This method checks if we need to backoff wifi Tx power due to SAR requirements.
2987      * It handles the case when the device is running the V1_2 version of WifiChip HAL
2988      */
sarPowerBackoffRequired_1_2(SarInfo sarInfo)2989     private boolean sarPowerBackoffRequired_1_2(SarInfo sarInfo) {
2990         if (sarInfo.sarSapSupported && sarInfo.isWifiSapEnabled) {
2991             return true;
2992         }
2993         if (sarInfo.sarVoiceCallSupported && (sarInfo.isVoiceCall || sarInfo.isEarPieceActive)) {
2994             return true;
2995         }
2996         return false;
2997     }
2998 
2999     /**
3000      * frameworkToHalTxPowerScenario_1_2()
3001      * This method maps the information inside the SarInfo instance into a SAR scenario
3002      * when device is running the V1_2 version of WifiChip HAL.
3003      * If SAR SoftAP input is supported,
3004      * we make these assumptions:
3005      *   - All voice calls are treated as if device is near the head.
3006      *   - SoftAP scenario is treated as if device is near the body.
3007      * In case SoftAP is not supported, then we should revert to the V1_1 HAL
3008      * behavior, and the only valid scenario would be when a voice call is ongoing.
3009      */
frameworkToHalTxPowerScenario_1_2(SarInfo sarInfo)3010     private int frameworkToHalTxPowerScenario_1_2(SarInfo sarInfo) {
3011         if (sarInfo.sarSapSupported && sarInfo.sarVoiceCallSupported) {
3012             if (sarInfo.isVoiceCall || sarInfo.isEarPieceActive) {
3013                 return android.hardware.wifi.V1_2.IWifiChip
3014                         .TxPowerScenario.ON_HEAD_CELL_ON;
3015             } else if (sarInfo.isWifiSapEnabled) {
3016                 return android.hardware.wifi.V1_2.IWifiChip
3017                         .TxPowerScenario.ON_BODY_CELL_ON;
3018             } else {
3019                 throw new IllegalArgumentException("bad scenario: no voice call/softAP active");
3020             }
3021         } else if (sarInfo.sarVoiceCallSupported) {
3022             /* SAR SoftAP input not supported, act like V1_1 */
3023             if (sarInfo.isVoiceCall || sarInfo.isEarPieceActive) {
3024                 return android.hardware.wifi.V1_1.IWifiChip.TxPowerScenario.VOICE_CALL;
3025             } else {
3026                 throw new IllegalArgumentException("bad scenario: voice call not active");
3027             }
3028         } else {
3029             throw new IllegalArgumentException("Invalid case: voice call not supported");
3030         }
3031     }
3032 
3033     /**
3034      * Select one of the pre-configured TX power level scenarios or reset it back to normal.
3035      * Primarily used for meeting SAR requirements during voice calls.
3036      *
3037      * Note: If it was found out that the scenario to be reported is the same as last reported one,
3038      *       then exit with success.
3039      *       This is to handle the case when some HAL versions deal with different inputs equally,
3040      *       in that case, we should not call the hal unless there is a change in scenario.
3041      * Note: It is assumed that this method is only called if SAR is enabled. The logic of whether
3042      *       to call it or not resides in SarManager class.
3043      *
3044      * @param sarInfo The collection of inputs to select the SAR scenario.
3045      * @return true for success; false for failure or if the HAL version does not support this API.
3046      */
selectTxPowerScenario(SarInfo sarInfo)3047     public boolean selectTxPowerScenario(SarInfo sarInfo) {
3048         synchronized (sLock) {
3049             // First attempt to get a V_1_2 instance of the Wifi HAL.
3050             android.hardware.wifi.V1_2.IWifiChip iWifiChipV12 = getWifiChipForV1_2Mockable();
3051             if (iWifiChipV12 != null) {
3052                 return selectTxPowerScenario_1_2(iWifiChipV12, sarInfo);
3053             }
3054 
3055             // Now attempt to get a V_1_1 instance of the Wifi HAL.
3056             android.hardware.wifi.V1_1.IWifiChip iWifiChipV11 = getWifiChipForV1_1Mockable();
3057             if (iWifiChipV11 != null) {
3058                 return selectTxPowerScenario_1_1(iWifiChipV11, sarInfo);
3059             }
3060 
3061             // HAL version does not support SAR
3062             return false;
3063         }
3064     }
3065 
selectTxPowerScenario_1_1( android.hardware.wifi.V1_1.IWifiChip iWifiChip, SarInfo sarInfo)3066     private boolean selectTxPowerScenario_1_1(
3067             android.hardware.wifi.V1_1.IWifiChip iWifiChip, SarInfo sarInfo) {
3068         WifiStatus status;
3069         try {
3070             if (sarPowerBackoffRequired_1_1(sarInfo)) {
3071                 // Power backoff is needed, so calculate the required scenario,
3072                 // and attempt to set it.
3073                 int halScenario = frameworkToHalTxPowerScenario_1_1(sarInfo);
3074                 if (sarInfo.setSarScenarioNeeded(halScenario)) {
3075                     status = iWifiChip.selectTxPowerScenario(halScenario);
3076                     if (ok(status)) {
3077                         mLog.d("Setting SAR scenario to " + halScenario);
3078                         return true;
3079                     } else {
3080                         mLog.e("Failed to set SAR scenario to " + halScenario);
3081                         return false;
3082                     }
3083                 }
3084 
3085                 // Reaching here means setting SAR scenario would be redundant,
3086                 // do nothing and return with success.
3087                 return true;
3088             }
3089 
3090             // We don't need to perform power backoff, so attempt to reset SAR scenario.
3091             if (sarInfo.resetSarScenarioNeeded()) {
3092                 status = iWifiChip.resetTxPowerScenario();
3093                 if (ok(status)) {
3094                     mLog.d("Resetting SAR scenario");
3095                     return true;
3096                 } else {
3097                     mLog.e("Failed to reset SAR scenario");
3098                     return false;
3099                 }
3100             }
3101 
3102             // Resetting SAR scenario would be redundant,
3103             // do nothing and return with success.
3104             return true;
3105         } catch (RemoteException e) {
3106             handleRemoteException(e);
3107             return false;
3108         } catch (IllegalArgumentException e) {
3109             mLog.err("Illegal argument for selectTxPowerScenario_1_1()").c(e.toString()).flush();
3110             return false;
3111         }
3112     }
3113 
selectTxPowerScenario_1_2( android.hardware.wifi.V1_2.IWifiChip iWifiChip, SarInfo sarInfo)3114     private boolean selectTxPowerScenario_1_2(
3115             android.hardware.wifi.V1_2.IWifiChip iWifiChip, SarInfo sarInfo) {
3116         WifiStatus status;
3117         try {
3118             if (sarPowerBackoffRequired_1_2(sarInfo)) {
3119                 // Power backoff is needed, so calculate the required scenario,
3120                 // and attempt to set it.
3121                 int halScenario = frameworkToHalTxPowerScenario_1_2(sarInfo);
3122                 if (sarInfo.setSarScenarioNeeded(halScenario)) {
3123                     status = iWifiChip.selectTxPowerScenario_1_2(halScenario);
3124                     if (ok(status)) {
3125                         mLog.d("Setting SAR scenario to " + halScenario);
3126                         return true;
3127                     } else {
3128                         mLog.e("Failed to set SAR scenario to " + halScenario);
3129                         return false;
3130                     }
3131                 }
3132 
3133                 // Reaching here means setting SAR scenario would be redundant,
3134                 // do nothing and return with success.
3135                 return true;
3136             }
3137 
3138             // We don't need to perform power backoff, so attempt to reset SAR scenario.
3139             if (sarInfo.resetSarScenarioNeeded()) {
3140                 status = iWifiChip.resetTxPowerScenario();
3141                 if (ok(status)) {
3142                     mLog.d("Resetting SAR scenario");
3143                     return true;
3144                 } else {
3145                     mLog.e("Failed to reset SAR scenario");
3146                     return false;
3147                 }
3148             }
3149 
3150             // Resetting SAR scenario would be redundant,
3151             // do nothing and return with success.
3152             return true;
3153         } catch (RemoteException e) {
3154             handleRemoteException(e);
3155             return false;
3156         } catch (IllegalArgumentException e) {
3157             mLog.err("Illegal argument for selectTxPowerScenario_1_2()").c(e.toString()).flush();
3158             return false;
3159         }
3160     }
3161 
3162     /**
3163      * Enable/Disable low-latency mode
3164      *
3165      * @param enabled true to enable low-latency mode, false to disable it
3166      */
setLowLatencyMode(boolean enabled)3167     public boolean setLowLatencyMode(boolean enabled) {
3168         synchronized (sLock) {
3169             android.hardware.wifi.V1_3.IWifiChip iWifiChipV13 = getWifiChipForV1_3Mockable();
3170             if (iWifiChipV13 != null) {
3171                 try {
3172                     int mode;
3173                     if (enabled) {
3174                         mode = android.hardware.wifi.V1_3.IWifiChip.LatencyMode.LOW;
3175                     } else {
3176                         mode = android.hardware.wifi.V1_3.IWifiChip.LatencyMode.NORMAL;
3177                     }
3178 
3179                     WifiStatus status = iWifiChipV13.setLatencyMode(mode);
3180                     if (ok(status)) {
3181                         mVerboseLog.d("Setting low-latency mode to " + enabled);
3182                         return true;
3183                     } else {
3184                         mLog.e("Failed to set low-latency mode to " + enabled);
3185                         return false;
3186                     }
3187                 } catch (RemoteException e) {
3188                     handleRemoteException(e);
3189                     return false;
3190                 }
3191             }
3192 
3193             // HAL version does not support this api
3194             return false;
3195         }
3196     }
3197 
3198     /**
3199      * Returns whether STA + AP concurrency is supported or not.
3200      */
isStaApConcurrencySupported()3201     public boolean isStaApConcurrencySupported() {
3202         synchronized (sLock) {
3203             return mHalDeviceManager.canSupportIfaceCombo(new SparseArray<Integer>() {{
3204                     put(IfaceType.STA, 1);
3205                     put(IfaceType.AP, 1);
3206                 }});
3207         }
3208     }
3209 
3210     /**
3211      * Returns whether STA + STA concurrency is supported or not.
3212      */
3213     public boolean isStaStaConcurrencySupported() {
3214         synchronized (sLock) {
3215             return mHalDeviceManager.canSupportIfaceCombo(new SparseArray<Integer>() {{
3216                     put(IfaceType.STA, 2);
3217                 }});
3218         }
3219     }
3220 
3221     /**
3222      * Returns whether a new AP iface can be created or not.
3223      */
3224     public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) {
3225         synchronized (sLock) {
3226             return mHalDeviceManager.isItPossibleToCreateIface(IfaceType.AP, requestorWs);
3227         }
3228     }
3229 
3230     /**
3231      * Returns whether a new STA iface can be created or not.
3232      */
3233     public boolean isItPossibleToCreateStaIface(@NonNull WorkSource requestorWs) {
3234         synchronized (sLock) {
3235             return mHalDeviceManager.isItPossibleToCreateIface(IfaceType.STA, requestorWs);
3236         }
3237 
3238     }
3239     /**
3240      * Set primary connection when multiple STA ifaces are active.
3241      *
3242      * @param ifaceName Name of the interface.
3243      * @return true for success
3244      */
3245     public boolean setMultiStaPrimaryConnection(@NonNull String ifaceName) {
3246         if (TextUtils.isEmpty(ifaceName)) return boolResult(false);
3247         synchronized (sLock) {
3248             try {
3249                 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
3250                 if (iWifiChipV15 == null) return boolResult(false);
3251                 WifiStatus status = iWifiChipV15.setMultiStaPrimaryConnection(ifaceName);
3252                 if (!ok(status)) return false;
3253                 return true;
3254             } catch (RemoteException e) {
3255                 handleRemoteException(e);
3256                 return false;
3257             }
3258         }
3259     }
3260 
3261     private byte frameworkMultiStaUseCaseToHidl(@WifiNative.MultiStaUseCase int useCase)
3262             throws IllegalArgumentException {
3263         switch (useCase) {
3264             case WifiNative.DUAL_STA_TRANSIENT_PREFER_PRIMARY:
3265                 return MultiStaUseCase.DUAL_STA_TRANSIENT_PREFER_PRIMARY;
3266             case WifiNative.DUAL_STA_NON_TRANSIENT_UNBIASED:
3267                 return MultiStaUseCase.DUAL_STA_NON_TRANSIENT_UNBIASED;
3268             default:
3269                 throw new IllegalArgumentException("Invalid use case " + useCase);
3270         }
3271     }
3272 
3273     /**
3274      * Set use-case when multiple STA ifaces are active.
3275      *
3276      * @param useCase one of the use cases.
3277      * @return true for success
3278      */
3279     public boolean setMultiStaUseCase(@WifiNative.MultiStaUseCase int useCase) {
3280         synchronized (sLock) {
3281             try {
3282                 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
3283                 if (iWifiChipV15 == null) return boolResult(false);
3284                 WifiStatus status = iWifiChipV15.setMultiStaUseCase(
3285                         frameworkMultiStaUseCaseToHidl(useCase));
3286                 if (!ok(status)) return false;
3287                 return true;
3288             } catch (IllegalArgumentException e) {
3289                 mLog.e("Invalid use case " + e);
3290                 return boolResult(false);
3291             } catch (RemoteException e) {
3292                 handleRemoteException(e);
3293                 return false;
3294             }
3295         }
3296     }
3297 
3298     /**
3299      * Notify scan mode state to driver to save power in scan-only mode.
3300      *
3301      * @param ifaceName Name of the interface.
3302      * @param enable whether is in scan-only mode
3303      * @return true for success
3304      */
3305     public boolean setScanMode(@NonNull String ifaceName, boolean enable) {
3306         synchronized (sLock) {
3307             try {
3308                 android.hardware.wifi.V1_5.IWifiStaIface iface =
3309                         getWifiStaIfaceForV1_5Mockable(ifaceName);
3310                 if (iface != null) {
3311                     WifiStatus status = iface.setScanMode(enable);
3312                     if (!ok(status)) return false;
3313                     return true;
3314                 }
3315                 return false;
3316             } catch (RemoteException e) {
3317                 handleRemoteException(e);
3318                 return false;
3319             }
3320         }
3321     }
3322 
3323     // This creates a blob of IE elements from the array received.
3324     // TODO: This ugly conversion can be removed if we put IE elements in ScanResult.
3325     private static byte[] hidlIeArrayToFrameworkIeBlob(ArrayList<WifiInformationElement> ies) {
3326         if (ies == null || ies.isEmpty()) return new byte[0];
3327         ArrayList<Byte> ieBlob = new ArrayList<>();
3328         for (WifiInformationElement ie : ies) {
3329             ieBlob.add(ie.id);
3330             ieBlob.addAll(ie.data);
3331         }
3332         return NativeUtil.byteArrayFromArrayList(ieBlob);
3333     }
3334 
3335     // This is only filling up the fields of Scan Result used by Gscan clients.
3336     private static ScanResult hidlToFrameworkScanResult(StaScanResult scanResult) {
3337         if (scanResult == null) return null;
3338         ScanResult frameworkScanResult = new ScanResult();
3339         frameworkScanResult.SSID = NativeUtil.encodeSsid(scanResult.ssid);
3340         frameworkScanResult.wifiSsid =
3341                 WifiSsid.createFromByteArray(NativeUtil.byteArrayFromArrayList(scanResult.ssid));
3342         frameworkScanResult.BSSID = NativeUtil.macAddressFromByteArray(scanResult.bssid);
3343         frameworkScanResult.level = scanResult.rssi;
3344         frameworkScanResult.frequency = scanResult.frequency;
3345         frameworkScanResult.timestamp = scanResult.timeStampInUs;
3346         return frameworkScanResult;
3347     }
3348 
3349     private static ScanResult[] hidlToFrameworkScanResults(ArrayList<StaScanResult> scanResults) {
3350         if (scanResults == null || scanResults.isEmpty()) return new ScanResult[0];
3351         ScanResult[] frameworkScanResults = new ScanResult[scanResults.size()];
3352         int i = 0;
3353         for (StaScanResult scanResult : scanResults) {
3354             frameworkScanResults[i++] = hidlToFrameworkScanResult(scanResult);
3355         }
3356         return frameworkScanResults;
3357     }
3358 
3359     /**
3360      * This just returns whether the scan was interrupted or not.
3361      */
3362     private static int hidlToFrameworkScanDataFlags(int flag) {
3363         if (flag == StaScanDataFlagMask.INTERRUPTED) {
3364             return 1;
3365         } else {
3366             return 0;
3367         }
3368     }
3369 
3370     private static WifiScanner.ScanData[] hidlToFrameworkScanDatas(
3371             int cmdId, ArrayList<StaScanData> scanDatas) {
3372         if (scanDatas == null || scanDatas.isEmpty()) return new WifiScanner.ScanData[0];
3373         WifiScanner.ScanData[] frameworkScanDatas = new WifiScanner.ScanData[scanDatas.size()];
3374         int i = 0;
3375         for (StaScanData scanData : scanDatas) {
3376             int flags = hidlToFrameworkScanDataFlags(scanData.flags);
3377             ScanResult[] frameworkScanResults = hidlToFrameworkScanResults(scanData.results);
3378             frameworkScanDatas[i++] =
3379                     new WifiScanner.ScanData(cmdId, flags, scanData.bucketsScanned,
3380                             WifiScanner.WIFI_BAND_UNSPECIFIED, frameworkScanResults);
3381         }
3382         return frameworkScanDatas;
3383     }
3384 
3385     /**
3386      * Callback for events on the STA interface.
3387      */
3388     private class StaIfaceEventCallback extends IWifiStaIfaceEventCallback.Stub {
3389         @Override
3390         public void onBackgroundScanFailure(int cmdId) {
3391             mVerboseLog.d("onBackgroundScanFailure " + cmdId);
3392             WifiNative.ScanEventHandler eventHandler;
3393             synchronized (sLock) {
3394                 if (mScan == null || cmdId != mScan.cmdId) return;
3395                 eventHandler = mScan.eventHandler;
3396             }
3397             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
3398         }
3399 
3400         @Override
3401         public void onBackgroundFullScanResult(
3402                 int cmdId, int bucketsScanned, StaScanResult result) {
3403             mVerboseLog.d("onBackgroundFullScanResult " + cmdId);
3404             WifiNative.ScanEventHandler eventHandler;
3405             synchronized (sLock) {
3406                 if (mScan == null || cmdId != mScan.cmdId) return;
3407                 eventHandler = mScan.eventHandler;
3408             }
3409             eventHandler.onFullScanResult(hidlToFrameworkScanResult(result), bucketsScanned);
3410         }
3411 
3412         @Override
3413         public void onBackgroundScanResults(int cmdId, ArrayList<StaScanData> scanDatas) {
3414             mVerboseLog.d("onBackgroundScanResults " + cmdId);
3415             WifiNative.ScanEventHandler eventHandler;
3416             // WifiScanner currently uses the results callback to fetch the scan results.
3417             // So, simulate that by sending out the notification and then caching the results
3418             // locally. This will then be returned to WifiScanner via getScanResults.
3419             synchronized (sLock) {
3420                 if (mScan == null || cmdId != mScan.cmdId) return;
3421                 eventHandler = mScan.eventHandler;
3422                 mScan.latestScanResults = hidlToFrameworkScanDatas(cmdId, scanDatas);
3423             }
3424             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
3425         }
3426 
3427         @Override
3428         public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
3429             mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
3430             WifiNative.WifiRssiEventHandler eventHandler;
3431             synchronized (sLock) {
3432                 if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return;
3433                 eventHandler = mWifiRssiEventHandler;
3434             }
3435             eventHandler.onRssiThresholdBreached((byte) currRssi);
3436         }
3437     }
3438 
3439     /**
3440      * Callback for events on the chip.
3441      */
3442     private class ChipEventCallback extends IWifiChipEventCallback.Stub {
3443         @Override
3444         public void onChipReconfigured(int modeId) {
3445             mVerboseLog.d("onChipReconfigured " + modeId);
3446         }
3447 
3448         @Override
3449         public void onChipReconfigureFailure(WifiStatus status) {
3450             mVerboseLog.d("onChipReconfigureFailure " + status);
3451         }
3452 
3453         public void onIfaceAdded(int type, String name) {
3454             mVerboseLog.d("onIfaceAdded " + type + ", name: " + name);
3455         }
3456 
3457         @Override
3458         public void onIfaceRemoved(int type, String name) {
3459             mVerboseLog.d("onIfaceRemoved " + type + ", name: " + name);
3460         }
3461 
3462         @Override
3463         public void onDebugRingBufferDataAvailable(
3464                 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
3465             //TODO(b/35875078) Reinstate logging when execessive callbacks are fixed
3466             // mVerboseLog.d("onDebugRingBufferDataAvailable " + status);
3467             mHalEventHandler.post(() -> {
3468                 WifiNative.WifiLoggerEventHandler eventHandler;
3469                 synchronized (sLock) {
3470                     if (mLogEventHandler == null || status == null || data == null) return;
3471                     eventHandler = mLogEventHandler;
3472                 }
3473                 // Because |sLock| has been released, there is a chance that we'll execute
3474                 // a spurious callback (after someone has called resetLogHandler()).
3475                 //
3476                 // However, the alternative risks deadlock. Consider:
3477                 // [T1.1] WifiDiagnostics.captureBugReport()
3478                 // [T1.2] -- acquire WifiDiagnostics object's intrinsic lock
3479                 // [T1.3]    -> WifiVendorHal.getRingBufferData()
3480                 // [T1.4]       -- acquire WifiVendorHal.sLock
3481                 // [T2.1] <lambda>()
3482                 // [T2.2] -- acquire WifiVendorHal.sLock
3483                 // [T2.3]    -> WifiDiagnostics.onRingBufferData()
3484                 // [T2.4]       -- acquire WifiDiagnostics object's intrinsic lock
3485                 //
3486                 // The problem here is that the two threads acquire the locks in opposite order.
3487                 // If, for example, T2.2 executes between T1.2 and 1.4, then T1 and T2
3488                 // will be deadlocked.
3489                 int sizeBefore = data.size();
3490                 boolean conversionFailure = false;
3491                 try {
3492                     eventHandler.onRingBufferData(
3493                             ringBufferStatus(status), NativeUtil.byteArrayFromArrayList(data));
3494                     int sizeAfter = data.size();
3495                     if (sizeAfter != sizeBefore) {
3496                         conversionFailure = true;
3497                     }
3498                 } catch (ArrayIndexOutOfBoundsException e) {
3499                     conversionFailure = true;
3500                 }
3501                 if (conversionFailure) {
3502                     Log.wtf("WifiVendorHal", "Conversion failure detected in "
3503                             + "onDebugRingBufferDataAvailable. "
3504                             + "The input ArrayList |data| is potentially corrupted. "
3505                             + "Starting size=" + sizeBefore + ", "
3506                             + "final size=" + data.size());
3507                 }
3508             });
3509         }
3510 
3511         @Override
3512         public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
3513             mLog.w("onDebugErrorAlert " + errorCode);
3514             mHalEventHandler.post(() -> {
3515                 WifiNative.WifiLoggerEventHandler eventHandler;
3516                 synchronized (sLock) {
3517                     if (mLogEventHandler == null || debugData == null) return;
3518                     eventHandler = mLogEventHandler;
3519                 }
3520                 // See comment in onDebugRingBufferDataAvailable(), for an explanation
3521                 // of why this callback is invoked without |sLock| held.
3522                 eventHandler.onWifiAlert(
3523                         errorCode, NativeUtil.byteArrayFromArrayList(debugData));
3524             });
3525         }
3526     }
3527 
3528     private boolean areSameIfaceNames(List<IfaceInfo> ifaceList1, List<IfaceInfo> ifaceList2) {
3529         List<String> ifaceNamesList1 = ifaceList1
3530                 .stream()
3531                 .map(i -> i.name)
3532                 .collect(Collectors.toList());
3533         List<String> ifaceNamesList2 = ifaceList2
3534                 .stream()
3535                 .map(i -> i.name)
3536                 .collect(Collectors.toList());
3537         return ifaceNamesList1.containsAll(ifaceNamesList2);
3538     }
3539 
3540     /**
3541      * Callback for events on the 1.2 chip.
3542      */
3543     private class ChipEventCallbackV12 extends
3544             android.hardware.wifi.V1_2.IWifiChipEventCallback.Stub {
3545         @Override
3546         public void onChipReconfigured(int modeId) {
3547             mIWifiChipEventCallback.onChipReconfigured(modeId);
3548         }
3549 
3550         @Override
3551         public void onChipReconfigureFailure(WifiStatus status) {
3552             mIWifiChipEventCallback.onChipReconfigureFailure(status);
3553         }
3554 
3555         public void onIfaceAdded(int type, String name) {
3556             mIWifiChipEventCallback.onIfaceAdded(type, name);
3557         }
3558 
3559         @Override
3560         public void onIfaceRemoved(int type, String name) {
3561             mIWifiChipEventCallback.onIfaceRemoved(type, name);
3562         }
3563 
3564         @Override
3565         public void onDebugRingBufferDataAvailable(
3566                 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
3567             mIWifiChipEventCallback.onDebugRingBufferDataAvailable(status, data);
3568         }
3569 
3570         @Override
3571         public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
3572             mIWifiChipEventCallback.onDebugErrorAlert(errorCode, debugData);
3573         }
3574 
3575         @Override
3576         public void onRadioModeChange(ArrayList<RadioModeInfo> radioModeInfoList) {
3577             mVerboseLog.d("onRadioModeChange " + radioModeInfoList);
3578             WifiNative.VendorHalRadioModeChangeEventHandler handler;
3579             synchronized (sLock) {
3580                 if (mRadioModeChangeEventHandler == null || radioModeInfoList == null) return;
3581                 handler = mRadioModeChangeEventHandler;
3582             }
3583             // Should only contain 1 or 2 radio infos.
3584             if (radioModeInfoList.size() == 0 || radioModeInfoList.size() > 2) {
3585                 mLog.e("Unexpected number of radio info in list " + radioModeInfoList.size());
3586                 return;
3587             }
3588             RadioModeInfo radioModeInfo0 = radioModeInfoList.get(0);
3589             RadioModeInfo radioModeInfo1 =
3590                     radioModeInfoList.size() == 2 ? radioModeInfoList.get(1) : null;
3591             // Number of ifaces on each radio should be equal.
3592             if (radioModeInfo1 != null
3593                     && radioModeInfo0.ifaceInfos.size() != radioModeInfo1.ifaceInfos.size()) {
3594                 mLog.e("Unexpected number of iface info in list "
3595                         + radioModeInfo0.ifaceInfos.size() + ", "
3596                         + radioModeInfo1.ifaceInfos.size());
3597                 return;
3598             }
3599             int numIfacesOnEachRadio = radioModeInfo0.ifaceInfos.size();
3600             // Only 1 or 2 ifaces should be present on each radio.
3601             if (numIfacesOnEachRadio == 0 || numIfacesOnEachRadio > 2) {
3602                 mLog.e("Unexpected number of iface info in list " + numIfacesOnEachRadio);
3603                 return;
3604             }
3605             Runnable runnable = null;
3606             // 2 ifaces simultaneous on 2 radios.
3607             if (radioModeInfoList.size() == 2 && numIfacesOnEachRadio == 1) {
3608                 // Iface on radio0 should be different from the iface on radio1 for DBS & SBS.
3609                 if (areSameIfaceNames(radioModeInfo0.ifaceInfos, radioModeInfo1.ifaceInfos)) {
3610                     mLog.e("Unexpected for both radio infos to have same iface");
3611                     return;
3612                 }
3613                 if (radioModeInfo0.bandInfo != radioModeInfo1.bandInfo) {
3614                     runnable = () -> {
3615                         handler.onDbs();
3616                     };
3617                 } else {
3618                     runnable = () -> {
3619                         handler.onSbs(radioModeInfo0.bandInfo);
3620                     };
3621                 }
3622             // 2 ifaces time sharing on 1 radio.
3623             } else if (radioModeInfoList.size() == 1 && numIfacesOnEachRadio == 2) {
3624                 IfaceInfo ifaceInfo0 = radioModeInfo0.ifaceInfos.get(0);
3625                 IfaceInfo ifaceInfo1 = radioModeInfo0.ifaceInfos.get(1);
3626                 if (ifaceInfo0.channel != ifaceInfo1.channel) {
3627                     runnable = () -> {
3628                         handler.onMcc(radioModeInfo0.bandInfo);
3629                     };
3630                 } else {
3631                     runnable = () -> {
3632                         handler.onScc(radioModeInfo0.bandInfo);
3633                     };
3634                 }
3635             } else {
3636                 // Not concurrency scenario, uninteresting...
3637             }
3638             if (runnable != null) mHalEventHandler.post(runnable);
3639         }
3640     }
3641 
3642     /**
3643      * Callback for events on the 1.4 chip.
3644      */
3645     private class ChipEventCallbackV14 extends
3646             android.hardware.wifi.V1_4.IWifiChipEventCallback.Stub {
3647         @Override
3648         public void onChipReconfigured(int modeId) {
3649             mIWifiChipEventCallback.onChipReconfigured(modeId);
3650         }
3651 
3652         @Override
3653         public void onChipReconfigureFailure(WifiStatus status) {
3654             mIWifiChipEventCallback.onChipReconfigureFailure(status);
3655         }
3656 
3657         public void onIfaceAdded(int type, String name) {
3658             mIWifiChipEventCallback.onIfaceAdded(type, name);
3659         }
3660 
3661         @Override
3662         public void onIfaceRemoved(int type, String name) {
3663             mIWifiChipEventCallback.onIfaceRemoved(type, name);
3664         }
3665 
3666         @Override
3667         public void onDebugRingBufferDataAvailable(
3668                 WifiDebugRingBufferStatus status, java.util.ArrayList<Byte> data) {
3669             mIWifiChipEventCallback.onDebugRingBufferDataAvailable(status, data);
3670         }
3671 
3672         @Override
3673         public void onDebugErrorAlert(int errorCode, java.util.ArrayList<Byte> debugData) {
3674             mIWifiChipEventCallback.onDebugErrorAlert(errorCode, debugData);
3675         }
3676 
3677         @Override
3678         public void onRadioModeChange(
3679                 ArrayList<android.hardware.wifi.V1_2.IWifiChipEventCallback.RadioModeInfo>
3680                 radioModeInfoList) {
3681             mIWifiChipEventCallbackV12.onRadioModeChange(radioModeInfoList);
3682         }
3683 
3684         @Override
3685         public void onRadioModeChange_1_4(ArrayList<RadioModeInfo> radioModeInfoList) {
3686             mVerboseLog.d("onRadioModeChange_1_4 " + radioModeInfoList);
3687             WifiNative.VendorHalRadioModeChangeEventHandler handler;
3688             synchronized (sLock) {
3689                 if (mRadioModeChangeEventHandler == null || radioModeInfoList == null) return;
3690                 handler = mRadioModeChangeEventHandler;
3691             }
3692             // Should only contain 1 or 2 radio infos.
3693             if (radioModeInfoList.size() == 0 || radioModeInfoList.size() > 2) {
3694                 mLog.e("Unexpected number of radio info in list " + radioModeInfoList.size());
3695                 return;
3696             }
3697             RadioModeInfo radioModeInfo0 = radioModeInfoList.get(0);
3698             RadioModeInfo radioModeInfo1 =
3699                     radioModeInfoList.size() == 2 ? radioModeInfoList.get(1) : null;
3700             // Number of ifaces on each radio should be equal.
3701             if (radioModeInfo1 != null
3702                     && radioModeInfo0.ifaceInfos.size() != radioModeInfo1.ifaceInfos.size()) {
3703                 mLog.e("Unexpected number of iface info in list "
3704                         + radioModeInfo0.ifaceInfos.size() + ", "
3705                         + radioModeInfo1.ifaceInfos.size());
3706                 return;
3707             }
3708             int numIfacesOnEachRadio = radioModeInfo0.ifaceInfos.size();
3709             // Only 1 or 2 ifaces should be present on each radio.
3710             if (numIfacesOnEachRadio == 0 || numIfacesOnEachRadio > 2) {
3711                 mLog.e("Unexpected number of iface info in list " + numIfacesOnEachRadio);
3712                 return;
3713             }
3714             Runnable runnable = null;
3715             // 2 ifaces simultaneous on 2 radios.
3716             if (radioModeInfoList.size() == 2 && numIfacesOnEachRadio == 1) {
3717                 // Iface on radio0 should be different from the iface on radio1 for DBS & SBS.
3718                 if (areSameIfaceNames(radioModeInfo0.ifaceInfos, radioModeInfo1.ifaceInfos)) {
3719                     mLog.e("Unexpected for both radio infos to have same iface");
3720                     return;
3721                 }
3722                 if (radioModeInfo0.bandInfo != radioModeInfo1.bandInfo) {
3723                     runnable = () -> {
3724                         handler.onDbs();
3725                     };
3726                 } else {
3727                     runnable = () -> {
3728                         handler.onSbs(radioModeInfo0.bandInfo);
3729                     };
3730                 }
3731             // 2 ifaces time sharing on 1 radio.
3732             } else if (radioModeInfoList.size() == 1 && numIfacesOnEachRadio == 2) {
3733                 IfaceInfo ifaceInfo0 = radioModeInfo0.ifaceInfos.get(0);
3734                 IfaceInfo ifaceInfo1 = radioModeInfo0.ifaceInfos.get(1);
3735                 if (ifaceInfo0.channel != ifaceInfo1.channel) {
3736                     runnable = () -> {
3737                         handler.onMcc(radioModeInfo0.bandInfo);
3738                     };
3739                 } else {
3740                     runnable = () -> {
3741                         handler.onScc(radioModeInfo0.bandInfo);
3742                     };
3743                 }
3744             } else {
3745                 // Not concurrency scenario, uninteresting...
3746             }
3747             if (runnable != null) mHalEventHandler.post(runnable);
3748         }
3749     }
3750 
3751     /**
3752      * Hal Device Manager callbacks.
3753      */
3754     public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
3755         @Override
3756         public void onStatusChanged() {
3757             boolean isReady = mHalDeviceManager.isReady();
3758             boolean isStarted = mHalDeviceManager.isStarted();
3759 
3760             mVerboseLog.i("Device Manager onStatusChanged. isReady(): " + isReady
3761                     + ", isStarted(): " + isStarted);
3762             if (!isReady) {
3763                 // Probably something unpleasant, e.g. the server died
3764                 WifiNative.VendorHalDeathEventHandler handler;
3765                 synchronized (sLock) {
3766                     clearState();
3767                     handler = mDeathEventHandler;
3768                 }
3769                 if (handler != null) {
3770                     handler.onDeath();
3771                 }
3772             }
3773         }
3774     }
3775 
3776     /**
3777      * Trigger subsystem restart in vendor side
3778      */
3779     public boolean startSubsystemRestart() {
3780         synchronized (sLock) {
3781             android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
3782             if (iWifiChipV15 != null) {
3783                 try {
3784                     return ok(iWifiChipV15.triggerSubsystemRestart());
3785                 } catch (RemoteException e) {
3786                     handleRemoteException(e);
3787                     return false;
3788                 }
3789             }
3790             // HAL version does not support this api
3791             return false;
3792         }
3793     }
3794 
3795     /**
3796      * Convert framework's operational mode to HAL's operational mode.
3797      */
3798     private int frameworkToHalIfaceMode(@WifiAvailableChannel.OpMode int mode) {
3799         int halMode = 0;
3800         if ((mode & WifiAvailableChannel.OP_MODE_STA) != 0) {
3801             halMode |= WifiIfaceMode.IFACE_MODE_STA;
3802         }
3803         if ((mode & WifiAvailableChannel.OP_MODE_SAP) != 0) {
3804             halMode |= WifiIfaceMode.IFACE_MODE_SOFTAP;
3805         }
3806         if ((mode & WifiAvailableChannel.OP_MODE_WIFI_DIRECT_CLI) != 0) {
3807             halMode |= WifiIfaceMode.IFACE_MODE_P2P_CLIENT;
3808         }
3809         if ((mode & WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO) != 0) {
3810             halMode |= WifiIfaceMode.IFACE_MODE_P2P_GO;
3811         }
3812         if ((mode & WifiAvailableChannel.OP_MODE_WIFI_AWARE) != 0) {
3813             halMode |= WifiIfaceMode.IFACE_MODE_NAN;
3814         }
3815         if ((mode & WifiAvailableChannel.OP_MODE_TDLS) != 0) {
3816             halMode |= WifiIfaceMode.IFACE_MODE_TDLS;
3817         }
3818         return halMode;
3819     }
3820 
3821     /**
3822      * Convert from HAL's operational mode to framework's operational mode.
3823      */
3824     private @WifiAvailableChannel.OpMode int frameworkFromHalIfaceMode(int halMode) {
3825         int mode = 0;
3826         if ((halMode & WifiIfaceMode.IFACE_MODE_STA) != 0) {
3827             mode |= WifiAvailableChannel.OP_MODE_STA;
3828         }
3829         if ((halMode & WifiIfaceMode.IFACE_MODE_SOFTAP) != 0) {
3830             mode |= WifiAvailableChannel.OP_MODE_SAP;
3831         }
3832         if ((halMode & WifiIfaceMode.IFACE_MODE_P2P_CLIENT) != 0) {
3833             mode |= WifiAvailableChannel.OP_MODE_WIFI_DIRECT_CLI;
3834         }
3835         if ((halMode & WifiIfaceMode.IFACE_MODE_P2P_GO) != 0) {
3836             mode |= WifiAvailableChannel.OP_MODE_WIFI_DIRECT_GO;
3837         }
3838         if ((halMode & WifiIfaceMode.IFACE_MODE_NAN) != 0) {
3839             mode |= WifiAvailableChannel.OP_MODE_WIFI_AWARE;
3840         }
3841         if ((halMode & WifiIfaceMode.IFACE_MODE_TDLS) != 0) {
3842             mode |= WifiAvailableChannel.OP_MODE_TDLS;
3843         }
3844         return mode;
3845     }
3846 
3847     /**
3848      * Convert framework's WifiAvailableChannel.FILTER_* to HAL's UsableChannelFilter.
3849      */
3850     private int frameworkToHalUsableFilter(@WifiAvailableChannel.Filter int filter) {
3851         int halFilter = 0;  // O implies no additional filter other than regulatory (default)
3852 
3853         if ((filter & WifiAvailableChannel.FILTER_CONCURRENCY) != 0) {
3854             halFilter |= UsableChannelFilter.CONCURRENCY;
3855         }
3856         if ((filter & WifiAvailableChannel.FILTER_CELLULAR_COEXISTENCE) != 0) {
3857             halFilter |= UsableChannelFilter.CELLULAR_COEXISTENCE;
3858         }
3859         return halFilter;
3860     }
3861 
3862     /**
3863      * Retrieve the list of usable Wifi channels.
3864      */
3865     public List<WifiAvailableChannel> getUsableChannels(
3866             @WifiScanner.WifiBand int band,
3867             @WifiAvailableChannel.OpMode int mode,
3868             @WifiAvailableChannel.Filter int filter) {
3869         synchronized (sLock) {
3870             try {
3871                 android.hardware.wifi.V1_5.IWifiChip iWifiChipV15 = getWifiChipForV1_5Mockable();
3872                 if (iWifiChipV15 == null) {
3873                     return null;
3874                 }
3875                 Mutable<List<WifiAvailableChannel>> answer = new Mutable<>();
3876                 iWifiChipV15.getUsableChannels(
3877                         makeWifiBandFromFrameworkBand(band),
3878                         frameworkToHalIfaceMode(mode),
3879                         frameworkToHalUsableFilter(filter), (status, channels) -> {
3880                             if (!ok(status)) return;
3881                             answer.value = new ArrayList<>();
3882                             for (WifiUsableChannel ch : channels) {
3883                                 answer.value.add(new WifiAvailableChannel(ch.channel,
3884                                         frameworkFromHalIfaceMode(ch.ifaceModeMask)));
3885                             }
3886                         });
3887                 return answer.value;
3888             } catch (RemoteException e) {
3889                 handleRemoteException(e);
3890                 return null;
3891             } catch (IllegalArgumentException e) {
3892                 mLog.e("Illegal argument for getUsableChannels() " + e);
3893                 return null;
3894             }
3895         }
3896     }
3897 }
3898