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.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY;
31 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
32 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED;
33 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_SIM_INSERTED;
34 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED;
35 import static com.android.server.wifi.SelfRecovery.REASON_API_CALL;
36 import static com.android.server.wifi.WifiConfigurationUtil.addSecurityTypeToNetworkId;
37 import static com.android.server.wifi.WifiConfigurationUtil.convertWifiInfoSecurityTypeToWifiConfiguration;
38 import static com.android.server.wifi.WifiConfigurationUtil.removeSecurityTypeFromNetworkId;
39 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED;
40 
41 import android.Manifest;
42 import android.annotation.CheckResult;
43 import android.annotation.NonNull;
44 import android.annotation.Nullable;
45 import android.app.AppOpsManager;
46 import android.bluetooth.BluetoothAdapter;
47 import android.content.BroadcastReceiver;
48 import android.content.ComponentName;
49 import android.content.Context;
50 import android.content.Intent;
51 import android.content.IntentFilter;
52 import android.content.pm.ApplicationInfo;
53 import android.content.pm.PackageInfo;
54 import android.content.pm.PackageManager;
55 import android.content.pm.ResolveInfo;
56 import android.net.DhcpInfo;
57 import android.net.DhcpResultsParcelable;
58 import android.net.InetAddresses;
59 import android.net.Network;
60 import android.net.NetworkCapabilities;
61 import android.net.NetworkStack;
62 import android.net.Uri;
63 import android.net.ip.IpClientUtil;
64 import android.net.wifi.CoexUnsafeChannel;
65 import android.net.wifi.IActionListener;
66 import android.net.wifi.ICoexCallback;
67 import android.net.wifi.IDppCallback;
68 import android.net.wifi.ILocalOnlyHotspotCallback;
69 import android.net.wifi.INetworkRequestMatchCallback;
70 import android.net.wifi.IOnWifiActivityEnergyInfoListener;
71 import android.net.wifi.IOnWifiUsabilityStatsListener;
72 import android.net.wifi.IScanResultsCallback;
73 import android.net.wifi.ISoftApCallback;
74 import android.net.wifi.ISubsystemRestartCallback;
75 import android.net.wifi.ISuggestionConnectionStatusListener;
76 import android.net.wifi.ISuggestionUserApprovalStatusListener;
77 import android.net.wifi.ITrafficStateCallback;
78 import android.net.wifi.IWifiConnectedNetworkScorer;
79 import android.net.wifi.IWifiVerboseLoggingStatusChangedListener;
80 import android.net.wifi.ScanResult;
81 import android.net.wifi.SoftApCapability;
82 import android.net.wifi.SoftApConfiguration;
83 import android.net.wifi.SoftApInfo;
84 import android.net.wifi.WifiAnnotations.WifiStandard;
85 import android.net.wifi.WifiAvailableChannel;
86 import android.net.wifi.WifiClient;
87 import android.net.wifi.WifiConfiguration;
88 import android.net.wifi.WifiInfo;
89 import android.net.wifi.WifiManager;
90 import android.net.wifi.WifiManager.AddNetworkResult;
91 import android.net.wifi.WifiManager.CoexRestriction;
92 import android.net.wifi.WifiManager.DeviceMobilityState;
93 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
94 import android.net.wifi.WifiManager.SapClientBlockedReason;
95 import android.net.wifi.WifiManager.SapStartFailure;
96 import android.net.wifi.WifiManager.SuggestionConnectionStatusListener;
97 import android.net.wifi.WifiManager.WifiApState;
98 import android.net.wifi.WifiNetworkSuggestion;
99 import android.net.wifi.WifiScanner;
100 import android.net.wifi.hotspot2.IProvisioningCallback;
101 import android.net.wifi.hotspot2.OsuProvider;
102 import android.net.wifi.hotspot2.PasspointConfiguration;
103 import android.os.AsyncTask;
104 import android.os.Binder;
105 import android.os.Build;
106 import android.os.Handler;
107 import android.os.HandlerExecutor;
108 import android.os.IBinder;
109 import android.os.Looper;
110 import android.os.ParcelFileDescriptor;
111 import android.os.PersistableBundle;
112 import android.os.PowerManager;
113 import android.os.Process;
114 import android.os.RemoteCallbackList;
115 import android.os.RemoteException;
116 import android.os.UserHandle;
117 import android.os.UserManager;
118 import android.os.WorkSource;
119 import android.os.connectivity.WifiActivityEnergyInfo;
120 import android.provider.Settings;
121 import android.telephony.CarrierConfigManager;
122 import android.telephony.PhoneStateListener;
123 import android.telephony.SubscriptionManager;
124 import android.telephony.TelephonyManager;
125 import android.text.TextUtils;
126 import android.util.Log;
127 
128 import androidx.annotation.RequiresApi;
129 
130 import com.android.internal.annotations.GuardedBy;
131 import com.android.internal.annotations.VisibleForTesting;
132 import com.android.modules.utils.ParceledListSlice;
133 import com.android.modules.utils.build.SdkLevel;
134 import com.android.net.module.util.Inet4AddressUtils;
135 import com.android.server.wifi.coex.CoexManager;
136 import com.android.server.wifi.hotspot2.PasspointManager;
137 import com.android.server.wifi.hotspot2.PasspointProvider;
138 import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent;
139 import com.android.server.wifi.util.ActionListenerWrapper;
140 import com.android.server.wifi.util.ApConfigUtil;
141 import com.android.server.wifi.util.GeneralUtil.Mutable;
142 import com.android.server.wifi.util.LastCallerInfoManager;
143 import com.android.server.wifi.util.RssiUtil;
144 import com.android.server.wifi.util.ScanResultUtil;
145 import com.android.server.wifi.util.WifiPermissionsUtil;
146 import com.android.wifi.resources.R;
147 
148 import java.io.BufferedReader;
149 import java.io.FileDescriptor;
150 import java.io.FileNotFoundException;
151 import java.io.FileReader;
152 import java.io.IOException;
153 import java.io.PrintWriter;
154 import java.net.Inet4Address;
155 import java.net.InetAddress;
156 import java.security.GeneralSecurityException;
157 import java.security.KeyStore;
158 import java.security.cert.CertPath;
159 import java.security.cert.CertPathValidator;
160 import java.security.cert.CertificateFactory;
161 import java.security.cert.PKIXParameters;
162 import java.security.cert.X509Certificate;
163 import java.util.ArrayList;
164 import java.util.Arrays;
165 import java.util.Collections;
166 import java.util.HashMap;
167 import java.util.List;
168 import java.util.Map;
169 import java.util.Objects;
170 import java.util.concurrent.CountDownLatch;
171 import java.util.concurrent.Executor;
172 import java.util.concurrent.TimeUnit;
173 
174 /**
175  * WifiService handles remote WiFi operation requests by implementing
176  * the IWifiManager interface.
177  */
178 public class WifiServiceImpl extends BaseWifiService {
179     private static final String TAG = "WifiService";
180     private static final boolean VDBG = false;
181 
182     /** Max wait time for posting blocking runnables */
183     private static final int RUN_WITH_SCISSORS_TIMEOUT_MILLIS = 4000;
184     @VisibleForTesting
185     static final int AUTO_DISABLE_SHOW_KEY_COUNTDOWN_MILLIS = 24 * 60 * 60 * 1000;
186 
187     private final ActiveModeWarden mActiveModeWarden;
188     private final ScanRequestProxy mScanRequestProxy;
189 
190     private final Context mContext;
191     private final FrameworkFacade mFacade;
192     private final Clock mClock;
193 
194     private final PowerManager mPowerManager;
195     private final AppOpsManager mAppOps;
196     private final UserManager mUserManager;
197     private final WifiCountryCode mCountryCode;
198 
199     /** Polls traffic stats and notifies clients */
200     private final WifiTrafficPoller mWifiTrafficPoller;
201     /** Tracks the persisted states for wi-fi & airplane mode */
202     private final WifiSettingsStore mSettingsStore;
203     /** Logs connection events and some general router and scan stats */
204     private final WifiMetrics mWifiMetrics;
205 
206     private final WifiInjector mWifiInjector;
207     /** Backup/Restore Module */
208     private final WifiBackupRestore mWifiBackupRestore;
209     private final SoftApBackupRestore mSoftApBackupRestore;
210     private final CoexManager mCoexManager;
211     private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
212     private final WifiConfigManager mWifiConfigManager;
213     private final PasspointManager mPasspointManager;
214     private final WifiLog mLog;
215     private final WifiConnectivityManager mWifiConnectivityManager;
216     private final ConnectHelper mConnectHelper;
217     private final WifiGlobals mWifiGlobals;
218     private final WifiCarrierInfoManager mWifiCarrierInfoManager;
219     private @WifiManager.VerboseLoggingLevel int mVerboseLoggingLevel =
220             WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED;
221     private final RemoteCallbackList<IWifiVerboseLoggingStatusChangedListener>
222             mRegisteredWifiLoggingStatusListeners = new RemoteCallbackList<>();
223 
224     private final FrameworkFacade mFrameworkFacade;
225 
226     private final WifiPermissionsUtil mWifiPermissionsUtil;
227 
228     private final TetheredSoftApTracker mTetheredSoftApTracker;
229 
230     private final LohsSoftApTracker mLohsSoftApTracker;
231 
232     private final BuildProperties mBuildProperties;
233 
234     private final DefaultClientModeManager mDefaultClientModeManager;
235 
236     /**
237      * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
238      */
239     public final class LocalOnlyRequestorCallback
240             implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback {
241         /**
242          * Called with requesting app has died.
243          */
244         @Override
onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor)245         public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) {
246             mLog.trace("onLocalOnlyHotspotRequestorDeath pid=%")
247                     .c(requestor.getPid()).flush();
248             mLohsSoftApTracker.stopByRequest(requestor);
249         }
250     }
251 
252     /**
253      * Listen for phone call state events to get active data subcription id.
254      */
255     private class WifiPhoneStateListener extends PhoneStateListener {
WifiPhoneStateListener(Looper looper)256         WifiPhoneStateListener(Looper looper) {
257             super(new HandlerExecutor(new Handler(looper)));
258         }
259 
260         @Override
onActiveDataSubscriptionIdChanged(int subId)261         public void onActiveDataSubscriptionIdChanged(int subId) {
262             // post operation to handler thread
263             mWifiThreadRunner.post(() -> {
264                 Log.d(TAG, "OBSERVED active data subscription change, subId: " + subId);
265                 mTetheredSoftApTracker.updateSoftApCapabilityWhenCarrierConfigChanged(subId);
266                 mActiveModeWarden.updateSoftApCapability(
267                         mTetheredSoftApTracker.getSoftApCapability());
268             });
269         }
270     }
271 
272     private final WifiLockManager mWifiLockManager;
273     private final WifiMulticastLockManager mWifiMulticastLockManager;
274     private final DppManager mDppManager;
275     private final WifiApConfigStore mWifiApConfigStore;
276     private final WifiThreadRunner mWifiThreadRunner;
277     private final MemoryStoreImpl mMemoryStoreImpl;
278     private final WifiScoreCard mWifiScoreCard;
279     private final WifiHealthMonitor mWifiHealthMonitor;
280     private final WifiDataStall mWifiDataStall;
281     private final WifiNative mWifiNative;
282     private final SimRequiredNotifier mSimRequiredNotifier;
283     private final MakeBeforeBreakManager mMakeBeforeBreakManager;
284     private final LastCallerInfoManager mLastCallerInfoManager;
285 
286     /**
287      * The wrapper of SoftApCallback is used in WifiService internally.
288      * see: {@code WifiManager.SoftApCallback}
289      */
290     public interface SoftApCallbackInternal {
291         /**
292          * see: {@code WifiManager.SoftApCallback#onStateChanged(int, int)}
293          */
onStateChanged(@ifiApState int state, @SapStartFailure int failureReason)294         default void onStateChanged(@WifiApState int state, @SapStartFailure int failureReason) {}
295 
296         /**
297          * The callback which only is used in service internally and pass to WifiManager.
298          * It will base on the change to send corresponding callback as below:
299          * 1. onInfoChanged(SoftApInfo)
300          * 2. onInfoChanged(List<SoftApInfo>)
301          * 3. onConnectedClientsChanged(SoftApInfo, List<WifiClient>)
302          * 4. onConnectedClientsChanged(List<WifiClient>)
303          */
onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged)304         default void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
305                 Map<String, List<WifiClient>> clients, boolean isBridged) {}
306 
307         /**
308          * see: {@code WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}
309          */
onCapabilityChanged(@onNull SoftApCapability softApCapability)310         default void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {}
311 
312         /**
313          * see: {@code WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient, int)}
314          */
onBlockedClientConnecting(@onNull WifiClient client, @SapClientBlockedReason int blockedReason)315         default void onBlockedClientConnecting(@NonNull WifiClient client,
316                 @SapClientBlockedReason int blockedReason) {}
317     }
318 
319 
WifiServiceImpl(Context context, WifiInjector wifiInjector)320     public WifiServiceImpl(Context context, WifiInjector wifiInjector) {
321         mContext = context;
322         mWifiInjector = wifiInjector;
323         mClock = wifiInjector.getClock();
324 
325         mFacade = mWifiInjector.getFrameworkFacade();
326         mWifiMetrics = mWifiInjector.getWifiMetrics();
327         mWifiTrafficPoller = mWifiInjector.getWifiTrafficPoller();
328         mUserManager = mWifiInjector.getUserManager();
329         mCountryCode = mWifiInjector.getWifiCountryCode();
330         mActiveModeWarden = mWifiInjector.getActiveModeWarden();
331         mScanRequestProxy = mWifiInjector.getScanRequestProxy();
332         mSettingsStore = mWifiInjector.getWifiSettingsStore();
333         mPowerManager = mContext.getSystemService(PowerManager.class);
334         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
335         mWifiLockManager = mWifiInjector.getWifiLockManager();
336         mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
337         mWifiBackupRestore = mWifiInjector.getWifiBackupRestore();
338         mSoftApBackupRestore = mWifiInjector.getSoftApBackupRestore();
339         mWifiApConfigStore = mWifiInjector.getWifiApConfigStore();
340         mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
341         mLog = mWifiInjector.makeLog(TAG);
342         mFrameworkFacade = wifiInjector.getFrameworkFacade();
343         mTetheredSoftApTracker = new TetheredSoftApTracker();
344         mActiveModeWarden.registerSoftApCallback(mTetheredSoftApTracker);
345         mLohsSoftApTracker = new LohsSoftApTracker();
346         mActiveModeWarden.registerLohsCallback(mLohsSoftApTracker);
347         mWifiNetworkSuggestionsManager = mWifiInjector.getWifiNetworkSuggestionsManager();
348         mDppManager = mWifiInjector.getDppManager();
349         mWifiThreadRunner = mWifiInjector.getWifiThreadRunner();
350         mWifiConfigManager = mWifiInjector.getWifiConfigManager();
351         mPasspointManager = mWifiInjector.getPasspointManager();
352         mWifiScoreCard = mWifiInjector.getWifiScoreCard();
353         mWifiHealthMonitor = wifiInjector.getWifiHealthMonitor();
354         mMemoryStoreImpl = new MemoryStoreImpl(mContext, mWifiInjector,
355                 mWifiScoreCard,  mWifiHealthMonitor);
356         mWifiConnectivityManager = wifiInjector.getWifiConnectivityManager();
357         mWifiDataStall = wifiInjector.getWifiDataStall();
358         mWifiNative = wifiInjector.getWifiNative();
359         mCoexManager = wifiInjector.getCoexManager();
360         mConnectHelper = wifiInjector.getConnectHelper();
361         mWifiGlobals = wifiInjector.getWifiGlobals();
362         mSimRequiredNotifier = wifiInjector.getSimRequiredNotifier();
363         mWifiCarrierInfoManager = wifiInjector.getWifiCarrierInfoManager();
364         mMakeBeforeBreakManager = mWifiInjector.getMakeBeforeBreakManager();
365         mLastCallerInfoManager = mWifiInjector.getLastCallerInfoManager();
366         mBuildProperties = mWifiInjector.getBuildProperties();
367         mDefaultClientModeManager = mWifiInjector.getDefaultClientModeManager();
368     }
369 
370     /**
371      * Check if we are ready to start wifi.
372      *
373      * First check if we will be restarting system services to decrypt the device. If the device is
374      * not encrypted, check if Wi-Fi needs to be enabled and start if needed
375      *
376      * This function is used only at boot time.
377      */
checkAndStartWifi()378     public void checkAndStartWifi() {
379         mWifiThreadRunner.post(() -> {
380             if (!mWifiConfigManager.loadFromStore()) {
381                 Log.e(TAG, "Failed to load from config store");
382             }
383             mWifiConfigManager.incrementNumRebootsSinceLastUse();
384             // config store is read, check if verbose logging is enabled.
385             enableVerboseLoggingInternal(
386                     mWifiInjector.getSettingsConfigStore().get(WIFI_VERBOSE_LOGGING_ENABLED)
387                     ? 1 : 0);
388             // Check if wi-fi needs to be enabled
389             boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
390             Log.i(TAG,
391                     "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled"));
392 
393             mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility().initialize();
394             mWifiInjector.getWifiNotificationManager().createNotificationChannels();
395             mContext.registerReceiver(
396                     new BroadcastReceiver() {
397                         @Override
398                         public void onReceive(Context context, Intent intent) {
399                             int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE,
400                                     TelephonyManager.SIM_STATE_UNKNOWN);
401                             if (TelephonyManager.SIM_STATE_ABSENT == state) {
402                                 Log.d(TAG, "resetting networks because SIM was removed");
403                                 resetCarrierNetworks(RESET_SIM_REASON_SIM_REMOVED);
404                             }
405                         }
406                     },
407                     new IntentFilter(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED));
408 
409             mContext.registerReceiver(
410                     new BroadcastReceiver() {
411                         @Override
412                         public void onReceive(Context context, Intent intent) {
413                             int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE,
414                                     TelephonyManager.SIM_STATE_UNKNOWN);
415                             if (TelephonyManager.SIM_STATE_LOADED == state) {
416                                 Log.d(TAG, "resetting networks because SIM was loaded");
417                                 resetCarrierNetworks(RESET_SIM_REASON_SIM_INSERTED);
418                             }
419                         }
420                     },
421                     new IntentFilter(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED));
422 
423             mContext.registerReceiver(
424                     new BroadcastReceiver() {
425                         private int mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
426                         @Override
427                         public void onReceive(Context context, Intent intent) {
428                             final int subId = intent.getIntExtra("subscription",
429                                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
430                             if (subId != mLastSubId) {
431                                 Log.d(TAG, "resetting networks as default data SIM is changed");
432                                 resetCarrierNetworks(RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED);
433                                 mLastSubId = subId;
434                                 mWifiThreadRunner.post(() -> {
435                                     mWifiDataStall.resetPhoneStateListener();
436                                 });
437                             }
438                         }
439                     },
440                     new IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED));
441 
442             mContext.registerReceiver(
443                     new BroadcastReceiver() {
444                     @Override
445                     public void onReceive(Context context, Intent intent) {
446                         String countryCode = intent.getStringExtra(
447                                 TelephonyManager.EXTRA_NETWORK_COUNTRY);
448                         Log.d(TAG, "Country code changed to :" + countryCode);
449                         mCountryCode.setTelephonyCountryCodeAndUpdate(countryCode);
450                     }}, new IntentFilter(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED));
451             mContext.registerReceiver(
452                     new BroadcastReceiver() {
453                         @Override
454                         public void onReceive(Context context, Intent intent) {
455                             Log.d(TAG, "locale changed");
456                             resetNotificationManager();
457                         }}, new IntentFilter(Intent.ACTION_LOCALE_CHANGED));
458 
459             // Adding optimizations of only receiving broadcasts when wifi is enabled
460             // can result in race conditions when apps toggle wifi in the background
461             // without active user involvement. Always receive broadcasts.
462             registerForBroadcasts();
463             mInIdleMode = mPowerManager.isDeviceIdleMode();
464 
465             mActiveModeWarden.start();
466             registerForCarrierConfigChange();
467             mWifiInjector.getAdaptiveConnectivityEnabledSettingObserver().initialize();
468         });
469     }
470 
resetCarrierNetworks(@lientModeImpl.ResetSimReason int resetReason)471     private void resetCarrierNetworks(@ClientModeImpl.ResetSimReason int resetReason) {
472         mWifiThreadRunner.post(() -> {
473             Log.d(TAG, "resetting carrier networks since SIM was changed");
474             if (resetReason == RESET_SIM_REASON_SIM_INSERTED
475                     || resetReason == RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED) {
476                 // clear all SIM related notifications since some action was taken to address
477                 // "missing" SIM issue
478                 mSimRequiredNotifier.dismissSimRequiredNotification();
479             }
480             if (resetReason != RESET_SIM_REASON_SIM_INSERTED) {
481                 mWifiConfigManager.resetSimNetworks();
482                 mWifiNetworkSuggestionsManager.resetSimNetworkSuggestions();
483                 mPasspointManager.resetSimPasspointNetwork();
484                 mWifiConfigManager.stopRestrictingAutoJoinToSubscriptionId();
485             }
486 
487             // do additional handling if we are current connected to a sim auth network
488             for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) {
489                 cmm.resetSimAuthNetworks(resetReason);
490             }
491             mWifiNetworkSuggestionsManager.resetCarrierPrivilegedApps();
492             if (resetReason == RESET_SIM_REASON_SIM_INSERTED) {
493                 // clear the blocklists in case any SIM based network were disabled due to the SIM
494                 // not being available.
495                 mWifiConfigManager.enableTemporaryDisabledNetworks();
496                 mWifiConnectivityManager.forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
497             } else {
498                 // Remove all ephemeral carrier networks keep subscriptionId update with SIM changes
499                 mWifiConfigManager.removeEphemeralCarrierNetworks();
500             }
501         });
502     }
503 
handleBootCompleted()504     public void handleBootCompleted() {
505         mWifiThreadRunner.post(() -> {
506             Log.d(TAG, "Handle boot completed");
507 
508             // Register for system broadcasts.
509             IntentFilter intentFilter = new IntentFilter();
510             intentFilter.addAction(Intent.ACTION_USER_REMOVED);
511             intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
512             intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
513             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
514             intentFilter.addAction(Intent.ACTION_SHUTDOWN);
515             mContext.registerReceiver(new BroadcastReceiver() {
516                 @Override
517                 public void onReceive(Context context, Intent intent) {
518                     String action = intent.getAction();
519                     if (action.equals(Intent.ACTION_USER_REMOVED)) {
520                         UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER);
521                         if (userHandle == null) {
522                             Log.e(TAG, "User removed broadcast received with no user handle");
523                             return;
524                         }
525                         mWifiThreadRunner.post(() -> mWifiConfigManager
526                                 .removeNetworksForUser(userHandle.getIdentifier()));
527                     } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
528                         int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
529                                 BluetoothAdapter.STATE_DISCONNECTED);
530                         boolean isConnected = state != BluetoothAdapter.STATE_DISCONNECTED;
531                         mWifiGlobals.setBluetoothConnected(isConnected);
532                         for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) {
533                             cmm.onBluetoothConnectionStateChanged();
534                         }
535                     } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
536                         int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
537                                 BluetoothAdapter.STATE_OFF);
538                         boolean isEnabled = state != BluetoothAdapter.STATE_OFF;
539                         mWifiGlobals.setBluetoothEnabled(isEnabled);
540                         for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) {
541                             cmm.onBluetoothConnectionStateChanged();
542                         }
543                     } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
544                         handleIdleModeChanged();
545                     } else if (action.equals(Intent.ACTION_SHUTDOWN)) {
546                         handleShutDown();
547                     }
548                 }
549             }, intentFilter);
550             mMemoryStoreImpl.start();
551             mPasspointManager.initializeProvisioner(
552                     mWifiInjector.getPasspointProvisionerHandlerThread().getLooper());
553             mWifiInjector.getWifiNetworkFactory().register();
554             mWifiInjector.getUntrustedWifiNetworkFactory().register();
555             mWifiInjector.getOemWifiNetworkFactory().register();
556             mWifiInjector.getWifiP2pConnection().handleBootCompleted();
557             // Start to listen country code change.
558             mCountryCode.registerListener(new CountryCodeListenerProxy());
559             mTetheredSoftApTracker.handleBootCompleted();
560             mWifiInjector.getSarManager().handleBootCompleted();
561         });
562     }
563 
handleUserSwitch(int userId)564     public void handleUserSwitch(int userId) {
565         Log.d(TAG, "Handle user switch " + userId);
566 
567         mWifiThreadRunner.post(() -> {
568             mWifiConfigManager.handleUserSwitch(userId);
569             resetNotificationManager();
570         });
571     }
572 
handleUserUnlock(int userId)573     public void handleUserUnlock(int userId) {
574         Log.d(TAG, "Handle user unlock " + userId);
575         mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserUnlock(userId));
576     }
577 
handleUserStop(int userId)578     public void handleUserStop(int userId) {
579         Log.d(TAG, "Handle user stop " + userId);
580         mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserStop(userId));
581     }
582 
583     /**
584      * See {@link android.net.wifi.WifiManager#startScan}
585      *
586      * @param packageName Package name of the app that requests wifi scan.
587      * @param featureId The feature in the package
588      */
589     @Override
startScan(String packageName, String featureId)590     public boolean startScan(String packageName, String featureId) {
591         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
592             return false;
593         }
594 
595         int callingUid = Binder.getCallingUid();
596         long ident = Binder.clearCallingIdentity();
597         mLog.info("startScan uid=%").c(callingUid).flush();
598         synchronized (this) {
599             if (mInIdleMode) {
600                 // Need to send an immediate scan result broadcast in case the
601                 // caller is waiting for a result ..
602 
603                 // TODO: investigate if the logic to cancel scans when idle can move to
604                 // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
605                 // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
606                 // be sent directly until b/31398592 is fixed.
607                 sendFailedScanBroadcast();
608                 mScanPending = true;
609                 return false;
610             }
611         }
612         try {
613             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
614                     null);
615             Boolean scanSuccess = mWifiThreadRunner.call(() ->
616                     mScanRequestProxy.startScan(callingUid, packageName), null);
617             if (scanSuccess == null) {
618                 sendFailedScanBroadcast();
619                 return false;
620             }
621             if (!scanSuccess) {
622                 Log.e(TAG, "Failed to start scan");
623                 return false;
624             }
625         } catch (SecurityException e) {
626             Log.w(TAG, "Permission violation - startScan not allowed for"
627                     + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
628             return false;
629         } finally {
630             Binder.restoreCallingIdentity(ident);
631         }
632         return true;
633     }
634 
635     // Send a failed scan broadcast to indicate the current scan request failed.
sendFailedScanBroadcast()636     private void sendFailedScanBroadcast() {
637         // clear calling identity to send broadcast
638         long callingIdentity = Binder.clearCallingIdentity();
639         try {
640             Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
641             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
642             intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
643             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
644         } finally {
645             // restore calling identity
646             Binder.restoreCallingIdentity(callingIdentity);
647         }
648 
649     }
650 
651     /**
652      * WPS support in Client mode is deprecated.  Return null.
653      */
654     @Override
getCurrentNetworkWpsNfcConfigurationToken()655     public String getCurrentNetworkWpsNfcConfigurationToken() {
656         // while CLs are in flight, return null here, will be removed (b/72423090)
657         enforceNetworkStackPermission();
658         if (isVerboseLoggingEnabled()) {
659             mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%")
660                     .c(Binder.getCallingUid()).flush();
661         }
662         return null;
663     }
664 
665     private boolean mInIdleMode;
666     private boolean mScanPending;
667 
handleIdleModeChanged()668     private void handleIdleModeChanged() {
669         boolean doScan = false;
670         synchronized (this) {
671             boolean idle = mPowerManager.isDeviceIdleMode();
672             if (mInIdleMode != idle) {
673                 mInIdleMode = idle;
674                 if (!idle) {
675                     if (mScanPending) {
676                         mScanPending = false;
677                         doScan = true;
678                     }
679                 }
680             }
681         }
682         if (doScan) {
683             // Someone requested a scan while we were idle; do a full scan now.
684             // A security check of the caller's identity was made when the request arrived via
685             // Binder. Now we'll pass the current process's identity to startScan().
686             startScan(mContext.getOpPackageName(), mContext.getAttributionTag());
687         }
688     }
689 
handleShutDown()690     private void handleShutDown() {
691         // Direct call to notify ActiveModeWarden as soon as possible with the assumption that
692         // notifyShuttingDown() doesn't have codes that may cause concurrentModificationException,
693         // e.g., access to a collection.
694         mActiveModeWarden.notifyShuttingDown();
695         mWifiThreadRunner.post(()-> {
696             // There is no explicit disconnection event in clientModeImpl during shutdown.
697             // Call resetConnectionState() so that connection duration is calculated
698             // before memory store write triggered by mMemoryStoreImpl.stop().
699             mWifiScoreCard.resetAllConnectionStates();
700             mMemoryStoreImpl.stop();
701         });
702     }
703 
checkNetworkSettingsPermission(int pid, int uid)704     private boolean checkNetworkSettingsPermission(int pid, int uid) {
705         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
706                 == PERMISSION_GRANTED;
707     }
708 
checkNetworkSetupWizardPermission(int pid, int uid)709     private boolean checkNetworkSetupWizardPermission(int pid, int uid) {
710         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, pid, uid)
711                 == PackageManager.PERMISSION_GRANTED;
712     }
713 
checkMainlineNetworkStackPermission(int pid, int uid)714     private boolean checkMainlineNetworkStackPermission(int pid, int uid) {
715         return mContext.checkPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid)
716                 == PackageManager.PERMISSION_GRANTED;
717     }
718 
checkNetworkStackPermission(int pid, int uid)719     private boolean checkNetworkStackPermission(int pid, int uid) {
720         return mContext.checkPermission(android.Manifest.permission.NETWORK_STACK, pid, uid)
721                 == PackageManager.PERMISSION_GRANTED;
722     }
723 
checkNetworkManagedProvisioningPermission(int pid, int uid)724     private boolean checkNetworkManagedProvisioningPermission(int pid, int uid) {
725         return mContext.checkPermission(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
726                 pid, uid) == PackageManager.PERMISSION_GRANTED;
727     }
728 
729     /**
730      * Helper method to check if the entity initiating the binder call has any of the signature only
731      * permissions.
732      */
isPrivileged(int pid, int uid)733     private boolean isPrivileged(int pid, int uid) {
734         return checkNetworkSettingsPermission(pid, uid)
735                 || checkNetworkSetupWizardPermission(pid, uid)
736                 || checkNetworkStackPermission(pid, uid)
737                 || checkNetworkManagedProvisioningPermission(pid, uid)
738                 || isSignedWithPlatformKey(uid);
739     }
740 
741     /** Whether the uid is signed with the same key as the platform. */
isSignedWithPlatformKey(int uid)742     private boolean isSignedWithPlatformKey(int uid) {
743         return mContext.getPackageManager().checkSignatures(uid, Process.SYSTEM_UID)
744                 == PackageManager.SIGNATURE_MATCH;
745     }
746 
747     /**
748      * Helper method to check if the entity initiating the binder call has setup wizard or settings
749      * permissions.
750      */
isSettingsOrSuw(int pid, int uid)751     private boolean isSettingsOrSuw(int pid, int uid) {
752         return checkNetworkSettingsPermission(pid, uid)
753                 || checkNetworkSetupWizardPermission(pid, uid);
754     }
755 
756     /** Helper method to check if the entity initiating the binder call is a DO/PO app. */
isDeviceOrProfileOwner(int uid, String packageName)757     private boolean isDeviceOrProfileOwner(int uid, String packageName) {
758         return mWifiPermissionsUtil.isDeviceOwner(uid, packageName)
759                 || mWifiPermissionsUtil.isProfileOwner(uid, packageName);
760     }
761 
enforceNetworkSettingsPermission()762     private void enforceNetworkSettingsPermission() {
763         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
764                 "WifiService");
765     }
766 
checkAnyPermissionOf(String... permissions)767     private boolean checkAnyPermissionOf(String... permissions) {
768         for (String permission : permissions) {
769             if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
770                 return true;
771             }
772         }
773         return false;
774     }
775 
enforceAnyPermissionOf(String... permissions)776     private void enforceAnyPermissionOf(String... permissions) {
777         if (!checkAnyPermissionOf(permissions)) {
778             throw new SecurityException("Requires one of the following permissions: "
779                     + String.join(", ", permissions) + ".");
780         }
781     }
782 
enforceNetworkStackPermission()783     private void enforceNetworkStackPermission() {
784         // TODO(b/142554155): Only check for MAINLINE_NETWORK_STACK permission
785         boolean granted = mContext.checkCallingOrSelfPermission(
786                 android.Manifest.permission.NETWORK_STACK)
787                 == PackageManager.PERMISSION_GRANTED;
788         if (granted) {
789             return;
790         }
791         mContext.enforceCallingOrSelfPermission(
792                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "WifiService");
793     }
794 
enforceAccessPermission()795     private void enforceAccessPermission() {
796         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
797                 "WifiService");
798     }
799 
enforceRestartWifiSubsystemPermission()800     private void enforceRestartWifiSubsystemPermission() {
801         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RESTART_WIFI_SUBSYSTEM,
802                 "WifiService");
803     }
804 
805     /**
806      * Checks whether the caller can change the wifi state.
807      * Possible results:
808      * 1. Operation is allowed. No exception thrown, and AppOpsManager.MODE_ALLOWED returned.
809      * 2. Operation is not allowed, and caller must be told about this. SecurityException is thrown.
810      * 3. Operation is not allowed, and caller must not be told about this (i.e. must silently
811      * ignore the operation). No exception is thrown, and AppOpsManager.MODE_IGNORED returned.
812      */
813     @CheckResult
enforceChangePermission(String callingPackage)814     private int enforceChangePermission(String callingPackage) {
815         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
816         if (checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())) {
817             return MODE_ALLOWED;
818         }
819         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
820                 "WifiService");
821 
822         return mAppOps.noteOp(
823                 AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Binder.getCallingUid(), callingPackage);
824     }
825 
enforceReadCredentialPermission()826     private void enforceReadCredentialPermission() {
827         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
828                                                 "WifiService");
829     }
830 
enforceMulticastChangePermission()831     private void enforceMulticastChangePermission() {
832         mContext.enforceCallingOrSelfPermission(
833                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
834                 "WifiService");
835     }
836 
enforceConnectivityInternalPermission()837     private void enforceConnectivityInternalPermission() {
838         mContext.enforceCallingOrSelfPermission(
839                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
840                 "ConnectivityService");
841     }
842 
enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)843     private void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) {
844         mWifiPermissionsUtil.enforceLocationPermission(pkgName, featureId, uid);
845     }
846 
847     /**
848      * Helper method to check if the app is allowed to access public API's deprecated in
849      * {@link Build.VERSION_CODES#Q}.
850      * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name.
851      */
isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid)852     private boolean isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid) {
853         return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q, uid)
854                 || isPrivileged(pid, uid)
855                 || isDeviceOrProfileOwner(uid, packageName)
856                 || mWifiPermissionsUtil.isSystem(packageName, uid)
857                 // TODO(b/140540984): Remove this bypass.
858                 || mWifiPermissionsUtil.checkSystemAlertWindowPermission(uid, packageName);
859     }
860 
861     /**
862      * Helper method to check if the app is allowed to access public API's deprecated in
863      * {@link Build.VERSION_CODES#R}.
864      * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name.
865      */
isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid)866     private boolean isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid) {
867         return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.R, uid)
868                 || isPrivileged(pid, uid)
869                 || isDeviceOrProfileOwner(uid, packageName)
870                 || mWifiPermissionsUtil.isSystem(packageName, uid);
871     }
872 
873     /**
874      * Get the current primary ClientModeManager in a thread safe manner, but blocks on the main
875      * Wifi thread.
876      */
getPrimaryClientModeManagerBlockingThreadSafe()877     private ClientModeManager getPrimaryClientModeManagerBlockingThreadSafe() {
878         return mWifiThreadRunner.call(
879                 () -> mActiveModeWarden.getPrimaryClientModeManager(),
880                 mDefaultClientModeManager);
881     }
882 
883     /**
884      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
885      * @param enable {@code true} to enable, {@code false} to disable.
886      * @return {@code true} if the enable/disable operation was
887      *         started or is already in the queue.
888      */
889     @Override
setWifiEnabled(String packageName, boolean enable)890     public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
891         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
892             return false;
893         }
894         boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid());
895         if (!isPrivileged && !isDeviceOrProfileOwner(Binder.getCallingUid(), packageName)
896                 && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q,
897                   Binder.getCallingUid())
898                 && !mWifiPermissionsUtil.isSystem(packageName, Binder.getCallingUid())) {
899             mLog.info("setWifiEnabled not allowed for uid=%")
900                     .c(Binder.getCallingUid()).flush();
901             return false;
902         }
903         // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
904         if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
905             mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
906             return false;
907         }
908 
909         // If SoftAp is enabled, only privileged apps are allowed to toggle wifi
910         if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
911             mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
912             return false;
913         }
914 
915         mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
916                 .c(Binder.getCallingUid()).c(enable).flush();
917         long ident = Binder.clearCallingIdentity();
918         try {
919             if (!mSettingsStore.handleWifiToggled(enable)) {
920                 // Nothing to do if wifi cannot be toggled
921                 return true;
922             }
923         } finally {
924             Binder.restoreCallingIdentity(ident);
925         }
926         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) {
927             if (enable) {
928                 mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON);
929             } else {
930                 WifiInfo wifiInfo =
931                         getPrimaryClientModeManagerBlockingThreadSafe().syncRequestConnectionInfo();
932                 mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF,
933                         wifiInfo == null ? -1 : wifiInfo.getNetworkId());
934             }
935         }
936         mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
937         mActiveModeWarden.wifiToggled(new WorkSource(Binder.getCallingUid(), packageName));
938         mLastCallerInfoManager.put(LastCallerInfoManager.WIFI_ENABLED, Process.myTid(),
939                 Binder.getCallingUid(), Binder.getCallingPid(), packageName, enable);
940         return true;
941     }
942 
943     @RequiresApi(Build.VERSION_CODES.S)
944     @Override
registerSubsystemRestartCallback(ISubsystemRestartCallback callback)945     public void registerSubsystemRestartCallback(ISubsystemRestartCallback callback) {
946         if (!SdkLevel.isAtLeastS()) {
947             throw new UnsupportedOperationException();
948         }
949         enforceAccessPermission();
950         if (isVerboseLoggingEnabled()) {
951             mLog.info("registerSubsystemRestartCallback uid=%").c(Binder.getCallingUid()).flush();
952         }
953 
954         mWifiThreadRunner.post(() -> {
955             if (!mActiveModeWarden.registerSubsystemRestartCallback(callback)) {
956                 Log.e(TAG, "registerSubsystemRestartCallback: Failed to register callback");
957             }
958         });
959     }
960 
961     @RequiresApi(Build.VERSION_CODES.S)
962     @Override
unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback)963     public void unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback) {
964         if (!SdkLevel.isAtLeastS()) {
965             throw new UnsupportedOperationException();
966         }
967         enforceAccessPermission();
968         if (isVerboseLoggingEnabled()) {
969             mLog.info("registerSubsystemRestartCallback uid=%").c(Binder.getCallingUid()).flush();
970         }
971         mWifiThreadRunner.post(() -> {
972             if (!mActiveModeWarden.unregisterSubsystemRestartCallback(callback)) {
973                 Log.e(TAG, "unregisterSubsystemRestartCallback: Failed to register callback");
974             }
975         });
976     }
977 
978     @RequiresApi(Build.VERSION_CODES.S)
979     @Override
restartWifiSubsystem()980     public void restartWifiSubsystem() {
981         if (!SdkLevel.isAtLeastS()) {
982             throw new UnsupportedOperationException();
983         }
984         enforceRestartWifiSubsystemPermission();
985         if (isVerboseLoggingEnabled()) {
986             mLog.info("restartWifiSubsystem uid=%").c(Binder.getCallingUid()).flush();
987         }
988         mWifiThreadRunner.post(() -> {
989             WifiInfo wifiInfo =
990                     mActiveModeWarden.getPrimaryClientModeManager().syncRequestConnectionInfo();
991             mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_RESTART_WIFI_SUB_SYSTEM,
992                     wifiInfo == null ? -1 : wifiInfo.getNetworkId());
993             mWifiInjector.getSelfRecovery().trigger(REASON_API_CALL);
994         });
995     }
996 
997     /**
998      * see {@link WifiManager#getWifiState()}
999      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
1000      *         {@link WifiManager#WIFI_STATE_DISABLING},
1001      *         {@link WifiManager#WIFI_STATE_ENABLED},
1002      *         {@link WifiManager#WIFI_STATE_ENABLING},
1003      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
1004      */
1005     @Override
getWifiEnabledState()1006     public int getWifiEnabledState() {
1007         enforceAccessPermission();
1008         if (isVerboseLoggingEnabled()) {
1009             mLog.info("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
1010         }
1011         return getPrimaryClientModeManagerBlockingThreadSafe().syncGetWifiState();
1012     }
1013 
1014     /**
1015      * see {@link WifiManager#getWifiApState()}
1016      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
1017      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
1018      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
1019      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
1020      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
1021      */
1022     @Override
getWifiApEnabledState()1023     public int getWifiApEnabledState() {
1024         enforceAccessPermission();
1025         if (isVerboseLoggingEnabled()) {
1026             mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
1027         }
1028         return mTetheredSoftApTracker.getState();
1029     }
1030 
1031     /**
1032      * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
1033      *
1034      * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
1035      *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
1036      *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
1037      *
1038      * @param ifaceName String name of the updated interface
1039      * @param mode new operating mode of the interface
1040      *
1041      * @throws SecurityException if the caller does not have permission to call update
1042      */
1043     @Override
updateInterfaceIpState(String ifaceName, int mode)1044     public void updateInterfaceIpState(String ifaceName, int mode) {
1045         // NETWORK_STACK is a signature only permission.
1046         enforceNetworkStackPermission();
1047         mLog.info("updateInterfaceIpState uid=%").c(Binder.getCallingUid()).flush();
1048         // hand off the work to our handler thread
1049         mWifiThreadRunner.post(() -> mLohsSoftApTracker.updateInterfaceIpState(ifaceName, mode));
1050     }
1051 
1052     /**
1053      * see {@link WifiManager#isDefaultCoexAlgorithmEnabled()}
1054      * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
1055      */
1056     @Override
isDefaultCoexAlgorithmEnabled()1057     public boolean isDefaultCoexAlgorithmEnabled() {
1058         return mContext.getResources().getBoolean(R.bool.config_wifiDefaultCoexAlgorithmEnabled);
1059     }
1060 
1061     /**
1062      * see {@link android.net.wifi.WifiManager#setCoexUnsafeChannels(List, int)}
1063      * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
1064      * @param restrictions Bitmap of {@link CoexRestriction} specifying the mandatory
1065      *                     uses of the specified channels.
1066      */
1067     @Override
1068     @RequiresApi(Build.VERSION_CODES.S)
setCoexUnsafeChannels( @onNull List<CoexUnsafeChannel> unsafeChannels, int restrictions)1069     public void setCoexUnsafeChannels(
1070             @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) {
1071         if (!SdkLevel.isAtLeastS()) {
1072             throw new UnsupportedOperationException();
1073         }
1074         mContext.enforceCallingOrSelfPermission(
1075                 Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS, "WifiService");
1076         if (unsafeChannels == null) {
1077             throw new IllegalArgumentException("unsafeChannels cannot be null");
1078         }
1079         if (mContext.getResources().getBoolean(R.bool.config_wifiDefaultCoexAlgorithmEnabled)) {
1080             Log.e(TAG, "setCoexUnsafeChannels called but default coex algorithm is enabled");
1081             return;
1082         }
1083         mWifiThreadRunner.post(() ->
1084                 mCoexManager.setCoexUnsafeChannels(unsafeChannels, restrictions));
1085     }
1086 
1087     /**
1088      * See {@link WifiManager#registerCoexCallback(WifiManager.CoexCallback)}
1089      */
1090     @RequiresApi(Build.VERSION_CODES.S)
registerCoexCallback(@onNull ICoexCallback callback)1091     public void registerCoexCallback(@NonNull ICoexCallback callback) {
1092         if (!SdkLevel.isAtLeastS()) {
1093             throw new UnsupportedOperationException();
1094         }
1095         mContext.enforceCallingOrSelfPermission(
1096                 Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS, "WifiService");
1097         if (callback == null) {
1098             throw new IllegalArgumentException("callback must not be null");
1099         }
1100         if (isVerboseLoggingEnabled()) {
1101             mLog.info("registerCoexCallback uid=%").c(Binder.getCallingUid()).flush();
1102         }
1103         mWifiThreadRunner.post(() -> mCoexManager.registerRemoteCoexCallback(callback));
1104     }
1105 
1106     /**
1107      * See {@link WifiManager#unregisterCoexCallback(WifiManager.CoexCallback)}
1108      */
1109     @RequiresApi(Build.VERSION_CODES.S)
unregisterCoexCallback(@onNull ICoexCallback callback)1110     public void unregisterCoexCallback(@NonNull ICoexCallback callback) {
1111         if (!SdkLevel.isAtLeastS()) {
1112             throw new UnsupportedOperationException();
1113         }
1114         mContext.enforceCallingOrSelfPermission(
1115                 Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS, "WifiService");
1116         if (callback == null) {
1117             throw new IllegalArgumentException("callback must not be null");
1118         }
1119         if (isVerboseLoggingEnabled()) {
1120             mLog.info("unregisterCoexCallback uid=%").c(Binder.getCallingUid()).flush();
1121         }
1122         mWifiThreadRunner.post(() -> mCoexManager.unregisterRemoteCoexCallback(callback));
1123     }
1124 
1125     /**
1126      * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
1127      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
1128      * @return {@code true} if softap start was triggered
1129      * @throws SecurityException if the caller does not have permission to start softap
1130      */
1131     @Override
startSoftAp(WifiConfiguration wifiConfig, String packageName)1132     public boolean startSoftAp(WifiConfiguration wifiConfig, String packageName) {
1133         // NETWORK_STACK is a signature only permission.
1134         enforceNetworkStackPermission();
1135 
1136         mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
1137 
1138         SoftApConfiguration softApConfig = null;
1139         if (wifiConfig != null) {
1140             softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig);
1141             if (softApConfig == null) {
1142                 return false;
1143             }
1144         }
1145 
1146         if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
1147             mLog.err("Tethering is already active.").flush();
1148             return false;
1149         }
1150 
1151         WorkSource requestorWs = new WorkSource(Binder.getCallingUid(), packageName);
1152         if (!mWifiThreadRunner.call(
1153                 () -> mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs), false)) {
1154             // Take down LOHS if it is up.
1155             mLohsSoftApTracker.stopAll();
1156         }
1157 
1158         if (!startSoftApInternal(new SoftApModeConfiguration(
1159                 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
1160                 mTetheredSoftApTracker.getSoftApCapability()), requestorWs)) {
1161             mTetheredSoftApTracker.setFailedWhileEnabling();
1162             return false;
1163         }
1164         mLastCallerInfoManager.put(LastCallerInfoManager.SOFT_AP, Process.myTid(),
1165                 Binder.getCallingUid(), Binder.getCallingPid(), packageName, true);
1166         return true;
1167     }
1168 
1169     /**
1170      * see {@link android.net.wifi.WifiManager#startTetheredHotspot(SoftApConfiguration)}
1171      * @param softApConfig SSID, security and channel details as part of SoftApConfiguration
1172      * @return {@code true} if softap start was triggered
1173      * @throws SecurityException if the caller does not have permission to start softap
1174      */
1175     @Override
startTetheredHotspot(@ullable SoftApConfiguration softApConfig, @NonNull String packageName)1176     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig,
1177             @NonNull String packageName) {
1178         // NETWORK_STACK is a signature only permission.
1179         enforceNetworkStackPermission();
1180 
1181         mLog.info("startTetheredHotspot uid=%").c(Binder.getCallingUid()).flush();
1182 
1183         if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
1184             mLog.err("Tethering is already active.").flush();
1185             return false;
1186         }
1187 
1188         WorkSource requestorWs = new WorkSource(Binder.getCallingUid(), packageName);
1189         if (!mWifiThreadRunner.call(
1190                 () -> mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs), false)) {
1191             // Take down LOHS if it is up.
1192             mLohsSoftApTracker.stopAll();
1193         }
1194 
1195         if (!startSoftApInternal(new SoftApModeConfiguration(
1196                 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
1197                 mTetheredSoftApTracker.getSoftApCapability()), requestorWs)) {
1198             mTetheredSoftApTracker.setFailedWhileEnabling();
1199             return false;
1200         }
1201         mLastCallerInfoManager.put(LastCallerInfoManager.TETHERED_HOTSPOT, Process.myTid(),
1202                 Binder.getCallingUid(), Binder.getCallingPid(), packageName, true);
1203         return true;
1204     }
1205 
1206     /**
1207      * Internal method to start softap mode. Callers of this method should have already checked
1208      * proper permissions beyond the NetworkStack permission.
1209      */
startSoftApInternal(SoftApModeConfiguration apConfig, WorkSource requestorWs)1210     private boolean startSoftApInternal(SoftApModeConfiguration apConfig, WorkSource requestorWs) {
1211         int uid = Binder.getCallingUid();
1212         boolean privileged = isSettingsOrSuw(Binder.getCallingPid(), uid);
1213         mLog.trace("startSoftApInternal uid=% mode=%")
1214                 .c(uid).c(apConfig.getTargetMode()).flush();
1215 
1216         // null wifiConfig is a meaningful input for CMD_SET_AP; it means to use the persistent
1217         // AP config.
1218         SoftApConfiguration softApConfig = apConfig.getSoftApConfiguration();
1219         if (softApConfig != null
1220                 && (!WifiApConfigStore.validateApWifiConfiguration(
1221                     softApConfig, privileged, mContext))) {
1222             Log.e(TAG, "Invalid SoftApConfiguration");
1223             return false;
1224         }
1225 
1226         mActiveModeWarden.startSoftAp(apConfig, requestorWs);
1227         return true;
1228     }
1229 
1230     /**
1231      * see {@link android.net.wifi.WifiManager#stopSoftAp()}
1232      * @return {@code true} if softap stop was triggered
1233      * @throws SecurityException if the caller does not have permission to stop softap
1234      */
1235     @Override
stopSoftAp()1236     public boolean stopSoftAp() {
1237         // NETWORK_STACK is a signature only permission.
1238         enforceNetworkStackPermission();
1239 
1240         // only permitted callers are allowed to this point - they must have gone through
1241         // connectivity service since this method is protected with the NETWORK_STACK PERMISSION
1242 
1243         mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
1244 
1245         stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
1246         mLastCallerInfoManager.put(LastCallerInfoManager.SOFT_AP, Process.myTid(),
1247                 Binder.getCallingUid(), Binder.getCallingPid(), "<unknown>", false);
1248         return true;
1249     }
1250 
1251     /**
1252      * Internal method to stop softap mode.
1253      *
1254      * Callers of this method should have already checked
1255      * proper permissions beyond the NetworkStack permission.
1256      *
1257      * @param mode the operating mode of APs to bring down (ex,
1258      *             {@link WifiManager.IFACE_IP_MODE_TETHERED} or
1259      *             {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
1260      *             Use {@link WifiManager.IFACE_IP_MODE_UNSPECIFIED} to stop all APs.
1261      */
stopSoftApInternal(int mode)1262     private void stopSoftApInternal(int mode) {
1263         mLog.trace("stopSoftApInternal uid=% mode=%").c(Binder.getCallingUid()).c(mode).flush();
1264 
1265         mActiveModeWarden.stopSoftAp(mode);
1266     }
1267 
1268     private final class CountryCodeListenerProxy implements WifiCountryCode.ChangeListener {
1269         @Override
onDriverCountryCodeChanged(String countryCode)1270         public void onDriverCountryCodeChanged(String countryCode) {
1271             // post operation to handler thread
1272             mWifiThreadRunner.post(() -> {
1273                 Log.i(TAG, "onDriverCountryCodeChanged " + countryCode);
1274                 mTetheredSoftApTracker.updateAvailChannelListInSoftApCapability();
1275                 mActiveModeWarden.updateSoftApCapability(
1276                         mTetheredSoftApTracker.getSoftApCapability());
1277             });
1278         }
1279     }
1280 
1281     /**
1282      * SoftAp callback
1283      */
1284     private final class TetheredSoftApTracker implements SoftApCallbackInternal {
1285         /**
1286          * State of tethered SoftAP
1287          * One of:  {@link WifiManager#WIFI_AP_STATE_DISABLED},
1288          *          {@link WifiManager#WIFI_AP_STATE_DISABLING},
1289          *          {@link WifiManager#WIFI_AP_STATE_ENABLED},
1290          *          {@link WifiManager#WIFI_AP_STATE_ENABLING},
1291          *          {@link WifiManager#WIFI_AP_STATE_FAILED}
1292          */
1293         private final Object mLock = new Object();
1294         private int mTetheredSoftApState = WIFI_AP_STATE_DISABLED;
1295         private Map<String, List<WifiClient>> mTetheredSoftApConnectedClientsMap = new HashMap();
1296         private Map<String, SoftApInfo> mTetheredSoftApInfoMap = new HashMap();
1297         private boolean mIsBridgedMode = false;
1298         // TODO: We need to maintain two capability. One for LTE + SAP and one for WIFI + SAP
1299         private SoftApCapability mTetheredSoftApCapability = null;
1300         private boolean mIsBootComplete = false;
1301 
handleBootCompleted()1302         public void handleBootCompleted() {
1303             mIsBootComplete = true;
1304             updateAvailChannelListInSoftApCapability();
1305         }
1306 
getState()1307         public int getState() {
1308             synchronized (mLock) {
1309                 return mTetheredSoftApState;
1310             }
1311         }
1312 
setEnablingIfAllowed()1313         public boolean setEnablingIfAllowed() {
1314             synchronized (mLock) {
1315                 if (mTetheredSoftApState != WIFI_AP_STATE_DISABLED
1316                         && mTetheredSoftApState != WIFI_AP_STATE_FAILED) {
1317                     return false;
1318                 }
1319                 mTetheredSoftApState = WIFI_AP_STATE_ENABLING;
1320                 return true;
1321             }
1322         }
1323 
setFailedWhileEnabling()1324         public void setFailedWhileEnabling() {
1325             synchronized (mLock) {
1326                 if (mTetheredSoftApState == WIFI_AP_STATE_ENABLING) {
1327                     mTetheredSoftApState = WIFI_AP_STATE_FAILED;
1328                 }
1329             }
1330         }
1331 
getConnectedClients()1332         public Map<String, List<WifiClient>> getConnectedClients() {
1333             synchronized (mLock) {
1334                 return mTetheredSoftApConnectedClientsMap;
1335             }
1336         }
1337 
getSoftApInfos()1338         public Map<String, SoftApInfo> getSoftApInfos() {
1339             synchronized (mLock) {
1340                 return mTetheredSoftApInfoMap;
1341             }
1342         }
1343 
getIsBridgedMode()1344         public boolean getIsBridgedMode() {
1345             synchronized (mLock) {
1346                 return mIsBridgedMode;
1347             }
1348         }
1349 
getSoftApCapability()1350         public SoftApCapability getSoftApCapability() {
1351             synchronized (mLock) {
1352                 if (mTetheredSoftApCapability == null) {
1353                     mTetheredSoftApCapability = ApConfigUtil.updateCapabilityFromResource(mContext);
1354                     // Default country code
1355                     mTetheredSoftApCapability = updateSoftApCapabilityWithAvailableChannelList(
1356                             mTetheredSoftApCapability);
1357                 }
1358                 return mTetheredSoftApCapability;
1359             }
1360         }
1361 
updateSoftApCapabilityWithAvailableChannelList( @onNull SoftApCapability softApCapability)1362         private SoftApCapability updateSoftApCapabilityWithAvailableChannelList(
1363                 @NonNull SoftApCapability softApCapability) {
1364             SoftApCapability newSoftApCapability = new SoftApCapability(softApCapability);
1365             if (!mIsBootComplete) {
1366                 // The available channel list is from wificond.
1367                 // It might be a failure or stuck during wificond init.
1368                 return newSoftApCapability;
1369             }
1370             List<Integer> supportedChannelList = null;
1371             if (ApConfigUtil.isSoftAp24GhzSupported(mContext)) {
1372                 supportedChannelList = ApConfigUtil.getAvailableChannelFreqsForBand(
1373                     SoftApConfiguration.BAND_2GHZ, mWifiNative, mContext.getResources(), false);
1374                 if (supportedChannelList != null) {
1375                     newSoftApCapability.setSupportedChannelList(
1376                             SoftApConfiguration.BAND_2GHZ,
1377                             supportedChannelList.stream().mapToInt(Integer::intValue).toArray());
1378                 }
1379             }
1380             if (ApConfigUtil.isSoftAp5GhzSupported(mContext)) {
1381                 supportedChannelList = ApConfigUtil.getAvailableChannelFreqsForBand(
1382                         SoftApConfiguration.BAND_5GHZ, mWifiNative, mContext.getResources(), false);
1383                 if (supportedChannelList != null) {
1384                     newSoftApCapability.setSupportedChannelList(
1385                             SoftApConfiguration.BAND_5GHZ,
1386                             supportedChannelList.stream().mapToInt(Integer::intValue).toArray());
1387                 }
1388             }
1389             if (ApConfigUtil.isSoftAp6GhzSupported(mContext)) {
1390                 supportedChannelList = ApConfigUtil.getAvailableChannelFreqsForBand(
1391                         SoftApConfiguration.BAND_6GHZ, mWifiNative, mContext.getResources(), false);
1392                 if (supportedChannelList != null) {
1393                     newSoftApCapability.setSupportedChannelList(
1394                             SoftApConfiguration.BAND_6GHZ,
1395                             supportedChannelList.stream().mapToInt(Integer::intValue).toArray());
1396                 }
1397             }
1398             if (ApConfigUtil.isSoftAp60GhzSupported(mContext)) {
1399                 supportedChannelList = ApConfigUtil.getAvailableChannelFreqsForBand(
1400                         SoftApConfiguration.BAND_60GHZ, mWifiNative, mContext.getResources(),
1401                         false);
1402                 if (supportedChannelList != null) {
1403                     newSoftApCapability.setSupportedChannelList(
1404                             SoftApConfiguration.BAND_60GHZ,
1405                             supportedChannelList.stream().mapToInt(Integer::intValue).toArray());
1406                 }
1407             }
1408             return newSoftApCapability;
1409         }
1410 
updateAvailChannelListInSoftApCapability()1411         public void updateAvailChannelListInSoftApCapability() {
1412             onCapabilityChanged(updateSoftApCapabilityWithAvailableChannelList(
1413                     getSoftApCapability()));
1414         }
1415 
updateSoftApCapabilityWhenCarrierConfigChanged(int subId)1416         public void updateSoftApCapabilityWhenCarrierConfigChanged(int subId) {
1417             CarrierConfigManager carrierConfigManager =
1418                     mContext.getSystemService(CarrierConfigManager.class);
1419             if (carrierConfigManager == null) return;
1420             PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
1421             if (carrierConfig == null) return;
1422             int carrierMaxClient = carrierConfig.getInt(
1423                     CarrierConfigManager.Wifi.KEY_HOTSPOT_MAX_CLIENT_COUNT);
1424             int finalSupportedClientNumber = mContext.getResources().getInteger(
1425                     R.integer.config_wifiHardwareSoftapMaxClientCount);
1426             if (carrierMaxClient > 0) {
1427                 finalSupportedClientNumber = Math.min(finalSupportedClientNumber,
1428                         carrierMaxClient);
1429             }
1430             if (finalSupportedClientNumber == getSoftApCapability().getMaxSupportedClients()) {
1431                 return;
1432             }
1433             SoftApCapability newSoftApCapability = new SoftApCapability(mTetheredSoftApCapability);
1434             newSoftApCapability.setMaxSupportedClients(
1435                     finalSupportedClientNumber);
1436             onCapabilityChanged(newSoftApCapability);
1437         }
1438 
1439         private final RemoteCallbackList<ISoftApCallback> mRegisteredSoftApCallbacks =
1440                 new RemoteCallbackList<>();
1441 
registerSoftApCallback(ISoftApCallback callback)1442         public boolean registerSoftApCallback(ISoftApCallback callback) {
1443             return mRegisteredSoftApCallbacks.register(callback);
1444         }
1445 
unregisterSoftApCallback(ISoftApCallback callback)1446         public void unregisterSoftApCallback(ISoftApCallback callback) {
1447             mRegisteredSoftApCallbacks.unregister(callback);
1448         }
1449 
1450         /**
1451          * Called when soft AP state changes.
1452          *
1453          * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED},
1454          *        {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED},
1455          *        {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED}
1456          * @param failureReason reason when in failed state. One of
1457          *        {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL}
1458          */
1459         @Override
onStateChanged(int state, int failureReason)1460         public void onStateChanged(int state, int failureReason) {
1461             synchronized (mLock) {
1462                 mTetheredSoftApState = state;
1463             }
1464 
1465             int itemCount = mRegisteredSoftApCallbacks.beginBroadcast();
1466             for (int i = 0; i < itemCount; i++) {
1467                 try {
1468                     mRegisteredSoftApCallbacks.getBroadcastItem(i).onStateChanged(state,
1469                             failureReason);
1470                 } catch (RemoteException e) {
1471                     Log.e(TAG, "onStateChanged: remote exception -- " + e);
1472                 }
1473             }
1474             mRegisteredSoftApCallbacks.finishBroadcast();
1475         }
1476 
1477         /**
1478          * Called when the connected clients to soft AP changes.
1479          *
1480          * @param clients connected clients to soft AP
1481          */
1482         @Override
onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged)1483         public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
1484                 Map<String, List<WifiClient>> clients, boolean isBridged) {
1485             synchronized (mLock) {
1486                 mIsBridgedMode = isBridged;
1487                 if (infos.size() == 0 && isBridged) {
1488                     Log.d(TAG, "ShutDown bridged mode, clear isBridged cache in Service");
1489                     mIsBridgedMode = false;
1490                 }
1491                 mTetheredSoftApConnectedClientsMap =
1492                         ApConfigUtil.deepCopyForWifiClientListMap(clients);
1493                 mTetheredSoftApInfoMap = ApConfigUtil.deepCopyForSoftApInfoMap(infos);
1494             }
1495             int itemCount = mRegisteredSoftApCallbacks.beginBroadcast();
1496             for (int i = 0; i < itemCount; i++) {
1497                 try {
1498                     mRegisteredSoftApCallbacks.getBroadcastItem(i).onConnectedClientsOrInfoChanged(
1499                             ApConfigUtil.deepCopyForSoftApInfoMap(mTetheredSoftApInfoMap),
1500                             ApConfigUtil.deepCopyForWifiClientListMap(
1501                                     mTetheredSoftApConnectedClientsMap), isBridged, false);
1502                 } catch (RemoteException e) {
1503                     Log.e(TAG, "onConnectedClientsOrInfoChanged: remote exception -- " + e);
1504                 }
1505             }
1506             mRegisteredSoftApCallbacks.finishBroadcast();
1507         }
1508 
1509         /**
1510          * Called when capability of softap changes.
1511          *
1512          * @param capability is the softap capability. {@link SoftApCapability}
1513          */
1514         @Override
onCapabilityChanged(SoftApCapability capability)1515         public void onCapabilityChanged(SoftApCapability capability) {
1516             synchronized (mLock) {
1517                 if (Objects.equals(capability, mTetheredSoftApCapability)) {
1518                     return;
1519                 }
1520                 mTetheredSoftApCapability = new SoftApCapability(capability);
1521             }
1522             int itemCount = mRegisteredSoftApCallbacks.beginBroadcast();
1523             for (int i = 0; i < itemCount; i++) {
1524                 try {
1525                     mRegisteredSoftApCallbacks.getBroadcastItem(i).onCapabilityChanged(
1526                             mTetheredSoftApCapability);
1527                 } catch (RemoteException e) {
1528                     Log.e(TAG, "onCapabiliyChanged: remote exception -- " + e);
1529                 }
1530             }
1531             mRegisteredSoftApCallbacks.finishBroadcast();
1532         }
1533 
1534         /**
1535          * Called when client trying to connect but device blocked the client with specific reason.
1536          *
1537          * @param client the currently blocked client.
1538          * @param blockedReason one of blocked reason from
1539          * {@link WifiManager.SapClientBlockedReason}
1540          */
1541         @Override
onBlockedClientConnecting(WifiClient client, int blockedReason)1542         public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
1543             int itemCount = mRegisteredSoftApCallbacks.beginBroadcast();
1544             for (int i = 0; i < itemCount; i++) {
1545                 try {
1546                     mRegisteredSoftApCallbacks.getBroadcastItem(i).onBlockedClientConnecting(client,
1547                             blockedReason);
1548                 } catch (RemoteException e) {
1549                     Log.e(TAG, "onBlockedClientConnecting: remote exception -- " + e);
1550                 }
1551             }
1552             mRegisteredSoftApCallbacks.finishBroadcast();
1553         }
1554     }
1555 
1556     /**
1557      * Implements LOHS behavior on top of the existing SoftAp API.
1558      */
1559     private final class LohsSoftApTracker implements SoftApCallbackInternal {
1560         @GuardedBy("mLocalOnlyHotspotRequests")
1561         private final HashMap<Integer, LocalOnlyHotspotRequestInfo>
1562                 mLocalOnlyHotspotRequests = new HashMap<>();
1563 
1564         /** Currently-active config, to be sent to shared clients registering later. */
1565         @GuardedBy("mLocalOnlyHotspotRequests")
1566         private SoftApModeConfiguration mActiveConfig = null;
1567 
1568         /**
1569          * Whether we are currently operating in exclusive mode (i.e. whether a custom config is
1570          * active).
1571          */
1572         @GuardedBy("mLocalOnlyHotspotRequests")
1573         private boolean mIsExclusive = false;
1574 
1575         @GuardedBy("mLocalOnlyHotspotRequests")
1576         private String mLohsInterfaceName;
1577 
1578         /**
1579          * State of local-only hotspot
1580          * One of:  {@link WifiManager#WIFI_AP_STATE_DISABLED},
1581          *          {@link WifiManager#WIFI_AP_STATE_DISABLING},
1582          *          {@link WifiManager#WIFI_AP_STATE_ENABLED},
1583          *          {@link WifiManager#WIFI_AP_STATE_ENABLING},
1584          *          {@link WifiManager#WIFI_AP_STATE_FAILED}
1585          */
1586         @GuardedBy("mLocalOnlyHotspotRequests")
1587         private int mLohsState = WIFI_AP_STATE_DISABLED;
1588 
1589         @GuardedBy("mLocalOnlyHotspotRequests")
1590         private int mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
1591 
1592         private SoftApCapability mLohsSoftApCapability = null;
1593 
getSoftApCapability()1594         public SoftApCapability getSoftApCapability() {
1595             if (mLohsSoftApCapability == null) {
1596                 mLohsSoftApCapability =  ApConfigUtil.updateCapabilityFromResource(mContext);
1597             }
1598             return mLohsSoftApCapability;
1599         }
1600 
updateInterfaceIpState(String ifaceName, int mode)1601         public void updateInterfaceIpState(String ifaceName, int mode) {
1602             // update interface IP state related to local-only hotspot
1603             synchronized (mLocalOnlyHotspotRequests) {
1604                 Log.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
1605                         + " previous LOHS mode= " + mLohsInterfaceMode);
1606 
1607                 switch (mode) {
1608                     case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
1609                         // first make sure we have registered requests.
1610                         if (mLocalOnlyHotspotRequests.isEmpty()) {
1611                             // we don't have requests...  stop the hotspot
1612                             Log.wtf(TAG, "Starting LOHS without any requests?");
1613                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1614                             return;
1615                         }
1616                         // LOHS is ready to go!  Call our registered requestors!
1617                         mLohsInterfaceName = ifaceName;
1618                         mLohsInterfaceMode = mode;
1619                         sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked();
1620                         break;
1621                     case WifiManager.IFACE_IP_MODE_TETHERED:
1622                         if (mLohsInterfaceName != null
1623                                 && mLohsInterfaceName.equals(ifaceName)) {
1624                             /* This shouldn't happen except in a race, but if it does, tear down
1625                              * the LOHS and let tethering win.
1626                              *
1627                              * If concurrent SAPs are allowed, the interface names will differ,
1628                              * so we don't have to check the config here.
1629                              */
1630                             Log.e(TAG, "Unexpected IP mode change on " + ifaceName);
1631                             mLohsInterfaceName = null;
1632                             mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
1633                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1634                                     LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
1635                         }
1636                         break;
1637                     case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR:
1638                         if (ifaceName == null) {
1639                             // All softAps
1640                             mLohsInterfaceName = null;
1641                             mLohsInterfaceMode = mode;
1642                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1643                                     LocalOnlyHotspotCallback.ERROR_GENERIC);
1644                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1645                         } else if (ifaceName.equals(mLohsInterfaceName)) {
1646                             mLohsInterfaceName = null;
1647                             mLohsInterfaceMode = mode;
1648                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1649                                     LocalOnlyHotspotCallback.ERROR_GENERIC);
1650                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1651                         } else {
1652                             // Not for LOHS. This is the wrong place to do this, but...
1653                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
1654                         }
1655                         break;
1656                     case WifiManager.IFACE_IP_MODE_UNSPECIFIED:
1657                         if (ifaceName == null || ifaceName.equals(mLohsInterfaceName)) {
1658                             mLohsInterfaceName = null;
1659                             mLohsInterfaceMode = mode;
1660                         }
1661                         break;
1662                     default:
1663                         mLog.warn("updateInterfaceIpState: unknown mode %").c(mode).flush();
1664                 }
1665             }
1666         }
1667 
1668         /**
1669          * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest
1670          * callers and clear the registrations.
1671          *
1672          * Callers should already hold the mLocalOnlyHotspotRequests lock.
1673          */
1674         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason)1675         private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason) {
1676             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1677                 try {
1678                     requestor.sendHotspotFailedMessage(reason);
1679                     requestor.unlinkDeathRecipient();
1680                 } catch (RemoteException e) {
1681                     // This will be cleaned up by binder death handling
1682                 }
1683             }
1684 
1685             // Since all callers were notified, now clear the registrations.
1686             mLocalOnlyHotspotRequests.clear();
1687         }
1688 
1689         /**
1690          * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest
1691          * callers and clear the registrations.
1692          *
1693          * Callers should already hold the mLocalOnlyHotspotRequests lock.
1694          */
1695         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked()1696         private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() {
1697             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1698                 try {
1699                     requestor.sendHotspotStoppedMessage();
1700                     requestor.unlinkDeathRecipient();
1701                 } catch (RemoteException e) {
1702                     // This will be cleaned up by binder death handling
1703                 }
1704             }
1705 
1706             // Since all callers were notified, now clear the registrations.
1707             mLocalOnlyHotspotRequests.clear();
1708         }
1709 
1710         /**
1711          * Add a new LOHS client
1712          */
start(int pid, LocalOnlyHotspotRequestInfo request)1713         private int start(int pid, LocalOnlyHotspotRequestInfo request) {
1714             synchronized (mLocalOnlyHotspotRequests) {
1715                 // does this caller already have a request?
1716                 if (mLocalOnlyHotspotRequests.get(pid) != null) {
1717                     mLog.trace("caller already has an active request").flush();
1718                     throw new IllegalStateException(
1719                             "Caller already has an active LocalOnlyHotspot request");
1720                 }
1721 
1722                 // Never accept exclusive requests (with custom configuration) at the same time as
1723                 // shared requests.
1724                 if (!mLocalOnlyHotspotRequests.isEmpty()) {
1725                     boolean requestIsExclusive = request.getCustomConfig() != null;
1726                     if (mIsExclusive || requestIsExclusive) {
1727                         mLog.trace("Cannot share with existing LOHS request due to custom config")
1728                                 .flush();
1729                         return LocalOnlyHotspotCallback.ERROR_GENERIC;
1730                     }
1731                 }
1732 
1733                 // At this point, the request is accepted.
1734                 if (mLocalOnlyHotspotRequests.isEmpty()) {
1735                     mWifiThreadRunner.post(() -> {
1736                         startForFirstRequestLocked(request);
1737                     });
1738 
1739                 } else if (mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) {
1740                     // LOHS has already started up for an earlier request, so we can send the
1741                     // current config to the incoming request right away.
1742                     try {
1743                         mLog.trace("LOHS already up, trigger onStarted callback").flush();
1744                         request.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration());
1745                     } catch (RemoteException e) {
1746                         return LocalOnlyHotspotCallback.ERROR_GENERIC;
1747                     }
1748                 }
1749 
1750                 mLocalOnlyHotspotRequests.put(pid, request);
1751                 return LocalOnlyHotspotCallback.REQUEST_REGISTERED;
1752             }
1753         }
1754 
1755         @GuardedBy("mLocalOnlyHotspotRequests")
startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request)1756         private void startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request) {
1757             int band = WifiApConfigStore.generateDefaultBand(mContext);
1758 
1759             // For auto only
1760             if (hasAutomotiveFeature(mContext)) {
1761                 if (mContext.getResources().getBoolean(R.bool.config_wifiLocalOnlyHotspot6ghz)
1762                         && ApConfigUtil.isBandSupported(SoftApConfiguration.BAND_6GHZ, mContext)) {
1763                     band = SoftApConfiguration.BAND_6GHZ;
1764                 } else if (mContext.getResources().getBoolean(
1765                         R.bool.config_wifi_local_only_hotspot_5ghz)
1766                         && ApConfigUtil.isBandSupported(SoftApConfiguration.BAND_5GHZ, mContext)) {
1767                     band = SoftApConfiguration.BAND_5GHZ;
1768                 }
1769             }
1770             SoftApConfiguration softApConfig = mWifiApConfigStore.generateLocalOnlyHotspotConfig(
1771                     mContext, band, request.getCustomConfig());
1772 
1773             mActiveConfig = new SoftApModeConfiguration(
1774                     WifiManager.IFACE_IP_MODE_LOCAL_ONLY,
1775                     softApConfig, mLohsSoftApTracker.getSoftApCapability());
1776             mIsExclusive = (request.getCustomConfig() != null);
1777 
1778             startSoftApInternal(mActiveConfig, request.getWorkSource());
1779         }
1780 
1781         /**
1782          * Requests that any local-only hotspot be stopped.
1783          */
stopAll()1784         public void stopAll() {
1785             synchronized (mLocalOnlyHotspotRequests) {
1786                 if (!mLocalOnlyHotspotRequests.isEmpty()) {
1787                     // This is used to take down LOHS when tethering starts, and in that
1788                     // case we send failed instead of stopped.
1789                     // TODO check if that is right. Calling onFailed instead of onStopped when the
1790                     // hotspot is already started does not seem to match the documentation
1791                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1792                             LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
1793                     stopIfEmptyLocked();
1794                 }
1795             }
1796         }
1797 
1798         /**
1799          * Unregisters the LOHS request from the given process and stops LOHS if no other clients.
1800          */
stopByPid(int pid)1801         public void stopByPid(int pid) {
1802             synchronized (mLocalOnlyHotspotRequests) {
1803                 LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.remove(pid);
1804                 if (requestInfo == null) return;
1805                 requestInfo.unlinkDeathRecipient();
1806                 stopIfEmptyLocked();
1807             }
1808         }
1809 
1810         /**
1811          * Unregisters LocalOnlyHotspot request and stops the hotspot if needed.
1812          */
stopByRequest(LocalOnlyHotspotRequestInfo request)1813         public void stopByRequest(LocalOnlyHotspotRequestInfo request) {
1814             synchronized (mLocalOnlyHotspotRequests) {
1815                 if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) {
1816                     mLog.trace("LocalOnlyHotspotRequestInfo not found to remove").flush();
1817                     return;
1818                 }
1819                 stopIfEmptyLocked();
1820             }
1821         }
1822 
1823         @GuardedBy("mLocalOnlyHotspotRequests")
stopIfEmptyLocked()1824         private void stopIfEmptyLocked() {
1825             if (mLocalOnlyHotspotRequests.isEmpty()) {
1826                 mActiveConfig = null;
1827                 mIsExclusive = false;
1828                 mLohsInterfaceName = null;
1829                 mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
1830                 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1831             }
1832         }
1833 
1834         /**
1835          * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest
1836          * callers.
1837          *
1838          * Callers should already hold the mLocalOnlyHotspotRequests lock.
1839          */
1840         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked()1841         private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() {
1842             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1843                 try {
1844                     requestor.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration());
1845                 } catch (RemoteException e) {
1846                     // This will be cleaned up by binder death handling
1847                 }
1848             }
1849         }
1850 
1851         @Override
onStateChanged(int state, int failureReason)1852         public void onStateChanged(int state, int failureReason) {
1853             // The AP state update from ClientModeImpl for softap
1854             synchronized (mLocalOnlyHotspotRequests) {
1855                 Log.d(TAG, "lohs.onStateChanged: currentState=" + state
1856                         + " previousState=" + mLohsState + " errorCode= " + failureReason
1857                         + " ifaceName=" + mLohsInterfaceName);
1858 
1859                 // check if we have a failure - since it is possible (worst case scenario where
1860                 // WifiController and ClientModeImpl are out of sync wrt modes) to get two FAILED
1861                 // notifications in a row, we need to handle this first.
1862                 if (state == WIFI_AP_STATE_FAILED) {
1863                     // update registered LOHS callbacks if we see a failure
1864                     int errorToReport = ERROR_GENERIC;
1865                     if (failureReason == SAP_START_FAILURE_NO_CHANNEL) {
1866                         errorToReport = ERROR_NO_CHANNEL;
1867                     }
1868                     // holding the required lock: send message to requestors and clear the list
1869                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(errorToReport);
1870                     // also need to clear interface ip state
1871                     updateInterfaceIpState(mLohsInterfaceName,
1872                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1873                 } else if (state == WIFI_AP_STATE_DISABLING || state == WIFI_AP_STATE_DISABLED) {
1874                     // softap is shutting down or is down...  let requestors know via the
1875                     // onStopped call
1876                     // if we are currently in hotspot mode, then trigger onStopped for registered
1877                     // requestors, otherwise something odd happened and we should clear state
1878                     if (mLohsInterfaceName != null
1879                             && mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) {
1880                         // holding the required lock: send message to requestors and clear the list
1881                         sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
1882                     } else {
1883                         // LOHS not active: report an error (still holding the required lock)
1884                         sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC);
1885                     }
1886                     // also clear interface ip state
1887                     updateInterfaceIpState(mLohsInterfaceName,
1888                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1889                 }
1890                 // For enabling and enabled, just record the new state
1891                 mLohsState = state;
1892             }
1893         }
1894     }
1895 
1896     /**
1897      * see {@link android.net.wifi.WifiManager#registerSoftApCallback(Executor,
1898      * WifiManager.SoftApCallback)}
1899      *
1900      * @param callback Soft AP callback to register
1901      *
1902      * @throws SecurityException if the caller does not have permission to register a callback
1903      * @throws RemoteException if remote exception happens
1904      * @throws IllegalArgumentException if the arguments are null or invalid
1905      */
1906     @Override
registerSoftApCallback(ISoftApCallback callback)1907     public void registerSoftApCallback(ISoftApCallback callback) {
1908         // verify arguments
1909         if (callback == null) {
1910             throw new IllegalArgumentException("Callback must not be null");
1911         }
1912 
1913         int uid = Binder.getCallingUid();
1914         int pid = Binder.getCallingPid();
1915         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
1916                 && !checkNetworkSettingsPermission(pid, uid)
1917                 && !checkMainlineNetworkStackPermission(pid, uid)) {
1918             // random apps should not be allowed to read the user specified config
1919             throw new SecurityException("App not allowed to read  WiFi Ap information "
1920                     + "(uid/pid = " + uid + "/" + pid + ")");
1921         }
1922 
1923         if (isVerboseLoggingEnabled()) {
1924             mLog.info("registerSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
1925         }
1926 
1927         // post operation to handler thread
1928         mWifiThreadRunner.post(() -> {
1929             if (!mTetheredSoftApTracker.registerSoftApCallback(callback)) {
1930                 Log.e(TAG, "registerSoftApCallback: Failed to add callback");
1931                 return;
1932             }
1933             // Update the client about the current state immediately after registering the callback
1934             try {
1935                 callback.onStateChanged(mTetheredSoftApTracker.getState(), 0);
1936                 callback.onConnectedClientsOrInfoChanged(mTetheredSoftApTracker.getSoftApInfos(),
1937                         mTetheredSoftApTracker.getConnectedClients(),
1938                         mTetheredSoftApTracker.getIsBridgedMode(), true);
1939                 callback.onCapabilityChanged(mTetheredSoftApTracker.getSoftApCapability());
1940             } catch (RemoteException e) {
1941                 Log.e(TAG, "registerSoftApCallback: remote exception -- " + e);
1942             }
1943         });
1944     }
1945 
1946     /**
1947      * see {@link android.net.wifi.WifiManager#unregisterSoftApCallback(WifiManager.SoftApCallback)}
1948      *
1949      * @param callback Soft AP callback to unregister
1950      *
1951      * @throws SecurityException if the caller does not have permission to register a callback
1952      */
1953     @Override
unregisterSoftApCallback(ISoftApCallback callback)1954     public void unregisterSoftApCallback(ISoftApCallback callback) {
1955         int uid = Binder.getCallingUid();
1956         int pid = Binder.getCallingPid();
1957         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
1958                 && !checkNetworkSettingsPermission(pid, uid)
1959                 && !checkMainlineNetworkStackPermission(pid, uid)) {
1960             // random apps should not be allowed to read the user specified config
1961             throw new SecurityException("App not allowed to read  WiFi Ap information "
1962                     + "(uid/pid = " + uid + "/" + pid + ")");
1963         }
1964 
1965         if (isVerboseLoggingEnabled()) {
1966             mLog.info("unregisterSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
1967         }
1968 
1969         // post operation to handler thread
1970         mWifiThreadRunner.post(() ->
1971                 mTetheredSoftApTracker.unregisterSoftApCallback(callback));
1972     }
1973 
1974     /**
1975      * Temporary method used for testing while start is not fully implemented.  This
1976      * method allows unit tests to register callbacks directly for testing mechanisms triggered by
1977      * softap mode changes.
1978      */
1979     @VisibleForTesting
registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request)1980     void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) {
1981         mLohsSoftApTracker.start(pid, request);
1982     }
1983 
1984     /**
1985      * Method to start LocalOnlyHotspot.  In this method, permissions, settings and modes are
1986      * checked to verify that we can enter softapmode.  This method returns
1987      * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise,
1988      * possible startup erros may include tethering being disallowed failure reason {@link
1989      * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason
1990      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}.
1991      *
1992      * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}
1993      *
1994      * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies.
1995      * @param packageName String name of the calling package.
1996      * @param featureId The feature in the package
1997      * @param customConfig Custom configuration to be applied to the hotspot, or null for a shared
1998      *                     hotspot with framework-generated config.
1999      *
2000      * @return int return code for attempt to start LocalOnlyHotspot.
2001      *
2002      * @throws SecurityException if the caller does not have permission to start a Local Only
2003      * Hotspot.
2004      * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they
2005      * have an outstanding request.
2006      */
2007     @Override
startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName, String featureId, SoftApConfiguration customConfig)2008     public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName,
2009             String featureId, SoftApConfiguration customConfig) {
2010         // first check if the caller has permission to start a local only hotspot
2011         // need to check for WIFI_STATE_CHANGE and location permission
2012         final int uid = Binder.getCallingUid();
2013         final int pid = Binder.getCallingPid();
2014 
2015         mLog.info("start uid=% pid=%").c(uid).c(pid).flush();
2016 
2017         final WorkSource requestorWs;
2018         // Permission requirements are different with/without custom config.
2019         if (customConfig == null) {
2020             if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2021                 return LocalOnlyHotspotCallback.ERROR_GENERIC;
2022             }
2023             enforceLocationPermission(packageName, featureId, uid);
2024             long ident = Binder.clearCallingIdentity();
2025             try {
2026                 // also need to verify that Locations services are enabled.
2027                 if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
2028                     throw new SecurityException("Location mode is not enabled.");
2029                 }
2030                 // TODO(b/162344695): Exception added for LOHS. This exception is need to avoid
2031                 // breaking existing LOHS behavior: LOHS AP iface is allowed to delete STA iface
2032                 // (even if LOHS app has lower priority than user toggled on STA iface). This does
2033                 // not fit in with the new context based concurrency priority in HalDeviceManager,
2034                 // but we cannot break existing API's. So, we artificially boost the priority of
2035                 // the request by "faking" the requestor context as settings app.
2036                 // We probably need some UI dialog to allow the user to grant the app's LOHS
2037                 // request. Once that UI dialog is added, we can get rid of this hack and use the UI
2038                 // to elevate the priority of LOHS request only if user approves the request to
2039                 // toggle wifi off for LOHS.
2040                 requestorWs = mFrameworkFacade.getSettingsWorkSource(mContext);
2041             } finally {
2042                 Binder.restoreCallingIdentity(ident);
2043             }
2044         } else {
2045             if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2046                 throw new SecurityException(TAG + ": Permission denied");
2047             }
2048             // Already privileged, no need to fake.
2049             requestorWs = new WorkSource(uid, packageName);
2050         }
2051 
2052         // verify that tethering is not disabled
2053         if (mUserManager.hasUserRestrictionForUser(
2054                 UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.getUserHandleForUid(uid))) {
2055             return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
2056         }
2057 
2058         // the app should be in the foreground
2059         long ident = Binder.clearCallingIdentity();
2060         try {
2061             // also need to verify that Locations services are enabled.
2062             if (!mFrameworkFacade.isAppForeground(mContext, uid)) {
2063                 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
2064             }
2065         } finally {
2066             Binder.restoreCallingIdentity(ident);
2067         }
2068 
2069         // check if we are currently tethering
2070         if (!mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs)
2071                 && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) {
2072             // Tethering is enabled, cannot start LocalOnlyHotspot
2073             mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.")
2074                     .flush();
2075             return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
2076         }
2077 
2078         // now create the new LOHS request info object
2079         LocalOnlyHotspotRequestInfo request = new LocalOnlyHotspotRequestInfo(
2080                 requestorWs, callback, new LocalOnlyRequestorCallback(), customConfig);
2081 
2082         return mLohsSoftApTracker.start(pid, request);
2083     }
2084 
2085     /**
2086      * see {@link WifiManager#stopLocalOnlyHotspot()}
2087      *
2088      * @throws SecurityException if the caller does not have permission to stop a Local Only
2089      * Hotspot.
2090      */
2091     @Override
stopLocalOnlyHotspot()2092     public void stopLocalOnlyHotspot() {
2093         // don't do a permission check here. if the app's permission to change the wifi state is
2094         // revoked, we still want them to be able to stop a previously created hotspot (otherwise
2095         // it could cost the user money). When the app created the hotspot, its permission was
2096         // checked.
2097         final int uid = Binder.getCallingUid();
2098         final int pid = Binder.getCallingPid();
2099 
2100         mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
2101 
2102         mLohsSoftApTracker.stopByPid(pid);
2103     }
2104 
2105     /**
2106      * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)}
2107      *
2108      * This call requires the android.permission.NETWORK_SETTINGS permission.
2109      *
2110      * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies.
2111      *
2112      * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot
2113      * status updates.
2114      * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with
2115      * an existing subscription.
2116      */
2117     @Override
startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback)2118     public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) {
2119         // NETWORK_SETTINGS is a signature only permission.
2120         enforceNetworkSettingsPermission();
2121 
2122         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
2123     }
2124 
2125     /**
2126      * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()}
2127      */
2128     @Override
stopWatchLocalOnlyHotspot()2129     public void stopWatchLocalOnlyHotspot() {
2130         // NETWORK_STACK is a signature only permission.
2131         enforceNetworkSettingsPermission();
2132         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
2133     }
2134 
2135     /**
2136      * see {@link WifiManager#getWifiApConfiguration()}
2137      * @return soft access point configuration
2138      * @throws SecurityException if the caller does not have permission to retrieve the softap
2139      * config
2140      */
2141     @Nullable
2142     @Override
getWifiApConfiguration()2143     public WifiConfiguration getWifiApConfiguration() {
2144         enforceAccessPermission();
2145         int uid = Binder.getCallingUid();
2146         // only allow Settings UI to get the saved SoftApConfig
2147         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
2148             // random apps should not be allowed to read the user specified config
2149             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
2150                     + "(uid = " + uid + ")");
2151         }
2152 
2153         if (isVerboseLoggingEnabled()) {
2154             mLog.info("getWifiApConfiguration uid=%").c(uid).flush();
2155         }
2156 
2157         // hand off work to the ClientModeImpl handler thread to sync work between calls
2158         // and SoftApManager starting up softap
2159         return (mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration,
2160                 new SoftApConfiguration.Builder().build())).toWifiConfiguration();
2161     }
2162 
2163     /**
2164      * see {@link WifiManager#getSoftApConfiguration()}
2165      * @return soft access point configuration {@link SoftApConfiguration}
2166      * @throws SecurityException if the caller does not have permission to retrieve the softap
2167      * config
2168      */
2169     @NonNull
2170     @Override
getSoftApConfiguration()2171     public SoftApConfiguration getSoftApConfiguration() {
2172         int uid = Binder.getCallingUid();
2173         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
2174                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
2175             // random apps should not be allowed to read the user specified config
2176             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
2177                     + "(uid = " + uid + ")");
2178         }
2179         if (isVerboseLoggingEnabled()) {
2180             mLog.info("getSoftApConfiguration uid=%").c(uid).flush();
2181         }
2182 
2183         // hand off work to the ClientModeImpl handler thread to sync work between calls
2184         // and SoftApManager starting up softap
2185         return mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration,
2186                 new SoftApConfiguration.Builder().build());
2187     }
2188 
2189     /**
2190      * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
2191      * @param wifiConfig WifiConfiguration details for soft access point
2192      * @return boolean indicating success or failure of the operation
2193      * @throws SecurityException if the caller does not have permission to write the softap config
2194      */
2195     @Override
setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName)2196     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
2197         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2198             return false;
2199         }
2200         int uid = Binder.getCallingUid();
2201         // only allow Settings UI to write the stored SoftApConfig
2202         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
2203             // random apps should not be allowed to read the user specified config
2204             throw new SecurityException("App not allowed to read or update stored WiFi AP config "
2205                     + "(uid = " + uid + ")");
2206         }
2207         mLog.info("setWifiApConfiguration uid=%").c(uid).flush();
2208         if (wifiConfig == null)
2209             return false;
2210         SoftApConfiguration softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig);
2211         if (softApConfig == null) return false;
2212         if (WifiApConfigStore.validateApWifiConfiguration(
2213                 softApConfig, false, mContext)) {
2214             mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(softApConfig));
2215             return true;
2216         } else {
2217             Log.e(TAG, "Invalid WifiConfiguration");
2218             return false;
2219         }
2220     }
2221 
2222     /**
2223      * see {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}
2224      * @param softApConfig {@link SoftApConfiguration} details for soft access point
2225      * @return boolean indicating success or failure of the operation
2226      * @throws SecurityException if the caller does not have permission to write the softap config
2227      */
2228     @Override
setSoftApConfiguration( @onNull SoftApConfiguration softApConfig, @NonNull String packageName)2229     public boolean setSoftApConfiguration(
2230             @NonNull SoftApConfiguration softApConfig, @NonNull String packageName) {
2231         int uid = Binder.getCallingUid();
2232         boolean privileged = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
2233         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
2234                 && !privileged) {
2235             // random apps should not be allowed to read the user specified config
2236             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
2237                     + "(uid = " + uid + ")");
2238         }
2239         mLog.info("setSoftApConfiguration uid=%").c(uid).flush();
2240         if (softApConfig == null) return false;
2241         if (WifiApConfigStore.validateApWifiConfiguration(softApConfig, privileged, mContext)) {
2242             mActiveModeWarden.updateSoftApConfiguration(softApConfig);
2243             mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(softApConfig));
2244             return true;
2245         } else {
2246             Log.e(TAG, "Invalid SoftAp Configuration");
2247             return false;
2248         }
2249     }
2250 
2251     /**
2252      * see {@link android.net.wifi.WifiManager#setScanAlwaysAvailable(boolean)}
2253      */
2254     @Override
setScanAlwaysAvailable(boolean isAvailable, String packageName)2255     public void setScanAlwaysAvailable(boolean isAvailable, String packageName) {
2256         enforceNetworkSettingsPermission();
2257         mLog.info("setScanAlwaysAvailable uid=% package=% isAvailable=%")
2258                 .c(Binder.getCallingUid())
2259                 .c(packageName)
2260                 .c(isAvailable)
2261                 .flush();
2262         mSettingsStore.handleWifiScanAlwaysAvailableToggled(isAvailable);
2263         long ident = Binder.clearCallingIdentity();
2264         try {
2265             mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility()
2266                     .handleWifiScanAlwaysAvailableToggled(isAvailable);
2267         } finally {
2268             Binder.restoreCallingIdentity(ident);
2269         }
2270         mActiveModeWarden.scanAlwaysModeChanged();
2271     }
2272 
2273     /**
2274      * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
2275      */
2276     @Override
isScanAlwaysAvailable()2277     public boolean isScanAlwaysAvailable() {
2278         enforceAccessPermission();
2279         if (isVerboseLoggingEnabled()) {
2280             mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
2281         }
2282         return mSettingsStore.isScanAlwaysAvailableToggleEnabled();
2283     }
2284 
2285     /**
2286      * see {@link android.net.wifi.WifiManager#disconnect()}
2287      */
2288     @Override
disconnect(String packageName)2289     public boolean disconnect(String packageName) {
2290         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2291             return false;
2292         }
2293         if (!isTargetSdkLessThanQOrPrivileged(
2294                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2295             mLog.info("disconnect not allowed for uid=%")
2296                     .c(Binder.getCallingUid()).flush();
2297             return false;
2298         }
2299         mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush();
2300         mWifiThreadRunner.post(() -> mActiveModeWarden.getPrimaryClientModeManager().disconnect());
2301         return true;
2302     }
2303 
2304     /**
2305      * see {@link android.net.wifi.WifiManager#reconnect()}
2306      */
2307     @Override
reconnect(String packageName)2308     public boolean reconnect(String packageName) {
2309         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2310             return false;
2311         }
2312         int callingUid = Binder.getCallingUid();
2313         if (!isTargetSdkLessThanQOrPrivileged(packageName, Binder.getCallingPid(), callingUid)) {
2314             mLog.info("reconnect not allowed for uid=%").c(callingUid).flush();
2315             return false;
2316         }
2317         mLog.info("reconnect uid=%").c(callingUid).flush();
2318 
2319         mWifiThreadRunner.post(() -> {
2320             mActiveModeWarden.getPrimaryClientModeManager().reconnect(new WorkSource(callingUid));
2321         });
2322         return true;
2323     }
2324 
2325     /**
2326      * see {@link android.net.wifi.WifiManager#reassociate()}
2327      */
2328     @Override
reassociate(String packageName)2329     public boolean reassociate(String packageName) {
2330         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2331             return false;
2332         }
2333         if (!isTargetSdkLessThanQOrPrivileged(
2334                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2335             mLog.info("reassociate not allowed for uid=%")
2336                     .c(Binder.getCallingUid()).flush();
2337             return false;
2338         }
2339         mLog.info("reassociate uid=%").c(Binder.getCallingUid()).flush();
2340         mWifiThreadRunner.post(() -> mActiveModeWarden.getPrimaryClientModeManager().reassociate());
2341         return true;
2342     }
2343 
2344     /**
2345      * Returns true if we should log the call to getSupportedFeatures.
2346      *
2347      * Because of the way getSupportedFeatures is used in WifiManager, there are
2348      * often clusters of several back-to-back calls; avoid repeated logging if
2349      * the feature set has not changed and the time interval is short.
2350      */
needToLogSupportedFeatures(long features)2351     private boolean needToLogSupportedFeatures(long features) {
2352         if (isVerboseLoggingEnabled()) {
2353             long now = mClock.getElapsedSinceBootMillis();
2354             synchronized (this) {
2355                 if (now > mLastLoggedSupportedFeaturesTimestamp + A_FEW_MILLISECONDS
2356                         || features != mLastLoggedSupportedFeatures) {
2357                     mLastLoggedSupportedFeaturesTimestamp = now;
2358                     mLastLoggedSupportedFeatures = features;
2359                     return true;
2360                 }
2361             }
2362         }
2363         return false;
2364     }
2365     private static final int A_FEW_MILLISECONDS = 250;
2366     private long mLastLoggedSupportedFeatures = -1;
2367     private long mLastLoggedSupportedFeaturesTimestamp = 0;
2368 
2369     /**
2370      * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
2371      */
2372     @Override
getSupportedFeatures()2373     public long getSupportedFeatures() {
2374         enforceAccessPermission();
2375         long features = getSupportedFeaturesInternal();
2376         if (needToLogSupportedFeatures(features)) {
2377             mLog.info("getSupportedFeatures uid=% returns %")
2378                     .c(Binder.getCallingUid())
2379                     .c(Long.toHexString(features))
2380                     .flush();
2381         }
2382         return features;
2383     }
2384 
2385     @Override
getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener)2386     public void getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener) {
2387         if (isVerboseLoggingEnabled()) {
2388             mLog.info("getWifiActivityEnergyInfoAsync uid=%")
2389                     .c(Binder.getCallingUid())
2390                     .flush();
2391         }
2392         // getWifiActivityEnergyInfo() performs permission checking
2393         WifiActivityEnergyInfo info = getWifiActivityEnergyInfo();
2394         try {
2395             listener.onWifiActivityEnergyInfo(info);
2396         } catch (RemoteException e) {
2397             Log.e(TAG, "onWifiActivityEnergyInfo: RemoteException -- ", e);
2398         }
2399     }
2400 
getWifiActivityEnergyInfo()2401     private WifiActivityEnergyInfo getWifiActivityEnergyInfo() {
2402         enforceAccessPermission();
2403         if (isVerboseLoggingEnabled()) {
2404             mLog.info("getWifiActivityEnergyInfo uid=%").c(Binder.getCallingUid()).flush();
2405         }
2406         if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
2407             return null;
2408         }
2409         WifiLinkLayerStats stats = mWifiThreadRunner.call(
2410                 () -> mActiveModeWarden.getPrimaryClientModeManager().getWifiLinkLayerStats(),
2411                 null);
2412         if (stats == null) {
2413             return null;
2414         }
2415 
2416         final long rxIdleTimeMillis = stats.on_time - stats.tx_time - stats.rx_time;
2417         if (VDBG || rxIdleTimeMillis < 0 || stats.on_time < 0 || stats.tx_time < 0
2418                 || stats.rx_time < 0 || stats.on_time_scan < 0) {
2419             Log.d(TAG, " getWifiActivityEnergyInfo: "
2420                     + " on_time_millis=" + stats.on_time
2421                     + " tx_time_millis=" + stats.tx_time
2422                     + " rx_time_millis=" + stats.rx_time
2423                     + " rxIdleTimeMillis=" + rxIdleTimeMillis
2424                     + " scan_time_millis=" + stats.on_time_scan);
2425         }
2426 
2427         // Convert the LinkLayerStats into WifiActivityEnergyInfo
2428         return new WifiActivityEnergyInfo(
2429                 mClock.getElapsedSinceBootMillis(),
2430                 WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE,
2431                 stats.tx_time,
2432                 stats.rx_time,
2433                 stats.on_time_scan,
2434                 rxIdleTimeMillis);
2435     }
2436 
2437     /**
2438      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
2439      *
2440      * @param packageName String name of the calling package
2441      * @param featureId The feature in the package
2442      * @param callerNetworksOnly Whether to only return networks created by the caller
2443      * @return the list of configured networks
2444      */
2445     @Override
getConfiguredNetworks(String packageName, String featureId, boolean callerNetworksOnly)2446     public ParceledListSlice<WifiConfiguration> getConfiguredNetworks(String packageName,
2447             String featureId, boolean callerNetworksOnly) {
2448         enforceAccessPermission();
2449         int callingUid = Binder.getCallingUid();
2450         // bypass shell: can get various pkg name
2451         // also bypass if caller is only retrieving networks added by itself
2452         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
2453             mWifiPermissionsUtil.checkPackage(callingUid, packageName);
2454             if (!callerNetworksOnly) {
2455                 long ident = Binder.clearCallingIdentity();
2456                 try {
2457                     mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId,
2458                             callingUid, null);
2459                 } catch (SecurityException e) {
2460                     Log.w(TAG, "Permission violation - getConfiguredNetworks not allowed for uid="
2461                             + callingUid + ", packageName=" + packageName + ", reason=" + e);
2462                     return new ParceledListSlice<>(new ArrayList<>());
2463                 } finally {
2464                     Binder.restoreCallingIdentity(ident);
2465                 }
2466             }
2467         }
2468         boolean isDeviceOrProfileOwner = isDeviceOrProfileOwner(callingUid, packageName);
2469         boolean isCarrierApp = mWifiInjector.makeTelephonyManager()
2470                 .checkCarrierPrivilegesForPackageAnyPhone(packageName)
2471                 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
2472         boolean isPrivileged = isPrivileged(getCallingPid(), callingUid);
2473         // Only DO, PO, carrier app or system app can use callerNetworksOnly argument
2474         if (callerNetworksOnly) {
2475             if (!isDeviceOrProfileOwner && !isCarrierApp && !isPrivileged) {
2476                 throw new SecurityException(
2477                         "Not a DO, PO, carrier or privileged app");
2478             }
2479         }
2480         boolean isTargetSdkLessThanQOrPrivileged = isTargetSdkLessThanQOrPrivileged(
2481                 packageName, Binder.getCallingPid(), callingUid);
2482         if (!isTargetSdkLessThanQOrPrivileged && !isCarrierApp) {
2483             mLog.info("getConfiguredNetworks not allowed for uid=%")
2484                     .c(callingUid).flush();
2485             return new ParceledListSlice<>(new ArrayList<>());
2486         }
2487         if (isVerboseLoggingEnabled()) {
2488             mLog.info("getConfiguredNetworks uid=%").c(callingUid).flush();
2489         }
2490 
2491         int targetConfigUid = Process.INVALID_UID; // don't expose any MAC addresses
2492         if (isPrivileged || isDeviceOrProfileOwner) {
2493             targetConfigUid = Process.WIFI_UID; // expose all MAC addresses
2494         } else if (isCarrierApp) {
2495             targetConfigUid = callingUid; // expose only those configs created by the Carrier App
2496         }
2497         int finalTargetConfigUid = targetConfigUid;
2498         List<WifiConfiguration> configs = mWifiThreadRunner.call(
2499                 () -> mWifiConfigManager.getSavedNetworks(finalTargetConfigUid),
2500                 Collections.emptyList());
2501         if (isTargetSdkLessThanQOrPrivileged && !callerNetworksOnly) {
2502             return new ParceledListSlice<>(
2503                     WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(configs));
2504         }
2505         // Should only get its own configs
2506         List<WifiConfiguration> creatorConfigs = new ArrayList<>();
2507         for (WifiConfiguration config : configs) {
2508             if (config.creatorUid == callingUid) {
2509                 creatorConfigs.add(config);
2510             }
2511         }
2512         return new ParceledListSlice<>(
2513                 WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(creatorConfigs));
2514     }
2515 
2516     /**
2517      * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
2518      *
2519      * @param packageName String name of the calling package
2520      * @param featureId The feature in the package
2521      * @return the list of configured networks with real preSharedKey
2522      */
2523     @Override
getPrivilegedConfiguredNetworks( String packageName, String featureId)2524     public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks(
2525             String packageName, String featureId) {
2526         enforceReadCredentialPermission();
2527         enforceAccessPermission();
2528         int callingUid = Binder.getCallingUid();
2529         long ident = Binder.clearCallingIdentity();
2530         try {
2531             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
2532                     null);
2533         } catch (SecurityException e) {
2534             Log.w(TAG, "Permission violation - getPrivilegedConfiguredNetworks not allowed for"
2535                     + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
2536             return null;
2537         } finally {
2538             Binder.restoreCallingIdentity(ident);
2539         }
2540         if (isVerboseLoggingEnabled()) {
2541             mLog.info("getPrivilegedConfiguredNetworks uid=%").c(callingUid).flush();
2542         }
2543         List<WifiConfiguration> configs = mWifiThreadRunner.call(
2544                 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(),
2545                 Collections.emptyList());
2546         return new ParceledListSlice<>(
2547                 WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(configs));
2548     }
2549 
2550     /**
2551      * Return a map of all matching configurations keys with corresponding scanResults (or an empty
2552      * map if none).
2553      *
2554      * @param scanResults The list of scan results
2555      * @return Map that consists of FQDN (Fully Qualified Domain Name) and corresponding
2556      * scanResults per network type({@link WifiManager#PASSPOINT_HOME_NETWORK} and {@link
2557      * WifiManager#PASSPOINT_ROAMING_NETWORK}).
2558      */
2559     @Override
2560     public Map<String, Map<Integer, List<ScanResult>>>
getAllMatchingPasspointProfilesForScanResults(List<ScanResult> scanResults)2561             getAllMatchingPasspointProfilesForScanResults(List<ScanResult> scanResults) {
2562         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2563             throw new SecurityException(TAG + ": Permission denied");
2564         }
2565         if (isVerboseLoggingEnabled()) {
2566             mLog.info("getMatchingPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
2567         }
2568         if (!ScanResultUtil.validateScanResultList(scanResults)) {
2569             Log.e(TAG, "Attempt to retrieve passpoint with invalid scanResult List");
2570             return Collections.emptyMap();
2571         }
2572         return mWifiThreadRunner.call(
2573             () -> mPasspointManager.getAllMatchingPasspointProfilesForScanResults(scanResults),
2574                 Collections.emptyMap());
2575     }
2576 
2577     /**
2578      * Returns list of OSU (Online Sign-Up) providers associated with the given list of ScanResult.
2579      *
2580      * @param scanResults a list of ScanResult that has Passpoint APs.
2581      * @return Map that consists of {@link OsuProvider} and a matching list of {@link ScanResult}.
2582      */
2583     @Override
getMatchingOsuProviders( List<ScanResult> scanResults)2584     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
2585             List<ScanResult> scanResults) {
2586         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2587             throw new SecurityException(TAG + ": Permission denied");
2588         }
2589         if (isVerboseLoggingEnabled()) {
2590             mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush();
2591         }
2592 
2593         if (!ScanResultUtil.validateScanResultList(scanResults)) {
2594             Log.w(TAG, "Attempt to retrieve OsuProviders with invalid scanResult List");
2595             return Collections.emptyMap();
2596         }
2597         return mWifiThreadRunner.call(
2598             () -> mPasspointManager.getMatchingOsuProviders(scanResults), Collections.emptyMap());
2599     }
2600 
2601     /**
2602      * Returns the matching Passpoint configurations for given OSU(Online Sign-Up) providers.
2603      *
2604      * @param osuProviders a list of {@link OsuProvider}
2605      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
2606      */
2607     @Override
getMatchingPasspointConfigsForOsuProviders( List<OsuProvider> osuProviders)2608     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
2609             List<OsuProvider> osuProviders) {
2610         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2611             throw new SecurityException(TAG + ": Permission denied");
2612         }
2613         if (isVerboseLoggingEnabled()) {
2614             mLog.info("getMatchingPasspointConfigsForOsuProviders uid=%").c(
2615                     Binder.getCallingUid()).flush();
2616         }
2617         if (osuProviders == null) {
2618             Log.e(TAG, "Attempt to retrieve Passpoint configuration with null osuProviders");
2619             return new HashMap<>();
2620         }
2621         return mWifiThreadRunner.call(
2622             () -> mPasspointManager.getMatchingPasspointConfigsForOsuProviders(osuProviders),
2623                 Collections.emptyMap());
2624     }
2625 
2626     /**
2627      * Returns the corresponding wifi configurations for given FQDN (Fully Qualified Domain Name)
2628      * list.
2629      *
2630      * An empty list will be returned when no match is found.
2631      *
2632      * @param fqdnList a list of FQDN
2633      * @return List of {@link WifiConfiguration} converted from {@link PasspointProvider}
2634      */
2635     @Override
getWifiConfigsForPasspointProfiles(List<String> fqdnList)2636     public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) {
2637         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2638             throw new SecurityException(TAG + ": Permission denied");
2639         }
2640         if (isVerboseLoggingEnabled()) {
2641             mLog.info("getWifiConfigsForPasspointProfiles uid=%").c(
2642                     Binder.getCallingUid()).flush();
2643         }
2644         if (fqdnList == null) {
2645             Log.e(TAG, "Attempt to retrieve WifiConfiguration with null fqdn List");
2646             return new ArrayList<>();
2647         }
2648         return mWifiThreadRunner.call(
2649             () -> mPasspointManager.getWifiConfigsForPasspointProfiles(fqdnList),
2650                 Collections.emptyList());
2651     }
2652 
2653     /**
2654      * Returns a list of Wifi configurations for matched available WifiNetworkSuggestion
2655      * corresponding to the given scan results.
2656      *
2657      * An empty list will be returned when no match is found or all matched suggestions is not
2658      * available(not allow user manually connect, user not approved or open network).
2659      *
2660      * @param scanResults a list of {@link ScanResult}.
2661      * @return a list of {@link WifiConfiguration} from matched {@link WifiNetworkSuggestion}.
2662      */
2663     @Override
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( List<ScanResult> scanResults)2664     public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
2665             List<ScanResult> scanResults) {
2666         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2667             throw new SecurityException(TAG + ": Permission denied");
2668         }
2669         if (isVerboseLoggingEnabled()) {
2670             mLog.info("getWifiConfigsForMatchedNetworkSuggestions uid=%").c(
2671                     Binder.getCallingUid()).flush();
2672         }
2673         if (!ScanResultUtil.validateScanResultList(scanResults)) {
2674             Log.w(TAG, "Attempt to retrieve WifiConfiguration with invalid scanResult List");
2675             return new ArrayList<>();
2676         }
2677         return mWifiThreadRunner.call(
2678                 () -> mWifiNetworkSuggestionsManager
2679                         .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults),
2680                 Collections.emptyList());
2681     }
2682 
2683     /**
2684      * see {@link WifiManager#addNetworkPrivileged(WifiConfiguration)}
2685      * @return WifiManager.AddNetworkResult Object.
2686      */
2687     @Override
addOrUpdateNetworkPrivileged( WifiConfiguration config, String packageName)2688     public @NonNull WifiManager.AddNetworkResult addOrUpdateNetworkPrivileged(
2689             WifiConfiguration config, String packageName) {
2690         int pid = Binder.getCallingPid();
2691         int uid = Binder.getCallingUid();
2692         mWifiPermissionsUtil.checkPackage(uid, packageName);
2693         boolean hasPermission = isPrivileged(pid, uid)
2694                 || isDeviceOrProfileOwner(uid, packageName)
2695                 || mWifiPermissionsUtil.isSystem(packageName, uid);
2696         if (!hasPermission) {
2697             throw new SecurityException("Caller is not a device owner, profile owner, system app,"
2698                     + " or privileged app");
2699         }
2700         if (config != null) {
2701             config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
2702         }
2703         return addOrUpdateNetworkInternal(config, packageName, uid);
2704     }
2705 
2706     /**
2707      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
2708      * @return the supplicant-assigned identifier for the new or updated
2709      * network if the operation succeeds, or {@code -1} if it fails
2710      */
2711     @Override
addOrUpdateNetwork(WifiConfiguration config, String packageName)2712     public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
2713         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2714             return -1;
2715         }
2716         int callingUid = Binder.getCallingUid();
2717         if (!isTargetSdkLessThanQOrPrivileged(
2718                 packageName, Binder.getCallingPid(), callingUid)) {
2719             mLog.info("addOrUpdateNetwork not allowed for uid=%")
2720                     .c(Binder.getCallingUid()).flush();
2721             return -1;
2722         }
2723         if (config != null) {
2724             config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
2725         }
2726         mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
2727         return addOrUpdateNetworkInternal(config, packageName, callingUid).networkId;
2728     }
2729 
addOrUpdateNetworkInternal(WifiConfiguration config, String packageName, int callingUid)2730     private @NonNull AddNetworkResult addOrUpdateNetworkInternal(WifiConfiguration config,
2731             String packageName, int callingUid) {
2732         if (config == null) {
2733             Log.e(TAG, "bad network configuration");
2734             return new AddNetworkResult(
2735                     AddNetworkResult.STATUS_INVALID_CONFIGURATION, -1);
2736         }
2737         mWifiMetrics.incrementNumAddOrUpdateNetworkCalls();
2738 
2739         // Previously, this API is overloaded for installing Passpoint profiles.  Now
2740         // that we have a dedicated API for doing it, redirect the call to the dedicated API.
2741         if (config.isPasspoint()) {
2742             PasspointConfiguration passpointConfig =
2743                     PasspointProvider.convertFromWifiConfig(config);
2744             if (passpointConfig == null || passpointConfig.getCredential() == null) {
2745                 Log.e(TAG, "Missing credential for Passpoint profile");
2746                 return new AddNetworkResult(
2747                         AddNetworkResult.STATUS_ADD_PASSPOINT_FAILURE, -1);
2748             }
2749 
2750             // Copy over certificates and keys.
2751             X509Certificate[] x509Certificates = null;
2752             if (config.enterpriseConfig.getCaCertificate() != null) {
2753                 x509Certificates =
2754                         new X509Certificate[]{config.enterpriseConfig.getCaCertificate()};
2755             }
2756             passpointConfig.getCredential().setCaCertificates(x509Certificates);
2757             passpointConfig.getCredential().setClientCertificateChain(
2758                     config.enterpriseConfig.getClientCertificateChain());
2759             passpointConfig.getCredential().setClientPrivateKey(
2760                     config.enterpriseConfig.getClientPrivateKey());
2761             if (!addOrUpdatePasspointConfiguration(passpointConfig, packageName)) {
2762                 Log.e(TAG, "Failed to add Passpoint profile");
2763                 return new AddNetworkResult(
2764                         AddNetworkResult.STATUS_ADD_PASSPOINT_FAILURE, -1);
2765             }
2766             // There is no network ID associated with a Passpoint profile.
2767             return new AddNetworkResult(AddNetworkResult.STATUS_SUCCESS, 0);
2768         }
2769 
2770         if (config.isEnterprise() && config.enterpriseConfig.isEapMethodServerCertUsed()
2771                 && !config.enterpriseConfig.isMandatoryParameterSetForServerCertValidation()) {
2772             if (!(mContext.getResources().getBoolean(
2773                     R.bool.config_wifiAllowInsecureEnterpriseConfigurationsForSettingsAndSUW)
2774                     && isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid()))) {
2775                 Log.e(TAG, "Enterprise network configuration is missing either a Root CA "
2776                         + "or a domain name");
2777                 return new AddNetworkResult(
2778                         AddNetworkResult.STATUS_INVALID_CONFIGURATION_ENTERPRISE, -1);
2779             }
2780             Log.w(TAG, "Insecure Enterprise network " + config.SSID
2781                     + " configured by Settings/SUW");
2782         }
2783 
2784         Log.i("addOrUpdateNetworkInternal", " uid = " + Binder.getCallingUid()
2785                 + " SSID " + config.SSID
2786                 + " nid=" + config.networkId);
2787         // TODO: b/171981339, add more detailed failure reason into
2788         //  WifiConfigManager.NetworkUpdateResult, and plumb that reason up.
2789         int networkId =  mWifiThreadRunner.call(
2790                 () -> mWifiConfigManager.addOrUpdateNetwork(config, callingUid, packageName)
2791                         .getNetworkId(),
2792                 WifiConfiguration.INVALID_NETWORK_ID);
2793         if (networkId >= 0) {
2794             return new AddNetworkResult(AddNetworkResult.STATUS_SUCCESS, addSecurityTypeToNetworkId(
2795                     networkId, config.getDefaultSecurityParams().getSecurityType()));
2796         }
2797         return new AddNetworkResult(
2798                 AddNetworkResult.STATUS_ADD_WIFI_CONFIG_FAILURE, -1);
2799     }
2800 
verifyCert(X509Certificate caCert)2801     public static void verifyCert(X509Certificate caCert)
2802             throws GeneralSecurityException, IOException {
2803         CertificateFactory factory = CertificateFactory.getInstance("X.509");
2804         CertPathValidator validator =
2805                 CertPathValidator.getInstance(CertPathValidator.getDefaultType());
2806         CertPath path = factory.generateCertPath(
2807                 Arrays.asList(caCert));
2808         KeyStore ks = KeyStore.getInstance("AndroidCAStore");
2809         ks.load(null, null);
2810         PKIXParameters params = new PKIXParameters(ks);
2811         params.setRevocationEnabled(false);
2812         validator.validate(path, params);
2813     }
2814 
2815     /**
2816      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
2817      * @param netId the integer that identifies the network configuration
2818      * to the supplicant
2819      * @return {@code true} if the operation succeeded
2820      */
2821     @Override
removeNetwork(int netId, String packageName)2822     public boolean removeNetwork(int netId, String packageName) {
2823         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2824             return false;
2825         }
2826         if (!isTargetSdkLessThanQOrPrivileged(
2827                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2828             mLog.info("removeNetwork not allowed for uid=%")
2829                     .c(Binder.getCallingUid()).flush();
2830             return false;
2831         }
2832         final int internalNetId = removeSecurityTypeFromNetworkId(netId);
2833         int callingUid = Binder.getCallingUid();
2834         mLog.info("removeNetwork uid=%").c(callingUid).flush();
2835         return mWifiThreadRunner.call(
2836                 () -> mWifiConfigManager.removeNetwork(internalNetId, callingUid, packageName),
2837                 false);
2838     }
2839 
2840     @Override
removeNonCallerConfiguredNetworks(String packageName)2841     public boolean removeNonCallerConfiguredNetworks(String packageName) {
2842         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2843             throw new SecurityException("Caller does not hold CHANGE_WIFI_STATE permission");
2844         }
2845         final int callingUid = Binder.getCallingUid();
2846         if (!mWifiPermissionsUtil.isDeviceOwner(callingUid, packageName)) {
2847             throw new SecurityException("Caller is not device owner");
2848         }
2849         return mWifiThreadRunner.call(
2850                 () -> mWifiConfigManager.removeNonCallerConfiguredNetwork(callingUid), false);
2851     }
2852 
2853     /**
2854      * Trigger a connect request and wait for the callback to return status.
2855      * This preserves the legacy connect API behavior, i.e. {@link WifiManager#enableNetwork(
2856      * int, true)}
2857      * @return
2858      */
triggerConnectAndReturnStatus(int netId, int callingUid)2859     private boolean triggerConnectAndReturnStatus(int netId, int callingUid) {
2860         final CountDownLatch countDownLatch = new CountDownLatch(1);
2861         final Mutable<Boolean> success = new Mutable<>(false);
2862         IActionListener.Stub connectListener = new IActionListener.Stub() {
2863             @Override
2864             public void onSuccess() {
2865                 success.value = true;
2866                 countDownLatch.countDown();
2867             }
2868             @Override
2869             public void onFailure(int reason) {
2870                 success.value = false;
2871                 countDownLatch.countDown();
2872             }
2873         };
2874         mWifiThreadRunner.post(() ->
2875                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
2876                         mConnectHelper.connectToNetwork(
2877                                 new NetworkUpdateResult(netId),
2878                                 new ActionListenerWrapper(connectListener),
2879                                 callingUid)
2880                 )
2881         );
2882         // now wait for response.
2883         try {
2884             countDownLatch.await(RUN_WITH_SCISSORS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
2885         } catch (InterruptedException e) {
2886             Log.e(TAG, "Failed to retrieve connect status");
2887         }
2888         return success.value;
2889     }
2890 
2891     /**
2892      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
2893      * @param netId the integer that identifies the network configuration
2894      * to the supplicant
2895      * @param disableOthers if true, disable all other networks.
2896      * @return {@code true} if the operation succeeded
2897      */
2898     @Override
enableNetwork(int netId, boolean disableOthers, String packageName)2899     public boolean enableNetwork(int netId, boolean disableOthers, String packageName) {
2900         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2901             return false;
2902         }
2903         if (!isTargetSdkLessThanQOrPrivileged(
2904                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2905             mLog.info("enableNetwork not allowed for uid=%")
2906                     .c(Binder.getCallingUid()).flush();
2907             return false;
2908         }
2909         final int internalNetId = removeSecurityTypeFromNetworkId(netId);
2910         int callingUid = Binder.getCallingUid();
2911         // TODO b/33807876 Log netId
2912         mLog.info("enableNetwork uid=% disableOthers=%")
2913                 .c(callingUid)
2914                 .c(disableOthers).flush();
2915 
2916         mWifiMetrics.incrementNumEnableNetworkCalls();
2917         if (disableOthers) {
2918             return triggerConnectAndReturnStatus(internalNetId, callingUid);
2919         } else {
2920             return mWifiThreadRunner.call(
2921                     () -> mWifiConfigManager.enableNetwork(
2922                             internalNetId, false, callingUid, packageName),
2923                     false);
2924         }
2925     }
2926 
2927     /**
2928      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
2929      * @param netId the integer that identifies the network configuration
2930      * to the supplicant
2931      * @return {@code true} if the operation succeeded
2932      */
2933     @Override
disableNetwork(int netId, String packageName)2934     public boolean disableNetwork(int netId, String packageName) {
2935         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
2936             return false;
2937         }
2938         if (!isTargetSdkLessThanQOrPrivileged(
2939                 packageName, Binder.getCallingPid(), Binder.getCallingUid())) {
2940             mLog.info("disableNetwork not allowed for uid=%")
2941                     .c(Binder.getCallingUid()).flush();
2942             return false;
2943         }
2944         final int internalNetId = removeSecurityTypeFromNetworkId(netId);
2945         int callingUid = Binder.getCallingUid();
2946         mLog.info("disableNetwork uid=%").c(callingUid).flush();
2947         return mWifiThreadRunner.call(
2948                 () -> mWifiConfigManager.disableNetwork(
2949                         internalNetId, callingUid, packageName), false);
2950     }
2951 
2952     /**
2953      * See
2954      * {@link android.net.wifi.WifiManager#startRestrictingAutoJoinToSubscriptionId(int)}
2955      * @param subscriptionId the subscription ID of the carrier whose merged wifi networks won't be
2956      *                       disabled.
2957      */
2958     @Override
2959     @RequiresApi(Build.VERSION_CODES.S)
startRestrictingAutoJoinToSubscriptionId(int subscriptionId)2960     public void startRestrictingAutoJoinToSubscriptionId(int subscriptionId) {
2961         if (!SdkLevel.isAtLeastS()) {
2962             throw new UnsupportedOperationException();
2963         }
2964         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2965             throw new SecurityException(TAG + ": Permission denied");
2966         }
2967 
2968         mLog.info("startRestrictingAutoJoinToSubscriptionId=% uid=%").c(subscriptionId)
2969                 .c(Binder.getCallingUid()).flush();
2970         mWifiThreadRunner.post(() -> {
2971             mWifiConfigManager
2972                     .startRestrictingAutoJoinToSubscriptionId(subscriptionId);
2973             // always disconnect here and rely on auto-join to find the appropriate carrier network
2974             // to join. Even if we are currently connected to the carrier-merged wifi, it's still
2975             // better to disconnect here because it's possible that carrier wifi offload is
2976             // disabled.
2977             mActiveModeWarden.getPrimaryClientModeManager().disconnect();
2978         });
2979     }
2980 
2981     /**
2982      * See {@link android.net.wifi.WifiManager#stopRestrictingAutoJoinToSubscriptionId()}
2983      */
2984     @Override
2985     @RequiresApi(Build.VERSION_CODES.S)
stopRestrictingAutoJoinToSubscriptionId()2986     public void stopRestrictingAutoJoinToSubscriptionId() {
2987         if (!SdkLevel.isAtLeastS()) {
2988             throw new UnsupportedOperationException();
2989         }
2990         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
2991             throw new SecurityException(TAG + ": Permission denied");
2992         }
2993 
2994         mLog.info("stopRestrictingAutoJoinToSubscriptionId uid=%")
2995                 .c(Binder.getCallingUid()).flush();
2996         mWifiThreadRunner.post(() ->
2997                 mWifiConfigManager.stopRestrictingAutoJoinToSubscriptionId());
2998     }
2999 
3000     /**
3001      * See {@link android.net.wifi.WifiManager#allowAutojoinGlobal(boolean)}
3002      * @param choice the OEM's choice to allow auto-join
3003      */
3004     @Override
allowAutojoinGlobal(boolean choice)3005     public void allowAutojoinGlobal(boolean choice) {
3006         enforceNetworkSettingsPermission();
3007 
3008         int callingUid = Binder.getCallingUid();
3009         mLog.info("allowAutojoinGlobal=% uid=%").c(choice).c(callingUid).flush();
3010         mWifiThreadRunner.post(() -> mWifiConnectivityManager.setAutoJoinEnabledExternal(choice));
3011         mLastCallerInfoManager.put(LastCallerInfoManager.AUTOJOIN_GLOBAL, Process.myTid(),
3012                 callingUid, Binder.getCallingPid(), "<unknown>", choice);
3013     }
3014 
3015     /**
3016      * See {@link android.net.wifi.WifiManager#allowAutojoin(int, boolean)}
3017      * @param netId the integer that identifies the network configuration
3018      * @param choice the user's choice to allow auto-join
3019      */
3020     @Override
allowAutojoin(int netId, boolean choice)3021     public void allowAutojoin(int netId, boolean choice) {
3022         enforceNetworkSettingsPermission();
3023 
3024         final int internalNetId = removeSecurityTypeFromNetworkId(netId);
3025         int callingUid = Binder.getCallingUid();
3026         mLog.info("allowAutojoin=% uid=%").c(choice).c(callingUid).flush();
3027         mWifiThreadRunner.post(() -> {
3028             WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(internalNetId);
3029             if (config == null) {
3030                 return;
3031             }
3032             if (config.fromWifiNetworkSpecifier) {
3033                 Log.e(TAG, "Auto-join configuration is not permitted for NetworkSpecifier "
3034                         + "connections: " + config);
3035                 return;
3036             }
3037             if (config.isPasspoint() && !config.isEphemeral()) {
3038                 Log.e(TAG,
3039                         "Auto-join configuration for a non-ephemeral Passpoint network should be "
3040                                 + "configured using FQDN: "
3041                                 + config);
3042                 return;
3043             }
3044             // If the network is a suggestion, store the auto-join configure to the
3045             // WifiNetWorkSuggestionsManager.
3046             if (config.fromWifiNetworkSuggestion) {
3047                 if (!mWifiNetworkSuggestionsManager
3048                         .allowNetworkSuggestionAutojoin(config, choice)) {
3049                     return;
3050                 }
3051             }
3052             // even for Suggestion, modify the current ephemeral configuration so that
3053             // existing configuration auto-connection is updated correctly
3054             if (choice != config.allowAutojoin) {
3055                 mWifiConfigManager.allowAutojoin(internalNetId, choice);
3056                 // do not log this metrics for passpoint networks again here since it's already
3057                 // logged in PasspointManager.
3058                 if (!config.isPasspoint()) {
3059                     mWifiMetrics.logUserActionEvent(choice
3060                             ? UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON
3061                             : UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF, internalNetId);
3062                 }
3063             }
3064         });
3065     }
3066 
3067     /**
3068      * See {@link android.net.wifi.WifiManager#allowAutojoinPasspoint(String, boolean)}
3069      * @param fqdn the FQDN that identifies the passpoint configuration
3070      * @param enableAutojoin true to enable auto-join, false to disable
3071      */
3072     @Override
allowAutojoinPasspoint(String fqdn, boolean enableAutojoin)3073     public void allowAutojoinPasspoint(String fqdn, boolean enableAutojoin) {
3074         enforceNetworkSettingsPermission();
3075         if (fqdn == null) {
3076             throw new IllegalArgumentException("FQDN cannot be null");
3077         }
3078 
3079         int callingUid = Binder.getCallingUid();
3080         mLog.info("allowAutojoinPasspoint=% uid=%").c(enableAutojoin).c(callingUid).flush();
3081         mWifiThreadRunner.post(
3082                 () -> mPasspointManager.enableAutojoin(null, fqdn, enableAutojoin));
3083     }
3084 
3085     /**
3086      * See {@link android.net.wifi.WifiManager
3087      * #setMacRandomizationSettingPasspointEnabled(String, boolean)}
3088      * @param fqdn the FQDN that identifies the passpoint configuration
3089      * @param enable true to enable mac randomization, false to disable
3090      */
3091     @Override
setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable)3092     public void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable) {
3093         enforceNetworkSettingsPermission();
3094         if (fqdn == null) {
3095             throw new IllegalArgumentException("FQDN cannot be null");
3096         }
3097 
3098         int callingUid = Binder.getCallingUid();
3099         mLog.info("setMacRandomizationSettingPasspointEnabled=% uid=%")
3100                 .c(enable).c(callingUid).flush();
3101         mWifiThreadRunner.post(
3102                 () -> mPasspointManager.enableMacRandomization(fqdn, enable));
3103     }
3104 
3105     /**
3106      * See {@link android.net.wifi.WifiManager#setPasspointMeteredOverride(String, boolean)}
3107      * @param fqdn the FQDN that identifies the passpoint configuration
3108      * @param meteredOverride One of the values in {@link MeteredOverride}
3109      */
3110     @Override
setPasspointMeteredOverride(String fqdn, int meteredOverride)3111     public void setPasspointMeteredOverride(String fqdn, int meteredOverride) {
3112         enforceNetworkSettingsPermission();
3113         if (fqdn == null) {
3114             throw new IllegalArgumentException("FQDN cannot be null");
3115         }
3116 
3117         int callingUid = Binder.getCallingUid();
3118         mLog.info("setPasspointMeteredOverride=% uid=%")
3119                 .c(meteredOverride).c(callingUid).flush();
3120         mWifiThreadRunner.post(
3121                 () -> mPasspointManager.setMeteredOverride(fqdn, meteredOverride));
3122     }
3123 
3124     /**
3125      * Provides backward compatibility for apps using
3126      * {@link WifiManager#getConnectionInfo()}, {@link WifiManager#getDhcpInfo()} when a
3127      * secondary STA is created as a result of a request from their app (peer to peer
3128      * WifiNetworkSpecifier request or oem paid/private suggestion).
3129      */
getClientModeManagerIfSecondaryCmmRequestedByCallerPresent( int callingUid, @NonNull String callingPackageName)3130     private ClientModeManager getClientModeManagerIfSecondaryCmmRequestedByCallerPresent(
3131             int callingUid, @NonNull String callingPackageName) {
3132         List<ConcreteClientModeManager> secondaryCmms =
3133                 mActiveModeWarden.getClientModeManagersInRoles(
3134                         ROLE_CLIENT_LOCAL_ONLY, ROLE_CLIENT_SECONDARY_LONG_LIVED);
3135         for (ConcreteClientModeManager cmm : secondaryCmms) {
3136             WorkSource reqWs = cmm.getRequestorWs();
3137             // If there are more than 1 secondary CMM for same app, return any one (should not
3138             // happen currently since we don't support 3 STA's concurrently).
3139             if (reqWs.equals(new WorkSource(callingUid, callingPackageName))) {
3140                 mLog.info("getConnectionInfo providing secondary CMM info").flush();
3141                 return cmm;
3142             }
3143         }
3144         // No secondary CMM's created for the app, return primary CMM.
3145         return mActiveModeWarden.getPrimaryClientModeManager();
3146     }
3147 
3148     /**
3149      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
3150      * @return the Wi-Fi information, contained in {@link WifiInfo}.
3151      */
3152     @Override
getConnectionInfo(String callingPackage, String callingFeatureId)3153     public WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId) {
3154         enforceAccessPermission();
3155         int uid = Binder.getCallingUid();
3156         if (isVerboseLoggingEnabled()) {
3157             mLog.info("getConnectionInfo uid=%").c(uid).flush();
3158         }
3159         long ident = Binder.clearCallingIdentity();
3160         try {
3161             WifiInfo wifiInfo = mWifiThreadRunner.call(
3162                     () -> getClientModeManagerIfSecondaryCmmRequestedByCallerPresent(
3163                             uid, callingPackage)
3164                             .syncRequestConnectionInfo(), new WifiInfo());
3165             long redactions = wifiInfo.getApplicableRedactions();
3166             if (mWifiPermissionsUtil.checkLocalMacAddressPermission(uid)) {
3167                 if (isVerboseLoggingEnabled()) {
3168                     Log.v(TAG, "Clearing REDACT_FOR_LOCAL_MAC_ADDRESS for " + callingPackage
3169                             + "(uid=" + uid + ")");
3170                 }
3171                 redactions &= ~NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
3172             }
3173             if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
3174                 if (isVerboseLoggingEnabled()) {
3175                     Log.v(TAG, "Clearing REDACT_FOR_NETWORK_SETTINGS for " + callingPackage
3176                             + "(uid=" + uid + ")");
3177                 }
3178                 redactions &= ~NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
3179             }
3180             try {
3181                 if (isVerboseLoggingEnabled()) {
3182                     Log.v(TAG, "Clearing REDACT_FOR_ACCESS_FINE_LOCATION for " + callingPackage
3183                             + "(uid=" + uid + ")");
3184                 }
3185                 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
3186                         uid, null);
3187                 redactions &= ~NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
3188             } catch (SecurityException ignored) {
3189                 if (isVerboseLoggingEnabled()) {
3190                     Log.v(TAG, "Keeping REDACT_FOR_ACCESS_FINE_LOCATION:" + ignored);
3191                 }
3192             }
3193             WifiInfo wifiInfoCopy = wifiInfo.makeCopy(redactions);
3194             wifiInfoCopy.setNetworkId(addSecurityTypeToNetworkId(wifiInfoCopy.getNetworkId(),
3195                     convertWifiInfoSecurityTypeToWifiConfiguration(
3196                             wifiInfoCopy.getCurrentSecurityType())));
3197             return wifiInfoCopy;
3198         } finally {
3199             Binder.restoreCallingIdentity(ident);
3200         }
3201     }
3202 
3203     /**
3204      * Return the results of the most recent access point scan, in the form of
3205      * a list of {@link ScanResult} objects.
3206      * @return the list of results
3207      */
3208     @Override
getScanResults(String callingPackage, String callingFeatureId)3209     public List<ScanResult> getScanResults(String callingPackage, String callingFeatureId) {
3210         enforceAccessPermission();
3211         int uid = Binder.getCallingUid();
3212         long ident = Binder.clearCallingIdentity();
3213         if (isVerboseLoggingEnabled()) {
3214             mLog.info("getScanResults uid=%").c(uid).flush();
3215         }
3216         try {
3217             mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
3218                     uid, null);
3219             List<ScanResult> scanResults = mWifiThreadRunner.call(
3220                     mScanRequestProxy::getScanResults, Collections.emptyList());
3221             return scanResults;
3222         } catch (SecurityException e) {
3223             Log.w(TAG, "Permission violation - getScanResults not allowed for uid="
3224                     + uid + ", packageName=" + callingPackage + ", reason=" + e);
3225             return new ArrayList<>();
3226         } finally {
3227             Binder.restoreCallingIdentity(ident);
3228         }
3229     }
3230 
3231     /**
3232      * Return the filtered ScanResults which may be authenticated by the suggested network
3233      * configurations.
3234      * @return The map of {@link WifiNetworkSuggestion} and the list of {@link ScanResult} which
3235      * may be authenticated by the corresponding network configuration.
3236      */
3237     @Override
3238     @NonNull
getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestions, @Nullable List<ScanResult> scanResults, String callingPackage, String callingFeatureId)3239     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
3240             @NonNull List<WifiNetworkSuggestion> networkSuggestions,
3241             @Nullable List<ScanResult> scanResults,
3242             String callingPackage, String callingFeatureId) {
3243         enforceAccessPermission();
3244         int uid = Binder.getCallingUid();
3245         long ident = Binder.clearCallingIdentity();
3246         try {
3247             mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
3248                     uid, null);
3249 
3250             return mWifiThreadRunner.call(
3251                     () -> {
3252                         if (!ScanResultUtil.validateScanResultList(scanResults)) {
3253                             return mWifiNetworkSuggestionsManager.getMatchingScanResults(
3254                                     networkSuggestions, mScanRequestProxy.getScanResults());
3255                         } else {
3256                             return mWifiNetworkSuggestionsManager.getMatchingScanResults(
3257                                     networkSuggestions, scanResults);
3258                         }
3259                     },
3260                     Collections.emptyMap());
3261         } catch (SecurityException e) {
3262             Log.w(TAG, "Permission violation - getMatchingScanResults not allowed for uid="
3263                     + uid + ", packageName=" + callingPackage + ", reason + e");
3264         } finally {
3265             Binder.restoreCallingIdentity(ident);
3266         }
3267 
3268         return Collections.emptyMap();
3269     }
3270 
3271     /**
3272      * Add or update a Passpoint configuration.
3273      *
3274      * @param config The Passpoint configuration to be added
3275      * @return true on success or false on failure
3276      */
3277     @Override
3278     public boolean addOrUpdatePasspointConfiguration(
3279             PasspointConfiguration config, String packageName) {
3280         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
3281             return false;
3282         }
3283         int callingUid = Binder.getCallingUid();
3284         if (!isTargetSdkLessThanROrPrivileged(
3285                 packageName, Binder.getCallingPid(), callingUid)) {
3286             mLog.info("addOrUpdatePasspointConfiguration not allowed for uid=%")
3287                     .c(Binder.getCallingUid()).flush();
3288             return false;
3289         }
3290         mLog.info("addorUpdatePasspointConfiguration uid=%").c(callingUid).flush();
3291         return mWifiThreadRunner.call(
3292                 () -> mPasspointManager.addOrUpdateProvider(config, callingUid, packageName,
3293                         false, true), false);
3294     }
3295 
3296     /**
3297      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
3298      *
3299      * @param fqdn The FQDN of the Passpoint configuration to be removed
3300      * @return true on success or false on failure
3301      */
3302     @Override
3303     public boolean removePasspointConfiguration(String fqdn, String packageName) {
3304         return removePasspointConfigurationInternal(fqdn, null);
3305     }
3306 
3307     /**
3308      * Remove a Passpoint profile based on either FQDN (multiple matching profiles) or a unique
3309      * identifier (one matching profile).
3310      *
3311      * @param fqdn The FQDN of the Passpoint configuration to be removed
3312      * @param uniqueId The unique identifier of the Passpoint configuration to be removed
3313      * @return true on success or false on failure
3314      */
3315     private boolean removePasspointConfigurationInternal(String fqdn, String uniqueId) {
3316         final int uid = Binder.getCallingUid();
3317         boolean privileged = false;
3318         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
3319                 || mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(uid)) {
3320             privileged = true;
3321         }
3322         mLog.info("removePasspointConfigurationInternal uid=%").c(Binder.getCallingUid()).flush();
3323         final boolean privilegedFinal = privileged;
3324         return mWifiThreadRunner.call(
3325                 () -> mPasspointManager.removeProvider(uid, privilegedFinal, uniqueId, fqdn),
3326                 false);
3327     }
3328 
3329     /**
3330      * Return the list of the installed Passpoint configurations.
3331      *
3332      * An empty list will be returned when no configuration is installed.
3333      * @param packageName String name of the calling package
3334      * @return A list of {@link PasspointConfiguration}.
3335      */
3336     @Override
3337     public List<PasspointConfiguration> getPasspointConfigurations(String packageName) {
3338         final int uid = Binder.getCallingUid();
3339         boolean privileged = false;
3340         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
3341                 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
3342             privileged = true;
3343         }
3344         if (isVerboseLoggingEnabled()) {
3345             mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
3346         }
3347         final boolean privilegedFinal = privileged;
3348         return mWifiThreadRunner.call(
3349             () -> mPasspointManager.getProviderConfigs(uid, privilegedFinal),
3350             Collections.emptyList());
3351     }
3352 
3353     /**
3354      * Query for a Hotspot 2.0 release 2 OSU icon
3355      * @param bssid The BSSID of the AP
3356      * @param fileName Icon file name
3357      */
3358     @Override
3359     public void queryPasspointIcon(long bssid, String fileName) {
3360         enforceAccessPermission();
3361         mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
3362         mWifiThreadRunner.post(() -> {
3363             mActiveModeWarden.getPrimaryClientModeManager().syncQueryPasspointIcon(bssid, fileName);
3364         });
3365     }
3366 
3367     /**
3368      * Match the currently associated network against the SP matching the given FQDN
3369      * @param fqdn FQDN of the SP
3370      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
3371      */
3372     @Override
3373     public int matchProviderWithCurrentNetwork(String fqdn) {
3374         mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
3375         return 0;
3376     }
3377 
3378      /**
3379      * Get the country code
3380      * @return Get the best choice country code for wifi, regardless of if it was set or
3381      * not.
3382      * Returns null when there is no country code available.
3383      */
3384     @Override
3385     public String getCountryCode() {
3386         enforceNetworkSettingsPermission();
3387         if (isVerboseLoggingEnabled()) {
3388             mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
3389         }
3390         return mCountryCode.getCountryCode();
3391     }
3392 
3393     /**
3394      * Set the Wifi country code. This call will override the country code set by telephony.
3395      * @param countryCode A 2-Character alphanumeric country code.
3396      *
3397      */
3398     @RequiresApi(Build.VERSION_CODES.S)
3399     @Override
3400     public void setOverrideCountryCode(@NonNull String countryCode) {
3401         if (!SdkLevel.isAtLeastS()) {
3402             throw new UnsupportedOperationException();
3403         }
3404         mContext.enforceCallingOrSelfPermission(
3405                 Manifest.permission.MANAGE_WIFI_COUNTRY_CODE, "WifiService");
3406         if (!WifiCountryCode.isValid(countryCode)) {
3407             throw new IllegalArgumentException("Country code must be a 2-Character alphanumeric"
3408                     + " code. But got countryCode " + countryCode
3409                     + " instead");
3410         }
3411         if (isVerboseLoggingEnabled()) {
3412             mLog.info("setOverrideCountryCode uid=% countryCode=%")
3413                     .c(Binder.getCallingUid()).c(countryCode).flush();
3414         }
3415         // Post operation to handler thread
3416         mWifiThreadRunner.post(() -> mCountryCode.setOverrideCountryCode(countryCode));
3417     }
3418 
3419     /**
3420      * Clear the country code previously set through setOverrideCountryCode method.
3421      *
3422      */
3423     @RequiresApi(Build.VERSION_CODES.S)
3424     @Override
3425     public void clearOverrideCountryCode() {
3426         if (!SdkLevel.isAtLeastS()) {
3427             throw new UnsupportedOperationException();
3428         }
3429         mContext.enforceCallingOrSelfPermission(
3430                 Manifest.permission.MANAGE_WIFI_COUNTRY_CODE, "WifiService");
3431         if (isVerboseLoggingEnabled()) {
3432             mLog.info("clearCountryCode uid=%").c(Binder.getCallingUid()).flush();
3433         }
3434         // Post operation to handler thread
3435         mWifiThreadRunner.post(() -> mCountryCode.clearOverrideCountryCode());
3436     }
3437 
3438     /**
3439      * Change the default country code previously set from ro.boot.wificountrycode.
3440      * @param countryCode A 2-Character alphanumeric country code.
3441      *
3442      */
3443     @RequiresApi(Build.VERSION_CODES.S)
3444     @Override
3445     public void setDefaultCountryCode(@NonNull String countryCode) {
3446         if (!SdkLevel.isAtLeastS()) {
3447             throw new UnsupportedOperationException();
3448         }
3449         mContext.enforceCallingOrSelfPermission(
3450                 Manifest.permission.MANAGE_WIFI_COUNTRY_CODE, "WifiService");
3451         if (!WifiCountryCode.isValid(countryCode)) {
3452             throw new IllegalArgumentException("Country code must be a 2-Character alphanumeric"
3453                     + " code. But got countryCode " + countryCode
3454                     + " instead");
3455         }
3456         if (isVerboseLoggingEnabled()) {
3457             mLog.info("setDefaultCountryCode uid=% countryCode=%")
3458                     .c(Binder.getCallingUid()).c(countryCode).flush();
3459         }
3460         // Post operation to handler thread
3461         mWifiThreadRunner.post(() -> mCountryCode.setDefaultCountryCode(countryCode));
3462     }
3463 
3464     @Override
3465     public boolean is24GHzBandSupported() {
3466         if (isVerboseLoggingEnabled()) {
3467             mLog.info("is24GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
3468         }
3469 
3470         return is24GhzBandSupportedInternal();
3471     }
3472 
3473     private boolean is24GhzBandSupportedInternal() {
3474         if (mContext.getResources().getBoolean(R.bool.config_wifi24ghzSupport)) {
3475             return true;
3476         }
3477         return mWifiThreadRunner.call(
3478                 () -> mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ).length > 0,
3479                 false);
3480     }
3481 
3482 
3483     @Override
3484     public boolean is5GHzBandSupported() {
3485         if (isVerboseLoggingEnabled()) {
3486             mLog.info("is5GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
3487         }
3488 
3489         return is5GhzBandSupportedInternal();
3490     }
3491 
3492     private boolean is5GhzBandSupportedInternal() {
3493         if (mContext.getResources().getBoolean(R.bool.config_wifi5ghzSupport)) {
3494             return true;
3495         }
3496         return mWifiThreadRunner.call(
3497                 () -> mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ).length > 0,
3498                 false);
3499     }
3500 
3501     @Override
3502     public boolean is6GHzBandSupported() {
3503         if (isVerboseLoggingEnabled()) {
3504             mLog.info("is6GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
3505         }
3506 
3507         return is6GhzBandSupportedInternal();
3508     }
3509 
3510     private boolean is6GhzBandSupportedInternal() {
3511         if (mContext.getResources().getBoolean(R.bool.config_wifi6ghzSupport)) {
3512             return true;
3513         }
3514         return mWifiThreadRunner.call(
3515                 () -> mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_6_GHZ).length > 0,
3516                 false);
3517     }
3518 
3519     @Override
3520     public boolean is60GHzBandSupported() {
3521         if (!SdkLevel.isAtLeastS()) {
3522             throw new UnsupportedOperationException();
3523         }
3524 
3525         if (isVerboseLoggingEnabled()) {
3526             mLog.info("is60GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
3527         }
3528 
3529         return is60GhzBandSupportedInternal();
3530     }
3531 
3532     private boolean is60GhzBandSupportedInternal() {
3533         if (mContext.getResources().getBoolean(R.bool.config_wifi60ghzSupport)) {
3534             return true;
3535         }
3536         return mWifiThreadRunner.call(
3537                 () -> mWifiNative.getChannelsForBand(WifiScanner.WIFI_BAND_60_GHZ).length > 0,
3538                 false);
3539     }
3540 
3541     @Override
3542     public boolean isWifiStandardSupported(@WifiStandard int standard) {
3543         return mWifiThreadRunner.call(
3544                 () -> mActiveModeWarden.getPrimaryClientModeManager().isWifiStandardSupported(
3545                         standard), false);
3546     }
3547 
3548     /**
3549      * Return the DHCP-assigned addresses from the last successful DHCP request,
3550      * if any.
3551      * @return the DHCP information
3552      * @deprecated
3553      */
3554     @Override
3555     public DhcpInfo getDhcpInfo(@NonNull String packageName) {
3556         enforceAccessPermission();
3557         int callingUid = Binder.getCallingUid();
3558         if (isVerboseLoggingEnabled()) {
3559             mLog.info("getDhcpInfo uid=%").c(callingUid).flush();
3560         }
3561         DhcpResultsParcelable dhcpResults = mWifiThreadRunner.call(
3562                 () -> getClientModeManagerIfSecondaryCmmRequestedByCallerPresent(
3563                         callingUid, packageName)
3564                         .syncGetDhcpResultsParcelable(), new DhcpResultsParcelable());
3565 
3566         DhcpInfo info = new DhcpInfo();
3567 
3568         if (dhcpResults.baseConfiguration != null) {
3569             if (dhcpResults.baseConfiguration.getIpAddress() != null
3570                     && dhcpResults.baseConfiguration.getIpAddress().getAddress()
3571                     instanceof Inet4Address) {
3572                 info.ipAddress = Inet4AddressUtils.inet4AddressToIntHTL(
3573                         (Inet4Address) dhcpResults.baseConfiguration.getIpAddress().getAddress());
3574             }
3575 
3576             if (dhcpResults.baseConfiguration.getGateway() != null) {
3577                 info.gateway = Inet4AddressUtils.inet4AddressToIntHTL(
3578                         (Inet4Address) dhcpResults.baseConfiguration.getGateway());
3579             }
3580 
3581             int dnsFound = 0;
3582             for (InetAddress dns : dhcpResults.baseConfiguration.getDnsServers()) {
3583                 if (dns instanceof Inet4Address) {
3584                     if (dnsFound == 0) {
3585                         info.dns1 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns);
3586                     } else {
3587                         info.dns2 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns);
3588                     }
3589                     if (++dnsFound > 1) break;
3590                 }
3591             }
3592         }
3593         String serverAddress = dhcpResults.serverAddress;
3594         if (serverAddress != null) {
3595             InetAddress serverInetAddress = InetAddresses.parseNumericAddress(serverAddress);
3596             info.serverAddress =
3597                     Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) serverInetAddress);
3598         }
3599         info.leaseDuration = dhcpResults.leaseDuration;
3600 
3601         return info;
3602     }
3603 
3604     /**
3605      * enable TDLS for the local NIC to remote NIC
3606      * The APPs don't know the remote MAC address to identify NIC though,
3607      * so we need to do additional work to find it from remote IP address
3608      */
3609 
3610     private static class TdlsTaskParams {
3611         String mRemoteIpAddress;
3612         boolean mEnable;
3613     }
3614 
3615     private class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
3616         @Override
3617         protected Integer doInBackground(TdlsTaskParams... params) {
3618 
3619             // Retrieve parameters for the call
3620             TdlsTaskParams param = params[0];
3621             String remoteIpAddress = param.mRemoteIpAddress.trim();
3622             boolean enable = param.mEnable;
3623 
3624             // Get MAC address of Remote IP
3625             String macAddress = null;
3626 
3627             try (BufferedReader reader = new BufferedReader(new FileReader("/proc/net/arp"))) {
3628                 // Skip over the line bearing column titles
3629                 reader.readLine();
3630 
3631                 String line;
3632                 while ((line = reader.readLine()) != null) {
3633                     String[] tokens = line.split("[ ]+");
3634                     if (tokens.length < 6) {
3635                         continue;
3636                     }
3637 
3638                     // ARP column format is
3639                     // Address HWType HWAddress Flags Mask IFace
3640                     String ip = tokens[0];
3641                     String mac = tokens[3];
3642 
3643                     if (remoteIpAddress.equals(ip)) {
3644                         macAddress = mac;
3645                         break;
3646                     }
3647                 }
3648 
3649                 if (macAddress == null) {
3650                     Log.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in "
3651                             + "/proc/net/arp");
3652                 } else {
3653                     enableTdlsWithMacAddress(macAddress, enable);
3654                 }
3655 
3656             } catch (FileNotFoundException e) {
3657                 Log.e(TAG, "Could not open /proc/net/arp to lookup mac address");
3658             } catch (IOException e) {
3659                 Log.e(TAG, "Could not read /proc/net/arp to lookup mac address");
3660             }
3661             return 0;
3662         }
3663     }
3664 
3665     @Override
3666     public void enableTdls(String remoteAddress, boolean enable) {
3667         if (remoteAddress == null) {
3668           throw new IllegalArgumentException("remoteAddress cannot be null");
3669         }
3670         mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
3671         TdlsTaskParams params = new TdlsTaskParams();
3672         params.mRemoteIpAddress = remoteAddress;
3673         params.mEnable = enable;
3674         new TdlsTask().execute(params);
3675     }
3676 
3677 
3678     @Override
3679     public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
3680         mLog.info("enableTdlsWithMacAddress uid=% enable=%")
3681                 .c(Binder.getCallingUid())
3682                 .c(enable)
3683                 .flush();
3684         if (remoteMacAddress == null) {
3685           throw new IllegalArgumentException("remoteMacAddress cannot be null");
3686         }
3687         mWifiThreadRunner.post(() ->
3688                 mActiveModeWarden.getPrimaryClientModeManager().enableTdls(
3689                         remoteMacAddress, enable));
3690     }
3691 
3692     /**
3693      * Temporarily disable a network, should be trigger when user disconnect a network
3694      */
3695     @Override
3696     public void disableEphemeralNetwork(String network, String packageName) {
3697         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
3698                 "WifiService");
3699         if (!isPrivileged(Binder.getCallingPid(), Binder.getCallingUid())) {
3700             mLog.info("disableEphemeralNetwork not allowed for uid=%")
3701                     .c(Binder.getCallingUid()).flush();
3702             return;
3703         }
3704         mLog.info("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
3705         mWifiThreadRunner.post(() -> mWifiConfigManager.userTemporarilyDisabledNetwork(network,
3706                 Binder.getCallingUid()));
3707     }
3708 
3709     private void removeAppStateInternal(int uid, @NonNull String pkgName) {
3710         ApplicationInfo ai = new ApplicationInfo();
3711         ai.packageName = pkgName;
3712         ai.uid = uid;
3713         mWifiConfigManager.removeNetworksForApp(ai);
3714         mScanRequestProxy.clearScanRequestTimestampsForApp(pkgName, uid);
3715 
3716         // Remove all suggestions from the package.
3717         mWifiNetworkSuggestionsManager.removeApp(pkgName);
3718         mWifiInjector.getWifiNetworkFactory().removeUserApprovedAccessPointsForApp(
3719                 pkgName);
3720 
3721         // Remove all Passpoint profiles from package.
3722         mWifiInjector.getPasspointManager().removePasspointProviderWithPackage(
3723                 pkgName);
3724     }
3725 
3726     private void registerForBroadcasts() {
3727         IntentFilter intentFilter = new IntentFilter();
3728         intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
3729         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
3730         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
3731         intentFilter.addDataScheme("package");
3732         mContext.registerReceiver(new BroadcastReceiver() {
3733             @Override
3734             public void onReceive(Context context, Intent intent) {
3735                 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
3736                 Uri uri = intent.getData();
3737                 if (uid == -1 || uri == null) {
3738                     Log.e(TAG, "Uid or Uri is missing for action:" + intent.getAction());
3739                     return;
3740                 }
3741                 String pkgName = uri.getSchemeSpecificPart();
3742                 PackageManager pm = context.getPackageManager();
3743                 PackageInfo packageInfo = null;
3744                 try {
3745                     packageInfo = pm.getPackageInfo(pkgName, 0);
3746                 } catch (PackageManager.NameNotFoundException e) {
3747                     Log.w(TAG, "Couldn't get PackageInfo for package:" + pkgName);
3748                 }
3749                 // If package is not removed or disabled, just ignore.
3750                 if (packageInfo != null
3751                         && packageInfo.applicationInfo != null
3752                         && packageInfo.applicationInfo.enabled) {
3753                     return;
3754                 }
3755                 Log.d(TAG, "Remove settings for package:" + pkgName);
3756                 // Call the method in the main Wifi thread.
3757                 mWifiThreadRunner.post(() -> {
3758                     removeAppStateInternal(uid, pkgName);
3759                 });
3760             }
3761         }, intentFilter);
3762     }
3763 
3764     private void registerForCarrierConfigChange() {
3765         IntentFilter filter = new IntentFilter();
3766         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
3767         mContext.registerReceiver(new BroadcastReceiver() {
3768             @Override
3769             public void onReceive(Context context, Intent intent) {
3770                 final int subId = SubscriptionManager.getActiveDataSubscriptionId();
3771                 // post operation to handler thread
3772                 mWifiThreadRunner.post(() -> {
3773                     Log.d(TAG, "ACTION_CARRIER_CONFIG_CHANGED, active subId: " + subId);
3774                     mTetheredSoftApTracker.updateSoftApCapabilityWhenCarrierConfigChanged(subId);
3775                     mActiveModeWarden.updateSoftApCapability(
3776                             mTetheredSoftApTracker.getSoftApCapability());
3777                 });
3778             }
3779         }, filter);
3780 
3781         WifiPhoneStateListener phoneStateListener = new WifiPhoneStateListener(
3782                 mWifiInjector.getWifiHandlerThread().getLooper());
3783 
3784         mContext.getSystemService(TelephonyManager.class).listen(
3785                 phoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
3786     }
3787 
3788     @Override
3789     public int handleShellCommand(@NonNull ParcelFileDescriptor in,
3790             @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
3791             @NonNull String[] args) {
3792         WifiShellCommand shellCommand =  new WifiShellCommand(mWifiInjector, this, mContext,
3793                 mWifiGlobals, mWifiThreadRunner);
3794         return shellCommand.exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
3795                 err.getFileDescriptor(), args);
3796     }
3797 
3798     private void updateWifiMetrics() {
3799         mWifiThreadRunner.run(() -> {
3800             mWifiMetrics.updateSavedNetworks(
3801                     mWifiConfigManager.getSavedNetworks(Process.WIFI_UID));
3802             mActiveModeWarden.updateMetrics();
3803             mPasspointManager.updateMetrics();
3804         });
3805         boolean isEnhancedMacRandEnabled = mFrameworkFacade.getIntegerSetting(mContext,
3806                 WifiConfigManager.ENHANCED_MAC_RANDOMIZATION_FEATURE_FORCE_ENABLE_FLAG, 0) == 1
3807                 ? true : false;
3808         mWifiMetrics.setEnhancedMacRandomizationForceEnabled(isEnhancedMacRandEnabled);
3809         mWifiMetrics.setIsScanningAlwaysEnabled(
3810                 mSettingsStore.isScanAlwaysAvailableToggleEnabled());
3811         mWifiMetrics.setVerboseLoggingEnabled(isVerboseLoggingEnabled());
3812         mWifiMetrics.setWifiWakeEnabled(mWifiInjector.getWakeupController().isEnabled());
3813     }
3814 
3815     @Override
3816     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
3817         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
3818                 != PERMISSION_GRANTED) {
3819             pw.println("Permission Denial: can't dump WifiService from from pid="
3820                     + Binder.getCallingPid()
3821                     + ", uid=" + Binder.getCallingUid());
3822             return;
3823         }
3824         if (args != null && args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
3825             // WifiMetrics proto bytes were requested. Dump only these.
3826             updateWifiMetrics();
3827             mWifiMetrics.dump(fd, pw, args);
3828         } else if (args != null && args.length > 0 && IpClientUtil.DUMP_ARG.equals(args[0])) {
3829             // IpClient dump was requested. Pass it along and take no further action.
3830             String[] ipClientArgs = new String[args.length - 1];
3831             System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length);
3832             mActiveModeWarden.getPrimaryClientModeManager().dumpIpClient(fd, pw, ipClientArgs);
3833         } else if (args != null && args.length > 0 && WifiScoreReport.DUMP_ARG.equals(args[0])) {
3834             mActiveModeWarden.getPrimaryClientModeManager().dumpWifiScoreReport(fd, pw, args);
3835         } else if (args != null && args.length > 0 && WifiScoreCard.DUMP_ARG.equals(args[0])) {
3836             WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
3837             String networkListBase64 = mWifiThreadRunner.call(() ->
3838                     wifiScoreCard.getNetworkListBase64(true), "");
3839             pw.println(networkListBase64);
3840         } else {
3841             pw.println("Verbose logging is " + (isVerboseLoggingEnabled() ? "on" : "off"));
3842             pw.println("Stay-awake conditions: " +
3843                     mFacade.getIntegerSetting(mContext,
3844                             Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
3845             pw.println("mInIdleMode " + mInIdleMode);
3846             pw.println("mScanPending " + mScanPending);
3847             pw.println("SettingsStore:");
3848             mSettingsStore.dump(fd, pw, args);
3849             mActiveModeWarden.dump(fd, pw, args);
3850             mMakeBeforeBreakManager.dump(fd, pw, args);
3851             pw.println();
3852             mWifiTrafficPoller.dump(fd, pw, args);
3853             pw.println();
3854             pw.println("Locks held:");
3855             mWifiLockManager.dump(pw);
3856             pw.println();
3857             mWifiMulticastLockManager.dump(pw);
3858             pw.println();
3859             WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
3860             String networkListBase64 = mWifiThreadRunner.call(() ->
3861                     wifiScoreCard.getNetworkListBase64(true), "");
3862             pw.println("WifiScoreCard:");
3863             pw.println(networkListBase64);
3864 
3865             updateWifiMetrics();
3866             mWifiMetrics.dump(fd, pw, args);
3867 
3868             pw.println();
3869             mWifiThreadRunner.run(() -> mWifiNetworkSuggestionsManager.dump(fd, pw, args));
3870             pw.println();
3871             mWifiBackupRestore.dump(fd, pw, args);
3872             pw.println();
3873             pw.println("ScoringParams: " + mWifiInjector.getScoringParams());
3874             pw.println();
3875             mWifiThreadRunner.run(() -> {
3876                 mWifiInjector.getWifiNetworkScoreCache().dumpWithLatestScanResults(
3877                         fd, pw, args, mScanRequestProxy.getScanResults());
3878                 mWifiInjector.getSettingsConfigStore().dump(fd, pw, args);
3879             });
3880             pw.println();
3881             mCountryCode.dump(fd, pw, args);
3882             mWifiInjector.getWifiNetworkFactory().dump(fd, pw, args);
3883             mWifiInjector.getUntrustedWifiNetworkFactory().dump(fd, pw, args);
3884             mWifiInjector.getOemWifiNetworkFactory().dump(fd, pw, args);
3885             pw.println("Wlan Wake Reasons:" + mWifiNative.getWlanWakeReasonCount());
3886             pw.println();
3887             mWifiConfigManager.dump(fd, pw, args);
3888             pw.println();
3889             mPasspointManager.dump(pw);
3890             pw.println();
3891             mWifiInjector.getWifiDiagnostics().captureBugReportData(
3892                     WifiDiagnostics.REPORT_REASON_USER_ACTION);
3893             mWifiInjector.getWifiDiagnostics().dump(fd, pw, args);
3894             mWifiConnectivityManager.dump(fd, pw, args);
3895             mWifiThreadRunner.run(() -> {
3896                 mWifiHealthMonitor.dump(fd, pw, args);
3897             });
3898             mWifiThreadRunner.run(() -> {
3899                 mWifiScoreCard.dump(fd, pw, args);
3900             });
3901             mWifiInjector.getWakeupController().dump(fd, pw, args);
3902             mWifiInjector.getWifiLastResortWatchdog().dump(fd, pw, args);
3903             mWifiInjector.getAdaptiveConnectivityEnabledSettingObserver().dump(fd, pw, args);
3904             mWifiInjector.getWifiGlobals().dump(fd, pw, args);
3905             mWifiInjector.getSarManager().dump(fd, pw, args);
3906             pw.println();
3907             mLastCallerInfoManager.dump(pw);
3908             pw.println();
3909             mWifiInjector.getLinkProbeManager().dump(fd, pw, args);
3910         }
3911     }
3912 
3913     @Override
3914     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
3915         mLog.info("acquireWifiLock uid=% lockMode=%")
3916                 .c(Binder.getCallingUid())
3917                 .c(lockMode).flush();
3918 
3919         // Check on permission to make this call
3920         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
3921 
3922         // If no UID is provided in worksource, use the calling UID
3923         WorkSource updatedWs = (ws == null || ws.isEmpty())
3924                 ? new WorkSource(Binder.getCallingUid()) : ws;
3925 
3926         if (!WifiLockManager.isValidLockMode(lockMode)) {
3927             throw new IllegalArgumentException("lockMode =" + lockMode);
3928         }
3929 
3930         return mWifiThreadRunner.call(() ->
3931                 mWifiLockManager.acquireWifiLock(lockMode, tag, binder, updatedWs), false);
3932     }
3933 
3934     @Override
3935     public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
3936         mLog.info("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
3937 
3938         // Check on permission to make this call
3939         mContext.enforceCallingOrSelfPermission(
3940                 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
3941 
3942         // If no UID is provided in worksource, use the calling UID
3943         WorkSource updatedWs = (ws == null || ws.isEmpty())
3944                 ? new WorkSource(Binder.getCallingUid()) : ws;
3945 
3946         mWifiThreadRunner.run(() ->
3947                 mWifiLockManager.updateWifiLockWorkSource(binder, updatedWs));
3948     }
3949 
3950     @Override
3951     public boolean releaseWifiLock(IBinder binder) {
3952         mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
3953 
3954         // Check on permission to make this call
3955         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
3956 
3957         return mWifiThreadRunner.call(() ->
3958                 mWifiLockManager.releaseWifiLock(binder), false);
3959     }
3960 
3961     @Override
3962     public void initializeMulticastFiltering() {
3963         enforceMulticastChangePermission();
3964         mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
3965         mWifiMulticastLockManager.initializeFiltering();
3966     }
3967 
3968     @Override
3969     public void acquireMulticastLock(IBinder binder, String tag) {
3970         enforceMulticastChangePermission();
3971         mLog.info("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
3972         mWifiMulticastLockManager.acquireLock(binder, tag);
3973     }
3974 
3975     @Override
3976     public void releaseMulticastLock(String tag) {
3977         enforceMulticastChangePermission();
3978         mLog.info("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
3979         mWifiMulticastLockManager.releaseLock(tag);
3980     }
3981 
3982     @Override
3983     public boolean isMulticastEnabled() {
3984         enforceAccessPermission();
3985         if (isVerboseLoggingEnabled()) {
3986             mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
3987         }
3988         return mWifiMulticastLockManager.isMulticastEnabled();
3989     }
3990 
3991     @Override
3992     public void enableVerboseLogging(int verbose) {
3993         enforceAccessPermission();
3994         enforceNetworkSettingsPermission();
3995         mLog.info("enableVerboseLogging uid=% verbose=%")
3996                 .c(Binder.getCallingUid())
3997                 .c(verbose).flush();
3998         boolean enabled = verbose > 0;
3999         mWifiInjector.getSettingsConfigStore().put(WIFI_VERBOSE_LOGGING_ENABLED, enabled);
4000         onVerboseLoggingStatusChanged(enabled);
4001         enableVerboseLoggingInternal(verbose);
4002     }
4003 
4004     private void onVerboseLoggingStatusChanged(boolean enabled) {
4005         int itemCount = mRegisteredWifiLoggingStatusListeners.beginBroadcast();
4006         for (int i = 0; i < itemCount; i++) {
4007             try {
4008                 mRegisteredWifiLoggingStatusListeners.getBroadcastItem(i)
4009                         .onStatusChanged(enabled);
4010             } catch (RemoteException e) {
4011                 Log.e(TAG, "onVerboseLoggingStatusChanged: RemoteException -- ", e);
4012             }
4013 
4014         }
4015         mRegisteredWifiLoggingStatusListeners.finishBroadcast();
4016     }
4017 
4018     private boolean isVerboseLoggingEnabled() {
4019         return WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED != mVerboseLoggingLevel;
4020     }
4021 
4022     private void enableVerboseLoggingInternal(int verbose) {
4023         if (verbose > WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED
4024                 && mBuildProperties.isUserBuild()) {
4025             throw new SecurityException(TAG + ": Not allowed for the user build.");
4026         }
4027         mVerboseLoggingLevel = verbose;
4028 
4029         // Update wifi globals before sending the verbose logging change.
4030         mWifiThreadRunner.removeCallbacks(mAutoDisableShowKeyVerboseLoggingModeRunnable);
4031         if (WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY == mVerboseLoggingLevel) {
4032             mWifiGlobals.setShowKeyVerboseLoggingModeEnabled(true);
4033             mWifiThreadRunner.postDelayed(mAutoDisableShowKeyVerboseLoggingModeRunnable,
4034                     AUTO_DISABLE_SHOW_KEY_COUNTDOWN_MILLIS);
4035         } else {
4036             // Ensure the show key mode is disabled.
4037             mWifiGlobals.setShowKeyVerboseLoggingModeEnabled(false);
4038         }
4039 
4040         mActiveModeWarden.enableVerboseLogging(isVerboseLoggingEnabled());
4041         mWifiLockManager.enableVerboseLogging(verbose);
4042         mWifiMulticastLockManager.enableVerboseLogging(verbose);
4043         mWifiInjector.enableVerboseLogging(verbose);
4044         mWifiInjector.getSarManager().enableVerboseLogging(verbose);
4045     }
4046 
4047     @Override
4048     public int getVerboseLoggingLevel() {
4049         if (isVerboseLoggingEnabled()) {
4050             mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
4051         }
4052         return mVerboseLoggingLevel;
4053     }
4054 
4055     private Runnable mAutoDisableShowKeyVerboseLoggingModeRunnable = new Runnable() {
4056         @Override
4057         public void run() {
4058             // If still enabled, fallback to the regular verbose logging mode.
4059             if (isVerboseLoggingEnabled()) {
4060                 enableVerboseLoggingInternal(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED);
4061             }
4062         }
4063     };
4064 
4065     @Override
4066     public void factoryReset(String packageName) {
4067         enforceNetworkSettingsPermission();
4068         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
4069             return;
4070         }
4071         mLog.info("factoryReset uid=%").c(Binder.getCallingUid()).flush();
4072         if (mUserManager.hasUserRestrictionForUser(
4073                 UserManager.DISALLOW_NETWORK_RESET,
4074                 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) {
4075             return;
4076         }
4077         if (!mUserManager.hasUserRestrictionForUser(
4078                 UserManager.DISALLOW_CONFIG_TETHERING,
4079                 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) {
4080             // Turn mobile hotspot off
4081             stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
4082         }
4083 
4084         if (mUserManager.hasUserRestrictionForUser(
4085                 UserManager.DISALLOW_CONFIG_WIFI,
4086                 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) {
4087             return;
4088         }
4089         // Delete all Wifi SSIDs
4090         List<WifiConfiguration> networks = mWifiThreadRunner.call(
4091                 () -> mWifiConfigManager.getSavedNetworks(Process.WIFI_UID),
4092                 Collections.emptyList());
4093         for (WifiConfiguration network : networks) {
4094             removeNetwork(network.networkId, packageName);
4095         }
4096         // Delete all Passpoint configurations
4097         List<PasspointConfiguration> configs = mWifiThreadRunner.call(
4098                 () -> mPasspointManager.getProviderConfigs(Process.WIFI_UID /* ignored */, true),
4099                 Collections.emptyList());
4100         for (PasspointConfiguration config : configs) {
4101             removePasspointConfigurationInternal(null, config.getUniqueId());
4102         }
4103         mWifiThreadRunner.post(() -> {
4104             mPasspointManager.clearAnqpRequestsAndFlushCache();
4105             mWifiConfigManager.clearUserTemporarilyDisabledList();
4106             mWifiConfigManager.removeAllEphemeralOrPasspointConfiguredNetworks();
4107             mWifiInjector.getWifiNetworkFactory().clear();
4108             mWifiNetworkSuggestionsManager.clear();
4109             mWifiInjector.getWifiScoreCard().clear();
4110             mWifiHealthMonitor.clear();
4111             mWifiCarrierInfoManager.clear();
4112             notifyFactoryReset();
4113         });
4114     }
4115 
4116     /**
4117      * Notify the Factory Reset Event to application who may installed wifi configurations.
4118      */
4119     private void notifyFactoryReset() {
4120         Intent intent = new Intent(WifiManager.ACTION_NETWORK_SETTINGS_RESET);
4121 
4122         // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts
4123         // to wake them up (if they're in background).
4124         List<ResolveInfo> resolveInfos =
4125                 mContext.getPackageManager().queryBroadcastReceiversAsUser(
4126                         intent, 0,
4127                         UserHandle.of(mWifiInjector.getWifiPermissionsWrapper().getCurrentUser()));
4128         if (resolveInfos == null || resolveInfos.isEmpty()) return; // No need to send broadcast.
4129 
4130         for (ResolveInfo resolveInfo : resolveInfos) {
4131             Intent intentToSend = new Intent(intent);
4132             intentToSend.setComponent(new ComponentName(
4133                     resolveInfo.activityInfo.applicationInfo.packageName,
4134                     resolveInfo.activityInfo.name));
4135             mContext.sendBroadcastAsUser(intentToSend, UserHandle.CURRENT,
4136                     android.Manifest.permission.NETWORK_CARRIER_PROVISIONING);
4137         }
4138     }
4139 
4140     @Override
4141     public Network getCurrentNetwork() {
4142         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4143             throw new SecurityException(TAG + ": Permission denied");
4144         }
4145         if (isVerboseLoggingEnabled()) {
4146             mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
4147         }
4148         return getPrimaryClientModeManagerBlockingThreadSafe().syncGetCurrentNetwork();
4149     }
4150 
4151     public static String toHexString(String s) {
4152         if (s == null) {
4153             return "null";
4154         }
4155         StringBuilder sb = new StringBuilder();
4156         sb.append('\'').append(s).append('\'');
4157         for (int n = 0; n < s.length(); n++) {
4158             sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
4159         }
4160         return sb.toString();
4161     }
4162 
4163     /**
4164      * Retrieve the data to be backed to save the current state.
4165      *
4166      * @return  Raw byte stream of the data to be backed up.
4167      */
4168     @Override
4169     public byte[] retrieveBackupData() {
4170         enforceNetworkSettingsPermission();
4171         mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
4172         Log.d(TAG, "Retrieving backup data");
4173         List<WifiConfiguration> wifiConfigurations = mWifiThreadRunner.call(
4174                 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(), null);
4175         byte[] backupData =
4176                 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
4177         Log.d(TAG, "Retrieved backup data");
4178         return backupData;
4179     }
4180 
4181     /**
4182      * Helper method to restore networks retrieved from backup data.
4183      *
4184      * @param configurations list of WifiConfiguration objects parsed from the backup data.
4185      */
4186     private void restoreNetworks(List<WifiConfiguration> configurations) {
4187         if (configurations == null) {
4188             Log.e(TAG, "Backup data parse failed");
4189             return;
4190         }
4191         int callingUid = Binder.getCallingUid();
4192         mWifiThreadRunner.run(
4193                 () -> {
4194                     for (WifiConfiguration configuration : configurations) {
4195                         int networkId =
4196                                 mWifiConfigManager.addOrUpdateNetwork(configuration, callingUid)
4197                                         .getNetworkId();
4198                         if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
4199                             Log.e(TAG, "Restore network failed: "
4200                                     + configuration.getProfileKey());
4201                             continue;
4202                         }
4203                         // Enable all networks restored.
4204                         mWifiConfigManager.enableNetwork(networkId, false, callingUid, null);
4205                         // Restore auto-join param.
4206                         mWifiConfigManager.allowAutojoin(networkId, configuration.allowAutojoin);
4207                     }
4208                 });
4209     }
4210 
4211     /**
4212      * Restore state from the backed up data.
4213      *
4214      * @param data Raw byte stream of the backed up data.
4215      */
4216     @Override
4217     public void restoreBackupData(byte[] data) {
4218         enforceNetworkSettingsPermission();
4219         mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
4220         Log.d(TAG, "Restoring backup data");
4221         List<WifiConfiguration> wifiConfigurations =
4222                 mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
4223         restoreNetworks(wifiConfigurations);
4224         Log.d(TAG, "Restored backup data");
4225     }
4226 
4227     /**
4228      * Retrieve the soft ap config data to be backed to save current config data.
4229      *
4230      * @return  Raw byte stream of the data to be backed up.
4231      */
4232     @Override
4233     public byte[] retrieveSoftApBackupData() {
4234         enforceNetworkSettingsPermission();
4235         mLog.info("retrieveSoftApBackupData uid=%").c(Binder.getCallingUid()).flush();
4236         SoftApConfiguration config = mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration,
4237                 new SoftApConfiguration.Builder().build());
4238         byte[] backupData =
4239                 mSoftApBackupRestore.retrieveBackupDataFromSoftApConfiguration(config);
4240         Log.d(TAG, "Retrieved soft ap backup data");
4241         return backupData;
4242     }
4243 
4244     /**
4245      * Restore soft ap config from the backed up data.
4246      *
4247      * @param data Raw byte stream of the backed up data.
4248      * @return restored SoftApConfiguration or Null if data is invalid.
4249      */
4250     @Override
4251     public SoftApConfiguration restoreSoftApBackupData(byte[] data) {
4252         enforceNetworkSettingsPermission();
4253         mLog.info("restoreSoftApBackupData uid=%").c(Binder.getCallingUid()).flush();
4254         SoftApConfiguration softApConfig =
4255                 mSoftApBackupRestore.retrieveSoftApConfigurationFromBackupData(data);
4256         if (softApConfig != null) {
4257             mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(
4258                     mWifiApConfigStore.resetToDefaultForUnsupportedConfig(
4259                     mWifiApConfigStore.upgradeSoftApConfiguration(softApConfig))));
4260             Log.d(TAG, "Restored soft ap backup data");
4261         }
4262         return softApConfig;
4263     }
4264 
4265 
4266     /**
4267      * Restore state from the older supplicant back up data.
4268      * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
4269      *
4270      * @param supplicantData Raw byte stream of wpa_supplicant.conf
4271      * @param ipConfigData Raw byte stream of ipconfig.txt
4272      */
4273     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
4274         enforceNetworkSettingsPermission();
4275         mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
4276         Log.d(TAG, "Restoring supplicant backup data");
4277         List<WifiConfiguration> wifiConfigurations =
4278                 mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
4279                         supplicantData, ipConfigData);
4280         restoreNetworks(wifiConfigurations);
4281         Log.d(TAG, "Restored supplicant backup data");
4282     }
4283 
4284     /**
4285      * Starts subscription provisioning with a provider.
4286      *
4287      * @param provider {@link OsuProvider} the provider to provision with
4288      * @param callback {@link IProvisioningCallback} the callback object to inform status
4289      */
4290     @Override
4291     public void startSubscriptionProvisioning(OsuProvider provider,
4292             IProvisioningCallback callback) {
4293         if (provider == null) {
4294             throw new IllegalArgumentException("Provider must not be null");
4295         }
4296         if (callback == null) {
4297             throw new IllegalArgumentException("Callback must not be null");
4298         }
4299         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4300             throw new SecurityException(TAG + ": Permission denied");
4301         }
4302         final int uid = Binder.getCallingUid();
4303         mLog.trace("startSubscriptionProvisioning uid=%").c(uid).flush();
4304         if (getPrimaryClientModeManagerBlockingThreadSafe()
4305                 .syncStartSubscriptionProvisioning(uid, provider, callback)) {
4306             mLog.trace("Subscription provisioning started with %")
4307                     .c(provider.toString()).flush();
4308         }
4309     }
4310 
4311     /**
4312      * See
4313      * {@link WifiManager#registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}
4314      *
4315      * @param callback Traffic State callback to register
4316      *
4317      * @throws SecurityException if the caller does not have permission to register a callback
4318      * @throws RemoteException if remote exception happens
4319      * @throws IllegalArgumentException if the arguments are null or invalid
4320      */
4321     @Override
4322     public void registerTrafficStateCallback(ITrafficStateCallback callback) {
4323         // verify arguments
4324         if (callback == null) {
4325             throw new IllegalArgumentException("Callback must not be null");
4326         }
4327         enforceNetworkSettingsPermission();
4328         if (isVerboseLoggingEnabled()) {
4329             mLog.info("registerTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
4330         }
4331         // Post operation to handler thread
4332         mWifiThreadRunner.post(() -> mWifiTrafficPoller.addCallback(callback));
4333     }
4334 
4335     /**
4336      * see {@link android.net.wifi.WifiManager#unregisterTrafficStateCallback(
4337      * WifiManager.TrafficStateCallback)}
4338      *
4339      * @param callback Traffic State callback to unregister
4340      *
4341      * @throws SecurityException if the caller does not have permission to register a callback
4342      */
4343     @Override
4344     public void unregisterTrafficStateCallback(ITrafficStateCallback callback) {
4345         enforceNetworkSettingsPermission();
4346         if (isVerboseLoggingEnabled()) {
4347             mLog.info("unregisterTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
4348         }
4349         // Post operation to handler thread
4350         mWifiThreadRunner.post(() -> mWifiTrafficPoller.removeCallback(callback));
4351     }
4352 
4353     private long getSupportedFeaturesInternal() {
4354         long supportedFeatureSet = mWifiThreadRunner.call(
4355                 () -> mActiveModeWarden.getPrimaryClientModeManager().getSupportedFeatures(),
4356                 0L);
4357         // Mask the feature set against system properties.
4358         boolean rttSupported = mContext.getPackageManager().hasSystemFeature(
4359                 PackageManager.FEATURE_WIFI_RTT);
4360         if (!rttSupported) {
4361             // flags filled in by vendor HAL, remove if overlay disables it.
4362             supportedFeatureSet &=
4363                     ~(WifiManager.WIFI_FEATURE_D2D_RTT | WifiManager.WIFI_FEATURE_D2AP_RTT);
4364         }
4365         if (!mContext.getResources().getBoolean(
4366                 R.bool.config_wifi_p2p_mac_randomization_supported)) {
4367             // flags filled in by vendor HAL, remove if overlay disables it.
4368             supportedFeatureSet &= ~WifiManager.WIFI_FEATURE_P2P_RAND_MAC;
4369         }
4370         if (mContext.getResources().getBoolean(
4371                 R.bool.config_wifi_connected_mac_randomization_supported)) {
4372             // no corresponding flags in vendor HAL, set if overlay enables it.
4373             supportedFeatureSet |= WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC;
4374         }
4375         if (ApConfigUtil.isApMacRandomizationSupported(mContext)) {
4376             // no corresponding flags in vendor HAL, set if overlay enables it.
4377             supportedFeatureSet |= WifiManager.WIFI_FEATURE_AP_RAND_MAC;
4378         }
4379         if (SdkLevel.isAtLeastS()) {
4380             if (ApConfigUtil.isBridgedModeSupported(mContext)) {
4381                 // The bridged mode requires the kernel network modules support.
4382                 // It doesn't relate the vendor HAL, set if overlay enables it.
4383                 supportedFeatureSet |= WifiManager.WIFI_FEATURE_BRIDGED_AP;
4384             }
4385             if (mContext.getResources().getBoolean(
4386                     R.bool.config_wifiStaWithBridgedSoftApConcurrencySupported)) {
4387                 // The bridged mode requires the kernel network modules support.
4388                 // It doesn't relate the vendor HAL, set if overlay enables it.
4389                 supportedFeatureSet |= WifiManager.WIFI_FEATURE_STA_BRIDGED_AP;
4390             }
4391         }
4392         supportedFeatureSet |= mWifiThreadRunner.call(
4393                 () -> {
4394                     long concurrencyFeatureSet = 0L;
4395                     if (mActiveModeWarden.isStaApConcurrencySupported()) {
4396                         concurrencyFeatureSet |= WifiManager.WIFI_FEATURE_AP_STA;
4397                     }
4398                     if (mActiveModeWarden.isStaStaConcurrencySupportedForLocalOnlyConnections()) {
4399                         concurrencyFeatureSet |= WifiManager.WIFI_FEATURE_ADDITIONAL_STA_LOCAL_ONLY;
4400                     }
4401                     if (mActiveModeWarden.isStaStaConcurrencySupportedForMbb()) {
4402                         concurrencyFeatureSet |= WifiManager.WIFI_FEATURE_ADDITIONAL_STA_MBB;
4403                     }
4404                     if (mActiveModeWarden.isStaStaConcurrencySupportedForRestrictedConnections()) {
4405                         concurrencyFeatureSet |= WifiManager.WIFI_FEATURE_ADDITIONAL_STA_RESTRICTED;
4406                     }
4407                     return concurrencyFeatureSet;
4408                 }, 0L);
4409         return supportedFeatureSet;
4410     }
4411 
4412     private static boolean hasAutomotiveFeature(Context context) {
4413         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
4414     }
4415 
4416     /**
4417      * See
4418      * {@link WifiManager#registerNetworkRequestMatchCallback(
4419      * Executor, WifiManager.NetworkRequestMatchCallback)}
4420      *
4421      * @param callback Network Request Match callback to register
4422      *
4423      * @throws SecurityException if the caller does not have permission to register a callback
4424      * @throws RemoteException if remote exception happens
4425      * @throws IllegalArgumentException if the arguments are null or invalid
4426      */
4427     @Override
4428     public void registerNetworkRequestMatchCallback(INetworkRequestMatchCallback callback) {
4429         // verify arguments
4430         if (callback == null) {
4431             throw new IllegalArgumentException("Callback must not be null");
4432         }
4433         enforceNetworkSettingsPermission();
4434         if (isVerboseLoggingEnabled()) {
4435             mLog.info("registerNetworkRequestMatchCallback uid=%")
4436                     .c(Binder.getCallingUid()).flush();
4437         }
4438         // Post operation to handler thread
4439         mWifiThreadRunner.post(() ->
4440                 mWifiInjector.getWifiNetworkFactory().addCallback(callback));
4441     }
4442 
4443     /**
4444      * see {@link android.net.wifi.WifiManager#unregisterNetworkRequestMatchCallback(
4445      * WifiManager.NetworkRequestMatchCallback)}
4446      *
4447      * @param callback Network Request Match callback to unregister
4448      *
4449      * @throws SecurityException if the caller does not have permission to register a callback
4450      */
4451     @Override
4452     public void unregisterNetworkRequestMatchCallback(INetworkRequestMatchCallback callback) {
4453         enforceNetworkSettingsPermission();
4454         if (isVerboseLoggingEnabled()) {
4455             mLog.info("unregisterNetworkRequestMatchCallback uid=%")
4456                     .c(Binder.getCallingUid()).flush();
4457         }
4458         // Post operation to handler thread
4459         mWifiThreadRunner.post(() ->
4460                 mWifiInjector.getWifiNetworkFactory().removeCallback(callback));
4461     }
4462 
4463     /**
4464      * See {@link android.net.wifi.WifiManager#addNetworkSuggestions(List)}
4465      *
4466      * @param networkSuggestions List of network suggestions to be added.
4467      * @param callingPackageName Package Name of the app adding the suggestions.
4468      * @param callingFeatureId Feature in the calling package
4469      * @throws SecurityException if the caller does not have permission.
4470      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
4471      */
4472     @Override
4473     public int addNetworkSuggestions(
4474             List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName,
4475             String callingFeatureId) {
4476         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
4477             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
4478         }
4479         if (isVerboseLoggingEnabled()) {
4480             mLog.info("addNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush();
4481         }
4482         int callingUid = Binder.getCallingUid();
4483 
4484         int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.add(
4485                 networkSuggestions, callingUid, callingPackageName, callingFeatureId),
4486                 WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL);
4487         if (success != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
4488             Log.e(TAG, "Failed to add network suggestions");
4489         }
4490         return success;
4491     }
4492 
4493     /**
4494      * See {@link android.net.wifi.WifiManager#removeNetworkSuggestions(List)}
4495      *
4496      * @param networkSuggestions List of network suggestions to be removed.
4497      * @param callingPackageName Package Name of the app removing the suggestions.
4498      * @throws SecurityException if the caller does not have permission.
4499      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
4500      */
4501     @Override
4502     public int removeNetworkSuggestions(
4503             List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) {
4504         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
4505             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
4506         }
4507         if (isVerboseLoggingEnabled()) {
4508             mLog.info("removeNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush();
4509         }
4510         int callingUid = Binder.getCallingUid();
4511 
4512         int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.remove(
4513                 networkSuggestions, callingUid, callingPackageName),
4514                 WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL);
4515         if (success != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
4516             Log.e(TAG, "Failed to remove network suggestions");
4517         }
4518         return success;
4519     }
4520 
4521     /**
4522      * See {@link android.net.wifi.WifiManager#getNetworkSuggestions()}
4523      * @param callingPackageName Package Name of the app getting the suggestions.
4524      * @return a list of network suggestions suggested by this app
4525      */
4526     @Override
4527     public List<WifiNetworkSuggestion> getNetworkSuggestions(String callingPackageName) {
4528         int callingUid = Binder.getCallingUid();
4529         mAppOps.checkPackage(callingUid, callingPackageName);
4530         enforceAccessPermission();
4531         if (isVerboseLoggingEnabled()) {
4532             mLog.info("getNetworkSuggestionList uid=%").c(Binder.getCallingUid()).flush();
4533         }
4534         return mWifiThreadRunner.call(() ->
4535                 mWifiNetworkSuggestionsManager.get(callingPackageName, callingUid),
4536                 Collections.emptyList());
4537     }
4538 
4539     /**
4540      * Gets the factory Wi-Fi MAC addresses.
4541      * @throws SecurityException if the caller does not have permission.
4542      * @return Array of String representing Wi-Fi MAC addresses, or empty array if failed.
4543      */
4544     @Override
4545     public String[] getFactoryMacAddresses() {
4546         final int uid = Binder.getCallingUid();
4547         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4548             throw new SecurityException("App not allowed to get Wi-Fi factory MAC address "
4549                     + "(uid = " + uid + ")");
4550         }
4551         String result = mWifiThreadRunner.call(
4552                 () -> mActiveModeWarden.getPrimaryClientModeManager().getFactoryMacAddress(),
4553                 null);
4554         // result can be empty array if either: WifiThreadRunner.call() timed out, or
4555         // ClientModeImpl.getFactoryMacAddress() returned null.
4556         // In this particular instance, we don't differentiate the two types of nulls.
4557         if (result == null) {
4558             return new String[0];
4559         }
4560         return new String[]{result};
4561     }
4562 
4563     /**
4564      * Sets the current device mobility state.
4565      * @param state the new device mobility state
4566      */
4567     @Override
4568     public void setDeviceMobilityState(@DeviceMobilityState int state) {
4569         mContext.enforceCallingOrSelfPermission(
4570                 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE, "WifiService");
4571 
4572         if (isVerboseLoggingEnabled()) {
4573             mLog.info("setDeviceMobilityState uid=% state=%")
4574                     .c(Binder.getCallingUid())
4575                     .c(state)
4576                     .flush();
4577         }
4578         // Post operation to handler thread
4579         mWifiThreadRunner.post(() -> {
4580             mWifiConnectivityManager.setDeviceMobilityState(state);
4581             mWifiHealthMonitor.setDeviceMobilityState(state);
4582             mWifiDataStall.setDeviceMobilityState(state);
4583         });
4584     }
4585 
4586     /**
4587      * Proxy for the final native call of the parent class. Enables mocking of
4588      * the function.
4589      */
4590     public int getMockableCallingUid() {
4591         return getCallingUid();
4592     }
4593 
4594     /**
4595      * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
4596      * with a peer, and send the SSID and password of the selected network.
4597      *
4598      * @param binder Caller's binder context
4599      * @param packageName Package name of the calling app
4600      * @param enrolleeUri URI of the Enrollee obtained externally (e.g. QR code scanning)
4601      * @param selectedNetworkId Selected network ID to be sent to the peer
4602      * @param netRole The network role of the enrollee
4603      * @param callback Callback for status updates
4604      */
4605     @Override
4606     public void startDppAsConfiguratorInitiator(IBinder binder, @NonNull String packageName,
4607             String enrolleeUri, int selectedNetworkId, int netRole, IDppCallback callback) {
4608         // verify arguments
4609         if (binder == null) {
4610             throw new IllegalArgumentException("Binder must not be null");
4611         }
4612         if (TextUtils.isEmpty(enrolleeUri)) {
4613             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
4614         }
4615         if (selectedNetworkId < 0) {
4616             throw new IllegalArgumentException("Selected network ID invalid");
4617         }
4618         if (callback == null) {
4619             throw new IllegalArgumentException("Callback must not be null");
4620         }
4621 
4622         final int uid = getMockableCallingUid();
4623 
4624         int callingUid = Binder.getCallingUid();
4625         mAppOps.checkPackage(callingUid, packageName);
4626         if (!isSettingsOrSuw(Binder.getCallingPid(), callingUid)) {
4627             throw new SecurityException(TAG + ": Permission denied");
4628         }
4629         // Stop MBB (if in progress) when DPP is initiated. Otherwise, DPP operation will fail
4630         // when the previous primary iface is removed after MBB completion.
4631         mWifiThreadRunner.post(() ->
4632                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
4633                         mDppManager.startDppAsConfiguratorInitiator(
4634                                 uid, packageName,
4635                                 mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
4636                                 binder, enrolleeUri,
4637                                 removeSecurityTypeFromNetworkId(selectedNetworkId), netRole,
4638                                 callback)));
4639     }
4640 
4641     /**
4642      * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
4643      * with a peer, and receive the SSID and password from the peer configurator.
4644      *
4645      * @param binder Caller's binder context
4646      * @param configuratorUri URI of the Configurator obtained externally (e.g. QR code scanning)
4647      * @param callback Callback for status updates
4648      */
4649     @Override
4650     public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
4651             IDppCallback callback) {
4652         // verify arguments
4653         if (binder == null) {
4654             throw new IllegalArgumentException("Binder must not be null");
4655         }
4656         if (TextUtils.isEmpty(configuratorUri)) {
4657             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
4658         }
4659         if (callback == null) {
4660             throw new IllegalArgumentException("Callback must not be null");
4661         }
4662 
4663         final int uid = getMockableCallingUid();
4664 
4665         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4666             throw new SecurityException(TAG + ": Permission denied");
4667         }
4668 
4669         // Stop MBB (if in progress) when DPP is initiated. Otherwise, DPP operation will fail
4670         // when the previous primary iface is removed after MBB completion.
4671         mWifiThreadRunner.post(() ->
4672                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
4673                         mDppManager.startDppAsEnrolleeInitiator(uid,
4674                                 mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
4675                                 binder, configuratorUri, callback)));
4676     }
4677 
4678     /**
4679      * Start DPP in Enrollee-Responder role. The current device will generate the
4680      * bootstrap code and wait for the peer device to start the DPP authentication process.
4681      *
4682      * @param binder Caller's binder context
4683      * @param deviceInfo Device specific info to display in QR code(e.g. Easy_connect_demo)
4684      * @param curve Elliptic curve cryptography type used to generate DPP public/private key pair.
4685      * @param callback Callback for status updates
4686      */
4687     @Override
4688     @RequiresApi(Build.VERSION_CODES.S)
4689     public void startDppAsEnrolleeResponder(IBinder binder, @Nullable String deviceInfo,
4690             @WifiManager.EasyConnectCryptographyCurve int curve, IDppCallback callback) {
4691         if (!SdkLevel.isAtLeastS()) {
4692             throw new UnsupportedOperationException();
4693         }
4694         // verify arguments
4695         if (binder == null) {
4696             throw new IllegalArgumentException("Binder must not be null");
4697         }
4698         if (callback == null) {
4699             throw new IllegalArgumentException("Callback must not be null");
4700         }
4701 
4702         final int uid = getMockableCallingUid();
4703 
4704         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4705             throw new SecurityException(TAG + ": Permission denied");
4706         }
4707 
4708         if (deviceInfo != null) {
4709             int deviceInfoLen = deviceInfo.length();
4710             if (deviceInfoLen > WifiManager.getEasyConnectMaxAllowedResponderDeviceInfoLength()) {
4711                 throw new IllegalArgumentException("Device info length: " + deviceInfoLen
4712                         + " must be less than "
4713                         + WifiManager.getEasyConnectMaxAllowedResponderDeviceInfoLength());
4714             }
4715             char c;
4716             for (int i = 0; i < deviceInfoLen; i++) {
4717                 c = deviceInfo.charAt(i);
4718                 if (c < '!' || c > '~' || c == ';') {
4719                     throw new IllegalArgumentException("Allowed Range of ASCII characters in"
4720                             + "deviceInfo - %x20-7E; semicolon and space are not allowed!"
4721                             + "Found c: " + c);
4722                 }
4723             }
4724         }
4725 
4726         // Stop MBB (if in progress) when DPP is initiated. Otherwise, DPP operation will fail
4727         // when the previous primary iface is removed after MBB completion.
4728         mWifiThreadRunner.post(() ->
4729                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
4730                         mDppManager.startDppAsEnrolleeResponder(uid,
4731                                 mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
4732                                 binder, deviceInfo, curve, callback)));
4733     }
4734 
4735     /**
4736      * Stop or abort a current DPP session.
4737      */
4738     @Override
4739     public void stopDppSession() throws RemoteException {
4740         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4741             throw new SecurityException(TAG + ": Permission denied");
4742         }
4743         final int uid = getMockableCallingUid();
4744 
4745         mWifiThreadRunner.post(() -> mDppManager.stopDppSession(uid));
4746     }
4747 
4748     /**
4749      * see {@link android.net.wifi.WifiManager#addWifiVerboseLoggingStatusChangedListener(Executor,
4750      * WifiManager.WifiVerboseLoggingStatusChangedListener)}
4751      *
4752      * @param listener IWifiVerboseLoggingStatusChangedListener listener to add
4753      *
4754      * @throws SecurityException if the caller does not have permission to add a listener.
4755      * @throws IllegalArgumentException if the argument is null.
4756      */
4757     @Override
4758     public void addWifiVerboseLoggingStatusChangedListener(
4759             IWifiVerboseLoggingStatusChangedListener listener) {
4760         if (listener == null) {
4761             throw new IllegalArgumentException("Listener must not be null");
4762         }
4763         enforceAccessPermission();
4764         // Post operation to handler thread
4765         mWifiThreadRunner.post(() ->
4766                 mRegisteredWifiLoggingStatusListeners.register(listener));
4767     }
4768 
4769     /**
4770      * see {@link android.net.wifi.WifiManager#unregisterWifiVerboseLoggingStatusCallback
4771      * (WifiManager.WifiVerboseLoggingStatusCallback)}
4772      *
4773      * @param listener the listener to be removed.
4774      *
4775      * @throws SecurityException if the caller does not have permission to add a listener.
4776      * @throws IllegalArgumentException if the argument is null.
4777      */
4778     @Override
4779     public void removeWifiVerboseLoggingStatusChangedListener(
4780             IWifiVerboseLoggingStatusChangedListener listener) {
4781         if (listener == null) {
4782             throw new IllegalArgumentException("Listener must not be null");
4783         }
4784         enforceAccessPermission();
4785         // Post operation to handler thread
4786         mWifiThreadRunner.post(() ->
4787                 mRegisteredWifiLoggingStatusListeners.unregister(listener));
4788     }
4789 
4790     /**
4791      * see {@link android.net.wifi.WifiManager#addOnWifiUsabilityStatsListener(Executor,
4792      * WifiManager.OnWifiUsabilityStatsListener)}
4793      *
4794      * @param listener WifiUsabilityStatsEntry listener to add
4795      *
4796      * @throws SecurityException if the caller does not have permission to add a listener
4797      * @throws RemoteException if remote exception happens
4798      * @throws IllegalArgumentException if the arguments are null or invalid
4799      */
4800     @Override
4801     public void addOnWifiUsabilityStatsListener(IOnWifiUsabilityStatsListener listener) {
4802         if (listener == null) {
4803             throw new IllegalArgumentException("Listener must not be null");
4804         }
4805         mContext.enforceCallingOrSelfPermission(
4806                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4807         if (isVerboseLoggingEnabled()) {
4808             mLog.info("addOnWifiUsabilityStatsListener uid=%")
4809                 .c(Binder.getCallingUid()).flush();
4810         }
4811         // Post operation to handler thread
4812         mWifiThreadRunner.post(() ->
4813                 mWifiMetrics.addOnWifiUsabilityListener(listener));
4814     }
4815 
4816     /**
4817      * see {@link android.net.wifi.WifiManager#removeOnWifiUsabilityStatsListener
4818      * (WifiManager.OnWifiUsabilityStatsListener)}
4819      *
4820      * @param listener listener to be removed.
4821      *
4822      * @throws SecurityException if the caller does not have permission to add a listener
4823      */
4824     @Override
4825     public void removeOnWifiUsabilityStatsListener(IOnWifiUsabilityStatsListener listener) {
4826         mContext.enforceCallingOrSelfPermission(
4827                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4828         if (isVerboseLoggingEnabled()) {
4829             mLog.info("removeOnWifiUsabilityStatsListener uid=%")
4830                     .c(Binder.getCallingUid()).flush();
4831         }
4832         // Post operation to handler thread
4833         mWifiThreadRunner.post(() ->
4834                 mWifiMetrics.removeOnWifiUsabilityListener(listener));
4835     }
4836 
4837     /**
4838      * Updates the Wi-Fi usability score.
4839      * @param seqNum Sequence number of the Wi-Fi usability score.
4840      * @param score The Wi-Fi usability score.
4841      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second.
4842      */
4843     @Override
4844     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
4845         mContext.enforceCallingOrSelfPermission(
4846                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
4847 
4848         if (isVerboseLoggingEnabled()) {
4849             mLog.info("updateWifiUsabilityScore uid=% seqNum=% score=% predictionHorizonSec=%")
4850                     .c(Binder.getCallingUid())
4851                     .c(seqNum)
4852                     .c(score)
4853                     .c(predictionHorizonSec)
4854                     .flush();
4855         }
4856         // Post operation to handler thread
4857         mWifiThreadRunner.post(() -> {
4858             String ifaceName = mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName();
4859             mWifiMetrics.incrementWifiUsabilityScoreCount(
4860                     ifaceName, seqNum, score, predictionHorizonSec);
4861         });
4862     }
4863 
4864     /**
4865      * Notify interested parties if a wifi config has been changed.
4866      *
4867      * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
4868      * @param config Must have a WifiConfiguration object to succeed
4869      */
4870     private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
4871             WifiConfiguration config) {
4872         Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
4873         if (config != null && config.SSID != null && mWifiPermissionsUtil.isLocationModeEnabled()) {
4874             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
4875         }
4876         intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
4877                 wifiCredentialEventType);
4878         mContext.createContextAsUser(UserHandle.CURRENT, 0)
4879                 .sendBroadcastWithMultiplePermissions(
4880                         intent,
4881                         new String[]{
4882                                 android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE,
4883                                 android.Manifest.permission.ACCESS_FINE_LOCATION,
4884                         });
4885     }
4886 
4887     /**
4888      * Connects to a network.
4889      *
4890      * If the supplied config is not null, then the netId argument will be ignored and the config
4891      * will be saved (or updated if its networkId or profile key already exist) and connected to.
4892      *
4893      * If the supplied config is null, then the netId argument will be matched to a saved config to
4894      * be connected to.
4895      *
4896      * @param config New or existing config to add/update and connect to
4897      * @param netId Network ID of existing config to connect to if the supplied config is null
4898      * @param callback Listener to notify action result
4899      *
4900      * see: {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)}
4901      *      {@link WifiManager#connect(int, WifiManager.ActionListener)}
4902      */
4903     @Override
4904     public void connect(WifiConfiguration config, int netId, @Nullable IActionListener callback) {
4905         int uid = Binder.getCallingUid();
4906         if (!isPrivileged(Binder.getCallingPid(), uid)) {
4907             throw new SecurityException(TAG + ": Permission denied");
4908         }
4909         if (config != null) {
4910             config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
4911         }
4912         final int netIdArg = removeSecurityTypeFromNetworkId(netId);
4913         mLog.info("connect uid=%").c(uid).flush();
4914         mWifiThreadRunner.post(() -> {
4915             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
4916             final NetworkUpdateResult result;
4917             // if connecting using WifiConfiguration, save the network first
4918             if (config != null) {
4919                 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4920                     mWifiMetrics.logUserActionEvent(
4921                             UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK, config.networkId);
4922                 }
4923                 result = mWifiConfigManager.addOrUpdateNetwork(config, uid);
4924                 if (!result.isSuccess()) {
4925                     Log.e(TAG, "connect adding/updating config=" + config + " failed");
4926                     wrapper.sendFailure(WifiManager.ERROR);
4927                     return;
4928                 }
4929                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
4930             } else {
4931                 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4932                     mWifiMetrics.logUserActionEvent(
4933                             UserActionEvent.EVENT_MANUAL_CONNECT, netIdArg);
4934                 }
4935                 result = new NetworkUpdateResult(netIdArg);
4936             }
4937             WifiConfiguration configuration = mWifiConfigManager
4938                     .getConfiguredNetwork(result.getNetworkId());
4939             if (configuration == null) {
4940                 Log.e(TAG, "connect to Invalid network Id=" + netIdArg);
4941                 wrapper.sendFailure(WifiManager.ERROR);
4942                 return;
4943             }
4944             if (configuration.enterpriseConfig != null
4945                     && configuration.enterpriseConfig.isAuthenticationSimBased()) {
4946                 int subId = mWifiCarrierInfoManager.getBestMatchSubscriptionId(configuration);
4947                 if (!mWifiCarrierInfoManager.isSimReady(subId)) {
4948                     Log.e(TAG, "connect to SIM-based config=" + configuration
4949                             + "while SIM is absent");
4950                     wrapper.sendFailure(WifiManager.ERROR);
4951                     return;
4952                 }
4953                 if (mWifiCarrierInfoManager.requiresImsiEncryption(subId)
4954                         && !mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(subId)) {
4955                     Log.e(TAG, "Imsi protection required but not available for Network="
4956                             + configuration);
4957                     wrapper.sendFailure(WifiManager.ERROR);
4958                     return;
4959                 }
4960             }
4961             mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
4962                     mConnectHelper.connectToNetwork(result, wrapper, uid));
4963         });
4964     }
4965 
4966     /**
4967      * see {@link android.net.wifi.WifiManager#save(WifiConfiguration,
4968      * WifiManager.ActionListener)}
4969      */
4970     @Override
4971     public void save(WifiConfiguration config, @Nullable IActionListener callback) {
4972         int uid = Binder.getCallingUid();
4973         if (!isPrivileged(Binder.getCallingPid(), uid)) {
4974             throw new SecurityException(TAG + ": Permission denied");
4975         }
4976         if (config != null) {
4977             config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
4978         }
4979         mLog.info("save uid=%").c(uid).flush();
4980         mWifiThreadRunner.post(() -> {
4981             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
4982             NetworkUpdateResult result =
4983                     mWifiConfigManager.updateBeforeSaveNetwork(config, uid);
4984             if (result.isSuccess()) {
4985                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
4986                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
4987                         mActiveModeWarden.getPrimaryClientModeManager()
4988                                 .saveNetwork(result, wrapper, uid));
4989                 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4990                     mWifiMetrics.logUserActionEvent(
4991                             UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK, config.networkId);
4992                 }
4993             } else {
4994                 wrapper.sendFailure(WifiManager.ERROR);
4995             }
4996         });
4997     }
4998 
4999     /**
5000      * see {@link android.net.wifi.WifiManager#forget(int, WifiManager.ActionListener)}
5001      */
5002     @Override
5003     public void forget(int netId, @Nullable IActionListener callback) {
5004         int uid = Binder.getCallingUid();
5005         if (!isPrivileged(Binder.getCallingPid(), uid)) {
5006             throw new SecurityException(TAG + ": Permission denied");
5007         }
5008         final int internalNetId = removeSecurityTypeFromNetworkId(netId);
5009         mLog.info("forget uid=%").c(Binder.getCallingUid()).flush();
5010         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
5011             // It's important to log this metric before the actual forget executes because
5012             // the netId becomes invalid after the forget operation.
5013             mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_FORGET_WIFI, internalNetId);
5014         }
5015         mWifiThreadRunner.post(() -> {
5016             WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(internalNetId);
5017             boolean success = mWifiConfigManager.removeNetwork(internalNetId, uid, null);
5018             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
5019             if (success) {
5020                 wrapper.sendSuccess();
5021                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT, config);
5022             } else {
5023                 Log.e(TAG, "Failed to remove network");
5024                 wrapper.sendFailure(WifiManager.ERROR);
5025             }
5026         });
5027     }
5028 
5029     /**
5030      * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)}
5031      */
5032     public void registerScanResultsCallback(@NonNull IScanResultsCallback callback) {
5033         if (callback == null) {
5034             throw new IllegalArgumentException("callback must not be null");
5035         }
5036         enforceAccessPermission();
5037 
5038         if (isVerboseLoggingEnabled()) {
5039             mLog.info("registerScanResultsCallback uid=%").c(Binder.getCallingUid()).flush();
5040         }
5041         mWifiThreadRunner.post(() -> {
5042             if (!mWifiInjector.getScanRequestProxy().registerScanResultsCallback(callback)) {
5043                 Log.e(TAG, "registerScanResultsCallback: Failed to register callback");
5044             }
5045         });
5046     }
5047 
5048     /**
5049      * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)}
5050      */
5051     public void unregisterScanResultsCallback(@NonNull IScanResultsCallback callback) {
5052         if (isVerboseLoggingEnabled()) {
5053             mLog.info("unregisterScanResultCallback uid=%").c(Binder.getCallingUid()).flush();
5054         }
5055         enforceAccessPermission();
5056         // post operation to handler thread
5057         mWifiThreadRunner.post(() -> mWifiInjector.getScanRequestProxy()
5058                         .unregisterScanResultsCallback(callback));
5059 
5060     }
5061 
5062     /**
5063      * See {@link WifiManager#addSuggestionConnectionStatusListener(Executor,
5064      * SuggestionConnectionStatusListener)}
5065      */
5066     public void registerSuggestionConnectionStatusListener(
5067             @NonNull ISuggestionConnectionStatusListener listener, String packageName,
5068             @Nullable String featureId) {
5069         if (listener == null) {
5070             throw new IllegalArgumentException("listener must not be null");
5071         }
5072         final int uid = Binder.getCallingUid();
5073         mWifiPermissionsUtil.checkPackage(uid, packageName);
5074         enforceAccessPermission();
5075         enforceLocationPermission(packageName, featureId, uid);
5076         if (isVerboseLoggingEnabled()) {
5077             mLog.info("registerSuggestionConnectionStatusListener uid=%").c(uid).flush();
5078         }
5079         mWifiThreadRunner.post(() ->
5080                 mWifiNetworkSuggestionsManager
5081                         .registerSuggestionConnectionStatusListener(listener, packageName, uid));
5082     }
5083 
5084     /**
5085      * See {@link WifiManager#removeSuggestionConnectionStatusListener(
5086      * SuggestionConnectionStatusListener)}
5087      */
5088     public void unregisterSuggestionConnectionStatusListener(
5089             @NonNull ISuggestionConnectionStatusListener listener, String packageName) {
5090         enforceAccessPermission();
5091         int uid = Binder.getCallingUid();
5092         if (isVerboseLoggingEnabled()) {
5093             mLog.info("unregisterSuggestionConnectionStatusListener uid=%")
5094                     .c(uid).flush();
5095         }
5096         mWifiThreadRunner.post(() ->
5097                 mWifiNetworkSuggestionsManager
5098                         .unregisterSuggestionConnectionStatusListener(listener, packageName, uid));
5099     }
5100 
5101     @Override
5102     public int calculateSignalLevel(int rssi) {
5103         return RssiUtil.calculateSignalLevel(mContext, rssi);
5104     }
5105 
5106     /**
5107      * See {@link android.net.wifi.WifiManager#setWifiConnectedNetworkScorer(Executor,
5108      * WifiManager.WifiConnectedNetworkScorer)}
5109      *
5110      * @param binder IBinder instance to allow cleanup if the app dies.
5111      * @param scorer Wifi connected network scorer to set.
5112      * @return true Scorer is set successfully.
5113      *
5114      * @throws RemoteException if remote exception happens
5115      * @throws IllegalArgumentException if the arguments are null or invalid
5116      */
5117     @Override
5118     public boolean setWifiConnectedNetworkScorer(IBinder binder,
5119             IWifiConnectedNetworkScorer scorer) {
5120         if (binder == null) {
5121             throw new IllegalArgumentException("Binder must not be null");
5122         }
5123         if (scorer == null) {
5124             throw new IllegalArgumentException("Scorer must not be null");
5125         }
5126         mContext.enforceCallingOrSelfPermission(
5127                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
5128         if (isVerboseLoggingEnabled()) {
5129             mLog.info("setWifiConnectedNetworkScorer uid=%").c(Binder.getCallingUid()).flush();
5130         }
5131         // Post operation to handler thread
5132         return mWifiThreadRunner.call(
5133                 () -> mActiveModeWarden.setWifiConnectedNetworkScorer(binder, scorer), false);
5134     }
5135 
5136     /**
5137      * See {@link WifiManager#clearWifiConnectedNetworkScorer()}
5138      */
5139     @Override
5140     public void clearWifiConnectedNetworkScorer() {
5141         mContext.enforceCallingOrSelfPermission(
5142                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
5143         if (isVerboseLoggingEnabled()) {
5144             mLog.info("clearWifiConnectedNetworkScorer uid=%").c(Binder.getCallingUid()).flush();
5145         }
5146         // Post operation to handler thread
5147         mWifiThreadRunner.post(() -> mActiveModeWarden.clearWifiConnectedNetworkScorer());
5148     }
5149 
5150     /**
5151      * See {@link android.net.wifi.WifiManager#setScanThrottleEnabled(boolean)}
5152      */
5153     @Override
5154     public void setScanThrottleEnabled(boolean enable) {
5155         enforceNetworkSettingsPermission();
5156         mLog.info("setScanThrottleEnabled uid=% verbose=%")
5157                 .c(Binder.getCallingUid())
5158                 .c(enable).flush();
5159         mWifiThreadRunner.post(()-> mScanRequestProxy.setScanThrottleEnabled(enable));
5160     }
5161 
5162     /**
5163      * See {@link android.net.wifi.WifiManager#isScanThrottleEnabled()}
5164      */
5165     @Override
5166     public boolean isScanThrottleEnabled() {
5167         enforceAccessPermission();
5168         if (isVerboseLoggingEnabled()) {
5169             mLog.info("isScanThrottleEnabled uid=%").c(Binder.getCallingUid()).flush();
5170         }
5171         return mWifiThreadRunner.call(()-> mScanRequestProxy.isScanThrottleEnabled(), true);
5172     }
5173 
5174     /**
5175      * See {@link android.net.wifi.WifiManager#setAutoWakeupEnabled(boolean)}
5176      */
5177     @Override
5178     public void setAutoWakeupEnabled(boolean enable) {
5179         enforceNetworkSettingsPermission();
5180         mLog.info("setWalkeupEnabled uid=% verbose=%")
5181                 .c(Binder.getCallingUid())
5182                 .c(enable).flush();
5183         mWifiThreadRunner.post(()-> mWifiInjector.getWakeupController().setEnabled(enable));
5184     }
5185 
5186     /**
5187      * See {@link android.net.wifi.WifiManager#isAutoWakeupEnabled()}
5188      */
5189     @Override
5190     public boolean isAutoWakeupEnabled() {
5191         enforceAccessPermission();
5192         if (isVerboseLoggingEnabled()) {
5193             mLog.info("isAutoWakeupEnabled uid=%").c(Binder.getCallingUid()).flush();
5194         }
5195         return mWifiThreadRunner.call(()-> mWifiInjector.getWakeupController().isEnabled(), false);
5196     }
5197 
5198     /**
5199      * See {@link android.net.wifi.WifiManager#setCarrierNetworkOffloadEnabled(int, boolean, boolean)}
5200      */
5201     @Override
5202     public void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged,
5203             boolean enabled) {
5204         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
5205             throw new SecurityException(TAG + ": Permission denied");
5206         }
5207         if (isVerboseLoggingEnabled()) {
5208             mLog.info("setCarrierNetworkOffloadEnabled uid=%").c(Binder.getCallingUid()).flush();
5209         }
5210         mWifiThreadRunner.post(() ->
5211                 mWifiCarrierInfoManager.setCarrierNetworkOffloadEnabled(subscriptionId, merged, enabled));
5212     }
5213 
5214     /**
5215      * See {@link android.net.wifi.WifiManager#isCarrierNetworkOffloadEnabled(int, boolean)}
5216      */
5217     @Override
5218     public boolean isCarrierNetworkOffloadEnabled(int subId, boolean merged) {
5219         enforceAccessPermission();
5220         if (isVerboseLoggingEnabled()) {
5221             mLog.info("isCarrierNetworkOffload uid=%").c(Binder.getCallingUid()).flush();
5222         }
5223 
5224         return mWifiThreadRunner.call(()->
5225                 mWifiCarrierInfoManager.isCarrierNetworkOffloadEnabled(subId, merged), true);
5226     }
5227 
5228     /**
5229      * See {@link android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener(Executor,
5230      * WifiManager.SuggestionUserApprovalStatusListener)}
5231      */
5232     @Override
5233     public void addSuggestionUserApprovalStatusListener(
5234             ISuggestionUserApprovalStatusListener listener, String packageName) {
5235         if (listener == null) {
5236             throw new NullPointerException("listener must not be null");
5237         }
5238         final int uid = Binder.getCallingUid();
5239         enforceAccessPermission();
5240         long callingIdentity = Binder.clearCallingIdentity();
5241         try {
5242             if (!mWifiPermissionsUtil.doesUidBelongToCurrentUser(uid)) {
5243                 Log.e(TAG, "UID " + uid + " not visible to the current user");
5244                 throw new SecurityException("UID " + uid + " not visible to the current user");
5245             }
5246         } finally {
5247             // restore calling identity
5248             Binder.restoreCallingIdentity(callingIdentity);
5249         }
5250         if (isVerboseLoggingEnabled()) {
5251             mLog.info("addSuggestionUserApprovalStatusListener uid=%").c(uid).flush();
5252         }
5253         mWifiThreadRunner.post(() -> mWifiNetworkSuggestionsManager
5254                 .addSuggestionUserApprovalStatusListener(listener, packageName, uid));
5255     }
5256 
5257     /**
5258      * See {@link android.net.wifi.WifiManager#removeSuggestionUserApprovalStatusListener(
5259      * WifiManager.SuggestionUserApprovalStatusListener)}
5260      */
5261     @Override
5262     public void removeSuggestionUserApprovalStatusListener(
5263             ISuggestionUserApprovalStatusListener listener, String packageName) {
5264         enforceAccessPermission();
5265         int uid = Binder.getCallingUid();
5266         long callingIdentity = Binder.clearCallingIdentity();
5267         try {
5268             if (!mWifiPermissionsUtil.doesUidBelongToCurrentUser(uid)) {
5269                 Log.e(TAG, "UID " + uid + " not visible to the current user");
5270                 throw new SecurityException("UID " + uid + " not visible to the current user");
5271             }
5272         } finally {
5273             // restore calling identity
5274             Binder.restoreCallingIdentity(callingIdentity);
5275         }
5276         if (isVerboseLoggingEnabled()) {
5277             mLog.info("removeSuggestionUserApprovalStatusListener uid=%")
5278                     .c(uid).flush();
5279         }
5280         mWifiThreadRunner.post(() ->
5281                 mWifiNetworkSuggestionsManager
5282                         .removeSuggestionUserApprovalStatusListener(listener, packageName, uid));
5283     }
5284 
5285     /**
5286      * See {@link android.net.wifi.WifiManager#setEmergencyScanRequestInProgress(boolean)}.
5287      */
5288     @Override
5289     public void setEmergencyScanRequestInProgress(boolean inProgress) {
5290         enforceNetworkStackPermission();
5291         int uid = Binder.getCallingUid();
5292         mLog.info("setEmergencyScanRequestInProgress uid=%").c(uid).flush();
5293         mActiveModeWarden.setEmergencyScanRequestInProgress(inProgress);
5294     }
5295 
5296     /**
5297      * See {@link android.net.wifi.WifiManager#removeAppState(int, String)}.
5298      */
5299     @Override
5300     public void removeAppState(int targetAppUid, @NonNull String targetAppPackageName) {
5301         enforceNetworkSettingsPermission();
5302         mLog.info("removeAppState uid=%").c(Binder.getCallingUid()).flush();
5303 
5304         mWifiThreadRunner.post(() -> {
5305             removeAppStateInternal(targetAppUid, targetAppPackageName);
5306         });
5307     }
5308 
5309     /**
5310      * See {@link android.net.wifi.WifiManager#setWifiScoringEnabled(boolean)}.
5311      */
5312     @Override
5313     public boolean setWifiScoringEnabled(boolean enabled) {
5314         mContext.enforceCallingOrSelfPermission(
5315                 android.Manifest.permission.NETWORK_SETTINGS, "WifiService");
5316         // Post operation to handler thread
5317         return mWifiThreadRunner.call(
5318                 () -> mSettingsStore.handleWifiScoringEnabled(enabled), false);
5319     }
5320 
5321     @VisibleForTesting
5322     static boolean isValidBandForGetUsableChannels(@WifiScanner.WifiBand int band) {
5323         switch (band) {
5324             case WifiScanner.WIFI_BAND_UNSPECIFIED:
5325             case WifiScanner.WIFI_BAND_24_GHZ:
5326             case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS:
5327             case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
5328             case WifiScanner.WIFI_BAND_6_GHZ:
5329             case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_GHZ:
5330             case WifiScanner.WIFI_BAND_60_GHZ:
5331             case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ:
5332                 return true;
5333             default:
5334                 return false;
5335         }
5336     }
5337 
5338     /**
5339      * See {@link android.net.wifi.WifiManager#getUsableChannels(int, int) and
5340      * See {@link android.net.wifi.WifiManager#getAllowedChannels(int, int).
5341      *
5342      * @throws SecurityException if the caller does not have permission
5343      * or IllegalArgumentException if the band is invalid for this method.
5344      */
5345     @Override
5346     public List<WifiAvailableChannel> getUsableChannels(@WifiScanner.WifiBand int band,
5347             @WifiAvailableChannel.OpMode int mode, @WifiAvailableChannel.Filter int filter) {
5348         // Location mode must be enabled
5349         if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
5350             throw new SecurityException("Location mode is disabled for the device");
5351         }
5352         final int uid = Binder.getCallingUid();
5353         if (isVerboseLoggingEnabled()) {
5354             mLog.info("getUsableChannels uid=%").c(Binder.getCallingUid()).flush();
5355         }
5356         if (!mWifiPermissionsUtil.checkCallersHardwareLocationPermission(uid)) {
5357             throw new SecurityException("UID " + uid + " does not have location h/w permission");
5358         }
5359         if (!isValidBandForGetUsableChannels(band)) {
5360             throw new IllegalArgumentException("Unsupported band: " + band);
5361         }
5362         List<WifiAvailableChannel> channels = mWifiThreadRunner.call(
5363                 () -> mWifiNative.getUsableChannels(band, mode, filter), null);
5364         if (channels == null) {
5365             throw new UnsupportedOperationException();
5366         }
5367         return channels;
5368     }
5369 
5370     private void resetNotificationManager() {
5371         mWifiInjector.getWifiNotificationManager().createNotificationChannels();
5372         mWifiInjector.getOpenNetworkNotifier().clearPendingNotification(false);
5373         mWifiCarrierInfoManager.resetNotification();
5374         mWifiNetworkSuggestionsManager.resetNotification();
5375         mWifiInjector.getWakeupController().resetNotification();
5376     }
5377 
5378     /**
5379      * See {@link android.net.wifi.WifiManager#flushPasspointAnqpCache()}.
5380      */
5381     @Override
5382     public void flushPasspointAnqpCache(@NonNull String packageName) {
5383         mWifiPermissionsUtil.checkPackage(Binder.getCallingUid(), packageName);
5384 
5385         if (!isDeviceOrProfileOwner(Binder.getCallingUid(), packageName)) {
5386             enforceAnyPermissionOf(android.Manifest.permission.NETWORK_SETTINGS,
5387                     android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
5388                     android.Manifest.permission.NETWORK_CARRIER_PROVISIONING);
5389         }
5390         mWifiThreadRunner.post(mPasspointManager::clearAnqpRequestsAndFlushCache);
5391     }
5392 }
5393