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 com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP;
19 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE;
20 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA;
21 
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.hardware.wifi.WifiStatusCode;
27 import android.net.MacAddress;
28 import android.net.apf.ApfCapabilities;
29 import android.net.wifi.OuiKeyedData;
30 import android.net.wifi.ScanResult;
31 import android.net.wifi.SoftApConfiguration;
32 import android.net.wifi.WifiAvailableChannel;
33 import android.net.wifi.WifiManager;
34 import android.net.wifi.WifiManager.RoamingMode;
35 import android.net.wifi.WifiScanner;
36 import android.net.wifi.WifiSsid;
37 import android.net.wifi.twt.TwtRequest;
38 import android.os.Bundle;
39 import android.os.Handler;
40 import android.os.WorkSource;
41 import android.text.TextUtils;
42 import android.util.Log;
43 import android.util.Pair;
44 import android.util.SparseArray;
45 
46 import com.android.internal.annotations.VisibleForTesting;
47 import com.android.server.wifi.HalDeviceManager.InterfaceDestroyedListener;
48 import com.android.server.wifi.WifiNative.RxFateReport;
49 import com.android.server.wifi.WifiNative.TxFateReport;
50 import com.android.server.wifi.hal.WifiApIface;
51 import com.android.server.wifi.hal.WifiChip;
52 import com.android.server.wifi.hal.WifiHal;
53 import com.android.server.wifi.hal.WifiStaIface;
54 
55 import com.google.errorprone.annotations.CompileTimeConstant;
56 
57 import java.util.ArrayList;
58 import java.util.Arrays;
59 import java.util.HashMap;
60 import java.util.List;
61 import java.util.Set;
62 import java.util.stream.Collectors;
63 
64 /**
65  * Wi-Fi Vendor HAL.
66  * Interface management is handled by the HalDeviceManager.
67  */
68 public class WifiVendorHal {
69 
70     private static final WifiLog sNoLog = new FakeWifiLog();
71 
72     /**
73      * Chatty logging should use mVerboseLog
74      */
75     @VisibleForTesting
76     WifiLog mVerboseLog = sNoLog;
77 
78     /**
79      * Errors should use mLog
80      */
81     @VisibleForTesting
82     WifiLog mLog = new LogcatLog("WifiVendorHal");
83 
84     /**
85      * Enables or disables verbose logging
86      *
87      */
enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)88     public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) {
89         synchronized (sLock) {
90             if (verboseEnabled) {
91                 mVerboseLog = mLog;
92                 enter("verbose=true").flush();
93             } else {
94                 enter("verbose=false").flush();
95                 mVerboseLog = sNoLog;
96             }
97         }
98     }
99 
100     /**
101      * Logs at method entry
102      *
103      * @param format string with % placeholders
104      * @return LogMessage formatter (remember to .flush())
105      */
enter(@ompileTimeConstant final String format)106     private WifiLog.LogMessage enter(@CompileTimeConstant final String format) {
107         if (mVerboseLog == sNoLog) return sNoLog.info(format);
108         return mVerboseLog.trace(format, 1);
109     }
110 
111     // Vendor HAL interface objects.
112     private WifiChip mWifiChip;
113     private HashMap<String, WifiStaIface> mWifiStaIfaces = new HashMap<>();
114     private HashMap<String, WifiApIface> mWifiApIfaces = new HashMap<>();
115     private static Context sContext;
116     private final HalDeviceManager mHalDeviceManager;
117     private final WifiGlobals mWifiGlobals;
118     private final SsidTranslator mSsidTranslator;
119     private final HalDeviceManagerStatusListener mHalDeviceManagerStatusCallbacks;
120     private final WifiStaIface.Callback mWifiStaIfaceEventCallback;
121     private final ChipEventCallback mWifiChipEventCallback;
122     private WifiNative.WifiTwtEvents mWifiTwtEvents;
123 
124     // Plumbing for event handling.
125     //
126     // Being final fields, they can be accessed without synchronization under
127     // some reasonable assumptions. See
128     // https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5
129     private final Handler mHalEventHandler;
130 
131     /**
132      * Wi-Fi chip related info.
133      */
134     private static class WifiChipInfo {
135         public WifiChip.WifiChipCapabilities capabilities = null;
136         /**
137          * Add more chip specific parameters here. Basically it avoids frequent call to chip by
138          * caching it on {@link mCachedWifiChipInfos}.
139          */
140     }
141     /** A cache which maps chip id to {@link WifiChipInfo} */
142     private SparseArray<WifiChipInfo> mCachedWifiChipInfos = new SparseArray<>();
143 
WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler, WifiGlobals wifiGlobals, @NonNull SsidTranslator ssidTranslator)144     public WifiVendorHal(Context context, HalDeviceManager halDeviceManager, Handler handler,
145             WifiGlobals wifiGlobals,
146             @NonNull SsidTranslator ssidTranslator) {
147         sContext = context;
148         mHalDeviceManager = halDeviceManager;
149         mHalEventHandler = handler;
150         mWifiGlobals = wifiGlobals;
151         mSsidTranslator = ssidTranslator;
152         mHalDeviceManagerStatusCallbacks = new HalDeviceManagerStatusListener();
153         mWifiStaIfaceEventCallback = new StaIfaceEventCallback();
154         mWifiChipEventCallback = new ChipEventCallback();
155     }
156 
157     public static final Object sLock = new Object();
158 
159     private WifiNative.VendorHalDeathEventHandler mDeathEventHandler;
160 
161     /**
162      * Initialize the Hal device manager and register for status callbacks.
163      *
164      * @param handler Handler to notify if the vendor HAL dies.
165      * @return true on success, false otherwise.
166      */
initialize(WifiNative.VendorHalDeathEventHandler handler)167     public boolean initialize(WifiNative.VendorHalDeathEventHandler handler) {
168         synchronized (sLock) {
169             mHalDeviceManager.initialize();
170             mHalDeviceManager.registerStatusListener(
171                     mHalDeviceManagerStatusCallbacks, mHalEventHandler);
172             mDeathEventHandler = handler;
173             return true;
174         }
175     }
176 
177     private WifiNative.VendorHalRadioModeChangeEventHandler mRadioModeChangeEventHandler;
178 
179     /**
180      * Register to listen for radio mode change events from the HAL.
181      *
182      * @param handler Handler to notify when the vendor HAL detects a radio mode change.
183      */
registerRadioModeChangeHandler( WifiNative.VendorHalRadioModeChangeEventHandler handler)184     public void registerRadioModeChangeHandler(
185             WifiNative.VendorHalRadioModeChangeEventHandler handler) {
186         synchronized (sLock) {
187             mRadioModeChangeEventHandler = handler;
188         }
189     }
190 
191     /**
192      * Register to listen for subsystem restart events from the HAL.
193      *
194      * @param listener SubsystemRestartListener listener object.
195      */
registerSubsystemRestartListener( HalDeviceManager.SubsystemRestartListener listener)196     public void registerSubsystemRestartListener(
197             HalDeviceManager.SubsystemRestartListener listener) {
198         mHalDeviceManager.registerSubsystemRestartListener(listener, mHalEventHandler);
199     }
200 
201     /**
202      * Returns whether the vendor HAL is supported on this device or not.
203      */
isVendorHalSupported()204     public boolean isVendorHalSupported() {
205         synchronized (sLock) {
206             return mHalDeviceManager.isSupported();
207         }
208     }
209 
210     /**
211      * Returns whether the vendor HAL is ready or not.
212      */
isVendorHalReady()213     public boolean isVendorHalReady() {
214         synchronized (sLock) {
215             return mHalDeviceManager.isReady();
216         }
217     }
218 
219     /**
220      * Bring up the Vendor HAL and configure for STA (Station) mode
221      *
222      * @return true for success
223      */
startVendorHalSta(@onNull ConcreteClientModeManager concreteClientModeManager)224     public boolean startVendorHalSta(@NonNull ConcreteClientModeManager concreteClientModeManager) {
225         synchronized (sLock) {
226             if (!startVendorHal()) {
227                 return false;
228             }
229             if (TextUtils.isEmpty(createStaIface(null, null,
230                     concreteClientModeManager))) {
231                 stopVendorHal();
232                 return false;
233             }
234             return true;
235         }
236     }
237 
238     /**
239      * Bring up the Vendor HAL.
240      * @return true on success, false otherwise.
241      */
startVendorHal()242     public boolean startVendorHal() {
243         synchronized (sLock) {
244             if (!mHalDeviceManager.start()) {
245                 mLog.err("Failed to start vendor HAL").flush();
246                 return false;
247             }
248             mLog.info("Vendor Hal started successfully").flush();
249             return true;
250         }
251     }
252 
253 
254     /** Helper method to lookup the corresponding STA iface object using iface name. */
getStaIface(@onNull String ifaceName)255     private WifiStaIface getStaIface(@NonNull String ifaceName) {
256         synchronized (sLock) {
257             return mWifiStaIfaces.get(ifaceName);
258         }
259     }
260 
261     private class StaInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener {
262         private final InterfaceDestroyedListener mExternalListener;
263 
StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)264         StaInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) {
265             mExternalListener = externalListener;
266         }
267 
268         @Override
onDestroyed(@onNull String ifaceName)269         public void onDestroyed(@NonNull String ifaceName) {
270             synchronized (sLock) {
271                 mWifiStaIfaces.remove(ifaceName);
272             }
273             if (mExternalListener != null) {
274                 mExternalListener.onDestroyed(ifaceName);
275             }
276         }
277     }
278 
279     /**
280      * Create a STA iface using {@link HalDeviceManager}.
281      *
282      * @param destroyedListener Listener to be invoked when the interface is destroyed.
283      * @param requestorWs Requestor worksource.
284      * @param concreteClientModeManager ConcreteClientModeManager requesting the interface.
285      * @return iface name on success, null otherwise.
286      */
createStaIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs, @NonNull ConcreteClientModeManager concreteClientModeManager)287     public String createStaIface(@Nullable InterfaceDestroyedListener destroyedListener,
288             @NonNull WorkSource requestorWs,
289             @NonNull ConcreteClientModeManager concreteClientModeManager) {
290         synchronized (sLock) {
291             WifiStaIface iface = mHalDeviceManager.createStaIface(
292                     new StaInterfaceDestroyedListenerInternal(destroyedListener), mHalEventHandler,
293                     requestorWs, concreteClientModeManager);
294             if (iface == null) {
295                 mLog.err("Failed to create STA iface").flush();
296                 return null;
297             }
298             String ifaceName = iface.getName();
299             if (TextUtils.isEmpty(ifaceName)) {
300                 mLog.err("Failed to get iface name").flush();
301                 return null;
302             }
303             if (!registerStaIfaceCallback(iface)) {
304                 mLog.err("Failed to register STA iface callback").flush();
305                 return null;
306             }
307             if (!retrieveWifiChip(iface)) {
308                 mLog.err("Failed to get wifi chip").flush();
309                 return null;
310             }
311             mWifiStaIfaces.put(ifaceName, iface);
312             return ifaceName;
313         }
314     }
315 
316     /**
317      * Replace the requestor worksource info for a STA iface using {@link HalDeviceManager}.
318      *
319      * @param ifaceName Name of the interface being removed.
320      * @param requestorWs Requestor worksource.
321      * @return true on success, false otherwise.
322      */
replaceStaIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)323     public boolean replaceStaIfaceRequestorWs(@NonNull String ifaceName,
324             @NonNull WorkSource requestorWs) {
325         synchronized (sLock) {
326             WifiStaIface iface = getStaIface(ifaceName);
327             if (iface == null) return false;
328 
329             if (!mHalDeviceManager.replaceRequestorWs(iface, requestorWs)) {
330                 mLog.err("Failed to replace requestor worksource for STA iface").flush();
331                 return false;
332             }
333             return true;
334         }
335     }
336 
337     /**
338      * Remove a STA iface using {@link HalDeviceManager}.
339      *
340      * @param ifaceName Name of the interface being removed.
341      * @return true on success, false otherwise.
342      */
removeStaIface(@onNull String ifaceName)343     public boolean removeStaIface(@NonNull String ifaceName) {
344         synchronized (sLock) {
345             WifiStaIface iface = getStaIface(ifaceName);
346             if (iface == null) return false;
347             if (!mHalDeviceManager.removeIface(iface)) {
348                 mLog.err("Failed to remove STA iface").flush();
349                 return false;
350             }
351             mWifiStaIfaces.remove(ifaceName);
352             return true;
353         }
354     }
355 
356     /** Helper method to lookup the corresponding AP iface object using iface name. */
getApIface(@onNull String ifaceName)357     private WifiApIface getApIface(@NonNull String ifaceName) {
358         synchronized (sLock) {
359             return mWifiApIfaces.get(ifaceName);
360         }
361     }
362 
363     private class ApInterfaceDestroyedListenerInternal implements InterfaceDestroyedListener {
364         private final InterfaceDestroyedListener mExternalListener;
365 
ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener)366         ApInterfaceDestroyedListenerInternal(InterfaceDestroyedListener externalListener) {
367             mExternalListener = externalListener;
368         }
369 
370         @Override
onDestroyed(@onNull String ifaceName)371         public void onDestroyed(@NonNull String ifaceName) {
372             synchronized (sLock) {
373                 mWifiApIfaces.remove(ifaceName);
374             }
375             if (mExternalListener != null) {
376                 mExternalListener.onDestroyed(ifaceName);
377             }
378         }
379     }
380 
getNecessaryCapabilitiesForSoftApMode(@oftApConfiguration.BandType int band)381     private long getNecessaryCapabilitiesForSoftApMode(@SoftApConfiguration.BandType int band) {
382         long caps = HalDeviceManager.CHIP_CAPABILITY_ANY;
383         if ((band & SoftApConfiguration.BAND_60GHZ) != 0) {
384             caps |= WifiManager.WIFI_FEATURE_INFRA_60G;
385         }
386         return caps;
387     }
388 
389     /**
390      * Create an AP iface using {@link HalDeviceManager}.
391      *
392      * @param destroyedListener Listener to be invoked when the interface is destroyed.
393      * @param requestorWs Requestor worksource.
394      * @param band The requesting band for this AP interface.
395      * @param isBridged Whether or not AP interface is a bridge interface.
396      * @param softApManager SoftApManager of the request.
397      * @param vendorData List of {@link OuiKeyedData} containing vendor-provided
398      *                   configuration data. Empty list indicates no vendor data.
399      * @return iface name on success, null otherwise.
400      */
createApIface(@ullable InterfaceDestroyedListener destroyedListener, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged, @NonNull SoftApManager softApManager, @NonNull List<OuiKeyedData> vendorData)401     public String createApIface(@Nullable InterfaceDestroyedListener destroyedListener,
402             @NonNull WorkSource requestorWs,
403             @SoftApConfiguration.BandType int band,
404             boolean isBridged,
405             @NonNull SoftApManager softApManager, @NonNull List<OuiKeyedData> vendorData) {
406         synchronized (sLock) {
407             WifiApIface iface = mHalDeviceManager.createApIface(
408                     getNecessaryCapabilitiesForSoftApMode(band),
409                     new ApInterfaceDestroyedListenerInternal(destroyedListener), mHalEventHandler,
410                     requestorWs, isBridged, softApManager, vendorData);
411             if (iface == null) {
412                 mLog.err("Failed to create AP iface").flush();
413                 return null;
414             }
415             String ifaceName = iface.getName();
416             if (TextUtils.isEmpty(ifaceName)) {
417                 mLog.err("Failed to get iface name").flush();
418                 return null;
419             }
420             if (!retrieveWifiChip(iface)) {
421                 mLog.err("Failed to get wifi chip").flush();
422                 return null;
423             }
424             mWifiApIfaces.put(ifaceName, iface);
425             return ifaceName;
426         }
427     }
428 
429     /**
430      * Replace the requestor worksource info for an AP iface using {@link HalDeviceManager}.
431      *
432      * @param ifaceName Name of the interface being removed.
433      * @param requestorWs Requestor worksource.
434      * @return true on success, false otherwise.
435      */
replaceApIfaceRequestorWs(@onNull String ifaceName, @NonNull WorkSource requestorWs)436     public boolean replaceApIfaceRequestorWs(@NonNull String ifaceName,
437             @NonNull WorkSource requestorWs) {
438         synchronized (sLock) {
439             WifiApIface iface = getApIface(ifaceName);
440             if (iface == null) return false;
441 
442             if (!mHalDeviceManager.replaceRequestorWs(iface, requestorWs)) {
443                 mLog.err("Failed to replace requestor worksource for AP iface").flush();
444                 return false;
445             }
446             return true;
447         }
448     }
449 
450     /**
451      * Remove an AP iface using {@link HalDeviceManager}.
452      *
453      * @param ifaceName Name of the interface being removed.
454      * @return true on success, false otherwise.
455      */
removeApIface(@onNull String ifaceName)456     public boolean removeApIface(@NonNull String ifaceName) {
457         synchronized (sLock) {
458             WifiApIface iface = getApIface(ifaceName);
459             if (iface == null) return false;
460 
461             if (!mHalDeviceManager.removeIface(iface)) {
462                 mLog.err("Failed to remove AP iface").flush();
463                 return false;
464             }
465             mWifiApIfaces.remove(ifaceName);
466             return true;
467         }
468     }
469 
470     /**
471      * Helper function to remove specific instance in bridged AP iface.
472      *
473      * @param ifaceName Name of the iface.
474      * @param apIfaceInstance The identity of the ap instance.
475      * @return true if the operation succeeded, false if there is an error in Hal.
476      */
removeIfaceInstanceFromBridgedApIface(@onNull String ifaceName, @NonNull String apIfaceInstance)477     public boolean removeIfaceInstanceFromBridgedApIface(@NonNull String ifaceName,
478             @NonNull String apIfaceInstance) {
479         if (mWifiChip == null) return false;
480         return mWifiChip.removeIfaceInstanceFromBridgedApIface(ifaceName, apIfaceInstance);
481     }
482 
483     /**
484      * Set the current coex unsafe channels to avoid and their restrictions.
485      * @param unsafeChannels List of {@link android.net.wifi.CoexUnsafeChannel} to avoid.
486      * @param restrictions int containing a bitwise-OR combination of
487      *                     {@link WifiManager.CoexRestriction}.
488      * @return true if the operation succeeded, false if there is an error in Hal.
489      */
setCoexUnsafeChannels( @onNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions)490     public boolean setCoexUnsafeChannels(
491             @NonNull List<android.net.wifi.CoexUnsafeChannel> unsafeChannels, int restrictions) {
492         if (mWifiChip == null) return false;
493         return mWifiChip.setCoexUnsafeChannels(unsafeChannels, restrictions);
494     }
495 
retrieveWifiChip(WifiHal.WifiInterface iface)496     private boolean retrieveWifiChip(WifiHal.WifiInterface iface) {
497         synchronized (sLock) {
498             boolean registrationNeeded = mWifiChip == null;
499             mWifiChip = mHalDeviceManager.getChip(iface);
500             if (mWifiChip == null) {
501                 mLog.err("Failed to get the chip created for the Iface").flush();
502                 return false;
503             }
504             if (!registrationNeeded) {
505                 return true;
506             }
507             if (!registerChipCallback()) {
508                 mLog.err("Failed to register chip callback").flush();
509                 mWifiChip = null;
510                 return false;
511             }
512             cacheWifiChipInfo(mWifiChip);
513             return true;
514         }
515     }
516 
517     /**
518      * Registers the sta iface callback.
519      */
registerStaIfaceCallback(WifiStaIface iface)520     private boolean registerStaIfaceCallback(WifiStaIface iface) {
521         synchronized (sLock) {
522             if (iface == null) return false;
523             if (mWifiStaIfaceEventCallback == null) return false;
524             return iface.registerFrameworkCallback(mWifiStaIfaceEventCallback);
525         }
526     }
527 
528     /**
529      * Registers the sta iface callback.
530      */
registerChipCallback()531     private boolean registerChipCallback() {
532         synchronized (sLock) {
533             if (mWifiChip == null) return false;
534             return mWifiChip.registerCallback(mWifiChipEventCallback);
535         }
536     }
537 
538     /**
539      * Stops the HAL
540      */
stopVendorHal()541     public void stopVendorHal() {
542         synchronized (sLock) {
543             mHalDeviceManager.stop();
544             clearState();
545             mLog.info("Vendor Hal stopped").flush();
546         }
547     }
548 
549     /**
550      * Clears the state associated with a started Iface
551      *
552      * Caller should hold the lock.
553      */
clearState()554     private void clearState() {
555         mWifiChip = null;
556         mWifiStaIfaces.clear();
557         mWifiApIfaces.clear();
558         mDriverDescription = null;
559         mFirmwareDescription = null;
560     }
561 
562     /**
563      * Tests whether the HAL is started and at least one iface is up.
564      */
isHalStarted()565     public boolean isHalStarted() {
566         // For external use only. Methods in this class should test for null directly.
567         synchronized (sLock) {
568             return (!mWifiStaIfaces.isEmpty() || !mWifiApIfaces.isEmpty());
569         }
570     }
571 
572     /**
573      * Gets the scan capabilities
574      *
575      * @param ifaceName Name of the interface.
576      * @param capabilities object to be filled in
577      * @return true for success, false for failure
578      */
getBgScanCapabilities( @onNull String ifaceName, WifiNative.ScanCapabilities capabilities)579     public boolean getBgScanCapabilities(
580             @NonNull String ifaceName, WifiNative.ScanCapabilities capabilities) {
581         synchronized (sLock) {
582             WifiStaIface iface = getStaIface(ifaceName);
583             if (iface == null) return false;
584 
585             WifiNative.ScanCapabilities result = iface.getBackgroundScanCapabilities();
586             if (result != null) {
587                 capabilities.max_scan_cache_size = result.max_scan_cache_size;
588                 capabilities.max_ap_cache_per_scan = result.max_ap_cache_per_scan;
589                 capabilities.max_scan_buckets = result.max_scan_buckets;
590                 capabilities.max_rssi_sample_size = result.max_rssi_sample_size;
591                 capabilities.max_scan_reporting_threshold = result.max_scan_reporting_threshold;
592             }
593             return result != null;
594         }
595     }
596 
597     /**
598      * Holds the current background scan state, to implement pause and restart
599      */
600     @VisibleForTesting
601     class CurrentBackgroundScan {
602         public int cmdId;
603         public WifiStaIface.StaBackgroundScanParameters param;
604         public WifiNative.ScanEventHandler eventHandler = null;
605         public boolean paused = false;
606         public WifiScanner.ScanData[] latestScanResults = null;
607 
CurrentBackgroundScan(int id, WifiNative.ScanSettings settings)608         CurrentBackgroundScan(int id, WifiNative.ScanSettings settings) {
609             cmdId = id;
610             List<WifiNative.BucketSettings> buckets = new ArrayList<>();
611             if (settings.buckets != null) {
612                 buckets = Arrays.asList(settings.buckets);
613             }
614             param = new WifiStaIface.StaBackgroundScanParameters(settings.base_period_ms,
615                     settings.max_ap_per_scan, settings.report_threshold_percent,
616                     settings.report_threshold_num_scans, buckets);
617         }
618     }
619 
620     private int mLastScanCmdId; // For assigning cmdIds to scans
621 
622     @VisibleForTesting
623     CurrentBackgroundScan mScan = null;
624 
625     /**
626      * Starts a background scan
627      *
628      * Any ongoing scan will be stopped first
629      *
630      * @param ifaceName    Name of the interface.
631      * @param settings     to control the scan
632      * @param eventHandler to call with the results
633      * @return true for success
634      */
startBgScan(@onNull String ifaceName, WifiNative.ScanSettings settings, WifiNative.ScanEventHandler eventHandler)635     public boolean startBgScan(@NonNull String ifaceName,
636                                WifiNative.ScanSettings settings,
637                                WifiNative.ScanEventHandler eventHandler) {
638         if (eventHandler == null) return false;
639         synchronized (sLock) {
640             WifiStaIface iface = getStaIface(ifaceName);
641             if (iface == null) return false;
642             if (mScan != null && !mScan.paused) {
643                 iface.stopBackgroundScan(mScan.cmdId);
644                 mScan = null;
645             }
646 
647             mLastScanCmdId = (mLastScanCmdId % 9) + 1; // cycle through non-zero single digits
648             CurrentBackgroundScan scan = new CurrentBackgroundScan(mLastScanCmdId, settings);
649             boolean success = iface.startBackgroundScan(scan.cmdId, scan.param);
650             if (!success) return false;
651 
652             scan.eventHandler = eventHandler;
653             mScan = scan;
654             return true;
655         }
656     }
657 
658 
659     /**
660      * Stops any ongoing background scan
661      *
662      * @param ifaceName Name of the interface.
663      */
stopBgScan(@onNull String ifaceName)664     public void stopBgScan(@NonNull String ifaceName) {
665         synchronized (sLock) {
666             WifiStaIface iface = getStaIface(ifaceName);
667             if (iface == null) return;
668             if (mScan != null) {
669                 iface.stopBackgroundScan(mScan.cmdId);
670                 mScan = null;
671             }
672         }
673     }
674 
675     /**
676      * Pauses an ongoing background scan
677      *
678      * @param ifaceName Name of the interface.
679      */
pauseBgScan(@onNull String ifaceName)680     public void pauseBgScan(@NonNull String ifaceName) {
681         synchronized (sLock) {
682             WifiStaIface iface = getStaIface(ifaceName);
683             if (iface == null) return;
684             if (mScan != null && !mScan.paused) {
685                 if (!iface.stopBackgroundScan(mScan.cmdId)) return;
686                 mScan.paused = true;
687             }
688         }
689     }
690 
691     /**
692      * Restarts a paused background scan
693      *
694      * @param ifaceName Name of the interface.
695      */
restartBgScan(@onNull String ifaceName)696     public void restartBgScan(@NonNull String ifaceName) {
697         synchronized (sLock) {
698             WifiStaIface iface = getStaIface(ifaceName);
699             if (iface == null) return;
700             if (mScan != null && mScan.paused) {
701                 if (!iface.startBackgroundScan(mScan.cmdId, mScan.param)) return;
702                 mScan.paused = false;
703             }
704         }
705     }
706 
707     /**
708      * Gets the latest scan results received from the HAL interface callback.
709      *
710      * @param ifaceName Name of the interface.
711      */
getBgScanResults(@onNull String ifaceName)712     public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) {
713         synchronized (sLock) {
714             WifiStaIface iface = getStaIface(ifaceName);
715             if (iface == null) return null;
716             if (mScan == null) return null;
717             return mScan.latestScanResults;
718         }
719     }
720 
721     /**
722      * Gets the cached scan data.
723      *
724      * @param ifaceName Name of the interface.
725      */
726     @Nullable
getCachedScanData(@onNull String ifaceName)727     public WifiScanner.ScanData getCachedScanData(@NonNull String ifaceName) {
728         synchronized (sLock) {
729             WifiStaIface iface = getStaIface(ifaceName);
730             if (iface == null) return null;
731             return iface.getCachedScanData();
732         }
733     }
734 
735     /**
736      * Get the link layer statistics
737      *
738      * Note - we always enable link layer stats on a STA interface.
739      *
740      * @param ifaceName Name of the interface.
741      * @return the statistics, or null if unable to do so
742      */
getWifiLinkLayerStats(@onNull String ifaceName)743     public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) {
744         synchronized (sLock) {
745             WifiStaIface iface = getStaIface(ifaceName);
746             if (iface == null) return null;
747             return iface.getLinkLayerStats();
748         }
749     }
750 
751     @VisibleForTesting
752     boolean mLinkLayerStatsDebug = false;  // Passed to Hal
753 
754     /**
755      * Enables the linkLayerStats in the Hal.
756      *
757      * This is called unconditionally whenever we create a STA interface.
758      *
759      * @param ifaceName Name of the interface.
760      */
enableLinkLayerStats(@onNull String ifaceName)761     public void enableLinkLayerStats(@NonNull String ifaceName) {
762         synchronized (sLock) {
763             WifiStaIface iface = getStaIface(ifaceName);
764             if (iface == null) {
765                 mLog.err("STA iface object is NULL - Failed to enable link layer stats")
766                         .flush();
767                 return;
768             }
769             if (!iface.enableLinkLayerStatsCollection(mLinkLayerStatsDebug)) {
770                 mLog.err("unable to enable link layer stats collection").flush();
771             }
772         }
773     }
774 
775     /**
776      * Translation table used by getSupportedFeatureSetFromPackageManager
777      * for translating System caps
778      */
779     private static final Pair[] sSystemFeatureCapabilityTranslation = new Pair[] {
780             Pair.create(WifiManager.WIFI_FEATURE_INFRA, PackageManager.FEATURE_WIFI),
781             Pair.create(WifiManager.WIFI_FEATURE_P2P, PackageManager.FEATURE_WIFI_DIRECT),
782             Pair.create(WifiManager.WIFI_FEATURE_AWARE, PackageManager.FEATURE_WIFI_AWARE),
783     };
784 
785     /**
786      * If VendorHal is not supported, reading PackageManager
787      * system features to return basic capabilities.
788      *
789      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
790      */
getSupportedFeatureSetFromPackageManager()791     private long getSupportedFeatureSetFromPackageManager() {
792         long featureSet = 0;
793         final PackageManager pm = sContext.getPackageManager();
794         for (Pair pair: sSystemFeatureCapabilityTranslation) {
795             if (pm.hasSystemFeature((String) pair.second)) {
796                 featureSet |= (long) pair.first;
797             }
798         }
799         enter("System feature set: %").c(featureSet).flush();
800         return featureSet;
801     }
802 
803     /**
804      * Get maximum number of links supported by the chip for MLO association.
805      *
806      * @param ifaceName Name of the interface.
807      * @return maximum number of association links or -1 if error or not available.
808      */
getMaxMloAssociationLinkCount(String ifaceName)809     public int getMaxMloAssociationLinkCount(String ifaceName) {
810         WifiChipInfo wifiChipInfo = getCachedWifiChipInfo(
811                 ifaceName);
812         if (wifiChipInfo == null || wifiChipInfo.capabilities == null) return -1;
813         return wifiChipInfo.capabilities.maxMloAssociationLinkCount;
814     }
815 
816     /**
817      * Get the maximum number of STR links used in Multi-Link Operation.
818      *
819      * @param ifaceName Name of the interface.
820      * @return maximum number of MLO STR links or -1 if error or not available.
821      */
getMaxMloStrLinkCount(String ifaceName)822     public int getMaxMloStrLinkCount(String ifaceName) {
823         WifiChipInfo wifiChipInfo = getCachedWifiChipInfo(
824                 ifaceName);
825         if (wifiChipInfo == null || wifiChipInfo.capabilities == null) return -1;
826         return wifiChipInfo.capabilities.maxMloStrLinkCount;
827     }
828 
829     /**
830      * Get the maximum number of concurrent TDLS sessions supported by the device.
831      *
832      * @param ifaceName Name of the interface.
833      * @return maximum number of concurrent TDLS sessions or -1 if error or not available.
834      */
getMaxSupportedConcurrentTdlsSessions(String ifaceName)835     public int getMaxSupportedConcurrentTdlsSessions(String ifaceName) {
836         WifiChipInfo wifiChipInfo = getCachedWifiChipInfo(
837                 ifaceName);
838         if (wifiChipInfo == null || wifiChipInfo.capabilities == null) return -1;
839         return wifiChipInfo.capabilities.maxConcurrentTdlsSessionCount;
840     }
841 
842     /**
843      * Get Chip specific cached info.
844      *
845      * @param ifaceName Name of the interface
846      * @return the cached information.
847      */
getCachedWifiChipInfo(String ifaceName)848     private WifiChipInfo getCachedWifiChipInfo(String ifaceName) {
849         WifiStaIface iface = getStaIface(ifaceName);
850         if (iface == null) return null;
851 
852         WifiChip chip = mHalDeviceManager.getChip(iface);
853         if (chip == null) return null;
854 
855         return mCachedWifiChipInfos.get(chip.getId());
856     }
857 
858     /**
859      * Cache chip specific info.
860      *
861      * @param chip Wi-Fi chip
862      */
cacheWifiChipInfo(@onNull WifiChip chip)863     private void cacheWifiChipInfo(@NonNull WifiChip chip) {
864         if (mCachedWifiChipInfos.contains(chip.getId())) return;
865         WifiChipInfo wifiChipInfo = new WifiChipInfo();
866         wifiChipInfo.capabilities = chip.getWifiChipCapabilities();
867         mCachedWifiChipInfos.put(chip.getId(), wifiChipInfo);
868     }
869 
870     /**
871      * Get the supported features
872      *
873      * The result may differ depending on the mode (STA or AP)
874      *
875      * @param ifaceName Name of the interface.
876      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
877      */
getSupportedFeatureSet(@onNull String ifaceName)878     public long getSupportedFeatureSet(@NonNull String ifaceName) {
879         long featureSet = 0L;
880         if (!mHalDeviceManager.isStarted() || !mHalDeviceManager.isSupported()) {
881             return getSupportedFeatureSetFromPackageManager();
882         }
883 
884         synchronized (sLock) {
885             if (mWifiChip != null) {
886                 WifiChip.Response<Long> capsResp = mWifiChip.getCapabilitiesAfterIfacesExist();
887                 if (capsResp.getStatusCode() == WifiHal.WIFI_STATUS_SUCCESS) {
888                     featureSet = capsResp.getValue();
889                 } else if (capsResp.getStatusCode() == WifiHal.WIFI_STATUS_ERROR_REMOTE_EXCEPTION) {
890                     return 0;
891                 }
892             }
893 
894             WifiStaIface iface = getStaIface(ifaceName);
895             if (iface != null) {
896                 featureSet |= iface.getCapabilities();
897                 if (mHalDeviceManager.is24g5gDbsSupported(iface)
898                         || mHalDeviceManager.is5g6gDbsSupported(iface)) {
899                     featureSet |= WifiManager.WIFI_FEATURE_DUAL_BAND_SIMULTANEOUS;
900                 }
901             }
902         }
903 
904         if (mWifiGlobals.isWpa3SaeH2eSupported()) {
905             featureSet |= WifiManager.WIFI_FEATURE_SAE_H2E;
906         }
907 
908         Set<Integer> supportedIfaceTypes = mHalDeviceManager.getSupportedIfaceTypes();
909         if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_STA)) {
910             featureSet |= WifiManager.WIFI_FEATURE_INFRA;
911         }
912         if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_AP)) {
913             featureSet |= WifiManager.WIFI_FEATURE_MOBILE_HOTSPOT;
914         }
915         if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_P2P)) {
916             featureSet |= WifiManager.WIFI_FEATURE_P2P;
917         }
918         if (supportedIfaceTypes.contains(WifiChip.IFACE_TYPE_NAN)) {
919             featureSet |= WifiManager.WIFI_FEATURE_AWARE;
920         }
921 
922         return featureSet;
923     }
924 
925     /**
926      * Set Mac address on the given interface
927      *
928      * @param ifaceName Name of the interface
929      * @param mac MAC address to change into
930      * @return true for success
931      */
setStaMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)932     public boolean setStaMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) {
933         synchronized (sLock) {
934             WifiStaIface iface = getStaIface(ifaceName);
935             if (iface == null) return false;
936             return iface.setMacAddress(mac);
937         }
938     }
939 
940     /**
941      * Reset MAC address to factory MAC address on the given interface
942      *
943      * @param ifaceName Name of the interface
944      * @return true for success
945      */
resetApMacToFactoryMacAddress(@onNull String ifaceName)946     public boolean resetApMacToFactoryMacAddress(@NonNull String ifaceName) {
947         synchronized (sLock) {
948             WifiApIface iface = getApIface(ifaceName);
949             if (iface == null) return false;
950             return iface.resetToFactoryMacAddress();
951         }
952     }
953 
954     /**
955      * Set Mac address on the given interface
956      *
957      * @param ifaceName Name of the interface
958      * @param mac MAC address to change into
959      * @return true for success
960      */
setApMacAddress(@onNull String ifaceName, @NonNull MacAddress mac)961     public boolean setApMacAddress(@NonNull String ifaceName, @NonNull MacAddress mac) {
962         synchronized (sLock) {
963             WifiApIface iface = getApIface(ifaceName);
964             if (iface == null) return false;
965             return iface.setMacAddress(mac);
966         }
967     }
968 
969     /**
970      * Returns true if Hal version supports setMacAddress, otherwise false.
971      *
972      * @param ifaceName Name of the interface
973      */
isApSetMacAddressSupported(@onNull String ifaceName)974     public boolean isApSetMacAddressSupported(@NonNull String ifaceName) {
975         synchronized (sLock) {
976             WifiApIface iface = getApIface(ifaceName);
977             if (iface == null) return false;
978             return iface.isSetMacAddressSupported();
979         }
980     }
981 
982     /**
983      * Get factory MAC address of the given interface
984      *
985      * @param ifaceName Name of the interface
986      * @return factory MAC address of the interface or null.
987      */
getStaFactoryMacAddress(@onNull String ifaceName)988     public MacAddress getStaFactoryMacAddress(@NonNull String ifaceName) {
989         synchronized (sLock) {
990             WifiStaIface iface = getStaIface(ifaceName);
991             if (iface == null) return null;
992             return iface.getFactoryMacAddress();
993         }
994     }
995 
996     /**
997      * Get factory MAC address of the given interface
998      *
999      * @param ifaceName Name of the interface
1000      * @return factory MAC address of the interface or null.
1001      */
getApFactoryMacAddress(@onNull String ifaceName)1002     public MacAddress getApFactoryMacAddress(@NonNull String ifaceName) {
1003         synchronized (sLock) {
1004             WifiApIface iface = getApIface(ifaceName);
1005             if (iface == null) return null;
1006             return iface.getFactoryMacAddress();
1007         }
1008     }
1009 
1010     /**
1011      * Get the APF (Android Packet Filter) capabilities of the device
1012      *
1013      * @param ifaceName Name of the interface.
1014      * @return APF capabilities object.
1015      */
getApfCapabilities(@onNull String ifaceName)1016     public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) {
1017         synchronized (sLock) {
1018             WifiStaIface iface = getStaIface(ifaceName);
1019             if (iface == null) return sNoApfCapabilities;
1020             return iface.getApfPacketFilterCapabilities();
1021         }
1022     }
1023 
1024     private static final ApfCapabilities sNoApfCapabilities = new ApfCapabilities(0, 0, 0);
1025 
1026     /**
1027      * Installs an APF program on this iface, replacing any existing program.
1028      *
1029      * @param ifaceName Name of the interface.
1030      * @param filter is the android packet filter program
1031      * @return true for success
1032      */
installPacketFilter(@onNull String ifaceName, byte[] filter)1033     public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) {
1034         if (filter == null) return false;
1035         enter("filter length %").c(filter.length).flush();
1036         synchronized (sLock) {
1037             WifiStaIface iface = getStaIface(ifaceName);
1038             if (iface == null) return false;
1039             return iface.installApfPacketFilter(filter);
1040         }
1041     }
1042 
1043     /**
1044      * Reads the APF program and data buffer on this iface.
1045      *
1046      * @param ifaceName Name of the interface
1047      * @return the buffer returned by the driver, or null in case of an error
1048      */
readPacketFilter(@onNull String ifaceName)1049     public byte[] readPacketFilter(@NonNull String ifaceName) {
1050         enter("").flush();
1051         // TODO: Must also take the wakelock here to prevent going to sleep with APF disabled.
1052         synchronized (sLock) {
1053             WifiStaIface iface = getStaIface(ifaceName);
1054             if (iface == null) return null;
1055             return iface.readApfPacketFilterData();
1056         }
1057     }
1058 
1059     /**
1060      * Set country code for this Wifi chip
1061      *
1062      * @param countryCode - two-letter country code (as ISO 3166)
1063      * @return true for success
1064      */
setChipCountryCode(String countryCode)1065     public boolean setChipCountryCode(String countryCode) {
1066         synchronized (sLock) {
1067             if (mWifiChip == null) return false;
1068             return mWifiChip.setCountryCode(countryCode);
1069         }
1070     }
1071 
1072     /**
1073      * Get the names of the bridged AP instances.
1074      *
1075      * @param ifaceName Name of the bridged interface.
1076      * @return A list which contains the names of the bridged AP instances.
1077      */
1078     @Nullable
getBridgedApInstances(@onNull String ifaceName)1079     public List<String> getBridgedApInstances(@NonNull String ifaceName) {
1080         synchronized (sLock) {
1081             WifiApIface iface = getApIface(ifaceName);
1082             if (iface == null) return null;
1083             return iface.getBridgedInstances();
1084         }
1085     }
1086 
1087     /**
1088      * Set country code for this AP iface.
1089      *
1090      * @param ifaceName Name of the interface.
1091      * @param countryCode - two-letter country code (as ISO 3166)
1092      * @return true for success
1093      */
setApCountryCode(@onNull String ifaceName, String countryCode)1094     public boolean setApCountryCode(@NonNull String ifaceName, String countryCode) {
1095         synchronized (sLock) {
1096             WifiApIface iface = getApIface(ifaceName);
1097             if (iface == null) return false;
1098             return iface.setCountryCode(countryCode);
1099         }
1100     }
1101 
1102     private WifiNative.WifiLoggerEventHandler mLogEventHandler = null;
1103 
1104     /**
1105      * Registers the logger callback and enables alerts.
1106      * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
1107      */
setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler)1108     public boolean setLoggingEventHandler(WifiNative.WifiLoggerEventHandler handler) {
1109         if (handler == null) return false;
1110         synchronized (sLock) {
1111             if (mWifiChip == null) return false;
1112             if (mLogEventHandler != null) return false;
1113             if (!mWifiChip.enableDebugErrorAlerts(true)) {
1114                 return false;
1115             }
1116             mLogEventHandler = handler;
1117             return true;
1118         }
1119     }
1120 
1121     /**
1122      * Stops all logging and resets the logger callback.
1123      * This stops both the alerts and ring buffer data collection.
1124      * Existing log handler is cleared.
1125      */
resetLogHandler()1126     public boolean resetLogHandler() {
1127         synchronized (sLock) {
1128             mLogEventHandler = null;
1129             if (mWifiChip == null) return false;
1130             if (!mWifiChip.enableDebugErrorAlerts(false)) {
1131                 return false;
1132             }
1133             return mWifiChip.stopLoggingToDebugRingBuffer();
1134         }
1135     }
1136 
1137     /**
1138      * Control debug data collection
1139      *
1140      * @param verboseLevel       0 to 3, inclusive. 0 stops logging.
1141      * @param flags              Ignored.
1142      * @param maxIntervalInSec   Maximum interval between reports; ignore if 0.
1143      * @param minDataSizeInBytes Minimum data size in buffer for report; ignore if 0.
1144      * @param ringName           Name of the ring for which data collection is to start.
1145      * @return true for success
1146      */
startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec, int minDataSizeInBytes, String ringName)1147     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxIntervalInSec,
1148                                           int minDataSizeInBytes, String ringName) {
1149         enter("verboseLevel=%, flags=%, maxIntervalInSec=%, minDataSizeInBytes=%, ringName=%")
1150                 .c(verboseLevel).c(flags).c(maxIntervalInSec).c(minDataSizeInBytes).c(ringName)
1151                 .flush();
1152         synchronized (sLock) {
1153             if (mWifiChip == null) return false;
1154             return mWifiChip.startLoggingToDebugRingBuffer(
1155                     ringName,
1156                     verboseLevel,
1157                     maxIntervalInSec,
1158                     minDataSizeInBytes
1159             );
1160         }
1161     }
1162 
1163     /**
1164      * Pointlessly fail
1165      *
1166      * @return -1
1167      */
getSupportedLoggerFeatureSet()1168     public int getSupportedLoggerFeatureSet() {
1169         return -1;
1170     }
1171 
1172     private String mDriverDescription; // Cached value filled by requestChipDebugInfo()
1173 
1174     /**
1175      * Vendor-provided wifi driver version string
1176      */
getDriverVersion()1177     public String getDriverVersion() {
1178         synchronized (sLock) {
1179             if (mDriverDescription == null) requestChipDebugInfo();
1180             return mDriverDescription;
1181         }
1182     }
1183 
1184     private String mFirmwareDescription; // Cached value filled by requestChipDebugInfo()
1185 
1186     /**
1187      * Vendor-provided wifi firmware version string
1188      */
getFirmwareVersion()1189     public String getFirmwareVersion() {
1190         synchronized (sLock) {
1191             if (mFirmwareDescription == null) requestChipDebugInfo();
1192             return mFirmwareDescription;
1193         }
1194     }
1195 
1196     /**
1197      * Refreshes our idea of the driver and firmware versions
1198      */
requestChipDebugInfo()1199     private void requestChipDebugInfo() {
1200         mDriverDescription = null;
1201         mFirmwareDescription = null;
1202         synchronized (sLock) {
1203             if (mWifiChip == null) return;
1204             WifiChip.ChipDebugInfo info = mWifiChip.requestChipDebugInfo();
1205             if (info == null) return;
1206             mDriverDescription = info.driverDescription;
1207             mFirmwareDescription = info.firmwareDescription;
1208         }
1209         mLog.info("Driver: % Firmware: %")
1210                 .c(mDriverDescription)
1211                 .c(mFirmwareDescription)
1212                 .flush();
1213     }
1214 
1215     /**
1216      * API to get the status of all ring buffers supported by driver
1217      */
getRingBufferStatus()1218     public WifiNative.RingBufferStatus[] getRingBufferStatus() {
1219         synchronized (sLock) {
1220             if (mWifiChip == null) return null;
1221             List<WifiNative.RingBufferStatus> statusList = mWifiChip.getDebugRingBuffersStatus();
1222             if (statusList == null) return null;
1223 
1224             WifiNative.RingBufferStatus[] statusArray =
1225                     new WifiNative.RingBufferStatus[statusList.size()];
1226             statusList.toArray(statusArray);
1227             return statusArray;
1228         }
1229     }
1230 
1231     /**
1232      * Indicates to driver that all the data has to be uploaded urgently
1233      */
getRingBufferData(String ringName)1234     public boolean getRingBufferData(String ringName) {
1235         enter("ringName %").c(ringName).flush();
1236         synchronized (sLock) {
1237             if (mWifiChip == null) return false;
1238             return mWifiChip.forceDumpToDebugRingBuffer(ringName);
1239         }
1240     }
1241 
1242     /**
1243      * request hal to flush ring buffers to files
1244      */
flushRingBufferData()1245     public boolean flushRingBufferData() {
1246         synchronized (sLock) {
1247             if (mWifiChip == null) return false;
1248             return mWifiChip.flushRingBufferToFile();
1249         }
1250     }
1251 
1252     /**
1253      * Request vendor debug info from the firmware
1254      */
getFwMemoryDump()1255     public byte[] getFwMemoryDump() {
1256         synchronized (sLock) {
1257             if (mWifiChip == null) return null;
1258             return mWifiChip.requestFirmwareDebugDump();
1259         }
1260     }
1261 
1262     /**
1263      * Request vendor debug info from the driver
1264      */
getDriverStateDump()1265     public byte[] getDriverStateDump() {
1266         synchronized (sLock) {
1267             if (mWifiChip == null) return (null);
1268             return mWifiChip.requestDriverDebugDump();
1269         }
1270     }
1271 
1272     /**
1273      * Start packet fate monitoring
1274      * <p>
1275      * Once started, monitoring remains active until HAL is unloaded.
1276      *
1277      * @param ifaceName Name of the interface.
1278      * @return true for success
1279      */
startPktFateMonitoring(@onNull String ifaceName)1280     public boolean startPktFateMonitoring(@NonNull String ifaceName) {
1281         synchronized (sLock) {
1282             WifiStaIface iface = getStaIface(ifaceName);
1283             if (iface == null) return false;
1284             return iface.startDebugPacketFateMonitoring();
1285         }
1286     }
1287 
1288     /**
1289      * Retrieve fates of outbound packets
1290      * <p>
1291      * Reports the outbound frames for the most recent association (space allowing).
1292      *
1293      * @param ifaceName Name of the interface.
1294      * @return list of TxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty
1295      * list on failure.
1296      */
getTxPktFates(@onNull String ifaceName)1297     public List<TxFateReport> getTxPktFates(@NonNull String ifaceName) {
1298         synchronized (sLock) {
1299             WifiStaIface iface = getStaIface(ifaceName);
1300             if (iface == null) return new ArrayList<>();
1301             return iface.getDebugTxPacketFates();
1302         }
1303     }
1304 
1305     /**
1306      * Retrieve fates of inbound packets
1307      * <p>
1308      * Reports the inbound frames for the most recent association (space allowing).
1309      *
1310      * @param ifaceName Name of the interface.
1311      * @return list of RxFateReports up to size {@link WifiLoggerHal#MAX_FATE_LOG_LEN}, or empty
1312      * list on failure.
1313      */
getRxPktFates(@onNull String ifaceName)1314     public List<RxFateReport> getRxPktFates(@NonNull String ifaceName) {
1315         synchronized (sLock) {
1316             WifiStaIface iface = getStaIface(ifaceName);
1317             if (iface == null) return new ArrayList<>();
1318             return iface.getDebugRxPacketFates();
1319         }
1320     }
1321 
1322     /**
1323      * Start sending the specified keep alive packets periodically.
1324      *
1325      * @param ifaceName Name of the interface.
1326      * @param slot Command ID to use for this invocation.
1327      * @param srcAddr Source MAC address of the packet.
1328      * @param dstAddr Destination MAC address of the packet.
1329      * @param packet IP packet contents to be transmitted.
1330      * @param protocol Ether type to be set in the ethernet frame transmitted.
1331      * @param periodInMs Interval at which this packet must be transmitted.
1332      * @return 0 for success, -1 for error
1333      */
startSendingOffloadedPacket( @onNull String ifaceName, int slot, byte[] srcAddr, byte[] dstAddr, byte[] packet, int protocol, int periodInMs)1334     public int startSendingOffloadedPacket(
1335             @NonNull String ifaceName, int slot, byte[] srcAddr, byte[] dstAddr,
1336             byte[] packet, int protocol, int periodInMs) {
1337         enter("slot=% periodInMs=%").c(slot).c(periodInMs).flush();
1338         synchronized (sLock) {
1339             WifiStaIface iface = getStaIface(ifaceName);
1340             if (iface == null) return -1;
1341             MacAddress srcMac, dstMac;
1342             try {
1343                 srcMac = MacAddress.fromBytes(srcAddr);
1344                 dstMac = MacAddress.fromBytes(dstAddr);
1345             } catch (IllegalArgumentException e) {
1346                 mLog.info("Invalid MacAddress in startSendingOffloadedPacket").flush();
1347                 return -1;
1348             }
1349             boolean success = iface.startSendingKeepAlivePackets(
1350                         slot,
1351                         packet,
1352                         (short) protocol,
1353                         srcMac,
1354                         dstMac,
1355                         periodInMs);
1356             return success ? 0 : -1;
1357         }
1358     }
1359 
1360     /**
1361      * Stop sending the specified keep alive packets.
1362      *
1363      * @param ifaceName Name of the interface.
1364      * @param slot id - same as startSendingOffloadedPacket call.
1365      * @return 0 for success, -1 for error
1366      */
stopSendingOffloadedPacket(@onNull String ifaceName, int slot)1367     public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) {
1368         enter("slot=%").c(slot).flush();
1369 
1370         synchronized (sLock) {
1371             WifiStaIface iface = getStaIface(ifaceName);
1372             if (iface == null) return -1;
1373             boolean success = iface.stopSendingKeepAlivePackets(slot);
1374             return success ? 0 : -1;
1375         }
1376     }
1377 
1378     /**
1379      * A fixed cmdId for our RssiMonitoring (we only do one at a time)
1380      */
1381     @VisibleForTesting
1382     static final int sRssiMonCmdId = 7551;
1383 
1384     /**
1385      * Our client's handler
1386      */
1387     private WifiNative.WifiRssiEventHandler mWifiRssiEventHandler;
1388 
1389     /**
1390      * Start RSSI monitoring on the currently connected access point.
1391      *
1392      * @param ifaceName        Name of the interface.
1393      * @param maxRssi          Maximum RSSI threshold.
1394      * @param minRssi          Minimum RSSI threshold.
1395      * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
1396      * @return 0 for success, -1 for failure
1397      */
startRssiMonitoring(@onNull String ifaceName, byte maxRssi, byte minRssi, WifiNative.WifiRssiEventHandler rssiEventHandler)1398     public int startRssiMonitoring(@NonNull String ifaceName, byte maxRssi, byte minRssi,
1399                                    WifiNative.WifiRssiEventHandler rssiEventHandler) {
1400         enter("maxRssi=% minRssi=%").c(maxRssi).c(minRssi).flush();
1401         if (maxRssi <= minRssi) return -1;
1402         if (rssiEventHandler == null) return -1;
1403         synchronized (sLock) {
1404             WifiStaIface iface = getStaIface(ifaceName);
1405             if (iface == null) return -1;
1406             iface.stopRssiMonitoring(sRssiMonCmdId);
1407             if (!iface.startRssiMonitoring(sRssiMonCmdId, maxRssi, minRssi)) return -1;
1408             mWifiRssiEventHandler = rssiEventHandler;
1409             return 0;
1410         }
1411     }
1412 
1413     /**
1414      * Stop RSSI monitoring
1415      *
1416      * @param ifaceName Name of the interface.
1417      * @return 0 for success, -1 for failure
1418      */
stopRssiMonitoring(@onNull String ifaceName)1419     public int stopRssiMonitoring(@NonNull String ifaceName) {
1420         synchronized (sLock) {
1421             mWifiRssiEventHandler = null;
1422             WifiStaIface iface = getStaIface(ifaceName);
1423             if (iface == null) return -1;
1424             boolean success = iface.stopRssiMonitoring(sRssiMonCmdId);
1425             return success ? 0 : -1;
1426         }
1427     }
1428 
1429     /**
1430      * Fetch the host wakeup reasons stats from wlan driver.
1431      *
1432      * @return the |WlanWakeReasonAndCounts| from the wlan driver, or null on failure.
1433      */
getWlanWakeReasonCount()1434     public WlanWakeReasonAndCounts getWlanWakeReasonCount() {
1435         synchronized (sLock) {
1436             if (mWifiChip == null) return null;
1437             return mWifiChip.getDebugHostWakeReasonStats();
1438         }
1439     }
1440 
1441     /**
1442      * Enable/Disable Neighbour discovery offload functionality in the firmware.
1443      *
1444      * @param ifaceName Name of the interface.
1445      * @param enabled true to enable, false to disable.
1446      * @return true for success, false for failure
1447      */
configureNeighborDiscoveryOffload(@onNull String ifaceName, boolean enabled)1448     public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) {
1449         enter("enabled=%").c(enabled).flush();
1450         synchronized (sLock) {
1451             WifiStaIface iface = getStaIface(ifaceName);
1452             if (iface == null) return false;
1453             return iface.enableNdOffload(enabled);
1454         }
1455     }
1456 
1457     // Firmware roaming control.
1458 
1459     /**
1460      * Query the firmware roaming capabilities.
1461      *
1462      * @param ifaceName Name of the interface.
1463      * @return capabilities object on success, null otherwise.
1464      */
1465     @Nullable
getRoamingCapabilities(@onNull String ifaceName)1466     public WifiNative.RoamingCapabilities getRoamingCapabilities(@NonNull String ifaceName) {
1467         synchronized (sLock) {
1468             WifiStaIface iface = getStaIface(ifaceName);
1469             if (iface == null) return null;
1470             return iface.getRoamingCapabilities();
1471         }
1472     }
1473 
1474     /**
1475      * Enable/disable firmware roaming.
1476      *
1477      * @param ifaceName Name of the interface.
1478      * @param state the intended roaming state
1479      * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE,
1480      *         or SET_FIRMWARE_ROAMING_BUSY
1481      */
enableFirmwareRoaming(@onNull String ifaceName, @WifiNative.RoamingEnableState int state)1482     public @WifiNative.RoamingEnableStatus int enableFirmwareRoaming(@NonNull String ifaceName,
1483             @WifiNative.RoamingEnableState int state) {
1484         synchronized (sLock) {
1485             WifiStaIface iface = getStaIface(ifaceName);
1486             if (iface == null) return WifiNative.SET_FIRMWARE_ROAMING_FAILURE;
1487             return iface.setRoamingState(state);
1488         }
1489     }
1490 
1491     /**
1492      * Set firmware roaming configurations.
1493      *
1494      * @param ifaceName Name of the interface.
1495      * @param config new roaming configuration object
1496      * @return true for success; false for failure
1497      */
configureRoaming(@onNull String ifaceName, WifiNative.RoamingConfig config)1498     public boolean configureRoaming(@NonNull String ifaceName, WifiNative.RoamingConfig config) {
1499         synchronized (sLock) {
1500             WifiStaIface iface = getStaIface(ifaceName);
1501             if (iface == null) return false;
1502             try {
1503                 // parse the blocklist BSSIDs if any
1504                 List<MacAddress> bssidBlocklist = new ArrayList<>();
1505                 if (config.blocklistBssids != null) {
1506                     for (String bssid : config.blocklistBssids) {
1507                         bssidBlocklist.add(MacAddress.fromString(bssid));
1508                     }
1509                 }
1510 
1511                 // parse the allowlist SSIDs if any
1512                 List<byte[]> ssidAllowlist = new ArrayList<>();
1513                 if (config.allowlistSsids != null) {
1514                     for (String ssidStr : config.allowlistSsids) {
1515                         for (WifiSsid originalSsid : mSsidTranslator.getAllPossibleOriginalSsids(
1516                                 WifiSsid.fromString(ssidStr))) {
1517                             // HIDL code is throwing InvalidArgumentException when ssidWhitelist has
1518                             // SSIDs with less than 32 byte length this is due to HAL definition of
1519                             // SSID declared it as 32-byte fixed length array. Thus pad additional
1520                             // bytes with 0's to pass SSIDs as byte arrays of 32 length
1521                             ssidAllowlist.add(
1522                                     Arrays.copyOf(originalSsid.getBytes(), 32));
1523                         }
1524                     }
1525                 }
1526 
1527                 return iface.configureRoaming(bssidBlocklist, ssidAllowlist);
1528             } catch (IllegalArgumentException e) {
1529                 mLog.err("Illegal argument for roaming configuration").c(e.toString()).flush();
1530                 return false;
1531             }
1532         }
1533     }
1534 
1535     /**
1536      * Select one of the pre-configured TX power level scenarios or reset it back to normal.
1537      * Primarily used for meeting SAR requirements during voice calls.
1538      *
1539      * Note: If it was found out that the scenario to be reported is the same as last reported one,
1540      *       then exit with success.
1541      *       This is to handle the case when some HAL versions deal with different inputs equally,
1542      *       in that case, we should not call the hal unless there is a change in scenario.
1543      * Note: It is assumed that this method is only called if SAR is enabled. The logic of whether
1544      *       to call it or not resides in SarManager class.
1545      *
1546      * @param sarInfo The collection of inputs to select the SAR scenario.
1547      * @return true for success; false for failure or if the HAL version does not support this API.
1548      */
selectTxPowerScenario(SarInfo sarInfo)1549     public boolean selectTxPowerScenario(SarInfo sarInfo) {
1550         synchronized (sLock) {
1551             if (mWifiChip == null) return false;
1552             return mWifiChip.selectTxPowerScenario(sarInfo);
1553         }
1554     }
1555 
1556     /**
1557      * Enable/Disable low-latency mode
1558      *
1559      * @param enabled true to enable low-latency mode, false to disable it
1560      */
setLowLatencyMode(boolean enabled)1561     public boolean setLowLatencyMode(boolean enabled) {
1562         synchronized (sLock) {
1563             if (mWifiChip == null) return false;
1564             return mWifiChip.setLowLatencyMode(enabled);
1565         }
1566     }
1567 
1568     /**
1569      * Returns whether the given HdmIfaceTypeForCreation combo is supported or not.
1570      */
canDeviceSupportCreateTypeCombo(SparseArray<Integer> combo)1571     public boolean canDeviceSupportCreateTypeCombo(SparseArray<Integer> combo) {
1572         synchronized (sLock) {
1573             return mHalDeviceManager.canDeviceSupportCreateTypeCombo(combo);
1574         }
1575     }
1576 
1577     /**
1578      * Returns whether a new iface can be created without tearing down any existing ifaces.
1579      */
canDeviceSupportAdditionalIface( @alDeviceManager.HdmIfaceTypeForCreation int createIfaceType, @NonNull WorkSource requestorWs)1580     public boolean canDeviceSupportAdditionalIface(
1581             @HalDeviceManager.HdmIfaceTypeForCreation int createIfaceType,
1582             @NonNull WorkSource requestorWs) {
1583         synchronized (sLock) {
1584             List<Pair<Integer, WorkSource>> creationImpact =
1585                     mHalDeviceManager.reportImpactToCreateIface(createIfaceType, true, requestorWs);
1586             return creationImpact != null && creationImpact.isEmpty();
1587         }
1588     }
1589 
1590     /**
1591      * Returns whether STA + AP concurrency is supported or not.
1592      */
isStaApConcurrencySupported()1593     public boolean isStaApConcurrencySupported() {
1594         synchronized (sLock) {
1595             return mHalDeviceManager.canDeviceSupportCreateTypeCombo(new SparseArray<Integer>() {{
1596                     put(HDM_CREATE_IFACE_STA, 1);
1597                     put(HDM_CREATE_IFACE_AP, 1);
1598                 }});
1599         }
1600     }
1601 
1602     /**
1603      * Returns whether STA + STA concurrency is supported or not.
1604      */
1605     public boolean isStaStaConcurrencySupported() {
1606         synchronized (sLock) {
1607             return mHalDeviceManager.canDeviceSupportCreateTypeCombo(new SparseArray<Integer>() {{
1608                     put(HDM_CREATE_IFACE_STA, 2);
1609                 }});
1610         }
1611     }
1612 
1613     /**
1614      * Returns whether a new AP iface can be created or not.
1615      */
1616     public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) {
1617         synchronized (sLock) {
1618             return mHalDeviceManager.isItPossibleToCreateIface(HDM_CREATE_IFACE_AP, requestorWs);
1619         }
1620     }
1621 
1622     /**
1623      * Returns whether a new AP iface can be created or not.
1624      */
1625     public boolean isItPossibleToCreateBridgedApIface(@NonNull WorkSource requestorWs) {
1626         synchronized (sLock) {
1627             return mHalDeviceManager.isItPossibleToCreateIface(
1628                     HDM_CREATE_IFACE_AP_BRIDGE, requestorWs);
1629         }
1630     }
1631 
1632     /**
1633      * Returns whether a new STA iface can be created or not.
1634      */
1635     public boolean isItPossibleToCreateStaIface(@NonNull WorkSource requestorWs) {
1636         synchronized (sLock) {
1637             return mHalDeviceManager.isItPossibleToCreateIface(HDM_CREATE_IFACE_STA, requestorWs);
1638         }
1639 
1640     }
1641     /**
1642      * Set primary connection when multiple STA ifaces are active.
1643      *
1644      * @param ifaceName Name of the interface.
1645      * @return true for success
1646      */
1647     public boolean setMultiStaPrimaryConnection(@NonNull String ifaceName) {
1648         if (TextUtils.isEmpty(ifaceName)) return false;
1649         synchronized (sLock) {
1650             if (mWifiChip == null) return false;
1651             return mWifiChip.setMultiStaPrimaryConnection(ifaceName);
1652         }
1653     }
1654 
1655     /**
1656      * Set use-case when multiple STA ifaces are active.
1657      *
1658      * @param useCase one of the use cases.
1659      * @return true for success
1660      */
1661     public boolean setMultiStaUseCase(@WifiNative.MultiStaUseCase int useCase) {
1662         synchronized (sLock) {
1663             if (mWifiChip == null) return false;
1664             return mWifiChip.setMultiStaUseCase(useCase);
1665         }
1666     }
1667 
1668     /**
1669      * Notify scan mode state to driver to save power in scan-only mode.
1670      *
1671      * @param ifaceName Name of the interface.
1672      * @param enable whether is in scan-only mode
1673      * @return true for success
1674      */
1675     public boolean setScanMode(@NonNull String ifaceName, boolean enable) {
1676         synchronized (sLock) {
1677             WifiStaIface iface = getStaIface(ifaceName);
1678             if (iface == null) return false;
1679             return iface.setScanMode(enable);
1680         }
1681     }
1682 
1683     /**
1684      * Callback for events on the STA interface.
1685      */
1686     private class StaIfaceEventCallback implements WifiStaIface.Callback {
1687         @Override
1688         public void onBackgroundScanFailure(int cmdId) {
1689             mVerboseLog.d("onBackgroundScanFailure " + cmdId);
1690             WifiNative.ScanEventHandler eventHandler;
1691             synchronized (sLock) {
1692                 if (mScan == null || cmdId != mScan.cmdId) return;
1693                 eventHandler = mScan.eventHandler;
1694             }
1695             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_FAILED);
1696         }
1697 
1698         @Override
1699         public void onBackgroundFullScanResult(
1700                 int cmdId, int bucketsScanned, ScanResult result) {
1701             mVerboseLog.d("onBackgroundFullScanResult " + cmdId);
1702             WifiNative.ScanEventHandler eventHandler;
1703             synchronized (sLock) {
1704                 if (mScan == null || cmdId != mScan.cmdId) return;
1705                 eventHandler = mScan.eventHandler;
1706             }
1707             eventHandler.onFullScanResult(result, bucketsScanned);
1708         }
1709 
1710         @Override
1711         public void onBackgroundScanResults(int cmdId, WifiScanner.ScanData[] scanDatas) {
1712             mVerboseLog.d("onBackgroundScanResults " + cmdId);
1713             WifiNative.ScanEventHandler eventHandler;
1714             // WifiScanner currently uses the results callback to fetch the scan results.
1715             // So, simulate that by sending out the notification and then caching the results
1716             // locally. This will then be returned to WifiScanner via getScanResults.
1717             synchronized (sLock) {
1718                 if (mScan == null || cmdId != mScan.cmdId) return;
1719                 eventHandler = mScan.eventHandler;
1720                 mScan.latestScanResults = scanDatas;
1721             }
1722             eventHandler.onScanStatus(WifiNative.WIFI_SCAN_RESULTS_AVAILABLE);
1723         }
1724 
1725         @Override
1726         public void onRssiThresholdBreached(int cmdId, byte[/* 6 */] currBssid, int currRssi) {
1727             mVerboseLog.d("onRssiThresholdBreached " + cmdId + "currRssi " + currRssi);
1728             WifiNative.WifiRssiEventHandler eventHandler;
1729             synchronized (sLock) {
1730                 if (mWifiRssiEventHandler == null || cmdId != sRssiMonCmdId) return;
1731                 eventHandler = mWifiRssiEventHandler;
1732             }
1733             eventHandler.onRssiThresholdBreached((byte) currRssi);
1734         }
1735 
1736         /**
1737          * Called when a TWT operation fails.
1738          *
1739          * @param cmdId        Unique command id which is failed
1740          * @param twtErrorCode Error code
1741          */
1742         @Override
1743         public void onTwtFailure(int cmdId, int twtErrorCode) {
1744             synchronized (sLock) {
1745                 mHalEventHandler.post(() -> {
1746                     if (mWifiTwtEvents == null) return;
1747                     mWifiTwtEvents.onTwtFailure(cmdId, twtErrorCode);
1748                 });
1749             }
1750         }
1751 
1752         /**
1753          * Called when {@link WifiStaIface#setupTwtSession(int, TwtRequest)} succeeds.
1754          *
1755          * @param cmdId          Unique command id used in
1756          *                       {@link WifiStaIface#setupTwtSession(int, TwtRequest)}
1757          * @param wakeDurationUs TWT wake duration for the session in microseconds
1758          * @param wakeIntervalUs TWT wake interval for the session in microseconds
1759          * @param linkId         Multi link operation link id
1760          * @param sessionId      TWT session id
1761          */
1762         @Override
1763         public void onTwtSessionCreate(int cmdId, int wakeDurationUs, long wakeIntervalUs,
1764                 int linkId, int sessionId) {
1765             synchronized (sLock) {
1766                 mHalEventHandler.post(() -> {
1767                     if (mWifiTwtEvents == null) return;
1768                     mWifiTwtEvents.onTwtSessionCreate(cmdId, wakeDurationUs, wakeIntervalUs,
1769                             linkId,
1770                             sessionId);
1771                 });
1772             }
1773 
1774         }
1775 
1776         /**
1777          * Called when TWT session is torndown by {@link WifiStaIface#tearDownTwtSession(int, int)}.
1778          * Can also be called unsolicitedly by the vendor software with proper reason code.
1779          *
1780          * @param cmdId        Unique command id used in
1781          *                     {@link WifiStaIface#tearDownTwtSession(int, int)}
1782          * @param twtSessionId TWT session Id
1783          */
1784         @Override
1785         public void onTwtSessionTeardown(int cmdId, int twtSessionId, int twtReasonCode) {
1786             synchronized (sLock) {
1787                 mHalEventHandler.post(() -> {
1788                     if (mWifiTwtEvents == null) return;
1789                     mWifiTwtEvents.onTwtSessionTeardown(cmdId, twtSessionId, twtReasonCode);
1790                 });
1791             }
1792         }
1793 
1794         /**
1795          * Called as a response to {@link WifiStaIface#getStatsTwtSession(int, int)}
1796          *
1797          * @param cmdId        Unique command id used in
1798          *                     {@link WifiStaIface#getStatsTwtSession(int, int)}
1799          * @param twtSessionId TWT session Id
1800          * @param twtStats     TWT stats bundle
1801          */
1802         @Override
1803         public void onTwtSessionStats(int cmdId, int twtSessionId, Bundle twtStats) {
1804             synchronized (sLock) {
1805                 mHalEventHandler.post(() -> {
1806                     if (mWifiTwtEvents == null) return;
1807                     mWifiTwtEvents.onTwtSessionStats(cmdId, twtSessionId, twtStats);
1808                 });
1809             }
1810         }
1811     }
1812 
1813     /**
1814      * Callback for events on the chip.
1815      */
1816     private class ChipEventCallback implements WifiChip.Callback {
1817         @Override
1818         public void onChipReconfigured(int modeId) {
1819             mVerboseLog.d("onChipReconfigured " + modeId);
1820         }
1821 
1822         @Override
1823         public void onChipReconfigureFailure(int status) {
1824             mVerboseLog.d("onChipReconfigureFailure " + status);
1825         }
1826 
1827         public void onIfaceAdded(int type, String name) {
1828             mVerboseLog.d("onIfaceAdded " + type + ", name: " + name);
1829         }
1830 
1831         @Override
1832         public void onIfaceRemoved(int type, String name) {
1833             mVerboseLog.d("onIfaceRemoved " + type + ", name: " + name);
1834         }
1835 
1836         @Override
1837         public void onDebugRingBufferDataAvailable(
1838                 WifiNative.RingBufferStatus status, byte[] data) {
1839             mHalEventHandler.post(() -> {
1840                 WifiNative.WifiLoggerEventHandler eventHandler;
1841                 synchronized (sLock) {
1842                     if (mLogEventHandler == null || status == null || data == null) return;
1843                     eventHandler = mLogEventHandler;
1844                 }
1845                 // Because |sLock| has been released, there is a chance that we'll execute
1846                 // a spurious callback (after someone has called resetLogHandler()).
1847                 //
1848                 // However, the alternative risks deadlock. Consider:
1849                 // [T1.1] WifiDiagnostics.captureBugReport()
1850                 // [T1.2] -- acquire WifiDiagnostics object's intrinsic lock
1851                 // [T1.3]    -> WifiVendorHal.getRingBufferData()
1852                 // [T1.4]       -- acquire WifiVendorHal.sLock
1853                 // [T2.1] <lambda>()
1854                 // [T2.2] -- acquire WifiVendorHal.sLock
1855                 // [T2.3]    -> WifiDiagnostics.onRingBufferData()
1856                 // [T2.4]       -- acquire WifiDiagnostics object's intrinsic lock
1857                 //
1858                 // The problem here is that the two threads acquire the locks in opposite order.
1859                 // If, for example, T2.2 executes between T1.2 and 1.4, then T1 and T2
1860                 // will be deadlocked.
1861                 int sizeBefore = data.length;
1862                 boolean conversionFailure = false;
1863                 try {
1864                     eventHandler.onRingBufferData(status, data);
1865                     int sizeAfter = data.length;
1866                     if (sizeAfter != sizeBefore) {
1867                         conversionFailure = true;
1868                     }
1869                 } catch (ArrayIndexOutOfBoundsException e) {
1870                     conversionFailure = true;
1871                 }
1872                 if (conversionFailure) {
1873                     Log.wtf("WifiVendorHal", "Conversion failure detected in "
1874                             + "onDebugRingBufferDataAvailable. "
1875                             + "The input ArrayList |data| is potentially corrupted. "
1876                             + "Starting size=" + sizeBefore + ", "
1877                             + "final size=" + data.length);
1878                 }
1879             });
1880         }
1881 
1882         @Override
1883         public void onDebugErrorAlert(int errorCode, byte[] debugData) {
1884             mLog.w("onDebugErrorAlert " + errorCode);
1885             mHalEventHandler.post(() -> {
1886                 WifiNative.WifiLoggerEventHandler eventHandler;
1887                 synchronized (sLock) {
1888                     if (mLogEventHandler == null || debugData == null) return;
1889                     eventHandler = mLogEventHandler;
1890                 }
1891                 // See comment in onDebugRingBufferDataAvailable(), for an explanation
1892                 // of why this callback is invoked without |sLock| held.
1893                 eventHandler.onWifiAlert(errorCode, debugData);
1894             });
1895         }
1896 
1897         @Override
1898         public void onRadioModeChange(List<WifiChip.RadioModeInfo> radioModeInfoList) {
1899             mVerboseLog.d("onRadioModeChange " + radioModeInfoList);
1900             WifiNative.VendorHalRadioModeChangeEventHandler handler;
1901             synchronized (sLock) {
1902                 if (mRadioModeChangeEventHandler == null || radioModeInfoList == null) return;
1903                 handler = mRadioModeChangeEventHandler;
1904             }
1905             // Should only contain 1 or 2 radio infos.
1906             if (radioModeInfoList.size() == 0 || radioModeInfoList.size() > 2) {
1907                 mLog.e("Unexpected number of radio info in list " + radioModeInfoList.size());
1908                 return;
1909             }
1910             WifiChip.RadioModeInfo radioModeInfo0 = radioModeInfoList.get(0);
1911             WifiChip.RadioModeInfo radioModeInfo1 =
1912                     radioModeInfoList.size() == 2 ? radioModeInfoList.get(1) : null;
1913             // Number of ifaces on each radio should be equal.
1914             if (radioModeInfo1 != null
1915                     && radioModeInfo0.ifaceInfos.size() != radioModeInfo1.ifaceInfos.size()) {
1916                 mLog.e("Unexpected number of iface info in list "
1917                         + radioModeInfo0.ifaceInfos.size() + ", "
1918                         + radioModeInfo1.ifaceInfos.size());
1919                 return;
1920             }
1921             int numIfacesOnEachRadio = radioModeInfo0.ifaceInfos.size();
1922             // Only 1 or 2 ifaces should be present on each radio.
1923             if (numIfacesOnEachRadio == 0 || numIfacesOnEachRadio > 2) {
1924                 mLog.e("Unexpected number of iface info in list " + numIfacesOnEachRadio);
1925                 return;
1926             }
1927             Runnable runnable = null;
1928             // 2 ifaces simultaneous on 2 radios.
1929             if (radioModeInfoList.size() == 2 && numIfacesOnEachRadio == 1) {
1930                 // Iface on radio0 should be different from the iface on radio1 for DBS & SBS.
1931                 if (areSameIfaceNames(radioModeInfo0.ifaceInfos, radioModeInfo1.ifaceInfos)) {
1932                     mLog.e("Unexpected for both radio infos to have same iface");
1933                     return;
1934                 }
1935                 if (radioModeInfo0.bandInfo != radioModeInfo1.bandInfo) {
1936                     runnable = () -> {
1937                         handler.onDbs();
1938                     };
1939                 } else {
1940                     runnable = () -> {
1941                         handler.onSbs(radioModeInfo0.bandInfo);
1942                     };
1943                 }
1944             // 2 ifaces time sharing on 1 radio.
1945             } else if (radioModeInfoList.size() == 1 && numIfacesOnEachRadio == 2) {
1946                 WifiChip.IfaceInfo ifaceInfo0 = radioModeInfo0.ifaceInfos.get(0);
1947                 WifiChip.IfaceInfo ifaceInfo1 = radioModeInfo0.ifaceInfos.get(1);
1948                 if (ifaceInfo0.channel != ifaceInfo1.channel) {
1949                     runnable = () -> {
1950                         handler.onMcc(radioModeInfo0.bandInfo);
1951                     };
1952                 } else {
1953                     runnable = () -> {
1954                         handler.onScc(radioModeInfo0.bandInfo);
1955                     };
1956                 }
1957             } else {
1958                 // Not concurrency scenario, uninteresting...
1959             }
1960             if (runnable != null) mHalEventHandler.post(runnable);
1961         }
1962     }
1963 
1964     private boolean areSameIfaceNames(List<WifiChip.IfaceInfo> ifaceList1,
1965             List<WifiChip.IfaceInfo> ifaceList2) {
1966         List<String> ifaceNamesList1 = ifaceList1
1967                 .stream()
1968                 .map(i -> i.name)
1969                 .collect(Collectors.toList());
1970         List<String> ifaceNamesList2 = ifaceList2
1971                 .stream()
1972                 .map(i -> i.name)
1973                 .collect(Collectors.toList());
1974         return ifaceNamesList1.containsAll(ifaceNamesList2);
1975     }
1976 
1977     /**
1978      * Hal Device Manager callbacks.
1979      */
1980     public class HalDeviceManagerStatusListener implements HalDeviceManager.ManagerStatusListener {
1981         @Override
1982         public void onStatusChanged() {
1983             boolean isReady = mHalDeviceManager.isReady();
1984             boolean isStarted = mHalDeviceManager.isStarted();
1985 
1986             mVerboseLog.i("Device Manager onStatusChanged. isReady(): " + isReady
1987                     + ", isStarted(): " + isStarted);
1988             if (!isReady) {
1989                 // Probably something unpleasant, e.g. the server died
1990                 WifiNative.VendorHalDeathEventHandler handler;
1991                 synchronized (sLock) {
1992                     clearState();
1993                     handler = mDeathEventHandler;
1994                 }
1995                 if (handler != null) {
1996                     handler.onDeath();
1997                 }
1998             }
1999         }
2000     }
2001 
2002     /**
2003      * Trigger subsystem restart in vendor side
2004      */
2005     public boolean startSubsystemRestart() {
2006         synchronized (sLock) {
2007             if (mWifiChip == null) return false;
2008             return mWifiChip.triggerSubsystemRestart();
2009         }
2010     }
2011 
2012     /**
2013      * Retrieve the list of usable Wifi channels.
2014      */
2015     public List<WifiAvailableChannel> getUsableChannels(
2016             @WifiScanner.WifiBand int band,
2017             @WifiAvailableChannel.OpMode int mode,
2018             @WifiAvailableChannel.Filter int filter) {
2019         synchronized (sLock) {
2020             if (mWifiChip == null) return null;
2021             return mWifiChip.getUsableChannels(band, mode, filter);
2022         }
2023     }
2024 
2025     /**
2026      * Set maximum acceptable DTIM multiplier to hardware driver. Any multiplier larger than the
2027      * maximum value must not be accepted, it will cause packet loss higher than what the system
2028      * can accept, which will cause unexpected behavior for apps, and may interrupt the network
2029      * connection.
2030      *
2031      * @param ifaceName Name of the interface.
2032      * @param multiplier integer maximum DTIM multiplier value to set.
2033      * @return true for success
2034      */
2035     public boolean setDtimMultiplier(@NonNull String ifaceName, int multiplier) {
2036         synchronized (sLock) {
2037             WifiStaIface iface = getStaIface(ifaceName);
2038             if (iface == null) return false;
2039             return iface.setDtimMultiplier(multiplier);
2040         }
2041     }
2042 
2043     /**
2044      * Set the Multi-Link Operation mode.
2045      *
2046      * @param mode Multi-Link operation mode {@link android.net.wifi.WifiManager.MloMode}.
2047      * @return {@code true} if success, otherwise {@code false}.
2048      */
2049     public @WifiStatusCode int setMloMode(@WifiManager.MloMode int mode) {
2050         synchronized (sLock) {
2051             if (mWifiChip == null) return WifiStatusCode.ERROR_WIFI_CHIP_INVALID;
2052             return mWifiChip.setMloMode(mode);
2053         }
2054     }
2055 
2056     /**
2057      * Enable/disable the feature of allowing current STA-connected channel for WFA GO, SAP and
2058      * Aware when the regulatory allows.
2059      *
2060      * @param enableIndoorChannel enable or disable indoor channel.
2061      * @param enableDfsChannel    enable or disable DFS channel.
2062      * @return true if the operation succeeded, false if there is an error in Hal.
2063      */
2064     public boolean enableStaChannelForPeerNetwork(boolean enableIndoorChannel,
2065             boolean enableDfsChannel) {
2066         synchronized (sLock) {
2067             if (mWifiChip == null) return false;
2068             return mWifiChip.enableStaChannelForPeerNetwork(enableIndoorChannel, enableDfsChannel);
2069         }
2070     }
2071 
2072     /**
2073      * See {@link WifiNative#isBandCombinationSupported(String, List)}.
2074      */
2075     public boolean isBandCombinationSupported(@NonNull String ifaceName,
2076             @NonNull List<Integer> bands) {
2077         synchronized (sLock) {
2078             WifiStaIface iface = getStaIface(ifaceName);
2079             if (iface == null) return false;
2080             return mHalDeviceManager.isBandCombinationSupported(iface, bands);
2081         }
2082     }
2083 
2084     /**
2085      * See {@link WifiNative#getSupportedBandCombinations(String)}.
2086      */
2087     public Set<List<Integer>> getSupportedBandCombinations(String ifaceName) {
2088         synchronized (sLock) {
2089             WifiStaIface iface = getStaIface(ifaceName);
2090             if (iface == null) return null;
2091             return mHalDeviceManager.getSupportedBandCombinations(iface);
2092         }
2093     }
2094 
2095     /**
2096      * See {@link WifiNative#setAfcChannelAllowance(WifiChip.AfcChannelAllowance)}
2097      */
2098     public boolean setAfcChannelAllowance(WifiChip.AfcChannelAllowance afcChannelAllowance) {
2099         if (mWifiChip == null) return false;
2100         return mWifiChip.setAfcChannelAllowance(afcChannelAllowance);
2101     }
2102 
2103     /**
2104      * See {@link WifiNative#setRoamingMode(String, int)}.
2105      */
2106     public @WifiStatusCode int setRoamingMode(@NonNull String ifaceName,
2107                                               @RoamingMode int roamingMode) {
2108         synchronized (sLock) {
2109             WifiStaIface iface = getStaIface(ifaceName);
2110             if (iface == null) return WifiStatusCode.ERROR_WIFI_IFACE_INVALID;
2111             return iface.setRoamingMode(roamingMode);
2112         }
2113     }
2114 
2115     /**
2116      * See {@link WifiNative#getTwtCapabilities(String)}
2117      */
2118     public Bundle getTwtCapabilities(String ifaceName) {
2119         synchronized (sLock) {
2120             WifiStaIface wifiStaIface = getStaIface(ifaceName);
2121             if (wifiStaIface == null) return null;
2122             return wifiStaIface.getTwtCapabilities();
2123         }
2124     }
2125 
2126     /**
2127      * See {@link WifiNative#registerTwtCallbacks(TwtManager.WifiNativeTwtEvents)}
2128      */
2129     public void registerTwtCallbacks(WifiNative.WifiTwtEvents wifiTwtCallback) {
2130         mWifiTwtEvents = wifiTwtCallback;
2131     }
2132 
2133     /**
2134      * See {@link WifiNative#setupTwtSession(int, String, TwtRequest)}
2135      */
2136     public boolean setupTwtSession(int cmdId, String ifaceName, TwtRequest twtRequest) {
2137         synchronized (sLock) {
2138             WifiStaIface wifiStaIface = getStaIface(ifaceName);
2139             if (wifiStaIface == null) return false;
2140             return wifiStaIface.setupTwtSession(cmdId, twtRequest);
2141         }
2142     }
2143 
2144     /**
2145      * See {@link WifiNative#tearDownTwtSession(int, String, int)}
2146      */
2147     public boolean tearDownTwtSession(int cmdId, String ifaceName, int sessionId) {
2148         synchronized (sLock) {
2149             WifiStaIface wifiStaIface = getStaIface(ifaceName);
2150             if (wifiStaIface == null) return false;
2151             return wifiStaIface.tearDownTwtSession(cmdId, sessionId);
2152         }
2153     }
2154 
2155     /**
2156      * See {@link WifiNative#getStatsTwtSession(int, String, int)}
2157      */
2158     public boolean getStatsTwtSession(int cmdId, String ifaceName, int sessionId) {
2159         synchronized (sLock) {
2160             WifiStaIface wifiStaIface = getStaIface(ifaceName);
2161             if (wifiStaIface == null) return false;
2162             return wifiStaIface.getStatsTwtSession(cmdId, sessionId);
2163         }
2164     }
2165 
2166     /**
2167      * Sets the wifi VoIP mode.
2168      *
2169      * @param mode Voip mode as defined by the enum |WifiVoipMode|
2170      * @return true if successful, false otherwise.
2171      */
2172     public boolean setVoipMode(@WifiChip.WifiVoipMode int mode) {
2173         synchronized (sLock) {
2174             if (mWifiChip == null) return false;
2175             return mWifiChip.setVoipMode(mode);
2176         }
2177     }
2178 }
2179