1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi;
18 
19 import static android.app.AppOpsManager.MODE_ALLOWED;
20 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
21 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
22 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
23 import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL;
24 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
25 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
26 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
27 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
28 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
29 
30 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED;
31 
32 import android.annotation.CheckResult;
33 import android.annotation.NonNull;
34 import android.annotation.Nullable;
35 import android.app.AppOpsManager;
36 import android.bluetooth.BluetoothAdapter;
37 import android.content.BroadcastReceiver;
38 import android.content.ComponentName;
39 import android.content.Context;
40 import android.content.Intent;
41 import android.content.IntentFilter;
42 import android.content.pm.ApplicationInfo;
43 import android.content.pm.PackageInfo;
44 import android.content.pm.PackageManager;
45 import android.content.pm.ParceledListSlice;
46 import android.content.pm.ResolveInfo;
47 import android.net.DhcpInfo;
48 import android.net.DhcpResultsParcelable;
49 import android.net.InetAddresses;
50 import android.net.Network;
51 import android.net.NetworkStack;
52 import android.net.Uri;
53 import android.net.ip.IpClientUtil;
54 import android.net.wifi.IActionListener;
55 import android.net.wifi.IDppCallback;
56 import android.net.wifi.ILocalOnlyHotspotCallback;
57 import android.net.wifi.INetworkRequestMatchCallback;
58 import android.net.wifi.IOnWifiActivityEnergyInfoListener;
59 import android.net.wifi.IOnWifiUsabilityStatsListener;
60 import android.net.wifi.IScanResultsCallback;
61 import android.net.wifi.ISoftApCallback;
62 import android.net.wifi.ISuggestionConnectionStatusListener;
63 import android.net.wifi.ITrafficStateCallback;
64 import android.net.wifi.IWifiConnectedNetworkScorer;
65 import android.net.wifi.ScanResult;
66 import android.net.wifi.SoftApCapability;
67 import android.net.wifi.SoftApConfiguration;
68 import android.net.wifi.SoftApInfo;
69 import android.net.wifi.WifiAnnotations.WifiStandard;
70 import android.net.wifi.WifiClient;
71 import android.net.wifi.WifiConfiguration;
72 import android.net.wifi.WifiInfo;
73 import android.net.wifi.WifiManager;
74 import android.net.wifi.WifiManager.DeviceMobilityState;
75 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
76 import android.net.wifi.WifiManager.SuggestionConnectionStatusListener;
77 import android.net.wifi.WifiNetworkSuggestion;
78 import android.net.wifi.WifiScanner;
79 import android.net.wifi.WifiSsid;
80 import android.net.wifi.hotspot2.IProvisioningCallback;
81 import android.net.wifi.hotspot2.OsuProvider;
82 import android.net.wifi.hotspot2.PasspointConfiguration;
83 import android.os.AsyncTask;
84 import android.os.Binder;
85 import android.os.Build;
86 import android.os.Handler;
87 import android.os.HandlerExecutor;
88 import android.os.IBinder;
89 import android.os.Looper;
90 import android.os.Message;
91 import android.os.ParcelFileDescriptor;
92 import android.os.PersistableBundle;
93 import android.os.PowerManager;
94 import android.os.Process;
95 import android.os.RemoteException;
96 import android.os.UserHandle;
97 import android.os.UserManager;
98 import android.os.WorkSource;
99 import android.os.connectivity.WifiActivityEnergyInfo;
100 import android.provider.Settings;
101 import android.telephony.CarrierConfigManager;
102 import android.telephony.PhoneStateListener;
103 import android.telephony.SubscriptionManager;
104 import android.telephony.TelephonyManager;
105 import android.text.TextUtils;
106 import android.util.Log;
107 import android.util.MutableBoolean;
108 
109 import com.android.internal.annotations.GuardedBy;
110 import com.android.internal.annotations.VisibleForTesting;
111 import com.android.internal.util.AsyncChannel;
112 import com.android.net.module.util.Inet4AddressUtils;
113 import com.android.server.wifi.hotspot2.PasspointManager;
114 import com.android.server.wifi.hotspot2.PasspointProvider;
115 import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent;
116 import com.android.server.wifi.util.ApConfigUtil;
117 import com.android.server.wifi.util.ExternalCallbackTracker;
118 import com.android.server.wifi.util.RssiUtil;
119 import com.android.server.wifi.util.ScanResultUtil;
120 import com.android.server.wifi.util.WifiHandler;
121 import com.android.server.wifi.util.WifiPermissionsUtil;
122 import com.android.wifi.resources.R;
123 
124 import java.io.BufferedReader;
125 import java.io.FileDescriptor;
126 import java.io.FileNotFoundException;
127 import java.io.FileReader;
128 import java.io.IOException;
129 import java.io.PrintWriter;
130 import java.net.Inet4Address;
131 import java.net.InetAddress;
132 import java.security.GeneralSecurityException;
133 import java.security.KeyStore;
134 import java.security.cert.CertPath;
135 import java.security.cert.CertPathValidator;
136 import java.security.cert.CertificateFactory;
137 import java.security.cert.PKIXParameters;
138 import java.security.cert.X509Certificate;
139 import java.util.ArrayList;
140 import java.util.Arrays;
141 import java.util.Collections;
142 import java.util.HashMap;
143 import java.util.Iterator;
144 import java.util.List;
145 import java.util.Map;
146 import java.util.concurrent.CountDownLatch;
147 import java.util.concurrent.Executor;
148 import java.util.concurrent.TimeUnit;
149 
150 /**
151  * WifiService handles remote WiFi operation requests by implementing
152  * the IWifiManager interface.
153  */
154 public class WifiServiceImpl extends BaseWifiService {
155     private static final String TAG = "WifiService";
156     private static final int APP_INFO_FLAGS_SYSTEM_APP =
157             ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
158     private static final boolean VDBG = false;
159 
160     /** Max wait time for posting blocking runnables */
161     private static final int RUN_WITH_SCISSORS_TIMEOUT_MILLIS = 4000;
162 
163     private final ClientModeImpl mClientModeImpl;
164     private final ActiveModeWarden mActiveModeWarden;
165     private final ScanRequestProxy mScanRequestProxy;
166 
167     private final Context mContext;
168     private final FrameworkFacade mFacade;
169     private final Clock mClock;
170 
171     private final PowerManager mPowerManager;
172     private final AppOpsManager mAppOps;
173     private final UserManager mUserManager;
174     private final WifiCountryCode mCountryCode;
175 
176     /** Polls traffic stats and notifies clients */
177     private final WifiTrafficPoller mWifiTrafficPoller;
178     /** Tracks the persisted states for wi-fi & airplane mode */
179     private final WifiSettingsStore mSettingsStore;
180     /** Logs connection events and some general router and scan stats */
181     private final WifiMetrics mWifiMetrics;
182 
183     private final WifiInjector mWifiInjector;
184     /** Backup/Restore Module */
185     private final WifiBackupRestore mWifiBackupRestore;
186     private final SoftApBackupRestore mSoftApBackupRestore;
187     private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
188     private final WifiConfigManager mWifiConfigManager;
189     private final PasspointManager mPasspointManager;
190     private final WifiLog mLog;
191     /**
192      * Verbose logging flag. Toggled by developer options.
193      */
194     private boolean mVerboseLoggingEnabled = false;
195 
196     /**
197      * Asynchronous channel to ClientModeImpl
198      */
199     @VisibleForTesting
200     AsyncChannel mClientModeImplChannel;
201 
202     private final FrameworkFacade mFrameworkFacade;
203 
204     private final WifiPermissionsUtil mWifiPermissionsUtil;
205 
206     private final TetheredSoftApTracker mTetheredSoftApTracker;
207 
208     private final LohsSoftApTracker mLohsSoftApTracker;
209 
210     private WifiScanner mWifiScanner;
211 
212     /**
213      * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
214      */
215     public final class LocalOnlyRequestorCallback
216             implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback {
217         /**
218          * Called with requesting app has died.
219          */
220         @Override
onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor)221         public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) {
222             mLog.trace("onLocalOnlyHotspotRequestorDeath pid=%")
223                     .c(requestor.getPid()).flush();
224             mLohsSoftApTracker.stopByRequest(requestor);
225         }
226     }
227 
228     /**
229      * Handles interaction with ClientModeImpl
230      */
231     private class ClientModeImplHandler extends WifiHandler {
232         private AsyncChannel mCmiChannel;
233 
ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel)234         ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel) {
235             super(tag, looper);
236             mCmiChannel = asyncChannel;
237             mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler());
238         }
239 
240         @Override
handleMessage(Message msg)241         public void handleMessage(Message msg) {
242             super.handleMessage(msg);
243             switch (msg.what) {
244                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
245                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
246                         mClientModeImplChannel = mCmiChannel;
247                     } else {
248                         Log.e(TAG, "ClientModeImpl connection failure, error=" + msg.arg1);
249                         mClientModeImplChannel = null;
250                     }
251                     break;
252                 }
253                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
254                     Log.e(TAG, "ClientModeImpl channel lost, msg.arg1 =" + msg.arg1);
255                     mClientModeImplChannel = null;
256                     //Re-establish connection to state machine
257                     mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler());
258                     break;
259                 }
260                 default: {
261                     Log.d(TAG, "ClientModeImplHandler.handleMessage ignoring msg=" + msg);
262                     break;
263                 }
264             }
265         }
266     }
267 
268     /**
269      * Listen for phone call state events to get active data subcription id.
270      */
271     private class WifiPhoneStateListener extends PhoneStateListener {
WifiPhoneStateListener(Looper looper)272         WifiPhoneStateListener(Looper looper) {
273             super(new HandlerExecutor(new Handler(looper)));
274         }
275 
276         @Override
onActiveDataSubscriptionIdChanged(int subId)277         public void onActiveDataSubscriptionIdChanged(int subId) {
278             Log.d(TAG, "OBSERVED active data subscription change, subId: " + subId);
279 
280             mTetheredSoftApTracker.updateSoftApCapability(subId);
281             mActiveModeWarden.updateSoftApCapability(mTetheredSoftApTracker.getSoftApCapability());
282         }
283     }
284 
285     private final ClientModeImplHandler mClientModeImplHandler;
286     private final WifiLockManager mWifiLockManager;
287     private final WifiMulticastLockManager mWifiMulticastLockManager;
288     private final DppManager mDppManager;
289     private final WifiApConfigStore mWifiApConfigStore;
290     private final WifiThreadRunner mWifiThreadRunner;
291     private final MemoryStoreImpl mMemoryStoreImpl;
292     private final WifiScoreCard mWifiScoreCard;
293 
WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel)294     public WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel) {
295         mContext = context;
296         mWifiInjector = wifiInjector;
297         mClock = wifiInjector.getClock();
298 
299         mFacade = mWifiInjector.getFrameworkFacade();
300         mWifiMetrics = mWifiInjector.getWifiMetrics();
301         mWifiTrafficPoller = mWifiInjector.getWifiTrafficPoller();
302         mUserManager = mWifiInjector.getUserManager();
303         mCountryCode = mWifiInjector.getWifiCountryCode();
304         mClientModeImpl = mWifiInjector.getClientModeImpl();
305         mActiveModeWarden = mWifiInjector.getActiveModeWarden();
306         mScanRequestProxy = mWifiInjector.getScanRequestProxy();
307         mSettingsStore = mWifiInjector.getWifiSettingsStore();
308         mPowerManager = mContext.getSystemService(PowerManager.class);
309         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
310         mWifiLockManager = mWifiInjector.getWifiLockManager();
311         mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
312         mClientModeImplHandler = new ClientModeImplHandler(TAG,
313                 mWifiInjector.getAsyncChannelHandlerThread().getLooper(), asyncChannel);
314         mWifiBackupRestore = mWifiInjector.getWifiBackupRestore();
315         mSoftApBackupRestore = mWifiInjector.getSoftApBackupRestore();
316         mWifiApConfigStore = mWifiInjector.getWifiApConfigStore();
317         mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
318         mLog = mWifiInjector.makeLog(TAG);
319         mFrameworkFacade = wifiInjector.getFrameworkFacade();
320         mTetheredSoftApTracker = new TetheredSoftApTracker();
321         mActiveModeWarden.registerSoftApCallback(mTetheredSoftApTracker);
322         mLohsSoftApTracker = new LohsSoftApTracker();
323         mActiveModeWarden.registerLohsCallback(mLohsSoftApTracker);
324         mWifiNetworkSuggestionsManager = mWifiInjector.getWifiNetworkSuggestionsManager();
325         mDppManager = mWifiInjector.getDppManager();
326         mWifiThreadRunner = mWifiInjector.getWifiThreadRunner();
327         mWifiConfigManager = mWifiInjector.getWifiConfigManager();
328         mPasspointManager = mWifiInjector.getPasspointManager();
329         mWifiScoreCard = mWifiInjector.getWifiScoreCard();
330         mMemoryStoreImpl = new MemoryStoreImpl(mContext, mWifiInjector,
331                 mWifiScoreCard,  mWifiInjector.getWifiHealthMonitor());
332     }
333 
334     /**
335      * Check if we are ready to start wifi.
336      *
337      * First check if we will be restarting system services to decrypt the device. If the device is
338      * not encrypted, check if Wi-Fi needs to be enabled and start if needed
339      *
340      * This function is used only at boot time.
341      */
checkAndStartWifi()342     public void checkAndStartWifi() {
343         mWifiThreadRunner.post(() -> {
344             if (!mWifiConfigManager.loadFromStore()) {
345                 Log.e(TAG, "Failed to load from config store");
346             }
347             // config store is read, check if verbose logging is enabled.
348             enableVerboseLoggingInternal(getVerboseLoggingLevel());
349             // Check if wi-fi needs to be enabled
350             boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
351             Log.i(TAG,
352                     "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled"));
353 
354             mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility().initialize();
355             mContext.registerReceiver(
356                     new BroadcastReceiver() {
357                         @Override
358                         public void onReceive(Context context, Intent intent) {
359                             if (mSettingsStore.handleAirplaneModeToggled()) {
360                                 mActiveModeWarden.airplaneModeToggled();
361                             }
362                         }
363                     },
364                     new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
365 
366             mContext.registerReceiver(
367                     new BroadcastReceiver() {
368                         @Override
369                         public void onReceive(Context context, Intent intent) {
370                             int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE,
371                                     TelephonyManager.SIM_STATE_UNKNOWN);
372                             if (TelephonyManager.SIM_STATE_ABSENT == state) {
373                                 Log.d(TAG, "resetting networks because SIM was removed");
374                                 mClientModeImpl.resetSimAuthNetworks(
375                                         ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED);
376                             }
377                         }
378                     },
379                     new IntentFilter(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED));
380 
381             mContext.registerReceiver(
382                     new BroadcastReceiver() {
383                         @Override
384                         public void onReceive(Context context, Intent intent) {
385                             int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE,
386                                     TelephonyManager.SIM_STATE_UNKNOWN);
387                             if (TelephonyManager.SIM_STATE_LOADED == state) {
388                                 Log.d(TAG, "resetting networks because SIM was loaded");
389                                 mClientModeImpl.resetSimAuthNetworks(
390                                         ClientModeImpl.RESET_SIM_REASON_SIM_INSERTED);
391                             }
392                         }
393                     },
394                     new IntentFilter(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED));
395 
396             mContext.registerReceiver(
397                     new BroadcastReceiver() {
398                         private int mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
399                         @Override
400                         public void onReceive(Context context, Intent intent) {
401                             final int subId = intent.getIntExtra("subscription",
402                                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
403                             if (subId != mLastSubId) {
404                                 Log.d(TAG, "resetting networks as default data SIM is changed");
405                                 mClientModeImpl.resetSimAuthNetworks(
406                                         ClientModeImpl.RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED);
407                                 mLastSubId = subId;
408                             }
409                         }
410                     },
411                     new IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED));
412 
413             // Adding optimizations of only receiving broadcasts when wifi is enabled
414             // can result in race conditions when apps toggle wifi in the background
415             // without active user involvement. Always receive broadcasts.
416             registerForBroadcasts();
417             mInIdleMode = mPowerManager.isDeviceIdleMode();
418 
419             mClientModeImpl.initialize();
420             mActiveModeWarden.start();
421             registerForCarrierConfigChange();
422         });
423     }
424 
handleBootCompleted()425     public void handleBootCompleted() {
426         mWifiThreadRunner.post(() -> {
427             Log.d(TAG, "Handle boot completed");
428 
429             // Register for system broadcasts.
430             IntentFilter intentFilter = new IntentFilter();
431             intentFilter.addAction(Intent.ACTION_USER_REMOVED);
432             intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
433             intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
434             intentFilter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
435             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
436             intentFilter.addAction(Intent.ACTION_SHUTDOWN);
437             boolean trackEmergencyCallState = mContext.getResources().getBoolean(
438                     R.bool.config_wifi_turn_off_during_emergency_call);
439             if (trackEmergencyCallState) {
440                 intentFilter.addAction(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED);
441             }
442             mContext.registerReceiver(mReceiver, intentFilter);
443             mMemoryStoreImpl.start();
444             mPasspointManager.initializeProvisioner(
445                     mWifiInjector.getPasspointProvisionerHandlerThread().getLooper());
446             mClientModeImpl.handleBootCompleted();
447         });
448     }
449 
handleUserSwitch(int userId)450     public void handleUserSwitch(int userId) {
451         Log.d(TAG, "Handle user switch " + userId);
452         mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserSwitch(userId));
453     }
454 
handleUserUnlock(int userId)455     public void handleUserUnlock(int userId) {
456         Log.d(TAG, "Handle user unlock " + userId);
457         mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserUnlock(userId));
458     }
459 
handleUserStop(int userId)460     public void handleUserStop(int userId) {
461         Log.d(TAG, "Handle user stop " + userId);
462         mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserStop(userId));
463     }
464 
465     /**
466      * See {@link android.net.wifi.WifiManager#startScan}
467      *
468      * @param packageName Package name of the app that requests wifi scan.
469      * @param featureId The feature in the package
470      */
471     @Override
startScan(String packageName, String featureId)472     public boolean startScan(String packageName, String featureId) {
473         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
474             return false;
475         }
476 
477         int callingUid = Binder.getCallingUid();
478         long ident = Binder.clearCallingIdentity();
479         mLog.info("startScan uid=%").c(callingUid).flush();
480         synchronized (this) {
481             if (mInIdleMode) {
482                 // Need to send an immediate scan result broadcast in case the
483                 // caller is waiting for a result ..
484 
485                 // TODO: investigate if the logic to cancel scans when idle can move to
486                 // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
487                 // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
488                 // be sent directly until b/31398592 is fixed.
489                 sendFailedScanBroadcast();
490                 mScanPending = true;
491                 return false;
492             }
493         }
494         try {
495             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
496                     null);
497             Boolean scanSuccess = mWifiThreadRunner.call(() ->
498                     mScanRequestProxy.startScan(callingUid, packageName), null);
499             if (scanSuccess == null) {
500                 sendFailedScanBroadcast();
501                 return false;
502             }
503             if (!scanSuccess) {
504                 Log.e(TAG, "Failed to start scan");
505                 return false;
506             }
507         } catch (SecurityException e) {
508             Log.e(TAG, "Permission violation - startScan not allowed for"
509                     + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
510             return false;
511         } finally {
512             Binder.restoreCallingIdentity(ident);
513         }
514         return true;
515     }
516 
517     // Send a failed scan broadcast to indicate the current scan request failed.
sendFailedScanBroadcast()518     private void sendFailedScanBroadcast() {
519         // clear calling identity to send broadcast
520         long callingIdentity = Binder.clearCallingIdentity();
521         try {
522             Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
523             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
524             intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
525             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
526         } finally {
527             // restore calling identity
528             Binder.restoreCallingIdentity(callingIdentity);
529         }
530 
531     }
532 
533     /**
534      * WPS support in Client mode is deprecated.  Return null.
535      */
536     @Override
getCurrentNetworkWpsNfcConfigurationToken()537     public String getCurrentNetworkWpsNfcConfigurationToken() {
538         // while CLs are in flight, return null here, will be removed (b/72423090)
539         enforceNetworkStackPermission();
540         if (mVerboseLoggingEnabled) {
541             mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%")
542                     .c(Binder.getCallingUid()).flush();
543         }
544         return null;
545     }
546 
547     private boolean mInIdleMode;
548     private boolean mScanPending;
549 
handleIdleModeChanged()550     private void handleIdleModeChanged() {
551         boolean doScan = false;
552         synchronized (this) {
553             boolean idle = mPowerManager.isDeviceIdleMode();
554             if (mInIdleMode != idle) {
555                 mInIdleMode = idle;
556                 if (!idle) {
557                     if (mScanPending) {
558                         mScanPending = false;
559                         doScan = true;
560                     }
561                 }
562             }
563         }
564         if (doScan) {
565             // Someone requested a scan while we were idle; do a full scan now.
566             // A security check of the caller's identity was made when the request arrived via
567             // Binder. Now we'll pass the current process's identity to startScan().
568             startScan(mContext.getOpPackageName(), mContext.getAttributionTag());
569         }
570     }
571 
handleShutDown()572     private void handleShutDown() {
573         // Direct call to notify ActiveModeWarden as soon as possible with the assumption that
574         // notifyShuttingDown() doesn't have codes that may cause concurrentModificationException,
575         // e.g., access to a collection.
576         mActiveModeWarden.notifyShuttingDown();
577         mWifiThreadRunner.post(()-> {
578             // There is no explicit disconnection event in clientModeImpl during shutdown.
579             // Call resetConnectionState() so that connection duration is calculated
580             // before memory store write triggered by mMemoryStoreImpl.stop().
581             mWifiScoreCard.resetConnectionState();
582             mMemoryStoreImpl.stop();
583         });
584     }
585 
checkNetworkSettingsPermission(int pid, int uid)586     private boolean checkNetworkSettingsPermission(int pid, int uid) {
587         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
588                 == PERMISSION_GRANTED;
589     }
590 
checkNetworkSetupWizardPermission(int pid, int uid)591     private boolean checkNetworkSetupWizardPermission(int pid, int uid) {
592         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, pid, uid)
593                 == PackageManager.PERMISSION_GRANTED;
594     }
595 
checkNetworkStackPermission(int pid, int uid)596     private boolean checkNetworkStackPermission(int pid, int uid) {
597         return mContext.checkPermission(android.Manifest.permission.NETWORK_STACK, pid, uid)
598                 == PackageManager.PERMISSION_GRANTED;
599     }
600 
checkNetworkManagedProvisioningPermission(int pid, int uid)601     private boolean checkNetworkManagedProvisioningPermission(int pid, int uid) {
602         return mContext.checkPermission(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
603                 pid, uid) == PackageManager.PERMISSION_GRANTED;
604     }
605 
606     /**
607      * Helper method to check if the entity initiating the binder call has any of the signature only
608      * permissions.
609      */
isPrivileged(int pid, int uid)610     private boolean isPrivileged(int pid, int uid) {
611         return checkNetworkSettingsPermission(pid, uid)
612                 || checkNetworkSetupWizardPermission(pid, uid)
613                 || checkNetworkStackPermission(pid, uid)
614                 || checkNetworkManagedProvisioningPermission(pid, uid);
615     }
616 
617     /**
618      * Helper method to check if the entity initiating the binder call has setup wizard or settings
619      * permissions.
620      */
isSettingsOrSuw(int pid, int uid)621     private boolean isSettingsOrSuw(int pid, int uid) {
622         return checkNetworkSettingsPermission(pid, uid)
623                 || checkNetworkSetupWizardPermission(pid, uid);
624     }
625 
626     /** Helper method to check if the entity initiating the binder call is a system app. */
isSystem(String packageName, int uid)627     private boolean isSystem(String packageName, int uid) {
628         long ident = Binder.clearCallingIdentity();
629         try {
630             ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser(
631                     packageName, 0, UserHandle.getUserHandleForUid(uid));
632             return (info.flags & APP_INFO_FLAGS_SYSTEM_APP) != 0;
633         } catch (PackageManager.NameNotFoundException e) {
634             // In case of exception, assume unknown app (more strict checking)
635             // Note: This case will never happen since checkPackage is
636             // called to verify validity before checking App's version.
637         } finally {
638             Binder.restoreCallingIdentity(ident);
639         }
640         return false;
641     }
642 
643     /** Helper method to check if the entity initiating the binder call is a DO/PO app. */
isDeviceOrProfileOwner(int uid, String packageName)644     private boolean isDeviceOrProfileOwner(int uid, String packageName) {
645         return mWifiPermissionsUtil.isDeviceOwner(uid, packageName)
646                 || mWifiPermissionsUtil.isProfileOwner(uid, packageName);
647     }
648 
enforceNetworkSettingsPermission()649     private void enforceNetworkSettingsPermission() {
650         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
651                 "WifiService");
652     }
653 
checkAnyPermissionOf(String... permissions)654     private boolean checkAnyPermissionOf(String... permissions) {
655         for (String permission : permissions) {
656             if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
657                 return true;
658             }
659         }
660         return false;
661     }
662 
enforceAnyPermissionOf(String... permissions)663     private void enforceAnyPermissionOf(String... permissions) {
664         if (!checkAnyPermissionOf(permissions)) {
665             throw new SecurityException("Requires one of the following permissions: "
666                     + String.join(", ", permissions) + ".");
667         }
668     }
669 
enforceNetworkStackOrSettingsPermission()670     private void enforceNetworkStackOrSettingsPermission() {
671         enforceAnyPermissionOf(
672                 android.Manifest.permission.NETWORK_SETTINGS,
673                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
674     }
675 
enforceNetworkStackPermission()676     private void enforceNetworkStackPermission() {
677         // TODO(b/142554155): Only check for MAINLINE_NETWORK_STACK permission
678         boolean granted = mContext.checkCallingOrSelfPermission(
679                 android.Manifest.permission.NETWORK_STACK)
680                 == PackageManager.PERMISSION_GRANTED;
681         if (granted) {
682             return;
683         }
684         mContext.enforceCallingOrSelfPermission(
685                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "WifiService");
686     }
687 
enforceAccessPermission()688     private void enforceAccessPermission() {
689         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
690                 "WifiService");
691     }
692 
693     /**
694      * Checks whether the caller can change the wifi state.
695      * Possible results:
696      * 1. Operation is allowed. No exception thrown, and AppOpsManager.MODE_ALLOWED returned.
697      * 2. Operation is not allowed, and caller must be told about this. SecurityException is thrown.
698      * 3. Operation is not allowed, and caller must not be told about this (i.e. must silently
699      * ignore the operation). No exception is thrown, and AppOpsManager.MODE_IGNORED returned.
700      */
701     @CheckResult
enforceChangePermission(String callingPackage)702     private int enforceChangePermission(String callingPackage) {
703         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
704         if (checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())) {
705             return MODE_ALLOWED;
706         }
707         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
708                 "WifiService");
709 
710         return mAppOps.noteOp(
711                 AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Binder.getCallingUid(), callingPackage);
712     }
713 
enforceReadCredentialPermission()714     private void enforceReadCredentialPermission() {
715         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
716                                                 "WifiService");
717     }
718 
enforceMulticastChangePermission()719     private void enforceMulticastChangePermission() {
720         mContext.enforceCallingOrSelfPermission(
721                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
722                 "WifiService");
723     }
724 
enforceConnectivityInternalPermission()725     private void enforceConnectivityInternalPermission() {
726         mContext.enforceCallingOrSelfPermission(
727                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
728                 "ConnectivityService");
729     }
730 
enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)731     private void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) {
732         mWifiPermissionsUtil.enforceLocationPermission(pkgName, featureId, uid);
733     }
734 
735     /**
736      * Helper method to check if the app is allowed to access public API's deprecated in
737      * {@link Build.VERSION_CODES#Q}.
738      * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name.
739      */
isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid)740     private boolean isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid) {
741         return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q, uid)
742                 || isPrivileged(pid, uid)
743                 || isDeviceOrProfileOwner(uid, packageName)
744                 || isSystem(packageName, uid)
745                 // TODO(b/140540984): Remove this bypass.
746                 || mWifiPermissionsUtil.checkSystemAlertWindowPermission(uid, packageName);
747     }
748 
749     /**
750      * Helper method to check if the app is allowed to access public API's deprecated in
751      * {@link Build.VERSION_CODES#R}.
752      * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name.
753      */
isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid)754     private boolean isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid) {
755         return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.R, uid)
756                 || isPrivileged(pid, uid)
757                 || isDeviceOrProfileOwner(uid, packageName)
758                 || isSystem(packageName, uid);
759     }
760 
761     /**
762      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
763      * @param enable {@code true} to enable, {@code false} to disable.
764      * @return {@code true} if the enable/disable operation was
765      *         started or is already in the queue.
766      */
767     @Override
setWifiEnabled(String packageName, boolean enable)768     public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
769         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
770             return false;
771         }
772         boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());
773         if (!isPrivileged && !isDeviceOrProfileOwner(Binder.getCallingUid(), packageName)
774                 && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q,
775                   Binder.getCallingUid())
776                 && !isSystem(packageName, Binder.getCallingUid())) {
777             mLog.info("setWifiEnabled not allowed for uid=%")
778                     .c(Binder.getCallingUid()).flush();
779             return false;
780         }
781         // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
782         if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
783             mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
784             return false;
785         }
786 
787         // If SoftAp is enabled, only privileged apps are allowed to toggle wifi
788         if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
789             mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
790             return false;
791         }
792 
793         mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
794                 .c(Binder.getCallingUid()).c(enable).flush();
795         long ident = Binder.clearCallingIdentity();
796         try {
797             if (!mSettingsStore.handleWifiToggled(enable)) {
798                 // Nothing to do if wifi cannot be toggled
799                 return true;
800             }
801         } finally {
802             Binder.restoreCallingIdentity(ident);
803         }
804         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) {
805             mWifiMetrics.logUserActionEvent(enable ? UserActionEvent.EVENT_TOGGLE_WIFI_ON
806                     : UserActionEvent.EVENT_TOGGLE_WIFI_OFF);
807         }
808         mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
809         mActiveModeWarden.wifiToggled();
810         return true;
811     }
812 
813     /**
814      * see {@link WifiManager#getWifiState()}
815      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
816      *         {@link WifiManager#WIFI_STATE_DISABLING},
817      *         {@link WifiManager#WIFI_STATE_ENABLED},
818      *         {@link WifiManager#WIFI_STATE_ENABLING},
819      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
820      */
821     @Override
getWifiEnabledState()822     public int getWifiEnabledState() {
823         enforceAccessPermission();
824         if (mVerboseLoggingEnabled) {
825             mLog.info("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
826         }
827         return mClientModeImpl.syncGetWifiState();
828     }
829 
830     /**
831      * see {@link WifiManager#getWifiApState()}
832      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
833      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
834      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
835      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
836      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
837      */
838     @Override
getWifiApEnabledState()839     public int getWifiApEnabledState() {
840         enforceAccessPermission();
841         if (mVerboseLoggingEnabled) {
842             mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
843         }
844         return mTetheredSoftApTracker.getState();
845     }
846 
847     /**
848      * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
849      *
850      * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
851      *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
852      *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
853      *
854      * @param ifaceName String name of the updated interface
855      * @param mode new operating mode of the interface
856      *
857      * @throws SecurityException if the caller does not have permission to call update
858      */
859     @Override
updateInterfaceIpState(String ifaceName, int mode)860     public void updateInterfaceIpState(String ifaceName, int mode) {
861         // NETWORK_STACK is a signature only permission.
862         enforceNetworkStackPermission();
863         mLog.info("updateInterfaceIpState uid=%").c(Binder.getCallingUid()).flush();
864 
865         // hand off the work to our handler thread
866         mWifiThreadRunner.post(() -> mLohsSoftApTracker.updateInterfaceIpState(ifaceName, mode));
867     }
868 
869     /**
870      * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
871      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
872      * @return {@code true} if softap start was triggered
873      * @throws SecurityException if the caller does not have permission to start softap
874      */
875     @Override
startSoftAp(WifiConfiguration wifiConfig)876     public boolean startSoftAp(WifiConfiguration wifiConfig) {
877         // NETWORK_STACK is a signature only permission.
878         enforceNetworkStackPermission();
879 
880         mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
881 
882         SoftApConfiguration softApConfig = null;
883         if (wifiConfig != null) {
884             softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig);
885             if (softApConfig == null) {
886                 return false;
887             }
888         }
889 
890         if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
891             mLog.err("Tethering is already active.").flush();
892             return false;
893         }
894 
895         if (!mWifiThreadRunner.call(
896                 () -> mActiveModeWarden.canRequestMoreSoftApManagers(), false)) {
897             // Take down LOHS if it is up.
898             mLohsSoftApTracker.stopAll();
899         }
900 
901         if (!startSoftApInternal(new SoftApModeConfiguration(
902                 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
903                 mTetheredSoftApTracker.getSoftApCapability()))) {
904             mTetheredSoftApTracker.setFailedWhileEnabling();
905             return false;
906         }
907 
908         return true;
909     }
910 
validateSoftApBand(int apBand)911     private boolean validateSoftApBand(int apBand) {
912         if (!ApConfigUtil.isBandValid(apBand)) {
913             mLog.err("Invalid SoftAp band. ").flush();
914             return false;
915         }
916 
917         if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_5GHZ)
918                 && !is5GhzBandSupportedInternal()) {
919             mLog.err("Can not start softAp with 5GHz band, not supported.").flush();
920             return false;
921         }
922 
923         if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_6GHZ)) {
924             if (!is6GhzBandSupportedInternal()
925                     || !mContext.getResources().getBoolean(
926                             R.bool.config_wifiSoftap6ghzSupported)) {
927                 mLog.err("Can not start softAp with 6GHz band, not supported.").flush();
928                 return false;
929             }
930         }
931 
932         return true;
933     }
934 
935     /**
936      * see {@link android.net.wifi.WifiManager#startTetheredHotspot(SoftApConfiguration)}
937      * @param softApConfig SSID, security and channel details as part of SoftApConfiguration
938      * @return {@code true} if softap start was triggered
939      * @throws SecurityException if the caller does not have permission to start softap
940      */
941     @Override
startTetheredHotspot(@ullable SoftApConfiguration softApConfig)942     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) {
943         // NETWORK_STACK is a signature only permission.
944         enforceNetworkStackPermission();
945 
946         mLog.info("startTetheredHotspot uid=%").c(Binder.getCallingUid()).flush();
947 
948         if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
949             mLog.err("Tethering is already active.").flush();
950             return false;
951         }
952 
953         if (!mWifiThreadRunner.call(
954                 () -> mActiveModeWarden.canRequestMoreSoftApManagers(), false)) {
955             // Take down LOHS if it is up.
956             mLohsSoftApTracker.stopAll();
957         }
958 
959         if (!startSoftApInternal(new SoftApModeConfiguration(
960                 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
961                 mTetheredSoftApTracker.getSoftApCapability()))) {
962             mTetheredSoftApTracker.setFailedWhileEnabling();
963             return false;
964         }
965 
966         return true;
967     }
968 
969     /**
970      * Internal method to start softap mode. Callers of this method should have already checked
971      * proper permissions beyond the NetworkStack permission.
972      */
startSoftApInternal(SoftApModeConfiguration apConfig)973     private boolean startSoftApInternal(SoftApModeConfiguration apConfig) {
974         int uid = Binder.getCallingUid();
975         boolean privileged = isSettingsOrSuw(Binder.getCallingPid(), uid);
976         mLog.trace("startSoftApInternal uid=% mode=%")
977                 .c(uid).c(apConfig.getTargetMode()).flush();
978 
979         // null wifiConfig is a meaningful input for CMD_SET_AP; it means to use the persistent
980         // AP config.
981         SoftApConfiguration softApConfig = apConfig.getSoftApConfiguration();
982         if (softApConfig != null
983                 && (!WifiApConfigStore.validateApWifiConfiguration(softApConfig, privileged)
984                     || !validateSoftApBand(softApConfig.getBand()))) {
985             Log.e(TAG, "Invalid SoftApConfiguration");
986             return false;
987         }
988 
989         mActiveModeWarden.startSoftAp(apConfig);
990         return true;
991     }
992 
993     /**
994      * see {@link android.net.wifi.WifiManager#stopSoftAp()}
995      * @return {@code true} if softap stop was triggered
996      * @throws SecurityException if the caller does not have permission to stop softap
997      */
998     @Override
stopSoftAp()999     public boolean stopSoftAp() {
1000         // NETWORK_STACK is a signature only permission.
1001         enforceNetworkStackPermission();
1002 
1003         // only permitted callers are allowed to this point - they must have gone through
1004         // connectivity service since this method is protected with the NETWORK_STACK PERMISSION
1005 
1006         mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
1007 
1008         stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
1009         return true;
1010     }
1011 
1012     /**
1013      * Internal method to stop softap mode.
1014      *
1015      * Callers of this method should have already checked
1016      * proper permissions beyond the NetworkStack permission.
1017      *
1018      * @param mode the operating mode of APs to bring down (ex,
1019      *             {@link WifiManager.IFACE_IP_MODE_TETHERED} or
1020      *             {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
1021      *             Use {@link WifiManager.IFACE_IP_MODE_UNSPECIFIED} to stop all APs.
1022      */
stopSoftApInternal(int mode)1023     private void stopSoftApInternal(int mode) {
1024         mLog.trace("stopSoftApInternal uid=% mode=%").c(Binder.getCallingUid()).c(mode).flush();
1025 
1026         mActiveModeWarden.stopSoftAp(mode);
1027     }
1028 
1029     /**
1030      * SoftAp callback
1031      */
1032     private final class TetheredSoftApTracker implements WifiManager.SoftApCallback {
1033         /**
1034          * State of tethered SoftAP
1035          * One of:  {@link WifiManager#WIFI_AP_STATE_DISABLED},
1036          *          {@link WifiManager#WIFI_AP_STATE_DISABLING},
1037          *          {@link WifiManager#WIFI_AP_STATE_ENABLED},
1038          *          {@link WifiManager#WIFI_AP_STATE_ENABLING},
1039          *          {@link WifiManager#WIFI_AP_STATE_FAILED}
1040          */
1041         private final Object mLock = new Object();
1042         private int mTetheredSoftApState = WIFI_AP_STATE_DISABLED;
1043         private List<WifiClient> mTetheredSoftApConnectedClients = new ArrayList<>();
1044         private SoftApInfo mTetheredSoftApInfo = new SoftApInfo();
1045         // TODO: We need to maintain two capability. One for LTE + SAP and one for WIFI + SAP
1046         private SoftApCapability mTetheredSoftApCapability = null;
1047 
getState()1048         public int getState() {
1049             synchronized (mLock) {
1050                 return mTetheredSoftApState;
1051             }
1052         }
1053 
setEnablingIfAllowed()1054         public boolean setEnablingIfAllowed() {
1055             synchronized (mLock) {
1056                 if (mTetheredSoftApState != WIFI_AP_STATE_DISABLED
1057                         && mTetheredSoftApState != WIFI_AP_STATE_FAILED) {
1058                     return false;
1059                 }
1060                 mTetheredSoftApState = WIFI_AP_STATE_ENABLING;
1061                 return true;
1062             }
1063         }
1064 
setFailedWhileEnabling()1065         public void setFailedWhileEnabling() {
1066             synchronized (mLock) {
1067                 if (mTetheredSoftApState == WIFI_AP_STATE_ENABLING) {
1068                     mTetheredSoftApState = WIFI_AP_STATE_FAILED;
1069                 }
1070             }
1071         }
1072 
getConnectedClients()1073         public List<WifiClient> getConnectedClients() {
1074             synchronized (mLock) {
1075                 return mTetheredSoftApConnectedClients;
1076             }
1077         }
1078 
getSoftApInfo()1079         public SoftApInfo getSoftApInfo() {
1080             synchronized (mLock) {
1081                 return mTetheredSoftApInfo;
1082             }
1083         }
1084 
getSoftApCapability()1085         public SoftApCapability getSoftApCapability() {
1086             synchronized (mLock) {
1087                 if (mTetheredSoftApCapability == null) {
1088                     mTetheredSoftApCapability = ApConfigUtil.updateCapabilityFromResource(mContext);
1089                 }
1090                 return mTetheredSoftApCapability;
1091             }
1092         }
1093 
updateSoftApCapability(int subId)1094         public void updateSoftApCapability(int subId) {
1095             synchronized (mLock) {
1096                 CarrierConfigManager carrierConfigManager =
1097                         (CarrierConfigManager) mContext.getSystemService(
1098                         Context.CARRIER_CONFIG_SERVICE);
1099                 if (carrierConfigManager == null) return;
1100                 PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
1101                 if (carrierConfig == null) return;
1102                 int carrierMaxClient = carrierConfig.getInt(
1103                         CarrierConfigManager.Wifi.KEY_HOTSPOT_MAX_CLIENT_COUNT);
1104                 int finalSupportedClientNumber = mContext.getResources().getInteger(
1105                         R.integer.config_wifiHardwareSoftapMaxClientCount);
1106                 if (carrierMaxClient > 0) {
1107                     finalSupportedClientNumber = Math.min(finalSupportedClientNumber,
1108                             carrierMaxClient);
1109                 }
1110                 if (finalSupportedClientNumber == getSoftApCapability().getMaxSupportedClients()) {
1111                     return;
1112                 }
1113                 mTetheredSoftApCapability.setMaxSupportedClients(
1114                         finalSupportedClientNumber);
1115             }
1116             onCapabilityChanged(mTetheredSoftApCapability);
1117         }
1118 
1119         private final ExternalCallbackTracker<ISoftApCallback> mRegisteredSoftApCallbacks =
1120                 new ExternalCallbackTracker<>(mClientModeImplHandler);
1121 
registerSoftApCallback(IBinder binder, ISoftApCallback callback, int callbackIdentifier)1122         public boolean registerSoftApCallback(IBinder binder, ISoftApCallback callback,
1123                 int callbackIdentifier) {
1124             return mRegisteredSoftApCallbacks.add(binder, callback, callbackIdentifier);
1125         }
1126 
unregisterSoftApCallback(int callbackIdentifier)1127         public void unregisterSoftApCallback(int callbackIdentifier) {
1128             mRegisteredSoftApCallbacks.remove(callbackIdentifier);
1129         }
1130 
1131         /**
1132          * Called when soft AP state changes.
1133          *
1134          * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
1135          *        {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
1136          *        {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
1137          * @param failureReason reason when in failed state. One of
1138          *        {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL}
1139          */
1140         @Override
onStateChanged(int state, int failureReason)1141         public void onStateChanged(int state, int failureReason) {
1142             synchronized (mLock) {
1143                 mTetheredSoftApState = state;
1144             }
1145 
1146             Iterator<ISoftApCallback> iterator =
1147                     mRegisteredSoftApCallbacks.getCallbacks().iterator();
1148             while (iterator.hasNext()) {
1149                 ISoftApCallback callback = iterator.next();
1150                 try {
1151                     callback.onStateChanged(state, failureReason);
1152                 } catch (RemoteException e) {
1153                     Log.e(TAG, "onStateChanged: remote exception -- " + e);
1154                     // TODO(b/138863863) remove does nothing, getCallbacks() returns a copy
1155                     iterator.remove();
1156                 }
1157             }
1158         }
1159 
1160         /**
1161          * Called when the connected clients to soft AP changes.
1162          *
1163          * @param clients connected clients to soft AP
1164          */
1165         @Override
onConnectedClientsChanged(List<WifiClient> clients)1166         public void onConnectedClientsChanged(List<WifiClient> clients) {
1167             synchronized (mLock) {
1168                 mTetheredSoftApConnectedClients = new ArrayList<>(clients);
1169             }
1170 
1171             Iterator<ISoftApCallback> iterator =
1172                     mRegisteredSoftApCallbacks.getCallbacks().iterator();
1173             while (iterator.hasNext()) {
1174                 ISoftApCallback callback = iterator.next();
1175                 try {
1176                     callback.onConnectedClientsChanged(mTetheredSoftApConnectedClients);
1177                 } catch (RemoteException e) {
1178                     Log.e(TAG, "onConnectedClientsChanged: remote exception -- " + e);
1179                     // TODO(b/138863863) remove does nothing, getCallbacks() returns a copy
1180                     iterator.remove();
1181                 }
1182             }
1183         }
1184 
1185         /**
1186          * Called when information of softap changes.
1187          *
1188          * @param softApInfo is the softap information. {@link SoftApInfo}
1189          */
1190         @Override
onInfoChanged(SoftApInfo softApInfo)1191         public void onInfoChanged(SoftApInfo softApInfo) {
1192             synchronized (mLock) {
1193                 mTetheredSoftApInfo = new SoftApInfo(softApInfo);
1194             }
1195 
1196             Iterator<ISoftApCallback> iterator =
1197                     mRegisteredSoftApCallbacks.getCallbacks().iterator();
1198             while (iterator.hasNext()) {
1199                 ISoftApCallback callback = iterator.next();
1200                 try {
1201                     callback.onInfoChanged(mTetheredSoftApInfo);
1202                 } catch (RemoteException e) {
1203                     Log.e(TAG, "onInfoChanged: remote exception -- " + e);
1204                 }
1205             }
1206         }
1207 
1208         /**
1209          * Called when capability of softap changes.
1210          *
1211          * @param capability is the softap capability. {@link SoftApCapability}
1212          */
1213         @Override
onCapabilityChanged(SoftApCapability capability)1214         public void onCapabilityChanged(SoftApCapability capability) {
1215             synchronized (mLock) {
1216                 mTetheredSoftApCapability = new SoftApCapability(capability);
1217             }
1218 
1219             Iterator<ISoftApCallback> iterator =
1220                     mRegisteredSoftApCallbacks.getCallbacks().iterator();
1221             while (iterator.hasNext()) {
1222                 ISoftApCallback callback = iterator.next();
1223                 try {
1224                     callback.onCapabilityChanged(mTetheredSoftApCapability);
1225                 } catch (RemoteException e) {
1226                     Log.e(TAG, "onCapabiliyChanged: remote exception -- " + e);
1227                 }
1228             }
1229         }
1230 
1231         /**
1232          * Called when client trying to connect but device blocked the client with specific reason.
1233          *
1234          * @param client the currently blocked client.
1235          * @param blockedReason one of blocked reason from
1236          * {@link WifiManager.SapClientBlockedReason}
1237          */
1238         @Override
onBlockedClientConnecting(WifiClient client, int blockedReason)1239         public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
1240             Iterator<ISoftApCallback> iterator =
1241                     mRegisteredSoftApCallbacks.getCallbacks().iterator();
1242             while (iterator.hasNext()) {
1243                 ISoftApCallback callback = iterator.next();
1244                 try {
1245                     callback.onBlockedClientConnecting(client, blockedReason);
1246                 } catch (RemoteException e) {
1247                     Log.e(TAG, "onBlockedClientConnecting: remote exception -- " + e);
1248                 }
1249             }
1250         }
1251     }
1252 
1253     /**
1254      * Implements LOHS behavior on top of the existing SoftAp API.
1255      */
1256     private final class LohsSoftApTracker implements WifiManager.SoftApCallback {
1257         @GuardedBy("mLocalOnlyHotspotRequests")
1258         private final HashMap<Integer, LocalOnlyHotspotRequestInfo>
1259                 mLocalOnlyHotspotRequests = new HashMap<>();
1260 
1261         /** Currently-active config, to be sent to shared clients registering later. */
1262         @GuardedBy("mLocalOnlyHotspotRequests")
1263         private SoftApModeConfiguration mActiveConfig = null;
1264 
1265         /**
1266          * Whether we are currently operating in exclusive mode (i.e. whether a custom config is
1267          * active).
1268          */
1269         @GuardedBy("mLocalOnlyHotspotRequests")
1270         private boolean mIsExclusive = false;
1271 
1272         @GuardedBy("mLocalOnlyHotspotRequests")
1273         private String mLohsInterfaceName;
1274 
1275         /**
1276          * State of local-only hotspot
1277          * One of:  {@link WifiManager#WIFI_AP_STATE_DISABLED},
1278          *          {@link WifiManager#WIFI_AP_STATE_DISABLING},
1279          *          {@link WifiManager#WIFI_AP_STATE_ENABLED},
1280          *          {@link WifiManager#WIFI_AP_STATE_ENABLING},
1281          *          {@link WifiManager#WIFI_AP_STATE_FAILED}
1282          */
1283         @GuardedBy("mLocalOnlyHotspotRequests")
1284         private int mLohsState = WIFI_AP_STATE_DISABLED;
1285 
1286         @GuardedBy("mLocalOnlyHotspotRequests")
1287         private int mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
1288 
1289         private SoftApCapability mLohsSoftApCapability = null;
1290 
getSoftApCapability()1291         public SoftApCapability getSoftApCapability() {
1292             if (mLohsSoftApCapability == null) {
1293                 mLohsSoftApCapability =  ApConfigUtil.updateCapabilityFromResource(mContext);
1294             }
1295             return mLohsSoftApCapability;
1296         }
1297 
updateInterfaceIpState(String ifaceName, int mode)1298         public void updateInterfaceIpState(String ifaceName, int mode) {
1299             // update interface IP state related to local-only hotspot
1300             synchronized (mLocalOnlyHotspotRequests) {
1301                 Log.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
1302                         + " previous LOHS mode= " + mLohsInterfaceMode);
1303 
1304                 switch (mode) {
1305                     case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
1306                         // first make sure we have registered requests.
1307                         if (mLocalOnlyHotspotRequests.isEmpty()) {
1308                             // we don't have requests...  stop the hotspot
1309                             Log.wtf(TAG, "Starting LOHS without any requests?");
1310                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1311                             return;
1312                         }
1313                         // LOHS is ready to go!  Call our registered requestors!
1314                         mLohsInterfaceName = ifaceName;
1315                         mLohsInterfaceMode = mode;
1316                         sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked();
1317                         break;
1318                     case WifiManager.IFACE_IP_MODE_TETHERED:
1319                         if (mLohsInterfaceName != null
1320                                 && mLohsInterfaceName.equals(ifaceName)) {
1321                             /* This shouldn't happen except in a race, but if it does, tear down
1322                              * the LOHS and let tethering win.
1323                              *
1324                              * If concurrent SAPs are allowed, the interface names will differ,
1325                              * so we don't have to check the config here.
1326                              */
1327                             Log.e(TAG, "Unexpected IP mode change on " + ifaceName);
1328                             mLohsInterfaceName = null;
1329                             mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
1330                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1331                                     LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
1332                         }
1333                         break;
1334                     case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR:
1335                         if (ifaceName == null) {
1336                             // All softAps
1337                             mLohsInterfaceName = null;
1338                             mLohsInterfaceMode = mode;
1339                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1340                                     LocalOnlyHotspotCallback.ERROR_GENERIC);
1341                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1342                         } else if (ifaceName.equals(mLohsInterfaceName)) {
1343                             mLohsInterfaceName = null;
1344                             mLohsInterfaceMode = mode;
1345                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1346                                     LocalOnlyHotspotCallback.ERROR_GENERIC);
1347                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1348                         } else {
1349                             // Not for LOHS. This is the wrong place to do this, but...
1350                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
1351                         }
1352                         break;
1353                     case WifiManager.IFACE_IP_MODE_UNSPECIFIED:
1354                         if (ifaceName == null || ifaceName.equals(mLohsInterfaceName)) {
1355                             mLohsInterfaceName = null;
1356                             mLohsInterfaceMode = mode;
1357                         }
1358                         break;
1359                     default:
1360                         mLog.warn("updateInterfaceIpState: unknown mode %").c(mode).flush();
1361                 }
1362             }
1363         }
1364 
1365         /**
1366          * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest
1367          * callers and clear the registrations.
1368          *
1369          * Callers should already hold the mLocalOnlyHotspotRequests lock.
1370          */
1371         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason)1372         private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason) {
1373             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1374                 try {
1375                     requestor.sendHotspotFailedMessage(reason);
1376                     requestor.unlinkDeathRecipient();
1377                 } catch (RemoteException e) {
1378                     // This will be cleaned up by binder death handling
1379                 }
1380             }
1381 
1382             // Since all callers were notified, now clear the registrations.
1383             mLocalOnlyHotspotRequests.clear();
1384         }
1385 
1386         /**
1387          * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest
1388          * callers and clear the registrations.
1389          *
1390          * Callers should already hold the mLocalOnlyHotspotRequests lock.
1391          */
1392         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked()1393         private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() {
1394             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1395                 try {
1396                     requestor.sendHotspotStoppedMessage();
1397                     requestor.unlinkDeathRecipient();
1398                 } catch (RemoteException e) {
1399                     // This will be cleaned up by binder death handling
1400                 }
1401             }
1402 
1403             // Since all callers were notified, now clear the registrations.
1404             mLocalOnlyHotspotRequests.clear();
1405         }
1406 
1407         /**
1408          * Add a new LOHS client
1409          */
start(int pid, LocalOnlyHotspotRequestInfo request)1410         private int start(int pid, LocalOnlyHotspotRequestInfo request) {
1411             synchronized (mLocalOnlyHotspotRequests) {
1412                 // does this caller already have a request?
1413                 if (mLocalOnlyHotspotRequests.get(pid) != null) {
1414                     mLog.trace("caller already has an active request").flush();
1415                     throw new IllegalStateException(
1416                             "Caller already has an active LocalOnlyHotspot request");
1417                 }
1418 
1419                 // Never accept exclusive requests (with custom configuration) at the same time as
1420                 // shared requests.
1421                 if (!mLocalOnlyHotspotRequests.isEmpty()) {
1422                     boolean requestIsExclusive = request.getCustomConfig() != null;
1423                     if (mIsExclusive || requestIsExclusive) {
1424                         mLog.trace("Cannot share with existing LOHS request due to custom config")
1425                                 .flush();
1426                         return LocalOnlyHotspotCallback.ERROR_GENERIC;
1427                     }
1428                 }
1429 
1430                 // At this point, the request is accepted.
1431                 if (mLocalOnlyHotspotRequests.isEmpty()) {
1432                     startForFirstRequestLocked(request);
1433                 } else if (mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) {
1434                     // LOHS has already started up for an earlier request, so we can send the
1435                     // current config to the incoming request right away.
1436                     try {
1437                         mLog.trace("LOHS already up, trigger onStarted callback").flush();
1438                         request.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration());
1439                     } catch (RemoteException e) {
1440                         return LocalOnlyHotspotCallback.ERROR_GENERIC;
1441                     }
1442                 }
1443 
1444                 mLocalOnlyHotspotRequests.put(pid, request);
1445                 return LocalOnlyHotspotCallback.REQUEST_REGISTERED;
1446             }
1447         }
1448 
1449         @GuardedBy("mLocalOnlyHotspotRequests")
startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request)1450         private void startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request) {
1451             int band = SoftApConfiguration.BAND_2GHZ;
1452 
1453             // For auto only
1454             if (hasAutomotiveFeature(mContext)) {
1455                 if (mContext.getResources().getBoolean(R.bool.config_wifiLocalOnlyHotspot6ghz)
1456                         && mContext.getResources().getBoolean(R.bool.config_wifiSoftap6ghzSupported)
1457                         && is6GhzBandSupportedInternal()) {
1458                     band = SoftApConfiguration.BAND_6GHZ;
1459                 } else if (mContext.getResources().getBoolean(
1460                         R.bool.config_wifi_local_only_hotspot_5ghz)
1461                         && is5GhzBandSupportedInternal()) {
1462                     band = SoftApConfiguration.BAND_5GHZ;
1463                 }
1464             }
1465 
1466             SoftApConfiguration softApConfig = WifiApConfigStore.generateLocalOnlyHotspotConfig(
1467                     mContext, band, request.getCustomConfig());
1468 
1469             mActiveConfig = new SoftApModeConfiguration(
1470                     WifiManager.IFACE_IP_MODE_LOCAL_ONLY,
1471                     softApConfig, mLohsSoftApTracker.getSoftApCapability());
1472             mIsExclusive = (request.getCustomConfig() != null);
1473 
1474             startSoftApInternal(mActiveConfig);
1475         }
1476 
1477         /**
1478          * Requests that any local-only hotspot be stopped.
1479          */
stopAll()1480         public void stopAll() {
1481             synchronized (mLocalOnlyHotspotRequests) {
1482                 if (!mLocalOnlyHotspotRequests.isEmpty()) {
1483                     // This is used to take down LOHS when tethering starts, and in that
1484                     // case we send failed instead of stopped.
1485                     // TODO check if that is right. Calling onFailed instead of onStopped when the
1486                     // hotspot is already started does not seem to match the documentation
1487                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1488                             LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
1489                     stopIfEmptyLocked();
1490                 }
1491             }
1492         }
1493 
1494         /**
1495          * Unregisters the LOHS request from the given process and stops LOHS if no other clients.
1496          */
stopByPid(int pid)1497         public void stopByPid(int pid) {
1498             synchronized (mLocalOnlyHotspotRequests) {
1499                 LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.remove(pid);
1500                 if (requestInfo == null) return;
1501                 requestInfo.unlinkDeathRecipient();
1502                 stopIfEmptyLocked();
1503             }
1504         }
1505 
1506         /**
1507          * Unregisters LocalOnlyHotspot request and stops the hotspot if needed.
1508          */
stopByRequest(LocalOnlyHotspotRequestInfo request)1509         public void stopByRequest(LocalOnlyHotspotRequestInfo request) {
1510             synchronized (mLocalOnlyHotspotRequests) {
1511                 if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) {
1512                     mLog.trace("LocalOnlyHotspotRequestInfo not found to remove").flush();
1513                     return;
1514                 }
1515                 stopIfEmptyLocked();
1516             }
1517         }
1518 
1519         @GuardedBy("mLocalOnlyHotspotRequests")
stopIfEmptyLocked()1520         private void stopIfEmptyLocked() {
1521             if (mLocalOnlyHotspotRequests.isEmpty()) {
1522                 mActiveConfig = null;
1523                 mIsExclusive = false;
1524                 mLohsInterfaceName = null;
1525                 mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
1526                 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1527             }
1528         }
1529 
1530         /**
1531          * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest
1532          * callers.
1533          *
1534          * Callers should already hold the mLocalOnlyHotspotRequests lock.
1535          */
1536         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked()1537         private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() {
1538             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1539                 try {
1540                     requestor.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration());
1541                 } catch (RemoteException e) {
1542                     // This will be cleaned up by binder death handling
1543                 }
1544             }
1545         }
1546 
1547         @Override
onStateChanged(int state, int failureReason)1548         public void onStateChanged(int state, int failureReason) {
1549             // The AP state update from ClientModeImpl for softap
1550             synchronized (mLocalOnlyHotspotRequests) {
1551                 Log.d(TAG, "lohs.onStateChanged: currentState=" + state
1552                         + " previousState=" + mLohsState + " errorCode= " + failureReason
1553                         + " ifaceName=" + mLohsInterfaceName);
1554 
1555                 // check if we have a failure - since it is possible (worst case scenario where
1556                 // WifiController and ClientModeImpl are out of sync wrt modes) to get two FAILED
1557                 // notifications in a row, we need to handle this first.
1558                 if (state == WIFI_AP_STATE_FAILED) {
1559                     // update registered LOHS callbacks if we see a failure
1560                     int errorToReport = ERROR_GENERIC;
1561                     if (failureReason == SAP_START_FAILURE_NO_CHANNEL) {
1562                         errorToReport = ERROR_NO_CHANNEL;
1563                     }
1564                     // holding the required lock: send message to requestors and clear the list
1565                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(errorToReport);
1566                     // also need to clear interface ip state
1567                     updateInterfaceIpState(mLohsInterfaceName,
1568                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1569                 } else if (state == WIFI_AP_STATE_DISABLING || state == WIFI_AP_STATE_DISABLED) {
1570                     // softap is shutting down or is down...  let requestors know via the
1571                     // onStopped call
1572                     // if we are currently in hotspot mode, then trigger onStopped for registered
1573                     // requestors, otherwise something odd happened and we should clear state
1574                     if (mLohsInterfaceName != null
1575                             && mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) {
1576                         // holding the required lock: send message to requestors and clear the list
1577                         sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
1578                     } else {
1579                         // LOHS not active: report an error (still holding the required lock)
1580                         sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC);
1581                     }
1582                     // also clear interface ip state
1583                     updateInterfaceIpState(mLohsInterfaceName,
1584                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1585                 }
1586                 // For enabling and enabled, just record the new state
1587                 mLohsState = state;
1588             }
1589         }
1590 
1591         @Override
onConnectedClientsChanged(List<WifiClient> clients)1592         public void onConnectedClientsChanged(List<WifiClient> clients) {
1593             // Nothing to do
1594         }
1595 
1596         /**
1597          * Called when information of softap changes.
1598          *
1599          * @param softApInfo is the softap information. {@link SoftApInfo}
1600          */
1601         @Override
onInfoChanged(SoftApInfo softApInfo)1602         public void onInfoChanged(SoftApInfo softApInfo) {
1603             // Nothing to do
1604         }
1605 
1606         /**
1607          * Called when capability of softap changes.
1608          *
1609          * @param capability is the softap information. {@link SoftApCapability}
1610          */
1611         @Override
onCapabilityChanged(SoftApCapability capability)1612         public void onCapabilityChanged(SoftApCapability capability) {
1613             // Nothing to do
1614         }
1615 
1616         /**
1617          * Called when client trying to connect but device blocked the client with specific reason.
1618          *
1619          * @param client the currently blocked client.
1620          * @param blockedReason one of blocked reason from
1621          * {@link WifiManager.SapClientBlockedReason}
1622          */
1623         @Override
onBlockedClientConnecting(WifiClient client, int blockedReason)1624         public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
1625             // Nothing to do
1626         }
1627     }
1628 
1629     /**
1630      * see {@link android.net.wifi.WifiManager#registerSoftApCallback(Executor, SoftApCallback)}
1631      *
1632      * @param binder IBinder instance to allow cleanup if the app dies
1633      * @param callback Soft AP callback to register
1634      * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to
1635      *        unregister the callback. See {@link unregisterSoftApCallback(int)}
1636      *
1637      * @throws SecurityException if the caller does not have permission to register a callback
1638      * @throws RemoteException if remote exception happens
1639      * @throws IllegalArgumentException if the arguments are null or invalid
1640      */
1641     @Override
registerSoftApCallback(IBinder binder, ISoftApCallback callback, int callbackIdentifier)1642     public void registerSoftApCallback(IBinder binder, ISoftApCallback callback,
1643             int callbackIdentifier) {
1644         // verify arguments
1645         if (binder == null) {
1646             throw new IllegalArgumentException("Binder must not be null");
1647         }
1648         if (callback == null) {
1649             throw new IllegalArgumentException("Callback must not be null");
1650         }
1651 
1652         enforceNetworkStackOrSettingsPermission();
1653 
1654         if (mVerboseLoggingEnabled) {
1655             mLog.info("registerSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
1656         }
1657 
1658         // post operation to handler thread
1659         mWifiThreadRunner.post(() -> {
1660             if (!mTetheredSoftApTracker.registerSoftApCallback(binder, callback,
1661                     callbackIdentifier)) {
1662                 Log.e(TAG, "registerSoftApCallback: Failed to add callback");
1663                 return;
1664             }
1665             // Update the client about the current state immediately after registering the callback
1666             try {
1667                 callback.onStateChanged(mTetheredSoftApTracker.getState(), 0);
1668                 callback.onConnectedClientsChanged(mTetheredSoftApTracker.getConnectedClients());
1669                 callback.onInfoChanged(mTetheredSoftApTracker.getSoftApInfo());
1670                 callback.onCapabilityChanged(mTetheredSoftApTracker.getSoftApCapability());
1671             } catch (RemoteException e) {
1672                 Log.e(TAG, "registerSoftApCallback: remote exception -- " + e);
1673             }
1674         });
1675     }
1676 
1677     /**
1678      * see {@link android.net.wifi.WifiManager#unregisterSoftApCallback(SoftApCallback)}
1679      *
1680      * @param callbackIdentifier Unique ID of the callback to be unregistered.
1681      *
1682      * @throws SecurityException if the caller does not have permission to register a callback
1683      */
1684     @Override
unregisterSoftApCallback(int callbackIdentifier)1685     public void unregisterSoftApCallback(int callbackIdentifier) {
1686         enforceNetworkStackOrSettingsPermission();
1687 
1688         if (mVerboseLoggingEnabled) {
1689             mLog.info("unregisterSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
1690         }
1691 
1692         // post operation to handler thread
1693         mWifiThreadRunner.post(() ->
1694                 mTetheredSoftApTracker.unregisterSoftApCallback(callbackIdentifier));
1695     }
1696 
1697     /**
1698      * Temporary method used for testing while start is not fully implemented.  This
1699      * method allows unit tests to register callbacks directly for testing mechanisms triggered by
1700      * softap mode changes.
1701      */
1702     @VisibleForTesting
registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request)1703     void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) {
1704         mLohsSoftApTracker.start(pid, request);
1705     }
1706 
1707     /**
1708      * Method to start LocalOnlyHotspot.  In this method, permissions, settings and modes are
1709      * checked to verify that we can enter softapmode.  This method returns
1710      * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise,
1711      * possible startup erros may include tethering being disallowed failure reason {@link
1712      * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason
1713      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}.
1714      *
1715      * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}
1716      *
1717      * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies.
1718      * @param packageName String name of the calling package.
1719      * @param featureId The feature in the package
1720      * @param customConfig Custom configuration to be applied to the hotspot, or null for a shared
1721      *                     hotspot with framework-generated config.
1722      *
1723      * @return int return code for attempt to start LocalOnlyHotspot.
1724      *
1725      * @throws SecurityException if the caller does not have permission to start a Local Only
1726      * Hotspot.
1727      * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they
1728      * have an outstanding request.
1729      */
1730     @Override
startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName, String featureId, SoftApConfiguration customConfig)1731     public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName,
1732             String featureId, SoftApConfiguration customConfig) {
1733         // first check if the caller has permission to start a local only hotspot
1734         // need to check for WIFI_STATE_CHANGE and location permission
1735         final int uid = Binder.getCallingUid();
1736         final int pid = Binder.getCallingPid();
1737 
1738         mLog.info("start uid=% pid=%").c(uid).c(pid).flush();
1739 
1740         // Permission requirements are different with/without custom config.
1741         if (customConfig == null) {
1742             if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1743                 return LocalOnlyHotspotCallback.ERROR_GENERIC;
1744             }
1745             enforceLocationPermission(packageName, featureId, uid);
1746             long ident = Binder.clearCallingIdentity();
1747             try {
1748                 // also need to verify that Locations services are enabled.
1749                 if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
1750                     throw new SecurityException("Location mode is not enabled.");
1751                 }
1752             } finally {
1753                 Binder.restoreCallingIdentity(ident);
1754             }
1755         } else {
1756             if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
1757                 throw new SecurityException(TAG + ": Permission denied");
1758             }
1759         }
1760 
1761         // verify that tethering is not disabled
1762         if (mUserManager.hasUserRestrictionForUser(
1763                 UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.getUserHandleForUid(uid))) {
1764             return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
1765         }
1766 
1767         // the app should be in the foreground
1768         long ident = Binder.clearCallingIdentity();
1769         try {
1770             // also need to verify that Locations services are enabled.
1771             if (!mFrameworkFacade.isAppForeground(mContext, uid)) {
1772                 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
1773             }
1774         } finally {
1775             Binder.restoreCallingIdentity(ident);
1776         }
1777 
1778         // check if we are currently tethering
1779         if (!mActiveModeWarden.canRequestMoreSoftApManagers()
1780                 && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
1781             // Tethering is enabled, cannot start LocalOnlyHotspot
1782             mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.")
1783                     .flush();
1784             return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
1785         }
1786 
1787         // now create the new LOHS request info object
1788         LocalOnlyHotspotRequestInfo request = new LocalOnlyHotspotRequestInfo(callback,
1789                 new LocalOnlyRequestorCallback(), customConfig);
1790 
1791         return mLohsSoftApTracker.start(pid, request);
1792     }
1793 
1794     /**
1795      * see {@link WifiManager#stopLocalOnlyHotspot()}
1796      *
1797      * @throws SecurityException if the caller does not have permission to stop a Local Only
1798      * Hotspot.
1799      */
1800     @Override
stopLocalOnlyHotspot()1801     public void stopLocalOnlyHotspot() {
1802         // don't do a permission check here. if the app's permission to change the wifi state is
1803         // revoked, we still want them to be able to stop a previously created hotspot (otherwise
1804         // it could cost the user money). When the app created the hotspot, its permission was
1805         // checked.
1806         final int uid = Binder.getCallingUid();
1807         final int pid = Binder.getCallingPid();
1808 
1809         mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
1810 
1811         mLohsSoftApTracker.stopByPid(pid);
1812     }
1813 
1814     /**
1815      * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)}
1816      *
1817      * This call requires the android.permission.NETWORK_SETTINGS permission.
1818      *
1819      * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies.
1820      *
1821      * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot
1822      * status updates.
1823      * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with
1824      * an existing subscription.
1825      */
1826     @Override
startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback)1827     public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) {
1828         // NETWORK_SETTINGS is a signature only permission.
1829         enforceNetworkSettingsPermission();
1830 
1831         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
1832     }
1833 
1834     /**
1835      * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()}
1836      */
1837     @Override
stopWatchLocalOnlyHotspot()1838     public void stopWatchLocalOnlyHotspot() {
1839         // NETWORK_STACK is a signature only permission.
1840         enforceNetworkSettingsPermission();
1841         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
1842     }
1843 
1844     /**
1845      * see {@link WifiManager#getWifiApConfiguration()}
1846      * @return soft access point configuration
1847      * @throws SecurityException if the caller does not have permission to retrieve the softap
1848      * config
1849      */
1850     @Nullable
1851     @Override
getWifiApConfiguration()1852     public WifiConfiguration getWifiApConfiguration() {
1853         enforceAccessPermission();
1854         int uid = Binder.getCallingUid();
1855         // only allow Settings UI to get the saved SoftApConfig
1856         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
1857             // random apps should not be allowed to read the user specified config
1858             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
1859                     + "(uid = " + uid + ")");
1860         }
1861 
1862         if (mVerboseLoggingEnabled) {
1863             mLog.info("getWifiApConfiguration uid=%").c(uid).flush();
1864         }
1865 
1866         // hand off work to the ClientModeImpl handler thread to sync work between calls
1867         // and SoftApManager starting up softap
1868         return (mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration,
1869                 new SoftApConfiguration.Builder().build())).toWifiConfiguration();
1870     }
1871 
1872     /**
1873      * see {@link WifiManager#getSoftApConfiguration()}
1874      * @return soft access point configuration {@link SoftApConfiguration}
1875      * @throws SecurityException if the caller does not have permission to retrieve the softap
1876      * config
1877      */
1878     @NonNull
1879     @Override
getSoftApConfiguration()1880     public SoftApConfiguration getSoftApConfiguration() {
1881         enforceNetworkSettingsPermission();
1882         int uid = Binder.getCallingUid();
1883         if (mVerboseLoggingEnabled) {
1884             mLog.info("getSoftApConfiguration uid=%").c(uid).flush();
1885         }
1886 
1887         // hand off work to the ClientModeImpl handler thread to sync work between calls
1888         // and SoftApManager starting up softap
1889         return mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration,
1890                 new SoftApConfiguration.Builder().build());
1891     }
1892 
1893     /**
1894      * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
1895      * @param wifiConfig WifiConfiguration details for soft access point
1896      * @return boolean indicating success or failure of the operation
1897      * @throws SecurityException if the caller does not have permission to write the softap config
1898      */
1899     @Override
setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName)1900     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
1901         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1902             return false;
1903         }
1904         int uid = Binder.getCallingUid();
1905         // only allow Settings UI to write the stored SoftApConfig
1906         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
1907             // random apps should not be allowed to read the user specified config
1908             throw new SecurityException("App not allowed to read or update stored WiFi AP config "
1909                     + "(uid = " + uid + ")");
1910         }
1911         mLog.info("setWifiApConfiguration uid=%").c(uid).flush();
1912         if (wifiConfig == null)
1913             return false;
1914         SoftApConfiguration softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig);
1915         if (softApConfig == null) return false;
1916         if (WifiApConfigStore.validateApWifiConfiguration(
1917                 softApConfig, false)) {
1918             mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(softApConfig));
1919             return true;
1920         } else {
1921             Log.e(TAG, "Invalid WifiConfiguration");
1922             return false;
1923         }
1924     }
1925 
1926     /**
1927      * see {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}
1928      * @param softApConfig {@link SoftApConfiguration} details for soft access point
1929      * @return boolean indicating success or failure of the operation
1930      * @throws SecurityException if the caller does not have permission to write the softap config
1931      */
1932     @Override
setSoftApConfiguration( @onNull SoftApConfiguration softApConfig, @NonNull String packageName)1933     public boolean setSoftApConfiguration(
1934             @NonNull SoftApConfiguration softApConfig, @NonNull String packageName) {
1935         enforceNetworkSettingsPermission();
1936         int uid = Binder.getCallingUid();
1937         boolean privileged = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
1938         mLog.info("setSoftApConfiguration uid=%").c(uid).flush();
1939         if (softApConfig == null) return false;
1940         if (WifiApConfigStore.validateApWifiConfiguration(softApConfig, privileged)) {
1941             mActiveModeWarden.updateSoftApConfiguration(softApConfig);
1942             mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(softApConfig));
1943             return true;
1944         } else {
1945             Log.e(TAG, "Invalid SoftAp Configuration");
1946             return false;
1947         }
1948     }
1949 
1950     /**
1951      * see {@link android.net.wifi.WifiManager#setScanAlwaysAvailable(boolean)}
1952      */
1953     @Override
setScanAlwaysAvailable(boolean isAvailable)1954     public void setScanAlwaysAvailable(boolean isAvailable) {
1955         enforceNetworkSettingsPermission();
1956         mLog.info("setScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
1957         mSettingsStore.handleWifiScanAlwaysAvailableToggled(isAvailable);
1958         long ident = Binder.clearCallingIdentity();
1959         try {
1960             mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility()
1961                     .handleWifiScanAlwaysAvailableToggled(isAvailable);
1962         } finally {
1963             Binder.restoreCallingIdentity(ident);
1964         }
1965         mActiveModeWarden.scanAlwaysModeChanged();
1966     }
1967 
1968     /**
1969      * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
1970      */
1971     @Override
isScanAlwaysAvailable()1972     public boolean isScanAlwaysAvailable() {
1973         enforceAccessPermission();
1974         if (mVerboseLoggingEnabled) {
1975             mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
1976         }
1977         return mSettingsStore.isScanAlwaysAvailable();
1978     }
1979 
1980     /**
1981      * see {@link android.net.wifi.WifiManager#disconnect()}
1982      */
1983     @Override
disconnect(String packageName)1984     public boolean disconnect(String packageName) {
1985         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1986             return false;
1987         }
1988         if (!isTargetSdkLessThanQOrPrivileged(
1989                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
1990             mLog.info("disconnect not allowed for uid=%")
1991                     .c(Binder.getCallingUid()).flush();
1992             return false;
1993         }
1994         mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush();
1995         mClientModeImpl.disconnectCommand();
1996         return true;
1997     }
1998 
1999     /**
2000      * see {@link android.net.wifi.WifiManager#reconnect()}
2001      */
2002     @Override
reconnect(String packageName)2003     public boolean reconnect(String packageName) {
2004         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2005             return false;
2006         }
2007         if (!isTargetSdkLessThanQOrPrivileged(
2008                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2009             mLog.info("reconnect not allowed for uid=%")
2010                     .c(Binder.getCallingUid()).flush();
2011             return false;
2012         }
2013         mLog.info("reconnect uid=%").c(Binder.getCallingUid()).flush();
2014         mClientModeImpl.reconnectCommand(new WorkSource(Binder.getCallingUid()));
2015         return true;
2016     }
2017 
2018     /**
2019      * see {@link android.net.wifi.WifiManager#reassociate()}
2020      */
2021     @Override
reassociate(String packageName)2022     public boolean reassociate(String packageName) {
2023         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2024             return false;
2025         }
2026         if (!isTargetSdkLessThanQOrPrivileged(
2027                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2028             mLog.info("reassociate not allowed for uid=%")
2029                     .c(Binder.getCallingUid()).flush();
2030             return false;
2031         }
2032         mLog.info("reassociate uid=%").c(Binder.getCallingUid()).flush();
2033         mClientModeImpl.reassociateCommand();
2034         return true;
2035     }
2036 
2037     /**
2038      * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
2039      */
2040     @Override
getSupportedFeatures()2041     public long getSupportedFeatures() {
2042         enforceAccessPermission();
2043         if (mVerboseLoggingEnabled) {
2044             mLog.info("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
2045         }
2046         return getSupportedFeaturesInternal();
2047     }
2048 
2049     @Override
getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener)2050     public void getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener) {
2051         if (mVerboseLoggingEnabled) {
2052             mLog.info("getWifiActivityEnergyInfoAsync uid=%")
2053                     .c(Binder.getCallingUid())
2054                     .flush();
2055         }
2056         // getWifiActivityEnergyInfo() performs permission checking
2057         WifiActivityEnergyInfo info = getWifiActivityEnergyInfo();
2058         try {
2059             listener.onWifiActivityEnergyInfo(info);
2060         } catch (RemoteException e) {
2061             Log.e(TAG, "onWifiActivityEnergyInfo: RemoteException -- ", e);
2062         }
2063     }
2064 
getWifiActivityEnergyInfo()2065     private WifiActivityEnergyInfo getWifiActivityEnergyInfo() {
2066         enforceAccessPermission();
2067         if (mVerboseLoggingEnabled) {
2068             mLog.info("getWifiActivityEnergyInfo uid=%").c(Binder.getCallingUid()).flush();
2069         }
2070         if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
2071             return null;
2072         }
2073         if (mClientModeImplChannel == null) {
2074             Log.e(TAG, "mClientModeImplChannel is not initialized");
2075             return null;
2076         }
2077         WifiLinkLayerStats stats = mClientModeImpl.syncGetLinkLayerStats(mClientModeImplChannel);
2078         if (stats == null) {
2079             return null;
2080         }
2081 
2082         final long rxIdleTimeMillis = stats.on_time - stats.tx_time - stats.rx_time;
2083         final long[] txTimePerLevelMillis;
2084         if (stats.tx_time_per_level == null) {
2085             // This will happen if the HAL get link layer API returned null.
2086             txTimePerLevelMillis = new long[0];
2087         } else {
2088             // need to manually copy since we are converting an int[] to a long[]
2089             txTimePerLevelMillis = new long[stats.tx_time_per_level.length];
2090             for (int i = 0; i < txTimePerLevelMillis.length; i++) {
2091                 txTimePerLevelMillis[i] = stats.tx_time_per_level[i];
2092                 // TODO(b/27227497): Need to read the power consumed per level from config
2093             }
2094         }
2095         if (VDBG || rxIdleTimeMillis < 0 || stats.on_time < 0 || stats.tx_time < 0
2096                 || stats.rx_time < 0 || stats.on_time_scan < 0) {
2097             Log.d(TAG, " getWifiActivityEnergyInfo: "
2098                     + " on_time_millis=" + stats.on_time
2099                     + " tx_time_millis=" + stats.tx_time
2100                     + " tx_time_per_level_millis=" + Arrays.toString(txTimePerLevelMillis)
2101                     + " rx_time_millis=" + stats.rx_time
2102                     + " rxIdleTimeMillis=" + rxIdleTimeMillis
2103                     + " scan_time_millis=" + stats.on_time_scan);
2104         }
2105 
2106         // Convert the LinkLayerStats into WifiActivityEnergyInfo
2107         return new WifiActivityEnergyInfo(
2108                 mClock.getElapsedSinceBootMillis(),
2109                 WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE,
2110                 stats.tx_time,
2111                 stats.rx_time,
2112                 stats.on_time_scan,
2113                 rxIdleTimeMillis);
2114     }
2115 
2116     /**
2117      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
2118      *
2119      * @param packageName String name of the calling package
2120      * @param featureId The feature in the package
2121      * @return the list of configured networks
2122      */
2123     @Override
getConfiguredNetworks(String packageName, String featureId)2124     public ParceledListSlice<WifiConfiguration> getConfiguredNetworks(String packageName,
2125             String featureId) {
2126         enforceAccessPermission();
2127         int callingUid = Binder.getCallingUid();
2128         // bypass shell: can get varioud pkg name
2129         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
2130             long ident = Binder.clearCallingIdentity();
2131             try {
2132                 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId,
2133                         callingUid, null);
2134             } catch (SecurityException e) {
2135                 Log.e(TAG, "Permission violation - getConfiguredNetworks not allowed for uid="
2136                         + callingUid + ", packageName=" + packageName + ", reason=" + e);
2137                 return new ParceledListSlice<>(new ArrayList<>());
2138             } finally {
2139                 Binder.restoreCallingIdentity(ident);
2140             }
2141         }
2142         boolean isTargetSdkLessThanQOrPrivileged = isTargetSdkLessThanQOrPrivileged(
2143                 packageName, Binder.getCallingPid(), callingUid);
2144         boolean isCarrierApp = mWifiInjector.makeTelephonyManager()
2145                 .checkCarrierPrivilegesForPackageAnyPhone(packageName)
2146                 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
2147         if (!isTargetSdkLessThanQOrPrivileged && !isCarrierApp) {
2148             mLog.info("getConfiguredNetworks not allowed for uid=%")
2149                     .c(callingUid).flush();
2150             return new ParceledListSlice<>(new ArrayList<>());
2151         }
2152         if (mVerboseLoggingEnabled) {
2153             mLog.info("getConfiguredNetworks uid=%").c(callingUid).flush();
2154         }
2155 
2156         int targetConfigUid = Process.INVALID_UID; // don't expose any MAC addresses
2157         if (isPrivileged(getCallingPid(), callingUid)
2158                 || isDeviceOrProfileOwner(callingUid, packageName)) {
2159             targetConfigUid = Process.WIFI_UID; // expose all MAC addresses
2160         } else if (isCarrierApp) {
2161             targetConfigUid = callingUid; // expose only those configs created by the Carrier App
2162         }
2163         int finalTargetConfigUid = targetConfigUid;
2164         List<WifiConfiguration> configs = mWifiThreadRunner.call(
2165                 () -> mWifiConfigManager.getSavedNetworks(finalTargetConfigUid),
2166                 Collections.emptyList());
2167         if (isTargetSdkLessThanQOrPrivileged) {
2168             return new ParceledListSlice<>(configs);
2169         }
2170         // Carrier app: should only get its own configs
2171         List<WifiConfiguration> creatorConfigs = new ArrayList<>();
2172         for (WifiConfiguration config : configs) {
2173             if (config.creatorUid == callingUid) {
2174                 creatorConfigs.add(config);
2175             }
2176         }
2177         return new ParceledListSlice<>(creatorConfigs);
2178     }
2179 
2180     /**
2181      * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
2182      *
2183      * @param packageName String name of the calling package
2184      * @param featureId The feature in the package
2185      * @return the list of configured networks with real preSharedKey
2186      */
2187     @Override
getPrivilegedConfiguredNetworks( String packageName, String featureId)2188     public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks(
2189             String packageName, String featureId) {
2190         enforceReadCredentialPermission();
2191         enforceAccessPermission();
2192         int callingUid = Binder.getCallingUid();
2193         long ident = Binder.clearCallingIdentity();
2194         try {
2195             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
2196                     null);
2197         } catch (SecurityException e) {
2198             Log.e(TAG, "Permission violation - getPrivilegedConfiguredNetworks not allowed for"
2199                     + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
2200             return null;
2201         } finally {
2202             Binder.restoreCallingIdentity(ident);
2203         }
2204         if (mVerboseLoggingEnabled) {
2205             mLog.info("getPrivilegedConfiguredNetworks uid=%").c(callingUid).flush();
2206         }
2207         List<WifiConfiguration> configs = mWifiThreadRunner.call(
2208                 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(),
2209                 Collections.emptyList());
2210         return new ParceledListSlice<>(configs);
2211     }
2212 
2213     /**
2214      * Return a map of all matching configurations keys with corresponding scanResults (or an empty
2215      * map if none).
2216      *
2217      * @param scanResults The list of scan results
2218      * @return Map that consists of FQDN (Fully Qualified Domain Name) and corresponding
2219      * scanResults per network type({@link WifiManager#PASSPOINT_HOME_NETWORK} and {@link
2220      * WifiManager#PASSPOINT_ROAMING_NETWORK}).
2221      */
2222     @Override
2223     public Map<String, Map<Integer, List<ScanResult>>>
getAllMatchingPasspointProfilesForScanResults(List<ScanResult> scanResults)2224             getAllMatchingPasspointProfilesForScanResults(List<ScanResult> scanResults) {
2225         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2226             throw new SecurityException(TAG + ": Permission denied");
2227         }
2228         if (mVerboseLoggingEnabled) {
2229             mLog.info("getMatchingPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
2230         }
2231         if (!ScanResultUtil.validateScanResultList(scanResults)) {
2232             Log.e(TAG, "Attempt to retrieve passpoint with invalid scanResult List");
2233             return Collections.emptyMap();
2234         }
2235         return mWifiThreadRunner.call(
2236             () -> mPasspointManager.getAllMatchingPasspointProfilesForScanResults(scanResults),
2237                 Collections.emptyMap());
2238     }
2239 
2240     /**
2241      * Returns list of OSU (Online Sign-Up) providers associated with the given list of ScanResult.
2242      *
2243      * @param scanResults a list of ScanResult that has Passpoint APs.
2244      * @return Map that consists of {@link OsuProvider} and a matching list of {@link ScanResult}.
2245      */
2246     @Override
getMatchingOsuProviders( List<ScanResult> scanResults)2247     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
2248             List<ScanResult> scanResults) {
2249         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2250             throw new SecurityException(TAG + ": Permission denied");
2251         }
2252         if (mVerboseLoggingEnabled) {
2253             mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush();
2254         }
2255 
2256         if (!ScanResultUtil.validateScanResultList(scanResults)) {
2257             Log.e(TAG, "Attempt to retrieve OsuProviders with invalid scanResult List");
2258             return Collections.emptyMap();
2259         }
2260         return mWifiThreadRunner.call(
2261             () -> mPasspointManager.getMatchingOsuProviders(scanResults), Collections.emptyMap());
2262     }
2263 
2264     /**
2265      * Returns the matching Passpoint configurations for given OSU(Online Sign-Up) providers.
2266      *
2267      * @param osuProviders a list of {@link OsuProvider}
2268      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
2269      */
2270     @Override
getMatchingPasspointConfigsForOsuProviders( List<OsuProvider> osuProviders)2271     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
2272             List<OsuProvider> osuProviders) {
2273         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2274             throw new SecurityException(TAG + ": Permission denied");
2275         }
2276         if (mVerboseLoggingEnabled) {
2277             mLog.info("getMatchingPasspointConfigsForOsuProviders uid=%").c(
2278                     Binder.getCallingUid()).flush();
2279         }
2280         if (osuProviders == null) {
2281             Log.e(TAG, "Attempt to retrieve Passpoint configuration with null osuProviders");
2282             return new HashMap<>();
2283         }
2284         return mWifiThreadRunner.call(
2285             () -> mPasspointManager.getMatchingPasspointConfigsForOsuProviders(osuProviders),
2286                 Collections.emptyMap());
2287     }
2288 
2289     /**
2290      * Returns the corresponding wifi configurations for given FQDN (Fully Qualified Domain Name)
2291      * list.
2292      *
2293      * An empty list will be returned when no match is found.
2294      *
2295      * @param fqdnList a list of FQDN
2296      * @return List of {@link WifiConfiguration} converted from {@link PasspointProvider}
2297      */
2298     @Override
getWifiConfigsForPasspointProfiles(List<String> fqdnList)2299     public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) {
2300         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2301             throw new SecurityException(TAG + ": Permission denied");
2302         }
2303         if (mVerboseLoggingEnabled) {
2304             mLog.info("getWifiConfigsForPasspointProfiles uid=%").c(
2305                     Binder.getCallingUid()).flush();
2306         }
2307         if (fqdnList == null) {
2308             Log.e(TAG, "Attempt to retrieve WifiConfiguration with null fqdn List");
2309             return new ArrayList<>();
2310         }
2311         return mWifiThreadRunner.call(
2312             () -> mPasspointManager.getWifiConfigsForPasspointProfiles(fqdnList),
2313                 Collections.emptyList());
2314     }
2315 
2316     /**
2317      * Returns a list of Wifi configurations for matched available WifiNetworkSuggestion
2318      * corresponding to the given scan results.
2319      *
2320      * An empty list will be returned when no match is found or all matched suggestions is not
2321      * available(not allow user manually connect, user not approved or open network).
2322      *
2323      * @param scanResults a list of {@link ScanResult}.
2324      * @return a list of {@link WifiConfiguration} from matched {@link WifiNetworkSuggestion}.
2325      */
2326     @Override
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( List<ScanResult> scanResults)2327     public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
2328             List<ScanResult> scanResults) {
2329         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2330             throw new SecurityException(TAG + ": Permission denied");
2331         }
2332         if (mVerboseLoggingEnabled) {
2333             mLog.info("getWifiConfigsForMatchedNetworkSuggestions uid=%").c(
2334                     Binder.getCallingUid()).flush();
2335         }
2336         if (!ScanResultUtil.validateScanResultList(scanResults)) {
2337             Log.e(TAG, "Attempt to retrieve WifiConfiguration with invalid scanResult List");
2338             return new ArrayList<>();
2339         }
2340         return mWifiThreadRunner.call(
2341                 () -> mWifiNetworkSuggestionsManager
2342                         .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults),
2343                 Collections.emptyList());
2344     }
2345 
2346     /**
2347      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
2348      * @return the supplicant-assigned identifier for the new or updated
2349      * network if the operation succeeds, or {@code -1} if it fails
2350      */
2351     @Override
addOrUpdateNetwork(WifiConfiguration config, String packageName)2352     public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
2353         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2354             return -1;
2355         }
2356         int callingUid = Binder.getCallingUid();
2357         if (!isTargetSdkLessThanQOrPrivileged(
2358                 packageName, Binder.getCallingPid(), callingUid)) {
2359             mLog.info("addOrUpdateNetwork not allowed for uid=%")
2360                     .c(Binder.getCallingUid()).flush();
2361             return -1;
2362         }
2363         mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
2364 
2365         if (config == null) {
2366             Log.e(TAG, "bad network configuration");
2367             return -1;
2368         }
2369         mWifiMetrics.incrementNumAddOrUpdateNetworkCalls();
2370 
2371         // Previously, this API is overloaded for installing Passpoint profiles.  Now
2372         // that we have a dedicated API for doing it, redirect the call to the dedicated API.
2373         if (config.isPasspoint()) {
2374             PasspointConfiguration passpointConfig =
2375                     PasspointProvider.convertFromWifiConfig(config);
2376             if (passpointConfig == null || passpointConfig.getCredential() == null) {
2377                 Log.e(TAG, "Missing credential for Passpoint profile");
2378                 return -1;
2379             }
2380 
2381             // Copy over certificates and keys.
2382             X509Certificate[] x509Certificates = null;
2383             if (config.enterpriseConfig.getCaCertificate() != null) {
2384                 x509Certificates =
2385                         new X509Certificate[]{config.enterpriseConfig.getCaCertificate()};
2386             }
2387             passpointConfig.getCredential().setCaCertificates(x509Certificates);
2388             passpointConfig.getCredential().setClientCertificateChain(
2389                     config.enterpriseConfig.getClientCertificateChain());
2390             passpointConfig.getCredential().setClientPrivateKey(
2391                     config.enterpriseConfig.getClientPrivateKey());
2392             if (!addOrUpdatePasspointConfiguration(passpointConfig, packageName)) {
2393                 Log.e(TAG, "Failed to add Passpoint profile");
2394                 return -1;
2395             }
2396             // There is no network ID associated with a Passpoint profile.
2397             return 0;
2398         }
2399 
2400         Log.i("addOrUpdateNetwork", " uid = " + Binder.getCallingUid()
2401                 + " SSID " + config.SSID
2402                 + " nid=" + config.networkId);
2403         return mWifiThreadRunner.call(
2404             () -> mWifiConfigManager.addOrUpdateNetwork(config, callingUid, packageName)
2405                     .getNetworkId(),
2406                 WifiConfiguration.INVALID_NETWORK_ID);
2407     }
2408 
verifyCert(X509Certificate caCert)2409     public static void verifyCert(X509Certificate caCert)
2410             throws GeneralSecurityException, IOException {
2411         CertificateFactory factory = CertificateFactory.getInstance("X.509");
2412         CertPathValidator validator =
2413                 CertPathValidator.getInstance(CertPathValidator.getDefaultType());
2414         CertPath path = factory.generateCertPath(
2415                 Arrays.asList(caCert));
2416         KeyStore ks = KeyStore.getInstance("AndroidCAStore");
2417         ks.load(null, null);
2418         PKIXParameters params = new PKIXParameters(ks);
2419         params.setRevocationEnabled(false);
2420         validator.validate(path, params);
2421     }
2422 
2423     /**
2424      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
2425      * @param netId the integer that identifies the network configuration
2426      * to the supplicant
2427      * @return {@code true} if the operation succeeded
2428      */
2429     @Override
removeNetwork(int netId, String packageName)2430     public boolean removeNetwork(int netId, String packageName) {
2431         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2432             return false;
2433         }
2434         if (!isTargetSdkLessThanQOrPrivileged(
2435                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2436             mLog.info("removeNetwork not allowed for uid=%")
2437                     .c(Binder.getCallingUid()).flush();
2438             return false;
2439         }
2440         int callingUid = Binder.getCallingUid();
2441         mLog.info("removeNetwork uid=%").c(callingUid).flush();
2442         return mWifiThreadRunner.call(
2443                 () -> mWifiConfigManager.removeNetwork(netId, callingUid, packageName), false);
2444     }
2445 
2446     /**
2447      * Trigger a connect request and wait for the callback to return status.
2448      * This preserves the legacy connect API behavior, i.e. {@link WifiManager#enableNetwork(
2449      * int, true)}
2450      * @return
2451      */
triggerConnectAndReturnStatus(int netId, int callingUid)2452     private boolean triggerConnectAndReturnStatus(int netId, int callingUid) {
2453         final CountDownLatch countDownLatch = new CountDownLatch(1);
2454         final MutableBoolean success = new MutableBoolean(false);
2455         IActionListener.Stub connectListener = new IActionListener.Stub() {
2456             @Override
2457             public void onSuccess() {
2458                 success.value = true;
2459                 countDownLatch.countDown();
2460             }
2461             @Override
2462             public void onFailure(int reason) {
2463                 success.value = false;
2464                 countDownLatch.countDown();
2465             }
2466         };
2467         mClientModeImpl.connect(null, netId, new Binder(), connectListener,
2468                 connectListener.hashCode(), callingUid);
2469         // now wait for response.
2470         try {
2471             countDownLatch.await(RUN_WITH_SCISSORS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
2472         } catch (InterruptedException e) {
2473             Log.e(TAG, "Failed to retrieve connect status");
2474         }
2475         return success.value;
2476     }
2477 
2478     /**
2479      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
2480      * @param netId the integer that identifies the network configuration
2481      * to the supplicant
2482      * @param disableOthers if true, disable all other networks.
2483      * @return {@code true} if the operation succeeded
2484      */
2485     @Override
enableNetwork(int netId, boolean disableOthers, String packageName)2486     public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
2487         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2488             return false;
2489         }
2490         if (!isTargetSdkLessThanQOrPrivileged(
2491                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2492             mLog.info("enableNetwork not allowed for uid=%")
2493                     .c(Binder.getCallingUid()).flush();
2494             return false;
2495         }
2496         int callingUid = Binder.getCallingUid();
2497         // TODO b/33807876 Log netId
2498         mLog.info("enableNetwork uid=% disableOthers=%")
2499                 .c(callingUid)
2500                 .c(disableOthers).flush();
2501 
2502         mWifiMetrics.incrementNumEnableNetworkCalls();
2503         if (disableOthers) {
2504             return triggerConnectAndReturnStatus(netId, callingUid);
2505         } else {
2506             return mWifiThreadRunner.call(
2507                     () -> mWifiConfigManager.enableNetwork(netId, false, callingUid, packageName),
2508                     false);
2509         }
2510     }
2511 
2512     /**
2513      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
2514      * @param netId the integer that identifies the network configuration
2515      * to the supplicant
2516      * @return {@code true} if the operation succeeded
2517      */
2518     @Override
disableNetwork(int netId, String packageName)2519     public boolean disableNetwork(int netId, String packageName) {
2520         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2521             return false;
2522         }
2523         if (!isTargetSdkLessThanQOrPrivileged(
2524                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2525             mLog.info("disableNetwork not allowed for uid=%")
2526                     .c(Binder.getCallingUid()).flush();
2527             return false;
2528         }
2529         int callingUid = Binder.getCallingUid();
2530         mLog.info("disableNetwork uid=%").c(callingUid).flush();
2531         return mWifiThreadRunner.call(
2532                 () -> mWifiConfigManager.disableNetwork(netId, callingUid, packageName), false);
2533     }
2534 
2535     /**
2536      * See {@link android.net.wifi.WifiManager#allowAutojoinGlobal(boolean)}
2537      * @param choice the OEM's choice to allow auto-join
2538      */
2539     @Override
allowAutojoinGlobal(boolean choice)2540     public void allowAutojoinGlobal(boolean choice) {
2541         enforceNetworkSettingsPermission();
2542 
2543         int callingUid = Binder.getCallingUid();
2544         mLog.info("allowAutojoin=% uid=%").c(choice).c(callingUid).flush();
2545 
2546         mWifiThreadRunner.post(() -> mClientModeImpl.allowAutoJoinGlobal(choice));
2547     }
2548 
2549     /**
2550      * See {@link android.net.wifi.WifiManager#allowAutojoin(int, boolean)}
2551      * @param netId the integer that identifies the network configuration
2552      * @param choice the user's choice to allow auto-join
2553      */
2554     @Override
allowAutojoin(int netId, boolean choice)2555     public void allowAutojoin(int netId, boolean choice) {
2556         enforceNetworkSettingsPermission();
2557 
2558         int callingUid = Binder.getCallingUid();
2559         mLog.info("allowAutojoin=% uid=%").c(choice).c(callingUid).flush();
2560         mWifiThreadRunner.post(() -> {
2561             WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId);
2562             if (config == null) {
2563                 return;
2564             }
2565             if (config.fromWifiNetworkSpecifier) {
2566                 Log.e(TAG, "Auto-join configuration is not permitted for NetworkSpecifier "
2567                         + "connections: " + config);
2568                 return;
2569             }
2570             if (config.isPasspoint() && !config.isEphemeral()) {
2571                 Log.e(TAG,
2572                         "Auto-join configuration for a non-ephemeral Passpoint network should be "
2573                                 + "configured using FQDN: "
2574                                 + config);
2575                 return;
2576             }
2577             // If the network is a suggestion, store the auto-join configure to the
2578             // WifiNetWorkSuggestionsManager.
2579             if (config.fromWifiNetworkSuggestion) {
2580                 if (!mWifiNetworkSuggestionsManager
2581                         .allowNetworkSuggestionAutojoin(config, choice)) {
2582                     return;
2583                 }
2584             }
2585             // even for Suggestion, modify the current ephemeral configuration so that
2586             // existing configuration auto-connection is updated correctly
2587             if (choice != config.allowAutojoin) {
2588                 mWifiConfigManager.allowAutojoin(netId, choice);
2589                 // do not log this metrics for passpoint networks again here since it's already
2590                 // logged in PasspointManager.
2591                 if (!config.isPasspoint()) {
2592                     mWifiMetrics.logUserActionEvent(choice
2593                             ? UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON
2594                             : UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF, netId);
2595                 }
2596             }
2597         });
2598     }
2599 
2600     /**
2601      * See {@link android.net.wifi.WifiManager#allowAutojoinPasspoint(String, boolean)}
2602      * @param fqdn the FQDN that identifies the passpoint configuration
2603      * @param enableAutojoin true to enable auto-join, false to disable
2604      */
2605     @Override
allowAutojoinPasspoint(String fqdn, boolean enableAutojoin)2606     public void allowAutojoinPasspoint(String fqdn, boolean enableAutojoin) {
2607         enforceNetworkSettingsPermission();
2608         if (fqdn == null) {
2609             throw new IllegalArgumentException("FQDN cannot be null");
2610         }
2611 
2612         int callingUid = Binder.getCallingUid();
2613         mLog.info("allowAutojoinPasspoint=% uid=%").c(enableAutojoin).c(callingUid).flush();
2614         mWifiThreadRunner.post(
2615                 () -> mPasspointManager.enableAutojoin(null, fqdn, enableAutojoin));
2616     }
2617 
2618     /**
2619      * See {@link android.net.wifi.WifiManager
2620      * #setMacRandomizationSettingPasspointEnabled(String, boolean)}
2621      * @param fqdn the FQDN that identifies the passpoint configuration
2622      * @param enable true to enable mac randomization, false to disable
2623      */
2624     @Override
setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable)2625     public void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable) {
2626         enforceNetworkSettingsPermission();
2627         if (fqdn == null) {
2628             throw new IllegalArgumentException("FQDN cannot be null");
2629         }
2630 
2631         int callingUid = Binder.getCallingUid();
2632         mLog.info("setMacRandomizationSettingPasspointEnabled=% uid=%")
2633                 .c(enable).c(callingUid).flush();
2634         mWifiThreadRunner.post(
2635                 () -> mPasspointManager.enableMacRandomization(fqdn, enable));
2636     }
2637 
2638     /**
2639      * See {@link android.net.wifi.WifiManager#setPasspointMeteredOverride(String, boolean)}
2640      * @param fqdn the FQDN that identifies the passpoint configuration
2641      * @param meteredOverride One of the values in {@link MeteredOverride}
2642      */
2643     @Override
setPasspointMeteredOverride(String fqdn, int meteredOverride)2644     public void setPasspointMeteredOverride(String fqdn, int meteredOverride) {
2645         enforceNetworkSettingsPermission();
2646         if (fqdn == null) {
2647             throw new IllegalArgumentException("FQDN cannot be null");
2648         }
2649 
2650         int callingUid = Binder.getCallingUid();
2651         mLog.info("setPasspointMeteredOverride=% uid=%")
2652                 .c(meteredOverride).c(callingUid).flush();
2653         mWifiThreadRunner.post(
2654                 () -> mPasspointManager.setMeteredOverride(fqdn, meteredOverride));
2655     }
2656 
2657     /**
2658      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
2659      * @return the Wi-Fi information, contained in {@link WifiInfo}.
2660      */
2661     @Override
getConnectionInfo(String callingPackage, String callingFeatureId)2662     public WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId) {
2663         enforceAccessPermission();
2664         int uid = Binder.getCallingUid();
2665         if (mVerboseLoggingEnabled) {
2666             mLog.info("getConnectionInfo uid=%").c(uid).flush();
2667         }
2668         long ident = Binder.clearCallingIdentity();
2669         try {
2670             WifiInfo result = mClientModeImpl.syncRequestConnectionInfo();
2671             boolean hideDefaultMacAddress = true;
2672             boolean hideBssidSsidNetworkIdAndFqdn = true;
2673 
2674             try {
2675                 if (mWifiInjector.getWifiPermissionsWrapper().getLocalMacAddressPermission(uid)
2676                         == PERMISSION_GRANTED) {
2677                     hideDefaultMacAddress = false;
2678                 }
2679                 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
2680                         uid, null);
2681                 hideBssidSsidNetworkIdAndFqdn = false;
2682             } catch (SecurityException ignored) {
2683             }
2684             if (hideDefaultMacAddress) {
2685                 result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS);
2686             }
2687             if (hideBssidSsidNetworkIdAndFqdn) {
2688                 result.setBSSID(WifiInfo.DEFAULT_MAC_ADDRESS);
2689                 result.setSSID(WifiSsid.createFromHex(null));
2690                 result.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID);
2691                 result.setFQDN(null);
2692                 result.setProviderFriendlyName(null);
2693                 result.setPasspointUniqueId(null);
2694             }
2695 
2696             if (mVerboseLoggingEnabled
2697                     && (hideBssidSsidNetworkIdAndFqdn || hideDefaultMacAddress)) {
2698                 mLog.v("getConnectionInfo: hideBssidSsidAndNetworkId="
2699                         + hideBssidSsidNetworkIdAndFqdn
2700                         + ", hideDefaultMacAddress="
2701                         + hideDefaultMacAddress);
2702             }
2703             return result;
2704         } finally {
2705             Binder.restoreCallingIdentity(ident);
2706         }
2707     }
2708 
2709     /**
2710      * Return the results of the most recent access point scan, in the form of
2711      * a list of {@link ScanResult} objects.
2712      * @return the list of results
2713      */
2714     @Override
getScanResults(String callingPackage, String callingFeatureId)2715     public List<ScanResult> getScanResults(String callingPackage, String callingFeatureId) {
2716         enforceAccessPermission();
2717         int uid = Binder.getCallingUid();
2718         long ident = Binder.clearCallingIdentity();
2719         if (mVerboseLoggingEnabled) {
2720             mLog.info("getScanResults uid=%").c(uid).flush();
2721         }
2722         try {
2723             mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
2724                     uid, null);
2725             List<ScanResult> scanResults = mWifiThreadRunner.call(
2726                     mScanRequestProxy::getScanResults, Collections.emptyList());
2727             return scanResults;
2728         } catch (SecurityException e) {
2729             Log.e(TAG, "Permission violation - getScanResults not allowed for uid="
2730                     + uid + ", packageName=" + callingPackage + ", reason=" + e);
2731             return new ArrayList<>();
2732         } finally {
2733             Binder.restoreCallingIdentity(ident);
2734         }
2735     }
2736 
2737     /**
2738      * Return the filtered ScanResults which may be authenticated by the suggested network
2739      * configurations.
2740      * @return The map of {@link WifiNetworkSuggestion} and the list of {@link ScanResult} which
2741      * may be authenticated by the corresponding network configuration.
2742      */
2743     @Override
2744     @NonNull
getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestions, @Nullable List<ScanResult> scanResults, String callingPackage, String callingFeatureId)2745     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
2746             @NonNull List<WifiNetworkSuggestion> networkSuggestions,
2747             @Nullable List<ScanResult> scanResults,
2748             String callingPackage, String callingFeatureId) {
2749         enforceAccessPermission();
2750         int uid = Binder.getCallingUid();
2751         long ident = Binder.clearCallingIdentity();
2752         try {
2753             mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
2754                     uid, null);
2755 
2756             return mWifiThreadRunner.call(
2757                     () -> {
2758                         if (!ScanResultUtil.validateScanResultList(scanResults)) {
2759                             return mWifiNetworkSuggestionsManager.getMatchingScanResults(
2760                                     networkSuggestions, mScanRequestProxy.getScanResults());
2761                         } else {
2762                             return mWifiNetworkSuggestionsManager.getMatchingScanResults(
2763                                     networkSuggestions, scanResults);
2764                         }
2765                     },
2766                     Collections.emptyMap());
2767         } catch (SecurityException e) {
2768             Log.e(TAG, "Permission violation - getMatchingScanResults not allowed for uid="
2769                     + uid + ", packageName=" + callingPackage + ", reason + e");
2770         } finally {
2771             Binder.restoreCallingIdentity(ident);
2772         }
2773 
2774         return Collections.emptyMap();
2775     }
2776 
2777     /**
2778      * Add or update a Passpoint configuration.
2779      *
2780      * @param config The Passpoint configuration to be added
2781      * @return true on success or false on failure
2782      */
2783     @Override
2784     public boolean addOrUpdatePasspointConfiguration(
2785             PasspointConfiguration config, String packageName) {
2786         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2787             return false;
2788         }
2789         int callingUid = Binder.getCallingUid();
2790         if (!isTargetSdkLessThanROrPrivileged(
2791                 packageName, Binder.getCallingPid(), callingUid)) {
2792             mLog.info("addOrUpdatePasspointConfiguration not allowed for uid=%")
2793                     .c(Binder.getCallingUid()).flush();
2794             return false;
2795         }
2796         mLog.info("addorUpdatePasspointConfiguration uid=%").c(callingUid).flush();
2797         return mWifiThreadRunner.call(
2798                 () -> mPasspointManager.addOrUpdateProvider(config, callingUid, packageName,
2799                         false, true), false);
2800     }
2801 
2802     /**
2803      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
2804      *
2805      * @param fqdn The FQDN of the Passpoint configuration to be removed
2806      * @return true on success or false on failure
2807      */
2808     @Override
2809     public boolean removePasspointConfiguration(String fqdn, String packageName) {
2810         return removePasspointConfigurationInternal(fqdn, null);
2811     }
2812 
2813     /**
2814      * Remove a Passpoint profile based on either FQDN (multiple matching profiles) or a unique
2815      * identifier (one matching profile).
2816      *
2817      * @param fqdn The FQDN of the Passpoint configuration to be removed
2818      * @param uniqueId The unique identifier of the Passpoint configuration to be removed
2819      * @return true on success or false on failure
2820      */
2821     private boolean removePasspointConfigurationInternal(String fqdn, String uniqueId) {
2822         final int uid = Binder.getCallingUid();
2823         boolean privileged = false;
2824         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
2825                 || mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(uid)) {
2826             privileged = true;
2827         }
2828         mLog.info("removePasspointConfigurationInternal uid=%").c(Binder.getCallingUid()).flush();
2829         final boolean privilegedFinal = privileged;
2830         return mWifiThreadRunner.call(
2831                 () -> mPasspointManager.removeProvider(uid, privilegedFinal, uniqueId, fqdn),
2832                 false);
2833     }
2834 
2835     /**
2836      * Return the list of the installed Passpoint configurations.
2837      *
2838      * An empty list will be returned when no configuration is installed.
2839      * @param packageName String name of the calling package
2840      * @return A list of {@link PasspointConfiguration}.
2841      */
2842     @Override
2843     public List<PasspointConfiguration> getPasspointConfigurations(String packageName) {
2844         final int uid = Binder.getCallingUid();
2845         boolean privileged = false;
2846         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
2847                 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
2848             privileged = true;
2849         }
2850         if (mVerboseLoggingEnabled) {
2851             mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
2852         }
2853         final boolean privilegedFinal = privileged;
2854         return mWifiThreadRunner.call(
2855             () -> mPasspointManager.getProviderConfigs(uid, privilegedFinal),
2856             Collections.emptyList());
2857     }
2858 
2859     /**
2860      * Query for a Hotspot 2.0 release 2 OSU icon
2861      * @param bssid The BSSID of the AP
2862      * @param fileName Icon file name
2863      */
2864     @Override
2865     public void queryPasspointIcon(long bssid, String fileName) {
2866         enforceAccessPermission();
2867         mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
2868         mClientModeImpl.syncQueryPasspointIcon(mClientModeImplChannel, bssid, fileName);
2869     }
2870 
2871     /**
2872      * Match the currently associated network against the SP matching the given FQDN
2873      * @param fqdn FQDN of the SP
2874      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
2875      */
2876     @Override
2877     public int matchProviderWithCurrentNetwork(String fqdn) {
2878         mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
2879         return 0;
2880     }
2881 
2882     /**
2883      * Deauthenticate and set the re-authentication hold off time for the current network
2884      * @param holdoff hold off time in milliseconds
2885      * @param ess set if the hold off pertains to an ESS rather than a BSS
2886      */
2887     @Override
2888     public void deauthenticateNetwork(long holdoff, boolean ess) {
2889         mLog.info("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
2890         mClientModeImpl.deauthenticateNetwork(mClientModeImplChannel, holdoff, ess);
2891     }
2892 
2893      /**
2894      * Get the country code
2895      * @return Get the best choice country code for wifi, regardless of if it was set or
2896      * not.
2897      * Returns null when there is no country code available.
2898      */
2899     @Override
2900     public String getCountryCode() {
2901         enforceNetworkSettingsPermission();
2902         if (mVerboseLoggingEnabled) {
2903             mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
2904         }
2905         return mCountryCode.getCountryCode();
2906     }
2907 
2908     @Override
2909     public boolean is5GHzBandSupported() {
2910         if (mVerboseLoggingEnabled) {
2911             mLog.info("is5GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
2912         }
2913 
2914         return is5GhzBandSupportedInternal();
2915     }
2916 
2917     private boolean is5GhzBandSupportedInternal() {
2918         return mWifiThreadRunner.call(
2919                 () -> mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ), false);
2920     }
2921 
2922     @Override
2923     public boolean is6GHzBandSupported() {
2924         if (mVerboseLoggingEnabled) {
2925             mLog.info("is6GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
2926         }
2927 
2928         return is6GhzBandSupportedInternal();
2929     }
2930 
2931     private boolean is6GhzBandSupportedInternal() {
2932         return mWifiThreadRunner.call(
2933                 () -> mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ), false);
2934     }
2935 
2936     @Override
2937     public boolean isWifiStandardSupported(@WifiStandard int standard) {
2938         return mWifiThreadRunner.call(
2939                 () -> mClientModeImpl.isWifiStandardSupported(standard), false);
2940     }
2941 
2942     /**
2943      * Return the DHCP-assigned addresses from the last successful DHCP request,
2944      * if any.
2945      * @return the DHCP information
2946      * @deprecated
2947      */
2948     @Override
2949     @Deprecated
2950     public DhcpInfo getDhcpInfo() {
2951         enforceAccessPermission();
2952         if (mVerboseLoggingEnabled) {
2953             mLog.info("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
2954         }
2955         DhcpResultsParcelable dhcpResults = mClientModeImpl.syncGetDhcpResultsParcelable();
2956 
2957         DhcpInfo info = new DhcpInfo();
2958 
2959         if (dhcpResults.baseConfiguration != null) {
2960             if (dhcpResults.baseConfiguration.getIpAddress() != null
2961                     && dhcpResults.baseConfiguration.getIpAddress().getAddress()
2962                     instanceof Inet4Address) {
2963                 info.ipAddress = Inet4AddressUtils.inet4AddressToIntHTL(
2964                         (Inet4Address) dhcpResults.baseConfiguration.getIpAddress().getAddress());
2965             }
2966 
2967             if (dhcpResults.baseConfiguration.getGateway() != null) {
2968                 info.gateway = Inet4AddressUtils.inet4AddressToIntHTL(
2969                         (Inet4Address) dhcpResults.baseConfiguration.getGateway());
2970             }
2971 
2972             int dnsFound = 0;
2973             for (InetAddress dns : dhcpResults.baseConfiguration.getDnsServers()) {
2974                 if (dns instanceof Inet4Address) {
2975                     if (dnsFound == 0) {
2976                         info.dns1 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns);
2977                     } else {
2978                         info.dns2 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns);
2979                     }
2980                     if (++dnsFound > 1) break;
2981                 }
2982             }
2983         }
2984         String serverAddress = dhcpResults.serverAddress;
2985         if (serverAddress != null) {
2986             InetAddress serverInetAddress = InetAddresses.parseNumericAddress(serverAddress);
2987             info.serverAddress =
2988                     Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) serverInetAddress);
2989         }
2990         info.leaseDuration = dhcpResults.leaseDuration;
2991 
2992         return info;
2993     }
2994 
2995     /**
2996      * enable TDLS for the local NIC to remote NIC
2997      * The APPs don't know the remote MAC address to identify NIC though,
2998      * so we need to do additional work to find it from remote IP address
2999      */
3000 
3001     private static class TdlsTaskParams {
3002         String mRemoteIpAddress;
3003         boolean mEnable;
3004     }
3005 
3006     private class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
3007         @Override
3008         protected Integer doInBackground(TdlsTaskParams... params) {
3009 
3010             // Retrieve parameters for the call
3011             TdlsTaskParams param = params[0];
3012             String remoteIpAddress = param.mRemoteIpAddress.trim();
3013             boolean enable = param.mEnable;
3014 
3015             // Get MAC address of Remote IP
3016             String macAddress = null;
3017 
3018             try (BufferedReader reader = new BufferedReader(new FileReader("/proc/net/arp"))) {
3019                 // Skip over the line bearing column titles
3020                 reader.readLine();
3021 
3022                 String line;
3023                 while ((line = reader.readLine()) != null) {
3024                     String[] tokens = line.split("[ ]+");
3025                     if (tokens.length < 6) {
3026                         continue;
3027                     }
3028 
3029                     // ARP column format is
3030                     // Address HWType HWAddress Flags Mask IFace
3031                     String ip = tokens[0];
3032                     String mac = tokens[3];
3033 
3034                     if (remoteIpAddress.equals(ip)) {
3035                         macAddress = mac;
3036                         break;
3037                     }
3038                 }
3039 
3040                 if (macAddress == null) {
3041                     Log.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in "
3042                             + "/proc/net/arp");
3043                 } else {
3044                     enableTdlsWithMacAddress(macAddress, enable);
3045                 }
3046 
3047             } catch (FileNotFoundException e) {
3048                 Log.e(TAG, "Could not open /proc/net/arp to lookup mac address");
3049             } catch (IOException e) {
3050                 Log.e(TAG, "Could not read /proc/net/arp to lookup mac address");
3051             }
3052             return 0;
3053         }
3054     }
3055 
3056     @Override
3057     public void enableTdls(String remoteAddress, boolean enable) {
3058         if (remoteAddress == null) {
3059           throw new IllegalArgumentException("remoteAddress cannot be null");
3060         }
3061         mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
3062         TdlsTaskParams params = new TdlsTaskParams();
3063         params.mRemoteIpAddress = remoteAddress;
3064         params.mEnable = enable;
3065         new TdlsTask().execute(params);
3066     }
3067 
3068 
3069     @Override
3070     public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
3071         mLog.info("enableTdlsWithMacAddress uid=% enable=%")
3072                 .c(Binder.getCallingUid())
3073                 .c(enable)
3074                 .flush();
3075         if (remoteMacAddress == null) {
3076           throw new IllegalArgumentException("remoteMacAddress cannot be null");
3077         }
3078 
3079         mClientModeImpl.enableTdls(remoteMacAddress, enable);
3080     }
3081 
3082     /**
3083      * Temporarily disable a network, should be trigger when user disconnect a network
3084      */
3085     @Override
3086     public void disableEphemeralNetwork(String network, String packageName) {
3087         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
3088                 "WifiService");
3089         if (!isPrivileged(Binder.getCallingPid(), Binder.getCallingUid())) {
3090             mLog.info("disableEphemeralNetwork not allowed for uid=%")
3091                     .c(Binder.getCallingUid()).flush();
3092             return;
3093         }
3094         mLog.info("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
3095         mWifiThreadRunner.post(() -> mWifiConfigManager.userTemporarilyDisabledNetwork(network,
3096                 Binder.getCallingUid()));
3097     }
3098 
3099     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
3100         @Override
3101         public void onReceive(Context context, Intent intent) {
3102             String action = intent.getAction();
3103             if (action.equals(Intent.ACTION_USER_REMOVED)) {
3104                 UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
3105                 if (userHandle == null) {
3106                     Log.e(TAG, "User removed broadcast received with no user handle");
3107                     return;
3108                 }
3109                 mWifiThreadRunner.post(() ->
3110                         mWifiConfigManager.removeNetworksForUser(userHandle.getIdentifier()));
3111             } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
3112                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
3113                         BluetoothAdapter.STATE_DISCONNECTED);
3114                 mClientModeImpl.sendBluetoothAdapterConnectionStateChange(state);
3115             } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
3116                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
3117                         BluetoothAdapter.STATE_OFF);
3118                 mClientModeImpl.sendBluetoothAdapterStateChange(state);
3119             } else if (action.equals(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
3120                 boolean emergencyMode =
3121                         intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false);
3122                 mActiveModeWarden.emergencyCallbackModeChanged(emergencyMode);
3123             } else if (action.equals(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED)) {
3124                 boolean inCall =
3125                         intent.getBooleanExtra(
3126                                 TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false);
3127                 mActiveModeWarden.emergencyCallStateChanged(inCall);
3128             } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
3129                 handleIdleModeChanged();
3130             } else if (action.equals(Intent.ACTION_SHUTDOWN)) {
3131                 handleShutDown();
3132             }
3133         }
3134     };
3135 
3136     private void registerForBroadcasts() {
3137         IntentFilter intentFilter = new IntentFilter();
3138         intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
3139         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
3140         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
3141         intentFilter.addDataScheme("package");
3142         mContext.registerReceiver(new BroadcastReceiver() {
3143             @Override
3144             public void onReceive(Context context, Intent intent) {
3145                 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
3146                 Uri uri = intent.getData();
3147                 if (uid == -1 || uri == null) {
3148                     Log.e(TAG, "Uid or Uri is missing for action:" + intent.getAction());
3149                     return;
3150                 }
3151                 String pkgName = uri.getSchemeSpecificPart();
3152                 PackageManager pm = context.getPackageManager();
3153                 PackageInfo packageInfo = null;
3154                 try {
3155                     packageInfo = pm.getPackageInfo(pkgName, 0);
3156                 } catch (PackageManager.NameNotFoundException e) {
3157                     Log.w(TAG, "Couldn't get PackageInfo for package:" + pkgName);
3158                 }
3159                 // If package is not removed or disabled, just ignore.
3160                 if (packageInfo != null
3161                         && packageInfo.applicationInfo != null
3162                         && packageInfo.applicationInfo.enabled) {
3163                     return;
3164                 }
3165                 Log.d(TAG, "Remove settings for package:" + pkgName);
3166                 // Call the method in the main Wifi thread.
3167                 mWifiThreadRunner.post(() -> {
3168                     ApplicationInfo ai = new ApplicationInfo();
3169                     ai.packageName = pkgName;
3170                     ai.uid = uid;
3171                     mWifiConfigManager.removeNetworksForApp(ai);
3172                     mScanRequestProxy.clearScanRequestTimestampsForApp(pkgName, uid);
3173 
3174                     // Remove all suggestions from the package.
3175                     mWifiNetworkSuggestionsManager.removeApp(pkgName);
3176                     mClientModeImpl.removeNetworkRequestUserApprovedAccessPointsForApp(pkgName);
3177 
3178                     // Remove all Passpoint profiles from package.
3179                     mWifiInjector.getPasspointManager().removePasspointProviderWithPackage(
3180                             pkgName);
3181                 });
3182             }
3183         }, intentFilter);
3184     }
3185 
3186     private void registerForCarrierConfigChange() {
3187         IntentFilter filter = new IntentFilter();
3188         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
3189         mContext.registerReceiver(new BroadcastReceiver() {
3190             @Override
3191             public void onReceive(Context context, Intent intent) {
3192                 final int subId = SubscriptionManager.getActiveDataSubscriptionId();
3193                 Log.d(TAG, "ACTION_CARRIER_CONFIG_CHANGED, active subId: " + subId);
3194 
3195                 mTetheredSoftApTracker.updateSoftApCapability(subId);
3196                 mActiveModeWarden.updateSoftApCapability(
3197                         mTetheredSoftApTracker.getSoftApCapability());
3198             }
3199         }, filter);
3200 
3201         WifiPhoneStateListener phoneStateListener = new WifiPhoneStateListener(
3202                 mWifiInjector.getWifiHandlerThread().getLooper());
3203 
3204         mContext.getSystemService(TelephonyManager.class).listen(
3205                 phoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
3206     }
3207 
3208     @Override
3209     public int handleShellCommand(@NonNull ParcelFileDescriptor in,
3210             @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
3211             @NonNull String[] args) {
3212         return new WifiShellCommand(mWifiInjector, this, mContext).exec(
3213                 this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(),
3214                 args);
3215     }
3216 
3217     private void updateWifiMetrics() {
3218         mWifiThreadRunner.run(() -> {
3219             mWifiMetrics.updateSavedNetworks(
3220                     mWifiConfigManager.getSavedNetworks(Process.WIFI_UID));
3221             mPasspointManager.updateMetrics();
3222         });
3223         boolean isEnhancedMacRandEnabled = mFrameworkFacade.getIntegerSetting(mContext,
3224                 WifiConfigManager.ENHANCED_MAC_RANDOMIZATION_FEATURE_FORCE_ENABLE_FLAG, 0) == 1
3225                 ? true : false;
3226         mWifiMetrics.setEnhancedMacRandomizationForceEnabled(isEnhancedMacRandEnabled);
3227         mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanAlwaysAvailable());
3228         mWifiMetrics.setVerboseLoggingEnabled(mVerboseLoggingEnabled);
3229         mWifiMetrics.setWifiWakeEnabled(mWifiInjector.getWakeupController().isEnabled());
3230     }
3231 
3232     @Override
3233     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3234         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
3235                 != PERMISSION_GRANTED) {
3236             pw.println("Permission Denial: can't dump WifiService from from pid="
3237                     + Binder.getCallingPid()
3238                     + ", uid=" + Binder.getCallingUid());
3239             return;
3240         }
3241         if (args != null && args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
3242             // WifiMetrics proto bytes were requested. Dump only these.
3243             updateWifiMetrics();
3244             mWifiMetrics.dump(fd, pw, args);
3245         } else if (args != null && args.length > 0 && IpClientUtil.DUMP_ARG.equals(args[0])) {
3246             // IpClient dump was requested. Pass it along and take no further action.
3247             String[] ipClientArgs = new String[args.length - 1];
3248             System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length);
3249             mClientModeImpl.dumpIpClient(fd, pw, ipClientArgs);
3250         } else if (args != null && args.length > 0 && WifiScoreReport.DUMP_ARG.equals(args[0])) {
3251             WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport();
3252             if (wifiScoreReport != null) wifiScoreReport.dump(fd, pw, args);
3253         } else if (args != null && args.length > 0 && WifiScoreCard.DUMP_ARG.equals(args[0])) {
3254             WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
3255             String networkListBase64 = mWifiThreadRunner.call(() ->
3256                     wifiScoreCard.getNetworkListBase64(true), "");
3257             pw.println(networkListBase64);
3258         } else {
3259             // Polls link layer stats and RSSI. This allows the stats to show up in
3260             // WifiScoreReport's dump() output when taking a bug report even if the screen is off.
3261             mClientModeImpl.updateLinkLayerStatsRssiAndScoreReport();
3262             pw.println("Wi-Fi is " + mClientModeImpl.syncGetWifiStateByName());
3263             pw.println("Verbose logging is " + (mVerboseLoggingEnabled ? "on" : "off"));
3264             pw.println("Stay-awake conditions: " +
3265                     mFacade.getIntegerSetting(mContext,
3266                             Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
3267             pw.println("mInIdleMode " + mInIdleMode);
3268             pw.println("mScanPending " + mScanPending);
3269             mSettingsStore.dump(fd, pw, args);
3270             mWifiTrafficPoller.dump(fd, pw, args);
3271             pw.println();
3272             pw.println("Locks held:");
3273             mWifiLockManager.dump(pw);
3274             pw.println();
3275             mWifiMulticastLockManager.dump(pw);
3276             pw.println();
3277             mActiveModeWarden.dump(fd, pw, args);
3278             pw.println();
3279             mClientModeImpl.dump(fd, pw, args);
3280             pw.println();
3281             WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
3282             String networkListBase64 = mWifiThreadRunner.call(() ->
3283                     wifiScoreCard.getNetworkListBase64(true), "");
3284             pw.println("WifiScoreCard:");
3285             pw.println(networkListBase64);
3286 
3287             updateWifiMetrics();
3288             mWifiMetrics.dump(fd, pw, args);
3289 
3290             pw.println();
3291             mWifiThreadRunner.run(() -> mWifiNetworkSuggestionsManager.dump(fd, pw, args));
3292             pw.println();
3293             mWifiBackupRestore.dump(fd, pw, args);
3294             pw.println();
3295             pw.println("ScoringParams: " + mWifiInjector.getScoringParams());
3296             pw.println();
3297             pw.println("WifiScoreReport:");
3298             WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport();
3299             wifiScoreReport.dump(fd, pw, args);
3300             pw.println();
3301             SarManager sarManager = mWifiInjector.getSarManager();
3302             sarManager.dump(fd, pw, args);
3303             pw.println();
3304             mWifiThreadRunner.run(() -> {
3305                 mWifiInjector.getWifiNetworkScoreCache().dumpWithLatestScanResults(
3306                         fd, pw, args, mScanRequestProxy.getScanResults());
3307                 mWifiInjector.getSettingsConfigStore().dump(fd, pw, args);
3308             });
3309             pw.println();
3310         }
3311     }
3312 
3313     @Override
3314     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
3315         mLog.info("acquireWifiLock uid=% lockMode=%")
3316                 .c(Binder.getCallingUid())
3317                 .c(lockMode).flush();
3318 
3319         // Check on permission to make this call
3320         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
3321 
3322         // If no UID is provided in worksource, use the calling UID
3323         WorkSource updatedWs = (ws == null || ws.isEmpty())
3324                 ? new WorkSource(Binder.getCallingUid()) : ws;
3325 
3326         if (!WifiLockManager.isValidLockMode(lockMode)) {
3327             throw new IllegalArgumentException("lockMode =" + lockMode);
3328         }
3329 
3330         return mWifiThreadRunner.call(() ->
3331                 mWifiLockManager.acquireWifiLock(lockMode, tag, binder, updatedWs), false);
3332     }
3333 
3334     @Override
3335     public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
3336         mLog.info("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
3337 
3338         // Check on permission to make this call
3339         mContext.enforceCallingOrSelfPermission(
3340                 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
3341 
3342         // If no UID is provided in worksource, use the calling UID
3343         WorkSource updatedWs = (ws == null || ws.isEmpty())
3344                 ? new WorkSource(Binder.getCallingUid()) : ws;
3345 
3346         mWifiThreadRunner.run(() ->
3347                 mWifiLockManager.updateWifiLockWorkSource(binder, updatedWs));
3348     }
3349 
3350     @Override
3351     public boolean releaseWifiLock(IBinder binder) {
3352         mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
3353 
3354         // Check on permission to make this call
3355         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
3356 
3357         return mWifiThreadRunner.call(() ->
3358                 mWifiLockManager.releaseWifiLock(binder), false);
3359     }
3360 
3361     @Override
3362     public void initializeMulticastFiltering() {
3363         enforceMulticastChangePermission();
3364         mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
3365         mWifiMulticastLockManager.initializeFiltering();
3366     }
3367 
3368     @Override
3369     public void acquireMulticastLock(IBinder binder, String tag) {
3370         enforceMulticastChangePermission();
3371         mLog.info("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
3372         mWifiMulticastLockManager.acquireLock(binder, tag);
3373     }
3374 
3375     @Override
3376     public void releaseMulticastLock(String tag) {
3377         enforceMulticastChangePermission();
3378         mLog.info("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
3379         mWifiMulticastLockManager.releaseLock(tag);
3380     }
3381 
3382     @Override
3383     public boolean isMulticastEnabled() {
3384         enforceAccessPermission();
3385         if (mVerboseLoggingEnabled) {
3386             mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
3387         }
3388         return mWifiMulticastLockManager.isMulticastEnabled();
3389     }
3390 
3391     @Override
3392     public void enableVerboseLogging(int verbose) {
3393         enforceAccessPermission();
3394         enforceNetworkSettingsPermission();
3395         mLog.info("enableVerboseLogging uid=% verbose=%")
3396                 .c(Binder.getCallingUid())
3397                 .c(verbose).flush();
3398         mWifiInjector.getSettingsConfigStore().put(WIFI_VERBOSE_LOGGING_ENABLED, verbose > 0);
3399         enableVerboseLoggingInternal(verbose);
3400     }
3401 
3402     private void enableVerboseLoggingInternal(int verbose) {
3403         mVerboseLoggingEnabled = verbose > 0;
3404         mClientModeImpl.enableVerboseLogging(verbose);
3405         mWifiLockManager.enableVerboseLogging(verbose);
3406         mWifiMulticastLockManager.enableVerboseLogging(verbose);
3407         mWifiInjector.enableVerboseLogging(verbose);
3408     }
3409 
3410     @Override
3411     public int getVerboseLoggingLevel() {
3412         if (mVerboseLoggingEnabled) {
3413             mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
3414         }
3415         return mWifiInjector.getSettingsConfigStore().get(WIFI_VERBOSE_LOGGING_ENABLED) ? 1 : 0;
3416     }
3417 
3418     @Override
3419     public void factoryReset(String packageName) {
3420         enforceNetworkSettingsPermission();
3421         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
3422             return;
3423         }
3424         mLog.info("factoryReset uid=%").c(Binder.getCallingUid()).flush();
3425         if (mUserManager.hasUserRestrictionForUser(
3426                 UserManager.DISALLOW_NETWORK_RESET,
3427                 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) {
3428             return;
3429         }
3430         if (!mUserManager.hasUserRestrictionForUser(
3431                 UserManager.DISALLOW_CONFIG_TETHERING,
3432                 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) {
3433             // Turn mobile hotspot off
3434             stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
3435         }
3436 
3437         if (mUserManager.hasUserRestrictionForUser(
3438                 UserManager.DISALLOW_CONFIG_WIFI,
3439                 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) {
3440             return;
3441         }
3442         // Delete all Wifi SSIDs
3443         List<WifiConfiguration> networks = mWifiThreadRunner.call(
3444                 () -> mWifiConfigManager.getSavedNetworks(Process.WIFI_UID),
3445                 Collections.emptyList());
3446         for (WifiConfiguration network : networks) {
3447             removeNetwork(network.networkId, packageName);
3448         }
3449         // Delete all Passpoint configurations
3450         List<PasspointConfiguration> configs = mWifiThreadRunner.call(
3451                 () -> mPasspointManager.getProviderConfigs(Process.WIFI_UID /* ignored */, true),
3452                 Collections.emptyList());
3453         for (PasspointConfiguration config : configs) {
3454             removePasspointConfigurationInternal(null, config.getUniqueId());
3455         }
3456         mWifiThreadRunner.post(() -> {
3457             mPasspointManager.clearAnqpRequestsAndFlushCache();
3458             mWifiConfigManager.clearUserTemporarilyDisabledList();
3459             mWifiConfigManager.removeAllEphemeralOrPasspointConfiguredNetworks();
3460             mClientModeImpl.clearNetworkRequestUserApprovedAccessPoints();
3461             mWifiNetworkSuggestionsManager.clear();
3462             mWifiInjector.getWifiScoreCard().clear();
3463             mWifiInjector.getWifiHealthMonitor().clear();
3464             notifyFactoryReset();
3465         });
3466     }
3467 
3468     /**
3469      * Notify the Factory Reset Event to application who may installed wifi configurations.
3470      */
3471     private void notifyFactoryReset() {
3472         Intent intent = new Intent(WifiManager.ACTION_NETWORK_SETTINGS_RESET);
3473 
3474         // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts
3475         // to wake them up (if they're in background).
3476         List<ResolveInfo> resolveInfos =
3477                 mContext.getPackageManager().queryBroadcastReceiversAsUser(
3478                         intent, 0,
3479                         UserHandle.of(mWifiInjector.getWifiPermissionsWrapper().getCurrentUser()));
3480         if (resolveInfos == null || resolveInfos.isEmpty()) return; // No need to send broadcast.
3481 
3482         for (ResolveInfo resolveInfo : resolveInfos) {
3483             Intent intentToSend = new Intent(intent);
3484             intentToSend.setComponent(new ComponentName(
3485                     resolveInfo.activityInfo.applicationInfo.packageName,
3486                     resolveInfo.activityInfo.name));
3487             mContext.sendBroadcastAsUser(intentToSend, UserHandle.ALL,
3488                     android.Manifest.permission.NETWORK_CARRIER_PROVISIONING);
3489         }
3490     }
3491 
3492     @Override
3493     public Network getCurrentNetwork() {
3494         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3495             throw new SecurityException(TAG + ": Permission denied");
3496         }
3497         if (mVerboseLoggingEnabled) {
3498             mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
3499         }
3500         return mClientModeImpl.syncGetCurrentNetwork(mClientModeImplChannel);
3501     }
3502 
3503     public static String toHexString(String s) {
3504         if (s == null) {
3505             return "null";
3506         }
3507         StringBuilder sb = new StringBuilder();
3508         sb.append('\'').append(s).append('\'');
3509         for (int n = 0; n < s.length(); n++) {
3510             sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
3511         }
3512         return sb.toString();
3513     }
3514 
3515     /**
3516      * Retrieve the data to be backed to save the current state.
3517      *
3518      * @return  Raw byte stream of the data to be backed up.
3519      */
3520     @Override
3521     public byte[] retrieveBackupData() {
3522         enforceNetworkSettingsPermission();
3523         mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
3524         if (mClientModeImplChannel == null) {
3525             Log.e(TAG, "mClientModeImplChannel is not initialized");
3526             return null;
3527         }
3528 
3529         Log.d(TAG, "Retrieving backup data");
3530         List<WifiConfiguration> wifiConfigurations = mWifiThreadRunner.call(
3531                 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(), null);
3532         byte[] backupData =
3533                 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
3534         Log.d(TAG, "Retrieved backup data");
3535         return backupData;
3536     }
3537 
3538     /**
3539      * Helper method to restore networks retrieved from backup data.
3540      *
3541      * @param configurations list of WifiConfiguration objects parsed from the backup data.
3542      */
3543     private void restoreNetworks(List<WifiConfiguration> configurations) {
3544         if (configurations == null) {
3545             Log.e(TAG, "Backup data parse failed");
3546             return;
3547         }
3548         int callingUid = Binder.getCallingUid();
3549         mWifiThreadRunner.run(
3550                 () -> {
3551                     for (WifiConfiguration configuration : configurations) {
3552                         int networkId =
3553                                 mWifiConfigManager.addOrUpdateNetwork(configuration, callingUid)
3554                                         .getNetworkId();
3555                         if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
3556                             Log.e(TAG, "Restore network failed: " + configuration.getKey());
3557                             continue;
3558                         }
3559                         // Enable all networks restored.
3560                         mWifiConfigManager.enableNetwork(networkId, false, callingUid, null);
3561                         // Restore auto-join param.
3562                         mWifiConfigManager.allowAutojoin(networkId, configuration.allowAutojoin);
3563                     }
3564                 });
3565     }
3566 
3567     /**
3568      * Restore state from the backed up data.
3569      *
3570      * @param data Raw byte stream of the backed up data.
3571      */
3572     @Override
3573     public void restoreBackupData(byte[] data) {
3574         enforceNetworkSettingsPermission();
3575         mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
3576         if (mClientModeImplChannel == null) {
3577             Log.e(TAG, "mClientModeImplChannel is not initialized");
3578             return;
3579         }
3580 
3581         Log.d(TAG, "Restoring backup data");
3582         List<WifiConfiguration> wifiConfigurations =
3583                 mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
3584         restoreNetworks(wifiConfigurations);
3585         Log.d(TAG, "Restored backup data");
3586     }
3587 
3588     /**
3589      * Retrieve the soft ap config data to be backed to save current config data.
3590      *
3591      * @return  Raw byte stream of the data to be backed up.
3592      */
3593     @Override
3594     public byte[] retrieveSoftApBackupData() {
3595         enforceNetworkSettingsPermission();
3596         mLog.info("retrieveSoftApBackupData uid=%").c(Binder.getCallingUid()).flush();
3597         SoftApConfiguration config = mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration,
3598                 new SoftApConfiguration.Builder().build());
3599         byte[] backupData =
3600                 mSoftApBackupRestore.retrieveBackupDataFromSoftApConfiguration(config);
3601         Log.d(TAG, "Retrieved soft ap backup data");
3602         return backupData;
3603     }
3604 
3605     /**
3606      * Restore soft ap config from the backed up data.
3607      *
3608      * @param data Raw byte stream of the backed up data.
3609      * @return restored SoftApConfiguration or Null if data is invalid.
3610      */
3611     @Override
3612     public SoftApConfiguration restoreSoftApBackupData(byte[] data) {
3613         enforceNetworkSettingsPermission();
3614         mLog.info("restoreSoftApBackupData uid=%").c(Binder.getCallingUid()).flush();
3615         SoftApConfiguration softApConfig =
3616                 mSoftApBackupRestore.retrieveSoftApConfigurationFromBackupData(data);
3617         if (softApConfig != null) {
3618             mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(
3619                     mWifiApConfigStore.resetToDefaultForUnsupportedConfig(softApConfig)));
3620             Log.d(TAG, "Restored soft ap backup data");
3621         }
3622         return softApConfig;
3623     }
3624 
3625 
3626     /**
3627      * Restore state from the older supplicant back up data.
3628      * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
3629      *
3630      * @param supplicantData Raw byte stream of wpa_supplicant.conf
3631      * @param ipConfigData Raw byte stream of ipconfig.txt
3632      */
3633     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
3634         enforceNetworkSettingsPermission();
3635         mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
3636         if (mClientModeImplChannel == null) {
3637             Log.e(TAG, "mClientModeImplChannel is not initialized");
3638             return;
3639         }
3640 
3641         Log.d(TAG, "Restoring supplicant backup data");
3642         List<WifiConfiguration> wifiConfigurations =
3643                 mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
3644                         supplicantData, ipConfigData);
3645         restoreNetworks(wifiConfigurations);
3646         Log.d(TAG, "Restored supplicant backup data");
3647     }
3648 
3649     /**
3650      * Starts subscription provisioning with a provider.
3651      *
3652      * @param provider {@link OsuProvider} the provider to provision with
3653      * @param callback {@link IProvisioningCallback} the callback object to inform status
3654      */
3655     @Override
3656     public void startSubscriptionProvisioning(OsuProvider provider,
3657             IProvisioningCallback callback) {
3658         if (provider == null) {
3659             throw new IllegalArgumentException("Provider must not be null");
3660         }
3661         if (callback == null) {
3662             throw new IllegalArgumentException("Callback must not be null");
3663         }
3664         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3665             throw new SecurityException(TAG + ": Permission denied");
3666         }
3667         final int uid = Binder.getCallingUid();
3668         mLog.trace("startSubscriptionProvisioning uid=%").c(uid).flush();
3669         if (mClientModeImpl.syncStartSubscriptionProvisioning(uid, provider,
3670                 callback, mClientModeImplChannel)) {
3671             mLog.trace("Subscription provisioning started with %")
3672                     .c(provider.toString()).flush();
3673         }
3674     }
3675 
3676     /**
3677      * See
3678      * {@link WifiManager#registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}
3679      *
3680      * @param binder IBinder instance to allow cleanup if the app dies
3681      * @param callback Traffic State callback to register
3682      * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to
3683      *        unregister the callback. See {@link unregisterTrafficStateCallback(int)}
3684      *
3685      * @throws SecurityException if the caller does not have permission to register a callback
3686      * @throws RemoteException if remote exception happens
3687      * @throws IllegalArgumentException if the arguments are null or invalid
3688      */
3689     @Override
3690     public void registerTrafficStateCallback(IBinder binder, ITrafficStateCallback callback,
3691                                              int callbackIdentifier) {
3692         // verify arguments
3693         if (binder == null) {
3694             throw new IllegalArgumentException("Binder must not be null");
3695         }
3696         if (callback == null) {
3697             throw new IllegalArgumentException("Callback must not be null");
3698         }
3699         enforceNetworkSettingsPermission();
3700         if (mVerboseLoggingEnabled) {
3701             mLog.info("registerTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
3702         }
3703         // Post operation to handler thread
3704         mWifiThreadRunner.post(() ->
3705                 mWifiTrafficPoller.addCallback(binder, callback, callbackIdentifier));
3706     }
3707 
3708     /**
3709      * see {@link android.net.wifi.WifiManager#unregisterTrafficStateCallback(
3710      * WifiManager.TrafficStateCallback)}
3711      *
3712      * @param callbackIdentifier Unique ID of the callback to be unregistered.
3713      *
3714      * @throws SecurityException if the caller does not have permission to register a callback
3715      */
3716     @Override
3717     public void unregisterTrafficStateCallback(int callbackIdentifier) {
3718         enforceNetworkSettingsPermission();
3719         if (mVerboseLoggingEnabled) {
3720             mLog.info("unregisterTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
3721         }
3722         // Post operation to handler thread
3723         mWifiThreadRunner.post(() ->
3724                 mWifiTrafficPoller.removeCallback(callbackIdentifier));
3725     }
3726 
3727     private long getSupportedFeaturesInternal() {
3728         final AsyncChannel channel = mClientModeImplChannel;
3729         long supportedFeatureSet = 0L;
3730         if (channel != null) {
3731             supportedFeatureSet = mClientModeImpl.syncGetSupportedFeatures(channel);
3732         } else {
3733             Log.e(TAG, "mClientModeImplChannel is not initialized");
3734             return supportedFeatureSet;
3735         }
3736         // Mask the feature set against system properties.
3737         boolean rttSupported = mContext.getPackageManager().hasSystemFeature(
3738                 PackageManager.FEATURE_WIFI_RTT);
3739         if (!rttSupported) {
3740             // flags filled in by vendor HAL, remove if overlay disables it.
3741             supportedFeatureSet &=
3742                     ~(WifiManager.WIFI_FEATURE_D2D_RTT | WifiManager.WIFI_FEATURE_D2AP_RTT);
3743         }
3744         if (!mContext.getResources().getBoolean(
3745                 R.bool.config_wifi_p2p_mac_randomization_supported)) {
3746             // flags filled in by vendor HAL, remove if overlay disables it.
3747             supportedFeatureSet &= ~WifiManager.WIFI_FEATURE_P2P_RAND_MAC;
3748         }
3749         if (mContext.getResources().getBoolean(
3750                 R.bool.config_wifi_connected_mac_randomization_supported)) {
3751             // no corresponding flags in vendor HAL, set if overlay enables it.
3752             supportedFeatureSet |= WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC;
3753         }
3754         if (mContext.getResources().getBoolean(
3755                 R.bool.config_wifi_ap_mac_randomization_supported)) {
3756             // no corresponding flags in vendor HAL, set if overlay enables it.
3757             supportedFeatureSet |= WifiManager.WIFI_FEATURE_AP_RAND_MAC;
3758         }
3759         if (mWifiThreadRunner.call(
3760                 () -> mActiveModeWarden.isStaApConcurrencySupported(),
3761                 false)) {
3762             supportedFeatureSet |= WifiManager.WIFI_FEATURE_AP_STA;
3763         }
3764         return supportedFeatureSet;
3765     }
3766 
3767     private static boolean hasAutomotiveFeature(Context context) {
3768         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
3769     }
3770 
3771     /**
3772      * See
3773      * {@link WifiManager#registerNetworkRequestMatchCallback(
3774      * Executor, WifiManager.NetworkRequestMatchCallback)}
3775      *
3776      * @param binder IBinder instance to allow cleanup if the app dies
3777      * @param callback Network Request Match callback to register
3778      * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to
3779      *                           unregister the callback.
3780      *                           See {@link #unregisterNetworkRequestMatchCallback(int)} (int)}
3781      *
3782      * @throws SecurityException if the caller does not have permission to register a callback
3783      * @throws RemoteException if remote exception happens
3784      * @throws IllegalArgumentException if the arguments are null or invalid
3785      */
3786     @Override
3787     public void registerNetworkRequestMatchCallback(IBinder binder,
3788                                                     INetworkRequestMatchCallback callback,
3789                                                     int callbackIdentifier) {
3790         // verify arguments
3791         if (binder == null) {
3792             throw new IllegalArgumentException("Binder must not be null");
3793         }
3794         if (callback == null) {
3795             throw new IllegalArgumentException("Callback must not be null");
3796         }
3797         enforceNetworkSettingsPermission();
3798         if (mVerboseLoggingEnabled) {
3799             mLog.info("registerNetworkRequestMatchCallback uid=%")
3800                     .c(Binder.getCallingUid()).flush();
3801         }
3802         // Post operation to handler thread
3803         mWifiThreadRunner.post(() -> mClientModeImpl.addNetworkRequestMatchCallback(
3804                 binder, callback, callbackIdentifier));
3805     }
3806 
3807     /**
3808      * see {@link android.net.wifi.WifiManager#unregisterNetworkRequestMatchCallback(
3809      * WifiManager.NetworkRequestMatchCallback)}
3810      *
3811      * @param callbackIdentifier Unique ID of the callback to be unregistered.
3812      *
3813      * @throws SecurityException if the caller does not have permission to register a callback
3814      */
3815     @Override
3816     public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) {
3817         enforceNetworkSettingsPermission();
3818         if (mVerboseLoggingEnabled) {
3819             mLog.info("unregisterNetworkRequestMatchCallback uid=%")
3820                     .c(Binder.getCallingUid()).flush();
3821         }
3822         // Post operation to handler thread
3823         mWifiThreadRunner.post(() ->
3824                 mClientModeImpl.removeNetworkRequestMatchCallback(callbackIdentifier));
3825     }
3826 
3827     /**
3828      * See {@link android.net.wifi.WifiManager#addNetworkSuggestions(List)}
3829      *
3830      * @param networkSuggestions List of network suggestions to be added.
3831      * @param callingPackageName Package Name of the app adding the suggestions.
3832      * @param callingFeatureId Feature in the calling package
3833      * @throws SecurityException if the caller does not have permission.
3834      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
3835      */
3836     @Override
3837     public int addNetworkSuggestions(
3838             List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName,
3839             String callingFeatureId) {
3840         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
3841             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
3842         }
3843         if (mVerboseLoggingEnabled) {
3844             mLog.info("addNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush();
3845         }
3846         int callingUid = Binder.getCallingUid();
3847 
3848         int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.add(
3849                 networkSuggestions, callingUid, callingPackageName, callingFeatureId),
3850                 WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL);
3851         if (success != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
3852             Log.e(TAG, "Failed to add network suggestions");
3853         }
3854         return success;
3855     }
3856 
3857     /**
3858      * See {@link android.net.wifi.WifiManager#removeNetworkSuggestions(List)}
3859      *
3860      * @param networkSuggestions List of network suggestions to be removed.
3861      * @param callingPackageName Package Name of the app removing the suggestions.
3862      * @throws SecurityException if the caller does not have permission.
3863      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
3864      */
3865     @Override
3866     public int removeNetworkSuggestions(
3867             List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
3868         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
3869             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
3870         }
3871         if (mVerboseLoggingEnabled) {
3872             mLog.info("removeNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush();
3873         }
3874         int callingUid = Binder.getCallingUid();
3875 
3876         int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.remove(
3877                 networkSuggestions, callingUid, callingPackageName),
3878                 WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL);
3879         if (success != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
3880             Log.e(TAG, "Failed to remove network suggestions");
3881         }
3882         return success;
3883     }
3884 
3885     /**
3886      * See {@link android.net.wifi.WifiManager#getNetworkSuggestions()}
3887      * @param callingPackageName Package Name of the app getting the suggestions.
3888      * @return a list of network suggestions suggested by this app
3889      */
3890     public List<WifiNetworkSuggestion> getNetworkSuggestions(String callingPackageName) {
3891         mAppOps.checkPackage(Binder.getCallingUid(), callingPackageName);
3892         enforceAccessPermission();
3893         if (mVerboseLoggingEnabled) {
3894             mLog.info("getNetworkSuggestionList uid=%").c(Binder.getCallingUid()).flush();
3895         }
3896         return mWifiThreadRunner.call(() ->
3897                 mWifiNetworkSuggestionsManager.get(callingPackageName), Collections.emptyList());
3898     }
3899 
3900     /**
3901      * Gets the factory Wi-Fi MAC addresses.
3902      * @throws SecurityException if the caller does not have permission.
3903      * @return Array of String representing Wi-Fi MAC addresses, or empty array if failed.
3904      */
3905     @Override
3906     public String[] getFactoryMacAddresses() {
3907         final int uid = Binder.getCallingUid();
3908         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
3909             throw new SecurityException("App not allowed to get Wi-Fi factory MAC address "
3910                     + "(uid = " + uid + ")");
3911         }
3912         String result = mWifiThreadRunner.call(mClientModeImpl::getFactoryMacAddress, null);
3913         // result can be empty array if either: WifiThreadRunner.call() timed out, or
3914         // ClientModeImpl.getFactoryMacAddress() returned null.
3915         // In this particular instance, we don't differentiate the two types of nulls.
3916         if (result == null) {
3917             return new String[0];
3918         }
3919         return new String[]{result};
3920     }
3921 
3922     /**
3923      * Sets the current device mobility state.
3924      * @param state the new device mobility state
3925      */
3926     @Override
3927     public void setDeviceMobilityState(@DeviceMobilityState int state) {
3928         mContext.enforceCallingOrSelfPermission(
3929                 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE, "WifiService");
3930 
3931         if (mVerboseLoggingEnabled) {
3932             mLog.info("setDeviceMobilityState uid=% state=%")
3933                     .c(Binder.getCallingUid())
3934                     .c(state)
3935                     .flush();
3936         }
3937         // Post operation to handler thread
3938         mWifiThreadRunner.post(() -> mClientModeImpl.setDeviceMobilityState(state));
3939     }
3940 
3941     /**
3942      * Proxy for the final native call of the parent class. Enables mocking of
3943      * the function.
3944      */
3945     public int getMockableCallingUid() {
3946         return getCallingUid();
3947     }
3948 
3949     /**
3950      * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
3951      * with a peer, and send the SSID and password of the selected network.
3952      *
3953      * @param binder Caller's binder context
3954      * @param enrolleeUri URI of the Enrollee obtained externally (e.g. QR code scanning)
3955      * @param selectedNetworkId Selected network ID to be sent to the peer
3956      * @param netRole The network role of the enrollee
3957      * @param callback Callback for status updates
3958      */
3959     @Override
3960     public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri,
3961             int selectedNetworkId, int netRole, IDppCallback callback) {
3962         // verify arguments
3963         if (binder == null) {
3964             throw new IllegalArgumentException("Binder must not be null");
3965         }
3966         if (TextUtils.isEmpty(enrolleeUri)) {
3967             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
3968         }
3969         if (selectedNetworkId < 0) {
3970             throw new IllegalArgumentException("Selected network ID invalid");
3971         }
3972         if (callback == null) {
3973             throw new IllegalArgumentException("Callback must not be null");
3974         }
3975 
3976         final int uid = getMockableCallingUid();
3977 
3978         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3979             throw new SecurityException(TAG + ": Permission denied");
3980         }
3981 
3982         mWifiThreadRunner.post(() -> mDppManager.startDppAsConfiguratorInitiator(
3983                 uid, binder, enrolleeUri, selectedNetworkId, netRole, callback));
3984     }
3985 
3986     /**
3987      * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
3988      * with a peer, and receive the SSID and password from the peer configurator.
3989      *
3990      * @param binder Caller's binder context
3991      * @param configuratorUri URI of the Configurator obtained externally (e.g. QR code scanning)
3992      * @param callback Callback for status updates
3993      */
3994     @Override
3995     public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
3996             IDppCallback callback) {
3997         // verify arguments
3998         if (binder == null) {
3999             throw new IllegalArgumentException("Binder must not be null");
4000         }
4001         if (TextUtils.isEmpty(configuratorUri)) {
4002             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
4003         }
4004         if (callback == null) {
4005             throw new IllegalArgumentException("Callback must not be null");
4006         }
4007 
4008         final int uid = getMockableCallingUid();
4009 
4010         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4011             throw new SecurityException(TAG + ": Permission denied");
4012         }
4013 
4014         mWifiThreadRunner.post(() ->
4015                 mDppManager.startDppAsEnrolleeInitiator(uid, binder, configuratorUri, callback));
4016     }
4017 
4018     /**
4019      * Stop or abort a current DPP session.
4020      */
4021     @Override
4022     public void stopDppSession() throws RemoteException {
4023         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4024             throw new SecurityException(TAG + ": Permission denied");
4025         }
4026         final int uid = getMockableCallingUid();
4027 
4028         mWifiThreadRunner.post(() -> mDppManager.stopDppSession(uid));
4029     }
4030 
4031     /**
4032      * see {@link android.net.wifi.WifiManager#addOnWifiUsabilityStatsListener(Executor,
4033      * OnWifiUsabilityStatsListener)}
4034      *
4035      * @param binder IBinder instance to allow cleanup if the app dies
4036      * @param listener WifiUsabilityStatsEntry listener to add
4037      * @param listenerIdentifier Unique ID of the adding listener. This ID will be used to
4038      *        remove the listener. See {@link removeOnWifiUsabilityStatsListener(int)}
4039      *
4040      * @throws SecurityException if the caller does not have permission to add a listener
4041      * @throws RemoteException if remote exception happens
4042      * @throws IllegalArgumentException if the arguments are null or invalid
4043      */
4044     @Override
4045     public void addOnWifiUsabilityStatsListener(IBinder binder,
4046             IOnWifiUsabilityStatsListener listener, int listenerIdentifier) {
4047         // verify arguments
4048         if (binder == null) {
4049             throw new IllegalArgumentException("Binder must not be null");
4050         }
4051         if (listener == null) {
4052             throw new IllegalArgumentException("Listener must not be null");
4053         }
4054         mContext.enforceCallingOrSelfPermission(
4055                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4056         if (mVerboseLoggingEnabled) {
4057             mLog.info("addOnWifiUsabilityStatsListener uid=%")
4058                 .c(Binder.getCallingUid()).flush();
4059         }
4060         // Post operation to handler thread
4061         mWifiThreadRunner.post(() ->
4062                 mWifiMetrics.addOnWifiUsabilityListener(binder, listener, listenerIdentifier));
4063     }
4064 
4065     /**
4066      * see {@link android.net.wifi.WifiManager#removeOnWifiUsabilityStatsListener(
4067      * OnWifiUsabilityStatsListener)}
4068      *
4069      * @param listenerIdentifier Unique ID of the listener to be removed.
4070      *
4071      * @throws SecurityException if the caller does not have permission to add a listener
4072      */
4073     @Override
4074     public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) {
4075         mContext.enforceCallingOrSelfPermission(
4076                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4077         if (mVerboseLoggingEnabled) {
4078             mLog.info("removeOnWifiUsabilityStatsListener uid=%")
4079                     .c(Binder.getCallingUid()).flush();
4080         }
4081         // Post operation to handler thread
4082         mWifiThreadRunner.post(() ->
4083                 mWifiMetrics.removeOnWifiUsabilityListener(listenerIdentifier));
4084     }
4085 
4086     /**
4087      * Updates the Wi-Fi usability score.
4088      * @param seqNum Sequence number of the Wi-Fi usability score.
4089      * @param score The Wi-Fi usability score.
4090      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second.
4091      */
4092     @Override
4093     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
4094         mContext.enforceCallingOrSelfPermission(
4095                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4096 
4097         if (mVerboseLoggingEnabled) {
4098             mLog.info("updateWifiUsabilityScore uid=% seqNum=% score=% predictionHorizonSec=%")
4099                     .c(Binder.getCallingUid())
4100                     .c(seqNum)
4101                     .c(score)
4102                     .c(predictionHorizonSec)
4103                     .flush();
4104         }
4105         // Post operation to handler thread
4106         mWifiThreadRunner.post(() ->
4107                 mClientModeImpl.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec));
4108     }
4109 
4110     /**
4111      * see {@link android.net.wifi.WifiManager#connect(int, WifiManager.ActionListener)}
4112      */
4113     @Override
4114     public void connect(WifiConfiguration config, int netId, IBinder binder,
4115             @Nullable IActionListener callback, int callbackIdentifier) {
4116         int uid = Binder.getCallingUid();
4117         if (!isPrivileged(Binder.getCallingPid(), uid)) {
4118             throw new SecurityException(TAG + ": Permission denied");
4119         }
4120         mLog.info("connect uid=%").c(uid).flush();
4121         mClientModeImpl.connect(config, netId, binder, callback, callbackIdentifier, uid);
4122         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4123             mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_MANUAL_CONNECT, netId);
4124         }
4125     }
4126 
4127     /**
4128      * see {@link android.net.wifi.WifiManager#save(WifiConfiguration,
4129      * WifiManager.ActionListener)}
4130      */
4131     @Override
4132     public void save(WifiConfiguration config, IBinder binder, @Nullable IActionListener callback,
4133             int callbackIdentifier) {
4134         if (!isPrivileged(Binder.getCallingPid(), Binder.getCallingUid())) {
4135             throw new SecurityException(TAG + ": Permission denied");
4136         }
4137         mLog.info("save uid=%").c(Binder.getCallingUid()).flush();
4138         mClientModeImpl.save(
4139                 config, binder, callback, callbackIdentifier, Binder.getCallingUid());
4140     }
4141 
4142     /**
4143      * see {@link android.net.wifi.WifiManager#forget(int, WifiManager.ActionListener)}
4144      */
4145     @Override
4146     public void forget(int netId, IBinder binder, @Nullable IActionListener callback,
4147             int callbackIdentifier) {
4148         int uid = Binder.getCallingUid();
4149         if (!isPrivileged(Binder.getCallingPid(), uid)) {
4150             throw new SecurityException(TAG + ": Permission denied");
4151         }
4152         mLog.info("forget uid=%").c(Binder.getCallingUid()).flush();
4153         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4154             // It's important to log this metric before the actual forget executes because
4155             // the netId becomes invalid after the forget operation.
4156             mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_FORGET_WIFI, netId);
4157         }
4158         mClientModeImpl.forget(netId, binder, callback, callbackIdentifier, uid);
4159     }
4160 
4161     /**
4162      * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)}
4163      */
4164     public void registerScanResultsCallback(@NonNull IScanResultsCallback callback) {
4165         if (callback == null) {
4166             throw new IllegalArgumentException("callback must not be null");
4167         }
4168         enforceAccessPermission();
4169 
4170         if (mVerboseLoggingEnabled) {
4171             mLog.info("registerScanResultsCallback uid=%").c(Binder.getCallingUid()).flush();
4172         }
4173         mWifiThreadRunner.post(() -> {
4174             if (!mWifiInjector.getScanRequestProxy().registerScanResultsCallback(callback)) {
4175                 Log.e(TAG, "registerScanResultsCallback: Failed to register callback");
4176             }
4177         });
4178     }
4179 
4180     /**
4181      * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)}
4182      */
4183     public void unregisterScanResultsCallback(@NonNull IScanResultsCallback callback) {
4184         if (mVerboseLoggingEnabled) {
4185             mLog.info("unregisterScanResultCallback uid=%").c(Binder.getCallingUid()).flush();
4186         }
4187         enforceAccessPermission();
4188         // post operation to handler thread
4189         mWifiThreadRunner.post(() -> mWifiInjector.getScanRequestProxy()
4190                         .unregisterScanResultsCallback(callback));
4191 
4192     }
4193 
4194     /**
4195      * See {@link WifiManager#addSuggestionConnectionStatusListener(Executor,
4196      * SuggestionConnectionStatusListener)}
4197      */
4198     public void registerSuggestionConnectionStatusListener(IBinder binder,
4199             @NonNull ISuggestionConnectionStatusListener listener,
4200             int listenerIdentifier, String packageName, @Nullable String featureId) {
4201         if (binder == null) {
4202             throw new IllegalArgumentException("Binder must not be null");
4203         }
4204         if (listener == null) {
4205             throw new IllegalArgumentException("listener must not be null");
4206         }
4207         final int uid = Binder.getCallingUid();
4208         enforceAccessPermission();
4209         enforceLocationPermission(packageName, featureId, uid);
4210         if (mVerboseLoggingEnabled) {
4211             mLog.info("registerSuggestionConnectionStatusListener uid=%").c(uid).flush();
4212         }
4213         mWifiThreadRunner.post(() ->
4214                 mWifiNetworkSuggestionsManager
4215                         .registerSuggestionConnectionStatusListener(binder, listener,
4216                                 listenerIdentifier, packageName));
4217     }
4218 
4219     /**
4220      * See {@link WifiManager#removeSuggestionConnectionStatusListener(
4221      * SuggestionConnectionStatusListener)}
4222      */
4223     public void unregisterSuggestionConnectionStatusListener(
4224             int listenerIdentifier, String packageName) {
4225         enforceAccessPermission();
4226         if (mVerboseLoggingEnabled) {
4227             mLog.info("unregisterSuggestionConnectionStatusListener uid=%")
4228                     .c(Binder.getCallingUid()).flush();
4229         }
4230         mWifiThreadRunner.post(() ->
4231                 mWifiNetworkSuggestionsManager
4232                         .unregisterSuggestionConnectionStatusListener(listenerIdentifier,
4233                                 packageName));
4234     }
4235 
4236     @Override
4237     public int calculateSignalLevel(int rssi) {
4238         return RssiUtil.calculateSignalLevel(mContext, rssi);
4239     }
4240 
4241     /**
4242      * See {@link android.net.wifi.WifiManager#setWifiConnectedNetworkScorer(Executor,
4243      * WifiConnectedNetworkScorer)}
4244      *
4245      * @param binder IBinder instance to allow cleanup if the app dies.
4246      * @param scorer Wifi connected network scorer to set.
4247      * @return true Scorer is set successfully.
4248      *
4249      * @throws RemoteException if remote exception happens
4250      * @throws IllegalArgumentException if the arguments are null or invalid
4251      */
4252     @Override
4253     public boolean setWifiConnectedNetworkScorer(IBinder binder,
4254             IWifiConnectedNetworkScorer scorer) {
4255         if (binder == null) {
4256             throw new IllegalArgumentException("Binder must not be null");
4257         }
4258         if (scorer == null) {
4259             throw new IllegalArgumentException("Scorer must not be null");
4260         }
4261         mContext.enforceCallingOrSelfPermission(
4262                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4263         if (mVerboseLoggingEnabled) {
4264             mLog.info("setWifiConnectedNetworkScorer uid=%").c(Binder.getCallingUid()).flush();
4265         }
4266         // Post operation to handler thread
4267         WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport();
4268         return mWifiThreadRunner.call(() -> wifiScoreReport.setWifiConnectedNetworkScorer(
4269                 binder, scorer), false);
4270     }
4271     /**
4272      * See {@link android.net.wifi.WifiManager#clearWifiConnectedNetworkScorer(
4273      * WifiConnectedNetworkScorer)}
4274      */
4275     @Override
4276     public void clearWifiConnectedNetworkScorer() {
4277         mContext.enforceCallingOrSelfPermission(
4278                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4279         if (mVerboseLoggingEnabled) {
4280             mLog.info("clearWifiConnectedNetworkScorer uid=%").c(Binder.getCallingUid()).flush();
4281         }
4282         // Post operation to handler thread
4283         WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport();
4284         mWifiThreadRunner.post(() ->
4285                 wifiScoreReport.clearWifiConnectedNetworkScorer());
4286     }
4287 
4288     /**
4289      * See {@link android.net.wifi.WifiManager#setScanThrottleEnabled(boolean)}
4290      */
4291     @Override
4292     public void setScanThrottleEnabled(boolean enable) {
4293         enforceNetworkSettingsPermission();
4294         mLog.info("setScanThrottleEnabled uid=% verbose=%")
4295                 .c(Binder.getCallingUid())
4296                 .c(enable).flush();
4297         mWifiThreadRunner.post(()-> mScanRequestProxy.setScanThrottleEnabled(enable));
4298     }
4299 
4300     /**
4301      * See {@link android.net.wifi.WifiManager#isScanThrottleEnabled()}
4302      */
4303     @Override
4304     public boolean isScanThrottleEnabled() {
4305         enforceAccessPermission();
4306         if (mVerboseLoggingEnabled) {
4307             mLog.info("isScanThrottleEnabled uid=%").c(Binder.getCallingUid()).flush();
4308         }
4309         return mWifiThreadRunner.call(()-> mScanRequestProxy.isScanThrottleEnabled(), true);
4310     }
4311 
4312     /**
4313      * See {@link android.net.wifi.WifiManager#setAutoWakeupEnabled(boolean)}
4314      */
4315     @Override
4316     public void setAutoWakeupEnabled(boolean enable) {
4317         enforceNetworkSettingsPermission();
4318         mLog.info("setWalkeupEnabled uid=% verbose=%")
4319                 .c(Binder.getCallingUid())
4320                 .c(enable).flush();
4321         mWifiThreadRunner.post(()-> mWifiInjector.getWakeupController().setEnabled(enable));
4322     }
4323 
4324     /**
4325      * See {@link android.net.wifi.WifiManager#isAutoWakeupEnabled()}
4326      */
4327     @Override
4328     public boolean isAutoWakeupEnabled() {
4329         enforceAccessPermission();
4330         if (mVerboseLoggingEnabled) {
4331             mLog.info("isAutoWakeupEnabled uid=%").c(Binder.getCallingUid()).flush();
4332         }
4333         return mWifiThreadRunner.call(()-> mWifiInjector.getWakeupController().isEnabled(), false);
4334     }
4335 }
4336