1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.wifi.nl80211;
18 
19 import android.annotation.CallbackExecutor;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.annotation.SystemService;
25 import android.app.AlarmManager;
26 import android.content.Context;
27 import android.net.wifi.SoftApInfo;
28 import android.net.wifi.WifiAnnotations;
29 import android.net.wifi.WifiScanner;
30 import android.os.Binder;
31 import android.os.Handler;
32 import android.os.IBinder;
33 import android.os.RemoteException;
34 import android.os.ServiceManager;
35 import android.os.SystemClock;
36 import android.util.Log;
37 
38 import com.android.internal.annotations.VisibleForTesting;
39 
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.RetentionPolicy;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.HashMap;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.Set;
48 import java.util.concurrent.Executor;
49 import java.util.concurrent.atomic.AtomicBoolean;
50 
51 /**
52  * This class encapsulates the interface the wificond daemon presents to the Wi-Fi framework - used
53  * to encapsulate the Wi-Fi 80211nl management interface. The
54  * interface is only for use by the Wi-Fi framework and access is protected by SELinux permissions.
55  *
56  * @hide
57  */
58 @SystemApi
59 @SystemService(Context.WIFI_NL80211_SERVICE)
60 public class WifiNl80211Manager {
61     private static final String TAG = "WifiNl80211Manager";
62     private boolean mVerboseLoggingEnabled = false;
63 
64     /**
65      * The {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
66      * timeout, in milliseconds, after which
67      * {@link SendMgmtFrameCallback#onFailure(int)} will be called with reason
68      * {@link #SEND_MGMT_FRAME_ERROR_TIMEOUT}.
69      */
70     private static final int SEND_MGMT_FRAME_TIMEOUT_MS = 1000;
71 
72     private static final String TIMEOUT_ALARM_TAG = TAG + " Send Management Frame Timeout";
73 
74     /** @hide */
75     @Retention(RetentionPolicy.SOURCE)
76     @IntDef(prefix = {"SCAN_TYPE_"},
77             value = {SCAN_TYPE_SINGLE_SCAN,
78                     SCAN_TYPE_PNO_SCAN})
79     public @interface ScanResultType {}
80 
81     /**
82      * Specifies a scan type: single scan initiated by the framework. Can be used in
83      * {@link #getScanResults(String, int)} to specify the type of scan result to fetch.
84      */
85     public static final int SCAN_TYPE_SINGLE_SCAN = 0;
86 
87     /**
88      * Specifies a scan type: PNO scan. Can be used in {@link #getScanResults(String, int)} to
89      * specify the type of scan result to fetch.
90      */
91     public static final int SCAN_TYPE_PNO_SCAN = 1;
92 
93     private AlarmManager mAlarmManager;
94     private Handler mEventHandler;
95 
96     // Cached wificond binder handlers.
97     private IWificond mWificond;
98     private HashMap<String, IClientInterface> mClientInterfaces = new HashMap<>();
99     private HashMap<String, IApInterface> mApInterfaces = new HashMap<>();
100     private HashMap<String, IWifiScannerImpl> mWificondScanners = new HashMap<>();
101     private HashMap<String, IScanEvent> mScanEventHandlers = new HashMap<>();
102     private HashMap<String, IPnoScanEvent> mPnoScanEventHandlers = new HashMap<>();
103     private HashMap<String, IApInterfaceEventCallback> mApInterfaceListeners = new HashMap<>();
104     private Runnable mDeathEventHandler;
105     /**
106      * Ensures that no more than one sendMgmtFrame operation runs concurrently.
107      */
108     private AtomicBoolean mSendMgmtFrameInProgress = new AtomicBoolean(false);
109 
110     /**
111      * Interface used when waiting for scans to be completed (with results).
112      */
113     public interface ScanEventCallback {
114         /**
115          * Called when scan results are available. Scans results should then be obtained from
116          * {@link #getScanResults(String, int)}.
117          */
onScanResultReady()118         void onScanResultReady();
119 
120         /**
121          * Called when a scan has failed.
122          */
onScanFailed()123         void onScanFailed();
124     }
125 
126     /**
127      * Interface for a callback to provide information about PNO scan request requested with
128      * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}. Note that the
129      * callback are for the status of the request - not the scan itself. The results of the scan
130      * are returned with {@link ScanEventCallback}.
131      */
132     public interface PnoScanRequestCallback {
133         /**
134          * Called when a PNO scan request has been successfully submitted.
135          */
onPnoRequestSucceeded()136         void onPnoRequestSucceeded();
137 
138         /**
139          * Called when a PNO scan request fails.
140          */
onPnoRequestFailed()141         void onPnoRequestFailed();
142     }
143 
144     private class ScanEventHandler extends IScanEvent.Stub {
145         private Executor mExecutor;
146         private ScanEventCallback mCallback;
147 
ScanEventHandler(@onNull Executor executor, @NonNull ScanEventCallback callback)148         ScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
149             mExecutor = executor;
150             mCallback = callback;
151         }
152 
153         @Override
OnScanResultReady()154         public void OnScanResultReady() {
155             Log.d(TAG, "Scan result ready event");
156             Binder.clearCallingIdentity();
157             mExecutor.execute(() -> mCallback.onScanResultReady());
158         }
159 
160         @Override
OnScanFailed()161         public void OnScanFailed() {
162             Log.d(TAG, "Scan failed event");
163             Binder.clearCallingIdentity();
164             mExecutor.execute(() -> mCallback.onScanFailed());
165         }
166     }
167 
168     /**
169      * Result of a signal poll requested using {@link #signalPoll(String)}.
170      */
171     public static class SignalPollResult {
172         /** @hide */
SignalPollResult(int currentRssiDbm, int txBitrateMbps, int rxBitrateMbps, int associationFrequencyMHz)173         public SignalPollResult(int currentRssiDbm, int txBitrateMbps, int rxBitrateMbps,
174                 int associationFrequencyMHz) {
175             this.currentRssiDbm = currentRssiDbm;
176             this.txBitrateMbps = txBitrateMbps;
177             this.rxBitrateMbps = rxBitrateMbps;
178             this.associationFrequencyMHz = associationFrequencyMHz;
179         }
180 
181         /**
182          * RSSI value in dBM.
183          */
184         public final int currentRssiDbm;
185 
186         /**
187          * Transmission bit rate in Mbps.
188          */
189         public final int txBitrateMbps;
190 
191         /**
192          * Last received packet bit rate in Mbps.
193          */
194         public final int rxBitrateMbps;
195 
196         /**
197          * Association frequency in MHz.
198          */
199         public final int associationFrequencyMHz;
200     }
201 
202     /**
203      * Transmission counters obtained using {@link #getTxPacketCounters(String)}.
204      */
205     public static class TxPacketCounters {
206         /** @hide */
TxPacketCounters(int txPacketSucceeded, int txPacketFailed)207         public TxPacketCounters(int txPacketSucceeded, int txPacketFailed) {
208             this.txPacketSucceeded = txPacketSucceeded;
209             this.txPacketFailed = txPacketFailed;
210         }
211 
212         /**
213          * Number of successfully transmitted packets.
214          */
215         public final int txPacketSucceeded;
216 
217         /**
218          * Number of packet transmission failures.
219          */
220         public final int txPacketFailed;
221     }
222 
223     /**
224      * Callbacks for SoftAp interface registered using
225      * {@link #registerApCallback(String, Executor, SoftApCallback)}.
226      */
227     public interface SoftApCallback {
228         /**
229          * Invoked when there is a fatal failure and the SoftAp is shutdown.
230          */
onFailure()231         void onFailure();
232 
233         /**
234          * Invoked when there is a change in the associated station (STA).
235          * @param client Information about the client whose status has changed.
236          * @param isConnected Indication as to whether the client is connected (true), or
237          *                    disconnected (false).
238          */
onConnectedClientsChanged(@onNull NativeWifiClient client, boolean isConnected)239         void onConnectedClientsChanged(@NonNull NativeWifiClient client, boolean isConnected);
240 
241         /**
242          * Invoked when a channel switch event happens - i.e. the SoftAp is moved to a different
243          * channel. Also called on initial registration.
244          * @param frequencyMhz The new frequency of the SoftAp. A value of 0 is invalid and is an
245          *                     indication that the SoftAp is not enabled.
246          * @param bandwidth The new bandwidth of the SoftAp.
247          */
onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth)248         void onSoftApChannelSwitched(int frequencyMhz, @WifiAnnotations.Bandwidth int bandwidth);
249     }
250 
251     /**
252      * Callback to notify the results of a
253      * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} call.
254      * Note: no callbacks will be triggered if the interface dies while sending a frame.
255      */
256     public interface SendMgmtFrameCallback {
257         /**
258          * Called when the management frame was successfully sent and ACKed by the recipient.
259          * @param elapsedTimeMs The elapsed time between when the management frame was sent and when
260          *                      the ACK was processed, in milliseconds, as measured by wificond.
261          *                      This includes the time that the send frame spent queuing before it
262          *                      was sent, any firmware retries, and the time the received ACK spent
263          *                      queuing before it was processed.
264          */
onAck(int elapsedTimeMs)265         void onAck(int elapsedTimeMs);
266 
267         /**
268          * Called when the send failed.
269          * @param reason The error code for the failure.
270          */
onFailure(@endMgmtFrameError int reason)271         void onFailure(@SendMgmtFrameError int reason);
272     }
273 
274     /** @hide */
275     @Retention(RetentionPolicy.SOURCE)
276     @IntDef(prefix = {"SEND_MGMT_FRAME_ERROR_"},
277             value = {SEND_MGMT_FRAME_ERROR_UNKNOWN,
278                     SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED,
279                     SEND_MGMT_FRAME_ERROR_NO_ACK,
280                     SEND_MGMT_FRAME_ERROR_TIMEOUT,
281                     SEND_MGMT_FRAME_ERROR_ALREADY_STARTED})
282     public @interface SendMgmtFrameError {}
283 
284     // Send management frame error codes
285 
286     /**
287      * Unknown error occurred during call to
288      * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
289      */
290     public static final int SEND_MGMT_FRAME_ERROR_UNKNOWN = 1;
291 
292     /**
293      * Specifying the MCS rate in
294      * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)} is not
295      * supported by this device.
296      */
297     public static final int SEND_MGMT_FRAME_ERROR_MCS_UNSUPPORTED = 2;
298 
299     /**
300      * Driver reported that no ACK was received for the frame transmitted using
301      * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}.
302      */
303     public static final int SEND_MGMT_FRAME_ERROR_NO_ACK = 3;
304 
305     /**
306      * Error code for when the driver fails to report on the status of the frame sent by
307      * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
308      * after {@link #SEND_MGMT_FRAME_TIMEOUT_MS} milliseconds.
309      */
310     public static final int SEND_MGMT_FRAME_ERROR_TIMEOUT = 4;
311 
312     /**
313      * An existing call to
314      * {@link #sendMgmtFrame(String, byte[], int, Executor, SendMgmtFrameCallback)}
315      * is in progress. Another frame cannot be sent until the first call completes.
316      */
317     public static final int SEND_MGMT_FRAME_ERROR_ALREADY_STARTED = 5;
318 
319     /** @hide */
WifiNl80211Manager(Context context)320     public WifiNl80211Manager(Context context) {
321         mAlarmManager = context.getSystemService(AlarmManager.class);
322         mEventHandler = new Handler(context.getMainLooper());
323     }
324 
325     /** @hide */
326     @VisibleForTesting
WifiNl80211Manager(Context context, IWificond wificond)327     public WifiNl80211Manager(Context context, IWificond wificond) {
328         this(context);
329         mWificond = wificond;
330     }
331 
332     private class PnoScanEventHandler extends IPnoScanEvent.Stub {
333         private Executor mExecutor;
334         private ScanEventCallback mCallback;
335 
PnoScanEventHandler(@onNull Executor executor, @NonNull ScanEventCallback callback)336         PnoScanEventHandler(@NonNull Executor executor, @NonNull ScanEventCallback callback) {
337             mExecutor = executor;
338             mCallback = callback;
339         }
340 
341         @Override
OnPnoNetworkFound()342         public void OnPnoNetworkFound() {
343             Log.d(TAG, "Pno scan result event");
344             Binder.clearCallingIdentity();
345             mExecutor.execute(() -> mCallback.onScanResultReady());
346         }
347 
348         @Override
OnPnoScanFailed()349         public void OnPnoScanFailed() {
350             Log.d(TAG, "Pno Scan failed event");
351             Binder.clearCallingIdentity();
352             mExecutor.execute(() -> mCallback.onScanFailed());
353         }
354     }
355 
356     /**
357      * Listener for AP Interface events.
358      */
359     private class ApInterfaceEventCallback extends IApInterfaceEventCallback.Stub {
360         private Executor mExecutor;
361         private SoftApCallback mSoftApListener;
362 
ApInterfaceEventCallback(Executor executor, SoftApCallback listener)363         ApInterfaceEventCallback(Executor executor, SoftApCallback listener) {
364             mExecutor = executor;
365             mSoftApListener = listener;
366         }
367 
368         @Override
onConnectedClientsChanged(NativeWifiClient client, boolean isConnected)369         public void onConnectedClientsChanged(NativeWifiClient client, boolean isConnected) {
370             if (mVerboseLoggingEnabled) {
371                 Log.d(TAG, "onConnectedClientsChanged called with "
372                         + client.getMacAddress() + " isConnected: " + isConnected);
373             }
374 
375             Binder.clearCallingIdentity();
376             mExecutor.execute(() -> mSoftApListener.onConnectedClientsChanged(client, isConnected));
377         }
378 
379         @Override
onSoftApChannelSwitched(int frequency, int bandwidth)380         public void onSoftApChannelSwitched(int frequency, int bandwidth) {
381             Binder.clearCallingIdentity();
382             mExecutor.execute(() -> mSoftApListener.onSoftApChannelSwitched(frequency,
383                     toFrameworkBandwidth(bandwidth)));
384         }
385 
toFrameworkBandwidth(int bandwidth)386         private @WifiAnnotations.Bandwidth int toFrameworkBandwidth(int bandwidth) {
387             switch(bandwidth) {
388                 case IApInterfaceEventCallback.BANDWIDTH_INVALID:
389                     return SoftApInfo.CHANNEL_WIDTH_INVALID;
390                 case IApInterfaceEventCallback.BANDWIDTH_20_NOHT:
391                     return SoftApInfo.CHANNEL_WIDTH_20MHZ_NOHT;
392                 case IApInterfaceEventCallback.BANDWIDTH_20:
393                     return SoftApInfo.CHANNEL_WIDTH_20MHZ;
394                 case IApInterfaceEventCallback.BANDWIDTH_40:
395                     return SoftApInfo.CHANNEL_WIDTH_40MHZ;
396                 case IApInterfaceEventCallback.BANDWIDTH_80:
397                     return SoftApInfo.CHANNEL_WIDTH_80MHZ;
398                 case IApInterfaceEventCallback.BANDWIDTH_80P80:
399                     return SoftApInfo.CHANNEL_WIDTH_80MHZ_PLUS_MHZ;
400                 case IApInterfaceEventCallback.BANDWIDTH_160:
401                     return SoftApInfo.CHANNEL_WIDTH_160MHZ;
402                 default:
403                     return SoftApInfo.CHANNEL_WIDTH_INVALID;
404             }
405         }
406     }
407 
408     /**
409      * Callback triggered by wificond.
410      */
411     private class SendMgmtFrameEvent extends ISendMgmtFrameEvent.Stub {
412         private Executor mExecutor;
413         private SendMgmtFrameCallback mCallback;
414         private AlarmManager.OnAlarmListener mTimeoutCallback;
415         /**
416          * ensures that mCallback is only called once
417          */
418         private boolean mWasCalled;
419 
runIfFirstCall(Runnable r)420         private void runIfFirstCall(Runnable r) {
421             if (mWasCalled) return;
422             mWasCalled = true;
423 
424             mSendMgmtFrameInProgress.set(false);
425             r.run();
426         }
427 
SendMgmtFrameEvent(@onNull Executor executor, @NonNull SendMgmtFrameCallback callback)428         SendMgmtFrameEvent(@NonNull Executor executor, @NonNull SendMgmtFrameCallback callback) {
429             mExecutor = executor;
430             mCallback = callback;
431             // called in main thread
432             mTimeoutCallback = () -> runIfFirstCall(() -> {
433                 if (mVerboseLoggingEnabled) {
434                     Log.e(TAG, "Timed out waiting for ACK");
435                 }
436                 Binder.clearCallingIdentity();
437                 mExecutor.execute(() -> mCallback.onFailure(SEND_MGMT_FRAME_ERROR_TIMEOUT));
438             });
439             mWasCalled = false;
440 
441             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
442                     SystemClock.elapsedRealtime() + SEND_MGMT_FRAME_TIMEOUT_MS,
443                     TIMEOUT_ALARM_TAG, mTimeoutCallback, mEventHandler);
444         }
445 
446         // called in binder thread
447         @Override
OnAck(int elapsedTimeMs)448         public void OnAck(int elapsedTimeMs) {
449             // post to main thread
450             mEventHandler.post(() -> runIfFirstCall(() -> {
451                 mAlarmManager.cancel(mTimeoutCallback);
452                 Binder.clearCallingIdentity();
453                 mExecutor.execute(() -> mCallback.onAck(elapsedTimeMs));
454             }));
455         }
456 
457         // called in binder thread
458         @Override
OnFailure(int reason)459         public void OnFailure(int reason) {
460             // post to main thread
461             mEventHandler.post(() -> runIfFirstCall(() -> {
462                 mAlarmManager.cancel(mTimeoutCallback);
463                 Binder.clearCallingIdentity();
464                 mExecutor.execute(() -> mCallback.onFailure(reason));
465             }));
466         }
467     }
468 
469     /**
470      * Called by the binder subsystem upon remote object death.
471      * Invoke all the register death handlers and clear state.
472      * @hide
473      */
474     @VisibleForTesting
binderDied()475     public void binderDied() {
476         mEventHandler.post(() -> {
477             Log.e(TAG, "Wificond died!");
478             clearState();
479             // Invalidate the global wificond handle on death. Will be refreshed
480             // on the next setup call.
481             mWificond = null;
482             if (mDeathEventHandler != null) {
483                 mDeathEventHandler.run();
484             }
485         });
486     }
487 
488     /**
489      * Enable or disable verbose logging of the WifiNl80211Manager module.
490      * @param enable True to enable verbose logging. False to disable verbose logging.
491      */
enableVerboseLogging(boolean enable)492     public void enableVerboseLogging(boolean enable) {
493         mVerboseLoggingEnabled = enable;
494     }
495 
496     /**
497      * Register a death notification for the WifiNl80211Manager which acts as a proxy for the
498      * wificond daemon (i.e. the death listener will be called when and if the wificond daemon
499      * dies).
500      *
501      * @param deathEventHandler A {@link Runnable} to be called whenever the wificond daemon dies.
502      */
setOnServiceDeadCallback(@onNull Runnable deathEventHandler)503     public void setOnServiceDeadCallback(@NonNull Runnable deathEventHandler) {
504         if (mDeathEventHandler != null) {
505             Log.e(TAG, "Death handler already present");
506         }
507         mDeathEventHandler = deathEventHandler;
508     }
509 
510     /**
511      * Helper method to retrieve the global wificond handle and register for
512      * death notifications.
513      */
retrieveWificondAndRegisterForDeath()514     private boolean retrieveWificondAndRegisterForDeath() {
515         if (mWificond != null) {
516             if (mVerboseLoggingEnabled) {
517                 Log.d(TAG, "Wificond handle already retrieved");
518             }
519             // We already have a wificond handle.
520             return true;
521         }
522         IBinder binder = ServiceManager.getService(Context.WIFI_NL80211_SERVICE);
523         mWificond = IWificond.Stub.asInterface(binder);
524         if (mWificond == null) {
525             Log.e(TAG, "Failed to get reference to wificond");
526             return false;
527         }
528         try {
529             mWificond.asBinder().linkToDeath(() -> binderDied(), 0);
530         } catch (RemoteException e) {
531             Log.e(TAG, "Failed to register death notification for wificond");
532             // The remote has already died.
533             return false;
534         }
535         return true;
536     }
537 
538     /**
539      * Set up an interface for client (STA) mode.
540      *
541      * @param ifaceName Name of the interface to configure.
542      * @param executor The Executor on which to execute the callbacks.
543      * @param scanCallback A callback for framework initiated scans.
544      * @param pnoScanCallback A callback for PNO (offloaded) scans.
545      * @return true on success.
546      */
setupInterfaceForClientMode(@onNull String ifaceName, @NonNull @CallbackExecutor Executor executor, @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback)547     public boolean setupInterfaceForClientMode(@NonNull String ifaceName,
548             @NonNull @CallbackExecutor Executor executor,
549             @NonNull ScanEventCallback scanCallback, @NonNull ScanEventCallback pnoScanCallback) {
550         Log.d(TAG, "Setting up interface for client mode");
551         if (!retrieveWificondAndRegisterForDeath()) {
552             return false;
553         }
554 
555         if (scanCallback == null || pnoScanCallback == null || executor == null) {
556             Log.e(TAG, "setupInterfaceForClientMode invoked with null callbacks");
557             return false;
558         }
559 
560         IClientInterface clientInterface = null;
561         try {
562             clientInterface = mWificond.createClientInterface(ifaceName);
563         } catch (RemoteException e1) {
564             Log.e(TAG, "Failed to get IClientInterface due to remote exception");
565             return false;
566         }
567 
568         if (clientInterface == null) {
569             Log.e(TAG, "Could not get IClientInterface instance from wificond");
570             return false;
571         }
572         Binder.allowBlocking(clientInterface.asBinder());
573 
574         // Refresh Handlers
575         mClientInterfaces.put(ifaceName, clientInterface);
576         try {
577             IWifiScannerImpl wificondScanner = clientInterface.getWifiScannerImpl();
578             if (wificondScanner == null) {
579                 Log.e(TAG, "Failed to get WificondScannerImpl");
580                 return false;
581             }
582             mWificondScanners.put(ifaceName, wificondScanner);
583             Binder.allowBlocking(wificondScanner.asBinder());
584             ScanEventHandler scanEventHandler = new ScanEventHandler(executor, scanCallback);
585             mScanEventHandlers.put(ifaceName,  scanEventHandler);
586             wificondScanner.subscribeScanEvents(scanEventHandler);
587             PnoScanEventHandler pnoScanEventHandler = new PnoScanEventHandler(executor,
588                     pnoScanCallback);
589             mPnoScanEventHandlers.put(ifaceName,  pnoScanEventHandler);
590             wificondScanner.subscribePnoScanEvents(pnoScanEventHandler);
591         } catch (RemoteException e) {
592             Log.e(TAG, "Failed to refresh wificond scanner due to remote exception");
593         }
594 
595         return true;
596     }
597 
598     /**
599      * Tear down a specific client (STA) interface configured using
600      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
601      *
602      * @param ifaceName Name of the interface to tear down.
603      * @return Returns true on success, false on failure (e.g. when called before an interface was
604      * set up).
605      */
tearDownClientInterface(@onNull String ifaceName)606     public boolean tearDownClientInterface(@NonNull String ifaceName) {
607         if (getClientInterface(ifaceName) == null) {
608             Log.e(TAG, "No valid wificond client interface handler");
609             return false;
610         }
611         try {
612             IWifiScannerImpl scannerImpl = mWificondScanners.get(ifaceName);
613             if (scannerImpl != null) {
614                 scannerImpl.unsubscribeScanEvents();
615                 scannerImpl.unsubscribePnoScanEvents();
616             }
617         } catch (RemoteException e) {
618             Log.e(TAG, "Failed to unsubscribe wificond scanner due to remote exception");
619             return false;
620         }
621 
622         if (mWificond == null) {
623             Log.e(TAG, "Reference to wifiCond is null");
624             return false;
625         }
626 
627         boolean success;
628         try {
629             success = mWificond.tearDownClientInterface(ifaceName);
630         } catch (RemoteException e1) {
631             Log.e(TAG, "Failed to teardown client interface due to remote exception");
632             return false;
633         }
634         if (!success) {
635             Log.e(TAG, "Failed to teardown client interface");
636             return false;
637         }
638 
639         mClientInterfaces.remove(ifaceName);
640         mWificondScanners.remove(ifaceName);
641         mScanEventHandlers.remove(ifaceName);
642         mPnoScanEventHandlers.remove(ifaceName);
643         return true;
644     }
645 
646     /**
647      * Set up interface as a Soft AP.
648      *
649      * @param ifaceName Name of the interface to configure.
650      * @return true on success.
651      */
setupInterfaceForSoftApMode(@onNull String ifaceName)652     public boolean setupInterfaceForSoftApMode(@NonNull String ifaceName) {
653         Log.d(TAG, "Setting up interface for soft ap mode");
654         if (!retrieveWificondAndRegisterForDeath()) {
655             return false;
656         }
657 
658         IApInterface apInterface = null;
659         try {
660             apInterface = mWificond.createApInterface(ifaceName);
661         } catch (RemoteException e1) {
662             Log.e(TAG, "Failed to get IApInterface due to remote exception");
663             return false;
664         }
665 
666         if (apInterface == null) {
667             Log.e(TAG, "Could not get IApInterface instance from wificond");
668             return false;
669         }
670         Binder.allowBlocking(apInterface.asBinder());
671 
672         // Refresh Handlers
673         mApInterfaces.put(ifaceName, apInterface);
674         return true;
675     }
676 
677     /**
678      * Tear down a Soft AP interface configured using
679      * {@link #setupInterfaceForSoftApMode(String)}.
680      *
681      * @param ifaceName Name of the interface to tear down.
682      * @return Returns true on success, false on failure (e.g. when called before an interface was
683      * set up).
684      */
tearDownSoftApInterface(@onNull String ifaceName)685     public boolean tearDownSoftApInterface(@NonNull String ifaceName) {
686         if (getApInterface(ifaceName) == null) {
687             Log.e(TAG, "No valid wificond ap interface handler");
688             return false;
689         }
690 
691         if (mWificond == null) {
692             Log.e(TAG, "Reference to wifiCond is null");
693             return false;
694         }
695 
696         boolean success;
697         try {
698             success = mWificond.tearDownApInterface(ifaceName);
699         } catch (RemoteException e1) {
700             Log.e(TAG, "Failed to teardown AP interface due to remote exception");
701             return false;
702         }
703         if (!success) {
704             Log.e(TAG, "Failed to teardown AP interface");
705             return false;
706         }
707         mApInterfaces.remove(ifaceName);
708         mApInterfaceListeners.remove(ifaceName);
709         return true;
710     }
711 
712     /**
713     * Tear down all interfaces, whether clients (STA) or Soft AP.
714      *
715     * @return Returns true on success.
716     */
tearDownInterfaces()717     public boolean tearDownInterfaces() {
718         Log.d(TAG, "tearing down interfaces in wificond");
719         // Explicitly refresh the wificodn handler because |tearDownInterfaces()|
720         // could be used to cleanup before we setup any interfaces.
721         if (!retrieveWificondAndRegisterForDeath()) {
722             return false;
723         }
724 
725         try {
726             for (Map.Entry<String, IWifiScannerImpl> entry : mWificondScanners.entrySet()) {
727                 entry.getValue().unsubscribeScanEvents();
728                 entry.getValue().unsubscribePnoScanEvents();
729             }
730             mWificond.tearDownInterfaces();
731             clearState();
732             return true;
733         } catch (RemoteException e) {
734             Log.e(TAG, "Failed to tear down interfaces due to remote exception");
735         }
736 
737         return false;
738     }
739 
740     /** Helper function to look up the interface handle using name */
getClientInterface(@onNull String ifaceName)741     private IClientInterface getClientInterface(@NonNull String ifaceName) {
742         return mClientInterfaces.get(ifaceName);
743     }
744 
745     /**
746      * Request signal polling.
747      *
748      * @param ifaceName Name of the interface on which to poll. The interface must have been
749      *                  already set up using
750      *{@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
751      *                  or {@link #setupInterfaceForSoftApMode(String)}.
752      *
753      * @return A {@link SignalPollResult} object containing interface statistics, or a null on
754      * error (e.g. the interface hasn't been set up yet).
755      */
signalPoll(@onNull String ifaceName)756     @Nullable public SignalPollResult signalPoll(@NonNull String ifaceName) {
757         IClientInterface iface = getClientInterface(ifaceName);
758         if (iface == null) {
759             Log.e(TAG, "No valid wificond client interface handler");
760             return null;
761         }
762 
763         int[] resultArray;
764         try {
765             resultArray = iface.signalPoll();
766             if (resultArray == null || resultArray.length != 4) {
767                 Log.e(TAG, "Invalid signal poll result from wificond");
768                 return null;
769             }
770         } catch (RemoteException e) {
771             Log.e(TAG, "Failed to do signal polling due to remote exception");
772             return null;
773         }
774         return new SignalPollResult(resultArray[0], resultArray[1], resultArray[3], resultArray[2]);
775     }
776 
777     /**
778      * Get current transmit (Tx) packet counters of the specified interface. The interface must
779      * have been already set up using
780      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
781      * or {@link #setupInterfaceForSoftApMode(String)}.
782      *
783      * @param ifaceName Name of the interface.
784      * @return {@link TxPacketCounters} of the current interface or null on error (e.g. when
785      * called before the interface has been set up).
786      */
getTxPacketCounters(@onNull String ifaceName)787     @Nullable public TxPacketCounters getTxPacketCounters(@NonNull String ifaceName) {
788         IClientInterface iface = getClientInterface(ifaceName);
789         if (iface == null) {
790             Log.e(TAG, "No valid wificond client interface handler");
791             return null;
792         }
793 
794         int[] resultArray;
795         try {
796             resultArray = iface.getPacketCounters();
797             if (resultArray == null || resultArray.length != 2) {
798                 Log.e(TAG, "Invalid signal poll result from wificond");
799                 return null;
800             }
801         } catch (RemoteException e) {
802             Log.e(TAG, "Failed to do signal polling due to remote exception");
803             return null;
804         }
805         return new TxPacketCounters(resultArray[0], resultArray[1]);
806     }
807 
808     /** Helper function to look up the scanner impl handle using name */
getScannerImpl(@onNull String ifaceName)809     private IWifiScannerImpl getScannerImpl(@NonNull String ifaceName) {
810         return mWificondScanners.get(ifaceName);
811     }
812 
813     /**
814      * Fetch the latest scan results of the indicated type for the specified interface. Note that
815      * this method fetches the latest results - it does not initiate a scan. Initiating a scan can
816      * be done using {@link #startScan(String, int, Set, List)} or
817      * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
818      *
819      * Note: The interface must have been already set up using
820      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
821      * or {@link #setupInterfaceForSoftApMode(String)}.
822      *
823      * @param ifaceName Name of the interface.
824      * @param scanType The type of scan result to be returned, can be
825      * {@link #SCAN_TYPE_SINGLE_SCAN} or {@link #SCAN_TYPE_PNO_SCAN}.
826      * @return Returns an array of {@link NativeScanResult} or an empty array on failure (e.g. when
827      * called before the interface has been set up).
828      */
getScanResults(@onNull String ifaceName, @ScanResultType int scanType)829     @NonNull public List<NativeScanResult> getScanResults(@NonNull String ifaceName,
830             @ScanResultType int scanType) {
831         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
832         if (scannerImpl == null) {
833             Log.e(TAG, "No valid wificond scanner interface handler");
834             return new ArrayList<>();
835         }
836         List<NativeScanResult> results = null;
837         try {
838             if (scanType == SCAN_TYPE_SINGLE_SCAN) {
839                 results = Arrays.asList(scannerImpl.getScanResults());
840             } else {
841                 results = Arrays.asList(scannerImpl.getPnoScanResults());
842             }
843         } catch (RemoteException e1) {
844             Log.e(TAG, "Failed to create ScanDetail ArrayList");
845         }
846         if (results == null) {
847             results = new ArrayList<>();
848         }
849         if (mVerboseLoggingEnabled) {
850             Log.d(TAG, "get " + results.size() + " scan results from wificond");
851         }
852 
853         return results;
854     }
855 
856     /**
857      * Return scan type for the parcelable {@link SingleScanSettings}
858      */
getScanType(@ifiAnnotations.ScanType int scanType)859     private static int getScanType(@WifiAnnotations.ScanType int scanType) {
860         switch (scanType) {
861             case WifiScanner.SCAN_TYPE_LOW_LATENCY:
862                 return IWifiScannerImpl.SCAN_TYPE_LOW_SPAN;
863             case WifiScanner.SCAN_TYPE_LOW_POWER:
864                 return IWifiScannerImpl.SCAN_TYPE_LOW_POWER;
865             case WifiScanner.SCAN_TYPE_HIGH_ACCURACY:
866                 return IWifiScannerImpl.SCAN_TYPE_HIGH_ACCURACY;
867             default:
868                 throw new IllegalArgumentException("Invalid scan type " + scanType);
869         }
870     }
871 
872     /**
873      * Start a scan using the specified parameters. A scan is an asynchronous operation. The
874      * result of the operation is returned in the {@link ScanEventCallback} registered when
875      * setting up an interface using
876      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
877      * The latest scans can be obtained using {@link #getScanResults(String, int)} and using a
878      * {@link #SCAN_TYPE_SINGLE_SCAN} for the {@code scanType}.
879      *
880      * Note: The interface must have been already set up using
881      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
882      * or {@link #setupInterfaceForSoftApMode(String)}.
883      *
884      * @param ifaceName Name of the interface on which to initiate the scan.
885      * @param scanType Type of scan to perform, can be any of
886      * {@link WifiScanner#SCAN_TYPE_HIGH_ACCURACY}, {@link WifiScanner#SCAN_TYPE_LOW_POWER}, or
887      * {@link WifiScanner#SCAN_TYPE_LOW_LATENCY}.
888      * @param freqs list of frequencies to scan for, if null scan all supported channels.
889      * @param hiddenNetworkSSIDs List of hidden networks to be scanned for, a null indicates that
890      *                           no hidden frequencies will be scanned for.
891      * @return Returns true on success, false on failure (e.g. when called before the interface
892      * has been set up).
893      */
startScan(@onNull String ifaceName, @WifiAnnotations.ScanType int scanType, @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs)894     public boolean startScan(@NonNull String ifaceName, @WifiAnnotations.ScanType int scanType,
895             @Nullable Set<Integer> freqs, @Nullable List<byte[]> hiddenNetworkSSIDs) {
896         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
897         if (scannerImpl == null) {
898             Log.e(TAG, "No valid wificond scanner interface handler");
899             return false;
900         }
901         SingleScanSettings settings = new SingleScanSettings();
902         try {
903             settings.scanType = getScanType(scanType);
904         } catch (IllegalArgumentException e) {
905             Log.e(TAG, "Invalid scan type ", e);
906             return false;
907         }
908         settings.channelSettings  = new ArrayList<>();
909         settings.hiddenNetworks  = new ArrayList<>();
910 
911         if (freqs != null) {
912             for (Integer freq : freqs) {
913                 ChannelSettings channel = new ChannelSettings();
914                 channel.frequency = freq;
915                 settings.channelSettings.add(channel);
916             }
917         }
918         if (hiddenNetworkSSIDs != null) {
919             for (byte[] ssid : hiddenNetworkSSIDs) {
920                 HiddenNetwork network = new HiddenNetwork();
921                 network.ssid = ssid;
922 
923                 // settings.hiddenNetworks is expected to be very small, so this shouldn't cause
924                 // any performance issues.
925                 if (!settings.hiddenNetworks.contains(network)) {
926                     settings.hiddenNetworks.add(network);
927                 }
928             }
929         }
930 
931         try {
932             return scannerImpl.scan(settings);
933         } catch (RemoteException e1) {
934             Log.e(TAG, "Failed to request scan due to remote exception");
935         }
936         return false;
937     }
938 
939     /**
940      * Request a PNO (Preferred Network Offload). The offload request and the scans are asynchronous
941      * operations. The result of the request are returned in the {@code callback} parameter which
942      * is an {@link PnoScanRequestCallback}. The scan results are are return in the
943      * {@link ScanEventCallback} which is registered when setting up an interface using
944      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}.
945      * The latest PNO scans can be obtained using {@link #getScanResults(String, int)} with the
946      * {@code scanType} set to {@link #SCAN_TYPE_PNO_SCAN}.
947      *
948      * Note: The interface must have been already set up using
949      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
950      * or {@link #setupInterfaceForSoftApMode(String)}.
951      *
952      * @param ifaceName Name of the interface on which to request a PNO.
953      * @param pnoSettings PNO scan configuration.
954      * @param executor The Executor on which to execute the callback.
955      * @param callback Callback for the results of the offload request.
956      * @return true on success, false on failure (e.g. when called before the interface has been set
957      * up).
958      */
startPnoScan(@onNull String ifaceName, @NonNull PnoSettings pnoSettings, @NonNull @CallbackExecutor Executor executor, @NonNull PnoScanRequestCallback callback)959     public boolean startPnoScan(@NonNull String ifaceName, @NonNull PnoSettings pnoSettings,
960             @NonNull @CallbackExecutor Executor executor,
961             @NonNull PnoScanRequestCallback callback) {
962         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
963         if (scannerImpl == null) {
964             Log.e(TAG, "No valid wificond scanner interface handler");
965             return false;
966         }
967 
968         if (callback == null || executor == null) {
969             Log.e(TAG, "startPnoScan called with a null callback");
970             return false;
971         }
972 
973         try {
974             boolean success = scannerImpl.startPnoScan(pnoSettings);
975             if (success) {
976                 executor.execute(callback::onPnoRequestSucceeded);
977             } else {
978                 executor.execute(callback::onPnoRequestFailed);
979             }
980             return success;
981         } catch (RemoteException e1) {
982             Log.e(TAG, "Failed to start pno scan due to remote exception");
983         }
984         return false;
985     }
986 
987     /**
988      * Stop PNO scan configured with
989      * {@link #startPnoScan(String, PnoSettings, Executor, PnoScanRequestCallback)}.
990      *
991      * Note: The interface must have been already set up using
992      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
993      * or {@link #setupInterfaceForSoftApMode(String)}.
994      *
995      * @param ifaceName Name of the interface on which the PNO scan was configured.
996      * @return true on success, false on failure (e.g. when called before the interface has been
997      * set up).
998      */
stopPnoScan(@onNull String ifaceName)999     public boolean stopPnoScan(@NonNull String ifaceName) {
1000         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
1001         if (scannerImpl == null) {
1002             Log.e(TAG, "No valid wificond scanner interface handler");
1003             return false;
1004         }
1005         try {
1006             return scannerImpl.stopPnoScan();
1007         } catch (RemoteException e1) {
1008             Log.e(TAG, "Failed to stop pno scan due to remote exception");
1009         }
1010         return false;
1011     }
1012 
1013     /**
1014      * Abort ongoing single scan started with {@link #startScan(String, int, Set, List)}. No failure
1015      * callback, e.g. {@link ScanEventCallback#onScanFailed()}, is triggered by this operation.
1016      *
1017      * Note: The interface must have been already set up using
1018      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
1019      * or {@link #setupInterfaceForSoftApMode(String)}. If the interface has not been set up then
1020      * this method has no impact.
1021      *
1022      * @param ifaceName Name of the interface on which the scan was started.
1023      */
abortScan(@onNull String ifaceName)1024     public void abortScan(@NonNull String ifaceName) {
1025         IWifiScannerImpl scannerImpl = getScannerImpl(ifaceName);
1026         if (scannerImpl == null) {
1027             Log.e(TAG, "No valid wificond scanner interface handler");
1028             return;
1029         }
1030         try {
1031             scannerImpl.abortScan();
1032         } catch (RemoteException e1) {
1033             Log.e(TAG, "Failed to request abortScan due to remote exception");
1034         }
1035     }
1036 
1037     /**
1038      * Query the list of valid frequencies (in MHz) for the provided band.
1039      * The result depends on the on the country code that has been set.
1040      *
1041      * @param band as specified by one of the WifiScanner.WIFI_BAND_* constants.
1042      * The following bands are supported:
1043      * {@link WifiScanner#WIFI_BAND_24_GHZ},
1044      * {@link WifiScanner#WIFI_BAND_5_GHZ},
1045      * {@link WifiScanner#WIFI_BAND_5_GHZ_DFS_ONLY},
1046      * {@link WifiScanner#WIFI_BAND_6_GHZ}
1047      * @return frequencies vector of valid frequencies (MHz), or an empty array for error.
1048      * @throws IllegalArgumentException if band is not recognized.
1049      */
getChannelsMhzForBand(@ifiAnnotations.WifiBandBasic int band)1050     public @NonNull int[] getChannelsMhzForBand(@WifiAnnotations.WifiBandBasic int band) {
1051         if (mWificond == null) {
1052             Log.e(TAG, "No valid wificond scanner interface handler");
1053             return new int[0];
1054         }
1055         int[] result = null;
1056         try {
1057             switch (band) {
1058                 case WifiScanner.WIFI_BAND_24_GHZ:
1059                     result = mWificond.getAvailable2gChannels();
1060                     break;
1061                 case WifiScanner.WIFI_BAND_5_GHZ:
1062                     result = mWificond.getAvailable5gNonDFSChannels();
1063                     break;
1064                 case WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY:
1065                     result = mWificond.getAvailableDFSChannels();
1066                     break;
1067                 case WifiScanner.WIFI_BAND_6_GHZ:
1068                     result = mWificond.getAvailable6gChannels();
1069                     break;
1070                 default:
1071                     throw new IllegalArgumentException("unsupported band " + band);
1072             }
1073         } catch (RemoteException e1) {
1074             Log.e(TAG, "Failed to request getChannelsForBand due to remote exception");
1075         }
1076         if (result == null) {
1077             result = new int[0];
1078         }
1079         return result;
1080     }
1081 
1082     /** Helper function to look up the interface handle using name */
getApInterface(@onNull String ifaceName)1083     private IApInterface getApInterface(@NonNull String ifaceName) {
1084         return mApInterfaces.get(ifaceName);
1085     }
1086 
1087     /**
1088      * Get the device phy capabilities for a given interface.
1089      *
1090      * Note: The interface must have been already set up using
1091      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
1092      * or {@link #setupInterfaceForSoftApMode(String)}.
1093      *
1094      * @return DeviceWiphyCapabilities or null on error (e.g. when called on an interface which has
1095      * not been set up).
1096      */
getDeviceWiphyCapabilities(@onNull String ifaceName)1097     @Nullable public DeviceWiphyCapabilities getDeviceWiphyCapabilities(@NonNull String ifaceName) {
1098         if (mWificond == null) {
1099             Log.e(TAG, "Can not query for device wiphy capabilities at this time");
1100             return null;
1101         }
1102 
1103         try {
1104             return mWificond.getDeviceWiphyCapabilities(ifaceName);
1105         } catch (RemoteException e) {
1106             return null;
1107         }
1108     }
1109 
1110     /**
1111      * Register the provided callback handler for SoftAp events. The interface must first be created
1112      * using {@link #setupInterfaceForSoftApMode(String)}. The callback registration is valid until
1113      * the interface is deleted using {@link #tearDownSoftApInterface(String)} (no deregistration
1114      * method is provided).
1115      * <p>
1116      * Note that only one callback can be registered at a time - any registration overrides previous
1117      * registrations.
1118      *
1119      * @param ifaceName Name of the interface on which to register the callback.
1120      * @param executor The Executor on which to execute the callbacks.
1121      * @param callback Callback for AP events.
1122      * @return true on success, false on failure (e.g. when called on an interface which has not
1123      * been set up).
1124      */
registerApCallback(@onNull String ifaceName, @NonNull @CallbackExecutor Executor executor, @NonNull SoftApCallback callback)1125     public boolean registerApCallback(@NonNull String ifaceName,
1126             @NonNull @CallbackExecutor Executor executor,
1127             @NonNull SoftApCallback callback) {
1128         IApInterface iface = getApInterface(ifaceName);
1129         if (iface == null) {
1130             Log.e(TAG, "No valid ap interface handler");
1131             return false;
1132         }
1133 
1134         if (callback == null || executor == null) {
1135             Log.e(TAG, "registerApCallback called with a null callback");
1136             return false;
1137         }
1138 
1139         try {
1140             IApInterfaceEventCallback wificondCallback = new ApInterfaceEventCallback(executor,
1141                     callback);
1142             mApInterfaceListeners.put(ifaceName, wificondCallback);
1143             boolean success = iface.registerCallback(wificondCallback);
1144             if (!success) {
1145                 Log.e(TAG, "Failed to register ap callback.");
1146                 return false;
1147             }
1148         } catch (RemoteException e) {
1149             Log.e(TAG, "Exception in registering AP callback: " + e);
1150             return false;
1151         }
1152         return true;
1153     }
1154 
1155     /**
1156      * Send a management frame on the specified interface at the specified rate. Useful for probing
1157      * the link with arbitrary frames.
1158      *
1159      * Note: The interface must have been already set up using
1160      * {@link #setupInterfaceForClientMode(String, Executor, ScanEventCallback, ScanEventCallback)}
1161      * or {@link #setupInterfaceForSoftApMode(String)}.
1162      *
1163      * @param ifaceName The interface on which to send the frame.
1164      * @param frame The raw byte array of the management frame to tramit.
1165      * @param mcs The MCS (modulation and coding scheme), i.e. rate, at which to transmit the
1166      *            frame. Specified per IEEE 802.11.
1167      * @param executor The Executor on which to execute the callbacks.
1168      * @param callback A {@link SendMgmtFrameCallback} callback for results of the operation.
1169      */
sendMgmtFrame(@onNull String ifaceName, @NonNull byte[] frame, int mcs, @NonNull @CallbackExecutor Executor executor, @NonNull SendMgmtFrameCallback callback)1170     public void sendMgmtFrame(@NonNull String ifaceName, @NonNull byte[] frame, int mcs,
1171             @NonNull @CallbackExecutor Executor executor,
1172             @NonNull SendMgmtFrameCallback callback) {
1173 
1174         if (callback == null || executor == null) {
1175             Log.e(TAG, "callback cannot be null!");
1176             return;
1177         }
1178 
1179         if (frame == null) {
1180             Log.e(TAG, "frame cannot be null!");
1181             executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
1182             return;
1183         }
1184 
1185         // TODO (b/112029045) validate mcs
1186         IClientInterface clientInterface = getClientInterface(ifaceName);
1187         if (clientInterface == null) {
1188             Log.e(TAG, "No valid wificond client interface handler");
1189             executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN));
1190             return;
1191         }
1192 
1193         if (!mSendMgmtFrameInProgress.compareAndSet(false, true)) {
1194             Log.e(TAG, "An existing management frame transmission is in progress!");
1195             executor.execute(() -> callback.onFailure(SEND_MGMT_FRAME_ERROR_ALREADY_STARTED));
1196             return;
1197         }
1198 
1199         SendMgmtFrameEvent sendMgmtFrameEvent = new SendMgmtFrameEvent(executor, callback);
1200         try {
1201             clientInterface.SendMgmtFrame(frame, sendMgmtFrameEvent, mcs);
1202         } catch (RemoteException e) {
1203             Log.e(TAG, "Exception while starting link probe: " + e);
1204             // Call sendMgmtFrameEvent.OnFailure() instead of callback.onFailure() so that
1205             // sendMgmtFrameEvent can clean up internal state, such as cancelling the timer.
1206             sendMgmtFrameEvent.OnFailure(SEND_MGMT_FRAME_ERROR_UNKNOWN);
1207         }
1208     }
1209 
1210     /**
1211      * Clear all internal handles.
1212      */
clearState()1213     private void clearState() {
1214         // Refresh handlers
1215         mClientInterfaces.clear();
1216         mWificondScanners.clear();
1217         mPnoScanEventHandlers.clear();
1218         mScanEventHandlers.clear();
1219         mApInterfaces.clear();
1220         mApInterfaceListeners.clear();
1221         mSendMgmtFrameInProgress.set(false);
1222     }
1223 
1224     /**
1225      * OEM parsed security type
1226      */
1227     public static class OemSecurityType {
1228         /** The protocol defined in {@link android.net.wifi.WifiAnnotations.Protocol}. */
1229         public final @WifiAnnotations.Protocol int protocol;
1230         /**
1231          * Supported key management types defined
1232          * in {@link android.net.wifi.WifiAnnotations.KeyMgmt}.
1233          */
1234         @NonNull public final List<Integer> keyManagement;
1235         /**
1236          * Supported pairwise cipher types defined
1237          * in {@link android.net.wifi.WifiAnnotations.Cipher}.
1238          */
1239         @NonNull public final List<Integer> pairwiseCipher;
1240         /** The group cipher type defined in {@link android.net.wifi.WifiAnnotations.Cipher}. */
1241         public final @WifiAnnotations.Cipher int groupCipher;
1242         /**
1243          * Default constructor for OemSecurityType
1244          *
1245          * @param protocol The protocol defined in
1246          *                 {@link android.net.wifi.WifiAnnotations.Protocol}.
1247          * @param keyManagement Supported key management types defined
1248          *                      in {@link android.net.wifi.WifiAnnotations.KeyMgmt}.
1249          * @param pairwiseCipher Supported pairwise cipher types defined
1250          *                       in {@link android.net.wifi.WifiAnnotations.Cipher}.
1251          * @param groupCipher The group cipher type defined
1252          *                    in {@link android.net.wifi.WifiAnnotations.Cipher}.
1253          */
OemSecurityType( @ifiAnnotations.Protocol int protocol, @NonNull List<Integer> keyManagement, @NonNull List<Integer> pairwiseCipher, @WifiAnnotations.Cipher int groupCipher)1254         public OemSecurityType(
1255                 @WifiAnnotations.Protocol int protocol,
1256                 @NonNull List<Integer> keyManagement,
1257                 @NonNull List<Integer> pairwiseCipher,
1258                 @WifiAnnotations.Cipher int groupCipher) {
1259             this.protocol = protocol;
1260             this.keyManagement = (keyManagement != null)
1261                 ? keyManagement : new ArrayList<Integer>();
1262             this.pairwiseCipher = (pairwiseCipher != null)
1263                 ? pairwiseCipher : new ArrayList<Integer>();
1264             this.groupCipher = groupCipher;
1265         }
1266     }
1267 
1268     /**
1269      * OEM information element parser for security types not parsed by the framework.
1270      *
1271      * The OEM method should use the method inputs {@code id}, {@code idExt}, and {@code bytes}
1272      * to perform the parsing. The method should place the results in an OemSecurityType objct.
1273      *
1274      * @param id The information element id.
1275      * @param idExt The information element extension id. This is valid only when id is
1276      *        the extension id, {@code 255}.
1277      * @param bytes The raw bytes of information element data, 'Element ID' and 'Length' are
1278      *              stripped off already.
1279      * @return an OemSecurityType object if this IE is parsed successfully, null otherwise.
1280      */
parseOemSecurityTypeElement( int id, int idExt, @NonNull byte[] bytes)1281     @Nullable public static OemSecurityType parseOemSecurityTypeElement(
1282             int id,
1283             int idExt,
1284             @NonNull byte[] bytes) {
1285         return null;
1286     }
1287 }
1288