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