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