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