• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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_DECORATED_IDENTITY;
20 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP;
21 import static android.net.wifi.WifiManager.WIFI_FEATURE_DPP_ENROLLEE_RESPONDER;
22 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA256;
23 import static android.net.wifi.WifiManager.WIFI_FEATURE_FILS_SHA384;
24 import static android.net.wifi.WifiManager.WIFI_FEATURE_MBO;
25 import static android.net.wifi.WifiManager.WIFI_FEATURE_OCE;
26 import static android.net.wifi.WifiManager.WIFI_FEATURE_OWE;
27 import static android.net.wifi.WifiManager.WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS;
28 import static android.net.wifi.WifiManager.WIFI_FEATURE_SAE_PK;
29 import static android.net.wifi.WifiManager.WIFI_FEATURE_SET_TLS_MINIMUM_VERSION;
30 import static android.net.wifi.WifiManager.WIFI_FEATURE_TLS_V1_3;
31 import static android.net.wifi.WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE;
32 import static android.net.wifi.WifiManager.WIFI_FEATURE_WAPI;
33 import static android.net.wifi.WifiManager.WIFI_FEATURE_WFD_R2;
34 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SAE;
35 import static android.net.wifi.WifiManager.WIFI_FEATURE_WPA3_SUITE_B;
36 
37 import android.annotation.NonNull;
38 import android.annotation.Nullable;
39 import android.annotation.SuppressLint;
40 import android.content.Context;
41 import android.hardware.wifi.supplicant.BtCoexistenceMode;
42 import android.hardware.wifi.supplicant.ConnectionCapabilities;
43 import android.hardware.wifi.supplicant.DebugLevel;
44 import android.hardware.wifi.supplicant.DppAkm;
45 import android.hardware.wifi.supplicant.DppCurve;
46 import android.hardware.wifi.supplicant.DppNetRole;
47 import android.hardware.wifi.supplicant.DppResponderBootstrapInfo;
48 import android.hardware.wifi.supplicant.INonStandardCertCallback;
49 import android.hardware.wifi.supplicant.ISupplicant;
50 import android.hardware.wifi.supplicant.ISupplicantStaIface;
51 import android.hardware.wifi.supplicant.ISupplicantStaIfaceCallback;
52 import android.hardware.wifi.supplicant.ISupplicantStaNetwork;
53 import android.hardware.wifi.supplicant.IfaceInfo;
54 import android.hardware.wifi.supplicant.IfaceType;
55 import android.hardware.wifi.supplicant.IpVersion;
56 import android.hardware.wifi.supplicant.KeyMgmtMask;
57 import android.hardware.wifi.supplicant.LegacyMode;
58 import android.hardware.wifi.supplicant.MloLinksInfo;
59 import android.hardware.wifi.supplicant.MscsParams.FrameClassifierFields;
60 import android.hardware.wifi.supplicant.MsduDeliveryInfo;
61 import android.hardware.wifi.supplicant.MsduDeliveryInfo.DeliveryRatio;
62 import android.hardware.wifi.supplicant.PortRange;
63 import android.hardware.wifi.supplicant.QosCharacteristics;
64 import android.hardware.wifi.supplicant.QosCharacteristics.QosCharacteristicsMask;
65 import android.hardware.wifi.supplicant.QosPolicyClassifierParams;
66 import android.hardware.wifi.supplicant.QosPolicyClassifierParamsMask;
67 import android.hardware.wifi.supplicant.QosPolicyData;
68 import android.hardware.wifi.supplicant.QosPolicyRequestType;
69 import android.hardware.wifi.supplicant.QosPolicyScsData;
70 import android.hardware.wifi.supplicant.QosPolicyScsData.LinkDirection;
71 import android.hardware.wifi.supplicant.QosPolicyScsRequestStatus;
72 import android.hardware.wifi.supplicant.QosPolicyScsRequestStatusCode;
73 import android.hardware.wifi.supplicant.QosPolicyStatus;
74 import android.hardware.wifi.supplicant.QosPolicyStatusCode;
75 import android.hardware.wifi.supplicant.RxFilterType;
76 import android.hardware.wifi.supplicant.SignalPollResult;
77 import android.hardware.wifi.supplicant.SupplicantStatusCode;
78 import android.hardware.wifi.supplicant.UsdBaseConfig;
79 import android.hardware.wifi.supplicant.UsdCapabilities;
80 import android.hardware.wifi.supplicant.UsdMessageInfo;
81 import android.hardware.wifi.supplicant.UsdPublishConfig;
82 import android.hardware.wifi.supplicant.UsdPublishTransmissionType;
83 import android.hardware.wifi.supplicant.UsdServiceProtoType;
84 import android.hardware.wifi.supplicant.UsdSubscribeConfig;
85 import android.hardware.wifi.supplicant.WifiChannelWidthInMhz;
86 import android.hardware.wifi.supplicant.WifiTechnology;
87 import android.hardware.wifi.supplicant.WpaDriverCapabilitiesMask;
88 import android.hardware.wifi.supplicant.WpsConfigMethods;
89 import android.net.DscpPolicy;
90 import android.net.MacAddress;
91 import android.net.NetworkAgent;
92 import android.net.wifi.MscsParams;
93 import android.net.wifi.QosPolicyParams;
94 import android.net.wifi.ScanResult;
95 import android.net.wifi.SecurityParams;
96 import android.net.wifi.WifiAnnotations;
97 import android.net.wifi.WifiConfiguration;
98 import android.net.wifi.WifiKeystore;
99 import android.net.wifi.WifiMigration;
100 import android.net.wifi.WifiSsid;
101 import android.net.wifi.flags.Flags;
102 import android.net.wifi.usd.Config;
103 import android.net.wifi.usd.PublishConfig;
104 import android.net.wifi.usd.SubscribeConfig;
105 import android.net.wifi.util.Environment;
106 import android.os.Handler;
107 import android.os.IBinder;
108 import android.os.IBinder.DeathRecipient;
109 import android.os.RemoteException;
110 import android.os.ServiceManager;
111 import android.os.ServiceSpecificException;
112 import android.text.TextUtils;
113 import android.util.Log;
114 import android.util.Pair;
115 
116 import com.android.internal.annotations.VisibleForTesting;
117 import com.android.modules.utils.HandlerExecutor;
118 import com.android.modules.utils.build.SdkLevel;
119 import com.android.server.wifi.mockwifi.MockWifiServiceUtil;
120 import com.android.server.wifi.usd.UsdNativeManager;
121 import com.android.server.wifi.usd.UsdRequestManager;
122 import com.android.server.wifi.util.HalAidlUtil;
123 import com.android.server.wifi.util.NativeUtil;
124 
125 import java.nio.ByteBuffer;
126 import java.nio.ByteOrder;
127 import java.util.ArrayList;
128 import java.util.Arrays;
129 import java.util.BitSet;
130 import java.util.HashMap;
131 import java.util.List;
132 import java.util.Map;
133 import java.util.NoSuchElementException;
134 import java.util.Objects;
135 import java.util.concurrent.CountDownLatch;
136 import java.util.concurrent.TimeUnit;
137 import java.util.function.IntConsumer;
138 import java.util.regex.Matcher;
139 import java.util.regex.Pattern;
140 
141 /**
142  * HAL calls to set up/tear down the supplicant daemon and make requests
143  * related to station mode. Uses the AIDL supplicant interface.
144  * To maintain thread-safety, the locking protocol is that every non-static method (regardless of
145  * access level) acquires mLock.
146  */
147 public class SupplicantStaIfaceHalAidlImpl implements ISupplicantStaIfaceHal {
148     private static final String TAG = "SupplicantStaIfaceHalAidlImpl";
149     private static final String ISUPPLICANTSTAIFACE = "ISupplicantStaIface";
150     @VisibleForTesting
151     private static final String HAL_INSTANCE_NAME = ISupplicant.DESCRIPTOR + "/default";
152     @VisibleForTesting
153     public static final long WAIT_FOR_DEATH_TIMEOUT_MS = 50L;
154     private static final long INVALID_CONNECT_TO_NETWORK_TIMESTAMP = -1L;
155     @VisibleForTesting
156     public static final long IGNORE_NETWORK_NOT_FOUND_DURATION_MS = 1000L;
157 
158     /**
159      * Regex pattern for extracting the wps device type bytes.
160      * Matches a strings like the following: "<categ>-<OUI>-<subcateg>";
161      */
162     private static final Pattern WPS_DEVICE_TYPE_PATTERN =
163             Pattern.compile("^(\\d{1,2})-([0-9a-fA-F]{8})-(\\d{1,2})$");
164 
165     private final Object mLock = new Object();
166     private boolean mVerboseLoggingEnabled = false;
167     private boolean mVerboseHalLoggingEnabled = false;
168     private boolean mServiceDeclared = false;
169     private int mServiceVersion = -1;
170 
171     // Supplicant HAL interface objects
172     private ISupplicant mISupplicant = null;
173     private Map<String, ISupplicantStaIface> mISupplicantStaIfaces = new HashMap<>();
174     private Map<String, ISupplicantStaIfaceCallback>
175             mISupplicantStaIfaceCallbacks = new HashMap<>();
176     private Map<String, SupplicantStaNetworkHalAidlImpl>
177             mCurrentNetworkRemoteHandles = new HashMap<>();
178     private Map<String, WifiConfiguration> mCurrentNetworkLocalConfigs = new HashMap<>();
179     private Map<String, Long> mCurrentNetworkConnectTimestamp = new HashMap<>();
180     private Map<String, List<WifiSsid>> mCurrentNetworkFallbackSsids = new HashMap<>();
181     private Map<String, Integer> mCurrentNetworkFallbackSsidIndex = new HashMap<>();
182     private Map<String, List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>>>
183             mLinkedNetworkLocalAndRemoteConfigs = new HashMap<>();
184     @VisibleForTesting
185     PmkCacheManager mPmkCacheManager;
186     private WifiNative.SupplicantDeathEventHandler mDeathEventHandler;
187     private SupplicantDeathRecipient mSupplicantDeathRecipient;
188     private final Context mContext;
189     private final WifiMonitor mWifiMonitor;
190     private final Handler mEventHandler;
191     private WifiNative.DppEventCallback mDppCallback = null;
192     private final Clock mClock;
193     private final WifiMetrics mWifiMetrics;
194     private final WifiGlobals mWifiGlobals;
195     private final SsidTranslator mSsidTranslator;
196     private final WifiInjector mWifiInjector;
197     private CountDownLatch mWaitForDeathLatch;
198     private INonStandardCertCallback mNonStandardCertCallback;
199     private SupplicantStaIfaceHal.QosScsResponseCallback mQosScsResponseCallback;
200     private MscsParams mLastMscsParams;
201 
202     @VisibleForTesting
203     protected boolean mHasMigratedLegacyKeystoreAliases = false;
204     @VisibleForTesting
205     protected KeystoreMigrationStatusConsumer mKeystoreMigrationStatusConsumer;
206 
207     /**
208      * Default implementation of USD events.
209      * {@link UsdRequestManager#registerUsdEventsCallback(UsdRequestManager.UsdNativeEventsCallback)} will override
210      * this default implementation.
211      */
212     private UsdNativeManager.UsdEventsCallback mUsdEventsCallback = null;
213 
214     private class SupplicantDeathRecipient implements DeathRecipient {
215         @Override
binderDied()216         public void binderDied() {
217         }
218 
219         @Override
binderDied(@onNull IBinder who)220         public void binderDied(@NonNull IBinder who) {
221             synchronized (mLock) {
222                 IBinder supplicantBinder = getServiceBinderMockable();
223                 Log.w(TAG, "ISupplicant binder died. who=" + who + ", service="
224                         + supplicantBinder);
225                 if (supplicantBinder == null) {
226                     Log.w(TAG, "Supplicant Death EventHandler called"
227                             + " when ISupplicant/binder service is already cleared");
228                 } else if (supplicantBinder != who) {
229                     Log.w(TAG, "Ignoring stale death recipient notification");
230                     return;
231                 }
232                 if (mWaitForDeathLatch != null) {
233                     mWaitForDeathLatch.countDown();
234                 }
235                 Log.w(TAG, "Handle supplicant death");
236                 supplicantServiceDiedHandler();
237             }
238         }
239     }
240 
241     @VisibleForTesting
242     protected class KeystoreMigrationStatusConsumer implements IntConsumer {
243         @Override
accept(int statusCode)244         public void accept(int statusCode) {
245             synchronized (mLock) {
246                 if (statusCode == WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_NOT_NEEDED
247                         || statusCode
248                                 == WifiMigration.KEYSTORE_MIGRATION_SUCCESS_MIGRATION_COMPLETE) {
249                     mHasMigratedLegacyKeystoreAliases = true;
250                 } else {
251                     mHasMigratedLegacyKeystoreAliases = false;
252                 }
253                 Log.i(TAG, "Keystore migration returned with success="
254                         + mHasMigratedLegacyKeystoreAliases + ", statusCode=" + statusCode);
255                 // Consumer is no longer needed, since the callback has been received
256                 mKeystoreMigrationStatusConsumer = null;
257             }
258         }
259     }
260 
SupplicantStaIfaceHalAidlImpl(Context context, WifiMonitor monitor, Handler handler, Clock clock, WifiMetrics wifiMetrics, WifiGlobals wifiGlobals, @NonNull SsidTranslator ssidTranslator, WifiInjector wifiInjector)261     public SupplicantStaIfaceHalAidlImpl(Context context, WifiMonitor monitor, Handler handler,
262             Clock clock, WifiMetrics wifiMetrics, WifiGlobals wifiGlobals,
263             @NonNull SsidTranslator ssidTranslator, WifiInjector wifiInjector) {
264         mContext = context;
265         mWifiMonitor = monitor;
266         mEventHandler = handler;
267         mClock = clock;
268         mWifiMetrics = wifiMetrics;
269         mWifiGlobals = wifiGlobals;
270         mSsidTranslator = ssidTranslator;
271         mSupplicantDeathRecipient = new SupplicantDeathRecipient();
272         mPmkCacheManager = new PmkCacheManager(mClock, mEventHandler);
273         mWifiInjector = wifiInjector;
274     }
275 
276     /**
277      * Enable/Disable verbose logging.
278      *
279      */
enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled)280     public void enableVerboseLogging(boolean verboseEnabled, boolean halVerboseEnabled) {
281         synchronized (mLock) {
282             mVerboseLoggingEnabled = verboseEnabled;
283             mVerboseHalLoggingEnabled = halVerboseEnabled;
284             setLogLevel(mVerboseHalLoggingEnabled);
285         }
286     }
287 
isVerboseLoggingEnabled()288     protected boolean isVerboseLoggingEnabled() {
289         synchronized (mLock) {
290             return mVerboseLoggingEnabled;
291         }
292     }
293 
294     /**
295      * Checks whether the ISupplicant service is declared, and therefore should be available.
296      *
297      * @return true if the ISupplicant service is declared
298      */
initialize()299     public boolean initialize() {
300         synchronized (mLock) {
301             if (mISupplicant != null) {
302                 Log.i(TAG, "Service is already initialized, skipping initialize method");
303                 return true;
304             }
305             if (mVerboseLoggingEnabled) {
306                 Log.i(TAG, "Checking for ISupplicant service.");
307             }
308             mISupplicantStaIfaces.clear();
309             mServiceDeclared = serviceDeclared();
310             return mServiceDeclared;
311         }
312     }
313 
getCurrentNetworkId(@onNull String ifaceName)314     protected int getCurrentNetworkId(@NonNull String ifaceName) {
315         synchronized (mLock) {
316             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
317             if (currentConfig == null) {
318                 return WifiConfiguration.INVALID_NETWORK_ID;
319             }
320             return currentConfig.networkId;
321         }
322     }
323 
324     /**
325      * Setup a STA interface for the specified iface name.
326      *
327      * @param ifaceName Name of the interface.
328      * @return true on success, false otherwise.
329      */
setupIface(@onNull String ifaceName)330     public boolean setupIface(@NonNull String ifaceName) {
331         synchronized (mLock) {
332             if (getStaIface(ifaceName) != null) {
333                 Log.e(TAG, "Iface " + ifaceName + " already exists.");
334                 return false;
335             }
336 
337             ISupplicantStaIface iface = addIface(ifaceName);
338             if (iface == null) {
339                 Log.e(TAG, "Unable to add iface " + ifaceName);
340                 return false;
341             }
342 
343             ISupplicantStaIfaceCallback callback = new SupplicantStaIfaceCallbackAidlImpl(
344                     SupplicantStaIfaceHalAidlImpl.this, ifaceName,
345                     new Object(), mContext, mWifiMonitor, mSsidTranslator, mEventHandler);
346             if (registerCallback(iface, callback)) {
347                 mISupplicantStaIfaces.put(ifaceName, iface);
348                 // Keep callback in a store to avoid recycling by garbage collector
349                 mISupplicantStaIfaceCallbacks.put(ifaceName, callback);
350                 return true;
351             } else {
352                 Log.e(TAG, "Unable to register callback for iface " + ifaceName);
353                 return false;
354             }
355         }
356     }
357 
358     /**
359      * Create a STA interface for the specified iface name.
360      *
361      * @param ifaceName Name of the interface.
362      * @return ISupplicantStaIface object on success, null otherwise.
363      */
addIface(@onNull String ifaceName)364     private ISupplicantStaIface addIface(@NonNull String ifaceName) {
365         synchronized (mLock) {
366             String methodStr = "addIface";
367             if (!checkSupplicantAndLogFailure(methodStr)) {
368                 return null;
369             }
370             try {
371                 return mISupplicant.addStaInterface(ifaceName);
372             } catch (RemoteException e) {
373                 handleRemoteException(e, methodStr);
374             } catch (ServiceSpecificException e) {
375                 handleServiceSpecificException(e, methodStr);
376             } catch (NoSuchElementException | IllegalArgumentException e) {
377                 Log.e(TAG, "Encountered exception at addIface: ", e);
378             }
379             return null;
380         }
381     }
382 
383     /**
384      * Teardown a STA interface for the specified iface name.
385      *
386      * @param ifaceName Name of the interface.
387      * @return true on success, false otherwise.
388      */
teardownIface(@onNull String ifaceName)389     public boolean teardownIface(@NonNull String ifaceName) {
390         synchronized (mLock) {
391             final String methodStr = "teardownIface";
392             if (checkStaIfaceAndLogFailure(ifaceName, methodStr) == null) {
393                 return false;
394             }
395             if (!checkSupplicantAndLogFailure(methodStr)) {
396                 return false;
397             }
398 
399             try {
400                 IfaceInfo ifaceInfo = new IfaceInfo();
401                 ifaceInfo.name = ifaceName;
402                 ifaceInfo.type = IfaceType.STA;
403                 mISupplicant.removeInterface(ifaceInfo);
404                 mISupplicantStaIfaces.remove(ifaceName);
405                 mISupplicantStaIfaceCallbacks.remove(ifaceName);
406                 return true;
407             } catch (RemoteException e) {
408                 handleRemoteException(e, methodStr);
409             } catch (ServiceSpecificException e) {
410                 handleServiceSpecificException(e, methodStr);
411             } catch (NoSuchElementException e) {
412                 Log.e(TAG, "Encountered exception at teardownIface: ", e);
413             }
414             return false;
415         }
416     }
417 
418     /**
419      * Registers a death notification for supplicant.
420      * @return Returns true on success.
421      */
registerDeathHandler(@onNull WifiNative.SupplicantDeathEventHandler handler)422     public boolean registerDeathHandler(@NonNull WifiNative.SupplicantDeathEventHandler handler) {
423         synchronized (mLock) {
424             if (mDeathEventHandler != null) {
425                 Log.e(TAG, "Death handler already present");
426             }
427             mDeathEventHandler = handler;
428             return true;
429         }
430     }
431 
432     /**
433      * Deregisters a death notification for supplicant.
434      * @return Returns true on success.
435      */
deregisterDeathHandler()436     public boolean deregisterDeathHandler() {
437         synchronized (mLock) {
438             if (mDeathEventHandler == null) {
439                 Log.e(TAG, "No Death handler present");
440             }
441             mDeathEventHandler = null;
442             return true;
443         }
444     }
445 
446     /**
447      * Signals whether initialization started successfully.
448      */
isInitializationStarted()449     public boolean isInitializationStarted() {
450         synchronized (mLock) {
451             return mServiceDeclared;
452         }
453     }
454 
455     /**
456      * Signals whether initialization completed successfully.
457      */
isInitializationComplete()458     public boolean isInitializationComplete() {
459         synchronized (mLock) {
460             return mISupplicant != null;
461         }
462     }
463 
464     /**
465      * Indicates whether the AIDL service is declared
466      */
serviceDeclared()467     public static boolean serviceDeclared() {
468         // Service Manager API ServiceManager#isDeclared supported after T.
469         if (!SdkLevel.isAtLeastT()) {
470             return false;
471         }
472         return ServiceManager.isDeclared(HAL_INSTANCE_NAME);
473     }
474 
475     /**
476      * Check that the service is running at least the expected version.
477      * Use to avoid the case where the framework is using a newer
478      * interface version than the service.
479      */
isServiceVersionAtLeast(int expectedVersion)480     protected boolean isServiceVersionAtLeast(int expectedVersion) {
481         return expectedVersion <= mServiceVersion;
482     }
483 
clearState()484     private void clearState() {
485         synchronized (mLock) {
486             Log.i(TAG, "Clearing internal state");
487             mISupplicant = null;
488             mISupplicantStaIfaces.clear();
489             mCurrentNetworkLocalConfigs.clear();
490             mCurrentNetworkRemoteHandles.clear();
491             mLinkedNetworkLocalAndRemoteConfigs.clear();
492             mNonStandardCertCallback = null;
493             mCurrentNetworkConnectTimestamp.clear();
494             mCurrentNetworkFallbackSsidIndex.clear();
495             mCurrentNetworkFallbackSsids.clear();
496         }
497     }
498 
supplicantServiceDiedHandler()499     private void supplicantServiceDiedHandler() {
500         synchronized (mLock) {
501             clearState();
502             if (mDeathEventHandler != null) {
503                 mDeathEventHandler.onDeath();
504             }
505         }
506     }
507 
508     /**
509      * Start the supplicant daemon.
510      *
511      * @return true on success, false otherwise.
512      */
startDaemon()513     public boolean startDaemon() {
514         synchronized (mLock) {
515             final String methodStr = "startDaemon";
516             if (mISupplicant != null) {
517                 Log.i(TAG, "Service is already initialized, skipping " + methodStr);
518                 return true;
519             }
520 
521             clearState();
522             mISupplicant = getSupplicantMockable();
523             if (mISupplicant == null) {
524                 Log.e(TAG, "Unable to obtain ISupplicant binder.");
525                 return false;
526             }
527             Log.i(TAG, "Obtained ISupplicant binder.");
528             Log.i(TAG, "Local Version: " + ISupplicant.VERSION);
529 
530             try {
531                 getServiceVersion();
532                 Log.i(TAG, "Remote Version: " + mServiceVersion);
533                 IBinder serviceBinder = getServiceBinderMockable();
534                 if (serviceBinder == null) {
535                     return false;
536                 }
537                 mWaitForDeathLatch = null;
538                 serviceBinder.linkToDeath(mSupplicantDeathRecipient, /* flags= */  0);
539                 setLogLevel(mVerboseHalLoggingEnabled);
540                 registerNonStandardCertCallback();
541                 return true;
542             } catch (RemoteException e) {
543                 handleRemoteException(e, methodStr);
544                 return false;
545             }
546         }
547     }
548 
getServiceVersion()549     private void getServiceVersion() throws RemoteException {
550         synchronized (mLock) {
551             if (mISupplicant == null) return;
552             if (mServiceVersion == -1) {
553                 int serviceVersion = mISupplicant.getInterfaceVersion();
554                 mWifiInjector.getSettingsConfigStore().put(
555                         WifiSettingsConfigStore.SUPPLICANT_HAL_AIDL_SERVICE_VERSION,
556                         serviceVersion);
557                 mServiceVersion = serviceVersion;
558                 Log.i(TAG, "Remote service version was cached");
559             }
560         }
561     }
562 
563     /**
564      * Terminate the supplicant daemon & wait for its death.
565      */
terminate()566     public void terminate() {
567         synchronized (mLock) {
568             final String methodStr = "terminate";
569             if (!checkSupplicantAndLogFailure(methodStr)) {
570                 return;
571             }
572             Log.i(TAG, "Terminate supplicant service");
573             try {
574                 mWaitForDeathLatch = new CountDownLatch(1);
575                 mISupplicant.terminate();
576             } catch (RemoteException e) {
577                 handleRemoteException(e, methodStr);
578             }
579         }
580 
581         // Wait for death recipient to confirm the service death.
582         try {
583             if (!mWaitForDeathLatch.await(WAIT_FOR_DEATH_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
584                 Log.w(TAG, "Timed out waiting for confirmation of supplicant death");
585             } else {
586                 Log.d(TAG, "Got service death confirmation");
587             }
588         } catch (InterruptedException e) {
589             Log.w(TAG, "Failed to wait for supplicant death");
590         }
591     }
592 
593     /**
594      * Wrapper functions to access HAL objects, created to be mockable in unit tests
595      */
596     @VisibleForTesting
getSupplicantMockable()597     protected ISupplicant getSupplicantMockable() {
598         synchronized (mLock) {
599             try {
600                 if (SdkLevel.isAtLeastT()) {
601                     return ISupplicant.Stub.asInterface(
602                             ServiceManager.waitForDeclaredService(HAL_INSTANCE_NAME));
603                 } else {
604                     return null;
605                 }
606             } catch (Exception e) {
607                 Log.e(TAG, "Unable to get ISupplicant service, " + e);
608                 return null;
609             }
610         }
611     }
612 
613     @VisibleForTesting
getServiceBinderMockable()614     protected IBinder getServiceBinderMockable() {
615         synchronized (mLock) {
616             if (mISupplicant == null) {
617                 return null;
618             }
619             return mISupplicant.asBinder();
620         }
621     }
622 
623     /**
624      * Helper method to look up the specified iface.
625      */
getStaIface(@onNull String ifaceName)626     private ISupplicantStaIface getStaIface(@NonNull String ifaceName) {
627         synchronized (mLock) {
628             return mISupplicantStaIfaces.get(ifaceName);
629         }
630     }
631 
632     /**
633      * Helper method to look up the network object for the specified iface.
634      */
getCurrentNetworkRemoteHandle( @onNull String ifaceName)635     private SupplicantStaNetworkHalAidlImpl getCurrentNetworkRemoteHandle(
636             @NonNull String ifaceName) {
637         synchronized (mLock) {
638             return mCurrentNetworkRemoteHandles.get(ifaceName);
639         }
640     }
641 
642     /**
643      * Helper method to look up the network config for the specified iface.
644      */
getCurrentNetworkLocalConfig(@onNull String ifaceName)645     protected WifiConfiguration getCurrentNetworkLocalConfig(@NonNull String ifaceName) {
646         synchronized (mLock) {
647             return mCurrentNetworkLocalConfigs.get(ifaceName);
648         }
649     }
650 
651     /**
652      * Add a network configuration to wpa_supplicant.
653      *
654      * @param config Config corresponding to the network.
655      * @return a Pair object including SupplicantStaNetworkHal and WifiConfiguration objects
656      * for the current network.
657      */
658     private Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>
addNetworkAndSaveConfig(@onNull String ifaceName, WifiConfiguration config)659             addNetworkAndSaveConfig(@NonNull String ifaceName, WifiConfiguration config) {
660         synchronized (mLock) {
661             if (config == null) {
662                 Log.e(TAG, "Cannot add null network.");
663                 return null;
664             }
665             SupplicantStaNetworkHalAidlImpl network = addNetwork(ifaceName);
666             if (network == null) {
667                 Log.e(TAG, "Failed to add network.");
668                 return null;
669             }
670             boolean saveSuccess = false;
671             try {
672                 saveSuccess = network.saveWifiConfiguration(config);
673             } catch (IllegalArgumentException e) {
674                 Log.e(TAG, "Exception while saving config params: " + config, e);
675             }
676             if (!saveSuccess) {
677                 Log.e(TAG, "Failed to save variables for: " + config.getProfileKey());
678                 if (!removeAllNetworks(ifaceName)) {
679                     Log.e(TAG, "Failed to remove all networks on failure.");
680                 }
681                 return null;
682             }
683             return new Pair(network, new WifiConfiguration(config));
684         }
685     }
686 
687     /**
688      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
689      * This method does the following:
690      * 1. If |config| is different to the current supplicant network, removes all supplicant
691      * networks and saves |config|.
692      * 2. Select the new network in wpa_supplicant.
693      *
694      * @param ifaceName Name of the interface.
695      * @param config WifiConfiguration parameters for the provided network.
696      * @return true if it succeeds, false otherwise
697      */
connectToNetwork(@onNull String ifaceName, @NonNull WifiConfiguration config)698     public boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config) {
699         return connectToNetwork(ifaceName, config, null);
700     }
701 
702     /**
703      * Returns whether to ignore the NETWORK_NOT_FOUND event in case it is based on stale cached
704      * scans.
705      *
706      * @param ifaceName Name of the interface.
707      * @return true if we should ignore NETWORK_NOT_FOUND, false otherwise
708      */
shouldIgnoreNetworkNotFound(@onNull String ifaceName)709     public boolean shouldIgnoreNetworkNotFound(@NonNull String ifaceName) {
710         synchronized (mLock) {
711             return (mClock.getElapsedSinceBootMillis()
712                     - mCurrentNetworkConnectTimestamp.getOrDefault(
713                             ifaceName, INVALID_CONNECT_TO_NETWORK_TIMESTAMP)
714                     < IGNORE_NETWORK_NOT_FOUND_DURATION_MS);
715         }
716     }
717 
718     /**
719      * Connects to the next fallback SSID (if any) of the current network upon a network not found
720      * notification. If all the fallback SSIDs have been tried, return to the first SSID and go
721      * through the fallbacks again.
722      *
723      * @return true if we're connecting to a fallback SSID, false if there are no fallback SSIDs, or
724      *         we've looped back to the first SSID.
725      */
connectToFallbackSsid(@onNull String ifaceName)726     public boolean connectToFallbackSsid(@NonNull String ifaceName) {
727         synchronized (mLock) {
728             List<WifiSsid> fallbackSsids = mCurrentNetworkFallbackSsids.get(ifaceName);
729             if (fallbackSsids == null || fallbackSsids.isEmpty()) {
730                 return false;
731             }
732             // Select the next fallback ssid.
733             // Note that the very first SSID we connect to is index 0, so the next SSID (i.e the
734             // first fallback SSID) will start with index 1. Once the entire list has been tried,
735             // wrap back to the first SSID at index 0.
736             int nextIndex = mCurrentNetworkFallbackSsidIndex.getOrDefault(ifaceName, 0) + 1;
737             if (nextIndex >= fallbackSsids.size()) {
738                 nextIndex = 0;
739             }
740             mCurrentNetworkFallbackSsidIndex.put(ifaceName, nextIndex);
741             WifiSsid nextSsid = fallbackSsids.get(nextIndex);
742             Log.d(TAG, "connectToFallbackSsid " + nextSsid + " at index " + nextIndex);
743             connectToNetwork(ifaceName, getCurrentNetworkLocalConfig(ifaceName), nextSsid);
744             return nextIndex != 0;
745         }
746     }
747 
748     /**
749      * Add the provided network configuration to wpa_supplicant and initiate connection to it.
750      * This method does the following:
751      * 1. If |config| is different to the current supplicant network, removes all supplicant
752      * networks and saves |config|.
753      * 2. Selects an SSID from the 2 possible original SSIDs derived from config.SSID to pass to
754      *    wpa_supplicant, and stores the unused one as fallback if the first one is not found.
755      * 3. Select the new network in wpa_supplicant.
756      *
757      * @param ifaceName Name of the interface.
758      * @param config WifiConfiguration parameters for the provided network.
759      * @param actualSsid The actual, untranslated SSID to send to supplicant. If this is null, then
760      *                   we will connect to either of the 2 possible original SSIDs based on the
761      *                   config's network selection BSSID or network selection candidate. If that
762      *                   SSID is not found, then we will immediately connect to the other one.
763      * @return true if it succeeds, false otherwise
764      */
connectToNetwork(@onNull String ifaceName, @NonNull WifiConfiguration config, WifiSsid actualSsid)765     private boolean connectToNetwork(@NonNull String ifaceName, @NonNull WifiConfiguration config,
766             WifiSsid actualSsid) {
767         synchronized (mLock) {
768             Log.d(TAG, "connectToNetwork " + config.getProfileKey() + ", actualSsid=" + actualSsid);
769             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
770             if (actualSsid == null && WifiConfigurationUtil.isSameNetwork(config, currentConfig)) {
771                 String networkSelectionBSSID = config.getNetworkSelectionStatus()
772                         .getNetworkSelectionBSSID();
773                 String networkSelectionBSSIDCurrent = currentConfig.getNetworkSelectionStatus()
774                         .getNetworkSelectionBSSID();
775                 if (Objects.equals(networkSelectionBSSID, networkSelectionBSSIDCurrent)) {
776                     Log.d(TAG, "Network is already saved, will not trigger remove and add.");
777                 } else {
778                     Log.d(TAG, "Network is already saved, but need to update BSSID.");
779                     if (!setCurrentNetworkBssid(
780                             ifaceName,
781                             config.getNetworkSelectionStatus().getNetworkSelectionBSSID())) {
782                         Log.e(TAG, "Failed to set current network BSSID.");
783                         return false;
784                     }
785                     mCurrentNetworkLocalConfigs.put(ifaceName, new WifiConfiguration(config));
786                 }
787             } else {
788                 mCurrentNetworkRemoteHandles.remove(ifaceName);
789                 mCurrentNetworkLocalConfigs.remove(ifaceName);
790                 mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
791                 if (!removeAllNetworks(ifaceName)) {
792                     Log.e(TAG, "Failed to remove existing networks");
793                     return false;
794                 }
795                 WifiConfiguration supplicantConfig = new WifiConfiguration(config);
796                 if (actualSsid != null) {
797                     supplicantConfig.SSID = actualSsid.toString();
798                 } else {
799                     mCurrentNetworkFallbackSsids.remove(ifaceName);
800                     mCurrentNetworkFallbackSsidIndex.remove(ifaceName);
801                     if (config.SSID != null) {
802                         // No actual SSID supplied, so select from the network selection BSSID
803                         // or the latest candidate BSSID.
804                         WifiSsid configSsid = WifiSsid.fromString(config.SSID);
805                         WifiSsid supplicantSsid = mSsidTranslator.getOriginalSsid(config);
806                         if (supplicantSsid != null) {
807                             Log.d(TAG, "Selecting supplicant SSID " + supplicantSsid);
808                             supplicantConfig.SSID = supplicantSsid.toString();
809 
810                             List<WifiSsid> fallbackSsids = mSsidTranslator
811                                     .getAllPossibleOriginalSsids(configSsid);
812                             fallbackSsids.remove(supplicantSsid);
813                             if (!fallbackSsids.isEmpty()) {
814                                 // Store the unused SSIDs to fallback on in
815                                 // connectToFallbackSsid(String) if the chosen SSID isn't found.
816                                 fallbackSsids.add(0, supplicantSsid);
817                                 mCurrentNetworkFallbackSsids.put(ifaceName, fallbackSsids);
818                                 mCurrentNetworkFallbackSsidIndex.put(ifaceName, 0);
819                             }
820                         }
821                         // Set the actual translation of the original SSID in case the untranslated
822                         // SSID has an ambiguous encoding.
823                         mSsidTranslator.setTranslatedSsidForStaIface(configSsid, ifaceName);
824                     }
825                 }
826                 Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair =
827                         addNetworkAndSaveConfig(ifaceName, supplicantConfig);
828                 if (pair == null) {
829                     Log.e(TAG, "Failed to add/save network configuration: " + config
830                             .getProfileKey());
831                     return false;
832                 }
833                 mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
834                 mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
835             }
836 
837             SupplicantStaNetworkHalAidlImpl networkHandle =
838                     checkStaNetworkAndLogFailure(ifaceName, "connectToNetwork");
839             if (networkHandle == null) {
840                 Log.e(TAG, "No valid remote network handle for network configuration: "
841                         + config.getProfileKey());
842                 return false;
843             }
844 
845             SecurityParams params = config.getNetworkSelectionStatus()
846                     .getCandidateSecurityParams();
847             if (params != null && !(params.isSecurityType(WifiConfiguration.SECURITY_TYPE_PSK)
848                     || params.isSecurityType(WifiConfiguration.SECURITY_TYPE_DPP))) {
849                 List<ArrayList<Byte>> pmkDataList = mPmkCacheManager.get(config.networkId);
850                 if (pmkDataList != null) {
851                     Log.i(TAG, "Set PMK cache for config id " + config.networkId);
852                     pmkDataList.forEach(pmkData -> {
853                         if (networkHandle.setPmkCache(NativeUtil.byteArrayFromArrayList(pmkData))) {
854                             mWifiMetrics.setConnectionPmkCache(ifaceName, true);
855                         }
856                     });
857                 }
858             }
859 
860             if (!networkHandle.select()) {
861                 Log.e(TAG, "Failed to select network configuration: " + config.getProfileKey());
862                 return false;
863             }
864             mCurrentNetworkConnectTimestamp.put(ifaceName, mClock.getElapsedSinceBootMillis());
865             return true;
866         }
867     }
868 
869     /**
870      * Initiates roaming to the already configured network in wpa_supplicant. If the network
871      * configuration provided does not match the already configured network, then this triggers
872      * a new connection attempt (instead of roam).
873      * 1. First check if we're attempting to connect to a linked network, and select the existing
874      *    supplicant network if there is one.
875      * 2. Set the new bssid for the network in wpa_supplicant.
876      * 3. Trigger reassociate command to wpa_supplicant.
877      *
878      * @param ifaceName Name of the interface.
879      * @param config WifiConfiguration parameters for the provided network.
880      * @return {@code true} if it succeeds, {@code false} otherwise
881      */
roamToNetwork(@onNull String ifaceName, WifiConfiguration config)882     public boolean roamToNetwork(@NonNull String ifaceName, WifiConfiguration config) {
883         synchronized (mLock) {
884             if (updateOnLinkedNetworkRoaming(ifaceName, config.networkId, true)) {
885                 SupplicantStaNetworkHalAidlImpl networkHandle =
886                         getCurrentNetworkRemoteHandle(ifaceName);
887                 if (networkHandle == null) {
888                     Log.e(TAG, "Roaming config matches a linked config, "
889                             + "but a linked network handle was not found.");
890                     return false;
891                 }
892                 return networkHandle.select();
893             }
894             if (getCurrentNetworkId(ifaceName) != config.networkId) {
895                 Log.w(TAG, "Cannot roam to a different network, initiate new connection. "
896                         + "Current network ID: " + getCurrentNetworkId(ifaceName));
897                 return connectToNetwork(ifaceName, config);
898             }
899             String bssid = config.getNetworkSelectionStatus().getNetworkSelectionBSSID();
900             Log.d(TAG, "roamToNetwork" + config.getProfileKey() + " (bssid " + bssid + ")");
901 
902             SupplicantStaNetworkHalAidlImpl networkHandle =
903                     checkStaNetworkAndLogFailure(ifaceName, "roamToNetwork");
904             if (networkHandle == null || !networkHandle.setBssid(bssid)) {
905                 Log.e(TAG, "Failed to set new bssid on network: " + config.getProfileKey());
906                 return false;
907             }
908             if (!reassociate(ifaceName)) {
909                 Log.e(TAG, "Failed to trigger reassociate");
910                 return false;
911             }
912             return true;
913         }
914     }
915 
916     /**
917      * Clean HAL cached data for |networkId| in the framework.
918      *
919      * @param networkId network id of the network to be removed from supplicant.
920      */
removeNetworkCachedData(int networkId)921     public void removeNetworkCachedData(int networkId) {
922         synchronized (mLock) {
923             Log.d(TAG, "Remove cached HAL data for config id " + networkId);
924             removePmkCacheEntry(networkId);
925         }
926     }
927 
928 
929     /**
930      * Clear HAL cached data if MAC address is changed.
931      *
932      * @param networkId network id of the network to be checked.
933      * @param curMacAddress current MAC address
934      */
removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress)935     public void removeNetworkCachedDataIfNeeded(int networkId, MacAddress curMacAddress) {
936         synchronized (mLock) {
937             mPmkCacheManager.remove(networkId, curMacAddress);
938         }
939     }
940 
941     /**
942      * Remove all networks from supplicant
943      *
944      * @param ifaceName Name of the interface.
945      */
removeAllNetworks(@onNull String ifaceName)946     public boolean removeAllNetworks(@NonNull String ifaceName) {
947         synchronized (mLock) {
948             int[] networks = listNetworks(ifaceName);
949             if (networks == null) {
950                 Log.e(TAG, "removeAllNetworks failed, got null networks");
951                 return false;
952             }
953             for (int id : networks) {
954                 if (!removeNetwork(ifaceName, id)) {
955                     Log.e(TAG, "removeAllNetworks failed to remove network: " + id);
956                     return false;
957                 }
958             }
959             // Reset current network info.
960             mCurrentNetworkRemoteHandles.remove(ifaceName);
961             mCurrentNetworkLocalConfigs.remove(ifaceName);
962             mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
963             return true;
964         }
965     }
966 
967     /**
968      * Disable the current network in supplicant
969      *
970      * @param ifaceName Name of the interface.
971      */
disableCurrentNetwork(@onNull String ifaceName)972     public boolean disableCurrentNetwork(@NonNull String ifaceName) {
973         synchronized (mLock) {
974             SupplicantStaNetworkHalAidlImpl networkHandle =
975                     checkStaNetworkAndLogFailure(ifaceName, "disableCurrentNetwork");
976             if (networkHandle == null) {
977                 return false;
978             }
979             Log.d(TAG, "Remove fallback ssids to avoid endless loop");
980             mCurrentNetworkFallbackSsids.remove(ifaceName);
981             mCurrentNetworkFallbackSsidIndex.remove(ifaceName);
982             return networkHandle.disable();
983         }
984     }
985 
986     /**
987      * Set the currently configured network's bssid.
988      *
989      * @param ifaceName Name of the interface.
990      * @param bssidStr Bssid to set in the form of "XX:XX:XX:XX:XX:XX"
991      * @return true if succeeds, false otherwise.
992      */
setCurrentNetworkBssid(@onNull String ifaceName, String bssidStr)993     public boolean setCurrentNetworkBssid(@NonNull String ifaceName, String bssidStr) {
994         synchronized (mLock) {
995             SupplicantStaNetworkHalAidlImpl networkHandle =
996                     checkStaNetworkAndLogFailure(ifaceName, "setCurrentNetworkBssid");
997             if (networkHandle == null) {
998                 return false;
999             }
1000             return networkHandle.setBssid(bssidStr);
1001         }
1002     }
1003 
1004     /**
1005      * Get the currently configured network's WPS NFC token.
1006      *
1007      * @param ifaceName Name of the interface.
1008      * @return Hex string corresponding to the WPS NFC token.
1009      */
getCurrentNetworkWpsNfcConfigurationToken(@onNull String ifaceName)1010     public String getCurrentNetworkWpsNfcConfigurationToken(@NonNull String ifaceName) {
1011         synchronized (mLock) {
1012             SupplicantStaNetworkHalAidlImpl networkHandle =
1013                     checkStaNetworkAndLogFailure(
1014                             ifaceName, "getCurrentNetworkWpsNfcConfigurationToken");
1015             if (networkHandle == null) {
1016                 return null;
1017             }
1018             return networkHandle.getWpsNfcConfigurationToken();
1019         }
1020     }
1021 
1022     /**
1023      * Get the eap anonymous identity for the currently configured network.
1024      *
1025      * @param ifaceName Name of the interface.
1026      * @return anonymous identity string if succeeds, null otherwise.
1027      */
getCurrentNetworkEapAnonymousIdentity(@onNull String ifaceName)1028     public String getCurrentNetworkEapAnonymousIdentity(@NonNull String ifaceName) {
1029         synchronized (mLock) {
1030             SupplicantStaNetworkHalAidlImpl networkHandle =
1031                     checkStaNetworkAndLogFailure(
1032                             ifaceName, "getCurrentNetworkEapAnonymousIdentity");
1033             if (networkHandle == null) {
1034                 return null;
1035             }
1036             return networkHandle.fetchEapAnonymousIdentity();
1037         }
1038     }
1039 
1040     /**
1041      * Send the eap identity response for the currently configured network.
1042      *
1043      * @param ifaceName Name of the interface.
1044      * @param identity identity used for EAP-Identity
1045      * @param encryptedIdentity encrypted identity used for EAP-AKA/EAP-SIM
1046      * @return true if succeeds, false otherwise.
1047      */
sendCurrentNetworkEapIdentityResponse( @onNull String ifaceName, @NonNull String identity, String encryptedIdentity)1048     public boolean sendCurrentNetworkEapIdentityResponse(
1049             @NonNull String ifaceName, @NonNull String identity, String encryptedIdentity) {
1050         synchronized (mLock) {
1051             SupplicantStaNetworkHalAidlImpl networkHandle =
1052                     checkStaNetworkAndLogFailure(
1053                             ifaceName, "sendCurrentNetworkEapIdentityResponse");
1054             if (networkHandle == null) {
1055                 return false;
1056             }
1057             return networkHandle.sendNetworkEapIdentityResponse(identity, encryptedIdentity);
1058         }
1059     }
1060 
1061     /**
1062      * Send the eap sim gsm auth response for the currently configured network.
1063      *
1064      * @param ifaceName Name of the interface.
1065      * @param paramsStr String to send.
1066      * @return true if succeeds, false otherwise.
1067      */
sendCurrentNetworkEapSimGsmAuthResponse( @onNull String ifaceName, String paramsStr)1068     public boolean sendCurrentNetworkEapSimGsmAuthResponse(
1069             @NonNull String ifaceName, String paramsStr) {
1070         synchronized (mLock) {
1071             SupplicantStaNetworkHalAidlImpl networkHandle =
1072                     checkStaNetworkAndLogFailure(
1073                             ifaceName, "sendCurrentNetworkEapSimGsmAuthResponse");
1074             if (networkHandle == null) {
1075                 return false;
1076             }
1077             return networkHandle.sendNetworkEapSimGsmAuthResponse(paramsStr);
1078         }
1079     }
1080 
1081     /**
1082      * Send the eap sim gsm auth failure for the currently configured network.
1083      *
1084      * @param ifaceName Name of the interface.
1085      * @return true if succeeds, false otherwise.
1086      */
sendCurrentNetworkEapSimGsmAuthFailure(@onNull String ifaceName)1087     public boolean sendCurrentNetworkEapSimGsmAuthFailure(@NonNull String ifaceName) {
1088         synchronized (mLock) {
1089             SupplicantStaNetworkHalAidlImpl networkHandle =
1090                     checkStaNetworkAndLogFailure(
1091                             ifaceName, "sendCurrentNetworkEapSimGsmAuthFailure");
1092             if (networkHandle == null) {
1093                 return false;
1094             }
1095             return networkHandle.sendNetworkEapSimGsmAuthFailure();
1096         }
1097     }
1098 
1099     /**
1100      * Send the eap sim umts auth response for the currently configured network.
1101      *
1102      * @param ifaceName Name of the interface.
1103      * @param paramsStr String to send.
1104      * @return true if succeeds, false otherwise.
1105      */
sendCurrentNetworkEapSimUmtsAuthResponse( @onNull String ifaceName, String paramsStr)1106     public boolean sendCurrentNetworkEapSimUmtsAuthResponse(
1107             @NonNull String ifaceName, String paramsStr) {
1108         synchronized (mLock) {
1109             SupplicantStaNetworkHalAidlImpl networkHandle =
1110                     checkStaNetworkAndLogFailure(
1111                             ifaceName, "sendCurrentNetworkEapSimUmtsAuthResponse");
1112             if (networkHandle == null) {
1113                 return false;
1114             }
1115             return networkHandle.sendNetworkEapSimUmtsAuthResponse(paramsStr);
1116         }
1117     }
1118 
1119     /**
1120      * Send the eap sim umts auts response for the currently configured network.
1121      *
1122      * @param ifaceName Name of the interface.
1123      * @param paramsStr String to send.
1124      * @return true if succeeds, false otherwise.
1125      */
sendCurrentNetworkEapSimUmtsAutsResponse( @onNull String ifaceName, String paramsStr)1126     public boolean sendCurrentNetworkEapSimUmtsAutsResponse(
1127             @NonNull String ifaceName, String paramsStr) {
1128         synchronized (mLock) {
1129             SupplicantStaNetworkHalAidlImpl networkHandle =
1130                     checkStaNetworkAndLogFailure(
1131                             ifaceName, "sendCurrentNetworkEapSimUmtsAutsResponse");
1132             if (networkHandle == null) {
1133                 return false;
1134             }
1135             return networkHandle.sendNetworkEapSimUmtsAutsResponse(paramsStr);
1136         }
1137     }
1138 
1139     /**
1140      * Send the eap sim umts auth failure for the currently configured network.
1141      *
1142      * @param ifaceName Name of the interface.
1143      * @return true if succeeds, false otherwise.
1144      */
sendCurrentNetworkEapSimUmtsAuthFailure(@onNull String ifaceName)1145     public boolean sendCurrentNetworkEapSimUmtsAuthFailure(@NonNull String ifaceName) {
1146         synchronized (mLock) {
1147             SupplicantStaNetworkHalAidlImpl networkHandle =
1148                     checkStaNetworkAndLogFailure(
1149                             ifaceName, "sendCurrentNetworkEapSimUmtsAuthFailure");
1150             if (networkHandle == null) {
1151                 return false;
1152             }
1153             return networkHandle.sendNetworkEapSimUmtsAuthFailure();
1154         }
1155     }
1156 
1157     /**
1158      * Adds a new network.
1159      *
1160      * @return SupplicantStaNetworkHalAidlImpl object for the new network, or null if the call fails
1161      */
addNetwork(@onNull String ifaceName)1162     private SupplicantStaNetworkHalAidlImpl addNetwork(@NonNull String ifaceName) {
1163         synchronized (mLock) {
1164             final String methodStr = "addNetwork";
1165             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1166             if (iface == null) {
1167                 return null;
1168             }
1169             try {
1170                 ISupplicantStaNetwork network = iface.addNetwork();
1171                 // Get framework wrapper around the AIDL network object
1172                 return getStaNetworkHalMockable(ifaceName, network);
1173             } catch (RemoteException e) {
1174                 handleRemoteException(e, methodStr);
1175             } catch (ServiceSpecificException e) {
1176                 handleServiceSpecificException(e, methodStr);
1177             }
1178             return null;
1179         }
1180     }
1181 
1182     /**
1183      * Remove network with specified network Id from supplicant.
1184      *
1185      * @return true if request is sent successfully, false otherwise.
1186      */
removeNetwork(@onNull String ifaceName, int id)1187     private boolean removeNetwork(@NonNull String ifaceName, int id) {
1188         synchronized (mLock) {
1189             final String methodStr = "removeNetwork";
1190             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1191             if (iface == null) {
1192                 return false;
1193             }
1194             try {
1195                 iface.removeNetwork(id);
1196                 return true;
1197             } catch (RemoteException e) {
1198                 handleRemoteException(e, methodStr);
1199             } catch (ServiceSpecificException e) {
1200                 handleServiceSpecificException(e, methodStr);
1201             }
1202             return false;
1203         }
1204     }
1205 
1206     /**
1207      * Creates a SupplicantStaNetworkHal wrapper around an AIDL ISupplicantStaNetwork object.
1208      * Declared mockable for use in unit tests.
1209      *
1210      * @param ifaceName Name of the interface.
1211      * @param network ISupplicantStaNetwork instance retrieved from AIDL.
1212      * @return SupplicantStaNetworkHal object for the given network, or null if
1213      * the call fails
1214      */
getStaNetworkHalMockable( @onNull String ifaceName, ISupplicantStaNetwork network)1215     protected SupplicantStaNetworkHalAidlImpl getStaNetworkHalMockable(
1216             @NonNull String ifaceName, ISupplicantStaNetwork network) {
1217         synchronized (mLock) {
1218             SupplicantStaNetworkHalAidlImpl networkWrapper =
1219                     new SupplicantStaNetworkHalAidlImpl(mServiceVersion,
1220                             network, ifaceName, mContext,
1221                             mWifiMonitor, mWifiGlobals,
1222                             getAdvancedCapabilities(ifaceName),
1223                             getWpaDriverFeatureSet(ifaceName));
1224             if (networkWrapper != null) {
1225                 networkWrapper.enableVerboseLogging(
1226                         mVerboseLoggingEnabled, mVerboseHalLoggingEnabled);
1227             }
1228             return networkWrapper;
1229         }
1230     }
1231 
registerCallback( ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback)1232     private boolean registerCallback(
1233             ISupplicantStaIface iface, ISupplicantStaIfaceCallback callback) {
1234         synchronized (mLock) {
1235             String methodStr = "registerCallback";
1236             if (iface == null) {
1237                 return false;
1238             }
1239             try {
1240                 iface.registerCallback(callback);
1241                 return true;
1242             } catch (RemoteException e) {
1243                 handleRemoteException(e, methodStr);
1244             } catch (ServiceSpecificException e) {
1245                 handleServiceSpecificException(e, methodStr);
1246             }
1247             return false;
1248         }
1249     }
1250 
1251     /**
1252      * Get list of id's of all networks controlled by supplicant.
1253      *
1254      * @return list of network id's, null if failed
1255      */
listNetworks(@onNull String ifaceName)1256     private int[] listNetworks(@NonNull String ifaceName) {
1257         synchronized (mLock) {
1258             final String methodStr = "listNetworks";
1259             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1260             if (iface == null) {
1261                 return null;
1262             }
1263             try {
1264                 return iface.listNetworks();
1265             } catch (RemoteException e) {
1266                 handleRemoteException(e, methodStr);
1267             } catch (ServiceSpecificException e) {
1268                 handleServiceSpecificException(e, methodStr);
1269             }
1270             return null;
1271         }
1272     }
1273 
1274     /**
1275      * Set WPS device name.
1276      *
1277      * @param ifaceName Name of the interface.
1278      * @param name String to be set.
1279      * @return true if request is sent successfully, false otherwise.
1280      */
setWpsDeviceName(@onNull String ifaceName, String name)1281     public boolean setWpsDeviceName(@NonNull String ifaceName, String name) {
1282         synchronized (mLock) {
1283             final String methodStr = "setWpsDeviceName";
1284             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1285             if (iface == null) {
1286                 return false;
1287             }
1288             try {
1289                 iface.setWpsDeviceName(name);
1290                 return true;
1291             } catch (RemoteException e) {
1292                 handleRemoteException(e, methodStr);
1293             } catch (ServiceSpecificException e) {
1294                 handleServiceSpecificException(e, methodStr);
1295             }
1296             return false;
1297         }
1298     }
1299 
1300     /**
1301      * Set WPS device type.
1302      *
1303      * @param ifaceName Name of the interface.
1304      * @param typeStr Type specified as a string. Used format: <categ>-<OUI>-<subcateg>
1305      * @return true if request is sent successfully, false otherwise.
1306      */
setWpsDeviceType(@onNull String ifaceName, String typeStr)1307     public boolean setWpsDeviceType(@NonNull String ifaceName, String typeStr) {
1308         synchronized (mLock) {
1309             try {
1310                 Matcher match = WPS_DEVICE_TYPE_PATTERN.matcher(typeStr);
1311                 if (!match.find() || match.groupCount() != 3) {
1312                     Log.e(TAG, "Malformed WPS device type " + typeStr);
1313                     return false;
1314                 }
1315                 short categ = Short.parseShort(match.group(1));
1316                 byte[] oui = NativeUtil.hexStringToByteArray(match.group(2));
1317                 short subCateg = Short.parseShort(match.group(3));
1318 
1319                 byte[] bytes = new byte[8];
1320                 ByteBuffer byteBuffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
1321                 byteBuffer.putShort(categ);
1322                 byteBuffer.put(oui);
1323                 byteBuffer.putShort(subCateg);
1324                 return setWpsDeviceType(ifaceName, bytes);
1325             } catch (IllegalArgumentException e) {
1326                 Log.e(TAG, "Illegal argument " + typeStr, e);
1327                 return false;
1328             }
1329         }
1330     }
1331 
setWpsDeviceType(@onNull String ifaceName, byte[ ] type)1332     private boolean setWpsDeviceType(@NonNull String ifaceName, byte[/* 8 */] type) {
1333         synchronized (mLock) {
1334             final String methodStr = "setWpsDeviceType";
1335             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1336             if (iface == null) {
1337                 return false;
1338             }
1339             try {
1340                 iface.setWpsDeviceType(type);
1341                 return true;
1342             } catch (RemoteException e) {
1343                 handleRemoteException(e, methodStr);
1344             } catch (ServiceSpecificException e) {
1345                 handleServiceSpecificException(e, methodStr);
1346             }
1347             return false;
1348         }
1349     }
1350 
1351     /**
1352      * Set WPS manufacturer.
1353      *
1354      * @param ifaceName Name of the interface.
1355      * @param manufacturer String to be set.
1356      * @return true if request is sent successfully, false otherwise.
1357      */
setWpsManufacturer(@onNull String ifaceName, String manufacturer)1358     public boolean setWpsManufacturer(@NonNull String ifaceName, String manufacturer) {
1359         synchronized (mLock) {
1360             final String methodStr = "setWpsManufacturer";
1361             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1362             if (iface == null) {
1363                 return false;
1364             }
1365             try {
1366                 iface.setWpsManufacturer(manufacturer);
1367                 return true;
1368             } catch (RemoteException e) {
1369                 handleRemoteException(e, methodStr);
1370             } catch (ServiceSpecificException e) {
1371                 handleServiceSpecificException(e, methodStr);
1372             }
1373             return false;
1374         }
1375     }
1376 
1377     /**
1378      * Set WPS model name.
1379      *
1380      * @param ifaceName Name of the interface.
1381      * @param modelName String to be set.
1382      * @return true if request is sent successfully, false otherwise.
1383      */
setWpsModelName(@onNull String ifaceName, String modelName)1384     public boolean setWpsModelName(@NonNull String ifaceName, String modelName) {
1385         synchronized (mLock) {
1386             final String methodStr = "setWpsModelName";
1387             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1388             if (iface == null) {
1389                 return false;
1390             }
1391             try {
1392                 iface.setWpsModelName(modelName);
1393                 return true;
1394             } catch (RemoteException e) {
1395                 handleRemoteException(e, methodStr);
1396             } catch (ServiceSpecificException e) {
1397                 handleServiceSpecificException(e, methodStr);
1398             }
1399             return false;
1400         }
1401     }
1402 
1403     /**
1404      * Set WPS model number.
1405      *
1406      * @param ifaceName Name of the interface.
1407      * @param modelNumber String to be set.
1408      * @return true if request is sent successfully, false otherwise.
1409      */
setWpsModelNumber(@onNull String ifaceName, String modelNumber)1410     public boolean setWpsModelNumber(@NonNull String ifaceName, String modelNumber) {
1411         synchronized (mLock) {
1412             final String methodStr = "setWpsModelNumber";
1413             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1414             if (iface == null) {
1415                 return false;
1416             }
1417             try {
1418                 iface.setWpsModelNumber(modelNumber);
1419                 return true;
1420             } catch (RemoteException e) {
1421                 handleRemoteException(e, methodStr);
1422             } catch (ServiceSpecificException e) {
1423                 handleServiceSpecificException(e, methodStr);
1424             }
1425             return false;
1426         }
1427     }
1428 
1429     /**
1430      * Set WPS serial number.
1431      *
1432      * @param ifaceName Name of the interface.
1433      * @param serialNumber String to be set.
1434      * @return true if request is sent successfully, false otherwise.
1435      */
setWpsSerialNumber(@onNull String ifaceName, String serialNumber)1436     public boolean setWpsSerialNumber(@NonNull String ifaceName, String serialNumber) {
1437         synchronized (mLock) {
1438             final String methodStr = "setWpsSerialNumber";
1439             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1440             if (iface == null) {
1441                 return false;
1442             }
1443             try {
1444                 iface.setWpsSerialNumber(serialNumber);
1445                 return true;
1446             } catch (RemoteException e) {
1447                 handleRemoteException(e, methodStr);
1448             } catch (ServiceSpecificException e) {
1449                 handleServiceSpecificException(e, methodStr);
1450             }
1451             return false;
1452         }
1453     }
1454 
1455     /**
1456      * Set WPS config methods
1457      *
1458      * @param ifaceName Name of the interface.
1459      * @param configMethodsStr List of config methods.
1460      * @return true if request is sent successfully, false otherwise.
1461      */
setWpsConfigMethods(@onNull String ifaceName, String configMethodsStr)1462     public boolean setWpsConfigMethods(@NonNull String ifaceName, String configMethodsStr) {
1463         synchronized (mLock) {
1464             int configMethodsMask = 0;
1465             String[] configMethodsStrArr = configMethodsStr.split("\\s+");
1466             for (int i = 0; i < configMethodsStrArr.length; i++) {
1467                 configMethodsMask |= stringToWpsConfigMethod(configMethodsStrArr[i]);
1468             }
1469             return setWpsConfigMethods(ifaceName, configMethodsMask);
1470         }
1471     }
1472 
setWpsConfigMethods(@onNull String ifaceName, int configMethods)1473     private boolean setWpsConfigMethods(@NonNull String ifaceName, int configMethods) {
1474         synchronized (mLock) {
1475             final String methodStr = "setWpsConfigMethods";
1476             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1477             if (iface == null) {
1478                 return false;
1479             }
1480             try {
1481                 iface.setWpsConfigMethods(configMethods);
1482                 return true;
1483             } catch (RemoteException e) {
1484                 handleRemoteException(e, methodStr);
1485             } catch (ServiceSpecificException e) {
1486                 handleServiceSpecificException(e, methodStr);
1487             }
1488             return false;
1489         }
1490     }
1491 
1492     /**
1493      * Trigger a reassociation even if the iface is currently connected.
1494      *
1495      * @param ifaceName Name of the interface.
1496      * @return true if request is sent successfully, false otherwise.
1497      */
reassociate(@onNull String ifaceName)1498     public boolean reassociate(@NonNull String ifaceName) {
1499         synchronized (mLock) {
1500             final String methodStr = "reassociate";
1501             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1502             if (iface == null) {
1503                 return false;
1504             }
1505             try {
1506                 iface.reassociate();
1507                 return true;
1508             } catch (RemoteException e) {
1509                 handleRemoteException(e, methodStr);
1510             } catch (ServiceSpecificException e) {
1511                 handleServiceSpecificException(e, methodStr);
1512             }
1513             return false;
1514         }
1515     }
1516 
1517     /**
1518      * Trigger a reconnection if the iface is disconnected.
1519      *
1520      * @param ifaceName Name of the interface.
1521      * @return true if request is sent successfully, false otherwise.
1522      */
reconnect(@onNull String ifaceName)1523     public boolean reconnect(@NonNull String ifaceName) {
1524         synchronized (mLock) {
1525             final String methodStr = "reconnect";
1526             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1527             if (iface == null) {
1528                 return false;
1529             }
1530             try {
1531                 iface.reconnect();
1532                 return true;
1533             } catch (RemoteException e) {
1534                 handleRemoteException(e, methodStr);
1535             } catch (ServiceSpecificException e) {
1536                 handleServiceSpecificException(e, methodStr);
1537             }
1538             return false;
1539         }
1540     }
1541 
1542 
1543     /**
1544      * Trigger a disconnection from the currently connected network.
1545      *
1546      * @param ifaceName Name of the interface.
1547      * @return true if request is sent successfully, false otherwise.
1548      */
disconnect(@onNull String ifaceName)1549     public boolean disconnect(@NonNull String ifaceName) {
1550         synchronized (mLock) {
1551             final String methodStr = "disconnect";
1552             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1553             if (iface == null) {
1554                 return false;
1555             }
1556             try {
1557                 iface.disconnect();
1558                 return true;
1559             } catch (RemoteException e) {
1560                 handleRemoteException(e, methodStr);
1561             } catch (ServiceSpecificException e) {
1562                 handleServiceSpecificException(e, methodStr);
1563             }
1564             return false;
1565         }
1566     }
1567 
1568     /**
1569      * Enable or disable power save mode.
1570      *
1571      * @param ifaceName Name of the interface.
1572      * @param enable true to enable, false to disable.
1573      * @return true if request is sent successfully, false otherwise.
1574      */
setPowerSave(@onNull String ifaceName, boolean enable)1575     public boolean setPowerSave(@NonNull String ifaceName, boolean enable) {
1576         synchronized (mLock) {
1577             final String methodStr = "setPowerSave";
1578             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1579             if (iface == null) {
1580                 return false;
1581             }
1582             try {
1583                 iface.setPowerSave(enable);
1584                 return true;
1585             } catch (RemoteException e) {
1586                 handleRemoteException(e, methodStr);
1587             } catch (ServiceSpecificException e) {
1588                 handleServiceSpecificException(e, methodStr);
1589             }
1590             return false;
1591         }
1592     }
1593 
1594     /**
1595      * Initiate TDLS discover with the specified AP.
1596      *
1597      * @param ifaceName Name of the interface.
1598      * @param macAddress MAC Address of the AP.
1599      * @return true if request is sent successfully, false otherwise.
1600      */
initiateTdlsDiscover(@onNull String ifaceName, String macAddress)1601     public boolean initiateTdlsDiscover(@NonNull String ifaceName, String macAddress) {
1602         synchronized (mLock) {
1603             try {
1604                 return initiateTdlsDiscover(
1605                         ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1606             } catch (IllegalArgumentException e) {
1607                 Log.e(TAG, "Illegal argument " + macAddress, e);
1608                 return false;
1609             }
1610         }
1611     }
1612 
initiateTdlsDiscover(@onNull String ifaceName, byte[ ] macAddress)1613     private boolean initiateTdlsDiscover(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1614         synchronized (mLock) {
1615             final String methodStr = "initiateTdlsDiscover";
1616             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1617             if (iface == null) {
1618                 return false;
1619             }
1620             try {
1621                 iface.initiateTdlsDiscover(macAddress);
1622                 return true;
1623             } catch (RemoteException e) {
1624                 handleRemoteException(e, methodStr);
1625             } catch (ServiceSpecificException e) {
1626                 handleServiceSpecificException(e, methodStr);
1627             }
1628             return false;
1629         }
1630     }
1631 
1632     /**
1633      * Initiate TDLS setup with the specified AP.
1634      *
1635      * @param ifaceName Name of the interface.
1636      * @param macAddress MAC Address of the AP.
1637      * @return true if request is sent successfully, false otherwise.
1638      */
initiateTdlsSetup(@onNull String ifaceName, String macAddress)1639     public boolean initiateTdlsSetup(@NonNull String ifaceName, String macAddress) {
1640         synchronized (mLock) {
1641             try {
1642                 return initiateTdlsSetup(ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1643             } catch (IllegalArgumentException e) {
1644                 Log.e(TAG, "Illegal argument " + macAddress, e);
1645                 return false;
1646             }
1647         }
1648     }
1649 
initiateTdlsSetup(@onNull String ifaceName, byte[ ] macAddress)1650     private boolean initiateTdlsSetup(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1651         synchronized (mLock) {
1652             final String methodStr = "initiateTdlsSetup";
1653             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1654             if (iface == null) {
1655                 return false;
1656             }
1657             try {
1658                 iface.initiateTdlsSetup(macAddress);
1659                 return true;
1660             } catch (RemoteException e) {
1661                 handleRemoteException(e, methodStr);
1662             } catch (ServiceSpecificException e) {
1663                 handleServiceSpecificException(e, methodStr);
1664             }
1665             return false;
1666         }
1667     }
1668 
1669     /**
1670      * Initiate TDLS teardown with the specified AP.
1671      *
1672      * @param ifaceName Name of the interface.
1673      * @param macAddress MAC Address of the AP.
1674      * @return true if request is sent successfully, false otherwise.
1675      */
initiateTdlsTeardown(@onNull String ifaceName, String macAddress)1676     public boolean initiateTdlsTeardown(@NonNull String ifaceName, String macAddress) {
1677         synchronized (mLock) {
1678             try {
1679                 return initiateTdlsTeardown(
1680                         ifaceName, NativeUtil.macAddressToByteArray(macAddress));
1681             } catch (IllegalArgumentException e) {
1682                 Log.e(TAG, "Illegal argument " + macAddress, e);
1683                 return false;
1684             }
1685         }
1686     }
1687 
initiateTdlsTeardown(@onNull String ifaceName, byte[ ] macAddress)1688     private boolean initiateTdlsTeardown(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1689         synchronized (mLock) {
1690             final String methodStr = "initiateTdlsTeardown";
1691             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1692             if (iface == null) {
1693                 return false;
1694             }
1695             try {
1696                 iface.initiateTdlsTeardown(macAddress);
1697                 return true;
1698             } catch (RemoteException e) {
1699                 handleRemoteException(e, methodStr);
1700             } catch (ServiceSpecificException e) {
1701                 handleServiceSpecificException(e, methodStr);
1702             }
1703             return false;
1704         }
1705     }
1706 
1707     /**
1708      * Request the specified ANQP elements |elements| from the specified AP |bssid|.
1709      *
1710      * @param ifaceName Name of the interface.
1711      * @param bssid BSSID of the AP
1712      * @param infoElements ANQP elements to be queried. Refer to ISupplicantStaIface.AnqpInfoId.
1713      * @param hs20SubTypes HS subtypes to be queried. Refer to ISupplicantStaIface.Hs20AnqpSubTypes.
1714      * @return true if request is sent successfully, false otherwise.
1715      */
initiateAnqpQuery(@onNull String ifaceName, String bssid, ArrayList<Short> infoElements, ArrayList<Integer> hs20SubTypes)1716     public boolean initiateAnqpQuery(@NonNull String ifaceName, String bssid,
1717             ArrayList<Short> infoElements,
1718             ArrayList<Integer> hs20SubTypes) {
1719         synchronized (mLock) {
1720             try {
1721                 int[] infoElementsCast = new int[infoElements.size()];
1722                 int[] hs20SubTypesCast = new int[hs20SubTypes.size()];
1723                 for (int i = 0; i < infoElements.size(); i++) {
1724                     infoElementsCast[i] = infoElements.get(i);
1725                 }
1726                 for (int i = 0; i < hs20SubTypes.size(); i++) {
1727                     hs20SubTypesCast[i] = hs20SubTypes.get(i);
1728                 }
1729                 return initiateAnqpQuery(
1730                         ifaceName,
1731                         NativeUtil.macAddressToByteArray(bssid),
1732                         infoElementsCast, hs20SubTypesCast);
1733             } catch (IllegalArgumentException e) {
1734                 Log.e(TAG, "Illegal argument " + bssid, e);
1735                 return false;
1736             }
1737         }
1738     }
1739 
initiateAnqpQuery(@onNull String ifaceName, byte[ ] macAddress, int[] infoElements, int[] subTypes)1740     private boolean initiateAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress,
1741             int[] infoElements, int[] subTypes) {
1742         synchronized (mLock) {
1743             final String methodStr = "initiateAnqpQuery";
1744             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1745             if (iface == null) {
1746                 return false;
1747             }
1748             try {
1749                 iface.initiateAnqpQuery(macAddress, infoElements, subTypes);
1750                 return true;
1751             } catch (RemoteException e) {
1752                 handleRemoteException(e, methodStr);
1753             } catch (ServiceSpecificException e) {
1754                 handleServiceSpecificException(e, methodStr);
1755             }
1756             return false;
1757         }
1758     }
1759 
1760     /**
1761      * Request Venue URL ANQP element from the specified AP |bssid|.
1762      *
1763      * @param ifaceName Name of the interface.
1764      * @param bssid BSSID of the AP
1765      * @return true if request is sent successfully, false otherwise.
1766      */
initiateVenueUrlAnqpQuery(@onNull String ifaceName, String bssid)1767     public boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, String bssid) {
1768         synchronized (mLock) {
1769             try {
1770                 return initiateVenueUrlAnqpQuery(
1771                         ifaceName, NativeUtil.macAddressToByteArray(bssid));
1772             } catch (IllegalArgumentException e) {
1773                 Log.e(TAG, "Illegal argument " + bssid, e);
1774                 return false;
1775             }
1776         }
1777     }
1778 
initiateVenueUrlAnqpQuery(@onNull String ifaceName, byte[ ] macAddress)1779     private boolean initiateVenueUrlAnqpQuery(@NonNull String ifaceName, byte[/* 6 */] macAddress) {
1780         synchronized (mLock) {
1781             final String methodStr = "initiateVenueUrlAnqpQuery";
1782             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1783             if (iface == null) {
1784                 return false;
1785             }
1786             try {
1787                 iface.initiateVenueUrlAnqpQuery(macAddress);
1788                 return true;
1789             } catch (RemoteException e) {
1790                 handleRemoteException(e, methodStr);
1791             } catch (ServiceSpecificException e) {
1792                 handleServiceSpecificException(e, methodStr);
1793             }
1794             return false;
1795         }
1796     }
1797 
1798     /**
1799      * Request the specified ANQP ICON from the specified AP |bssid|.
1800      *
1801      * @param ifaceName Name of the interface.
1802      * @param bssid BSSID of the AP
1803      * @param fileName Name of the file to request.
1804      * @return true if request is sent successfully, false otherwise.
1805      */
initiateHs20IconQuery(@onNull String ifaceName, String bssid, String fileName)1806     public boolean initiateHs20IconQuery(@NonNull String ifaceName, String bssid, String fileName) {
1807         synchronized (mLock) {
1808             try {
1809                 return initiateHs20IconQuery(
1810                         ifaceName, NativeUtil.macAddressToByteArray(bssid), fileName);
1811             } catch (IllegalArgumentException e) {
1812                 Log.e(TAG, "Illegal argument " + bssid, e);
1813                 return false;
1814             }
1815         }
1816     }
1817 
initiateHs20IconQuery(@onNull String ifaceName, byte[ ] macAddress, String fileName)1818     private boolean initiateHs20IconQuery(@NonNull String ifaceName,
1819             byte[/* 6 */] macAddress, String fileName) {
1820         synchronized (mLock) {
1821             final String methodStr = "initiateHs20IconQuery";
1822             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1823             if (iface == null) {
1824                 return false;
1825             }
1826             try {
1827                 iface.initiateHs20IconQuery(macAddress, fileName);
1828                 return true;
1829             } catch (RemoteException e) {
1830                 handleRemoteException(e, methodStr);
1831             } catch (ServiceSpecificException e) {
1832                 handleServiceSpecificException(e, methodStr);
1833             }
1834             return false;
1835         }
1836     }
1837 
1838     /**
1839      * Gets MAC Address from the supplicant.
1840      *
1841      * @param ifaceName Name of the interface.
1842      * @return string containing the MAC address, or null on a failed call
1843      */
getMacAddress(@onNull String ifaceName)1844     public String getMacAddress(@NonNull String ifaceName) {
1845         synchronized (mLock) {
1846             final String methodStr = "getMacAddress";
1847             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1848             if (iface == null) {
1849                 return null;
1850             }
1851             try {
1852                 byte[] macAddr = iface.getMacAddress();
1853                 return NativeUtil.macAddressFromByteArray(macAddr);
1854             } catch (RemoteException e) {
1855                 handleRemoteException(e, methodStr);
1856             } catch (ServiceSpecificException e) {
1857                 handleServiceSpecificException(e, methodStr);
1858             } catch (IllegalArgumentException e) {
1859                 Log.e(TAG, "Invalid MAC address value", e);
1860             }
1861             return null;
1862         }
1863     }
1864 
1865     /**
1866      * Start using the added RX filters.
1867      *
1868      * @param ifaceName Name of the interface.
1869      * @return true if request is sent successfully, false otherwise.
1870      */
startRxFilter(@onNull String ifaceName)1871     public boolean startRxFilter(@NonNull String ifaceName) {
1872         synchronized (mLock) {
1873             final String methodStr = "startRxFilter";
1874             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1875             if (iface == null) {
1876                 return false;
1877             }
1878             try {
1879                 iface.startRxFilter();
1880                 return true;
1881             } catch (RemoteException e) {
1882                 handleRemoteException(e, methodStr);
1883             } catch (ServiceSpecificException e) {
1884                 handleServiceSpecificException(e, methodStr);
1885             }
1886             return false;
1887         }
1888     }
1889 
1890     /**
1891      * Stop using the added RX filters.
1892      *
1893      * @param ifaceName Name of the interface.
1894      * @return true if request is sent successfully, false otherwise.
1895      */
stopRxFilter(@onNull String ifaceName)1896     public boolean stopRxFilter(@NonNull String ifaceName) {
1897         synchronized (mLock) {
1898             final String methodStr = "stopRxFilter";
1899             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1900             if (iface == null) {
1901                 return false;
1902             }
1903             try {
1904                 iface.stopRxFilter();
1905                 return true;
1906             } catch (RemoteException e) {
1907                 handleRemoteException(e, methodStr);
1908             } catch (ServiceSpecificException e) {
1909                 handleServiceSpecificException(e, methodStr);
1910             }
1911             return false;
1912         }
1913     }
1914 
1915     /**
1916      * Add an RX filter.
1917      *
1918      * @param ifaceName Name of the interface.
1919      * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1920      *        {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1921      * @return true if request is sent successfully, false otherwise.
1922      */
addRxFilter(@onNull String ifaceName, int type)1923     public boolean addRxFilter(@NonNull String ifaceName, int type) {
1924         synchronized (mLock) {
1925             byte halType;
1926             switch (type) {
1927                 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1928                     halType = RxFilterType.V4_MULTICAST;
1929                     break;
1930                 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1931                     halType = RxFilterType.V6_MULTICAST;
1932                     break;
1933                 default:
1934                     Log.e(TAG, "Invalid Rx Filter type: " + type);
1935                     return false;
1936             }
1937             return addRxFilter(ifaceName, halType);
1938         }
1939     }
1940 
addRxFilter(@onNull String ifaceName, byte type)1941     private boolean addRxFilter(@NonNull String ifaceName, byte type) {
1942         synchronized (mLock) {
1943             final String methodStr = "addRxFilter";
1944             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1945             if (iface == null) {
1946                 return false;
1947             }
1948             try {
1949                 iface.addRxFilter(type);
1950                 return true;
1951             } catch (RemoteException e) {
1952                 handleRemoteException(e, methodStr);
1953             } catch (ServiceSpecificException e) {
1954                 handleServiceSpecificException(e, methodStr);
1955             }
1956             return false;
1957         }
1958     }
1959 
1960     /**
1961      * Remove an RX filter.
1962      *
1963      * @param ifaceName Name of the interface.
1964      * @param type one of {@link WifiNative#RX_FILTER_TYPE_V4_MULTICAST}
1965      *        {@link WifiNative#RX_FILTER_TYPE_V6_MULTICAST} values.
1966      * @return true if request is sent successfully, false otherwise.
1967      */
removeRxFilter(@onNull String ifaceName, int type)1968     public boolean removeRxFilter(@NonNull String ifaceName, int type) {
1969         synchronized (mLock) {
1970             byte halType;
1971             switch (type) {
1972                 case WifiNative.RX_FILTER_TYPE_V4_MULTICAST:
1973                     halType = RxFilterType.V4_MULTICAST;
1974                     break;
1975                 case WifiNative.RX_FILTER_TYPE_V6_MULTICAST:
1976                     halType = RxFilterType.V6_MULTICAST;
1977                     break;
1978                 default:
1979                     Log.e(TAG, "Invalid Rx Filter type: " + type);
1980                     return false;
1981             }
1982             return removeRxFilter(ifaceName, halType);
1983         }
1984     }
1985 
removeRxFilter(@onNull String ifaceName, byte type)1986     private boolean removeRxFilter(@NonNull String ifaceName, byte type) {
1987         synchronized (mLock) {
1988             final String methodStr = "removeRxFilter";
1989             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
1990             if (iface == null) {
1991                 return false;
1992             }
1993             try {
1994                 iface.removeRxFilter(type);
1995                 return true;
1996             } catch (RemoteException e) {
1997                 handleRemoteException(e, methodStr);
1998             } catch (ServiceSpecificException e) {
1999                 handleServiceSpecificException(e, methodStr);
2000             }
2001             return false;
2002         }
2003     }
2004 
2005     /**
2006      * Set Bt co existense mode.
2007      *
2008      * @param ifaceName Name of the interface.
2009      * @param mode one of the above {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_DISABLED},
2010      *             {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_ENABLED} or
2011      *             {@link WifiNative#BLUETOOTH_COEXISTENCE_MODE_SENSE}.
2012      * @return true if request is sent successfully, false otherwise.
2013      */
setBtCoexistenceMode(@onNull String ifaceName, int mode)2014     public boolean setBtCoexistenceMode(@NonNull String ifaceName, int mode) {
2015         synchronized (mLock) {
2016             byte halMode;
2017             switch (mode) {
2018                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_ENABLED:
2019                     halMode = BtCoexistenceMode.ENABLED;
2020                     break;
2021                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_DISABLED:
2022                     halMode = BtCoexistenceMode.DISABLED;
2023                     break;
2024                 case WifiNative.BLUETOOTH_COEXISTENCE_MODE_SENSE:
2025                     halMode = BtCoexistenceMode.SENSE;
2026                     break;
2027                 default:
2028                     Log.e(TAG, "Invalid Bt Coex mode: " + mode);
2029                     return false;
2030             }
2031             return setBtCoexistenceMode(ifaceName, halMode);
2032         }
2033     }
2034 
setBtCoexistenceMode(@onNull String ifaceName, byte mode)2035     private boolean setBtCoexistenceMode(@NonNull String ifaceName, byte mode) {
2036         synchronized (mLock) {
2037             final String methodStr = "setBtCoexistenceMode";
2038             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2039             if (iface == null) {
2040                 return false;
2041             }
2042             try {
2043                 iface.setBtCoexistenceMode(mode);
2044                 return true;
2045             } catch (RemoteException e) {
2046                 handleRemoteException(e, methodStr);
2047             } catch (ServiceSpecificException e) {
2048                 handleServiceSpecificException(e, methodStr);
2049             }
2050             return false;
2051         }
2052     }
2053 
2054     /** Enable or disable BT coexistence mode.
2055      *
2056      * @param ifaceName Name of the interface.
2057      * @param enable true to enable, false to disable.
2058      * @return true if request is sent successfully, false otherwise.
2059      */
setBtCoexistenceScanModeEnabled(@onNull String ifaceName, boolean enable)2060     public boolean setBtCoexistenceScanModeEnabled(@NonNull String ifaceName, boolean enable) {
2061         synchronized (mLock) {
2062             final String methodStr = "setBtCoexistenceScanModeEnabled";
2063             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2064             if (iface == null) {
2065                 return false;
2066             }
2067             try {
2068                 iface.setBtCoexistenceScanModeEnabled(enable);
2069                 return true;
2070             } catch (RemoteException e) {
2071                 handleRemoteException(e, methodStr);
2072             } catch (ServiceSpecificException e) {
2073                 handleServiceSpecificException(e, methodStr);
2074             }
2075             return false;
2076         }
2077     }
2078 
2079     /**
2080      * Enable or disable suspend mode optimizations.
2081      *
2082      * @param ifaceName Name of the interface.
2083      * @param enable true to enable, false otherwise.
2084      * @return true if request is sent successfully, false otherwise.
2085      */
setSuspendModeEnabled(@onNull String ifaceName, boolean enable)2086     public boolean setSuspendModeEnabled(@NonNull String ifaceName, boolean enable) {
2087         synchronized (mLock) {
2088             final String methodStr = "setSuspendModeEnabled";
2089             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2090             if (iface == null) {
2091                 return false;
2092             }
2093             try {
2094                 iface.setSuspendModeEnabled(enable);
2095                 return true;
2096             } catch (RemoteException e) {
2097                 handleRemoteException(e, methodStr);
2098             } catch (ServiceSpecificException e) {
2099                 handleServiceSpecificException(e, methodStr);
2100             }
2101             return false;
2102         }
2103     }
2104 
2105     /**
2106      * Set country code.
2107      *
2108      * @param ifaceName Name of the interface.
2109      * @param codeStr 2 byte ASCII string. For ex: US, CA.
2110      * @return true if request is sent successfully, false otherwise.
2111      */
setCountryCode(@onNull String ifaceName, String codeStr)2112     public boolean setCountryCode(@NonNull String ifaceName, String codeStr) {
2113         synchronized (mLock) {
2114             if (TextUtils.isEmpty(codeStr)) {
2115                 return false;
2116             }
2117             byte[] countryCodeBytes = NativeUtil.stringToByteArray(codeStr);
2118             if (countryCodeBytes.length != 2) {
2119                 return false;
2120             }
2121             return setCountryCode(ifaceName, countryCodeBytes);
2122         }
2123     }
2124 
setCountryCode(@onNull String ifaceName, byte[ ] code)2125     private boolean setCountryCode(@NonNull String ifaceName, byte[/* 2 */] code) {
2126         synchronized (mLock) {
2127             final String methodStr = "setCountryCode";
2128             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2129             if (iface == null) {
2130                 return false;
2131             }
2132             try {
2133                 iface.setCountryCode(code);
2134                 return true;
2135             } catch (RemoteException e) {
2136                 handleRemoteException(e, methodStr);
2137             } catch (ServiceSpecificException e) {
2138                 handleServiceSpecificException(e, methodStr);
2139             }
2140             return false;
2141         }
2142     }
2143 
2144     /**
2145      * Flush all previously configured HLPs.
2146      *
2147      * @param ifaceName Name of the interface.
2148      * @return true if request is sent successfully, false otherwise.
2149      */
flushAllHlp(@onNull String ifaceName)2150     public boolean flushAllHlp(@NonNull String ifaceName) {
2151         synchronized (mLock) {
2152             final String methodStr = "filsHlpFlushRequest";
2153             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2154             if (iface == null) {
2155                 return false;
2156             }
2157             try {
2158                 iface.filsHlpFlushRequest();
2159                 return true;
2160             } catch (RemoteException e) {
2161                 handleRemoteException(e, methodStr);
2162             } catch (ServiceSpecificException e) {
2163                 handleServiceSpecificException(e, methodStr);
2164             }
2165             return false;
2166         }
2167     }
2168 
2169     /**
2170      * Set FILS HLP packet.
2171      *
2172      * @param ifaceName Name of the interface.
2173      * @param dst Destination MAC address.
2174      * @param hlpPacket Hlp Packet data in hex.
2175      * @return true if request is sent successfully, false otherwise.
2176      */
addHlpReq(@onNull String ifaceName, byte[] dst, byte[] hlpPacket)2177     public boolean addHlpReq(@NonNull String ifaceName, byte[] dst, byte[] hlpPacket) {
2178         synchronized (mLock) {
2179             final String methodStr = "filsHlpAddRequest";
2180             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2181             if (iface == null) {
2182                 return false;
2183             }
2184             try {
2185                 iface.filsHlpAddRequest(dst, hlpPacket);
2186                 return true;
2187             } catch (RemoteException e) {
2188                 handleRemoteException(e, methodStr);
2189             } catch (ServiceSpecificException e) {
2190                 handleServiceSpecificException(e, methodStr);
2191             }
2192             return false;
2193         }
2194     }
2195 
2196     /**
2197      * Start WPS pin registrar operation with the specified peer and pin.
2198      *
2199      * @param ifaceName Name of the interface.
2200      * @param bssidStr BSSID of the peer.
2201      * @param pin Pin to be used.
2202      * @return true if request is sent successfully, false otherwise.
2203      */
startWpsRegistrar(@onNull String ifaceName, String bssidStr, String pin)2204     public boolean startWpsRegistrar(@NonNull String ifaceName, String bssidStr, String pin) {
2205         synchronized (mLock) {
2206             if (TextUtils.isEmpty(bssidStr) || TextUtils.isEmpty(pin)) {
2207                 return false;
2208             }
2209             try {
2210                 return startWpsRegistrar(
2211                         ifaceName, NativeUtil.macAddressToByteArray(bssidStr), pin);
2212             } catch (IllegalArgumentException e) {
2213                 Log.e(TAG, "Illegal argument " + bssidStr, e);
2214                 return false;
2215             }
2216         }
2217     }
2218 
startWpsRegistrar(@onNull String ifaceName, byte[ ] bssid, String pin)2219     private boolean startWpsRegistrar(@NonNull String ifaceName, byte[/* 6 */] bssid, String pin) {
2220         synchronized (mLock) {
2221             final String methodStr = "startWpsRegistrar";
2222             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2223             if (iface == null) {
2224                 return false;
2225             }
2226             try {
2227                 iface.startWpsRegistrar(bssid, pin);
2228                 return true;
2229             } catch (RemoteException e) {
2230                 handleRemoteException(e, methodStr);
2231             } catch (ServiceSpecificException e) {
2232                 handleServiceSpecificException(e, methodStr);
2233             }
2234             return false;
2235         }
2236     }
2237 
2238     /**
2239      * Start WPS pin display operation with the specified peer.
2240      *
2241      * @param ifaceName Name of the interface.
2242      * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
2243      * @return true if request is sent successfully, false otherwise.
2244      */
startWpsPbc(@onNull String ifaceName, String bssidStr)2245     public boolean startWpsPbc(@NonNull String ifaceName, String bssidStr) {
2246         synchronized (mLock) {
2247             try {
2248                 return startWpsPbc(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
2249             } catch (IllegalArgumentException e) {
2250                 Log.e(TAG, "Illegal argument " + bssidStr, e);
2251                 return false;
2252             }
2253         }
2254     }
2255 
startWpsPbc(@onNull String ifaceName, byte[ ] bssid)2256     private boolean startWpsPbc(@NonNull String ifaceName, byte[/* 6 */] bssid) {
2257         synchronized (mLock) {
2258             final String methodStr = "startWpsPbc";
2259             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2260             if (iface == null) {
2261                 return false;
2262             }
2263             try {
2264                 iface.startWpsPbc(bssid);
2265                 return true;
2266             } catch (RemoteException e) {
2267                 handleRemoteException(e, methodStr);
2268             } catch (ServiceSpecificException e) {
2269                 handleServiceSpecificException(e, methodStr);
2270             }
2271             return false;
2272         }
2273     }
2274 
2275     /**
2276      * Start WPS pin keypad operation with the specified pin.
2277      *
2278      * @param ifaceName Name of the interface.
2279      * @param pin Pin to be used.
2280      * @return true if request is sent successfully, false otherwise.
2281      */
startWpsPinKeypad(@onNull String ifaceName, String pin)2282     public boolean startWpsPinKeypad(@NonNull String ifaceName, String pin) {
2283         if (TextUtils.isEmpty(pin)) {
2284             return false;
2285         }
2286         synchronized (mLock) {
2287             final String methodStr = "startWpsPinKeypad";
2288             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2289             if (iface == null) {
2290                 return false;
2291             }
2292             try {
2293                 iface.startWpsPinKeypad(pin);
2294                 return true;
2295             } catch (RemoteException e) {
2296                 handleRemoteException(e, methodStr);
2297             } catch (ServiceSpecificException e) {
2298                 handleServiceSpecificException(e, methodStr);
2299             }
2300             return false;
2301         }
2302     }
2303 
2304     /**
2305      * Start WPS pin display operation with the specified peer.
2306      *
2307      * @param ifaceName Name of the interface.
2308      * @param bssidStr BSSID of the peer. Use empty bssid to indicate wildcard.
2309      * @return new pin generated on success, null otherwise.
2310      */
startWpsPinDisplay(@onNull String ifaceName, String bssidStr)2311     public String startWpsPinDisplay(@NonNull String ifaceName, String bssidStr) {
2312         synchronized (mLock) {
2313             try {
2314                 return startWpsPinDisplay(ifaceName, NativeUtil.macAddressToByteArray(bssidStr));
2315             } catch (IllegalArgumentException e) {
2316                 Log.e(TAG, "Illegal argument " + bssidStr, e);
2317                 return null;
2318             }
2319         }
2320     }
2321 
startWpsPinDisplay(@onNull String ifaceName, byte[ ] bssid)2322     private String startWpsPinDisplay(@NonNull String ifaceName, byte[/* 6 */] bssid) {
2323         synchronized (mLock) {
2324             final String methodStr = "startWpsPinDisplay";
2325             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2326             if (iface == null) {
2327                 return null;
2328             }
2329             try {
2330                 return iface.startWpsPinDisplay(bssid);
2331             } catch (RemoteException e) {
2332                 handleRemoteException(e, methodStr);
2333             } catch (ServiceSpecificException e) {
2334                 handleServiceSpecificException(e, methodStr);
2335             }
2336             return null;
2337         }
2338     }
2339 
2340     /**
2341      * Cancels any ongoing WPS requests.
2342      *
2343      * @param ifaceName Name of the interface.
2344      * @return true if request is sent successfully, false otherwise.
2345      */
cancelWps(@onNull String ifaceName)2346     public boolean cancelWps(@NonNull String ifaceName) {
2347         synchronized (mLock) {
2348             final String methodStr = "cancelWps";
2349             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2350             if (iface == null) {
2351                 return false;
2352             }
2353             try {
2354                 iface.cancelWps();
2355                 return true;
2356             } catch (RemoteException e) {
2357                 handleRemoteException(e, methodStr);
2358             } catch (ServiceSpecificException e) {
2359                 handleServiceSpecificException(e, methodStr);
2360             }
2361             return false;
2362         }
2363     }
2364 
2365     /**
2366      * Sets whether to use external sim for SIM/USIM processing.
2367      *
2368      * @param ifaceName Name of the interface.
2369      * @param useExternalSim true to enable, false otherwise.
2370      * @return true if request is sent successfully, false otherwise.
2371      */
setExternalSim(@onNull String ifaceName, boolean useExternalSim)2372     public boolean setExternalSim(@NonNull String ifaceName, boolean useExternalSim) {
2373         synchronized (mLock) {
2374             final String methodStr = "setExternalSim";
2375             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2376             if (iface == null) {
2377                 return false;
2378             }
2379             try {
2380                 iface.setExternalSim(useExternalSim);
2381                 return true;
2382             } catch (RemoteException e) {
2383                 handleRemoteException(e, methodStr);
2384             } catch (ServiceSpecificException e) {
2385                 handleServiceSpecificException(e, methodStr);
2386             }
2387             return false;
2388         }
2389     }
2390 
2391     /**
2392      * Enable/Disable auto reconnect to networks.
2393      * Use this to prevent wpa_supplicant from trying to connect to networks
2394      * on its own.
2395      *
2396      * @param enable true to enable, false to disable.
2397      * @return true if no exceptions occurred, false otherwise
2398      */
enableAutoReconnect(@onNull String ifaceName, boolean enable)2399     public boolean enableAutoReconnect(@NonNull String ifaceName, boolean enable) {
2400         synchronized (mLock) {
2401             final String methodStr = "enableAutoReconnect";
2402             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2403             if (iface == null) {
2404                 return false;
2405             }
2406             try {
2407                 iface.enableAutoReconnect(enable);
2408                 return true;
2409             } catch (RemoteException e) {
2410                 handleRemoteException(e, methodStr);
2411             } catch (ServiceSpecificException e) {
2412                 handleServiceSpecificException(e, methodStr);
2413             }
2414             return false;
2415         }
2416     }
2417 
2418     /**
2419      * Set the debug log level for wpa_supplicant
2420      *
2421      * @param turnOnVerbose Whether to turn on verbose logging or not.
2422      * @return true if request is sent successfully, false otherwise.
2423      */
setLogLevel(boolean turnOnVerbose)2424     public boolean setLogLevel(boolean turnOnVerbose) {
2425         synchronized (mLock) {
2426             int logLevel = turnOnVerbose
2427                     ? DebugLevel.DEBUG
2428                     : DebugLevel.INFO;
2429             return setDebugParams(logLevel, false,
2430                     turnOnVerbose && mWifiGlobals.getShowKeyVerboseLoggingModeEnabled());
2431         }
2432     }
2433 
2434     /**
2435      * Set debug parameters for the ISupplicant service.
2436      *
2437      * @param level Debug logging level for the supplicant.
2438      *        (one of |DebugLevel| values).
2439      * @param showTimestamp Determines whether to show timestamps in logs or not.
2440      * @param showKeys Determines whether to show keys in debug logs or not.
2441      *        CAUTION: Do not set this param in production code!
2442      * @return true if no exceptions occurred, false otherwise
2443      */
setDebugParams(int level, boolean showTimestamp, boolean showKeys)2444     private boolean setDebugParams(int level, boolean showTimestamp, boolean showKeys) {
2445         synchronized (mLock) {
2446             final String methodStr = "setDebugParams";
2447             if (!checkSupplicantAndLogFailure(methodStr)) {
2448                 return false;
2449             }
2450             try {
2451                 mISupplicant.setDebugParams(level, showTimestamp, showKeys);
2452                 return true;
2453             } catch (RemoteException e) {
2454                 handleRemoteException(e, methodStr);
2455             } catch (ServiceSpecificException e) {
2456                 handleServiceSpecificException(e, methodStr);
2457             }
2458             return false;
2459         }
2460     }
2461 
2462     /**
2463      * Set concurrency priority between P2P & STA operations.
2464      *
2465      * @param isStaHigherPriority Set to true to prefer STA over P2P during concurrency operations,
2466      *                            false otherwise.
2467      * @return true if request is sent successfully, false otherwise.
2468      */
setConcurrencyPriority(boolean isStaHigherPriority)2469     public boolean setConcurrencyPriority(boolean isStaHigherPriority) {
2470         synchronized (mLock) {
2471             if (isStaHigherPriority) {
2472                 return setConcurrencyPriority(IfaceType.STA);
2473             } else {
2474                 return setConcurrencyPriority(IfaceType.P2P);
2475             }
2476         }
2477     }
2478 
setConcurrencyPriority(int type)2479     private boolean setConcurrencyPriority(int type) {
2480         synchronized (mLock) {
2481             final String methodStr = "setConcurrencyPriority";
2482             if (!checkSupplicantAndLogFailure(methodStr)) {
2483                 return false;
2484             }
2485             try {
2486                 mISupplicant.setConcurrencyPriority(type);
2487                 return true;
2488             } catch (RemoteException e) {
2489                 handleRemoteException(e, methodStr);
2490             } catch (ServiceSpecificException e) {
2491                 handleServiceSpecificException(e, methodStr);
2492             }
2493             return false;
2494         }
2495     }
2496 
2497     /**
2498      * Returns false if mISupplicant is null and logs failure message
2499      */
checkSupplicantAndLogFailure(final String methodStr)2500     private boolean checkSupplicantAndLogFailure(final String methodStr) {
2501         synchronized (mLock) {
2502             if (mISupplicant == null) {
2503                 Log.e(TAG, "Can't call " + methodStr + ", ISupplicant is null");
2504                 return false;
2505             }
2506             return true;
2507         }
2508     }
2509 
2510     /**
2511      * Returns specified STA iface if it exists. Otherwise, logs error and returns null.
2512      */
checkStaIfaceAndLogFailure( @onNull String ifaceName, final String methodStr)2513     private ISupplicantStaIface checkStaIfaceAndLogFailure(
2514             @NonNull String ifaceName, final String methodStr) {
2515         synchronized (mLock) {
2516             ISupplicantStaIface iface = getStaIface(ifaceName);
2517             if (iface == null) {
2518                 Log.e(TAG, "Can't call " + methodStr + ", ISupplicantStaIface is null for "
2519                         + "iface=" + ifaceName);
2520                 return null;
2521             }
2522             return iface;
2523         }
2524     }
2525 
2526     /**
2527      * Returns network belonging to the specified STA iface if it exists.
2528      * Otherwise, logs error and returns null.
2529      */
checkStaNetworkAndLogFailure( @onNull String ifaceName, final String methodStr)2530     private SupplicantStaNetworkHalAidlImpl checkStaNetworkAndLogFailure(
2531             @NonNull String ifaceName, final String methodStr) {
2532         synchronized (mLock) {
2533             SupplicantStaNetworkHalAidlImpl networkHandle =
2534                     getCurrentNetworkRemoteHandle(ifaceName);
2535             if (networkHandle == null) {
2536                 Log.e(TAG, "Can't call " + methodStr + ", SupplicantStaNetwork for iface="
2537                         + ifaceName + " is null.");
2538                 return null;
2539             }
2540             return networkHandle;
2541         }
2542     }
2543 
2544     /**
2545      * Helper function to log callback events
2546      */
logCallback(final String methodStr)2547     protected void logCallback(final String methodStr) {
2548         synchronized (mLock) {
2549             if (mVerboseLoggingEnabled) {
2550                 Log.d(TAG, "ISupplicantStaIfaceCallback." + methodStr + " received");
2551             }
2552         }
2553     }
2554 
handleRemoteException(RemoteException e, String methodStr)2555     private void handleRemoteException(RemoteException e, String methodStr) {
2556         synchronized (mLock) {
2557             clearState();
2558             Log.e(TAG,
2559                     "ISupplicantStaIface." + methodStr + " failed with remote exception: ", e);
2560         }
2561     }
2562 
handleServiceSpecificException(ServiceSpecificException e, String methodStr)2563     private void handleServiceSpecificException(ServiceSpecificException e, String methodStr) {
2564         synchronized (mLock) {
2565             Log.e(TAG, "ISupplicantStaIface." + methodStr + " failed with "
2566                     + "service specific exception: ", e);
2567         }
2568     }
2569 
2570     /**
2571      * Converts the Wps config method string to the equivalent enum value.
2572      */
stringToWpsConfigMethod(String configMethod)2573     private static int stringToWpsConfigMethod(String configMethod) {
2574         switch (configMethod) {
2575             case "usba":
2576                 return WpsConfigMethods.USBA;
2577             case "ethernet":
2578                 return WpsConfigMethods.ETHERNET;
2579             case "label":
2580                 return WpsConfigMethods.LABEL;
2581             case "display":
2582                 return WpsConfigMethods.DISPLAY;
2583             case "int_nfc_token":
2584                 return WpsConfigMethods.INT_NFC_TOKEN;
2585             case "ext_nfc_token":
2586                 return WpsConfigMethods.EXT_NFC_TOKEN;
2587             case "nfc_interface":
2588                 return WpsConfigMethods.NFC_INTERFACE;
2589             case "push_button":
2590                 return WpsConfigMethods.PUSHBUTTON;
2591             case "keypad":
2592                 return WpsConfigMethods.KEYPAD;
2593             case "virtual_push_button":
2594                 return WpsConfigMethods.VIRT_PUSHBUTTON;
2595             case "physical_push_button":
2596                 return WpsConfigMethods.PHY_PUSHBUTTON;
2597             case "p2ps":
2598                 return WpsConfigMethods.P2PS;
2599             case "virtual_display":
2600                 return WpsConfigMethods.VIRT_DISPLAY;
2601             case "physical_display":
2602                 return WpsConfigMethods.PHY_DISPLAY;
2603             default:
2604                 throw new IllegalArgumentException(
2605                         "Invalid WPS config method: " + configMethod);
2606         }
2607     }
2608 
addPmkCacheEntry(String ifaceName, int networkId, byte[ ] bssid, long expirationTimeInSec, ArrayList<Byte> serializedEntry)2609     protected void addPmkCacheEntry(String ifaceName, int networkId, byte[/* 6 */] bssid,
2610             long expirationTimeInSec, ArrayList<Byte> serializedEntry) {
2611         synchronized (mLock) {
2612             String macAddressStr = getMacAddress(ifaceName);
2613             try {
2614                 MacAddress bssAddr = bssid != null ? MacAddress.fromBytes(bssid) : null;
2615                 if (!mPmkCacheManager.add(MacAddress.fromString(macAddressStr), networkId,
2616                         bssAddr, expirationTimeInSec, serializedEntry)) {
2617                     Log.w(TAG, "Cannot add PMK cache for " + ifaceName);
2618                 }
2619             } catch (IllegalArgumentException ex) {
2620                 Log.w(TAG, "Cannot add PMK cache: " + ex);
2621             }
2622         }
2623     }
2624 
removePmkCacheEntry(int networkId)2625     protected void removePmkCacheEntry(int networkId) {
2626         synchronized (mLock) {
2627             mPmkCacheManager.remove(networkId);
2628         }
2629     }
2630 
2631     /**
2632      * See comments for {@link ISupplicantStaIfaceHal#getAdvancedCapabilities(String)}
2633      */
getAdvancedCapabilities(@onNull String ifaceName)2634     public @NonNull BitSet getAdvancedCapabilities(@NonNull String ifaceName) {
2635         synchronized (mLock) {
2636             final String methodStr = "getAdvancedCapabilities";
2637             BitSet advancedCapabilities = new BitSet();
2638             int keyMgmtCapabilities = getKeyMgmtCapabilities(ifaceName);
2639 
2640             advancedCapabilities.set(WIFI_FEATURE_PASSPOINT_TERMS_AND_CONDITIONS);
2641             advancedCapabilities.set(WIFI_FEATURE_DECORATED_IDENTITY);
2642             if (mVerboseLoggingEnabled) {
2643                 Log.v(TAG, methodStr + ": Passpoint T&C supported");
2644                 Log.v(TAG, methodStr + ": RFC 7542 decorated identity supported");
2645             }
2646 
2647             if ((keyMgmtCapabilities & KeyMgmtMask.SAE) != 0) {
2648                 advancedCapabilities.set(WIFI_FEATURE_WPA3_SAE);
2649 
2650                 if (mVerboseLoggingEnabled) {
2651                     Log.v(TAG, methodStr + ": SAE supported");
2652                 }
2653             }
2654 
2655             if ((keyMgmtCapabilities & KeyMgmtMask.SUITE_B_192) != 0) {
2656                 advancedCapabilities.set(WIFI_FEATURE_WPA3_SUITE_B);
2657 
2658                 if (mVerboseLoggingEnabled) {
2659                     Log.v(TAG, methodStr + ": SUITE_B supported");
2660                 }
2661             }
2662 
2663             if ((keyMgmtCapabilities & KeyMgmtMask.OWE) != 0) {
2664                 advancedCapabilities.set(WIFI_FEATURE_OWE);
2665 
2666                 if (mVerboseLoggingEnabled) {
2667                     Log.v(TAG, methodStr + ": OWE supported");
2668                 }
2669             }
2670 
2671             if ((keyMgmtCapabilities & KeyMgmtMask.DPP) != 0) {
2672                 advancedCapabilities.set(WIFI_FEATURE_DPP);
2673                 advancedCapabilities.set(WIFI_FEATURE_DPP_ENROLLEE_RESPONDER);
2674 
2675                 if (mVerboseLoggingEnabled) {
2676                     Log.v(TAG, methodStr + ": DPP supported");
2677                     Log.v(TAG, methodStr + ": DPP ENROLLEE RESPONDER supported");
2678                 }
2679             }
2680 
2681             if ((keyMgmtCapabilities & KeyMgmtMask.WAPI_PSK) != 0) {
2682                 advancedCapabilities.set(WIFI_FEATURE_WAPI);
2683 
2684                 if (mVerboseLoggingEnabled) {
2685                     Log.v(TAG, methodStr + ": WAPI supported");
2686                 }
2687             }
2688 
2689             if ((keyMgmtCapabilities & KeyMgmtMask.FILS_SHA256) != 0) {
2690                 advancedCapabilities.set(WIFI_FEATURE_FILS_SHA256);
2691 
2692                 if (mVerboseLoggingEnabled) {
2693                     Log.v(TAG, methodStr + ": FILS_SHA256 supported");
2694                 }
2695             }
2696 
2697             if ((keyMgmtCapabilities & KeyMgmtMask.FILS_SHA384) != 0) {
2698                 advancedCapabilities.set(WIFI_FEATURE_FILS_SHA384);
2699 
2700                 if (mVerboseLoggingEnabled) {
2701                     Log.v(TAG, methodStr + ": FILS_SHA384 supported");
2702                 }
2703             }
2704 
2705             if (mVerboseLoggingEnabled) {
2706                 Log.v(TAG, methodStr + ": Capability flags = " + keyMgmtCapabilities);
2707             }
2708 
2709             return advancedCapabilities;
2710         }
2711     }
2712 
2713     /**
2714      * Get the bitmask of supplicant/driver supported key management capabilities in
2715      * AIDL KeyMgmtMask format.
2716      */
getKeyMgmtCapabilities(@onNull String ifaceName)2717     private int getKeyMgmtCapabilities(@NonNull String ifaceName) {
2718         synchronized (mLock) {
2719             final String methodStr = "getKeyMgmtCapabilities";
2720             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2721             if (iface == null) {
2722                 return 0;
2723             }
2724             try {
2725                 return iface.getKeyMgmtCapabilities();
2726             } catch (RemoteException e) {
2727                 handleRemoteException(e, methodStr);
2728             } catch (ServiceSpecificException e) {
2729                 handleServiceSpecificException(e, methodStr);
2730             }
2731             return 0;
2732         }
2733     }
2734 
aidlWpaDrvFeatureSetToFrameworkV2(int drvCapabilitiesMask)2735     private BitSet aidlWpaDrvFeatureSetToFrameworkV2(int drvCapabilitiesMask) {
2736         if (!isServiceVersionAtLeast(2)) return new BitSet();
2737 
2738         final String methodStr = "getWpaDriverFeatureSetV2";
2739         BitSet featureSet = new BitSet();
2740 
2741         if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.SET_TLS_MINIMUM_VERSION) != 0) {
2742             featureSet.set(WIFI_FEATURE_SET_TLS_MINIMUM_VERSION);
2743             if (mVerboseLoggingEnabled) {
2744                 Log.v(TAG, methodStr + ": EAP-TLS minimum version supported");
2745             }
2746         }
2747 
2748         if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.TLS_V1_3) != 0) {
2749             featureSet.set(WIFI_FEATURE_TLS_V1_3);
2750             if (mVerboseLoggingEnabled) {
2751                 Log.v(TAG, methodStr + ": EAP-TLS v1.3 supported");
2752             }
2753         }
2754         return featureSet;
2755     }
2756 
2757     /**
2758      * See comments for {@link ISupplicantStaIfaceHal#getWpaDriverFeatureSet(String)}
2759      */
getWpaDriverFeatureSet(@onNull String ifaceName)2760     public @NonNull BitSet getWpaDriverFeatureSet(@NonNull String ifaceName) {
2761         synchronized (mLock) {
2762             final String methodStr = "getWpaDriverFeatureSet";
2763             int drvCapabilitiesMask = getWpaDriverCapabilities(ifaceName);
2764             BitSet featureSet = new BitSet();
2765 
2766             if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.MBO) != 0) {
2767                 featureSet.set(WIFI_FEATURE_MBO);
2768                 if (mVerboseLoggingEnabled) {
2769                     Log.v(TAG, methodStr + ": MBO supported");
2770                 }
2771                 if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.OCE) != 0) {
2772                     featureSet.set(WIFI_FEATURE_OCE);
2773                     if (mVerboseLoggingEnabled) {
2774                         Log.v(TAG, methodStr + ": OCE supported");
2775                     }
2776                 }
2777             }
2778 
2779             if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.SAE_PK) != 0) {
2780                 featureSet.set(WIFI_FEATURE_SAE_PK);
2781                 if (mVerboseLoggingEnabled) {
2782                     Log.v(TAG, methodStr + ": SAE-PK supported");
2783                 }
2784             }
2785 
2786             if ((drvCapabilitiesMask & WpaDriverCapabilitiesMask.WFD_R2) != 0) {
2787                 featureSet.set(WIFI_FEATURE_WFD_R2);
2788                 if (mVerboseLoggingEnabled) {
2789                     Log.v(TAG, methodStr + ": WFD-R2 supported");
2790                 }
2791             }
2792 
2793             if ((drvCapabilitiesMask
2794                     & WpaDriverCapabilitiesMask.TRUST_ON_FIRST_USE) != 0) {
2795                 featureSet.set(WIFI_FEATURE_TRUST_ON_FIRST_USE);
2796                 if (mVerboseLoggingEnabled) {
2797                     Log.v(TAG, methodStr + ": Trust-On-First-Use supported");
2798                 }
2799             }
2800 
2801             featureSet.or(aidlWpaDrvFeatureSetToFrameworkV2(drvCapabilitiesMask));
2802 
2803             return featureSet;
2804         }
2805     }
2806 
2807     /**
2808      * Returns true if this device supports RSN Overriding, false otherwise. Need service version
2809      * at least 4 or higher.
2810      */
isRsnOverridingSupported(@onNull String ifaceName)2811     public boolean isRsnOverridingSupported(@NonNull String ifaceName) {
2812         synchronized (mLock) {
2813             final String methodStr = "isRsnOverridingSupported";
2814             if (!isServiceVersionAtLeast(4)) {
2815                 return false;
2816             }
2817             int drvCapabilitiesMask = getWpaDriverCapabilities(ifaceName);
2818             boolean rsnOverridingSupported =
2819                     (drvCapabilitiesMask & WpaDriverCapabilitiesMask.RSN_OVERRIDING) != 0;
2820             if (mVerboseLoggingEnabled) {
2821                 Log.v(TAG, methodStr + ": RSN Overriding supported: "
2822                         + rsnOverridingSupported);
2823             }
2824             return rsnOverridingSupported;
2825         }
2826     }
2827 
2828     /**
2829      * Get the bitmask of supplicant/driver supported features in
2830      * AIDL WpaDriverCapabilitiesMask format.
2831      */
getWpaDriverCapabilities(@onNull String ifaceName)2832     private int getWpaDriverCapabilities(@NonNull String ifaceName) {
2833         synchronized (mLock) {
2834             final String methodStr = "getWpaDriverCapabilities";
2835             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
2836             if (iface == null) {
2837                 return 0;
2838             }
2839             try {
2840                 return iface.getWpaDriverCapabilities();
2841             } catch (RemoteException e) {
2842                 handleRemoteException(e, methodStr);
2843             } catch (ServiceSpecificException e) {
2844                 handleServiceSpecificException(e, methodStr);
2845             }
2846             return 0;
2847         }
2848     }
2849 
getWifiStandard(int technology)2850     private @WifiAnnotations.WifiStandard int getWifiStandard(int technology) {
2851         switch(technology) {
2852             case WifiTechnology.EHT:
2853                 return ScanResult.WIFI_STANDARD_11BE;
2854             case WifiTechnology.HE:
2855                 return ScanResult.WIFI_STANDARD_11AX;
2856             case WifiTechnology.VHT:
2857                 return ScanResult.WIFI_STANDARD_11AC;
2858             case WifiTechnology.HT:
2859                 return ScanResult.WIFI_STANDARD_11N;
2860             case WifiTechnology.LEGACY:
2861                 return ScanResult.WIFI_STANDARD_LEGACY;
2862             default:
2863                 return ScanResult.WIFI_STANDARD_UNKNOWN;
2864         }
2865     }
2866 
getChannelBandwidth(int channelBandwidth)2867     private int getChannelBandwidth(int channelBandwidth) {
2868         switch(channelBandwidth) {
2869             case WifiChannelWidthInMhz.WIDTH_20:
2870                 return ScanResult.CHANNEL_WIDTH_20MHZ;
2871             case WifiChannelWidthInMhz.WIDTH_40:
2872                 return ScanResult.CHANNEL_WIDTH_40MHZ;
2873             case WifiChannelWidthInMhz.WIDTH_80:
2874                 return ScanResult.CHANNEL_WIDTH_80MHZ;
2875             case WifiChannelWidthInMhz.WIDTH_160:
2876                 return ScanResult.CHANNEL_WIDTH_160MHZ;
2877             case WifiChannelWidthInMhz.WIDTH_80P80:
2878                 return ScanResult.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
2879             case WifiChannelWidthInMhz.WIDTH_320:
2880                 return ScanResult.CHANNEL_WIDTH_320MHZ;
2881             default:
2882                 return ScanResult.CHANNEL_WIDTH_20MHZ;
2883         }
2884     }
2885 
frameworkToAidlDppAkm(int dppAkm)2886     private int frameworkToAidlDppAkm(int dppAkm) {
2887         switch(dppAkm) {
2888             case SupplicantStaIfaceHal.DppAkm.PSK:
2889                 return DppAkm.PSK;
2890             case SupplicantStaIfaceHal.DppAkm.PSK_SAE:
2891                 return DppAkm.PSK_SAE;
2892             case SupplicantStaIfaceHal.DppAkm.SAE:
2893                 return DppAkm.SAE;
2894             case SupplicantStaIfaceHal.DppAkm.DPP:
2895                 return DppAkm.DPP;
2896             default:
2897                 Log.e(TAG, "Invalid DppAkm received");
2898                 return -1;
2899         }
2900     }
2901 
frameworkToAidlDppCurve(int dppCurve)2902     private int frameworkToAidlDppCurve(int dppCurve) {
2903         switch(dppCurve) {
2904             case SupplicantStaIfaceHal.DppCurve.PRIME256V1:
2905                 return DppCurve.PRIME256V1;
2906             case SupplicantStaIfaceHal.DppCurve.SECP384R1:
2907                 return DppCurve.SECP384R1;
2908             case SupplicantStaIfaceHal.DppCurve.SECP521R1:
2909                 return DppCurve.SECP521R1;
2910             case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP256R1:
2911                 return DppCurve.BRAINPOOLP256R1;
2912             case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP384R1:
2913                 return DppCurve.BRAINPOOLP384R1;
2914             case SupplicantStaIfaceHal.DppCurve.BRAINPOOLP512R1:
2915                 return DppCurve.BRAINPOOLP512R1;
2916             default:
2917                 Log.e(TAG, "Invalid DppCurve received");
2918                 return -1;
2919         }
2920     }
2921 
frameworkToAidlDppNetRole(int dppNetRole)2922     private int frameworkToAidlDppNetRole(int dppNetRole) {
2923         switch(dppNetRole) {
2924             case SupplicantStaIfaceHal.DppNetRole.STA:
2925                 return DppNetRole.STA;
2926             case SupplicantStaIfaceHal.DppNetRole.AP:
2927                 return DppNetRole.AP;
2928             default:
2929                 Log.e(TAG, "Invalid DppNetRole received");
2930                 return -1;
2931         }
2932     }
2933 
dscpPolicyToAidlQosPolicyStatusCode(int status)2934     protected byte dscpPolicyToAidlQosPolicyStatusCode(int status) {
2935         switch (status) {
2936             case NetworkAgent.DSCP_POLICY_STATUS_SUCCESS:
2937             case NetworkAgent.DSCP_POLICY_STATUS_DELETED:
2938                 return QosPolicyStatusCode.QOS_POLICY_SUCCESS;
2939             case NetworkAgent.DSCP_POLICY_STATUS_REQUEST_DECLINED:
2940                 return QosPolicyStatusCode.QOS_POLICY_REQUEST_DECLINED;
2941             case NetworkAgent.DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED:
2942                 return QosPolicyStatusCode.QOS_POLICY_CLASSIFIER_NOT_SUPPORTED;
2943             case NetworkAgent.DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES:
2944                 return QosPolicyStatusCode.QOS_POLICY_INSUFFICIENT_RESOURCES;
2945             default:
2946                 Log.e(TAG, "Invalid DSCP policy failure code received: " + status);
2947                 return QosPolicyStatusCode.QOS_POLICY_REQUEST_DECLINED;
2948         }
2949     }
2950 
halToFrameworkQosPolicyRequestType(byte requestType)2951     protected static int halToFrameworkQosPolicyRequestType(byte requestType) {
2952         switch (requestType) {
2953             case QosPolicyRequestType.QOS_POLICY_ADD:
2954                 return SupplicantStaIfaceHal.QOS_POLICY_REQUEST_ADD;
2955             case QosPolicyRequestType.QOS_POLICY_REMOVE:
2956                 return SupplicantStaIfaceHal.QOS_POLICY_REQUEST_REMOVE;
2957             default:
2958                 Log.e(TAG, "Invalid QosPolicyRequestType received: " + requestType);
2959                 return -1;
2960         }
2961     }
2962 
qosClassifierParamHasValue(int classifierParamMask, int paramBit)2963     private static boolean qosClassifierParamHasValue(int classifierParamMask, int paramBit) {
2964         return (classifierParamMask & paramBit) != 0;
2965     }
2966 
2967     /**
2968      * Convert from a HAL QosPolicyData object to a framework QosPolicy object.
2969      */
halToFrameworkQosPolicy( QosPolicyData halQosPolicy)2970     public static SupplicantStaIfaceHal.QosPolicyRequest halToFrameworkQosPolicy(
2971             QosPolicyData halQosPolicy) {
2972         QosPolicyClassifierParams classifierParams = halQosPolicy.classifierParams;
2973         int classifierParamMask = classifierParams.classifierParamMask;
2974 
2975         byte[] srcIp = null;
2976         byte[] dstIp = null;
2977         int srcPort = DscpPolicy.SOURCE_PORT_ANY;
2978         int[] dstPortRange = null;
2979         int protocol = DscpPolicy.PROTOCOL_ANY;
2980         boolean hasSrcIp = false;
2981         boolean hasDstIp = false;
2982 
2983         if (qosClassifierParamHasValue(classifierParamMask, QosPolicyClassifierParamsMask.SRC_IP)) {
2984             hasSrcIp = true;
2985             srcIp = classifierParams.srcIp;
2986         }
2987         if (qosClassifierParamHasValue(classifierParamMask, QosPolicyClassifierParamsMask.DST_IP)) {
2988             hasDstIp = true;
2989             dstIp = classifierParams.dstIp;
2990         }
2991         if (qosClassifierParamHasValue(classifierParamMask,
2992                 QosPolicyClassifierParamsMask.SRC_PORT)) {
2993             srcPort = classifierParams.srcPort;
2994         }
2995         if (qosClassifierParamHasValue(classifierParamMask,
2996                 QosPolicyClassifierParamsMask.DST_PORT_RANGE)) {
2997             dstPortRange = new int[2];
2998             dstPortRange[0] = classifierParams.dstPortRange.startPort;
2999             dstPortRange[1] = classifierParams.dstPortRange.endPort;
3000         }
3001         if (qosClassifierParamHasValue(classifierParamMask,
3002                 QosPolicyClassifierParamsMask.PROTOCOL_NEXT_HEADER)) {
3003             protocol = classifierParams.protocolNextHdr;
3004         }
3005 
3006         return new SupplicantStaIfaceHal.QosPolicyRequest(halQosPolicy.policyId,
3007                 halToFrameworkQosPolicyRequestType(halQosPolicy.requestType), halQosPolicy.dscp,
3008                 new SupplicantStaIfaceHal.QosPolicyClassifierParams(
3009                         hasSrcIp, srcIp, hasDstIp, dstIp, srcPort, dstPortRange, protocol));
3010     }
3011 
3012     @VisibleForTesting
frameworkToHalDeliveryRatio( @ndroid.net.wifi.QosCharacteristics.DeliveryRatio int frameworkRatio)3013     protected static byte frameworkToHalDeliveryRatio(
3014             @android.net.wifi.QosCharacteristics.DeliveryRatio int frameworkRatio) {
3015         switch (frameworkRatio) {
3016             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_95:
3017                 return DeliveryRatio.RATIO_95;
3018             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_96:
3019                 return DeliveryRatio.RATIO_96;
3020             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_97:
3021                 return DeliveryRatio.RATIO_97;
3022             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_98:
3023                 return DeliveryRatio.RATIO_98;
3024             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99:
3025                 return DeliveryRatio.RATIO_99;
3026             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_9:
3027                 return DeliveryRatio.RATIO_99_9;
3028             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_99:
3029                 return DeliveryRatio.RATIO_99_99;
3030             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_999:
3031                 return DeliveryRatio.RATIO_99_999;
3032             case android.net.wifi.QosCharacteristics.DELIVERY_RATIO_99_9999:
3033                 return DeliveryRatio.RATIO_99_9999;
3034             default:
3035                 Log.e(TAG, "Invalid delivery ratio received: " + frameworkRatio);
3036                 return DeliveryRatio.RATIO_95;
3037         }
3038     }
3039 
3040     @VisibleForTesting
frameworkToHalPolicyDirection( @osPolicyParams.Direction int frameworkDirection)3041     protected static byte frameworkToHalPolicyDirection(
3042             @QosPolicyParams.Direction int frameworkDirection) {
3043         switch (frameworkDirection) {
3044             case QosPolicyParams.DIRECTION_UPLINK:
3045                 return LinkDirection.UPLINK;
3046             case QosPolicyParams.DIRECTION_DOWNLINK:
3047                 return LinkDirection.DOWNLINK;
3048             default:
3049                 Log.e(TAG, "Invalid direction received: " + frameworkDirection);
3050                 return LinkDirection.DOWNLINK;
3051         }
3052     }
3053 
3054     /**
3055      * Convert from a framework QosCharacteristics to its HAL equivalent.
3056      */
3057     @VisibleForTesting
frameworkToHalQosCharacteristics( android.net.wifi.QosCharacteristics frameworkChars)3058     protected static QosCharacteristics frameworkToHalQosCharacteristics(
3059             android.net.wifi.QosCharacteristics frameworkChars) {
3060         QosCharacteristics halChars = new QosCharacteristics();
3061         halChars.minServiceIntervalUs = frameworkChars.getMinServiceIntervalMicros();
3062         halChars.maxServiceIntervalUs = frameworkChars.getMaxServiceIntervalMicros();
3063         halChars.minDataRateKbps = frameworkChars.getMinDataRateKbps();
3064         halChars.delayBoundUs = frameworkChars.getDelayBoundMicros();
3065 
3066         int optionalFieldMask = 0;
3067         if (frameworkChars.containsOptionalField(
3068                 android.net.wifi.QosCharacteristics.MAX_MSDU_SIZE)) {
3069             optionalFieldMask |= QosCharacteristicsMask.MAX_MSDU_SIZE;
3070             halChars.maxMsduSizeOctets = (char) frameworkChars.getMaxMsduSizeOctets();
3071         }
3072         if (frameworkChars.containsOptionalField(
3073                 android.net.wifi.QosCharacteristics.SERVICE_START_TIME)) {
3074             optionalFieldMask |= QosCharacteristicsMask.SERVICE_START_TIME;
3075             optionalFieldMask |= QosCharacteristicsMask.SERVICE_START_TIME_LINK_ID;
3076             halChars.serviceStartTimeUs = frameworkChars.getServiceStartTimeMicros();
3077             halChars.serviceStartTimeLinkId = (byte) frameworkChars.getServiceStartTimeLinkId();
3078         }
3079         if (frameworkChars.containsOptionalField(
3080                 android.net.wifi.QosCharacteristics.MEAN_DATA_RATE)) {
3081             optionalFieldMask |= QosCharacteristicsMask.MEAN_DATA_RATE;
3082             halChars.meanDataRateKbps = frameworkChars.getMeanDataRateKbps();
3083         }
3084         if (frameworkChars.containsOptionalField(
3085                 android.net.wifi.QosCharacteristics.BURST_SIZE)) {
3086             optionalFieldMask |= QosCharacteristicsMask.BURST_SIZE;
3087             halChars.burstSizeOctets = frameworkChars.getBurstSizeOctets();
3088         }
3089         if (frameworkChars.containsOptionalField(
3090                 android.net.wifi.QosCharacteristics.MSDU_LIFETIME)) {
3091             optionalFieldMask |= QosCharacteristicsMask.MSDU_LIFETIME;
3092             halChars.msduLifetimeMs = (char) frameworkChars.getMsduLifetimeMillis();
3093         }
3094         if (frameworkChars.containsOptionalField(
3095                 android.net.wifi.QosCharacteristics.MSDU_DELIVERY_INFO)) {
3096             optionalFieldMask |= QosCharacteristicsMask.MSDU_DELIVERY_INFO;
3097             MsduDeliveryInfo deliveryInfo = new MsduDeliveryInfo();
3098             deliveryInfo.deliveryRatio =
3099                     frameworkToHalDeliveryRatio(frameworkChars.getDeliveryRatio());
3100             deliveryInfo.countExponent = (byte) frameworkChars.getCountExponent();
3101             halChars.msduDeliveryInfo = deliveryInfo;
3102         }
3103 
3104         halChars.optionalFieldMask = optionalFieldMask;
3105         return halChars;
3106     }
3107 
3108     /**
3109      * Convert from a framework {@link QosPolicyParams} to a HAL QosPolicyScsData object.
3110      */
3111     @VisibleForTesting
frameworkToHalQosPolicyScsData(QosPolicyParams params)3112     protected QosPolicyScsData frameworkToHalQosPolicyScsData(QosPolicyParams params) {
3113         QosPolicyScsData halData = new QosPolicyScsData();
3114         halData.policyId = (byte) params.getTranslatedPolicyId();
3115         halData.userPriority = (byte) params.getUserPriority();
3116         QosPolicyClassifierParams classifierParams = new QosPolicyClassifierParams();
3117         int paramsMask = 0;
3118 
3119         classifierParams.srcIp = new byte[0];
3120         classifierParams.dstIp = new byte[0];
3121         classifierParams.dstPortRange = new PortRange();
3122         classifierParams.flowLabelIpv6 = new byte[0];
3123         classifierParams.domainName = "";
3124         classifierParams.ipVersion = params.getIpVersion() == QosPolicyParams.IP_VERSION_4
3125                 ? IpVersion.VERSION_4 : IpVersion.VERSION_6;
3126 
3127         if (params.getSourceAddress() != null) {
3128             paramsMask |= QosPolicyClassifierParamsMask.SRC_IP;
3129             classifierParams.srcIp = params.getSourceAddress().getAddress();
3130         }
3131         if (params.getDestinationAddress() != null) {
3132             paramsMask |= QosPolicyClassifierParamsMask.DST_IP;
3133             classifierParams.dstIp = params.getDestinationAddress().getAddress();
3134         }
3135         if (params.getSourcePort() != DscpPolicy.SOURCE_PORT_ANY) {
3136             paramsMask |= QosPolicyClassifierParamsMask.SRC_PORT;
3137             classifierParams.srcPort = params.getSourcePort();
3138         }
3139         if (params.getDestinationPortRange() != null) {
3140             paramsMask |= QosPolicyClassifierParamsMask.DST_PORT_RANGE;
3141             classifierParams.dstPortRange.startPort = params.getDestinationPortRange()[0];
3142             classifierParams.dstPortRange.endPort = params.getDestinationPortRange()[1];
3143         }
3144         if (params.getProtocol() != QosPolicyParams.PROTOCOL_ANY) {
3145             paramsMask |= QosPolicyClassifierParamsMask.PROTOCOL_NEXT_HEADER;
3146             classifierParams.protocolNextHdr = (byte) params.getProtocol();
3147         }
3148         if (params.getDscp() != QosPolicyParams.DSCP_ANY) {
3149             paramsMask |= QosPolicyClassifierParamsMask.DSCP;
3150             classifierParams.dscp = (byte) params.getDscp();
3151         }
3152         if (params.getFlowLabel() != null) {
3153             paramsMask |= QosPolicyClassifierParamsMask.FLOW_LABEL;
3154             classifierParams.flowLabelIpv6 = params.getFlowLabel();
3155         }
3156         if (SdkLevel.isAtLeastV() && isServiceVersionAtLeast(3)) {
3157             halData.direction = frameworkToHalPolicyDirection(params.getDirection());
3158             if (params.getQosCharacteristics() != null) {
3159                 halData.QosCharacteristics =
3160                         frameworkToHalQosCharacteristics(params.getQosCharacteristics());
3161             }
3162         }
3163 
3164         classifierParams.classifierParamMask = paramsMask;
3165         halData.classifierParams = classifierParams;
3166         return halData;
3167     }
3168 
frameworkToHalQosPolicyScsDataList( List<QosPolicyParams> frameworkPolicies)3169     private QosPolicyScsData[] frameworkToHalQosPolicyScsDataList(
3170             List<QosPolicyParams> frameworkPolicies) {
3171         QosPolicyScsData[] halDataList = new QosPolicyScsData[frameworkPolicies.size()];
3172         int index = 0;
3173         for (QosPolicyParams policy : frameworkPolicies) {
3174             halDataList[index] = frameworkToHalQosPolicyScsData(policy);
3175             index++;
3176         }
3177         return halDataList;
3178     }
3179 
3180     private static @SupplicantStaIfaceHal.QosPolicyScsRequestStatusCode int
halToFrameworkQosPolicyScsRequestStatusCode(int statusCode)3181             halToFrameworkQosPolicyScsRequestStatusCode(int statusCode) {
3182         switch (statusCode) {
3183             case QosPolicyScsRequestStatusCode.SENT:
3184                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_SENT;
3185             case QosPolicyScsRequestStatusCode.ALREADY_ACTIVE:
3186                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_ALREADY_ACTIVE;
3187             case QosPolicyScsRequestStatusCode.NOT_EXIST:
3188                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_NOT_EXIST;
3189             case QosPolicyScsRequestStatusCode.INVALID:
3190                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_INVALID;
3191             default:
3192                 Log.wtf(TAG, "Invalid QosPolicyScsRequestStatusCode: " + statusCode);
3193                 return SupplicantStaIfaceHal.QOS_POLICY_SCS_REQUEST_STATUS_ERROR_UNKNOWN;
3194         }
3195     }
3196 
3197     private static List<SupplicantStaIfaceHal.QosPolicyStatus>
halToFrameworkQosPolicyScsRequestStatusList(QosPolicyScsRequestStatus[] halStatusList)3198             halToFrameworkQosPolicyScsRequestStatusList(QosPolicyScsRequestStatus[] halStatusList) {
3199         List<SupplicantStaIfaceHal.QosPolicyStatus> frameworkStatusList = new ArrayList<>();
3200         for (QosPolicyScsRequestStatus halStatus : halStatusList) {
3201             frameworkStatusList.add(new SupplicantStaIfaceHal.QosPolicyStatus(
3202                     halStatus.policyId,
3203                     halToFrameworkQosPolicyScsRequestStatusCode(
3204                             halStatus.qosPolicyScsRequestStatusCode)));
3205         }
3206         return frameworkStatusList;
3207     }
3208 
3209     /**
3210      * Returns connection capabilities of the current network
3211      *
3212      * @param ifaceName Name of the interface.
3213      * @return connection capabilities of the current network
3214      */
getConnectionCapabilities(@onNull String ifaceName)3215     public WifiNative.ConnectionCapabilities getConnectionCapabilities(@NonNull String ifaceName) {
3216         synchronized (mLock) {
3217             final String methodStr = "getConnectionCapabilities";
3218             WifiNative.ConnectionCapabilities capOut = new WifiNative.ConnectionCapabilities();
3219             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3220             if (iface == null) {
3221                 return capOut;
3222             }
3223             try {
3224                 ConnectionCapabilities cap = iface.getConnectionCapabilities();
3225                 capOut.wifiStandard = getWifiStandard(cap.technology);
3226                 capOut.channelBandwidth = getChannelBandwidth(cap.channelBandwidth);
3227                 capOut.is11bMode = (cap.legacyMode == LegacyMode.B_MODE);
3228                 capOut.maxNumberTxSpatialStreams = cap.maxNumberTxSpatialStreams;
3229                 capOut.maxNumberRxSpatialStreams = cap.maxNumberRxSpatialStreams;
3230                 capOut.apTidToLinkMapNegotiationSupported = cap.apTidToLinkMapNegotiationSupported;
3231                 if (isServiceVersionAtLeast(3) && cap.vendorData != null) {
3232                     capOut.vendorData = HalAidlUtil.halToFrameworkOuiKeyedDataList(cap.vendorData);
3233                 }
3234                 return capOut;
3235             } catch (RemoteException e) {
3236                 handleRemoteException(e, methodStr);
3237             } catch (ServiceSpecificException e) {
3238                 handleServiceSpecificException(e, methodStr);
3239             }
3240             return capOut;
3241         }
3242     }
3243 
3244     /**
3245      * Returns signal poll results for all Wi-Fi links of the interface. Need service version at
3246      * least 2 or higher.
3247      *
3248      * @param ifaceName Name of the interface.
3249      * @return Signal poll results or null if error.
3250      */
getSignalPollResults(@onNull String ifaceName)3251     public WifiSignalPollResults getSignalPollResults(@NonNull String ifaceName) {
3252         if (!isServiceVersionAtLeast(2)) return null;
3253         synchronized (mLock) {
3254             final String methodStr = "getSignalPollResult";
3255             ISupplicantStaIface iface;
3256             if (mWifiInjector.getMockWifiServiceUtil() != null
3257                     && mWifiInjector.getMockWifiServiceUtil().isMethodConfigured(
3258                         MockWifiServiceUtil.MOCK_SUPPLICANT_SERVICE, ISUPPLICANTSTAIFACE
3259                             + MockWifiServiceUtil.AIDL_METHOD_IDENTIFIER
3260                                 + "getSignalPollResults")) {
3261                 iface = mWifiInjector.getMockWifiServiceUtil().getMockSupplicantManager()
3262                         .getMockSupplicantStaIface(ifaceName);
3263             } else {
3264                 iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3265             }
3266             if (iface == null) {
3267                 return null;
3268             }
3269             try {
3270                 SignalPollResult[] halSignalPollResults = iface.getSignalPollResults();
3271                 if (halSignalPollResults == null) {
3272                     return null;
3273                 }
3274                 WifiSignalPollResults nativeSignalPollResults =
3275                         new WifiSignalPollResults();
3276                 for (SignalPollResult r : halSignalPollResults) {
3277                     nativeSignalPollResults.addEntry(r.linkId, r.currentRssiDbm, r.txBitrateMbps,
3278                             r.rxBitrateMbps, r.frequencyMhz);
3279                 }
3280                 return nativeSignalPollResults;
3281             } catch (RemoteException e) {
3282                 handleRemoteException(e, methodStr);
3283             } catch (ServiceSpecificException e) {
3284                 handleServiceSpecificException(e, methodStr);
3285             }
3286             return null;
3287         }
3288     }
3289 
3290     /**
3291      * Returns connection MLO links info
3292      *
3293      * @param ifaceName Name of the interface.
3294      * @return connection MLO links info
3295      */
getConnectionMloLinksInfo(@onNull String ifaceName)3296     public WifiNative.ConnectionMloLinksInfo getConnectionMloLinksInfo(@NonNull String ifaceName) {
3297         synchronized (mLock) {
3298             final String methodStr = "getConnectionMloLinksInfo";
3299             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3300             if (iface == null) {
3301                 return null;
3302             }
3303             try {
3304                 MloLinksInfo halInfo = iface.getConnectionMloLinksInfo();
3305                 if (halInfo == null) {
3306                     return null;
3307                 }
3308 
3309                 WifiNative.ConnectionMloLinksInfo nativeInfo =
3310                         new WifiNative.ConnectionMloLinksInfo();
3311 
3312                 // The parameter 'apMldMacAddress' can come as null.
3313                 if (halInfo.apMldMacAddress != null) {
3314                     nativeInfo.apMldMacAddress = MacAddress.fromBytes(halInfo.apMldMacAddress);
3315                 }
3316                 nativeInfo.apMloLinkId = halInfo.apMloLinkId;
3317                 nativeInfo.links = new WifiNative.ConnectionMloLink[halInfo.links.length];
3318 
3319                 for (int i = 0; i < halInfo.links.length; i++) {
3320                     // The parameter 'apLinkMacAddress' can come as null.
3321                     nativeInfo.links[i] = new WifiNative.ConnectionMloLink(
3322                             halInfo.links[i].linkId,
3323                             MacAddress.fromBytes(halInfo.links[i].staLinkMacAddress),
3324                             (halInfo.links[i].apLinkMacAddress != null) ? MacAddress.fromBytes(
3325                                     halInfo.links[i].apLinkMacAddress) : null,
3326                             halInfo.links[i].tidsUplinkMap, halInfo.links[i].tidsDownlinkMap,
3327                             halInfo.links[i].frequencyMHz);
3328                 }
3329                 return nativeInfo;
3330             } catch (RemoteException e) {
3331                 handleRemoteException(e, methodStr);
3332             } catch (ServiceSpecificException e) {
3333                 handleServiceSpecificException(e, methodStr);
3334             } catch (IllegalArgumentException e) {
3335                 Log.e(TAG, "Invalid STA Mac Address received from HAL");
3336                 return null;
3337             }
3338 
3339             return null;
3340         }
3341     }
3342 
3343     /**
3344      * Adds a DPP peer URI to the URI list.
3345      *
3346      * Returns an ID to be used later to refer to this URI (>0).
3347      * On error, -1 is returned.
3348      */
addDppPeerUri(@onNull String ifaceName, @NonNull String uri)3349     public int addDppPeerUri(@NonNull String ifaceName, @NonNull String uri) {
3350         synchronized (mLock) {
3351             final String methodStr = "addDppPeerUri";
3352             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3353             if (iface == null) {
3354                 return -1;
3355             }
3356             try {
3357                 return iface.addDppPeerUri(uri);
3358             } catch (RemoteException e) {
3359                 handleRemoteException(e, methodStr);
3360             } catch (ServiceSpecificException e) {
3361                 handleServiceSpecificException(e, methodStr);
3362             }
3363             return -1;
3364         }
3365     }
3366 
3367     /**
3368      * Removes a DPP URI to the URI list given an ID.
3369      *
3370      * Returns true when operation is successful
3371      * On error, false is returned.
3372      */
removeDppUri(@onNull String ifaceName, int bootstrapId)3373     public boolean removeDppUri(@NonNull String ifaceName, int bootstrapId)  {
3374         synchronized (mLock) {
3375             final String methodStr = "removeDppUri";
3376             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3377             if (iface == null) {
3378                 return false;
3379             }
3380             try {
3381                 iface.removeDppUri(bootstrapId);
3382                 return true;
3383             } catch (RemoteException e) {
3384                 handleRemoteException(e, methodStr);
3385             } catch (ServiceSpecificException e) {
3386                 handleServiceSpecificException(e, methodStr);
3387             }
3388             return false;
3389         }
3390     }
3391 
3392     /**
3393      * Stops/aborts DPP Initiator request
3394      *
3395      * Returns true when operation is successful
3396      * On error, false is returned.
3397      */
stopDppInitiator(@onNull String ifaceName)3398     public boolean stopDppInitiator(@NonNull String ifaceName)  {
3399         synchronized (mLock) {
3400             final String methodStr = "stopDppInitiator";
3401             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3402             if (iface == null) {
3403                 return false;
3404             }
3405             try {
3406                 iface.stopDppInitiator();
3407                 return true;
3408             } catch (RemoteException e) {
3409                 handleRemoteException(e, methodStr);
3410             } catch (ServiceSpecificException e) {
3411                 handleServiceSpecificException(e, methodStr);
3412             }
3413             return false;
3414         }
3415     }
3416 
3417     /**
3418      * Starts DPP Configurator-Initiator request
3419      *
3420      * Returns true when operation is successful
3421      * On error, false is returned.
3422      */
startDppConfiguratorInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId, @NonNull String ssid, String password, String psk, int netRole, int securityAkm, byte[] privEcKey)3423     public boolean startDppConfiguratorInitiator(@NonNull String ifaceName, int peerBootstrapId,
3424             int ownBootstrapId, @NonNull String ssid, String password, String psk,
3425             int netRole, int securityAkm, byte[] privEcKey)  {
3426         synchronized (mLock) {
3427             final String methodStr = "startDppConfiguratorInitiator";
3428             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3429             if (iface == null) {
3430                 return false;
3431             }
3432             try {
3433                 byte[] key = iface.startDppConfiguratorInitiator(peerBootstrapId, ownBootstrapId,
3434                         ssid, password != null ? password : "", psk != null ? psk : "",
3435                         frameworkToAidlDppNetRole(netRole), frameworkToAidlDppAkm(securityAkm),
3436                         privEcKey != null ? privEcKey : new byte[] {});
3437                 if (key != null && key.length > 0 && mDppCallback != null) {
3438                     mDppCallback.onDppConfiguratorKeyUpdate(key);
3439                 }
3440                 return true;
3441             } catch (RemoteException e) {
3442                 handleRemoteException(e, methodStr);
3443             } catch (ServiceSpecificException e) {
3444                 handleServiceSpecificException(e, methodStr);
3445             }
3446             return false;
3447         }
3448     }
3449 
3450     /**
3451      * Starts DPP Enrollee-Initiator request
3452      *
3453      * Returns true when operation is successful
3454      * On error, false is returned.
3455      */
startDppEnrolleeInitiator(@onNull String ifaceName, int peerBootstrapId, int ownBootstrapId)3456     public boolean startDppEnrolleeInitiator(@NonNull String ifaceName, int peerBootstrapId,
3457             int ownBootstrapId)  {
3458         synchronized (mLock) {
3459             final String methodStr = "startDppEnrolleeInitiator";
3460             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3461             if (iface == null) {
3462                 return false;
3463             }
3464             try {
3465                 iface.startDppEnrolleeInitiator(peerBootstrapId, ownBootstrapId);
3466                 return true;
3467             } catch (RemoteException e) {
3468                 handleRemoteException(e, methodStr);
3469             } catch (ServiceSpecificException e) {
3470                 handleServiceSpecificException(e, methodStr);
3471             }
3472             return false;
3473         }
3474     }
3475 
3476     /**
3477      * Generate a DPP QR code based boot strap info
3478      *
3479      * Returns DppResponderBootstrapInfo;
3480      */
generateDppBootstrapInfoForResponder( @onNull String ifaceName, String macAddress, @NonNull String deviceInfo, int dppCurve)3481     public WifiNative.DppBootstrapQrCodeInfo generateDppBootstrapInfoForResponder(
3482             @NonNull String ifaceName, String macAddress, @NonNull String deviceInfo,
3483             int dppCurve) {
3484         synchronized (mLock) {
3485             final String methodStr = "generateDppBootstrapInfoForResponder";
3486             WifiNative.DppBootstrapQrCodeInfo bootstrapInfoOut =
3487                     new WifiNative.DppBootstrapQrCodeInfo();
3488             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3489             if (iface == null) {
3490                 return bootstrapInfoOut;
3491             }
3492             try {
3493                 DppResponderBootstrapInfo info = iface.generateDppBootstrapInfoForResponder(
3494                         NativeUtil.macAddressToByteArray(macAddress), deviceInfo,
3495                         frameworkToAidlDppCurve(dppCurve));
3496                 bootstrapInfoOut.bootstrapId = info.bootstrapId;
3497                 bootstrapInfoOut.listenChannel = info.listenChannel;
3498                 bootstrapInfoOut.uri = info.uri;
3499                 return bootstrapInfoOut;
3500             } catch (RemoteException e) {
3501                 handleRemoteException(e, methodStr);
3502             } catch (ServiceSpecificException e) {
3503                 handleServiceSpecificException(e, methodStr);
3504             }
3505             return bootstrapInfoOut;
3506         }
3507     }
3508 
3509     /**
3510      * Starts DPP Enrollee-Responder request
3511      *
3512      * Returns true when operation is successful
3513      * On error, false is returned.
3514      */
startDppEnrolleeResponder(@onNull String ifaceName, int listenChannel)3515     public boolean startDppEnrolleeResponder(@NonNull String ifaceName, int listenChannel) {
3516         synchronized (mLock) {
3517             final String methodStr = "startDppEnrolleeResponder";
3518             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3519             if (iface == null) {
3520                 return false;
3521             }
3522             try {
3523                 iface.startDppEnrolleeResponder(listenChannel);
3524                 return true;
3525             } catch (RemoteException e) {
3526                 handleRemoteException(e, methodStr);
3527             } catch (ServiceSpecificException e) {
3528                 handleServiceSpecificException(e, methodStr);
3529             }
3530             return false;
3531         }
3532     }
3533 
3534     /**
3535      * Stops/aborts DPP Responder request.
3536      *
3537      * Returns true when operation is successful
3538      * On error, false is returned.
3539      */
stopDppResponder(@onNull String ifaceName, int ownBootstrapId)3540     public boolean stopDppResponder(@NonNull String ifaceName, int ownBootstrapId)  {
3541         synchronized (mLock) {
3542             final String methodStr = "stopDppResponder";
3543             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3544             if (iface == null) {
3545                 return false;
3546             }
3547             try {
3548                 iface.stopDppResponder(ownBootstrapId);
3549                 return true;
3550             } catch (RemoteException e) {
3551                 handleRemoteException(e, methodStr);
3552             } catch (ServiceSpecificException e) {
3553                 handleServiceSpecificException(e, methodStr);
3554             }
3555             return false;
3556         }
3557     }
3558 
3559     /**
3560      * Register callbacks for DPP events.
3561      *
3562      * @param dppCallback DPP callback object.
3563      */
registerDppCallback(WifiNative.DppEventCallback dppCallback)3564     public void registerDppCallback(WifiNative.DppEventCallback dppCallback) {
3565         synchronized (mLock) {
3566             mDppCallback = dppCallback;
3567         }
3568     }
3569 
getDppCallback()3570     protected WifiNative.DppEventCallback getDppCallback() {
3571         synchronized (mLock) {
3572             return mDppCallback;
3573         }
3574     }
3575 
3576     /**
3577      * Set MBO cellular data availability.
3578      *
3579      * @param ifaceName Name of the interface.
3580      * @param available true means cellular data available, false otherwise.
3581      * @return true is operation is successful, false otherwise.
3582      */
setMboCellularDataStatus(@onNull String ifaceName, boolean available)3583     public boolean setMboCellularDataStatus(@NonNull String ifaceName, boolean available) {
3584         synchronized (mLock) {
3585             final String methodStr = "setMboCellularDataStatus";
3586             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3587             if (iface == null) {
3588                 return false;
3589             }
3590             try {
3591                 iface.setMboCellularDataStatus(available);
3592                 return true;
3593             } catch (RemoteException e) {
3594                 handleRemoteException(e, methodStr);
3595             } catch (ServiceSpecificException e) {
3596                 handleServiceSpecificException(e, methodStr);
3597             }
3598             return false;
3599         }
3600     }
3601 
3602     /**
3603      * Set whether the network-centric QoS policy feature is enabled or not for this interface.
3604      *
3605      * @param ifaceName name of the interface.
3606      * @param isEnabled true if feature is enabled, false otherwise.
3607      * @return true if operation is successful, false otherwise.
3608      */
setNetworkCentricQosPolicyFeatureEnabled(@onNull String ifaceName, boolean isEnabled)3609     public boolean setNetworkCentricQosPolicyFeatureEnabled(@NonNull String ifaceName,
3610             boolean isEnabled) {
3611         synchronized (mLock) {
3612             String methodStr = "setNetworkCentricQosPolicyFeatureEnabled";
3613             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3614             if (iface == null) {
3615                 return false;
3616             }
3617             try {
3618                 iface.setQosPolicyFeatureEnabled(isEnabled);
3619                 return true;
3620             } catch (RemoteException e) {
3621                 handleRemoteException(e, methodStr);
3622             } catch (ServiceSpecificException e) {
3623                 handleServiceSpecificException(e, methodStr);
3624             }
3625             return false;
3626         }
3627     }
3628 
3629     /**
3630      * Check if we've roamed to a linked network and make the linked network the current network
3631      * if we have.
3632      *
3633      * @param ifaceName Name of the interface.
3634      * @param newNetworkId Network id of the new network we've roamed to. If fromFramework is
3635      *                     {@code true}, this will be a framework network id. Otherwise, this will
3636      *                     be a remote network id.
3637      * @param fromFramework {@code true} if the network id is a framework network id, {@code false}
3638                             if the network id is a remote network id.
3639      * @return true if we've roamed to a linked network, false if not.
3640      */
updateOnLinkedNetworkRoaming( @onNull String ifaceName, int newNetworkId, boolean fromFramework)3641     public boolean updateOnLinkedNetworkRoaming(
3642             @NonNull String ifaceName, int newNetworkId, boolean fromFramework) {
3643         synchronized (mLock) {
3644             List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>> linkedNetworkHandles =
3645                     mLinkedNetworkLocalAndRemoteConfigs.get(ifaceName);
3646             SupplicantStaNetworkHalAidlImpl currentHandle =
3647                     getCurrentNetworkRemoteHandle(ifaceName);
3648             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3649             if (linkedNetworkHandles == null || currentHandle == null || currentConfig == null) {
3650                 return false;
3651             }
3652             if (fromFramework ? currentConfig.networkId == newNetworkId
3653                     : currentHandle.getNetworkId() == newNetworkId) {
3654                 return false;
3655             }
3656             for (Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair
3657                     : linkedNetworkHandles) {
3658                 if (fromFramework ? pair.second.networkId == newNetworkId
3659                         : pair.first.getNetworkId() == newNetworkId) {
3660                     Log.i(TAG, "Roamed to linked network, make linked network as current network");
3661                     mCurrentNetworkRemoteHandles.put(ifaceName, pair.first);
3662                     mCurrentNetworkLocalConfigs.put(ifaceName, pair.second);
3663                     return true;
3664                 }
3665             }
3666             return false;
3667         }
3668     }
3669 
3670     /**
3671      * Updates the linked networks for the current network and sends them to the supplicant.
3672      *
3673      * @param ifaceName Name of the interface.
3674      * @param networkId Network id of the network to link the configurations to.
3675      * @param linkedConfigurations Map of config profile key to config for linking.
3676      * @return true if networks were successfully linked, false otherwise.
3677      */
updateLinkedNetworks(@onNull String ifaceName, int networkId, Map<String, WifiConfiguration> linkedConfigurations)3678     public boolean updateLinkedNetworks(@NonNull String ifaceName, int networkId,
3679             Map<String, WifiConfiguration> linkedConfigurations) {
3680         synchronized (mLock) {
3681             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3682             SupplicantStaNetworkHalAidlImpl currentHandle =
3683                     getCurrentNetworkRemoteHandle(ifaceName);
3684 
3685             if (currentConfig == null || currentHandle == null) {
3686                 Log.e(TAG, "current network not configured yet.");
3687                 return false;
3688             }
3689 
3690             if (networkId != currentConfig.networkId) {
3691                 Log.e(TAG, "current config network id is not matching");
3692                 return false;
3693             }
3694 
3695             final int remoteNetworkId = currentHandle.getNetworkId();
3696             if (remoteNetworkId == -1) {
3697                 Log.e(TAG, "current handle getNetworkId failed");
3698                 return false;
3699             }
3700 
3701             if (!removeAllNetworksExcept(ifaceName, remoteNetworkId)) {
3702                 Log.e(TAG, "couldn't remove non-current supplicant networks");
3703                 return false;
3704             }
3705 
3706             mLinkedNetworkLocalAndRemoteConfigs.remove(ifaceName);
3707 
3708             if (linkedConfigurations == null || linkedConfigurations.size() == 0) {
3709                 Log.i(TAG, "cleared linked networks");
3710                 return true;
3711             }
3712 
3713             List<Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration>> linkedNetworkHandles =
3714                     new ArrayList<>();
3715             linkedNetworkHandles.add(new Pair(currentHandle, currentConfig));
3716             for (String linkedNetwork : linkedConfigurations.keySet()) {
3717                 Log.i(TAG, "add linked network: " + linkedNetwork);
3718                 Pair<SupplicantStaNetworkHalAidlImpl, WifiConfiguration> pair =
3719                         addNetworkAndSaveConfig(ifaceName, linkedConfigurations.get(linkedNetwork));
3720                 if (pair == null) {
3721                     Log.e(TAG, "failed to add/save linked network: " + linkedNetwork);
3722                     return false;
3723                 }
3724                 pair.first.enable(true);
3725                 linkedNetworkHandles.add(pair);
3726             }
3727 
3728             mLinkedNetworkLocalAndRemoteConfigs.put(ifaceName, linkedNetworkHandles);
3729 
3730             return true;
3731         }
3732     }
3733 
3734     /**
3735      * Remove all networks except the supplied network ID from supplicant
3736      *
3737      * @param ifaceName Name of the interface
3738      * @param networkId network id to keep
3739      */
removeAllNetworksExcept(@onNull String ifaceName, int networkId)3740     private boolean removeAllNetworksExcept(@NonNull String ifaceName, int networkId) {
3741         synchronized (mLock) {
3742             int[] networks = listNetworks(ifaceName);
3743             if (networks == null) {
3744                 Log.e(TAG, "removeAllNetworksExcept failed, got null networks");
3745                 return false;
3746             }
3747             for (int id : networks) {
3748                 if (networkId == id) {
3749                     continue;
3750                 }
3751                 if (!removeNetwork(ifaceName, id)) {
3752                     Log.e(TAG, "removeAllNetworksExcept failed to remove network: " + id);
3753                     return false;
3754                 }
3755             }
3756             return true;
3757         }
3758     }
3759 
3760     /**
3761      * Gets the security params of the current network associated with this interface
3762      *
3763      * @param ifaceName Name of the interface
3764      * @return Security params of the current network associated with the interface
3765      */
getCurrentNetworkSecurityParams(@onNull String ifaceName)3766     public SecurityParams getCurrentNetworkSecurityParams(@NonNull String ifaceName) {
3767         WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3768 
3769         if (currentConfig == null) {
3770             return null;
3771         }
3772 
3773         return currentConfig.getNetworkSelectionStatus().getCandidateSecurityParams();
3774     }
3775 
3776     /**
3777      * Sends a QoS policy response.
3778      *
3779      * @param ifaceName Name of the interface.
3780      * @param qosPolicyRequestId Dialog token to identify the request.
3781      * @param morePolicies Flag to indicate more QoS policies can be accommodated.
3782      * @param qosPolicyStatusList List of framework QosPolicyStatus objects.
3783      * @return true if response is sent successfully, false otherwise.
3784      */
sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId, boolean morePolicies, @NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList)3785     public boolean sendQosPolicyResponse(String ifaceName, int qosPolicyRequestId,
3786             boolean morePolicies,
3787             @NonNull List<SupplicantStaIfaceHal.QosPolicyStatus> qosPolicyStatusList) {
3788         synchronized (mLock) {
3789             final String methodStr = "sendQosPolicyResponse";
3790             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3791             if (iface == null) {
3792                 return false;
3793             }
3794 
3795             int index = 0;
3796             QosPolicyStatus[] halPolicyStatusList = new QosPolicyStatus[qosPolicyStatusList.size()];
3797             for (SupplicantStaIfaceHal.QosPolicyStatus frameworkPolicyStatus
3798                     : qosPolicyStatusList) {
3799                 if (frameworkPolicyStatus == null) {
3800                     return false;
3801                 }
3802                 QosPolicyStatus halPolicyStatus = new QosPolicyStatus();
3803                 halPolicyStatus.policyId = (byte) frameworkPolicyStatus.policyId;
3804                 halPolicyStatus.status = dscpPolicyToAidlQosPolicyStatusCode(
3805                         frameworkPolicyStatus.statusCode);
3806                 halPolicyStatusList[index] = halPolicyStatus;
3807                 index++;
3808             }
3809 
3810             try {
3811                 iface.sendQosPolicyResponse(qosPolicyRequestId, morePolicies, halPolicyStatusList);
3812                 return true;
3813             } catch (RemoteException e) {
3814                 handleRemoteException(e, methodStr);
3815             } catch (ServiceSpecificException e) {
3816                 handleServiceSpecificException(e, methodStr);
3817             }
3818             return false;
3819         }
3820     }
3821 
3822     /**
3823      * Indicates the removal of all active QoS policies configured by the AP.
3824      *
3825      * @param ifaceName Name of the interface.
3826      */
removeAllQosPolicies(String ifaceName)3827     public boolean removeAllQosPolicies(String ifaceName) {
3828         final String methodStr = "removeAllQosPolicies";
3829         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3830         if (iface == null) {
3831             return false;
3832         }
3833 
3834         try {
3835             iface.removeAllQosPolicies();
3836             return true;
3837         } catch (RemoteException e) {
3838             handleRemoteException(e, methodStr);
3839         } catch (ServiceSpecificException e) {
3840             handleServiceSpecificException(e, methodStr);
3841         }
3842         return false;
3843     }
3844 
3845     /**
3846      * See comments for {@link ISupplicantStaIfaceHal#addQosPolicyRequestForScs(String, List)}
3847      */
addQosPolicyRequestForScs( @onNull String ifaceName, @NonNull List<QosPolicyParams> policies)3848     public List<SupplicantStaIfaceHal.QosPolicyStatus> addQosPolicyRequestForScs(
3849             @NonNull String ifaceName, @NonNull List<QosPolicyParams> policies) {
3850         synchronized (mLock) {
3851             final String methodStr = "addQosPolicyRequestForScs";
3852             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3853             if (iface == null) {
3854                 return null;
3855             }
3856             try {
3857                 QosPolicyScsData[] halPolicies = frameworkToHalQosPolicyScsDataList(policies);
3858                 QosPolicyScsRequestStatus[] halStatusList =
3859                         iface.addQosPolicyRequestForScs(halPolicies);
3860                 return halToFrameworkQosPolicyScsRequestStatusList(halStatusList);
3861             } catch (RemoteException e) {
3862                 handleRemoteException(e, methodStr);
3863             } catch (ServiceSpecificException e) {
3864                 handleServiceSpecificException(e, methodStr);
3865             }
3866             return null;
3867         }
3868     }
3869 
3870     /**
3871      * See comments for {@link ISupplicantStaIfaceHal#removeQosPolicyForScs(String, List)}
3872      */
removeQosPolicyForScs( @onNull String ifaceName, @NonNull List<Byte> policyIds)3873     public List<SupplicantStaIfaceHal.QosPolicyStatus> removeQosPolicyForScs(
3874             @NonNull String ifaceName, @NonNull List<Byte> policyIds) {
3875         synchronized (mLock) {
3876             final String methodStr = "removeQosPolicyForScs";
3877             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3878             if (iface == null) {
3879                 return null;
3880             }
3881             try {
3882                 byte[] halPolicyIds = new byte[policyIds.size()];
3883                 for (int i = 0; i < policyIds.size(); i++) {
3884                     halPolicyIds[i] = policyIds.get(i);
3885                 }
3886                 QosPolicyScsRequestStatus[] halStatusList =
3887                         iface.removeQosPolicyForScs(halPolicyIds);
3888                 return halToFrameworkQosPolicyScsRequestStatusList(halStatusList);
3889             } catch (RemoteException e) {
3890                 handleRemoteException(e, methodStr);
3891             } catch (ServiceSpecificException e) {
3892                 handleServiceSpecificException(e, methodStr);
3893             }
3894             return null;
3895         }
3896     }
3897 
3898     /**
3899      * See comments for {@link ISupplicantStaIfaceHal#registerQosScsResponseCallback(
3900      *                             SupplicantStaIfaceHal.QosScsResponseCallback)}
3901      */
registerQosScsResponseCallback( @onNull SupplicantStaIfaceHal.QosScsResponseCallback callback)3902     public void registerQosScsResponseCallback(
3903             @NonNull SupplicantStaIfaceHal.QosScsResponseCallback callback) {
3904         synchronized (mLock) {
3905             if (callback == null) {
3906                 Log.e(TAG, "QosScsResponseCallback should not be null");
3907                 return;
3908             } else if (mQosScsResponseCallback != null) {
3909                 Log.e(TAG, "mQosScsResponseCallback has already been assigned");
3910                 return;
3911             }
3912             mQosScsResponseCallback = callback;
3913         }
3914     }
3915 
getQosScsResponseCallback()3916     protected SupplicantStaIfaceHal.QosScsResponseCallback getQosScsResponseCallback() {
3917         return mQosScsResponseCallback;
3918     }
3919 
3920     /**
3921      * Generate DPP credential for network access
3922      *
3923      * @param ifaceName Name of the interface.
3924      * @param ssid ssid of the network
3925      * @param privEcKey Private EC Key for DPP Configurator
3926      * Returns true when operation is successful. On error, false is returned.
3927      */
generateSelfDppConfiguration(@onNull String ifaceName, @NonNull String ssid, byte[] privEcKey)3928     public boolean generateSelfDppConfiguration(@NonNull String ifaceName, @NonNull String ssid,
3929             byte[] privEcKey) {
3930         synchronized (mLock) {
3931             final String methodStr = "generateSelfDppConfiguration";
3932             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
3933             if (iface == null) {
3934                 return false;
3935             }
3936             try {
3937                 iface.generateSelfDppConfiguration(
3938                         NativeUtil.removeEnclosingQuotes(ssid), privEcKey);
3939                 return true;
3940             } catch (RemoteException e) {
3941                 handleRemoteException(e, methodStr);
3942             } catch (ServiceSpecificException e) {
3943                 handleServiceSpecificException(e, methodStr);
3944             }
3945             return false;
3946         }
3947     }
3948 
3949     /**
3950      * Set the currently configured network's anonymous identity.
3951      *
3952      * @param ifaceName Name of the interface.
3953      * @param anonymousIdentity the anonymouns identity.
3954      * @param updateToNativeService write the data to the native service.
3955      * @return true if succeeds, false otherwise.
3956      */
setEapAnonymousIdentity(@onNull String ifaceName, String anonymousIdentity, boolean updateToNativeService)3957     public boolean setEapAnonymousIdentity(@NonNull String ifaceName, String anonymousIdentity,
3958             boolean updateToNativeService) {
3959         synchronized (mLock) {
3960             SupplicantStaNetworkHalAidlImpl networkHandle =
3961                     checkStaNetworkAndLogFailure(ifaceName, "setEapAnonymousIdentity");
3962             if (networkHandle == null) return false;
3963             if (anonymousIdentity == null) return false;
3964             WifiConfiguration currentConfig = getCurrentNetworkLocalConfig(ifaceName);
3965             if (currentConfig == null) return false;
3966             if (!currentConfig.isEnterprise()) return false;
3967 
3968             if (updateToNativeService) {
3969                 if (!networkHandle.setEapAnonymousIdentity(anonymousIdentity.getBytes())) {
3970                     Log.w(TAG, "Cannot set EAP anonymous identity.");
3971                     return false;
3972                 }
3973             }
3974 
3975             // Update cached config after setting native data successfully.
3976             currentConfig.enterpriseConfig.setAnonymousIdentity(anonymousIdentity);
3977             return true;
3978         }
3979     }
3980 
frameworkToHalFrameClassifierMask(int frameworkBitmap)3981     private static byte frameworkToHalFrameClassifierMask(int frameworkBitmap) {
3982         byte halBitmap = 0;
3983         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_IP_VERSION) != 0) {
3984             halBitmap |= FrameClassifierFields.IP_VERSION;
3985         }
3986         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_SRC_IP_ADDR) != 0) {
3987             halBitmap |= FrameClassifierFields.SRC_IP_ADDR;
3988         }
3989         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_DST_IP_ADDR) != 0) {
3990             halBitmap |= FrameClassifierFields.DST_IP_ADDR;
3991         }
3992         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_SRC_PORT) != 0) {
3993             halBitmap |= FrameClassifierFields.SRC_PORT;
3994         }
3995         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_DST_PORT) != 0) {
3996             halBitmap |= FrameClassifierFields.DST_PORT;
3997         }
3998         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_DSCP) != 0) {
3999             halBitmap |= FrameClassifierFields.DSCP;
4000         }
4001         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_PROTOCOL_NEXT_HDR) != 0) {
4002             halBitmap |= FrameClassifierFields.PROTOCOL_NEXT_HDR;
4003         }
4004         if ((frameworkBitmap & MscsParams.FRAME_CLASSIFIER_FLOW_LABEL) != 0) {
4005             halBitmap |= FrameClassifierFields.FLOW_LABEL;
4006         }
4007         return halBitmap;
4008     }
4009 
frameworkToHalMscsParams( MscsParams frameworkParams)4010     private static android.hardware.wifi.supplicant.MscsParams frameworkToHalMscsParams(
4011             MscsParams frameworkParams) {
4012         android.hardware.wifi.supplicant.MscsParams halParams =
4013                 new android.hardware.wifi.supplicant.MscsParams();
4014         halParams.upBitmap = (byte) frameworkParams.getUserPriorityBitmap();
4015         halParams.upLimit = (byte) frameworkParams.getUserPriorityLimit();
4016         halParams.streamTimeoutUs = frameworkParams.getStreamTimeoutUs();
4017         halParams.frameClassifierMask =
4018                 frameworkToHalFrameClassifierMask(frameworkParams.getFrameClassifierFields());
4019         return halParams;
4020     }
4021 
4022     /**
4023      * See comments for {@link ISupplicantStaIfaceHal#enableMscs(MscsParams, String)}
4024      */
4025     @Override
enableMscs(@onNull MscsParams mscsParams, String ifaceName)4026     public void enableMscs(@NonNull MscsParams mscsParams, String ifaceName) {
4027         synchronized (mLock) {
4028             if (!isServiceVersionAtLeast(3)) {
4029                 return;
4030             }
4031             configureMscsInternal(mscsParams, ifaceName);
4032             mLastMscsParams = mscsParams;
4033         }
4034     }
4035 
4036     /**
4037      * See comments for {@link ISupplicantStaIfaceHal#resendMscs(String)}
4038      */
resendMscs(String ifaceName)4039     public void resendMscs(String ifaceName) {
4040         synchronized (mLock) {
4041             if (!isServiceVersionAtLeast(3)) {
4042                 return;
4043             }
4044             if (mLastMscsParams == null) {
4045                 return;
4046             }
4047             configureMscsInternal(mLastMscsParams, ifaceName);
4048         }
4049     }
4050 
configureMscsInternal(@onNull MscsParams mscsParams, String ifaceName)4051     private void configureMscsInternal(@NonNull MscsParams mscsParams, String ifaceName) {
4052         synchronized (mLock) {
4053             if (!isServiceVersionAtLeast(3)) {
4054                 return;
4055             }
4056             String methodStr = "configureMscsInternal";
4057             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
4058             if (iface == null) {
4059                 return;
4060             }
4061             try {
4062                 android.hardware.wifi.supplicant.MscsParams halParams =
4063                         frameworkToHalMscsParams(mscsParams);
4064                 iface.configureMscs(halParams);
4065             } catch (RemoteException e) {
4066                 handleRemoteException(e, methodStr);
4067             } catch (ServiceSpecificException e) {
4068                 handleServiceSpecificException(e, methodStr);
4069             }
4070         }
4071     }
4072 
4073     /**
4074      * See comments for {@link ISupplicantStaIface#disableMscs()}
4075      */
4076     @Override
disableMscs(String ifaceName)4077     public void disableMscs(String ifaceName) {
4078         if (!isServiceVersionAtLeast(3)) {
4079             return;
4080         }
4081         String methodStr = "disableMscs";
4082         mLastMscsParams = null;
4083         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
4084         if (iface == null) {
4085             return;
4086         }
4087         try {
4088             iface.disableMscs();
4089         } catch (RemoteException e) {
4090             handleRemoteException(e, methodStr);
4091         } catch (ServiceSpecificException e) {
4092             handleServiceSpecificException(e, methodStr);
4093         }
4094     }
4095 
4096     private class NonStandardCertCallback extends INonStandardCertCallback.Stub {
4097         @Override
getBlob(String alias)4098         public byte[] getBlob(String alias) {
4099             byte[] blob = null;
4100             if (SdkLevel.isAtLeastU()) {
4101                 Log.i(TAG, "Non-standard certificate requested");
4102                 blob = WifiKeystore.get(alias);
4103             }
4104             if (blob != null) {
4105                 return blob;
4106             } else {
4107                 Log.e(TAG, "Unable to retrieve the blob");
4108                 throw new ServiceSpecificException(SupplicantStatusCode.FAILURE_UNKNOWN);
4109             }
4110         }
4111 
4112         @Override
listAliases(String prefix)4113         public String[] listAliases(String prefix) {
4114             Log.i(TAG, "Alias list was requested");
4115             return SdkLevel.isAtLeastU() ? WifiKeystore.list(prefix) : null;
4116         }
4117 
4118         @Override
getInterfaceHash()4119         public String getInterfaceHash() {
4120             return INonStandardCertCallback.HASH;
4121         }
4122 
4123         @Override
getInterfaceVersion()4124         public int getInterfaceVersion() {
4125             return INonStandardCertCallback.VERSION;
4126         }
4127     }
4128 
4129     @SuppressLint("NewApi") // Keystore migration API is guarded by an SDK check
registerNonStandardCertCallback()4130     private void registerNonStandardCertCallback() {
4131         synchronized (mLock) {
4132             final String methodStr = "registerNonStandardCertCallback";
4133             if (!checkSupplicantAndLogFailure(methodStr) || !isServiceVersionAtLeast(2)) {
4134                 return;
4135             } else if (mNonStandardCertCallback != null) {
4136                 Log.i(TAG, "Non-standard cert callback has already been registered");
4137                 return;
4138             }
4139 
4140             if (!mHasMigratedLegacyKeystoreAliases && Environment.isSdkAtLeastB()
4141                     && Flags.legacyKeystoreToWifiBlobstoreMigrationReadOnly()) {
4142                 if (mKeystoreMigrationStatusConsumer == null) {
4143                     // Create global callback temporarily for access in the unit tests
4144                     mKeystoreMigrationStatusConsumer = new KeystoreMigrationStatusConsumer();
4145                 }
4146                 WifiMigration.migrateLegacyKeystoreToWifiBlobstore(
4147                         new HandlerExecutor(mEventHandler), mKeystoreMigrationStatusConsumer);
4148             }
4149 
4150             try {
4151                 INonStandardCertCallback tempCallback = new NonStandardCertCallback();
4152                 mISupplicant.registerNonStandardCertCallback(tempCallback);
4153                 mNonStandardCertCallback = tempCallback;
4154                 Log.i(TAG, "Non-standard cert callback was registered");
4155             } catch (RemoteException e) {
4156                 handleRemoteException(e, methodStr);
4157             } catch (ServiceSpecificException e) {
4158                 handleServiceSpecificException(e, methodStr);
4159             }
4160         }
4161     }
4162 
4163     @Override
getUsdCapabilities(String ifaceName)4164     public SupplicantStaIfaceHal.UsdCapabilitiesInternal getUsdCapabilities(String ifaceName) {
4165         synchronized (mLock) {
4166             if (!isServiceVersionAtLeast(4)) {
4167                 return null;
4168             }
4169             String methodStr = "getUsdCapabilities";
4170             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(ifaceName, methodStr);
4171             if (iface == null) {
4172                 return null;
4173             }
4174             try {
4175                 UsdCapabilities usdCapabilities = iface.getUsdCapabilities();
4176                 return new SupplicantStaIfaceHal.UsdCapabilitiesInternal(
4177                         usdCapabilities.isUsdPublisherSupported,
4178                         usdCapabilities.isUsdSubscriberSupported,
4179                         usdCapabilities.maxLocalSsiLengthBytes,
4180                         usdCapabilities.maxServiceNameLengthBytes,
4181                         usdCapabilities.maxMatchFilterLengthBytes,
4182                         usdCapabilities.maxNumPublishSessions,
4183                         usdCapabilities.maxNumSubscribeSessions);
4184             } catch (RemoteException e) {
4185                 handleRemoteException(e, methodStr);
4186             } catch (ServiceSpecificException e) {
4187                 handleServiceSpecificException(e, methodStr);
4188             }
4189             return null;
4190         }
4191     }
4192 
4193     @Override
startUsdPublish(String interfaceName, int cmdId, PublishConfig publishConfig)4194     public boolean startUsdPublish(String interfaceName, int cmdId, PublishConfig publishConfig) {
4195         synchronized (mLock) {
4196             if (!isServiceVersionAtLeast(4)) {
4197                 return false;
4198             }
4199             String methodStr = "startUsdPublish";
4200             ISupplicantStaIface iface = checkStaIfaceAndLogFailure(interfaceName, methodStr);
4201             if (iface == null) {
4202                 return false;
4203             }
4204             try {
4205                 iface.startUsdPublish(cmdId, frameworkToHalPublishConfig(publishConfig));
4206                 return true;
4207             } catch (RemoteException e) {
4208                 handleRemoteException(e, methodStr);
4209             } catch (ServiceSpecificException e) {
4210                 handleServiceSpecificException(e, methodStr);
4211             }
4212             return false;
4213         }
4214     }
4215 
frameworkToHalPublishConfig(PublishConfig frameworkConfig)4216     private UsdPublishConfig frameworkToHalPublishConfig(PublishConfig frameworkConfig) {
4217         UsdPublishConfig aidlConfig = new UsdPublishConfig();
4218         // USD publisher is always solicited and unsolicited.
4219         aidlConfig.publishType = UsdPublishConfig.PublishType.SOLICITED_AND_UNSOLICITED;
4220         // USD has FSD enabled always.
4221         aidlConfig.isFsd = true;
4222         aidlConfig.transmissionType = frameworkToHalTransmissionType(
4223                 frameworkConfig.getSolicitedTransmissionType());
4224         aidlConfig.announcementPeriodMillis = frameworkConfig.getAnnouncementPeriodMillis();
4225         aidlConfig.usdBaseConfig = new UsdBaseConfig();
4226         aidlConfig.usdBaseConfig.ttlSec = frameworkConfig.getTtlSeconds();
4227         int[] freqs = frameworkConfig.getOperatingFrequenciesMhz();
4228         aidlConfig.usdBaseConfig.defaultFreqMhz = (freqs == null) ? 2437 : freqs[0];
4229         aidlConfig.usdBaseConfig.freqsMhz =
4230                 (freqs == null || freqs.length <= 1) ? new int[0] : Arrays.copyOfRange(freqs, 1,
4231                         freqs.length);
4232         aidlConfig.usdBaseConfig.serviceName = Arrays.toString(frameworkConfig.getServiceName());
4233         aidlConfig.usdBaseConfig.serviceSpecificInfo =
4234                 frameworkConfig.getServiceSpecificInfo() != null
4235                         ? frameworkConfig.getServiceSpecificInfo() : new byte[0];
4236         aidlConfig.usdBaseConfig.rxMatchFilter = frameworkConfig.getRxMatchFilterTlv() != null
4237                 ? frameworkConfig.getRxMatchFilterTlv() : new byte[0];
4238         aidlConfig.usdBaseConfig.txMatchFilter = frameworkConfig.getTxMatchFilterTlv() != null
4239                 ? frameworkConfig.getTxMatchFilterTlv() : new byte[0];
4240         aidlConfig.usdBaseConfig.serviceProtoType = frameworkToHalProtoType(
4241                 frameworkConfig.getServiceProtoType());
4242         return aidlConfig;
4243     }
4244 
frameworkToHalTransmissionType( @onfig.TransmissionType int transmissionType)4245     private static int frameworkToHalTransmissionType(
4246             @Config.TransmissionType int transmissionType) {
4247         if (transmissionType == Config.TRANSMISSION_TYPE_MULTICAST) {
4248             return UsdPublishTransmissionType.MULTICAST;
4249         } else {
4250             return UsdPublishTransmissionType.UNICAST;
4251         }
4252     }
4253 
frameworkToHalProtoType(int serviceProtoType)4254     private static int frameworkToHalProtoType(int serviceProtoType) {
4255         return switch (serviceProtoType) {
4256             case Config.SERVICE_PROTO_TYPE_GENERIC -> UsdServiceProtoType.GENERIC;
4257             case Config.SERVICE_PROTO_TYPE_CSA_MATTER -> UsdServiceProtoType.CSA_MATTER;
4258             default -> UsdServiceProtoType.UNKNOWN;
4259         };
4260     }
4261 
4262     @Override
startUsdSubscribe(String interfaceName, int cmdId, SubscribeConfig subscribeConfig)4263     public boolean startUsdSubscribe(String interfaceName, int cmdId,
4264             SubscribeConfig subscribeConfig) {
4265         if (!isServiceVersionAtLeast(4)) {
4266             return false;
4267         }
4268         String methodStr = "startUsdSubscribe";
4269         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(interfaceName, methodStr);
4270         if (iface == null) {
4271             return false;
4272         }
4273         try {
4274             iface.startUsdSubscribe(cmdId, frameworkToHalSubscribeConfig(subscribeConfig));
4275             return true;
4276         } catch (RemoteException e) {
4277             handleRemoteException(e, methodStr);
4278         } catch (ServiceSpecificException e) {
4279             handleServiceSpecificException(e, methodStr);
4280         }
4281         return false;
4282     }
4283 
frameworkToHalSubscribeConfig(SubscribeConfig frameworkConfig)4284     private UsdSubscribeConfig frameworkToHalSubscribeConfig(SubscribeConfig frameworkConfig) {
4285         UsdSubscribeConfig aidlconfig = new UsdSubscribeConfig();
4286         aidlconfig.subscribeType = frameworkToHalSubscriberType(frameworkConfig.getSubscribeType());
4287         aidlconfig.queryPeriodMillis = frameworkConfig.getQueryPeriodMillis();
4288         aidlconfig.usdBaseConfig = new UsdBaseConfig();
4289         aidlconfig.usdBaseConfig.ttlSec = frameworkConfig.getTtlSeconds();
4290         int[] freqs = frameworkConfig.getOperatingFrequenciesMhz();
4291         aidlconfig.usdBaseConfig.defaultFreqMhz = (freqs == null) ? 2437 : freqs[0];
4292         aidlconfig.usdBaseConfig.freqsMhz =
4293                 (freqs == null || freqs.length <= 1) ? new int[0] : Arrays.copyOfRange(freqs, 1,
4294                         freqs.length);
4295         aidlconfig.usdBaseConfig.serviceName = Arrays.toString(frameworkConfig.getServiceName());
4296         aidlconfig.usdBaseConfig.serviceSpecificInfo =
4297                 frameworkConfig.getServiceSpecificInfo() != null
4298                         ? frameworkConfig.getServiceSpecificInfo() : new byte[0];
4299         aidlconfig.usdBaseConfig.rxMatchFilter = frameworkConfig.getRxMatchFilterTlv() != null
4300                 ? frameworkConfig.getRxMatchFilterTlv() : new byte[0];
4301         aidlconfig.usdBaseConfig.txMatchFilter = frameworkConfig.getTxMatchFilterTlv() != null
4302                 ? frameworkConfig.getTxMatchFilterTlv() : new byte[0];
4303         aidlconfig.usdBaseConfig.serviceProtoType = frameworkToHalProtoType(
4304                 frameworkConfig.getServiceProtoType());
4305         return aidlconfig;
4306     }
4307 
frameworkToHalSubscriberType(int subscribeType)4308     private byte frameworkToHalSubscriberType(int subscribeType) {
4309         if (subscribeType == Config.SUBSCRIBE_TYPE_ACTIVE) {
4310             return UsdSubscribeConfig.SubscribeType.ACTIVE_MODE;
4311         }
4312         return UsdSubscribeConfig.SubscribeType.PASSIVE_MODE;
4313     }
4314 
4315     @Override
updateUsdPublish(String interfaceName, int publishId, byte[] ssi)4316     public void updateUsdPublish(String interfaceName, int publishId, byte[] ssi) {
4317         if (!isServiceVersionAtLeast(4)) {
4318             return;
4319         }
4320         String methodStr = "updateUsdPublish";
4321         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(interfaceName, methodStr);
4322         if (iface == null) {
4323             return;
4324         }
4325         try {
4326             iface.updateUsdPublish(publishId, ssi);
4327         } catch (RemoteException e) {
4328             handleRemoteException(e, methodStr);
4329         } catch (ServiceSpecificException e) {
4330             handleServiceSpecificException(e, methodStr);
4331         }
4332     }
4333 
4334     @Override
cancelUsdPublish(String interfaceName, int publishId)4335     public void cancelUsdPublish(String interfaceName, int publishId) {
4336         if (!isServiceVersionAtLeast(4)) {
4337             return;
4338         }
4339         String methodStr = "updateUsdPublish";
4340         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(interfaceName, methodStr);
4341         if (iface == null) {
4342             return;
4343         }
4344         try {
4345             iface.cancelUsdPublish(publishId);
4346         } catch (RemoteException e) {
4347             handleRemoteException(e, methodStr);
4348         } catch (ServiceSpecificException e) {
4349             handleServiceSpecificException(e, methodStr);
4350         }
4351     }
4352 
4353     @Override
cancelUsdSubscribe(String interfaceName, int subscribeId)4354     public void cancelUsdSubscribe(String interfaceName, int subscribeId) {
4355         if (!isServiceVersionAtLeast(4)) {
4356             return;
4357         }
4358         String methodStr = "cancelUsdSubscribe";
4359         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(interfaceName, methodStr);
4360         if (iface == null) {
4361             return;
4362         }
4363         try {
4364             iface.cancelUsdSubscribe(subscribeId);
4365         } catch (RemoteException e) {
4366             handleRemoteException(e, methodStr);
4367         } catch (ServiceSpecificException e) {
4368             handleServiceSpecificException(e, methodStr);
4369         }
4370     }
4371 
4372     @Override
sendUsdMessage(String interfaceName, int ownId, int peerId, MacAddress peerMacAddress, byte[] message)4373     public boolean sendUsdMessage(String interfaceName, int ownId, int peerId,
4374             MacAddress peerMacAddress, byte[] message) {
4375         if (!isServiceVersionAtLeast(4)) {
4376             return false;
4377         }
4378         String methodStr = "sendUsdMessage";
4379         ISupplicantStaIface iface = checkStaIfaceAndLogFailure(interfaceName, methodStr);
4380         if (iface == null) {
4381             return false;
4382         }
4383         try {
4384             UsdMessageInfo usdMessageInfo = new UsdMessageInfo();
4385             usdMessageInfo.ownId = ownId;
4386             usdMessageInfo.peerId = peerId;
4387             usdMessageInfo.peerMacAddress = peerMacAddress.toByteArray();
4388             usdMessageInfo.message = message;
4389             iface.sendUsdMessage(usdMessageInfo);
4390             return true;
4391         } catch (RemoteException e) {
4392             handleRemoteException(e, methodStr);
4393         } catch (ServiceSpecificException e) {
4394             handleServiceSpecificException(e, methodStr);
4395         }
4396         return false;
4397     }
4398 
4399     /**
4400      * Register a framework callback to receive USD events.
4401      */
registerUsdEventsCallback( UsdRequestManager.UsdNativeEventsCallback usdEventsCallback)4402     public void registerUsdEventsCallback(
4403             UsdRequestManager.UsdNativeEventsCallback usdEventsCallback) {
4404         mUsdEventsCallback = usdEventsCallback;
4405     }
4406 
4407     /**
4408      * Get USD event callback.
4409      */
4410     @Nullable
getUsdEventsCallback()4411     public UsdNativeManager.UsdEventsCallback getUsdEventsCallback() {
4412         return mUsdEventsCallback;
4413     }
4414 }
4415