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