• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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 
17 package com.android.server.wifi;
18 
19 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.net.MacAddress;
25 import android.net.TrafficStats;
26 import android.net.apf.ApfCapabilities;
27 import android.net.wifi.CoexUnsafeChannel;
28 import android.net.wifi.ScanResult;
29 import android.net.wifi.SoftApConfiguration;
30 import android.net.wifi.WifiAnnotations;
31 import android.net.wifi.WifiAvailableChannel;
32 import android.net.wifi.WifiConfiguration;
33 import android.net.wifi.WifiScanner;
34 import android.net.wifi.WifiSsid;
35 import android.net.wifi.nl80211.DeviceWiphyCapabilities;
36 import android.net.wifi.nl80211.NativeScanResult;
37 import android.net.wifi.nl80211.NativeWifiClient;
38 import android.net.wifi.nl80211.RadioChainInfo;
39 import android.net.wifi.nl80211.WifiNl80211Manager;
40 import android.os.Bundle;
41 import android.os.Handler;
42 import android.os.SystemClock;
43 import android.os.WorkSource;
44 import android.text.TextUtils;
45 import android.util.ArraySet;
46 import android.util.Log;
47 
48 import com.android.internal.annotations.Immutable;
49 import com.android.internal.util.HexDump;
50 import com.android.modules.utils.build.SdkLevel;
51 import com.android.server.wifi.hotspot2.NetworkDetail;
52 import com.android.server.wifi.util.FrameParser;
53 import com.android.server.wifi.util.InformationElementUtil;
54 import com.android.server.wifi.util.NativeUtil;
55 import com.android.server.wifi.util.NetdWrapper;
56 import com.android.server.wifi.util.NetdWrapper.NetdEventObserver;
57 
58 import java.io.PrintWriter;
59 import java.io.StringWriter;
60 import java.lang.annotation.Retention;
61 import java.lang.annotation.RetentionPolicy;
62 import java.nio.ByteBuffer;
63 import java.nio.ByteOrder;
64 import java.text.SimpleDateFormat;
65 import java.util.ArrayList;
66 import java.util.Arrays;
67 import java.util.Date;
68 import java.util.HashMap;
69 import java.util.HashSet;
70 import java.util.Iterator;
71 import java.util.List;
72 import java.util.Map;
73 import java.util.Objects;
74 import java.util.Random;
75 import java.util.Set;
76 import java.util.TimeZone;
77 
78 /**
79  * Native calls for bring up/shut down of the supplicant daemon and for
80  * sending requests to the supplicant daemon
81  *
82  * {@hide}
83  */
84 public class WifiNative {
85     private static final String TAG = "WifiNative";
86 
87     private final SupplicantStaIfaceHal mSupplicantStaIfaceHal;
88     private final HostapdHal mHostapdHal;
89     private final WifiVendorHal mWifiVendorHal;
90     private final WifiNl80211Manager mWifiCondManager;
91     private final WifiMonitor mWifiMonitor;
92     private final PropertyService mPropertyService;
93     private final WifiMetrics mWifiMetrics;
94     private final Handler mHandler;
95     private final Random mRandom;
96     private final BuildProperties mBuildProperties;
97     private final WifiInjector mWifiInjector;
98     private NetdWrapper mNetdWrapper;
99     private boolean mVerboseLoggingEnabled = false;
100     private boolean mIsEnhancedOpenSupported = false;
101     private final List<CoexUnsafeChannel> mCachedCoexUnsafeChannels = new ArrayList<>();
102     private int mCachedCoexRestrictions;
103     private CountryCodeChangeListenerInternal mCountryCodeChangeListener;
104     private boolean mUseFakeScanDetails;
105     private final ArrayList<ScanDetail> mFakeScanDetails = new ArrayList<>();
106 
WifiNative(WifiVendorHal vendorHal, SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal, WifiNl80211Manager condManager, WifiMonitor wifiMonitor, PropertyService propertyService, WifiMetrics wifiMetrics, Handler handler, Random random, BuildProperties buildProperties, WifiInjector wifiInjector)107     public WifiNative(WifiVendorHal vendorHal,
108                       SupplicantStaIfaceHal staIfaceHal, HostapdHal hostapdHal,
109                       WifiNl80211Manager condManager, WifiMonitor wifiMonitor,
110                       PropertyService propertyService, WifiMetrics wifiMetrics,
111                       Handler handler, Random random, BuildProperties buildProperties,
112                       WifiInjector wifiInjector) {
113         mWifiVendorHal = vendorHal;
114         mSupplicantStaIfaceHal = staIfaceHal;
115         mHostapdHal = hostapdHal;
116         mWifiCondManager = condManager;
117         mWifiMonitor = wifiMonitor;
118         mPropertyService = propertyService;
119         mWifiMetrics = wifiMetrics;
120         mHandler = handler;
121         mRandom = random;
122         mBuildProperties = buildProperties;
123         mWifiInjector = wifiInjector;
124     }
125 
126     /**
127      * Enable verbose logging for all sub modules.
128      */
enableVerboseLogging(boolean verbose)129     public void enableVerboseLogging(boolean verbose) {
130         mVerboseLoggingEnabled = verbose;
131         setSupplicantLogLevel(mVerboseLoggingEnabled);
132         mWifiCondManager.enableVerboseLogging(mVerboseLoggingEnabled);
133         mSupplicantStaIfaceHal.enableVerboseLogging(mVerboseLoggingEnabled);
134         mHostapdHal.enableVerboseLogging(mVerboseLoggingEnabled);
135         mWifiVendorHal.enableVerboseLogging(mVerboseLoggingEnabled);
136     }
137 
138     /**
139      * Callbacks for SoftAp interface.
140      */
141     public class SoftApListenerFromWificond implements WifiNl80211Manager.SoftApCallback {
142         // placeholder for now - provide a shell so that clients don't use a
143         // WifiNl80211Manager-specific API.
144         private String mIfaceName;
145         private SoftApListener mSoftApListener;
146 
SoftApListenerFromWificond(String ifaceName, SoftApListener softApListener)147         SoftApListenerFromWificond(String ifaceName,
148                 SoftApListener softApListener) {
149             mIfaceName = ifaceName;
150             mSoftApListener = softApListener;
151         }
152 
153         @Override
onFailure()154         public void onFailure() {
155             mSoftApListener.onFailure();
156         }
157 
158         @Override
onSoftApChannelSwitched(int frequency, int bandwidth)159         public void onSoftApChannelSwitched(int frequency, int bandwidth) {
160             mSoftApListener.onInfoChanged(mIfaceName, frequency, bandwidth,
161                     ScanResult.WIFI_STANDARD_UNKNOWN, null);
162         }
163 
164         @Override
onConnectedClientsChanged(NativeWifiClient client, boolean isConnected)165         public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) {
166             mSoftApListener.onConnectedClientsChanged(mIfaceName,
167                     client.getMacAddress(), isConnected);
168         }
169     }
170 
171     private static class CountryCodeChangeListenerInternal implements
172             WifiNl80211Manager.CountryCodeChangedListener {
173         private WifiCountryCode.ChangeListener mListener;
174 
setChangeListener(@onNull WifiCountryCode.ChangeListener listener)175         public void setChangeListener(@NonNull WifiCountryCode.ChangeListener listener) {
176             mListener = listener;
177         }
178 
onSetCountryCodeSucceeded(String country)179         public void onSetCountryCodeSucceeded(String country) {
180             Log.d(TAG, "onSetCountryCodeSucceeded: " + country);
181             if (mListener != null) {
182                 mListener.onSetCountryCodeSucceeded(country);
183             }
184         }
185 
186         @Override
onCountryCodeChanged(String country)187         public void onCountryCodeChanged(String country) {
188             Log.d(TAG, "onCountryCodeChanged: " + country);
189             if (mListener != null) {
190                 mListener.onDriverCountryCodeChanged(country);
191             }
192         }
193     }
194 
195     /**
196      * Callbacks for SoftAp instance.
197      */
198     public interface SoftApListener {
199         /**
200          * Invoked when there is a fatal failure and the SoftAp is shutdown.
201          */
onFailure()202         void onFailure();
203 
204         /**
205          * Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different
206          * channel. Also called on initial registration.
207          *
208          * @param apIfaceInstance The identity of the ap instance.
209          * @param frequency The new frequency of the SoftAp. A value of 0 is invalid and is an
210          *                     indication that the SoftAp is not enabled.
211          * @param bandwidth The new bandwidth of the SoftAp.
212          * @param generation The new generation of the SoftAp.
213          */
onInfoChanged(String apIfaceInstance, int frequency, int bandwidth, int generation, MacAddress apIfaceInstanceMacAddress)214         void onInfoChanged(String apIfaceInstance, int frequency, int bandwidth,
215                 int generation, MacAddress apIfaceInstanceMacAddress);
216         /**
217          * Invoked when there is a change in the associated station (STA).
218          *
219          * @param apIfaceInstance The identity of the ap instance.
220          * @param clientAddress Macaddress of the client.
221          * @param isConnected Indication as to whether the client is connected (true), or
222          *                    disconnected (false).
223          */
onConnectedClientsChanged(String apIfaceInstance, MacAddress clientAddress, boolean isConnected)224         void onConnectedClientsChanged(String apIfaceInstance, MacAddress clientAddress,
225                 boolean isConnected);
226     }
227 
228     /********************************************************
229      * Interface management related methods.
230      ********************************************************/
231     /**
232      * Meta-info about every iface that is active.
233      */
234     private static class Iface {
235         /** Type of ifaces possible */
236         public static final int IFACE_TYPE_AP = 0;
237         public static final int IFACE_TYPE_STA_FOR_CONNECTIVITY = 1;
238         public static final int IFACE_TYPE_STA_FOR_SCAN = 2;
239 
240         @IntDef({IFACE_TYPE_AP, IFACE_TYPE_STA_FOR_CONNECTIVITY, IFACE_TYPE_STA_FOR_SCAN})
241         @Retention(RetentionPolicy.SOURCE)
242         public @interface IfaceType{}
243 
244         /** Identifier allocated for the interface */
245         public final int id;
246         /** Type of the iface: STA (for Connectivity or Scan) or AP */
247         public @IfaceType int type;
248         /** Name of the interface */
249         public String name;
250         /** Is the interface up? This is used to mask up/down notifications to external clients. */
251         public boolean isUp;
252         /** External iface destroyed listener for the iface */
253         public InterfaceCallback externalListener;
254         /** Network observer registered for this interface */
255         public NetworkObserverInternal networkObserver;
256         /** Interface feature set / capabilities */
257         public long featureSet;
258         public DeviceWiphyCapabilities phyCapabilities;
259 
Iface(int id, @Iface.IfaceType int type)260         Iface(int id, @Iface.IfaceType int type) {
261             this.id = id;
262             this.type = type;
263         }
264 
265         @Override
toString()266         public String toString() {
267             StringBuffer sb = new StringBuffer();
268             String typeString;
269             switch(type) {
270                 case IFACE_TYPE_STA_FOR_CONNECTIVITY:
271                     typeString = "STA_CONNECTIVITY";
272                     break;
273                 case IFACE_TYPE_STA_FOR_SCAN:
274                     typeString = "STA_SCAN";
275                     break;
276                 case IFACE_TYPE_AP:
277                     typeString = "AP";
278                     break;
279                 default:
280                     typeString = "<UNKNOWN>";
281                     break;
282             }
283             sb.append("Iface:")
284                 .append("{")
285                 .append("Name=").append(name)
286                 .append(",")
287                 .append("Id=").append(id)
288                 .append(",")
289                 .append("Type=").append(typeString)
290                 .append("}");
291             return sb.toString();
292         }
293     }
294 
295     /**
296      * Iface Management entity. This class maintains list of all the active ifaces.
297      */
298     private static class IfaceManager {
299         /** Integer to allocate for the next iface being created */
300         private int mNextId;
301         /** Map of the id to the iface structure */
302         private HashMap<Integer, Iface> mIfaces = new HashMap<>();
303 
304         /** Allocate a new iface for the given type */
allocateIface(@face.IfaceType int type)305         private Iface allocateIface(@Iface.IfaceType  int type) {
306             Iface iface = new Iface(mNextId, type);
307             mIfaces.put(mNextId, iface);
308             mNextId++;
309             return iface;
310         }
311 
312         /** Remove the iface using the provided id */
removeIface(int id)313         private Iface removeIface(int id) {
314             return mIfaces.remove(id);
315         }
316 
317         /** Lookup the iface using the provided id */
getIface(int id)318         private Iface getIface(int id) {
319             return mIfaces.get(id);
320         }
321 
322         /** Lookup the iface using the provided name */
getIface(@onNull String ifaceName)323         private Iface getIface(@NonNull String ifaceName) {
324             for (Iface iface : mIfaces.values()) {
325                 if (TextUtils.equals(iface.name, ifaceName)) {
326                     return iface;
327                 }
328             }
329             return null;
330         }
331 
332         /** Iterator to use for deleting all the ifaces while performing teardown on each of them */
getIfaceIdIter()333         private Iterator<Integer> getIfaceIdIter() {
334             return mIfaces.keySet().iterator();
335         }
336 
337         /** Checks if there are any iface active. */
hasAnyIface()338         private boolean hasAnyIface() {
339             return !mIfaces.isEmpty();
340         }
341 
342         /** Checks if there are any iface of the given type active. */
hasAnyIfaceOfType(@face.IfaceType int type)343         private boolean hasAnyIfaceOfType(@Iface.IfaceType int type) {
344             for (Iface iface : mIfaces.values()) {
345                 if (iface.type == type) {
346                     return true;
347                 }
348             }
349             return false;
350         }
351 
352         /** Checks if there are any STA (for connectivity) iface active. */
hasAnyStaIfaceForConnectivity()353         private boolean hasAnyStaIfaceForConnectivity() {
354             return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
355         }
356 
357         /** Checks if there are any STA (for scan) iface active. */
hasAnyStaIfaceForScan()358         private boolean hasAnyStaIfaceForScan() {
359             return hasAnyIfaceOfType(Iface.IFACE_TYPE_STA_FOR_SCAN);
360         }
361 
362         /** Checks if there are any AP iface active. */
hasAnyApIface()363         private boolean hasAnyApIface() {
364             return hasAnyIfaceOfType(Iface.IFACE_TYPE_AP);
365         }
366 
findAllStaIfaceNames()367         private @NonNull Set<String> findAllStaIfaceNames() {
368             Set<String> ifaceNames = new ArraySet<>();
369             for (Iface iface : mIfaces.values()) {
370                 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
371                         || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
372                     ifaceNames.add(iface.name);
373                 }
374             }
375             return ifaceNames;
376         }
377 
findAllApIfaceNames()378         private @NonNull Set<String> findAllApIfaceNames() {
379             Set<String> ifaceNames = new ArraySet<>();
380             for (Iface iface : mIfaces.values()) {
381                 if (iface.type == Iface.IFACE_TYPE_AP) {
382                     ifaceNames.add(iface.name);
383                 }
384             }
385             return ifaceNames;
386         }
387 
388         /** Removes the existing iface that does not match the provided id. */
removeExistingIface(int newIfaceId)389         public Iface removeExistingIface(int newIfaceId) {
390             Iface removedIface = null;
391             // The number of ifaces in the database could be 1 existing & 1 new at the max.
392             if (mIfaces.size() > 2) {
393                 Log.wtf(TAG, "More than 1 existing interface found");
394             }
395             Iterator<Map.Entry<Integer, Iface>> iter = mIfaces.entrySet().iterator();
396             while (iter.hasNext()) {
397                 Map.Entry<Integer, Iface> entry = iter.next();
398                 if (entry.getKey() != newIfaceId) {
399                     removedIface = entry.getValue();
400                     iter.remove();
401                 }
402             }
403             return removedIface;
404         }
405     }
406 
407     private class NormalScanEventCallback implements WifiNl80211Manager.ScanEventCallback {
408         private String mIfaceName;
409 
NormalScanEventCallback(String ifaceName)410         NormalScanEventCallback(String ifaceName) {
411             mIfaceName = ifaceName;
412         }
413 
414         @Override
onScanResultReady()415         public void onScanResultReady() {
416             Log.d(TAG, "Scan result ready event");
417             mWifiMonitor.broadcastScanResultEvent(mIfaceName);
418         }
419 
420         @Override
onScanFailed()421         public void onScanFailed() {
422             Log.d(TAG, "Scan failed event");
423             mWifiMonitor.broadcastScanFailedEvent(mIfaceName);
424         }
425     }
426 
427     private class PnoScanEventCallback implements WifiNl80211Manager.ScanEventCallback {
428         private String mIfaceName;
429 
PnoScanEventCallback(String ifaceName)430         PnoScanEventCallback(String ifaceName) {
431             mIfaceName = ifaceName;
432         }
433 
434         @Override
onScanResultReady()435         public void onScanResultReady() {
436             Log.d(TAG, "Pno scan result event");
437             mWifiMonitor.broadcastPnoScanResultEvent(mIfaceName);
438             mWifiMetrics.incrementPnoFoundNetworkEventCount();
439         }
440 
441         @Override
onScanFailed()442         public void onScanFailed() {
443             Log.d(TAG, "Pno Scan failed event");
444             mWifiMetrics.incrementPnoScanFailedCount();
445         }
446     }
447 
448     private final Object mLock = new Object();
449     private final IfaceManager mIfaceMgr = new IfaceManager();
450     private HashSet<StatusListener> mStatusListeners = new HashSet<>();
451 
452     /** Helper method invoked to start supplicant if there were no ifaces */
startHal()453     private boolean startHal() {
454         synchronized (mLock) {
455             if (!mIfaceMgr.hasAnyIface()) {
456                 if (mWifiVendorHal.isVendorHalSupported()) {
457                     if (!mWifiVendorHal.startVendorHal()) {
458                         Log.e(TAG, "Failed to start vendor HAL");
459                         return false;
460                     }
461                     if (SdkLevel.isAtLeastS()) {
462                         mWifiVendorHal.setCoexUnsafeChannels(
463                                 mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
464                     }
465                 } else {
466                     Log.i(TAG, "Vendor Hal not supported, ignoring start.");
467                 }
468             }
469             registerWificondListenerIfNecessary();
470             return true;
471         }
472     }
473 
474     /** Helper method invoked to stop HAL if there are no more ifaces */
stopHalAndWificondIfNecessary()475     private void stopHalAndWificondIfNecessary() {
476         synchronized (mLock) {
477             if (!mIfaceMgr.hasAnyIface()) {
478                 if (!mWifiCondManager.tearDownInterfaces()) {
479                     Log.e(TAG, "Failed to teardown ifaces from wificond");
480                 }
481                 if (mWifiVendorHal.isVendorHalSupported()) {
482                     mWifiVendorHal.stopVendorHal();
483                 } else {
484                     Log.i(TAG, "Vendor Hal not supported, ignoring stop.");
485                 }
486             }
487         }
488     }
489 
490     /**
491      * Helper method invoked to setup wificond related callback/listener.
492      */
registerWificondListenerIfNecessary()493     private void registerWificondListenerIfNecessary() {
494         if (mCountryCodeChangeListener == null && SdkLevel.isAtLeastS()) {
495             // The country code listener is a new API in S.
496             mCountryCodeChangeListener = new CountryCodeChangeListenerInternal();
497             mWifiCondManager.registerCountryCodeChangedListener(Runnable::run,
498                     mCountryCodeChangeListener);
499         }
500     }
501 
502     private static final int CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS = 100;
503     private static final int CONNECT_TO_SUPPLICANT_RETRY_TIMES = 50;
504     /**
505      * This method is called to wait for establishing connection to wpa_supplicant.
506      *
507      * @return true if connection is established, false otherwise.
508      */
startAndWaitForSupplicantConnection()509     private boolean startAndWaitForSupplicantConnection() {
510         // Start initialization if not already started.
511         if (!mSupplicantStaIfaceHal.isInitializationStarted()
512                 && !mSupplicantStaIfaceHal.initialize()) {
513             return false;
514         }
515         if (!mSupplicantStaIfaceHal.startDaemon()) {
516             Log.e(TAG, "Failed to startup supplicant");
517             return false;
518         }
519         boolean connected = false;
520         int connectTries = 0;
521         while (!connected && connectTries++ < CONNECT_TO_SUPPLICANT_RETRY_TIMES) {
522             // Check if the initialization is complete.
523             connected = mSupplicantStaIfaceHal.isInitializationComplete();
524             if (connected) {
525                 break;
526             }
527             try {
528                 Thread.sleep(CONNECT_TO_SUPPLICANT_RETRY_INTERVAL_MS);
529             } catch (InterruptedException ignore) {
530             }
531         }
532         return connected;
533     }
534 
535     /** Helper method invoked to start supplicant if there were no STA ifaces */
startSupplicant()536     private boolean startSupplicant() {
537         synchronized (mLock) {
538             if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
539                 if (!startAndWaitForSupplicantConnection()) {
540                     Log.e(TAG, "Failed to connect to supplicant");
541                     return false;
542                 }
543                 if (!mSupplicantStaIfaceHal.registerDeathHandler(
544                         new SupplicantDeathHandlerInternal())) {
545                     Log.e(TAG, "Failed to register supplicant death handler");
546                     return false;
547                 }
548             }
549             return true;
550         }
551     }
552 
553     /** Helper method invoked to stop supplicant if there are no more STA ifaces */
stopSupplicantIfNecessary()554     private void stopSupplicantIfNecessary() {
555         synchronized (mLock) {
556             if (!mIfaceMgr.hasAnyStaIfaceForConnectivity()) {
557                 if (!mSupplicantStaIfaceHal.deregisterDeathHandler()) {
558                     Log.e(TAG, "Failed to deregister supplicant death handler");
559                 }
560                 mSupplicantStaIfaceHal.terminate();
561             }
562         }
563     }
564 
565     /** Helper method invoked to start hostapd if there were no AP ifaces */
startHostapd()566     private boolean startHostapd() {
567         synchronized (mLock) {
568             if (!mIfaceMgr.hasAnyApIface()) {
569                 if (!startAndWaitForHostapdConnection()) {
570                     Log.e(TAG, "Failed to connect to hostapd");
571                     return false;
572                 }
573                 if (!mHostapdHal.registerDeathHandler(
574                         new HostapdDeathHandlerInternal())) {
575                     Log.e(TAG, "Failed to register hostapd death handler");
576                     return false;
577                 }
578             }
579             return true;
580         }
581     }
582 
583     /** Helper method invoked to stop hostapd if there are no more AP ifaces */
stopHostapdIfNecessary()584     private void stopHostapdIfNecessary() {
585         synchronized (mLock) {
586             if (!mIfaceMgr.hasAnyApIface()) {
587                 if (!mHostapdHal.deregisterDeathHandler()) {
588                     Log.e(TAG, "Failed to deregister hostapd death handler");
589                 }
590                 mHostapdHal.terminate();
591             }
592         }
593     }
594 
595     /** Helper method to register a network observer and return it */
registerNetworkObserver(NetworkObserverInternal observer)596     private boolean registerNetworkObserver(NetworkObserverInternal observer) {
597         if (observer == null) return false;
598         mNetdWrapper.registerObserver(observer);
599         return true;
600     }
601 
602     /** Helper method to unregister a network observer */
unregisterNetworkObserver(NetworkObserverInternal observer)603     private boolean unregisterNetworkObserver(NetworkObserverInternal observer) {
604         if (observer == null) return false;
605         mNetdWrapper.unregisterObserver(observer);
606         return true;
607     }
608 
609     /**
610      * Helper method invoked to teardown client iface (for connectivity) and perform
611      * necessary cleanup
612      */
onClientInterfaceForConnectivityDestroyed(@onNull Iface iface)613     private void onClientInterfaceForConnectivityDestroyed(@NonNull Iface iface) {
614         synchronized (mLock) {
615             mWifiMonitor.stopMonitoring(iface.name);
616             if (!unregisterNetworkObserver(iface.networkObserver)) {
617                 Log.e(TAG, "Failed to unregister network observer on " + iface);
618             }
619             if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
620                 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface);
621             }
622             if (!mWifiCondManager.tearDownClientInterface(iface.name)) {
623                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
624             }
625             stopSupplicantIfNecessary();
626             stopHalAndWificondIfNecessary();
627         }
628     }
629 
630     /** Helper method invoked to teardown client iface (for scan) and perform necessary cleanup */
onClientInterfaceForScanDestroyed(@onNull Iface iface)631     private void onClientInterfaceForScanDestroyed(@NonNull Iface iface) {
632         synchronized (mLock) {
633             mWifiMonitor.stopMonitoring(iface.name);
634             if (!unregisterNetworkObserver(iface.networkObserver)) {
635                 Log.e(TAG, "Failed to unregister network observer on " + iface);
636             }
637             if (!mWifiCondManager.tearDownClientInterface(iface.name)) {
638                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
639             }
640             stopHalAndWificondIfNecessary();
641         }
642     }
643 
644     /** Helper method invoked to teardown softAp iface and perform necessary cleanup */
onSoftApInterfaceDestroyed(@onNull Iface iface)645     private void onSoftApInterfaceDestroyed(@NonNull Iface iface) {
646         synchronized (mLock) {
647             if (!unregisterNetworkObserver(iface.networkObserver)) {
648                 Log.e(TAG, "Failed to unregister network observer on " + iface);
649             }
650             if (!mHostapdHal.removeAccessPoint(iface.name)) {
651                 Log.e(TAG, "Failed to remove access point on " + iface);
652             }
653             if (!mWifiCondManager.tearDownSoftApInterface(iface.name)) {
654                 Log.e(TAG, "Failed to teardown iface in wificond on " + iface);
655             }
656             stopHostapdIfNecessary();
657             stopHalAndWificondIfNecessary();
658         }
659     }
660 
661     /** Helper method invoked to teardown iface and perform necessary cleanup */
onInterfaceDestroyed(@onNull Iface iface)662     private void onInterfaceDestroyed(@NonNull Iface iface) {
663         synchronized (mLock) {
664             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
665                 onClientInterfaceForConnectivityDestroyed(iface);
666             } else if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
667                 onClientInterfaceForScanDestroyed(iface);
668             } else if (iface.type == Iface.IFACE_TYPE_AP) {
669                 onSoftApInterfaceDestroyed(iface);
670             }
671             // Invoke the external callback only if the iface was not destroyed because of vendor
672             // HAL crash. In case of vendor HAL crash, let the crash recovery destroy the mode
673             // managers.
674             if (mWifiVendorHal.isVendorHalReady()) {
675                 iface.externalListener.onDestroyed(iface.name);
676             }
677         }
678     }
679 
680     /**
681      * Callback to be invoked by HalDeviceManager when an interface is destroyed.
682      */
683     private class InterfaceDestoyedListenerInternal
684             implements HalDeviceManager.InterfaceDestroyedListener {
685         /** Identifier allocated for the interface */
686         private final int mInterfaceId;
687 
InterfaceDestoyedListenerInternal(int ifaceId)688         InterfaceDestoyedListenerInternal(int ifaceId) {
689             mInterfaceId = ifaceId;
690         }
691 
692         @Override
onDestroyed(@onNull String ifaceName)693         public void onDestroyed(@NonNull String ifaceName) {
694             synchronized (mLock) {
695                 final Iface iface = mIfaceMgr.removeIface(mInterfaceId);
696                 if (iface == null) {
697                     if (mVerboseLoggingEnabled) {
698                         Log.v(TAG, "Received iface destroyed notification on an invalid iface="
699                                 + ifaceName);
700                     }
701                     return;
702                 }
703                 onInterfaceDestroyed(iface);
704                 Log.i(TAG, "Successfully torn down " + iface);
705             }
706         }
707     }
708 
709     /**
710      * Helper method invoked to trigger the status changed callback after one of the native
711      * daemon's death.
712      */
onNativeDaemonDeath()713     private void onNativeDaemonDeath() {
714         synchronized (mLock) {
715             for (StatusListener listener : mStatusListeners) {
716                 listener.onStatusChanged(false);
717             }
718             for (StatusListener listener : mStatusListeners) {
719                 listener.onStatusChanged(true);
720             }
721         }
722     }
723 
724     /**
725      * Death handler for the Vendor HAL daemon.
726      */
727     private class VendorHalDeathHandlerInternal implements VendorHalDeathEventHandler {
728         @Override
onDeath()729         public void onDeath() {
730             synchronized (mLock) {
731                 Log.i(TAG, "Vendor HAL died. Cleaning up internal state.");
732                 onNativeDaemonDeath();
733                 mWifiMetrics.incrementNumHalCrashes();
734             }
735         }
736     }
737 
738     /**
739      * Death handler for the wificond daemon.
740      */
741     private class WificondDeathHandlerInternal implements Runnable {
742         @Override
run()743         public void run() {
744             synchronized (mLock) {
745                 Log.i(TAG, "wificond died. Cleaning up internal state.");
746                 onNativeDaemonDeath();
747                 mWifiMetrics.incrementNumWificondCrashes();
748             }
749         }
750     }
751 
752     /**
753      * Death handler for the supplicant daemon.
754      */
755     private class SupplicantDeathHandlerInternal implements SupplicantDeathEventHandler {
756         @Override
onDeath()757         public void onDeath() {
758             synchronized (mLock) {
759                 Log.i(TAG, "wpa_supplicant died. Cleaning up internal state.");
760                 onNativeDaemonDeath();
761                 mWifiMetrics.incrementNumSupplicantCrashes();
762             }
763         }
764     }
765 
766     /**
767      * Death handler for the hostapd daemon.
768      */
769     private class HostapdDeathHandlerInternal implements HostapdDeathEventHandler {
770         @Override
onDeath()771         public void onDeath() {
772             synchronized (mLock) {
773                 Log.i(TAG, "hostapd died. Cleaning up internal state.");
774                 onNativeDaemonDeath();
775                 mWifiMetrics.incrementNumHostapdCrashes();
776             }
777         }
778     }
779 
780     /** Helper method invoked to handle interface change. */
onInterfaceStateChanged(Iface iface, boolean isUp)781     private void onInterfaceStateChanged(Iface iface, boolean isUp) {
782         synchronized (mLock) {
783             // Mask multiple notifications with the same state.
784             if (isUp == iface.isUp) {
785                 if (mVerboseLoggingEnabled) {
786                     Log.v(TAG, "Interface status unchanged on " + iface + " from " + isUp
787                             + ", Ignoring...");
788                 }
789                 return;
790             }
791             Log.i(TAG, "Interface state changed on " + iface + ", isUp=" + isUp);
792             if (isUp) {
793                 iface.externalListener.onUp(iface.name);
794             } else {
795                 iface.externalListener.onDown(iface.name);
796                 if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
797                         || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
798                     mWifiMetrics.incrementNumClientInterfaceDown();
799                 } else if (iface.type == Iface.IFACE_TYPE_AP) {
800                     mWifiMetrics.incrementNumSoftApInterfaceDown();
801                 }
802             }
803             iface.isUp = isUp;
804         }
805     }
806 
807     /**
808      * Network observer to use for all interface up/down notifications.
809      */
810     private class NetworkObserverInternal implements NetdEventObserver {
811         /** Identifier allocated for the interface */
812         private final int mInterfaceId;
813 
NetworkObserverInternal(int id)814         NetworkObserverInternal(int id) {
815             mInterfaceId = id;
816         }
817 
818         /**
819          * Note: We should ideally listen to
820          * {@link NetdEventObserver#interfaceStatusChanged(String, boolean)} here. But, that
821          * callback is not working currently (broken in netd). So, instead listen to link state
822          * change callbacks as triggers to query the real interface state. We should get rid of
823          * this workaround if we get the |interfaceStatusChanged| callback to work in netd.
824          * Also, this workaround will not detect an interface up event, if the link state is
825          * still down.
826          */
827         @Override
interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp)828         public void interfaceLinkStateChanged(String ifaceName, boolean unusedIsLinkUp) {
829             // This is invoked from the main system_server thread. Post to our handler.
830             mHandler.post(() -> {
831                 synchronized (mLock) {
832                     final Iface ifaceWithId = mIfaceMgr.getIface(mInterfaceId);
833                     if (ifaceWithId == null) {
834                         if (mVerboseLoggingEnabled) {
835                             Log.v(TAG, "Received iface link up/down notification on an invalid"
836                                     + " iface=" + mInterfaceId);
837                         }
838                         return;
839                     }
840                     final Iface ifaceWithName = mIfaceMgr.getIface(ifaceName);
841                     if (ifaceWithName == null || ifaceWithName != ifaceWithId) {
842                         if (mVerboseLoggingEnabled) {
843                             Log.v(TAG, "Received iface link up/down notification on an invalid"
844                                     + " iface=" + ifaceName);
845                         }
846                         return;
847                     }
848                     onInterfaceStateChanged(ifaceWithName, isInterfaceUp(ifaceName));
849                 }
850             });
851         }
852 
853         @Override
interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp)854         public void interfaceStatusChanged(String ifaceName, boolean unusedIsLinkUp) {
855             // unused currently. Look at note above.
856         }
857     }
858 
859     /**
860      * Radio mode change handler for the Vendor HAL daemon.
861      */
862     private class VendorHalRadioModeChangeHandlerInternal
863             implements VendorHalRadioModeChangeEventHandler {
864         @Override
onMcc(int band)865         public void onMcc(int band) {
866             synchronized (mLock) {
867                 Log.i(TAG, "Device is in MCC mode now");
868                 mWifiMetrics.incrementNumRadioModeChangeToMcc();
869             }
870         }
871         @Override
onScc(int band)872         public void onScc(int band) {
873             synchronized (mLock) {
874                 Log.i(TAG, "Device is in SCC mode now");
875                 mWifiMetrics.incrementNumRadioModeChangeToScc();
876             }
877         }
878         @Override
onSbs(int band)879         public void onSbs(int band) {
880             synchronized (mLock) {
881                 Log.i(TAG, "Device is in SBS mode now");
882                 mWifiMetrics.incrementNumRadioModeChangeToSbs();
883             }
884         }
885         @Override
onDbs()886         public void onDbs() {
887             synchronized (mLock) {
888                 Log.i(TAG, "Device is in DBS mode now");
889                 mWifiMetrics.incrementNumRadioModeChangeToDbs();
890             }
891         }
892     }
893 
894     // For devices that don't support the vendor HAL, we will not support any concurrency.
895     // So simulate the HalDeviceManager behavior by triggering the destroy listener for
896     // any active interface.
handleIfaceCreationWhenVendorHalNotSupported(@onNull Iface newIface)897     private String handleIfaceCreationWhenVendorHalNotSupported(@NonNull Iface newIface) {
898         synchronized (mLock) {
899             Iface existingIface = mIfaceMgr.removeExistingIface(newIface.id);
900             if (existingIface != null) {
901                 onInterfaceDestroyed(existingIface);
902                 Log.i(TAG, "Successfully torn down " + existingIface);
903             }
904             // Return the interface name directly from the system property.
905             return mPropertyService.getString("wifi.interface", "wlan0");
906         }
907     }
908 
909     /**
910      * Helper function to handle creation of STA iface.
911      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
912      * teardown any existing iface.
913      */
createStaIface(@onNull Iface iface, @NonNull WorkSource requestorWs)914     private String createStaIface(@NonNull Iface iface, @NonNull WorkSource requestorWs) {
915         synchronized (mLock) {
916             if (mWifiVendorHal.isVendorHalSupported()) {
917                 return mWifiVendorHal.createStaIface(
918                         new InterfaceDestoyedListenerInternal(iface.id), requestorWs);
919             } else {
920                 Log.i(TAG, "Vendor Hal not supported, ignoring createStaIface.");
921                 return handleIfaceCreationWhenVendorHalNotSupported(iface);
922             }
923         }
924     }
925 
926     /**
927      * Helper function to handle creation of AP iface.
928      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
929      * teardown any existing iface.
930      */
createApIface(@onNull Iface iface, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged)931     private String createApIface(@NonNull Iface iface, @NonNull WorkSource requestorWs,
932             @SoftApConfiguration.BandType int band, boolean isBridged) {
933         synchronized (mLock) {
934             if (mWifiVendorHal.isVendorHalSupported()) {
935                 return mWifiVendorHal.createApIface(
936                         new InterfaceDestoyedListenerInternal(iface.id), requestorWs,
937                         band, isBridged);
938             } else {
939                 Log.i(TAG, "Vendor Hal not supported, ignoring createApIface.");
940                 return handleIfaceCreationWhenVendorHalNotSupported(iface);
941             }
942         }
943     }
944 
945     /**
946      * Get list of instance name from this bridged AP iface.
947      *
948      * @param ifaceName Name of the bridged interface.
949      * @return list of instance name when succeed, otherwise null.
950      */
951     @Nullable
getBridgedApInstances(@onNull String ifaceName)952     private List<String> getBridgedApInstances(@NonNull String ifaceName) {
953         synchronized (mLock) {
954             if (mWifiVendorHal.isVendorHalSupported()) {
955                 return mWifiVendorHal.getBridgedApInstances(ifaceName);
956             } else {
957                 Log.i(TAG, "Vendor Hal not supported, ignoring getBridgedApInstances.");
958                 return null;
959             }
960         }
961     }
962 
963     // For devices that don't support the vendor HAL, we will not support any concurrency.
964     // So simulate the HalDeviceManager behavior by triggering the destroy listener for
965     // the interface.
handleIfaceRemovalWhenVendorHalNotSupported(@onNull Iface iface)966     private boolean handleIfaceRemovalWhenVendorHalNotSupported(@NonNull Iface iface) {
967         synchronized (mLock) {
968             mIfaceMgr.removeIface(iface.id);
969             onInterfaceDestroyed(iface);
970             Log.i(TAG, "Successfully torn down " + iface);
971             return true;
972         }
973     }
974 
975     /**
976      * Helper function to handle removal of STA iface.
977      * For devices which do not the support the HAL, this will bypass HalDeviceManager &
978      * teardown any existing iface.
979      */
removeStaIface(@onNull Iface iface)980     private boolean removeStaIface(@NonNull Iface iface) {
981         synchronized (mLock) {
982             if (mWifiVendorHal.isVendorHalSupported()) {
983                 return mWifiVendorHal.removeStaIface(iface.name);
984             } else {
985                 Log.i(TAG, "Vendor Hal not supported, ignoring removeStaIface.");
986                 return handleIfaceRemovalWhenVendorHalNotSupported(iface);
987             }
988         }
989     }
990 
991     /**
992      * Helper function to handle removal of STA iface.
993      */
removeApIface(@onNull Iface iface)994     private boolean removeApIface(@NonNull Iface iface) {
995         synchronized (mLock) {
996             if (mWifiVendorHal.isVendorHalSupported()) {
997                 return mWifiVendorHal.removeApIface(iface.name);
998             } else {
999                 Log.i(TAG, "Vendor Hal not supported, ignoring removeApIface.");
1000                 return handleIfaceRemovalWhenVendorHalNotSupported(iface);
1001             }
1002         }
1003     }
1004 
1005     /**
1006      * Helper function to remove specific instance in bridged AP iface.
1007      *
1008      * @param ifaceName Name of the iface.
1009      * @param apIfaceInstance The identity of the ap instance.
1010      * @return true if the operation succeeded, false if there is an error in Hal.
1011      */
removeIfaceInstanceFromBridgedApIface(@onNull String ifaceName, @NonNull String apIfaceInstance)1012     public boolean removeIfaceInstanceFromBridgedApIface(@NonNull String ifaceName,
1013             @NonNull String apIfaceInstance) {
1014         synchronized (mLock) {
1015             if (mWifiVendorHal.isVendorHalSupported()) {
1016                 return mWifiVendorHal.removeIfaceInstanceFromBridgedApIface(ifaceName,
1017                         apIfaceInstance);
1018             } else {
1019                 return false;
1020             }
1021         }
1022     }
1023 
1024     /**
1025      * Register listener for subsystem restart event
1026      *
1027      * @param listener SubsystemRestartListener listener object.
1028      */
registerSubsystemRestartListener( HalDeviceManager.SubsystemRestartListener listener)1029     public void registerSubsystemRestartListener(
1030             HalDeviceManager.SubsystemRestartListener listener) {
1031         if (listener != null) {
1032             mWifiVendorHal.registerSubsystemRestartListener(listener);
1033         }
1034     }
1035 
1036     /**
1037      * Initialize the native modules.
1038      *
1039      * @return true on success, false otherwise.
1040      */
initialize()1041     public boolean initialize() {
1042         synchronized (mLock) {
1043             if (!mWifiVendorHal.initialize(new VendorHalDeathHandlerInternal())) {
1044                 Log.e(TAG, "Failed to initialize vendor HAL");
1045                 return false;
1046             }
1047             mWifiCondManager.setOnServiceDeadCallback(new WificondDeathHandlerInternal());
1048             mWifiCondManager.tearDownInterfaces();
1049             mWifiVendorHal.registerRadioModeChangeHandler(
1050                     new VendorHalRadioModeChangeHandlerInternal());
1051             mNetdWrapper = mWifiInjector.makeNetdWrapper();
1052             return true;
1053         }
1054     }
1055 
1056     /**
1057      * Callback to notify when the status of one of the native daemons
1058      * (wificond, wpa_supplicant & vendor HAL) changes.
1059      */
1060     public interface StatusListener {
1061         /**
1062          * @param allReady Indicates if all the native daemons are ready for operation or not.
1063          */
onStatusChanged(boolean allReady)1064         void onStatusChanged(boolean allReady);
1065     }
1066 
1067     /**
1068      * Register a StatusListener to get notified about any status changes from the native daemons.
1069      *
1070      * It is safe to re-register the same callback object - duplicates are detected and only a
1071      * single copy kept.
1072      *
1073      * @param listener StatusListener listener object.
1074      */
registerStatusListener(@onNull StatusListener listener)1075     public void registerStatusListener(@NonNull StatusListener listener) {
1076         mStatusListeners.add(listener);
1077     }
1078 
1079     /**
1080      * Callback to notify when the associated interface is destroyed, up or down.
1081      */
1082     public interface InterfaceCallback {
1083         /**
1084          * Interface destroyed by HalDeviceManager.
1085          *
1086          * @param ifaceName Name of the iface.
1087          */
onDestroyed(String ifaceName)1088         void onDestroyed(String ifaceName);
1089 
1090         /**
1091          * Interface is up.
1092          *
1093          * @param ifaceName Name of the iface.
1094          */
onUp(String ifaceName)1095         void onUp(String ifaceName);
1096 
1097         /**
1098          * Interface is down.
1099          *
1100          * @param ifaceName Name of the iface.
1101          */
onDown(String ifaceName)1102         void onDown(String ifaceName);
1103     }
1104 
initializeNwParamsForClientInterface(@onNull String ifaceName)1105     private void initializeNwParamsForClientInterface(@NonNull String ifaceName) {
1106         try {
1107             // A runtime crash or shutting down AP mode can leave
1108             // IP addresses configured, and this affects
1109             // connectivity when supplicant starts up.
1110             // Ensure we have no IP addresses before a supplicant start.
1111             mNetdWrapper.clearInterfaceAddresses(ifaceName);
1112 
1113             // Set privacy extensions
1114             mNetdWrapper.setInterfaceIpv6PrivacyExtensions(ifaceName, true);
1115 
1116             // IPv6 is enabled only as long as access point is connected since:
1117             // - IPv6 addresses and routes stick around after disconnection
1118             // - kernel is unaware when connected and fails to start IPv6 negotiation
1119             // - kernel can start autoconfiguration when 802.1x is not complete
1120             mNetdWrapper.disableIpv6(ifaceName);
1121         } catch (IllegalStateException e) {
1122             Log.e(TAG, "Unable to change interface settings", e);
1123         }
1124     }
1125 
1126     /**
1127      * Setup an interface for client mode (for connectivity) operations.
1128      *
1129      * This method configures an interface in STA mode in all the native daemons
1130      * (wificond, wpa_supplicant & vendor HAL).
1131      *
1132      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1133      * @param requestorWs Requestor worksource.
1134      * @return Returns the name of the allocated interface, will be null on failure.
1135      */
setupInterfaceForClientInConnectivityMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs)1136     public String setupInterfaceForClientInConnectivityMode(
1137             @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs) {
1138         synchronized (mLock) {
1139             if (!startHal()) {
1140                 Log.e(TAG, "Failed to start Hal");
1141                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1142                 return null;
1143             }
1144             if (!startSupplicant()) {
1145                 Log.e(TAG, "Failed to start supplicant");
1146                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1147                 return null;
1148             }
1149             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY);
1150             if (iface == null) {
1151                 Log.e(TAG, "Failed to allocate new STA iface");
1152                 return null;
1153             }
1154             iface.externalListener = interfaceCallback;
1155             iface.name = createStaIface(iface, requestorWs);
1156             if (TextUtils.isEmpty(iface.name)) {
1157                 Log.e(TAG, "Failed to create STA iface in vendor HAL");
1158                 mIfaceMgr.removeIface(iface.id);
1159                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1160                 return null;
1161             }
1162             if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
1163                     new NormalScanEventCallback(iface.name),
1164                     new PnoScanEventCallback(iface.name))) {
1165                 Log.e(TAG, "Failed to setup iface in wificond on " + iface);
1166                 teardownInterface(iface.name);
1167                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
1168                 return null;
1169             }
1170             if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
1171                 Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
1172                 teardownInterface(iface.name);
1173                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1174                 return null;
1175             }
1176             iface.networkObserver = new NetworkObserverInternal(iface.id);
1177             if (!registerNetworkObserver(iface.networkObserver)) {
1178                 Log.e(TAG, "Failed to register network observer on " + iface);
1179                 teardownInterface(iface.name);
1180                 return null;
1181             }
1182             mWifiMonitor.startMonitoring(iface.name);
1183             // Just to avoid any race conditions with interface state change callbacks,
1184             // update the interface state before we exit.
1185             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1186             initializeNwParamsForClientInterface(iface.name);
1187             Log.i(TAG, "Successfully setup " + iface);
1188 
1189             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1190             mIsEnhancedOpenSupported = (iface.featureSet & WIFI_FEATURE_OWE) != 0;
1191             return iface.name;
1192         }
1193     }
1194 
1195     /**
1196      * Setup an interface for client mode (for scan) operations.
1197      *
1198      * This method configures an interface in STA mode in the native daemons
1199      * (wificond, vendor HAL).
1200      *
1201      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1202      * @param requestorWs Requestor worksource.
1203      * @return Returns the name of the allocated interface, will be null on failure.
1204      */
setupInterfaceForClientInScanMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs)1205     public String setupInterfaceForClientInScanMode(
1206             @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs) {
1207         synchronized (mLock) {
1208             if (!startHal()) {
1209                 Log.e(TAG, "Failed to start Hal");
1210                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1211                 return null;
1212             }
1213             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_STA_FOR_SCAN);
1214             if (iface == null) {
1215                 Log.e(TAG, "Failed to allocate new STA iface");
1216                 return null;
1217             }
1218             iface.externalListener = interfaceCallback;
1219             iface.name = createStaIface(iface, requestorWs);
1220             if (TextUtils.isEmpty(iface.name)) {
1221                 Log.e(TAG, "Failed to create iface in vendor HAL");
1222                 mIfaceMgr.removeIface(iface.id);
1223                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToHal();
1224                 return null;
1225             }
1226             if (!mWifiCondManager.setupInterfaceForClientMode(iface.name, Runnable::run,
1227                     new NormalScanEventCallback(iface.name),
1228                     new PnoScanEventCallback(iface.name))) {
1229                 Log.e(TAG, "Failed to setup iface in wificond=" + iface.name);
1230                 teardownInterface(iface.name);
1231                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToWificond();
1232                 return null;
1233             }
1234             iface.networkObserver = new NetworkObserverInternal(iface.id);
1235             if (!registerNetworkObserver(iface.networkObserver)) {
1236                 Log.e(TAG, "Failed to register network observer for iface=" + iface.name);
1237                 teardownInterface(iface.name);
1238                 return null;
1239             }
1240             mWifiMonitor.startMonitoring(iface.name);
1241             // Just to avoid any race conditions with interface state change callbacks,
1242             // update the interface state before we exit.
1243             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1244             Log.i(TAG, "Successfully setup " + iface);
1245 
1246             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1247             return iface.name;
1248         }
1249     }
1250 
1251     /**
1252      * Setup an interface for Soft AP mode operations.
1253      *
1254      * This method configures an interface in AP mode in all the native daemons
1255      * (wificond, wpa_supplicant & vendor HAL).
1256      *
1257      * @param interfaceCallback Associated callback for notifying status changes for the iface.
1258      * @param requestorWs Requestor worksource.
1259      * @param isBridged Whether or not AP interface is a bridge interface.
1260      * @return Returns the name of the allocated interface, will be null on failure.
1261      */
setupInterfaceForSoftApMode( @onNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs, @SoftApConfiguration.BandType int band, boolean isBridged)1262     public String setupInterfaceForSoftApMode(
1263             @NonNull InterfaceCallback interfaceCallback, @NonNull WorkSource requestorWs,
1264             @SoftApConfiguration.BandType int band, boolean isBridged) {
1265         synchronized (mLock) {
1266             if (!startHal()) {
1267                 Log.e(TAG, "Failed to start Hal");
1268                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1269                 return null;
1270             }
1271             if (!startHostapd()) {
1272                 Log.e(TAG, "Failed to start hostapd");
1273                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1274                 return null;
1275             }
1276             Iface iface = mIfaceMgr.allocateIface(Iface.IFACE_TYPE_AP);
1277             if (iface == null) {
1278                 Log.e(TAG, "Failed to allocate new AP iface");
1279                 return null;
1280             }
1281             iface.externalListener = interfaceCallback;
1282             iface.name = createApIface(iface, requestorWs, band, isBridged);
1283             if (TextUtils.isEmpty(iface.name)) {
1284                 Log.e(TAG, "Failed to create AP iface in vendor HAL");
1285                 mIfaceMgr.removeIface(iface.id);
1286                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1287                 return null;
1288             }
1289             String ifaceInstanceName = iface.name;
1290             if (isBridged) {
1291                 List<String> instances = getBridgedApInstances(iface.name);
1292                 if (instances == null || instances.size() == 0) {
1293                     Log.e(TAG, "Failed to get bridged AP instances" + iface.name);
1294                     teardownInterface(iface.name);
1295                     mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHal();
1296                     return null;
1297                 }
1298                 // Always select first instance as wificond interface.
1299                 ifaceInstanceName = instances.get(0);
1300             }
1301             if (!mWifiCondManager.setupInterfaceForSoftApMode(ifaceInstanceName)) {
1302                 Log.e(TAG, "Failed to setup iface in wificond on " + iface);
1303                 teardownInterface(iface.name);
1304                 mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToWificond();
1305                 return null;
1306             }
1307             iface.networkObserver = new NetworkObserverInternal(iface.id);
1308             if (!registerNetworkObserver(iface.networkObserver)) {
1309                 Log.e(TAG, "Failed to register network observer on " + iface);
1310                 teardownInterface(iface.name);
1311                 return null;
1312             }
1313             // Just to avoid any race conditions with interface state change callbacks,
1314             // update the interface state before we exit.
1315             onInterfaceStateChanged(iface, isInterfaceUp(iface.name));
1316             Log.i(TAG, "Successfully setup " + iface);
1317 
1318             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1319             return iface.name;
1320         }
1321     }
1322 
1323     /**
1324      * Switches an existing Client mode interface from connectivity
1325      * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY} to scan mode
1326      * {@link Iface#IFACE_TYPE_STA_FOR_SCAN}.
1327      *
1328      * @param ifaceName Name of the interface.
1329      * @param requestorWs Requestor worksource.
1330      * @return true if the operation succeeded, false if there is an error or the iface is already
1331      * in scan mode.
1332      */
switchClientInterfaceToScanMode(@onNull String ifaceName, @NonNull WorkSource requestorWs)1333     public boolean switchClientInterfaceToScanMode(@NonNull String ifaceName,
1334             @NonNull WorkSource requestorWs) {
1335         synchronized (mLock) {
1336             final Iface iface = mIfaceMgr.getIface(ifaceName);
1337             if (iface == null) {
1338                 Log.e(TAG, "Trying to switch to scan mode on an invalid iface=" + ifaceName);
1339                 return false;
1340             }
1341             if (iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
1342                 Log.e(TAG, "Already in scan mode on iface=" + ifaceName);
1343                 return true;
1344             }
1345             if (mWifiVendorHal.isVendorHalSupported()
1346                     && !mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, requestorWs)) {
1347                 Log.e(TAG, "Failed to replace requestor ws on " + iface);
1348                 teardownInterface(iface.name);
1349                 return false;
1350             }
1351             if (!mSupplicantStaIfaceHal.teardownIface(iface.name)) {
1352                 Log.e(TAG, "Failed to teardown iface in supplicant on " + iface);
1353                 teardownInterface(iface.name);
1354                 return false;
1355             }
1356             iface.type = Iface.IFACE_TYPE_STA_FOR_SCAN;
1357             stopSupplicantIfNecessary();
1358             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1359             iface.phyCapabilities = null;
1360             Log.i(TAG, "Successfully switched to scan mode on iface=" + iface);
1361             return true;
1362         }
1363     }
1364 
1365     /**
1366      * Switches an existing Client mode interface from scan mode
1367      * {@link Iface#IFACE_TYPE_STA_FOR_SCAN} to connectivity mode
1368      * {@link Iface#IFACE_TYPE_STA_FOR_CONNECTIVITY}.
1369      *
1370      * @param ifaceName Name of the interface.
1371      * @param requestorWs Requestor worksource.
1372      * @return true if the operation succeeded, false if there is an error or the iface is already
1373      * in scan mode.
1374      */
switchClientInterfaceToConnectivityMode(@onNull String ifaceName, @NonNull WorkSource requestorWs)1375     public boolean switchClientInterfaceToConnectivityMode(@NonNull String ifaceName,
1376             @NonNull WorkSource requestorWs) {
1377         synchronized (mLock) {
1378             final Iface iface = mIfaceMgr.getIface(ifaceName);
1379             if (iface == null) {
1380                 Log.e(TAG, "Trying to switch to connectivity mode on an invalid iface="
1381                         + ifaceName);
1382                 return false;
1383             }
1384             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY) {
1385                 Log.e(TAG, "Already in connectivity mode on iface=" + ifaceName);
1386                 return true;
1387             }
1388             if (mWifiVendorHal.isVendorHalSupported()
1389                     && !mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, requestorWs)) {
1390                 Log.e(TAG, "Failed to replace requestor ws on " + iface);
1391                 teardownInterface(iface.name);
1392                 return false;
1393             }
1394             if (!startSupplicant()) {
1395                 Log.e(TAG, "Failed to start supplicant");
1396                 teardownInterface(iface.name);
1397                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1398                 return false;
1399             }
1400             if (!mSupplicantStaIfaceHal.setupIface(iface.name)) {
1401                 Log.e(TAG, "Failed to setup iface in supplicant on " + iface);
1402                 teardownInterface(iface.name);
1403                 mWifiMetrics.incrementNumSetupClientInterfaceFailureDueToSupplicant();
1404                 return false;
1405             }
1406             iface.type = Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY;
1407             iface.featureSet = getSupportedFeatureSetInternal(iface.name);
1408             mIsEnhancedOpenSupported = (iface.featureSet & WIFI_FEATURE_OWE) != 0;
1409             Log.i(TAG, "Successfully switched to connectivity mode on iface=" + iface);
1410             return true;
1411         }
1412     }
1413 
1414     /**
1415      * Change the requestor WorkSource for a given STA iface.
1416      * @return true if the operation succeeded, false otherwise.
1417      */
replaceStaIfaceRequestorWs(@onNull String ifaceName, WorkSource newWorkSource)1418     public boolean replaceStaIfaceRequestorWs(@NonNull String ifaceName, WorkSource newWorkSource) {
1419         final Iface iface = mIfaceMgr.getIface(ifaceName);
1420         if (iface == null) {
1421             Log.e(TAG, "Called replaceStaIfaceRequestorWs() on an invalid iface=" + ifaceName);
1422             return false;
1423         }
1424         if (!mWifiVendorHal.isVendorHalSupported()) {
1425             // if vendor HAL isn't supported, return true since there's nothing to do.
1426             return true;
1427         }
1428         if (!mWifiVendorHal.replaceStaIfaceRequestorWs(iface.name, newWorkSource)) {
1429             Log.e(TAG, "Failed to replace requestor ws on " + iface);
1430             teardownInterface(iface.name);
1431             return false;
1432         }
1433         return true;
1434     }
1435 
1436     /**
1437      *
1438      * Check if the interface is up or down.
1439      *
1440      * @param ifaceName Name of the interface.
1441      * @return true if iface is up, false if it's down or on error.
1442      */
isInterfaceUp(@onNull String ifaceName)1443     public boolean isInterfaceUp(@NonNull String ifaceName) {
1444         synchronized (mLock) {
1445             final Iface iface = mIfaceMgr.getIface(ifaceName);
1446             if (iface == null) {
1447                 Log.e(TAG, "Trying to get iface state on invalid iface=" + ifaceName);
1448                 return false;
1449             }
1450             try {
1451                 return mNetdWrapper.isInterfaceUp(ifaceName);
1452             } catch (IllegalStateException e) {
1453                 Log.e(TAG, "Unable to get interface config", e);
1454                 return false;
1455             }
1456         }
1457     }
1458 
1459     /**
1460      * Teardown an interface in Client/AP mode.
1461      *
1462      * This method tears down the associated interface from all the native daemons
1463      * (wificond, wpa_supplicant & vendor HAL).
1464      * Also, brings down the HAL, supplicant or hostapd as necessary.
1465      *
1466      * @param ifaceName Name of the interface.
1467      */
teardownInterface(@onNull String ifaceName)1468     public void teardownInterface(@NonNull String ifaceName) {
1469         synchronized (mLock) {
1470             final Iface iface = mIfaceMgr.getIface(ifaceName);
1471             if (iface == null) {
1472                 Log.e(TAG, "Trying to teardown an invalid iface=" + ifaceName);
1473                 return;
1474             }
1475             // Trigger the iface removal from HAL. The rest of the cleanup will be triggered
1476             // from the interface destroyed callback.
1477             if (iface.type == Iface.IFACE_TYPE_STA_FOR_CONNECTIVITY
1478                     || iface.type == Iface.IFACE_TYPE_STA_FOR_SCAN) {
1479                 if (!removeStaIface(iface)) {
1480                     Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
1481                     return;
1482                 }
1483             } else if (iface.type == Iface.IFACE_TYPE_AP) {
1484                 if (!removeApIface(iface)) {
1485                     Log.e(TAG, "Failed to remove iface in vendor HAL=" + ifaceName);
1486                     return;
1487                 }
1488             }
1489             Log.i(TAG, "Successfully initiated teardown for iface=" + ifaceName);
1490         }
1491     }
1492 
1493     /**
1494      * Teardown all the active interfaces.
1495      *
1496      * This method tears down the associated interfaces from all the native daemons
1497      * (wificond, wpa_supplicant & vendor HAL).
1498      * Also, brings down the HAL, supplicant or hostapd as necessary.
1499      */
teardownAllInterfaces()1500     public void teardownAllInterfaces() {
1501         synchronized (mLock) {
1502             Iterator<Integer> ifaceIdIter = mIfaceMgr.getIfaceIdIter();
1503             while (ifaceIdIter.hasNext()) {
1504                 Iface iface = mIfaceMgr.getIface(ifaceIdIter.next());
1505                 ifaceIdIter.remove();
1506                 onInterfaceDestroyed(iface);
1507                 Log.i(TAG, "Successfully torn down " + iface);
1508             }
1509             Log.i(TAG, "Successfully torn down all ifaces");
1510         }
1511     }
1512 
1513     /**
1514      * Get names of all the client interfaces.
1515      *
1516      * @return List of interface name of all active client interfaces.
1517      */
getClientInterfaceNames()1518     public Set<String> getClientInterfaceNames() {
1519         synchronized (mLock) {
1520             return mIfaceMgr.findAllStaIfaceNames();
1521         }
1522     }
1523 
1524     /**
1525      * Get names of all the client interfaces.
1526      *
1527      * @return List of interface name of all active client interfaces.
1528      */
getSoftApInterfaceNames()1529     public Set<String> getSoftApInterfaceNames() {
1530         synchronized (mLock) {
1531             return mIfaceMgr.findAllApIfaceNames();
1532         }
1533     }
1534 
1535     /********************************************************
1536      * Wificond operations
1537      ********************************************************/
1538 
1539     /**
1540      * Request signal polling to wificond.
1541      *
1542      * @param ifaceName Name of the interface.
1543      * Returns an SignalPollResult object.
1544      * Returns null on failure.
1545      */
signalPoll(@onNull String ifaceName)1546     public WifiNl80211Manager.SignalPollResult signalPoll(@NonNull String ifaceName) {
1547         return mWifiCondManager.signalPoll(ifaceName);
1548     }
1549 
1550     /**
1551      * Query the list of valid frequencies for the provided band.
1552      * The result depends on the on the country code that has been set.
1553      *
1554      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1555      * The following bands are supported {@link WifiAnnotations.WifiBandBasic}:
1556      * WifiScanner.WIFI_BAND_24_GHZ
1557      * WifiScanner.WIFI_BAND_5_GHZ
1558      * WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY
1559      * WifiScanner.WIFI_BAND_6_GHZ
1560      * WifiScanner.WIFI_BAND_60_GHZ
1561      * @return frequencies vector of valid frequencies (MHz), or null for error.
1562      * @throws IllegalArgumentException if band is not recognized.
1563      */
getChannelsForBand(@ifiAnnotations.WifiBandBasic int band)1564     public int [] getChannelsForBand(@WifiAnnotations.WifiBandBasic int band) {
1565         if (!SdkLevel.isAtLeastS() && band == WifiScanner.WIFI_BAND_60_GHZ) {
1566             // 60 GHz band is new in Android S, return empty array on older SDK versions
1567             return new int[0];
1568         }
1569         return mWifiCondManager.getChannelsMhzForBand(band);
1570     }
1571 
1572     /**
1573      * Start a scan using wificond for the given parameters.
1574      * @param ifaceName Name of the interface.
1575      * @param scanType Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY},
1576      * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}.
1577      * @param freqs list of frequencies to scan for, if null scan all supported channels.
1578      * @param hiddenNetworkSSIDs List of hidden networks to be scanned for.
1579      * @param enable6GhzRnr whether Reduced Neighbor Report should be enabled for 6Ghz scanning.
1580      * @return Returns true on success.
1581      */
scan( @onNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs, List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr)1582     public boolean scan(
1583             @NonNull String ifaceName, @WifiAnnotations.ScanType int scanType, Set<Integer> freqs,
1584             List<String> hiddenNetworkSSIDs, boolean enable6GhzRnr) {
1585         List<byte[]> hiddenNetworkSsidsArrays = new ArrayList<>();
1586         for (String hiddenNetworkSsid : hiddenNetworkSSIDs) {
1587             try {
1588                 hiddenNetworkSsidsArrays.add(
1589                         NativeUtil.byteArrayFromArrayList(
1590                                 NativeUtil.decodeSsid(hiddenNetworkSsid)));
1591             } catch (IllegalArgumentException e) {
1592                 Log.e(TAG, "Illegal argument " + hiddenNetworkSsid, e);
1593                 continue;
1594             }
1595         }
1596         // enable6GhzRnr is a new parameter first introduced in Android S.
1597         if (SdkLevel.isAtLeastS()) {
1598             Bundle extraScanningParams = new Bundle();
1599             extraScanningParams.putBoolean(WifiNl80211Manager.SCANNING_PARAM_ENABLE_6GHZ_RNR,
1600                     enable6GhzRnr);
1601             return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays,
1602                     extraScanningParams);
1603         } else {
1604             return mWifiCondManager.startScan(ifaceName, scanType, freqs, hiddenNetworkSsidsArrays);
1605         }
1606     }
1607 
1608     /**
1609      * Fetch the latest scan result from kernel via wificond.
1610      * @param ifaceName Name of the interface.
1611      * @return Returns an ArrayList of ScanDetail.
1612      * Returns an empty ArrayList on failure.
1613      */
getScanResults(@onNull String ifaceName)1614     public ArrayList<ScanDetail> getScanResults(@NonNull String ifaceName) {
1615         if (mUseFakeScanDetails) {
1616             synchronized (mFakeScanDetails) {
1617                 ArrayList<ScanDetail> copy = new ArrayList<>();
1618                 for (ScanDetail sd: mFakeScanDetails) {
1619                     sd.getScanResult().ifaceName = ifaceName;
1620                     // otherwise the fake will be too old
1621                     sd.getScanResult().timestamp = SystemClock.elapsedRealtime() * 1000;
1622 
1623                     // clone the ScanResult (which was updated above) so that each call gets a
1624                     // unique timestamp
1625                     copy.add(new ScanDetail(new ScanResult(sd.getScanResult()),
1626                             sd.getNetworkDetail()));
1627                 }
1628                 return copy;
1629             }
1630         }
1631         return convertNativeScanResults(ifaceName, mWifiCondManager.getScanResults(
1632                 ifaceName, WifiNl80211Manager.SCAN_TYPE_SINGLE_SCAN));
1633     }
1634 
1635     /**
1636      * Start faking scan results - using information provided via
1637      * {@link #addFakeScanDetail(ScanDetail)}. Stop with {@link #stopFakingScanDetails()}.
1638      */
startFakingScanDetails()1639     public void startFakingScanDetails() {
1640         if (mBuildProperties.isUserBuild()) {
1641             Log.wtf(TAG, "Can't fake scan results in a user build!");
1642             return;
1643         }
1644         Log.d(TAG, "Starting faking scan results - " + mFakeScanDetails);
1645         mUseFakeScanDetails = true;
1646     }
1647 
1648     /**
1649      * Add fake scan result. Fakes are not used until activated via
1650      * {@link #startFakingScanDetails()}.
1651      * @param fakeScanDetail
1652      */
addFakeScanDetail(@onNull ScanDetail fakeScanDetail)1653     public void addFakeScanDetail(@NonNull ScanDetail fakeScanDetail) {
1654         synchronized (mFakeScanDetails) {
1655             mFakeScanDetails.add(fakeScanDetail);
1656         }
1657     }
1658 
1659     /**
1660      * Reset the fake scan result list updated via {@link #addFakeScanDetail(ScanDetail)} .}
1661      */
resetFakeScanDetails()1662     public void resetFakeScanDetails() {
1663         synchronized (mFakeScanDetails) {
1664             mFakeScanDetails.clear();
1665         }
1666     }
1667 
1668     /**
1669      * Stop faking scan results. Started with {@link #startFakingScanDetails()}.
1670      */
stopFakingScanDetails()1671     public void stopFakingScanDetails() {
1672         mUseFakeScanDetails = false;
1673     }
1674 
1675     /**
1676      * Fetch the latest scan result from kernel via wificond.
1677      * @param ifaceName Name of the interface.
1678      * @return Returns an ArrayList of ScanDetail.
1679      * Returns an empty ArrayList on failure.
1680      */
getPnoScanResults(@onNull String ifaceName)1681     public ArrayList<ScanDetail> getPnoScanResults(@NonNull String ifaceName) {
1682         return convertNativeScanResults(ifaceName, mWifiCondManager.getScanResults(ifaceName,
1683                 WifiNl80211Manager.SCAN_TYPE_PNO_SCAN));
1684     }
1685 
convertNativeScanResults(@onNull String ifaceName, List<NativeScanResult> nativeResults)1686     private ArrayList<ScanDetail> convertNativeScanResults(@NonNull String ifaceName,
1687             List<NativeScanResult> nativeResults) {
1688         ArrayList<ScanDetail> results = new ArrayList<>();
1689         for (NativeScanResult result : nativeResults) {
1690             WifiSsid wifiSsid = WifiSsid.createFromByteArray(result.getSsid());
1691             MacAddress bssidMac = result.getBssid();
1692             if (bssidMac == null) {
1693                 Log.e(TAG, "Invalid MAC (BSSID) for SSID " + wifiSsid);
1694                 continue;
1695             }
1696             String bssid = bssidMac.toString();
1697             ScanResult.InformationElement[] ies =
1698                     InformationElementUtil.parseInformationElements(result.getInformationElements());
1699             InformationElementUtil.Capabilities capabilities =
1700                     new InformationElementUtil.Capabilities();
1701             capabilities.from(ies, result.getCapabilities(), mIsEnhancedOpenSupported,
1702                               result.getFrequencyMhz());
1703             String flags = capabilities.generateCapabilitiesString();
1704             NetworkDetail networkDetail;
1705             try {
1706                 networkDetail = new NetworkDetail(bssid, ies, null, result.getFrequencyMhz());
1707             } catch (IllegalArgumentException e) {
1708                 Log.e(TAG, "Illegal argument for scan result with bssid: " + bssid, e);
1709                 continue;
1710             }
1711 
1712             ScanDetail scanDetail = new ScanDetail(networkDetail, wifiSsid, bssid, flags,
1713                     result.getSignalMbm() / 100, result.getFrequencyMhz(), result.getTsf(), ies,
1714                     null, result.getInformationElements());
1715             ScanResult scanResult = scanDetail.getScanResult();
1716             scanResult.setWifiStandard(wifiModeToWifiStandard(networkDetail.getWifiMode()));
1717             scanResult.ifaceName = ifaceName;
1718 
1719             // Fill up the radio chain info.
1720             scanResult.radioChainInfos =
1721                     new ScanResult.RadioChainInfo[result.getRadioChainInfos().size()];
1722             int idx = 0;
1723             for (RadioChainInfo nativeRadioChainInfo : result.getRadioChainInfos()) {
1724                 scanResult.radioChainInfos[idx] = new ScanResult.RadioChainInfo();
1725                 scanResult.radioChainInfos[idx].id = nativeRadioChainInfo.getChainId();
1726                 scanResult.radioChainInfos[idx].level = nativeRadioChainInfo.getLevelDbm();
1727                 idx++;
1728             }
1729             results.add(scanDetail);
1730         }
1731         if (mVerboseLoggingEnabled) {
1732             Log.d(TAG, "get " + results.size() + " scan results from wificond");
1733         }
1734 
1735         return results;
1736     }
1737 
1738     @WifiAnnotations.WifiStandard
wifiModeToWifiStandard(int wifiMode)1739     private static int wifiModeToWifiStandard(int wifiMode) {
1740         switch (wifiMode) {
1741             case InformationElementUtil.WifiMode.MODE_11A:
1742             case InformationElementUtil.WifiMode.MODE_11B:
1743             case InformationElementUtil.WifiMode.MODE_11G:
1744                 return ScanResult.WIFI_STANDARD_LEGACY;
1745             case InformationElementUtil.WifiMode.MODE_11N:
1746                 return ScanResult.WIFI_STANDARD_11N;
1747             case InformationElementUtil.WifiMode.MODE_11AC:
1748                 return ScanResult.WIFI_STANDARD_11AC;
1749             case InformationElementUtil.WifiMode.MODE_11AX:
1750                 return ScanResult.WIFI_STANDARD_11AX;
1751             case InformationElementUtil.WifiMode.MODE_UNDEFINED:
1752             default:
1753                 return ScanResult.WIFI_STANDARD_UNKNOWN;
1754         }
1755     }
1756 
1757     /**
1758      * Start PNO scan.
1759      * @param ifaceName Name of the interface.
1760      * @param pnoSettings Pno scan configuration.
1761      * @return true on success.
1762      */
startPnoScan(@onNull String ifaceName, PnoSettings pnoSettings)1763     public boolean startPnoScan(@NonNull String ifaceName, PnoSettings pnoSettings) {
1764         return mWifiCondManager.startPnoScan(ifaceName, pnoSettings.toNativePnoSettings(),
1765                 Runnable::run,
1766                 new WifiNl80211Manager.PnoScanRequestCallback() {
1767                     @Override
1768                     public void onPnoRequestSucceeded() {
1769                         mWifiMetrics.incrementPnoScanStartAttemptCount();
1770                     }
1771 
1772                     @Override
1773                     public void onPnoRequestFailed() {
1774                         mWifiMetrics.incrementPnoScanStartAttemptCount();
1775                         mWifiMetrics.incrementPnoScanFailedCount();
1776                     }
1777                 });
1778     }
1779 
1780     /**
1781      * Stop PNO scan.
1782      * @param ifaceName Name of the interface.
1783      * @return true on success.
1784      */
1785     public boolean stopPnoScan(@NonNull String ifaceName) {
1786         return mWifiCondManager.stopPnoScan(ifaceName);
1787     }
1788 
1789     /**
1790      * Sends an arbitrary 802.11 management frame on the current channel.
1791      *
1792      * @param ifaceName Name of the interface.
1793      * @param frame Bytes of the 802.11 management frame to be sent, including the header, but not
1794      *              including the frame check sequence (FCS).
1795      * @param callback A callback triggered when the transmitted frame is ACKed or the transmission
1796      *                 fails.
1797      * @param mcs The MCS index that the frame will be sent at. If mcs < 0, the driver will select
1798      *            the rate automatically. If the device does not support sending the frame at a
1799      *            specified MCS rate, the transmission will be aborted and
1800      *            {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called
1801      *            with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}.
1802      */
1803     public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame,
1804             @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) {
1805         mWifiCondManager.sendMgmtFrame(ifaceName, frame, mcs, Runnable::run, callback);
1806     }
1807 
1808     /**
1809      * Sends a probe request to the AP and waits for a response in order to determine whether
1810      * there is connectivity between the device and AP.
1811      *
1812      * @param ifaceName Name of the interface.
1813      * @param receiverMac the MAC address of the AP that the probe request will be sent to.
1814      * @param callback callback triggered when the probe was ACKed by the AP, or when
1815      *                an error occurs after the link probe was started.
1816      * @param mcs The MCS index that this probe will be sent at. If mcs < 0, the driver will select
1817      *            the rate automatically. If the device does not support sending the frame at a
1818      *            specified MCS rate, the transmission will be aborted and
1819      *            {@link WifiNl80211Manager.SendMgmtFrameCallback#onFailure(int)} will be called
1820      *            with reason {@link WifiNl80211Manager#SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED}.
1821      */
1822     public void probeLink(@NonNull String ifaceName, @NonNull MacAddress receiverMac,
1823             @NonNull WifiNl80211Manager.SendMgmtFrameCallback callback, int mcs) {
1824         if (callback == null) {
1825             Log.e(TAG, "callback cannot be null!");
1826             return;
1827         }
1828 
1829         if (receiverMac == null) {
1830             Log.e(TAG, "Receiver MAC address cannot be null!");
1831             callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
1832             return;
1833         }
1834 
1835         String senderMacStr = getMacAddress(ifaceName);
1836         if (senderMacStr == null) {
1837             Log.e(TAG, "Failed to get this device's MAC Address");
1838             callback.onFailure(WifiNl80211Manager.SEND_MGMT_FRAME_ERROR_UNKNOWN);
1839             return;
1840         }
1841 
1842         byte[] frame = buildProbeRequestFrame(
1843                 receiverMac.toByteArray(),
1844                 NativeUtil.macAddressToByteArray(senderMacStr));
1845         sendMgmtFrame(ifaceName, frame, callback, mcs);
1846     }
1847 
1848     // header = 24 bytes, minimal body = 2 bytes, no FCS (will be added by driver)
1849     private static final int BASIC_PROBE_REQUEST_FRAME_SIZE = 24 + 2;
1850 
1851     private byte[] buildProbeRequestFrame(byte[] receiverMac, byte[] transmitterMac) {
1852         ByteBuffer frame = ByteBuffer.allocate(BASIC_PROBE_REQUEST_FRAME_SIZE);
1853         // ByteBuffer is big endian by default, switch to little endian
1854         frame.order(ByteOrder.LITTLE_ENDIAN);
1855 
1856         // Protocol version = 0, Type = management, Subtype = Probe Request
1857         frame.put((byte) 0x40);
1858 
1859         // no flags set
1860         frame.put((byte) 0x00);
1861 
1862         // duration = 60 microseconds. Note: this is little endian
1863         // Note: driver should calculate the duration and replace it before sending, putting a
1864         // reasonable default value here just in case.
1865         frame.putShort((short) 0x3c);
1866 
1867         // receiver/destination MAC address byte array
1868         frame.put(receiverMac);
1869         // sender MAC address byte array
1870         frame.put(transmitterMac);
1871         // BSSID (same as receiver address since we are sending to the AP)
1872         frame.put(receiverMac);
1873 
1874         // Generate random sequence number, fragment number = 0
1875         // Note: driver should replace the sequence number with the correct number that is
1876         // incremented from the last used sequence number. Putting a random sequence number as a
1877         // default here just in case.
1878         // bit 0 is least significant bit, bit 15 is most significant bit
1879         // bits [0, 7] go in byte 0
1880         // bits [8, 15] go in byte 1
1881         // bits [0, 3] represent the fragment number (which is 0)
1882         // bits [4, 15] represent the sequence number (which is random)
1883         // clear bits [0, 3] to set fragment number = 0
1884         short sequenceAndFragmentNumber = (short) (mRandom.nextInt() & 0xfff0);
1885         frame.putShort(sequenceAndFragmentNumber);
1886 
1887         // NL80211 rejects frames with an empty body, so we just need to put a placeholder
1888         // information element.
1889         // Tag for SSID
1890         frame.put((byte) 0x00);
1891         // Represents broadcast SSID. Not accurate, but works as placeholder.
1892         frame.put((byte) 0x00);
1893 
1894         return frame.array();
1895     }
1896 
1897     private static final int CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS = 100;
1898     private static final int CONNECT_TO_HOSTAPD_RETRY_TIMES = 50;
1899     /**
1900      * This method is called to wait for establishing connection to hostapd.
1901      *
1902      * @return true if connection is established, false otherwise.
1903      */
1904     private boolean startAndWaitForHostapdConnection() {
1905         // Start initialization if not already started.
1906         if (!mHostapdHal.isInitializationStarted()
1907                 && !mHostapdHal.initialize()) {
1908             return false;
1909         }
1910         if (!mHostapdHal.startDaemon()) {
1911             Log.e(TAG, "Failed to startup hostapd");
1912             return false;
1913         }
1914         boolean connected = false;
1915         int connectTries = 0;
1916         while (!connected && connectTries++ < CONNECT_TO_HOSTAPD_RETRY_TIMES) {
1917             // Check if the initialization is complete.
1918             connected = mHostapdHal.isInitializationComplete();
1919             if (connected) {
1920                 break;
1921             }
1922             try {
1923                 Thread.sleep(CONNECT_TO_HOSTAPD_RETRY_INTERVAL_MS);
1924             } catch (InterruptedException ignore) {
1925             }
1926         }
1927         return connected;
1928     }
1929 
1930     /**
1931      * Start Soft AP operation using the provided configuration.
1932      *
1933      * @param ifaceName Name of the interface.
1934      * @param config Configuration to use for the soft ap created.
1935      * @param isMetered Indicates the network is metered or not.
1936      * @param listener Callback for AP events.
1937      * @return true on success, false otherwise.
1938      */
1939     public boolean startSoftAp(
1940             @NonNull String ifaceName, SoftApConfiguration config, boolean isMetered,
1941             SoftApListener listener) {
1942         if (mHostapdHal.isApInfoCallbackSupported()) {
1943             if (!mHostapdHal.registerApCallback(ifaceName, listener)) {
1944                 Log.e(TAG, "Failed to register ap listener");
1945                 return false;
1946             }
1947         } else {
1948             SoftApListenerFromWificond softApListenerFromWificond =
1949                     new SoftApListenerFromWificond(ifaceName, listener);
1950             if (!mWifiCondManager.registerApCallback(ifaceName,
1951                     Runnable::run, softApListenerFromWificond)) {
1952                 Log.e(TAG, "Failed to register ap listener from wificond");
1953                 return false;
1954             }
1955         }
1956 
1957         if (!mHostapdHal.addAccessPoint(ifaceName, config, isMetered, listener::onFailure)) {
1958             Log.e(TAG, "Failed to add acccess point");
1959             mWifiMetrics.incrementNumSetupSoftApInterfaceFailureDueToHostapd();
1960             return false;
1961         }
1962 
1963         return true;
1964     }
1965 
1966     /**
1967      * Force a softap client disconnect with specific reason code.
1968      *
1969      * @param ifaceName Name of the interface.
1970      * @param client Mac address to force disconnect in clients of the SoftAp.
1971      * @param reasonCode One of disconnect reason code which defined in {@link ApConfigUtil}.
1972      * @return true on success, false otherwise.
1973      */
1974     public boolean forceClientDisconnect(@NonNull String ifaceName,
1975             @NonNull MacAddress client, int reasonCode) {
1976         return mHostapdHal.forceClientDisconnect(ifaceName, client, reasonCode);
1977     }
1978 
1979     /**
1980      * Set MAC address of the given interface
1981      * @param interfaceName Name of the interface
1982      * @param mac Mac address to change into
1983      * @return true on success
1984      */
1985     public boolean setStaMacAddress(String interfaceName, MacAddress mac) {
1986         // TODO(b/72459123): Suppress interface down/up events from this call
1987         // Trigger an explicit disconnect to avoid losing the disconnect event reason (if currently
1988         // connected) from supplicant if the interface is brought down for MAC address change.
1989         disconnect(interfaceName);
1990         return mWifiVendorHal.setStaMacAddress(interfaceName, mac);
1991     }
1992 
1993     /**
1994      * Set MAC address of the given interface
1995      * @param interfaceName Name of the interface
1996      * @param mac Mac address to change into
1997      * @return true on success
1998      */
1999     public boolean setApMacAddress(String interfaceName, MacAddress mac) {
2000         return mWifiVendorHal.setApMacAddress(interfaceName, mac);
2001     }
2002 
2003     /**
2004      * Returns true if Hal version supports setMacAddress, otherwise false.
2005      *
2006      * @param interfaceName Name of the interface
2007      */
2008     public boolean isStaSetMacAddressSupported(@NonNull String interfaceName) {
2009         return mWifiVendorHal.isStaSetMacAddressSupported(interfaceName);
2010     }
2011 
2012     /**
2013      * Returns true if Hal version supports setMacAddress, otherwise false.
2014      *
2015      * @param interfaceName Name of the interface
2016      */
2017     public boolean isApSetMacAddressSupported(@NonNull String interfaceName) {
2018         return mWifiVendorHal.isApSetMacAddressSupported(interfaceName);
2019     }
2020 
2021     /**
2022      * Get the factory MAC address of the given interface
2023      * @param interfaceName Name of the interface.
2024      * @return factory MAC address, or null on a failed call or if feature is unavailable.
2025      */
2026     public MacAddress getStaFactoryMacAddress(@NonNull String interfaceName) {
2027         return mWifiVendorHal.getStaFactoryMacAddress(interfaceName);
2028     }
2029 
2030     /**
2031      * Get the factory MAC address of the given interface
2032      * @param interfaceName Name of the interface.
2033      * @return factory MAC address, or null on a failed call or if feature is unavailable.
2034      */
2035     public MacAddress getApFactoryMacAddress(@NonNull String interfaceName) {
2036         return mWifiVendorHal.getApFactoryMacAddress(interfaceName);
2037     }
2038 
2039     /**
2040      * Reset MAC address to factory MAC address on the given interface
2041      *
2042      * @param interfaceName Name of the interface
2043      * @return true for success
2044      */
2045     public boolean resetApMacToFactoryMacAddress(@NonNull String interfaceName) {
2046         return mWifiVendorHal.resetApMacToFactoryMacAddress(interfaceName);
2047     }
2048 
2049     /**
2050      * Set the unsafe channels and restrictions to avoid for coex.
2051      * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid
2052      * @param restrictions Bitmask of WifiManager.COEX_RESTRICTION_ flags
2053      */
2054     public void setCoexUnsafeChannels(
2055             @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) {
2056         mCachedCoexUnsafeChannels.clear();
2057         mCachedCoexUnsafeChannels.addAll(unsafeChannels);
2058         mCachedCoexRestrictions = restrictions;
2059         mWifiVendorHal.setCoexUnsafeChannels(mCachedCoexUnsafeChannels, mCachedCoexRestrictions);
2060     }
2061 
2062     /********************************************************
2063      * Hostapd operations
2064      ********************************************************/
2065 
2066     /**
2067      * Callback to notify hostapd death.
2068      */
2069     public interface HostapdDeathEventHandler {
2070         /**
2071          * Invoked when the supplicant dies.
2072          */
2073         void onDeath();
2074     }
2075 
2076     /********************************************************
2077      * Supplicant operations
2078      ********************************************************/
2079 
2080     /**
2081      * Callback to notify supplicant death.
2082      */
2083     public interface SupplicantDeathEventHandler {
2084         /**
2085          * Invoked when the supplicant dies.
2086          */
2087         void onDeath();
2088     }
2089 
2090     /**
2091      * Set supplicant log level
2092      *
2093      * @param turnOnVerbose Whether to turn on verbose logging or not.
2094      */
2095     public void setSupplicantLogLevel(boolean turnOnVerbose) {
2096         mSupplicantStaIfaceHal.setLogLevel(turnOnVerbose);
2097     }
2098 
2099     /**
2100      * Trigger a reconnection if the iface is disconnected.
2101      *
2102      * @param ifaceName Name of the interface.
2103      * @return true if request is sent successfully, false otherwise.
2104      */
2105     public boolean reconnect(@NonNull String ifaceName) {
2106         return mSupplicantStaIfaceHal.reconnect(ifaceName);
2107     }
2108 
2109     /**
2110      * Trigger a reassociation even if the iface is currently connected.
2111      *
2112      * @param ifaceName Name of the interface.
2113      * @return true if request is sent successfully, false otherwise.
2114      */
2115     public boolean reassociate(@NonNull String ifaceName) {
2116         return mSupplicantStaIfaceHal.reassociate(ifaceName);
2117     }
2118 
2119     /**
2120      * Trigger a disconnection from the currently connected network.
2121      *
2122      * @param ifaceName Name of the interface.
2123      * @return true if request is sent successfully, false otherwise.
2124      */
2125     public boolean disconnect(@NonNull String ifaceName) {
2126         return mSupplicantStaIfaceHal.disconnect(ifaceName);
2127     }
2128 
2129     /**
2130      * Makes a callback to HIDL to getMacAddress from supplicant
2131      *
2132      * @param ifaceName Name of the interface.
2133      * @return string containing the MAC address, or null on a failed call
2134      */
2135     public String getMacAddress(@NonNull String ifaceName) {
2136         return mSupplicantStaIfaceHal.getMacAddress(ifaceName);
2137     }
2138 
2139     public static final int RX_FILTER_TYPE_V4_MULTICAST = 0;
2140     public static final int RX_FILTER_TYPE_V6_MULTICAST = 1;
2141     /**
2142      * Start filtering out Multicast V4 packets
2143      * @param ifaceName Name of the interface.
2144      * @return {@code true} if the operation succeeded, {@code false} otherwise
2145      *
2146      * Multicast filtering rules work as follows:
2147      *
2148      * The driver can filter multicast (v4 and/or v6) and broadcast packets when in
2149      * a power optimized mode (typically when screen goes off).
2150      *
2151      * In order to prevent the driver from filtering the multicast/broadcast packets, we have to
2152      * add a DRIVER RXFILTER-ADD rule followed by DRIVER RXFILTER-START to make the rule effective
2153      *
2154      * DRIVER RXFILTER-ADD Num
2155      *   where Num = 0 - Unicast, 1 - Broadcast, 2 - Mutil4 or 3 - Multi6
2156      *
2157      * and DRIVER RXFILTER-START
2158      * In order to stop the usage of these rules, we do
2159      *
2160      * DRIVER RXFILTER-STOP
2161      * DRIVER RXFILTER-REMOVE Num
2162      *   where Num is as described for RXFILTER-ADD
2163      *
2164      * The  SETSUSPENDOPT driver command overrides the filtering rules
2165      */
2166     public boolean startFilteringMulticastV4Packets(@NonNull String ifaceName) {
2167         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2168                 && mSupplicantStaIfaceHal.removeRxFilter(
2169                         ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
2170                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2171     }
2172 
2173     /**
2174      * Stop filtering out Multicast V4 packets.
2175      * @param ifaceName Name of the interface.
2176      * @return {@code true} if the operation succeeded, {@code false} otherwise
2177      */
2178     public boolean stopFilteringMulticastV4Packets(@NonNull String ifaceName) {
2179         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2180                 && mSupplicantStaIfaceHal.addRxFilter(
2181                         ifaceName, RX_FILTER_TYPE_V4_MULTICAST)
2182                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2183     }
2184 
2185     /**
2186      * Start filtering out Multicast V6 packets
2187      * @param ifaceName Name of the interface.
2188      * @return {@code true} if the operation succeeded, {@code false} otherwise
2189      */
2190     public boolean startFilteringMulticastV6Packets(@NonNull String ifaceName) {
2191         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2192                 && mSupplicantStaIfaceHal.removeRxFilter(
2193                         ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
2194                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2195     }
2196 
2197     /**
2198      * Stop filtering out Multicast V6 packets.
2199      * @param ifaceName Name of the interface.
2200      * @return {@code true} if the operation succeeded, {@code false} otherwise
2201      */
2202     public boolean stopFilteringMulticastV6Packets(@NonNull String ifaceName) {
2203         return mSupplicantStaIfaceHal.stopRxFilter(ifaceName)
2204                 && mSupplicantStaIfaceHal.addRxFilter(
2205                         ifaceName, RX_FILTER_TYPE_V6_MULTICAST)
2206                 && mSupplicantStaIfaceHal.startRxFilter(ifaceName);
2207     }
2208 
2209     public static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED  = 0;
2210     public static final int BLUETOOTH_COEXISTENCE_MODE_DISABLED = 1;
2211     public static final int BLUETOOTH_COEXISTENCE_MODE_SENSE    = 2;
2212     /**
2213      * Sets the bluetooth coexistence mode.
2214      *
2215      * @param ifaceName Name of the interface.
2216      * @param mode One of {@link #BLUETOOTH_COEXISTENCE_MODE_DISABLED},
2217      *            {@link #BLUETOOTH_COEXISTENCE_MODE_ENABLED}, or
2218      *            {@link #BLUETOOTH_COEXISTENCE_MODE_SENSE}.
2219      * @return Whether the mode was successfully set.
2220      */
2221     public boolean setBluetoothCoexistenceMode(@NonNull String ifaceName, int mode) {
2222         return mSupplicantStaIfaceHal.setBtCoexistenceMode(ifaceName, mode);
2223     }
2224 
2225     /**
2226      * Enable or disable Bluetooth coexistence scan mode. When this mode is on,
2227      * some of the low-level scan parameters used by the driver are changed to
2228      * reduce interference with A2DP streaming.
2229      *
2230      * @param ifaceName Name of the interface.
2231      * @param setCoexScanMode whether to enable or disable this mode
2232      * @return {@code true} if the command succeeded, {@code false} otherwise.
2233      */
2234     public boolean setBluetoothCoexistenceScanMode(
2235             @NonNull String ifaceName, boolean setCoexScanMode) {
2236         return mSupplicantStaIfaceHal.setBtCoexistenceScanModeEnabled(
2237                 ifaceName, setCoexScanMode);
2238     }
2239 
2240     /**
2241      * Enable or disable suspend mode optimizations.
2242      *
2243      * @param ifaceName Name of the interface.
2244      * @param enabled true to enable, false otherwise.
2245      * @return true if request is sent successfully, false otherwise.
2246      */
2247     public boolean setSuspendOptimizations(@NonNull String ifaceName, boolean enabled) {
2248         return mSupplicantStaIfaceHal.setSuspendModeEnabled(ifaceName, enabled);
2249     }
2250 
2251     /**
2252      * Set country code for STA interface
2253      *
2254      * @param ifaceName Name of the STA interface.
2255      * @param countryCode 2 byte ASCII string. For ex: US, CA.
2256      * @return true if request is sent successfully, false otherwise.
2257      */
2258     public boolean setStaCountryCode(@NonNull String ifaceName, String countryCode) {
2259         if (mSupplicantStaIfaceHal.setCountryCode(ifaceName, countryCode)) {
2260             if (mCountryCodeChangeListener != null) {
2261                 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode);
2262             }
2263             return true;
2264         }
2265         return false;
2266     }
2267 
2268     /**
2269      * Flush all previously configured HLPs.
2270      *
2271      * @return true if request is sent successfully, false otherwise.
2272      */
2273     public boolean flushAllHlp(@NonNull String ifaceName) {
2274         return mSupplicantStaIfaceHal.flushAllHlp(ifaceName);
2275     }
2276 
2277     /**
2278      * Set FILS HLP packet.
2279      *
2280      * @param dst Destination MAC address.
2281      * @param hlpPacket Hlp Packet data in hex.
2282      * @return true if request is sent successfully, false otherwise.
2283      */
2284     public boolean addHlpReq(@NonNull String ifaceName, MacAddress dst, byte [] hlpPacket) {
2285         return mSupplicantStaIfaceHal.addHlpReq(ifaceName, dst.toByteArray(), hlpPacket);
2286     }
2287 
2288     /**
2289      * Initiate TDLS discover and setup or teardown with the specified peer.
2290      *
2291      * @param ifaceName Name of the interface.
2292      * @param macAddr MAC Address of the peer.
2293      * @param enable true to start discovery and setup, false to teardown.
2294      */
2295     public void startTdls(@NonNull String ifaceName, String macAddr, boolean enable) {
2296         if (enable) {
2297             mSupplicantStaIfaceHal.initiateTdlsDiscover(ifaceName, macAddr);
2298             mSupplicantStaIfaceHal.initiateTdlsSetup(ifaceName, macAddr);
2299         } else {
2300             mSupplicantStaIfaceHal.initiateTdlsTeardown(ifaceName, macAddr);
2301         }
2302     }
2303 
2304     /**
2305      * Start WPS pin display operation with the specified peer.
2306      *
2307      * @param ifaceName Name of the interface.
2308      * @param bssid BSSID of the peer.
2309      * @return true if request is sent successfully, false otherwise.
2310      */
2311     public boolean startWpsPbc(@NonNull String ifaceName, String bssid) {
2312         return mSupplicantStaIfaceHal.startWpsPbc(ifaceName, bssid);
2313     }
2314 
2315     /**
2316      * Start WPS pin keypad operation with the specified pin.
2317      *
2318      * @param ifaceName Name of the interface.
2319      * @param pin Pin to be used.
2320      * @return true if request is sent successfully, false otherwise.
2321      */
2322     public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
2323         return mSupplicantStaIfaceHal.startWpsPinKeypad(ifaceName, pin);
2324     }
2325 
2326     /**
2327      * Start WPS pin display operation with the specified peer.
2328      *
2329      * @param ifaceName Name of the interface.
2330      * @param bssid BSSID of the peer.
2331      * @return new pin generated on success, null otherwise.
2332      */
2333     public String startWpsPinDisplay(@NonNull String ifaceName, String bssid) {
2334         return mSupplicantStaIfaceHal.startWpsPinDisplay(ifaceName, bssid);
2335     }
2336 
2337     /**
2338      * Sets whether to use external sim for SIM/USIM processing.
2339      *
2340      * @param ifaceName Name of the interface.
2341      * @param external true to enable, false otherwise.
2342      * @return true if request is sent successfully, false otherwise.
2343      */
2344     public boolean setExternalSim(@NonNull String ifaceName, boolean external) {
2345         return mSupplicantStaIfaceHal.setExternalSim(ifaceName, external);
2346     }
2347 
2348     /**
2349      * Sim auth response types.
2350      */
2351     public static final String SIM_AUTH_RESP_TYPE_GSM_AUTH = "GSM-AUTH";
2352     public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTH = "UMTS-AUTH";
2353     public static final String SIM_AUTH_RESP_TYPE_UMTS_AUTS = "UMTS-AUTS";
2354 
2355     /**
2356      * EAP-SIM Error Codes
2357      */
2358     public static final int EAP_SIM_NOT_SUBSCRIBED = 1031;
2359     public static final int EAP_SIM_VENDOR_SPECIFIC_CERT_EXPIRED = 16385;
2360 
2361     /**
2362      * Send the sim auth response for the currently configured network.
2363      *
2364      * @param ifaceName Name of the interface.
2365      * @param type |GSM-AUTH|, |UMTS-AUTH| or |UMTS-AUTS|.
2366      * @param response Response params.
2367      * @return true if succeeds, false otherwise.
2368      */
2369     public boolean simAuthResponse(
2370             @NonNull String ifaceName, String type, String response) {
2371         if (SIM_AUTH_RESP_TYPE_GSM_AUTH.equals(type)) {
2372             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthResponse(
2373                     ifaceName, response);
2374         } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTH.equals(type)) {
2375             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthResponse(
2376                     ifaceName, response);
2377         } else if (SIM_AUTH_RESP_TYPE_UMTS_AUTS.equals(type)) {
2378             return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAutsResponse(
2379                     ifaceName, response);
2380         } else {
2381             return false;
2382         }
2383     }
2384 
2385     /**
2386      * Send the eap sim gsm auth failure for the currently configured network.
2387      *
2388      * @param ifaceName Name of the interface.
2389      * @return true if succeeds, false otherwise.
2390      */
2391     public boolean simAuthFailedResponse(@NonNull String ifaceName) {
2392         return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimGsmAuthFailure(ifaceName);
2393     }
2394 
2395     /**
2396      * Send the eap sim umts auth failure for the currently configured network.
2397      *
2398      * @param ifaceName Name of the interface.
2399      * @return true if succeeds, false otherwise.
2400      */
2401     public boolean umtsAuthFailedResponse(@NonNull String ifaceName) {
2402         return mSupplicantStaIfaceHal.sendCurrentNetworkEapSimUmtsAuthFailure(ifaceName);
2403     }
2404 
2405     /**
2406      * Send the eap identity response for the currently configured network.
2407      *
2408      * @param ifaceName Name of the interface.
2409      * @param unencryptedResponse String to send.
2410      * @param encryptedResponse String to send.
2411      * @return true if succeeds, false otherwise.
2412      */
2413     public boolean simIdentityResponse(@NonNull String ifaceName, String unencryptedResponse,
2414                                        String encryptedResponse) {
2415         return mSupplicantStaIfaceHal.sendCurrentNetworkEapIdentityResponse(ifaceName,
2416                 unencryptedResponse, encryptedResponse);
2417     }
2418 
2419     /**
2420      * This get anonymous identity from supplicant and returns it as a string.
2421      *
2422      * @param ifaceName Name of the interface.
2423      * @return anonymous identity string if succeeds, null otherwise.
2424      */
2425     public String getEapAnonymousIdentity(@NonNull String ifaceName) {
2426         String anonymousIdentity = mSupplicantStaIfaceHal
2427                 .getCurrentNetworkEapAnonymousIdentity(ifaceName);
2428 
2429         if (TextUtils.isEmpty(anonymousIdentity)) {
2430             return anonymousIdentity;
2431         }
2432 
2433         int indexOfDecoration = anonymousIdentity.lastIndexOf('!');
2434         if (indexOfDecoration >= 0) {
2435             if (anonymousIdentity.substring(indexOfDecoration).length() < 2) {
2436                 // Invalid identity, shouldn't happen
2437                 Log.e(TAG, "Unexpected anonymous identity: " + anonymousIdentity);
2438                 return null;
2439             }
2440             // Truncate RFC 7542 decorated prefix, if exists. Keep only the anonymous identity or
2441             // pseudonym.
2442             anonymousIdentity = anonymousIdentity.substring(indexOfDecoration + 1);
2443         }
2444 
2445         return anonymousIdentity;
2446     }
2447 
2448     /**
2449      * Start WPS pin registrar operation with the specified peer and pin.
2450      *
2451      * @param ifaceName Name of the interface.
2452      * @param bssid BSSID of the peer.
2453      * @param pin Pin to be used.
2454      * @return true if request is sent successfully, false otherwise.
2455      */
2456     public boolean startWpsRegistrar(@NonNull String ifaceName, String bssid, String pin) {
2457         return mSupplicantStaIfaceHal.startWpsRegistrar(ifaceName, bssid, pin);
2458     }
2459 
2460     /**
2461      * Cancels any ongoing WPS requests.
2462      *
2463      * @param ifaceName Name of the interface.
2464      * @return true if request is sent successfully, false otherwise.
2465      */
2466     public boolean cancelWps(@NonNull String ifaceName) {
2467         return mSupplicantStaIfaceHal.cancelWps(ifaceName);
2468     }
2469 
2470     /**
2471      * Set WPS device name.
2472      *
2473      * @param ifaceName Name of the interface.
2474      * @param name String to be set.
2475      * @return true if request is sent successfully, false otherwise.
2476      */
2477     public boolean setDeviceName(@NonNull String ifaceName, String name) {
2478         return mSupplicantStaIfaceHal.setWpsDeviceName(ifaceName, name);
2479     }
2480 
2481     /**
2482      * Set WPS device type.
2483      *
2484      * @param ifaceName Name of the interface.
2485      * @param type Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
2486      * @return true if request is sent successfully, false otherwise.
2487      */
2488     public boolean setDeviceType(@NonNull String ifaceName, String type) {
2489         return mSupplicantStaIfaceHal.setWpsDeviceType(ifaceName, type);
2490     }
2491 
2492     /**
2493      * Set WPS config methods
2494      *
2495      * @param cfg List of config methods.
2496      * @return true if request is sent successfully, false otherwise.
2497      */
2498     public boolean setConfigMethods(@NonNull String ifaceName, String cfg) {
2499         return mSupplicantStaIfaceHal.setWpsConfigMethods(ifaceName, cfg);
2500     }
2501 
2502     /**
2503      * Set WPS manufacturer.
2504      *
2505      * @param ifaceName Name of the interface.
2506      * @param value String to be set.
2507      * @return true if request is sent successfully, false otherwise.
2508      */
2509     public boolean setManufacturer(@NonNull String ifaceName, String value) {
2510         return mSupplicantStaIfaceHal.setWpsManufacturer(ifaceName, value);
2511     }
2512 
2513     /**
2514      * Set WPS model name.
2515      *
2516      * @param ifaceName Name of the interface.
2517      * @param value String to be set.
2518      * @return true if request is sent successfully, false otherwise.
2519      */
2520     public boolean setModelName(@NonNull String ifaceName, String value) {
2521         return mSupplicantStaIfaceHal.setWpsModelName(ifaceName, value);
2522     }
2523 
2524     /**
2525      * Set WPS model number.
2526      *
2527      * @param ifaceName Name of the interface.
2528      * @param value String to be set.
2529      * @return true if request is sent successfully, false otherwise.
2530      */
2531     public boolean setModelNumber(@NonNull String ifaceName, String value) {
2532         return mSupplicantStaIfaceHal.setWpsModelNumber(ifaceName, value);
2533     }
2534 
2535     /**
2536      * Set WPS serial number.
2537      *
2538      * @param ifaceName Name of the interface.
2539      * @param value String to be set.
2540      * @return true if request is sent successfully, false otherwise.
2541      */
2542     public boolean setSerialNumber(@NonNull String ifaceName, String value) {
2543         return mSupplicantStaIfaceHal.setWpsSerialNumber(ifaceName, value);
2544     }
2545 
2546     /**
2547      * Enable or disable power save mode.
2548      *
2549      * @param ifaceName Name of the interface.
2550      * @param enabled true to enable, false to disable.
2551      */
2552     public void setPowerSave(@NonNull String ifaceName, boolean enabled) {
2553         mSupplicantStaIfaceHal.setPowerSave(ifaceName, enabled);
2554     }
2555 
2556     /**
2557      * Enable or disable low latency mode.
2558      *
2559      * @param enabled true to enable, false to disable.
2560      * @return true on success, false on failure
2561      */
2562     public boolean setLowLatencyMode(boolean enabled) {
2563         return mWifiVendorHal.setLowLatencyMode(enabled);
2564     }
2565 
2566     /**
2567      * Set concurrency priority between P2P & STA operations.
2568      *
2569      * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
2570      *                            false otherwise.
2571      * @return true if request is sent successfully, false otherwise.
2572      */
2573     public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
2574         return mSupplicantStaIfaceHal.setConcurrencyPriority(isStaHigherPriority);
2575     }
2576 
2577     /**
2578      * Enable/Disable auto reconnect functionality in wpa_supplicant.
2579      *
2580      * @param ifaceName Name of the interface.
2581      * @param enable true to enable auto reconnecting, false to disable.
2582      * @return true if request is sent successfully, false otherwise.
2583      */
2584     public boolean enableStaAutoReconnect(@NonNull String ifaceName, boolean enable) {
2585         return mSupplicantStaIfaceHal.enableAutoReconnect(ifaceName, enable);
2586     }
2587 
2588     /**
2589      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
2590      * This method does the following:
2591      * 1. Abort any ongoing scan to unblock the connection request.
2592      * 2. Remove any existing network in wpa_supplicant(This implicitly triggers disconnect).
2593      * 3. Add a new network to wpa_supplicant.
2594      * 4. Save the provided configuration to wpa_supplicant.
2595      * 5. Select the new network in wpa_supplicant.
2596      * 6. Triggers reconnect command to wpa_supplicant.
2597      *
2598      * @param ifaceName Name of the interface.
2599      * @param configuration WifiConfiguration parameters for the provided network.
2600      * @return {@code true} if it succeeds, {@code false} otherwise
2601      */
2602     public boolean connectToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
2603         // Abort ongoing scan before connect() to unblock connection request.
2604         mWifiCondManager.abortScan(ifaceName);
2605         return mSupplicantStaIfaceHal.connectToNetwork(ifaceName, configuration);
2606     }
2607 
2608     /**
2609      * Initiates roaming to the already configured network in wpa_supplicant. If the network
2610      * configuration provided does not match the already configured network, then this triggers
2611      * a new connection attempt (instead of roam).
2612      * 1. Abort any ongoing scan to unblock the roam request.
2613      * 2. First check if we're attempting to connect to the same network as we currently have
2614      * configured.
2615      * 3. Set the new bssid for the network in wpa_supplicant.
2616      * 4. Triggers reassociate command to wpa_supplicant.
2617      *
2618      * @param ifaceName Name of the interface.
2619      * @param configuration WifiConfiguration parameters for the provided network.
2620      * @return {@code true} if it succeeds, {@code false} otherwise
2621      */
2622     public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration configuration) {
2623         // Abort ongoing scan before connect() to unblock roaming request.
2624         mWifiCondManager.abortScan(ifaceName);
2625         return mSupplicantStaIfaceHal.roamToNetwork(ifaceName, configuration);
2626     }
2627 
2628     /**
2629      * Remove all the networks.
2630      *
2631      * @param ifaceName Name of the interface.
2632      * @return {@code true} if it succeeds, {@code false} otherwise
2633      */
2634     public boolean removeAllNetworks(@NonNull String ifaceName) {
2635         return mSupplicantStaIfaceHal.removeAllNetworks(ifaceName);
2636     }
2637 
2638     /**
2639      * Disable the currently configured network in supplicant
2640      *
2641      * @param ifaceName Name of the interface.
2642      */
2643     public boolean disableNetwork(@NonNull String ifaceName) {
2644         return mSupplicantStaIfaceHal.disableCurrentNetwork(ifaceName);
2645     }
2646 
2647     /**
2648      * Set the BSSID for the currently configured network in wpa_supplicant.
2649      *
2650      * @param ifaceName Name of the interface.
2651      * @return true if successful, false otherwise.
2652      */
2653     public boolean setNetworkBSSID(@NonNull String ifaceName, String bssid) {
2654         return mSupplicantStaIfaceHal.setCurrentNetworkBssid(ifaceName, bssid);
2655     }
2656 
2657     /**
2658      * Initiate ANQP query.
2659      *
2660      * @param ifaceName Name of the interface.
2661      * @param bssid BSSID of the AP to be queried
2662      * @param anqpIds Set of anqp IDs.
2663      * @param hs20Subtypes Set of HS20 subtypes.
2664      * @return true on success, false otherwise.
2665      */
2666     public boolean requestAnqp(
2667             @NonNull String ifaceName, String bssid, Set<Integer> anqpIds,
2668             Set<Integer> hs20Subtypes) {
2669         if (bssid == null || ((anqpIds == null || anqpIds.isEmpty())
2670                 && (hs20Subtypes == null || hs20Subtypes.isEmpty()))) {
2671             Log.e(TAG, "Invalid arguments for ANQP request.");
2672             return false;
2673         }
2674         ArrayList<Short> anqpIdList = new ArrayList<>();
2675         for (Integer anqpId : anqpIds) {
2676             anqpIdList.add(anqpId.shortValue());
2677         }
2678         ArrayList<Integer> hs20SubtypeList = new ArrayList<>();
2679         hs20SubtypeList.addAll(hs20Subtypes);
2680         return mSupplicantStaIfaceHal.initiateAnqpQuery(
2681                 ifaceName, bssid, anqpIdList, hs20SubtypeList);
2682     }
2683 
2684     /**
2685      * Request a passpoint icon file |filename| from the specified AP |bssid|.
2686      *
2687      * @param ifaceName Name of the interface.
2688      * @param bssid BSSID of the AP
2689      * @param fileName name of the icon file
2690      * @return true if request is sent successfully, false otherwise
2691      */
2692     public boolean requestIcon(@NonNull String ifaceName, String  bssid, String fileName) {
2693         if (bssid == null || fileName == null) {
2694             Log.e(TAG, "Invalid arguments for Icon request.");
2695             return false;
2696         }
2697         return mSupplicantStaIfaceHal.initiateHs20IconQuery(ifaceName, bssid, fileName);
2698     }
2699 
2700     /**
2701      * Initiate Venue URL ANQP query.
2702      *
2703      * @param ifaceName Name of the interface.
2704      * @param bssid BSSID of the AP to be queried
2705      * @return true on success, false otherwise.
2706      */
2707     public boolean requestVenueUrlAnqp(
2708             @NonNull String ifaceName, String bssid) {
2709         if (bssid == null) {
2710             Log.e(TAG, "Invalid arguments for Venue URL ANQP request.");
2711             return false;
2712         }
2713         return mSupplicantStaIfaceHal.initiateVenueUrlAnqpQuery(ifaceName, bssid);
2714     }
2715 
2716     /**
2717      * Get the currently configured network's WPS NFC token.
2718      *
2719      * @param ifaceName Name of the interface.
2720      * @return Hex string corresponding to the WPS NFC token.
2721      */
2722     public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
2723         return mSupplicantStaIfaceHal.getCurrentNetworkWpsNfcConfigurationToken(ifaceName);
2724     }
2725 
2726     /**
2727      * Clean HAL cached data for |networkId|.
2728      *
2729      * @param networkId network id of the network to be removed from supplicant.
2730      */
2731     public void removeNetworkCachedData(int networkId) {
2732         mSupplicantStaIfaceHal.removeNetworkCachedData(networkId);
2733     }
2734 
2735     /** Clear HAL cached data for |networkId| if MAC address is changed.
2736      *
2737      * @param networkId network id of the network to be checked.
2738      * @param curMacAddress current MAC address
2739      */
2740     public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
2741         mSupplicantStaIfaceHal.removeNetworkCachedDataIfNeeded(networkId, curMacAddress);
2742     }
2743 
2744     /*
2745      * DPP
2746      */
2747 
2748     /**
2749      * Adds a DPP peer URI to the URI list.
2750      *
2751      * @param ifaceName Interface name
2752      * @param uri Bootstrap (URI) string (e.g. DPP:....)
2753      * @return ID, or -1 for failure
2754      */
2755     public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) {
2756         return mSupplicantStaIfaceHal.addDppPeerUri(ifaceName, uri);
2757     }
2758 
2759     /**
2760      * Removes a DPP URI to the URI list given an ID.
2761      *
2762      * @param ifaceName Interface name
2763      * @param bootstrapId Bootstrap (URI) ID
2764      * @return true when operation is successful, or false for failure
2765      */
2766     public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId)  {
2767         return mSupplicantStaIfaceHal.removeDppUri(ifaceName, bootstrapId);
2768     }
2769 
2770     /**
2771      * Stops/aborts DPP Initiator request
2772      *
2773      * @param ifaceName Interface name
2774      * @return true when operation is successful, or false for failure
2775      */
2776     public boolean stopDppInitiator(@NonNull String ifaceName)  {
2777         return mSupplicantStaIfaceHal.stopDppInitiator(ifaceName);
2778     }
2779 
2780     /**
2781      * Starts DPP Configurator-Initiator request
2782      *
2783      * @param ifaceName Interface name
2784      * @param peerBootstrapId Peer's bootstrap (URI) ID
2785      * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none
2786      * @param ssid SSID of the selected network
2787      * @param password Password of the selected network, or
2788      * @param psk PSK of the selected network in hexadecimal representation
2789      * @param netRole The network role of the enrollee (STA or AP)
2790      * @param securityAkm Security AKM to use: PSK, SAE
2791      * @return true when operation is successful, or false for failure
2792      */
2793     public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId,
2794             int ownBootstrapId, @NonNull String ssid, String password, String psk,
2795             int netRole, int securityAkm)  {
2796         return mSupplicantStaIfaceHal.startDppConfiguratorInitiator(ifaceName, peerBootstrapId,
2797                 ownBootstrapId, ssid, password, psk, netRole, securityAkm);
2798     }
2799 
2800     /**
2801      * Starts DPP Enrollee-Initiator request
2802      *
2803      * @param ifaceName Interface name
2804      * @param peerBootstrapId Peer's bootstrap (URI) ID
2805      * @param ownBootstrapId Own bootstrap (URI) ID - Optional, 0 for none
2806      * @return true when operation is successful, or false for failure
2807      */
2808     public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId,
2809             int ownBootstrapId)  {
2810         return mSupplicantStaIfaceHal.startDppEnrolleeInitiator(ifaceName, peerBootstrapId,
2811                 ownBootstrapId);
2812     }
2813 
2814     /**
2815      * Callback to notify about DPP success, failure and progress events.
2816      */
2817     public interface DppEventCallback {
2818         /**
2819          * Called when local DPP Enrollee successfully receives a new Wi-Fi configuration from the
2820          * peer DPP configurator.
2821          *
2822          * @param newWifiConfiguration New Wi-Fi configuration received from the configurator
2823          */
2824         void onSuccessConfigReceived(WifiConfiguration newWifiConfiguration);
2825 
2826         /**
2827          * DPP Success event.
2828          *
2829          * @param dppStatusCode Status code of the success event.
2830          */
2831         void onSuccess(int dppStatusCode);
2832 
2833         /**
2834          * DPP Progress event.
2835          *
2836          * @param dppStatusCode Status code of the progress event.
2837          */
2838         void onProgress(int dppStatusCode);
2839 
2840         /**
2841          * DPP Failure event.
2842          *
2843          * @param dppStatusCode Status code of the failure event.
2844          * @param ssid SSID of the network the Enrollee tried to connect to.
2845          * @param channelList List of channels the Enrollee scanned for the network.
2846          * @param bandList List of bands the Enrollee supports.
2847          */
2848         void onFailure(int dppStatusCode, String ssid, String channelList, int[] bandList);
2849     }
2850 
2851     /**
2852      * Class to get generated bootstrap info for DPP responder operation.
2853      */
2854     public static class DppBootstrapQrCodeInfo {
2855         public int bootstrapId;
2856         public int listenChannel;
2857         public String uri = new String();
2858         DppBootstrapQrCodeInfo() {
2859             bootstrapId = -1;
2860             listenChannel = -1;
2861         }
2862     }
2863 
2864     /**
2865      * Generate DPP bootstrap Information:Bootstrap ID, DPP URI and the listen channel.
2866      *
2867      * @param ifaceName Interface name
2868      * @param deviceInfo Device specific info to attach in DPP URI.
2869      * @param dppCurve Elliptic curve cryptography type used to generate DPP
2870      *                 public/private key pair.
2871      * @return ID, or -1 for failure
2872      */
2873     public DppBootstrapQrCodeInfo generateDppBootstrapInfoForResponder(@NonNull String ifaceName,
2874             String deviceInfo, int dppCurve) {
2875         return mSupplicantStaIfaceHal.generateDppBootstrapInfoForResponder(ifaceName,
2876                 getMacAddress(ifaceName), deviceInfo, dppCurve);
2877     }
2878 
2879     /**
2880      * start DPP Enrollee responder mode.
2881      *
2882      * @param ifaceName Interface name
2883      * @param listenChannel Listen channel to wait for DPP authentication request.
2884      * @return ID, or -1 for failure
2885      */
2886     public boolean startDppEnrolleeResponder(@NonNull String ifaceName, int listenChannel) {
2887         return mSupplicantStaIfaceHal.startDppEnrolleeResponder(ifaceName, listenChannel);
2888     }
2889 
2890     /**
2891      * Stops/aborts DPP Responder request
2892      *
2893      * @param ifaceName Interface name
2894      * @param ownBootstrapId Bootstrap (URI) ID
2895      * @return true when operation is successful, or false for failure
2896      */
2897     public boolean stopDppResponder(@NonNull String ifaceName, int ownBootstrapId)  {
2898         return mSupplicantStaIfaceHal.stopDppResponder(ifaceName, ownBootstrapId);
2899     }
2900 
2901 
2902     /**
2903      * Registers DPP event callbacks.
2904      *
2905      * @param dppEventCallback Callback object.
2906      */
2907     public void registerDppEventCallback(DppEventCallback dppEventCallback) {
2908         mSupplicantStaIfaceHal.registerDppCallback(dppEventCallback);
2909     }
2910 
2911     /********************************************************
2912      * Vendor HAL operations
2913      ********************************************************/
2914     /**
2915      * Callback to notify vendor HAL death.
2916      */
2917     public interface VendorHalDeathEventHandler {
2918         /**
2919          * Invoked when the vendor HAL dies.
2920          */
2921         void onDeath();
2922     }
2923 
2924     /**
2925      * Callback to notify when vendor HAL detects that a change in radio mode.
2926      */
2927     public interface VendorHalRadioModeChangeEventHandler {
2928         /**
2929          * Invoked when the vendor HAL detects a change to MCC mode.
2930          * MCC (Multi channel concurrency) = Multiple interfaces are active on the same band,
2931          * different channels, same radios.
2932          *
2933          * @param band Band on which MCC is detected (specified by one of the
2934          *             WifiScanner.WIFI_BAND_* constants)
2935          */
2936         void onMcc(int band);
2937         /**
2938          * Invoked when the vendor HAL detects a change to SCC mode.
2939          * SCC (Single channel concurrency) = Multiple interfaces are active on the same band, same
2940          * channels, same radios.
2941          *
2942          * @param band Band on which SCC is detected (specified by one of the
2943          *             WifiScanner.WIFI_BAND_* constants)
2944          */
2945         void onScc(int band);
2946         /**
2947          * Invoked when the vendor HAL detects a change to SBS mode.
2948          * SBS (Single Band Simultaneous) = Multiple interfaces are active on the same band,
2949          * different channels, different radios.
2950          *
2951          * @param band Band on which SBS is detected (specified by one of the
2952          *             WifiScanner.WIFI_BAND_* constants)
2953          */
2954         void onSbs(int band);
2955         /**
2956          * Invoked when the vendor HAL detects a change to DBS mode.
2957          * DBS (Dual Band Simultaneous) = Multiple interfaces are active on the different bands,
2958          * different channels, different radios.
2959          */
2960         void onDbs();
2961     }
2962 
2963     /**
2964      * Tests whether the HAL is running or not
2965      */
2966     public boolean isHalStarted() {
2967         return mWifiVendorHal.isHalStarted();
2968     }
2969 
2970     // TODO: Change variable names to camel style.
2971     public static class ScanCapabilities {
2972         public int  max_scan_cache_size;
2973         public int  max_scan_buckets;
2974         public int  max_ap_cache_per_scan;
2975         public int  max_rssi_sample_size;
2976         public int  max_scan_reporting_threshold;
2977     }
2978 
2979     /**
2980      * Gets the scan capabilities
2981      *
2982      * @param ifaceName Name of the interface.
2983      * @param capabilities object to be filled in
2984      * @return true for success. false for failure
2985      */
2986     public boolean getBgScanCapabilities(
2987             @NonNull String ifaceName, ScanCapabilities capabilities) {
2988         return mWifiVendorHal.getBgScanCapabilities(ifaceName, capabilities);
2989     }
2990 
2991     public static class ChannelSettings {
2992         public int frequency;
2993         public int dwell_time_ms;
2994         public boolean passive;
2995     }
2996 
2997     public static class BucketSettings {
2998         public int bucket;
2999         public int band;
3000         public int period_ms;
3001         public int max_period_ms;
3002         public int step_count;
3003         public int report_events;
3004         public int num_channels;
3005         public ChannelSettings[] channels;
3006     }
3007 
3008     /**
3009      * Network parameters for hidden networks to be scanned for.
3010      */
3011     public static class HiddenNetwork {
3012         public String ssid;
3013 
3014         @Override
3015         public boolean equals(Object otherObj) {
3016             if (this == otherObj) {
3017                 return true;
3018             } else if (otherObj == null || getClass() != otherObj.getClass()) {
3019                 return false;
3020             }
3021             HiddenNetwork other = (HiddenNetwork) otherObj;
3022             return Objects.equals(ssid, other.ssid);
3023         }
3024 
3025         @Override
3026         public int hashCode() {
3027             return Objects.hash(ssid);
3028         }
3029     }
3030 
3031     public static class ScanSettings {
3032         /**
3033          * Type of scan to perform. One of {@link WifiScanner#SCAN_TYPE_LOW_LATENCY},
3034          * {@link WifiScanner#SCAN_TYPE_LOW_POWER} or {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}.
3035          */
3036         @WifiAnnotations.ScanType
3037         public int scanType;
3038         public int base_period_ms;
3039         public int max_ap_per_scan;
3040         public int report_threshold_percent;
3041         public int report_threshold_num_scans;
3042         public int num_buckets;
3043         public boolean enable6GhzRnr;
3044         /* Not used for bg scans. Only works for single scans. */
3045         public HiddenNetwork[] hiddenNetworks;
3046         public BucketSettings[] buckets;
3047     }
3048 
3049     /**
3050      * Network parameters to start PNO scan.
3051      */
3052     public static class PnoNetwork {
3053         public String ssid;
3054         public byte flags;
3055         public byte auth_bit_field;
3056         public int[] frequencies;
3057 
3058         @Override
3059         public boolean equals(Object otherObj) {
3060             if (this == otherObj) {
3061                 return true;
3062             } else if (otherObj == null || getClass() != otherObj.getClass()) {
3063                 return false;
3064             }
3065             PnoNetwork other = (PnoNetwork) otherObj;
3066             return ((Objects.equals(ssid, other.ssid)) && (flags == other.flags)
3067                     && (auth_bit_field == other.auth_bit_field))
3068                     && Arrays.equals(frequencies, other.frequencies);
3069         }
3070 
3071         @Override
3072         public int hashCode() {
3073             return Objects.hash(ssid, flags, auth_bit_field, frequencies);
3074         }
3075 
3076         android.net.wifi.nl80211.PnoNetwork toNativePnoNetwork() {
3077             android.net.wifi.nl80211.PnoNetwork nativePnoNetwork =
3078                     new android.net.wifi.nl80211.PnoNetwork();
3079             nativePnoNetwork.setHidden(
3080                     (flags & WifiScanner.PnoSettings.PnoNetwork.FLAG_DIRECTED_SCAN) != 0);
3081             try {
3082                 nativePnoNetwork.setSsid(
3083                         NativeUtil.byteArrayFromArrayList(NativeUtil.decodeSsid(ssid)));
3084             } catch (IllegalArgumentException e) {
3085                 Log.e(TAG, "Illegal argument " + ssid, e);
3086                 return null;
3087             }
3088             nativePnoNetwork.setFrequenciesMhz(frequencies);
3089             return nativePnoNetwork;
3090         }
3091     }
3092 
3093     /**
3094      * Parameters to start PNO scan. This holds the list of networks which are going to used for
3095      * PNO scan.
3096      */
3097     public static class PnoSettings {
3098         public int min5GHzRssi;
3099         public int min24GHzRssi;
3100         public int min6GHzRssi;
3101         public int periodInMs;
3102         public boolean isConnected;
3103         public PnoNetwork[] networkList;
3104 
3105         android.net.wifi.nl80211.PnoSettings toNativePnoSettings() {
3106             android.net.wifi.nl80211.PnoSettings nativePnoSettings =
3107                     new android.net.wifi.nl80211.PnoSettings();
3108             nativePnoSettings.setIntervalMillis(periodInMs);
3109             nativePnoSettings.setMin2gRssiDbm(min24GHzRssi);
3110             nativePnoSettings.setMin5gRssiDbm(min5GHzRssi);
3111             nativePnoSettings.setMin6gRssiDbm(min6GHzRssi);
3112 
3113             List<android.net.wifi.nl80211.PnoNetwork> pnoNetworks = new ArrayList<>();
3114             if (networkList != null) {
3115                 for (PnoNetwork network : networkList) {
3116                     android.net.wifi.nl80211.PnoNetwork nativeNetwork =
3117                             network.toNativePnoNetwork();
3118                     if (nativeNetwork != null) {
3119                         pnoNetworks.add(nativeNetwork);
3120                     }
3121                 }
3122             }
3123             nativePnoSettings.setPnoNetworks(pnoNetworks);
3124             return nativePnoSettings;
3125         }
3126     }
3127 
3128     public static interface ScanEventHandler {
3129         /**
3130          * Called for each AP as it is found with the entire contents of the beacon/probe response.
3131          * Only called when WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT is specified.
3132          */
3133         void onFullScanResult(ScanResult fullScanResult, int bucketsScanned);
3134         /**
3135          * Callback on an event during a gscan scan.
3136          * See WifiNative.WIFI_SCAN_* for possible values.
3137          */
3138         void onScanStatus(int event);
3139         /**
3140          * Called with the current cached scan results when gscan is paused.
3141          */
3142         void onScanPaused(WifiScanner.ScanData[] data);
3143         /**
3144          * Called with the current cached scan results when gscan is resumed.
3145          */
3146         void onScanRestarted();
3147     }
3148 
3149     /**
3150      * Handler to notify the occurrence of various events during PNO scan.
3151      */
3152     public interface PnoEventHandler {
3153         /**
3154          * Callback to notify when one of the shortlisted networks is found during PNO scan.
3155          * @param results List of Scan results received.
3156          */
3157         void onPnoNetworkFound(ScanResult[] results);
3158 
3159         /**
3160          * Callback to notify when the PNO scan schedule fails.
3161          */
3162         void onPnoScanFailed();
3163     }
3164 
3165     public static final int WIFI_SCAN_RESULTS_AVAILABLE = 0;
3166     public static final int WIFI_SCAN_THRESHOLD_NUM_SCANS = 1;
3167     public static final int WIFI_SCAN_THRESHOLD_PERCENT = 2;
3168     public static final int WIFI_SCAN_FAILED = 3;
3169 
3170     /**
3171      * Starts a background scan.
3172      * Any ongoing scan will be stopped first
3173      *
3174      * @param ifaceName Name of the interface.
3175      * @param settings     to control the scan
3176      * @param eventHandler to call with the results
3177      * @return true for success
3178      */
3179     public boolean startBgScan(
3180             @NonNull String ifaceName, ScanSettings settings, ScanEventHandler eventHandler) {
3181         return mWifiVendorHal.startBgScan(ifaceName, settings, eventHandler);
3182     }
3183 
3184     /**
3185      * Stops any ongoing backgound scan
3186      * @param ifaceName Name of the interface.
3187      */
3188     public void stopBgScan(@NonNull String ifaceName) {
3189         mWifiVendorHal.stopBgScan(ifaceName);
3190     }
3191 
3192     /**
3193      * Pauses an ongoing backgound scan
3194      * @param ifaceName Name of the interface.
3195      */
3196     public void pauseBgScan(@NonNull String ifaceName) {
3197         mWifiVendorHal.pauseBgScan(ifaceName);
3198     }
3199 
3200     /**
3201      * Restarts a paused scan
3202      * @param ifaceName Name of the interface.
3203      */
3204     public void restartBgScan(@NonNull String ifaceName) {
3205         mWifiVendorHal.restartBgScan(ifaceName);
3206     }
3207 
3208     /**
3209      * Gets the latest scan results received.
3210      * @param ifaceName Name of the interface.
3211      */
3212     public WifiScanner.ScanData[] getBgScanResults(@NonNull String ifaceName) {
3213         return mWifiVendorHal.getBgScanResults(ifaceName);
3214     }
3215 
3216     /**
3217      * Gets the latest link layer stats
3218      * @param ifaceName Name of the interface.
3219      */
3220     public WifiLinkLayerStats getWifiLinkLayerStats(@NonNull String ifaceName) {
3221         return mWifiVendorHal.getWifiLinkLayerStats(ifaceName);
3222     }
3223 
3224     /**
3225      * Gets the usable channels
3226      * @param band one of the {@code WifiScanner#WIFI_BAND_*} constants.
3227      * @param mode bitmask of {@code WifiAvailablechannel#OP_MODE_*} constants.
3228      * @param filter bitmask of filters (regulatory, coex, concurrency).
3229      *
3230      * @return list of channels
3231      */
3232     public List<WifiAvailableChannel> getUsableChannels(
3233             @WifiScanner.WifiBand int band,
3234             @WifiAvailableChannel.OpMode int mode,
3235             @WifiAvailableChannel.Filter int filter) {
3236         return mWifiVendorHal.getUsableChannels(band, mode, filter);
3237     }
3238 
3239     /**
3240      * Returns whether STA + AP concurrency is supported or not.
3241      */
3242     public boolean isStaApConcurrencySupported() {
3243         synchronized (mLock) {
3244             return mWifiVendorHal.isStaApConcurrencySupported();
3245         }
3246     }
3247 
3248     /**
3249      * Returns whether STA + STA concurrency is supported or not.
3250      */
3251     public boolean isStaStaConcurrencySupported() {
3252         synchronized (mLock) {
3253             return mWifiVendorHal.isStaStaConcurrencySupported();
3254         }
3255     }
3256 
3257     /**
3258      * Returns whether a new AP iface can be created or not.
3259      */
3260     public boolean isItPossibleToCreateApIface(@NonNull WorkSource requestorWs) {
3261         synchronized (mLock) {
3262             return mWifiVendorHal.isItPossibleToCreateApIface(requestorWs);
3263         }
3264     }
3265 
3266     /**
3267      * Returns whether a new STA iface can be created or not.
3268      */
3269     public boolean isItPossibleToCreateStaIface(@NonNull WorkSource requestorWs) {
3270         synchronized (mLock) {
3271             return mWifiVendorHal.isItPossibleToCreateStaIface(requestorWs);
3272         }
3273     }
3274 
3275     /**
3276      * Set primary connection when multiple STA ifaces are active.
3277      *
3278      * @param ifaceName Name of the interface.
3279      * @return true for success
3280      */
3281     public boolean setMultiStaPrimaryConnection(@NonNull String ifaceName) {
3282         synchronized (mLock) {
3283             return mWifiVendorHal.setMultiStaPrimaryConnection(ifaceName);
3284         }
3285     }
3286 
3287     /**
3288      * Multi STA use case flags.
3289      */
3290     public static final int DUAL_STA_TRANSIENT_PREFER_PRIMARY = 0;
3291     public static final int DUAL_STA_NON_TRANSIENT_UNBIASED = 1;
3292 
3293     @IntDef({DUAL_STA_TRANSIENT_PREFER_PRIMARY, DUAL_STA_NON_TRANSIENT_UNBIASED})
3294     @Retention(RetentionPolicy.SOURCE)
3295     public @interface MultiStaUseCase{}
3296 
3297     /**
3298      * Set use-case when multiple STA ifaces are active.
3299      *
3300      * @param useCase one of the use cases.
3301      * @return true for success
3302      */
3303     public boolean setMultiStaUseCase(@MultiStaUseCase int useCase) {
3304         synchronized (mLock) {
3305             return mWifiVendorHal.setMultiStaUseCase(useCase);
3306         }
3307     }
3308 
3309     /**
3310      * Get the supported features
3311      *
3312      * @param ifaceName Name of the interface.
3313      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
3314      */
3315     public long getSupportedFeatureSet(@NonNull String ifaceName) {
3316         synchronized (mLock) {
3317             Iface iface = mIfaceMgr.getIface(ifaceName);
3318             if (iface == null) {
3319                 Log.e(TAG, "Could not get Iface object for interface " + ifaceName);
3320                 return 0;
3321             }
3322 
3323             return iface.featureSet;
3324         }
3325     }
3326 
3327     /**
3328      * Get the supported features
3329      *
3330      * @param ifaceName Name of the interface.
3331      * @return bitmask defined by WifiManager.WIFI_FEATURE_*
3332      */
3333     private long getSupportedFeatureSetInternal(@NonNull String ifaceName) {
3334         return mSupplicantStaIfaceHal.getAdvancedCapabilities(ifaceName)
3335                 | mWifiVendorHal.getSupportedFeatureSet(ifaceName)
3336                 | mSupplicantStaIfaceHal.getWpaDriverFeatureSet(ifaceName);
3337     }
3338 
3339     /**
3340      * Class to retrieve connection capability parameters after association
3341      */
3342     public static class ConnectionCapabilities {
3343         public @WifiAnnotations.WifiStandard int wifiStandard;
3344         public int channelBandwidth;
3345         public int maxNumberTxSpatialStreams;
3346         public int maxNumberRxSpatialStreams;
3347         public boolean is11bMode;
3348         ConnectionCapabilities() {
3349             wifiStandard = ScanResult.WIFI_STANDARD_UNKNOWN;
3350             channelBandwidth = ScanResult.CHANNEL_WIDTH_20MHZ;
3351             maxNumberTxSpatialStreams = 1;
3352             maxNumberRxSpatialStreams = 1;
3353             is11bMode = false;
3354         }
3355     }
3356 
3357     /**
3358      * Returns connection capabilities of the current network
3359      *
3360      * @param ifaceName Name of the interface.
3361      * @return connection capabilities of the current network
3362      */
3363     public ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) {
3364         return mSupplicantStaIfaceHal.getConnectionCapabilities(ifaceName);
3365     }
3366 
3367     /**
3368      * Get the APF (Android Packet Filter) capabilities of the device
3369      * @param ifaceName Name of the interface.
3370      */
3371     public ApfCapabilities getApfCapabilities(@NonNull String ifaceName) {
3372         return mWifiVendorHal.getApfCapabilities(ifaceName);
3373     }
3374 
3375     /**
3376      * Installs an APF program on this iface, replacing any existing program.
3377      *
3378      * @param ifaceName Name of the interface
3379      * @param filter is the android packet filter program
3380      * @return true for success
3381      */
3382     public boolean installPacketFilter(@NonNull String ifaceName, byte[] filter) {
3383         return mWifiVendorHal.installPacketFilter(ifaceName, filter);
3384     }
3385 
3386     /**
3387      * Reads the APF program and data buffer for this iface.
3388      *
3389      * @param ifaceName Name of the interface
3390      * @return the buffer returned by the driver, or null in case of an error
3391      */
3392     public byte[] readPacketFilter(@NonNull String ifaceName) {
3393         return mWifiVendorHal.readPacketFilter(ifaceName);
3394     }
3395 
3396     /**
3397      * Set country code for this AP iface.
3398      * @param ifaceName Name of the AP interface.
3399      * @param countryCode - two-letter country code (as ISO 3166)
3400      * @return true for success
3401      */
3402     public boolean setApCountryCode(@NonNull String ifaceName, String countryCode) {
3403         if (mWifiVendorHal.setApCountryCode(ifaceName, countryCode)) {
3404             if (mCountryCodeChangeListener != null) {
3405                 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode);
3406             }
3407             return true;
3408         }
3409         return false;
3410     }
3411 
3412     /**
3413      * Set country code for this chip
3414      * @param countryCode - two-letter country code (as ISO 3166)
3415      * @return true for success
3416      */
3417     public boolean setChipCountryCode(String countryCode) {
3418         if (mWifiVendorHal.setChipCountryCode(countryCode)) {
3419             if (mCountryCodeChangeListener != null) {
3420                 mCountryCodeChangeListener.onSetCountryCodeSucceeded(countryCode);
3421             }
3422             return true;
3423         }
3424         return false;
3425     }
3426 
3427     //---------------------------------------------------------------------------------
3428     /* Wifi Logger commands/events */
3429     public static interface WifiLoggerEventHandler {
3430         void onRingBufferData(RingBufferStatus status, byte[] buffer);
3431         void onWifiAlert(int errorCode, byte[] buffer);
3432     }
3433 
3434     /**
3435      * Registers the logger callback and enables alerts.
3436      * Ring buffer data collection is only triggered when |startLoggingRingBuffer| is invoked.
3437      *
3438      * @param handler Callback to be invoked.
3439      * @return true on success, false otherwise.
3440      */
3441     public boolean setLoggingEventHandler(WifiLoggerEventHandler handler) {
3442         return mWifiVendorHal.setLoggingEventHandler(handler);
3443     }
3444 
3445     /**
3446      * Control debug data collection
3447      *
3448      * @param verboseLevel 0 to 3, inclusive. 0 stops logging.
3449      * @param flags        Ignored.
3450      * @param maxInterval  Maximum interval between reports; ignore if 0.
3451      * @param minDataSize  Minimum data size in buffer for report; ignore if 0.
3452      * @param ringName     Name of the ring for which data collection is to start.
3453      * @return true for success, false otherwise.
3454      */
3455     public boolean startLoggingRingBuffer(int verboseLevel, int flags, int maxInterval,
3456             int minDataSize, String ringName){
3457         return mWifiVendorHal.startLoggingRingBuffer(
3458                 verboseLevel, flags, maxInterval, minDataSize, ringName);
3459     }
3460 
3461     /**
3462      * Logger features exposed.
3463      * This is a no-op now, will always return -1.
3464      *
3465      * @return true on success, false otherwise.
3466      */
3467     public int getSupportedLoggerFeatureSet() {
3468         return mWifiVendorHal.getSupportedLoggerFeatureSet();
3469     }
3470 
3471     /**
3472      * Stops all logging and resets the logger callback.
3473      * This stops both the alerts and ring buffer data collection.
3474      * @return true on success, false otherwise.
3475      */
3476     public boolean resetLogHandler() {
3477         return mWifiVendorHal.resetLogHandler();
3478     }
3479 
3480     /**
3481      * Vendor-provided wifi driver version string
3482      *
3483      * @return String returned from the HAL.
3484      */
3485     public String getDriverVersion() {
3486         return mWifiVendorHal.getDriverVersion();
3487     }
3488 
3489     /**
3490      * Vendor-provided wifi firmware version string
3491      *
3492      * @return String returned from the HAL.
3493      */
3494     public String getFirmwareVersion() {
3495         return mWifiVendorHal.getFirmwareVersion();
3496     }
3497 
3498     public static class RingBufferStatus{
3499         String name;
3500         int flag;
3501         int ringBufferId;
3502         int ringBufferByteSize;
3503         int verboseLevel;
3504         int writtenBytes;
3505         int readBytes;
3506         int writtenRecords;
3507 
3508         // Bit masks for interpreting |flag|
3509         public static final int HAS_BINARY_ENTRIES = (1 << 0);
3510         public static final int HAS_ASCII_ENTRIES = (1 << 1);
3511         public static final int HAS_PER_PACKET_ENTRIES = (1 << 2);
3512 
3513         @Override
3514         public String toString() {
3515             return "name: " + name + " flag: " + flag + " ringBufferId: " + ringBufferId +
3516                     " ringBufferByteSize: " +ringBufferByteSize + " verboseLevel: " +verboseLevel +
3517                     " writtenBytes: " + writtenBytes + " readBytes: " + readBytes +
3518                     " writtenRecords: " + writtenRecords;
3519         }
3520     }
3521 
3522     /**
3523      * API to get the status of all ring buffers supported by driver
3524      */
3525     public RingBufferStatus[] getRingBufferStatus() {
3526         return mWifiVendorHal.getRingBufferStatus();
3527     }
3528 
3529     /**
3530      * Indicates to driver that all the data has to be uploaded urgently
3531      *
3532      * @param ringName Name of the ring buffer requested.
3533      * @return true on success, false otherwise.
3534      */
3535     public boolean getRingBufferData(String ringName) {
3536         return mWifiVendorHal.getRingBufferData(ringName);
3537     }
3538 
3539     /**
3540      * Request hal to flush ring buffers to files
3541      *
3542      * @return true on success, false otherwise.
3543      */
3544     public boolean flushRingBufferData() {
3545         return mWifiVendorHal.flushRingBufferData();
3546     }
3547 
3548     /**
3549      * Request vendor debug info from the firmware
3550      *
3551      * @return Raw data obtained from the HAL.
3552      */
3553     public byte[] getFwMemoryDump() {
3554         return mWifiVendorHal.getFwMemoryDump();
3555     }
3556 
3557     /**
3558      * Request vendor debug info from the driver
3559      *
3560      * @return Raw data obtained from the HAL.
3561      */
3562     public byte[] getDriverStateDump() {
3563         return mWifiVendorHal.getDriverStateDump();
3564     }
3565 
3566     //---------------------------------------------------------------------------------
3567     /* Packet fate API */
3568 
3569     @Immutable
3570     abstract static class FateReport {
3571         final static int USEC_PER_MSEC = 1000;
3572         // The driver timestamp is a 32-bit counter, in microseconds. This field holds the
3573         // maximal value of a driver timestamp in milliseconds.
3574         final static int MAX_DRIVER_TIMESTAMP_MSEC = (int) (0xffffffffL / 1000);
3575         final static SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss.SSS");
3576 
3577         final byte mFate;
3578         final long mDriverTimestampUSec;
3579         final byte mFrameType;
3580         final byte[] mFrameBytes;
3581         final long mEstimatedWallclockMSec;
3582 
3583         FateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3584             mFate = fate;
3585             mDriverTimestampUSec = driverTimestampUSec;
3586             mEstimatedWallclockMSec =
3587                     convertDriverTimestampUSecToWallclockMSec(mDriverTimestampUSec);
3588             mFrameType = frameType;
3589             mFrameBytes = frameBytes;
3590         }
3591 
3592         public String toTableRowString() {
3593             StringWriter sw = new StringWriter();
3594             PrintWriter pw = new PrintWriter(sw);
3595             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
3596             dateFormatter.setTimeZone(TimeZone.getDefault());
3597             pw.format("%-15s  %12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3598                     mDriverTimestampUSec,
3599                     dateFormatter.format(new Date(mEstimatedWallclockMSec)),
3600                     directionToString(), fateToString(), parser.mMostSpecificProtocolString,
3601                     parser.mTypeString, parser.mResultString);
3602             return sw.toString();
3603         }
3604 
3605         public String toVerboseStringWithPiiAllowed() {
3606             StringWriter sw = new StringWriter();
3607             PrintWriter pw = new PrintWriter(sw);
3608             FrameParser parser = new FrameParser(mFrameType, mFrameBytes);
3609             pw.format("Frame direction: %s\n", directionToString());
3610             pw.format("Frame timestamp: %d\n", mDriverTimestampUSec);
3611             pw.format("Frame fate: %s\n", fateToString());
3612             pw.format("Frame type: %s\n", frameTypeToString(mFrameType));
3613             pw.format("Frame protocol: %s\n", parser.mMostSpecificProtocolString);
3614             pw.format("Frame protocol type: %s\n", parser.mTypeString);
3615             pw.format("Frame length: %d\n", mFrameBytes.length);
3616             pw.append("Frame bytes");
3617             pw.append(HexDump.dumpHexString(mFrameBytes));  // potentially contains PII
3618             pw.append("\n");
3619             return sw.toString();
3620         }
3621 
3622         /* Returns a header to match the output of toTableRowString(). */
3623         public static String getTableHeader() {
3624             StringWriter sw = new StringWriter();
3625             PrintWriter pw = new PrintWriter(sw);
3626             pw.format("\n%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3627                     "Time usec", "Walltime", "Direction", "Fate", "Protocol", "Type", "Result");
3628             pw.format("%-15s  %-12s  %-9s  %-32s  %-12s  %-23s  %s\n",
3629                     "---------", "--------", "---------", "----", "--------", "----", "------");
3630             return sw.toString();
3631         }
3632 
3633         protected abstract String directionToString();
3634 
3635         protected abstract String fateToString();
3636 
3637         private static String frameTypeToString(byte frameType) {
3638             switch (frameType) {
3639                 case WifiLoggerHal.FRAME_TYPE_UNKNOWN:
3640                     return "unknown";
3641                 case WifiLoggerHal.FRAME_TYPE_ETHERNET_II:
3642                     return "data";
3643                 case WifiLoggerHal.FRAME_TYPE_80211_MGMT:
3644                     return "802.11 management";
3645                 default:
3646                     return Byte.toString(frameType);
3647             }
3648         }
3649 
3650         /**
3651          * Converts a driver timestamp to a wallclock time, based on the current
3652          * BOOTTIME to wallclock mapping. The driver timestamp is a 32-bit counter of
3653          * microseconds, with the same base as BOOTTIME.
3654          */
3655         private static long convertDriverTimestampUSecToWallclockMSec(long driverTimestampUSec) {
3656             final long wallclockMillisNow = System.currentTimeMillis();
3657             final long boottimeMillisNow = SystemClock.elapsedRealtime();
3658             final long driverTimestampMillis = driverTimestampUSec / USEC_PER_MSEC;
3659 
3660             long boottimeTimestampMillis = boottimeMillisNow % MAX_DRIVER_TIMESTAMP_MSEC;
3661             if (boottimeTimestampMillis < driverTimestampMillis) {
3662                 // The 32-bit microsecond count has wrapped between the time that the driver
3663                 // recorded the packet, and the call to this function. Adjust the BOOTTIME
3664                 // timestamp, to compensate.
3665                 //
3666                 // Note that overflow is not a concern here, since the result is less than
3667                 // 2 * MAX_DRIVER_TIMESTAMP_MSEC. (Given the modulus operation above,
3668                 // boottimeTimestampMillis must be less than MAX_DRIVER_TIMESTAMP_MSEC.) And, since
3669                 // MAX_DRIVER_TIMESTAMP_MSEC is an int, 2 * MAX_DRIVER_TIMESTAMP_MSEC must fit
3670                 // within a long.
3671                 boottimeTimestampMillis += MAX_DRIVER_TIMESTAMP_MSEC;
3672             }
3673 
3674             final long millisSincePacketTimestamp = boottimeTimestampMillis - driverTimestampMillis;
3675             return wallclockMillisNow - millisSincePacketTimestamp;
3676         }
3677     }
3678 
3679     /**
3680      * Represents the fate information for one outbound packet.
3681      */
3682     @Immutable
3683     public static final class TxFateReport extends FateReport {
3684         TxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3685             super(fate, driverTimestampUSec, frameType, frameBytes);
3686         }
3687 
3688         @Override
3689         protected String directionToString() {
3690             return "TX";
3691         }
3692 
3693         @Override
3694         protected String fateToString() {
3695             switch (mFate) {
3696                 case WifiLoggerHal.TX_PKT_FATE_ACKED:
3697                     return "acked";
3698                 case WifiLoggerHal.TX_PKT_FATE_SENT:
3699                     return "sent";
3700                 case WifiLoggerHal.TX_PKT_FATE_FW_QUEUED:
3701                     return "firmware queued";
3702                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_INVALID:
3703                     return "firmware dropped (invalid frame)";
3704                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_NOBUFS:
3705                     return "firmware dropped (no bufs)";
3706                 case WifiLoggerHal.TX_PKT_FATE_FW_DROP_OTHER:
3707                     return "firmware dropped (other)";
3708                 case WifiLoggerHal.TX_PKT_FATE_DRV_QUEUED:
3709                     return "driver queued";
3710                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_INVALID:
3711                     return "driver dropped (invalid frame)";
3712                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_NOBUFS:
3713                     return "driver dropped (no bufs)";
3714                 case WifiLoggerHal.TX_PKT_FATE_DRV_DROP_OTHER:
3715                     return "driver dropped (other)";
3716                 default:
3717                     return Byte.toString(mFate);
3718             }
3719         }
3720     }
3721 
3722     /**
3723      * Represents the fate information for one inbound packet.
3724      */
3725     @Immutable
3726     public static final class RxFateReport extends FateReport {
3727         RxFateReport(byte fate, long driverTimestampUSec, byte frameType, byte[] frameBytes) {
3728             super(fate, driverTimestampUSec, frameType, frameBytes);
3729         }
3730 
3731         @Override
3732         protected String directionToString() {
3733             return "RX";
3734         }
3735 
3736         @Override
3737         protected String fateToString() {
3738             switch (mFate) {
3739                 case WifiLoggerHal.RX_PKT_FATE_SUCCESS:
3740                     return "success";
3741                 case WifiLoggerHal.RX_PKT_FATE_FW_QUEUED:
3742                     return "firmware queued";
3743                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_FILTER:
3744                     return "firmware dropped (filter)";
3745                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_INVALID:
3746                     return "firmware dropped (invalid frame)";
3747                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_NOBUFS:
3748                     return "firmware dropped (no bufs)";
3749                 case WifiLoggerHal.RX_PKT_FATE_FW_DROP_OTHER:
3750                     return "firmware dropped (other)";
3751                 case WifiLoggerHal.RX_PKT_FATE_DRV_QUEUED:
3752                     return "driver queued";
3753                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_FILTER:
3754                     return "driver dropped (filter)";
3755                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_INVALID:
3756                     return "driver dropped (invalid frame)";
3757                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_NOBUFS:
3758                     return "driver dropped (no bufs)";
3759                 case WifiLoggerHal.RX_PKT_FATE_DRV_DROP_OTHER:
3760                     return "driver dropped (other)";
3761                 default:
3762                     return Byte.toString(mFate);
3763             }
3764         }
3765     }
3766 
3767     /**
3768      * Ask the HAL to enable packet fate monitoring. Fails unless HAL is started.
3769      *
3770      * @param ifaceName Name of the interface.
3771      * @return true for success, false otherwise.
3772      */
3773     public boolean startPktFateMonitoring(@NonNull String ifaceName) {
3774         return mWifiVendorHal.startPktFateMonitoring(ifaceName);
3775     }
3776 
3777     /**
3778      * Fetch the most recent TX packet fates from the HAL. Fails unless HAL is started.
3779      *
3780      * @param ifaceName Name of the interface.
3781      * @return TxFateReport list on success, empty list on failure. Never returns null.
3782      */
3783     @NonNull
3784     public List<TxFateReport> getTxPktFates(@NonNull String ifaceName) {
3785         return mWifiVendorHal.getTxPktFates(ifaceName);
3786     }
3787 
3788     /**
3789      * Fetch the most recent RX packet fates from the HAL. Fails unless HAL is started.
3790      * @param ifaceName Name of the interface.
3791      * @return RxFateReport list on success, empty list on failure. Never returns null.
3792      */
3793     @NonNull
3794     public List<RxFateReport> getRxPktFates(@NonNull String ifaceName) {
3795         return mWifiVendorHal.getRxPktFates(ifaceName);
3796     }
3797 
3798     /**
3799      * Get the tx packet counts for the interface.
3800      *
3801      * @param ifaceName Name of the interface.
3802      * @return tx packet counts
3803      */
3804     public long getTxPackets(@NonNull String ifaceName) {
3805         return TrafficStats.getTxPackets(ifaceName);
3806     }
3807 
3808     /**
3809      * Get the rx packet counts for the interface.
3810      *
3811      * @param ifaceName Name of the interface
3812      * @return rx packet counts
3813      */
3814     public long getRxPackets(@NonNull String ifaceName) {
3815         return TrafficStats.getRxPackets(ifaceName);
3816     }
3817 
3818     /**
3819      * Start sending the specified keep alive packets periodically.
3820      *
3821      * @param ifaceName Name of the interface.
3822      * @param slot Integer used to identify each request.
3823      * @param dstMac Destination MAC Address
3824      * @param packet Raw packet contents to send.
3825      * @param protocol The ethernet protocol type
3826      * @param period Period to use for sending these packets.
3827      * @return 0 for success, -1 for error
3828      */
3829     public int startSendingOffloadedPacket(@NonNull String ifaceName, int slot,
3830             byte[] dstMac, byte[] packet, int protocol, int period) {
3831         byte[] srcMac = NativeUtil.macAddressToByteArray(getMacAddress(ifaceName));
3832         return mWifiVendorHal.startSendingOffloadedPacket(
3833                 ifaceName, slot, srcMac, dstMac, packet, protocol, period);
3834     }
3835 
3836     /**
3837      * Stop sending the specified keep alive packets.
3838      *
3839      * @param ifaceName Name of the interface.
3840      * @param slot id - same as startSendingOffloadedPacket call.
3841      * @return 0 for success, -1 for error
3842      */
3843     public int stopSendingOffloadedPacket(@NonNull String ifaceName, int slot) {
3844         return mWifiVendorHal.stopSendingOffloadedPacket(ifaceName, slot);
3845     }
3846 
3847     public static interface WifiRssiEventHandler {
3848         void onRssiThresholdBreached(byte curRssi);
3849     }
3850 
3851     /**
3852      * Start RSSI monitoring on the currently connected access point.
3853      *
3854      * @param ifaceName        Name of the interface.
3855      * @param maxRssi          Maximum RSSI threshold.
3856      * @param minRssi          Minimum RSSI threshold.
3857      * @param rssiEventHandler Called when RSSI goes above maxRssi or below minRssi
3858      * @return 0 for success, -1 for failure
3859      */
3860     public int startRssiMonitoring(
3861             @NonNull String ifaceName, byte maxRssi, byte minRssi,
3862             WifiRssiEventHandler rssiEventHandler) {
3863         return mWifiVendorHal.startRssiMonitoring(
3864                 ifaceName, maxRssi, minRssi, rssiEventHandler);
3865     }
3866 
3867     /**
3868      * Stop RSSI monitoring on the currently connected access point.
3869      *
3870      * @param ifaceName Name of the interface.
3871      * @return 0 for success, -1 for failure
3872      */
3873     public int stopRssiMonitoring(@NonNull String ifaceName) {
3874         return mWifiVendorHal.stopRssiMonitoring(ifaceName);
3875     }
3876 
3877     /**
3878      * Fetch the host wakeup reasons stats from wlan driver.
3879      *
3880      * @return the |WlanWakeReasonAndCounts| object retrieved from the wlan driver.
3881      */
3882     public WlanWakeReasonAndCounts getWlanWakeReasonCount() {
3883         return mWifiVendorHal.getWlanWakeReasonCount();
3884     }
3885 
3886     /**
3887      * Enable/Disable Neighbour discovery offload functionality in the firmware.
3888      *
3889      * @param ifaceName Name of the interface.
3890      * @param enabled true to enable, false to disable.
3891      * @return true for success, false otherwise.
3892      */
3893     public boolean configureNeighborDiscoveryOffload(@NonNull String ifaceName, boolean enabled) {
3894         return mWifiVendorHal.configureNeighborDiscoveryOffload(ifaceName, enabled);
3895     }
3896 
3897     // Firmware roaming control.
3898 
3899     /**
3900      * Class to retrieve firmware roaming capability parameters.
3901      */
3902     public static class RoamingCapabilities {
3903         public int maxBlocklistSize;
3904         public int maxAllowlistSize;
3905     }
3906 
3907     /**
3908      * Query the firmware roaming capabilities.
3909      * @param ifaceName Name of the interface.
3910      * @return capabilities object on success, null otherwise.
3911      */
3912     @Nullable
3913     public RoamingCapabilities getRoamingCapabilities(@NonNull String ifaceName) {
3914         return mWifiVendorHal.getRoamingCapabilities(ifaceName);
3915     }
3916 
3917     /**
3918      * Macros for controlling firmware roaming.
3919      */
3920     public static final int DISABLE_FIRMWARE_ROAMING = 0;
3921     public static final int ENABLE_FIRMWARE_ROAMING = 1;
3922 
3923     @IntDef({ENABLE_FIRMWARE_ROAMING, DISABLE_FIRMWARE_ROAMING})
3924     @Retention(RetentionPolicy.SOURCE)
3925     public @interface RoamingEnableState {}
3926 
3927     /**
3928      * Indicates success for enableFirmwareRoaming
3929      */
3930     public static final int SET_FIRMWARE_ROAMING_SUCCESS = 0;
3931 
3932     /**
3933      * Indicates failure for enableFirmwareRoaming
3934      */
3935     public static final int SET_FIRMWARE_ROAMING_FAILURE = 1;
3936 
3937     /**
3938      * Indicates temporary failure for enableFirmwareRoaming - try again later
3939      */
3940     public static final int SET_FIRMWARE_ROAMING_BUSY = 2;
3941 
3942     @IntDef({SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE, SET_FIRMWARE_ROAMING_BUSY})
3943     @Retention(RetentionPolicy.SOURCE)
3944     public @interface RoamingEnableStatus {}
3945 
3946     /**
3947      * Enable/disable firmware roaming.
3948      *
3949      * @param ifaceName Name of the interface.
3950      * @return SET_FIRMWARE_ROAMING_SUCCESS, SET_FIRMWARE_ROAMING_FAILURE,
3951      *         or SET_FIRMWARE_ROAMING_BUSY
3952      */
3953     public @RoamingEnableStatus int enableFirmwareRoaming(@NonNull String ifaceName,
3954             @RoamingEnableState int state) {
3955         return mWifiVendorHal.enableFirmwareRoaming(ifaceName, state);
3956     }
3957 
3958     /**
3959      * Class for specifying the roaming configurations.
3960      */
3961     public static class RoamingConfig {
3962         public ArrayList<String> blocklistBssids;
3963         public ArrayList<String> allowlistSsids;
3964     }
3965 
3966     /**
3967      * Set firmware roaming configurations.
3968      * @param ifaceName Name of the interface.
3969      */
3970     public boolean configureRoaming(@NonNull String ifaceName, RoamingConfig config) {
3971         return mWifiVendorHal.configureRoaming(ifaceName, config);
3972     }
3973 
3974     /**
3975      * Reset firmware roaming configuration.
3976      * @param ifaceName Name of the interface.
3977      */
3978     public boolean resetRoamingConfiguration(@NonNull String ifaceName) {
3979         // Pass in an empty RoamingConfig object which translates to zero size
3980         // blacklist and whitelist to reset the firmware roaming configuration.
3981         return mWifiVendorHal.configureRoaming(ifaceName, new RoamingConfig());
3982     }
3983 
3984     /**
3985      * Select one of the pre-configured transmit power level scenarios or reset it back to normal.
3986      * Primarily used for meeting SAR requirements.
3987      *
3988      * @param sarInfo The collection of inputs used to select the SAR scenario.
3989      * @return true for success; false for failure or if the HAL version does not support this API.
3990      */
3991     public boolean selectTxPowerScenario(SarInfo sarInfo) {
3992         return mWifiVendorHal.selectTxPowerScenario(sarInfo);
3993     }
3994 
3995     /**
3996      * Set MBO cellular data status
3997      *
3998      * @param ifaceName Name of the interface.
3999      * @param available cellular data status,
4000      *        true means cellular data available, false otherwise.
4001      */
4002     public void setMboCellularDataStatus(@NonNull String ifaceName, boolean available) {
4003         mSupplicantStaIfaceHal.setMboCellularDataStatus(ifaceName, available);
4004     }
4005 
4006     /**
4007      * Query of support of Wi-Fi standard
4008      *
4009      * @param ifaceName name of the interface to check support on
4010      * @param standard the wifi standard to check on
4011      * @return true if the wifi standard is supported on this interface, false otherwise.
4012      */
4013     public boolean isWifiStandardSupported(@NonNull String ifaceName,
4014             @WifiAnnotations.WifiStandard int standard) {
4015         synchronized (mLock) {
4016             Iface iface = mIfaceMgr.getIface(ifaceName);
4017             if (iface == null || iface.phyCapabilities == null) {
4018                 return false;
4019             }
4020             return iface.phyCapabilities.isWifiStandardSupported(standard);
4021         }
4022     }
4023 
4024     /**
4025      * Get the Wiphy capabilities of a device for a given interface
4026      * If the interface is not associated with one,
4027      * it will be read from the device through wificond
4028      *
4029      * @param ifaceName name of the interface
4030      * @return the device capabilities for this interface
4031      */
4032     public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) {
4033         synchronized (mLock) {
4034             Iface iface = mIfaceMgr.getIface(ifaceName);
4035             if (iface == null) {
4036                 Log.e(TAG, "Failed to get device capabilities, interface not found: " + ifaceName);
4037                 return null;
4038             }
4039             if (iface.phyCapabilities == null) {
4040                 iface.phyCapabilities = mWifiCondManager.getDeviceWiphyCapabilities(ifaceName);
4041             }
4042             return iface.phyCapabilities;
4043         }
4044     }
4045 
4046     /**
4047      * Set the Wiphy capabilities of a device for a given interface
4048      *
4049      * @param ifaceName name of the interface
4050      * @param capabilities the wiphy capabilities to set for this interface
4051      */
4052     public void setDeviceWiphyCapabilities(@NonNull String ifaceName,
4053             DeviceWiphyCapabilities capabilities) {
4054         synchronized (mLock) {
4055             Iface iface = mIfaceMgr.getIface(ifaceName);
4056             if (iface == null) {
4057                 Log.e(TAG, "Failed to set device capabilities, interface not found: " + ifaceName);
4058                 return;
4059             }
4060             iface.phyCapabilities = capabilities;
4061         }
4062     }
4063 
4064     /**
4065      * Notify scan mode state to driver to save power in scan-only mode.
4066      *
4067      * @param ifaceName Name of the interface.
4068      * @param enable whether is in scan-only mode
4069      * @return true for success
4070      */
4071     public boolean setScanMode(String ifaceName, boolean enable) {
4072         return mWifiVendorHal.setScanMode(ifaceName, enable);
4073     }
4074 
4075     /** updates linked networks of the |networkId| in supplicant if it's the current network,
4076      * if the current configured network matches |networkId|.
4077      *
4078      * @param ifaceName Name of the interface.
4079      * @param networkId network id of the network to be updated from supplicant.
4080      * @param linkedNetworks Map of config profile key and config for linking.
4081      */
4082     public boolean updateLinkedNetworks(@NonNull String ifaceName, int networkId,
4083             Map<String, WifiConfiguration> linkedNetworks) {
4084         return mSupplicantStaIfaceHal.updateLinkedNetworks(ifaceName, networkId, linkedNetworks);
4085     }
4086 
4087     /**
4088      * Start Subsystem Restart
4089      * @return true on success
4090      */
4091     public boolean startSubsystemRestart() {
4092         return mWifiVendorHal.startSubsystemRestart();
4093     }
4094 
4095     /**
4096      * Register the provided listener for country code event.
4097      *
4098      * @param listener listener for country code changed events.
4099      */
4100     public void registerCountryCodeEventListener(WifiCountryCode.ChangeListener listener) {
4101         registerWificondListenerIfNecessary();
4102         if (mCountryCodeChangeListener != null) {
4103             mCountryCodeChangeListener.setChangeListener(listener);
4104         }
4105     }
4106 }
4107