• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.ScanResult.WIFI_BAND_24_GHZ;
22 import static android.net.wifi.ScanResult.WIFI_BAND_5_GHZ;
23 import static android.net.wifi.ScanResult.WIFI_BAND_6_GHZ;
24 import static android.net.wifi.WifiManager.CHANNEL_DATA_KEY_FREQUENCY_MHZ;
25 import static android.net.wifi.WifiManager.CHANNEL_DATA_KEY_NUM_AP;
26 import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
27 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
28 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
29 import static android.net.wifi.WifiManager.NOT_OVERRIDE_EXISTING_NETWORKS_ON_RESTORE;
30 import static android.net.wifi.WifiManager.PnoScanResultsCallback.REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED;
31 import static android.net.wifi.WifiManager.ROAMING_MODE_AGGRESSIVE;
32 import static android.net.wifi.WifiManager.SAP_START_FAILURE_GENERAL;
33 import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL;
34 import static android.net.wifi.WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS;
35 import static android.net.wifi.WifiManager.VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY;
36 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
37 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
38 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
39 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
40 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
41 import static android.net.wifi.WifiManager.WIFI_INTERFACE_TYPE_AP;
42 import static android.net.wifi.WifiManager.WIFI_INTERFACE_TYPE_AWARE;
43 import static android.net.wifi.WifiManager.WIFI_INTERFACE_TYPE_DIRECT;
44 import static android.net.wifi.WifiManager.WIFI_INTERFACE_TYPE_STA;
45 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
46 import static android.net.wifi.WifiManager.WifiStateChangedListener;
47 import static android.os.Process.WIFI_UID;
48 
49 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY;
50 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED;
51 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_TRANSIENT;
52 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED;
53 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_SIM_INSERTED;
54 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED;
55 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP;
56 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_AP_BRIDGE;
57 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_NAN;
58 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_P2P;
59 import static com.android.server.wifi.HalDeviceManager.HDM_CREATE_IFACE_STA;
60 import static com.android.server.wifi.ScanRequestProxy.createBroadcastOptionsForScanResultsAvailable;
61 import static com.android.server.wifi.SelfRecovery.REASON_API_CALL;
62 import static com.android.server.wifi.WifiSettingsConfigStore.D2D_ALLOWED_WHEN_INFRA_STA_DISABLED;
63 import static com.android.server.wifi.WifiSettingsConfigStore.SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI;
64 import static com.android.server.wifi.WifiSettingsConfigStore.SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI_SET_BY_API;
65 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_AWARE_VERBOSE_LOGGING_ENABLED;
66 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_STA_FACTORY_MAC_ADDRESS;
67 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED;
68 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_WEP_ALLOWED;
69 
70 import android.Manifest;
71 import android.annotation.AnyThread;
72 import android.annotation.CheckResult;
73 import android.annotation.IntDef;
74 import android.annotation.NonNull;
75 import android.annotation.Nullable;
76 import android.app.AppOpsManager;
77 import android.app.admin.DevicePolicyManager;
78 import android.app.admin.WifiSsidPolicy;
79 import android.app.compat.CompatChanges;
80 import android.bluetooth.BluetoothAdapter;
81 import android.content.AttributionSource;
82 import android.content.BroadcastReceiver;
83 import android.content.ComponentName;
84 import android.content.Context;
85 import android.content.Intent;
86 import android.content.IntentFilter;
87 import android.content.ServiceConnection;
88 import android.content.pm.ApplicationInfo;
89 import android.content.pm.PackageInfo;
90 import android.content.pm.PackageManager;
91 import android.content.pm.ResolveInfo;
92 import android.content.res.Resources;
93 import android.hardware.wifi.WifiStatusCode;
94 import android.location.LocationManager;
95 import android.net.DhcpInfo;
96 import android.net.DhcpOption;
97 import android.net.DhcpResultsParcelable;
98 import android.net.InetAddresses;
99 import android.net.MacAddress;
100 import android.net.Network;
101 import android.net.NetworkCapabilities;
102 import android.net.NetworkStack;
103 import android.net.TetheringManager;
104 import android.net.Uri;
105 import android.net.ip.IpClientUtil;
106 import android.net.thread.ThreadNetworkController;
107 import android.net.thread.ThreadNetworkManager;
108 import android.net.wifi.BlockingOption;
109 import android.net.wifi.CoexUnsafeChannel;
110 import android.net.wifi.IActionListener;
111 import android.net.wifi.IBooleanListener;
112 import android.net.wifi.IByteArrayListener;
113 import android.net.wifi.ICoexCallback;
114 import android.net.wifi.IDppCallback;
115 import android.net.wifi.IIntegerListener;
116 import android.net.wifi.IInterfaceCreationInfoCallback;
117 import android.net.wifi.ILastCallerListener;
118 import android.net.wifi.IListListener;
119 import android.net.wifi.ILocalOnlyConnectionStatusListener;
120 import android.net.wifi.ILocalOnlyHotspotCallback;
121 import android.net.wifi.IMacAddressListListener;
122 import android.net.wifi.IMapListener;
123 import android.net.wifi.INetworkRequestMatchCallback;
124 import android.net.wifi.IOnWifiActivityEnergyInfoListener;
125 import android.net.wifi.IOnWifiDriverCountryCodeChangedListener;
126 import android.net.wifi.IOnWifiUsabilityStatsListener;
127 import android.net.wifi.IPnoScanResultsCallback;
128 import android.net.wifi.IScanResultsCallback;
129 import android.net.wifi.ISoftApCallback;
130 import android.net.wifi.IStringListener;
131 import android.net.wifi.ISubsystemRestartCallback;
132 import android.net.wifi.ISuggestionConnectionStatusListener;
133 import android.net.wifi.ISuggestionUserApprovalStatusListener;
134 import android.net.wifi.ITrafficStateCallback;
135 import android.net.wifi.ITwtCallback;
136 import android.net.wifi.ITwtCapabilitiesListener;
137 import android.net.wifi.ITwtStatsListener;
138 import android.net.wifi.IWifiBandsListener;
139 import android.net.wifi.IWifiConnectedNetworkScorer;
140 import android.net.wifi.IWifiLowLatencyLockListener;
141 import android.net.wifi.IWifiManager;
142 import android.net.wifi.IWifiNetworkSelectionConfigListener;
143 import android.net.wifi.IWifiNetworkStateChangedListener;
144 import android.net.wifi.IWifiStateChangedListener;
145 import android.net.wifi.IWifiVerboseLoggingStatusChangedListener;
146 import android.net.wifi.MscsParams;
147 import android.net.wifi.QosPolicyParams;
148 import android.net.wifi.ScanResult;
149 import android.net.wifi.SoftApCapability;
150 import android.net.wifi.SoftApConfiguration;
151 import android.net.wifi.SoftApInfo;
152 import android.net.wifi.SoftApState;
153 import android.net.wifi.WifiAnnotations.WifiStandard;
154 import android.net.wifi.WifiAvailableChannel;
155 import android.net.wifi.WifiBands;
156 import android.net.wifi.WifiClient;
157 import android.net.wifi.WifiConfiguration;
158 import android.net.wifi.WifiContext;
159 import android.net.wifi.WifiInfo;
160 import android.net.wifi.WifiManager;
161 import android.net.wifi.WifiManager.AddNetworkResult;
162 import android.net.wifi.WifiManager.CoexRestriction;
163 import android.net.wifi.WifiManager.DeviceMobilityState;
164 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
165 import android.net.wifi.WifiManager.RoamingMode;
166 import android.net.wifi.WifiManager.SapClientBlockedReason;
167 import android.net.wifi.WifiManager.SuggestionConnectionStatusListener;
168 import android.net.wifi.WifiNetworkSelectionConfig;
169 import android.net.wifi.WifiNetworkSuggestion;
170 import android.net.wifi.WifiScanner;
171 import android.net.wifi.WifiSsid;
172 import android.net.wifi.hotspot2.IProvisioningCallback;
173 import android.net.wifi.hotspot2.OsuProvider;
174 import android.net.wifi.hotspot2.PasspointConfiguration;
175 import android.net.wifi.twt.TwtRequest;
176 import android.net.wifi.twt.TwtSession;
177 import android.net.wifi.twt.TwtSessionCallback;
178 import android.net.wifi.util.Environment;
179 import android.net.wifi.util.ScanResultUtil;
180 import android.net.wifi.util.WifiResourceCache;
181 import android.os.AsyncTask;
182 import android.os.Binder;
183 import android.os.Build;
184 import android.os.Bundle;
185 import android.os.Handler;
186 import android.os.HandlerThread;
187 import android.os.IBinder;
188 import android.os.Looper;
189 import android.os.ParcelFileDescriptor;
190 import android.os.PersistableBundle;
191 import android.os.PowerManager;
192 import android.os.Process;
193 import android.os.RemoteCallbackList;
194 import android.os.RemoteException;
195 import android.os.UserHandle;
196 import android.os.UserManager;
197 import android.os.WorkSource;
198 import android.os.connectivity.WifiActivityEnergyInfo;
199 import android.provider.Settings;
200 import android.telephony.CarrierConfigManager;
201 import android.telephony.PhoneStateListener;
202 import android.telephony.SubscriptionManager;
203 import android.telephony.TelephonyManager;
204 import android.text.TextUtils;
205 import android.util.ArraySet;
206 import android.util.EventLog;
207 import android.util.Log;
208 import android.util.Pair;
209 import android.util.SparseArray;
210 import android.util.SparseIntArray;
211 import android.uwb.UwbManager;
212 
213 import androidx.annotation.RequiresApi;
214 
215 import com.android.internal.annotations.GuardedBy;
216 import com.android.internal.annotations.VisibleForTesting;
217 import com.android.modules.utils.HandlerExecutor;
218 import com.android.modules.utils.ParceledListSlice;
219 import com.android.modules.utils.StringParceledListSlice;
220 import com.android.modules.utils.build.SdkLevel;
221 import com.android.net.module.util.Inet4AddressUtils;
222 import com.android.server.wifi.coex.CoexManager;
223 import com.android.server.wifi.entitlement.PseudonymInfo;
224 import com.android.server.wifi.hotspot2.PasspointManager;
225 import com.android.server.wifi.hotspot2.PasspointProvider;
226 import com.android.server.wifi.proto.WifiStatsLog;
227 import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent;
228 import com.android.server.wifi.util.ActionListenerWrapper;
229 import com.android.server.wifi.util.ApConfigUtil;
230 import com.android.server.wifi.util.FeatureBitsetUtils;
231 import com.android.server.wifi.util.GeneralUtil.Mutable;
232 import com.android.server.wifi.util.LastCallerInfoManager;
233 import com.android.server.wifi.util.RssiUtil;
234 import com.android.server.wifi.util.WifiPermissionsUtil;
235 import com.android.server.wifi.util.WorkSourceHelper;
236 import com.android.wifi.flags.FeatureFlags;
237 import com.android.wifi.resources.R;
238 
239 import org.json.JSONArray;
240 import org.json.JSONException;
241 
242 import java.io.BufferedReader;
243 import java.io.FileDescriptor;
244 import java.io.FileNotFoundException;
245 import java.io.FileReader;
246 import java.io.IOException;
247 import java.io.PrintWriter;
248 import java.lang.annotation.Retention;
249 import java.lang.annotation.RetentionPolicy;
250 import java.net.Inet4Address;
251 import java.net.InetAddress;
252 import java.security.GeneralSecurityException;
253 import java.security.KeyStore;
254 import java.security.cert.CertPath;
255 import java.security.cert.CertPathValidator;
256 import java.security.cert.CertificateFactory;
257 import java.security.cert.PKIXParameters;
258 import java.security.cert.X509Certificate;
259 import java.util.ArrayList;
260 import java.util.Arrays;
261 import java.util.BitSet;
262 import java.util.Collections;
263 import java.util.HashMap;
264 import java.util.HashSet;
265 import java.util.List;
266 import java.util.Map;
267 import java.util.Objects;
268 import java.util.Optional;
269 import java.util.Set;
270 import java.util.concurrent.CountDownLatch;
271 import java.util.concurrent.Executor;
272 import java.util.concurrent.TimeUnit;
273 import java.util.function.BiConsumer;
274 import java.util.function.Consumer;
275 import java.util.function.IntConsumer;
276 
277 /**
278  * WifiService handles remote WiFi operation requests by implementing
279  * the IWifiManager interface.
280  */
281 public class WifiServiceImpl extends IWifiManager.Stub {
282     private static final String TAG = "WifiService";
283     private static final boolean VDBG = false;
284 
285     /** Max wait time for posting blocking runnables */
286     private static final int RUN_WITH_SCISSORS_TIMEOUT_MILLIS = 4000;
287     @VisibleForTesting
288     static final int AUTO_DISABLE_SHOW_KEY_COUNTDOWN_MILLIS = 24 * 60 * 60 * 1000;
289     private static final int CHANNEL_USAGE_WEAK_SCAN_RSSI_DBM = -80;
290 
291     private static final int SCORER_BINDING_STATE_INVALID = -1;
292     // The system is brining up the scorer service.
293     private static final int SCORER_BINDING_STATE_BRINGING_UP = 0;
294     private static final int SCORER_BINDING_STATE_CONNECTED = 1;
295     private static final int SCORER_BINDING_STATE_DISCONNECTED = 2;
296     private static final int SCORER_BINDING_STATE_BINDING_DIED = 3;
297     // A null binder is received.
298     private static final int SCORER_BINDING_STATE_NULL_BINDING = 4;
299     // The system couldn't find the service to bind to.
300     private static final int SCORER_BINDING_STATE_NO_SERVICE = 5;
301     // The app has cleared the Wi-Fi scorer. So the service is unbound.
302     private static final int SCORER_BINDING_STATE_CLEARED = 6;
303     // The app has set a new Wi-Fi scorer. Rebind to the service.
304     public static final int SCORER_BINDING_STATE_REBINDING = 7;
305 
306     @IntDef(prefix = { "SCORER_BINDING_STATE_" }, value = {
307         SCORER_BINDING_STATE_INVALID,
308         SCORER_BINDING_STATE_BRINGING_UP,
309         SCORER_BINDING_STATE_CONNECTED,
310         SCORER_BINDING_STATE_DISCONNECTED,
311         SCORER_BINDING_STATE_BINDING_DIED,
312         SCORER_BINDING_STATE_NULL_BINDING,
313         SCORER_BINDING_STATE_NO_SERVICE,
314         SCORER_BINDING_STATE_CLEARED,
315         SCORER_BINDING_STATE_REBINDING
316 
317     })
318     @Retention(RetentionPolicy.SOURCE)
319     private @interface ScorerBindingState {}
320 
321     private @ScorerBindingState int mLastScorerBindingState = SCORER_BINDING_STATE_INVALID;
322     @VisibleForTesting
323     ScorerServiceConnection mScorerServiceConnection;
324 
325     private final ActiveModeWarden mActiveModeWarden;
326     private final ScanRequestProxy mScanRequestProxy;
327 
328     private final WifiContext mContext;
329     private final FrameworkFacade mFacade;
330     private final Clock mClock;
331     private final PowerManager mPowerManager;
332     private final AppOpsManager mAppOps;
333     private final UserManager mUserManager;
334     private final WifiCountryCode mCountryCode;
335 
336     /** Polls traffic stats and notifies clients */
337     private final WifiTrafficPoller mWifiTrafficPoller;
338     /** Tracks the persisted states for wi-fi & airplane mode */
339     private final WifiSettingsStore mSettingsStore;
340     /** Logs connection events and some general router and scan stats */
341     private final WifiMetrics mWifiMetrics;
342 
343     private final WifiInjector mWifiInjector;
344     /** Backup/Restore Module */
345     private final WifiBackupRestore mWifiBackupRestore;
346     private final SoftApBackupRestore mSoftApBackupRestore;
347     private final WifiSettingsBackupRestore mWifiSettingsBackupRestore;
348     private final BackupRestoreController mBackupRestoreController;
349     private final CoexManager mCoexManager;
350     private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager;
351     private final WifiConfigManager mWifiConfigManager;
352     private final HalDeviceManager mHalDeviceManager;
353     private final WifiBlocklistMonitor mWifiBlocklistMonitor;
354     private final PasspointManager mPasspointManager;
355     private final WifiLog mLog;
356     private final WifiConnectivityManager mWifiConnectivityManager;
357     private final ConnectHelper mConnectHelper;
358     private final WifiGlobals mWifiGlobals;
359     private final WifiCarrierInfoManager mWifiCarrierInfoManager;
360     private final WifiPseudonymManager mWifiPseudonymManager;
361     private final WifiNetworkFactory mWifiNetworkFactory;
362     private @WifiManager.VerboseLoggingLevel int mVerboseLoggingLevel =
363             WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED;
364     private boolean mVerboseLoggingEnabled = false;
365     private final RemoteCallbackList<IWifiVerboseLoggingStatusChangedListener>
366             mRegisteredWifiLoggingStatusListeners = new RemoteCallbackList<>();
367 
368     private final FrameworkFacade mFrameworkFacade;
369 
370     private final WifiPermissionsUtil mWifiPermissionsUtil;
371 
372     private final TetheredSoftApTracker mTetheredSoftApTracker;
373 
374     private final LohsSoftApTracker mLohsSoftApTracker;
375 
376     private final BuildProperties mBuildProperties;
377 
378     private final DefaultClientModeManager mDefaultClientModeManager;
379 
380     private final WepNetworkUsageController mWepNetworkUsageController;
381 
382     private final FeatureFlags mFeatureFlags;
383     @VisibleForTesting
384     public final CountryCodeTracker mCountryCodeTracker;
385     private final MultiInternetManager mMultiInternetManager;
386     private final DeviceConfigFacade mDeviceConfigFacade;
387     private boolean mIsWifiServiceStarted = false;
388     private static final String PACKAGE_NAME_NOT_AVAILABLE = "Not Available";
389     private static final String CERT_INSTALLER_PKG = "com.android.certinstaller";
390 
391     private final WifiSettingsConfigStore mSettingsConfigStore;
392     private final WifiResourceCache mResourceCache;
393     private boolean mIsUsdSupported = false;
394 
395     /**
396      * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
397      */
398     public final class LocalOnlyRequestorCallback
399             implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback {
400         /**
401          * Called with requesting app has died.
402          */
403         @Override
onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor)404         public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) {
405             mLog.trace("onLocalOnlyHotspotRequestorDeath pid=%")
406                     .c(requestor.getPid()).flush();
407             mLohsSoftApTracker.stopByRequest(requestor);
408         }
409     }
410 
411     /**
412      * Listen for phone call state events to get active data subcription id.
413      */
414     private class WifiPhoneStateListener extends PhoneStateListener {
WifiPhoneStateListener(Looper looper)415         WifiPhoneStateListener(Looper looper) {
416             super(new HandlerExecutor(new Handler(looper)));
417         }
418 
419         @Override
onActiveDataSubscriptionIdChanged(int subId)420         public void onActiveDataSubscriptionIdChanged(int subId) {
421             // post operation to handler thread
422             mWifiThreadRunner.post(() -> {
423                 Log.d(TAG, "OBSERVED active data subscription change, subId: " + subId);
424                 mTetheredSoftApTracker.updateSoftApCapabilityWhenCarrierConfigChanged(subId);
425                 mActiveModeWarden.updateSoftApCapability(
426                         mTetheredSoftApTracker.getSoftApCapability(),
427                         WifiManager.IFACE_IP_MODE_TETHERED);
428             }, this.getClass().getSimpleName() + "#onActiveDataSubscriptionIdChanged");
429         }
430     }
431 
432     private class ScorerServiceConnection implements ServiceConnection {
433         @Override
onServiceConnected(ComponentName name, IBinder binder)434         public void onServiceConnected(ComponentName name, IBinder binder) {
435             Log.i(TAG, "ScorerServiceConnection.onServiceConnected(" + name + ", " + binder + ")");
436             if (binder == null) {
437                 mWifiThreadRunner.post(() -> unbindScorerService(SCORER_BINDING_STATE_NULL_BINDING),
438                         "ScorerServiceConnection#onServiceConnected");
439             } else {
440                 mWifiThreadRunner.post(() -> {
441                     mLastScorerBindingState = SCORER_BINDING_STATE_CONNECTED;
442                 }, "ScorerServiceConnection#onServiceConnected");
443             }
444         }
445         @Override
onServiceDisconnected(ComponentName name)446         public void onServiceDisconnected(ComponentName name) {
447             Log.w(TAG, "ScorerServiceConnection.onServiceDisconnected(" + name + ")");
448             mWifiThreadRunner.post(() -> unbindScorerService(SCORER_BINDING_STATE_DISCONNECTED),
449                     "ScorerServiceConnection#onServiceDisconnected");
450         }
451 
452         @Override
onBindingDied(ComponentName name)453         public void onBindingDied(ComponentName name) {
454             Log.w(TAG, "ScorerServiceConnection.onBindingDied(" + name + ")");
455             mWifiThreadRunner.post(() -> unbindScorerService(SCORER_BINDING_STATE_BINDING_DIED),
456                     "ScorerServiceConnection#onBindingDied");
457         }
458 
459         @Override
onNullBinding(ComponentName name)460         public void onNullBinding(ComponentName name) {
461             Log.i(TAG, "Wifi scorer service " + name + " - onNullBinding");
462             mWifiThreadRunner.post(() -> unbindScorerService(SCORER_BINDING_STATE_NULL_BINDING),
463                     "ScorerServiceConnection#onNullBinding");
464         }
465     }
466 
467     /**
468      * Bind to the scorer service to prevent the process of the external scorer from freezing.
469      */
bindScorerService(int scorerUid)470     private void bindScorerService(int scorerUid) {
471         if (mScorerServiceConnection != null) {
472             Log.i(TAG, "bindScorerService() service is already bound. Unbind it now.");
473             unbindScorerService(SCORER_BINDING_STATE_REBINDING);
474         }
475 
476         mLastScorerBindingState = SCORER_BINDING_STATE_NO_SERVICE;
477         PackageManager pm = mContext.getPackageManager();
478         if (pm == null) {
479             Log.e(TAG, "PackageManager is null!");
480             return;
481         } else {
482             String[] packageNames = pm.getPackagesForUid(scorerUid);
483             for (String packageName : packageNames) {
484                 if (!TextUtils.isEmpty(packageName)) {
485                     mScorerServiceConnection = new ScorerServiceConnection();
486                     if (bindScorerServiceAsSystemUser(packageName, mScorerServiceConnection)) {
487                         mLastScorerBindingState = SCORER_BINDING_STATE_BRINGING_UP;
488                         return;
489                     } else {
490                         unbindScorerService(SCORER_BINDING_STATE_NO_SERVICE);
491                     }
492                 } else {
493                     Log.d(TAG, "bindScorerService() packageName is empty");
494                 }
495             }
496         }
497     }
498 
bindScorerServiceAsSystemUser(@onNull String packageName, @NonNull ServiceConnection serviceConnection)499     private boolean bindScorerServiceAsSystemUser(@NonNull String packageName,
500             @NonNull ServiceConnection serviceConnection) {
501         Intent intent = new Intent("android.wifi.ScorerService");
502         intent.setPackage(packageName);
503         try {
504             if (mContext.bindServiceAsUser(intent, serviceConnection,
505                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
506                     UserHandle.SYSTEM)) {
507                 Log.i(TAG, "bindScorerServiceAsSystemUser(): Bringing up service: " + packageName);
508                 return true;
509             }
510         } catch (SecurityException ex) {
511             Log.e(TAG, "Fail to bindServiceAsSystemUser(): " + ex);
512         } catch (Exception ex) {
513             // Just make sure that it won't crash WiFi process
514             Log.e(TAG, "Fail to bindServiceAsSystemUser(): " + ex);
515         }
516         return false;
517     }
518 
519     /**
520      * Unbind scorer service to let the system freeze the process of the external scorer freely.
521      */
unbindScorerService(@corerBindingState int state)522     private void unbindScorerService(@ScorerBindingState int state) {
523         mLastScorerBindingState = state;
524         if (mScorerServiceConnection != null) {
525             Log.i(TAG, "unbindScorerService(" + state + ")");
526             try {
527                 mContext.unbindService(mScorerServiceConnection);
528             } catch (Exception e) {
529                 Log.e(TAG, "Fail to unbindService! " + e);
530             }
531             mScorerServiceConnection = null;
532         } else {
533             Log.i(TAG, "unbindScorerService(" + state
534                     + ") mScorerServiceConnection is already null.");
535         }
536     }
537 
538     private final WifiLockManager mWifiLockManager;
539     private final WifiMulticastLockManager mWifiMulticastLockManager;
540     private final DppManager mDppManager;
541     private final WifiApConfigStore mWifiApConfigStore;
542     private final WifiThreadRunner mWifiThreadRunner;
543     private final HandlerThread mWifiHandlerThread;
544     private final MemoryStoreImpl mMemoryStoreImpl;
545     private final WifiScoreCard mWifiScoreCard;
546     private final WifiHealthMonitor mWifiHealthMonitor;
547     private final WifiDataStall mWifiDataStall;
548     private final WifiNative mWifiNative;
549     private final SimRequiredNotifier mSimRequiredNotifier;
550     private final MakeBeforeBreakManager mMakeBeforeBreakManager;
551     private final LastCallerInfoManager mLastCallerInfoManager;
552     private final @NonNull WifiDialogManager mWifiDialogManager;
553     private final WifiPulledAtomLogger mWifiPulledAtomLogger;
554 
555     private final SparseArray<WifiDialogManager.DialogHandle> mWifiEnableRequestDialogHandles =
556             new SparseArray<>();
557 
558     private boolean mWifiTetheringDisallowed;
559     private boolean mIsBootComplete;
560     private boolean mIsLocationModeEnabled;
561 
562     private WifiNetworkSelectionConfig mNetworkSelectionConfig;
563     private ApplicationQosPolicyRequestHandler mApplicationQosPolicyRequestHandler;
564     private final AfcManager mAfcManager;
565     private final TwtManager mTwtManager;
566 
567     /**
568      * The wrapper of SoftApCallback is used in WifiService internally.
569      * see: {@code WifiManager.SoftApCallback}
570      */
571     public abstract class SoftApCallbackInternal {
572         /**
573          * see: {@code WifiManager.SoftApCallback#onStateChanged(int, int)}
574          */
onStateChanged(SoftApState state)575         void onStateChanged(SoftApState state) {}
576 
577         /**
578          * The callback which only is used in service internally and pass to WifiManager.
579          * It will base on the change to send corresponding callback as below:
580          * 1. onInfoChanged(SoftApInfo)
581          * 2. onInfoChanged(List<SoftApInfo>)
582          * 3. onConnectedClientsChanged(SoftApInfo, List<WifiClient>)
583          * 4. onConnectedClientsChanged(List<WifiClient>)
584          */
onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged)585         void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
586                 Map<String, List<WifiClient>> clients, boolean isBridged) {}
587 
588         /**
589          * see:
590          * {@code WifiManager.SoftApCallback#onClientsDisconnected(SoftApInfo,
591          * List<WifiClient>)}
592          */
onClientsDisconnected(@onNull SoftApInfo info, @NonNull List<WifiClient> clients)593         void onClientsDisconnected(@NonNull SoftApInfo info,
594                 @NonNull List<WifiClient> clients) {}
595 
596         /**
597          * see: {@code WifiManager.SoftApCallback#onCapabilityChanged(SoftApCapability)}
598          */
onCapabilityChanged(@onNull SoftApCapability softApCapability)599         void onCapabilityChanged(@NonNull SoftApCapability softApCapability) {}
600 
601         /**
602          * see: {@code WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient, int)}
603          */
onBlockedClientConnecting(@onNull WifiClient client, @SapClientBlockedReason int blockedReason)604         void onBlockedClientConnecting(@NonNull WifiClient client,
605                 @SapClientBlockedReason int blockedReason) {}
606 
607         /**
608          * Checks the AttributionSource of a callback and returns true if the AttributionSource
609          * has the correct permissions. This should be extended by child classes.
610          */
checkCallbackPermission(@ullable Object broadcastCookie)611         boolean checkCallbackPermission(@Nullable Object broadcastCookie) {
612             return true;
613         }
614 
615         /**
616          * Notify register the state of soft AP changed.
617          */
notifyRegisterOnStateChanged(RemoteCallbackList<ISoftApCallback> callbacks, SoftApState state)618         public void notifyRegisterOnStateChanged(RemoteCallbackList<ISoftApCallback> callbacks,
619                 SoftApState state) {
620             int itemCount = callbacks.beginBroadcast();
621             for (int i = 0; i < itemCount; i++) {
622                 try {
623                     if (!checkCallbackPermission(callbacks.getBroadcastCookie(i))) {
624                         continue;
625                     }
626                     callbacks.getBroadcastItem(i).onStateChanged(state);
627                 } catch (RemoteException e) {
628                     Log.e(TAG, "onStateChanged: remote exception -- " + e);
629                 }
630             }
631             callbacks.finishBroadcast();
632         }
633 
634        /**
635         * Notify register the connected clients to soft AP changed.
636         *
637         * @param clients connected clients to soft AP
638         */
notifyRegisterOnConnectedClientsOrInfoChanged( RemoteCallbackList<ISoftApCallback> callbacks, Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged)639         public void notifyRegisterOnConnectedClientsOrInfoChanged(
640                 RemoteCallbackList<ISoftApCallback> callbacks, Map<String, SoftApInfo> infos,
641                 Map<String, List<WifiClient>> clients, boolean isBridged) {
642             int itemCount = callbacks.beginBroadcast();
643             for (int i = 0; i < itemCount; i++) {
644                 try {
645                     if (!checkCallbackPermission(callbacks.getBroadcastCookie(i))) {
646                         continue;
647                     }
648                     callbacks.getBroadcastItem(i).onConnectedClientsOrInfoChanged(
649                             ApConfigUtil.deepCopyForSoftApInfoMap(infos),
650                             ApConfigUtil.deepCopyForWifiClientListMap(
651                                     clients), isBridged, false);
652                 } catch (RemoteException e) {
653                     Log.e(TAG, "onConnectedClientsOrInfoChanged: remote exception -- " + e);
654                 }
655             }
656             callbacks.finishBroadcast();
657         }
658 
659         /**
660          * Notify register capability of softap changed.
661          *
662          * @param capability is the softap capability. {@link SoftApCapability}
663          */
notifyRegisterOnCapabilityChanged(RemoteCallbackList<ISoftApCallback> callbacks, SoftApCapability capability)664         public void notifyRegisterOnCapabilityChanged(RemoteCallbackList<ISoftApCallback> callbacks,
665                 SoftApCapability capability) {
666             int itemCount = callbacks.beginBroadcast();
667             for (int i = 0; i < itemCount; i++) {
668                 try {
669                     if (!checkCallbackPermission(callbacks.getBroadcastCookie(i))) {
670                         continue;
671                     }
672                     callbacks.getBroadcastItem(i).onCapabilityChanged(capability);
673                 } catch (RemoteException e) {
674                     Log.e(TAG, "onCapabilityChanged: remote exception -- " + e);
675                 }
676             }
677             callbacks.finishBroadcast();
678         }
679 
680         /**
681          * Notify register there was a client trying to connect but device blocked the client with
682          * specific reason.
683          *
684          * @param client        the currently blocked client.
685          * @param blockedReason one of blocked reason from
686          *                      {@link SapClientBlockedReason}
687          */
notifyRegisterOnBlockedClientConnecting( RemoteCallbackList<ISoftApCallback> callbacks, WifiClient client, int blockedReason)688         public void notifyRegisterOnBlockedClientConnecting(
689                 RemoteCallbackList<ISoftApCallback> callbacks, WifiClient client,
690                 int blockedReason) {
691             int itemCount = callbacks.beginBroadcast();
692             for (int i = 0; i < itemCount; i++) {
693                 try {
694                     if (!checkCallbackPermission(callbacks.getBroadcastCookie(i))) {
695                         continue;
696                     }
697                     callbacks.getBroadcastItem(i).onBlockedClientConnecting(client, blockedReason);
698                 } catch (RemoteException e) {
699                     Log.e(TAG, "onBlockedClientConnecting: remote exception -- " + e);
700                 }
701             }
702             callbacks.finishBroadcast();
703         }
704 
705         /**
706          * Notify register that clients have disconnected from a soft AP instance.
707          *
708          * @param info The {@link SoftApInfo} of the AP.
709          * @param clients The clients that have disconnected from the AP instance specified by
710          *                {@code info}.
711          */
notifyRegisterOnClientsDisconnected( RemoteCallbackList<ISoftApCallback> callbacks, SoftApInfo info, List<WifiClient> clients)712         public void notifyRegisterOnClientsDisconnected(
713                 RemoteCallbackList<ISoftApCallback> callbacks, SoftApInfo info,
714                 List<WifiClient> clients) {
715             int itemCount = callbacks.beginBroadcast();
716             for (int i = 0; i < itemCount; i++) {
717                 try {
718                     if (!checkCallbackPermission(callbacks.getBroadcastCookie(i))) {
719                         continue;
720                     }
721                     callbacks.getBroadcastItem(i).onClientsDisconnected(new SoftApInfo(info),
722                             clients);
723                 } catch (RemoteException e) {
724                     Log.e(TAG, "onClientsDisconnected: remote exception -- " + e);
725                 }
726             }
727             callbacks.finishBroadcast();
728         }
729     }
730 
WifiServiceImpl(WifiContext context, WifiInjector wifiInjector)731     public WifiServiceImpl(WifiContext context, WifiInjector wifiInjector) {
732         mContext = context;
733         mResourceCache = mContext.getResourceCache();
734         mWifiInjector = wifiInjector;
735         mClock = wifiInjector.getClock();
736 
737         mSettingsConfigStore = mWifiInjector.getSettingsConfigStore();
738         mFacade = mWifiInjector.getFrameworkFacade();
739         mWifiMetrics = mWifiInjector.getWifiMetrics();
740         mWifiTrafficPoller = mWifiInjector.getWifiTrafficPoller();
741         mUserManager = mWifiInjector.getUserManager();
742         mCountryCode = mWifiInjector.getWifiCountryCode();
743         mActiveModeWarden = mWifiInjector.getActiveModeWarden();
744         mScanRequestProxy = mWifiInjector.getScanRequestProxy();
745         mSettingsStore = mWifiInjector.getWifiSettingsStore();
746         mPowerManager = mContext.getSystemService(PowerManager.class);
747         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
748         mWifiLockManager = mWifiInjector.getWifiLockManager();
749         mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
750         mWifiBackupRestore = mWifiInjector.getWifiBackupRestore();
751         mSoftApBackupRestore = mWifiInjector.getSoftApBackupRestore();
752         mWifiSettingsBackupRestore = mWifiInjector.getWifiSettingsBackupRestore();
753         mBackupRestoreController = mWifiInjector.getBackupRestoreController();
754         mWifiApConfigStore = mWifiInjector.getWifiApConfigStore();
755         mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
756         mLog = mWifiInjector.makeLog(TAG);
757         mFrameworkFacade = wifiInjector.getFrameworkFacade();
758         mTetheredSoftApTracker = new TetheredSoftApTracker();
759         mActiveModeWarden.registerSoftApCallback(mTetheredSoftApTracker);
760         mLohsSoftApTracker = new LohsSoftApTracker();
761         mActiveModeWarden.registerLohsCallback(mLohsSoftApTracker);
762         mWifiNetworkSuggestionsManager = mWifiInjector.getWifiNetworkSuggestionsManager();
763         mWifiNetworkFactory = mWifiInjector.getWifiNetworkFactory();
764         mDppManager = mWifiInjector.getDppManager();
765         mWifiThreadRunner = mWifiInjector.getWifiThreadRunner();
766         mWifiHandlerThread = mWifiInjector.getWifiHandlerThread();
767         mWifiConfigManager = mWifiInjector.getWifiConfigManager();
768         mHalDeviceManager = mWifiInjector.getHalDeviceManager();
769         mWifiBlocklistMonitor = mWifiInjector.getWifiBlocklistMonitor();
770         mPasspointManager = mWifiInjector.getPasspointManager();
771         mWifiScoreCard = mWifiInjector.getWifiScoreCard();
772         mWifiHealthMonitor = wifiInjector.getWifiHealthMonitor();
773         mMemoryStoreImpl = new MemoryStoreImpl(mContext, mWifiInjector,
774                 mWifiScoreCard,  mWifiHealthMonitor);
775         mWifiConnectivityManager = wifiInjector.getWifiConnectivityManager();
776         mWifiDataStall = wifiInjector.getWifiDataStall();
777         mWifiNative = wifiInjector.getWifiNative();
778         mCoexManager = wifiInjector.getCoexManager();
779         mConnectHelper = wifiInjector.getConnectHelper();
780         mWifiGlobals = wifiInjector.getWifiGlobals();
781         mSimRequiredNotifier = wifiInjector.getSimRequiredNotifier();
782         mWifiCarrierInfoManager = wifiInjector.getWifiCarrierInfoManager();
783         mWifiPseudonymManager = wifiInjector.getWifiPseudonymManager();
784         mMakeBeforeBreakManager = mWifiInjector.getMakeBeforeBreakManager();
785         mLastCallerInfoManager = mWifiInjector.getLastCallerInfoManager();
786         mWifiDialogManager = mWifiInjector.getWifiDialogManager();
787         mBuildProperties = mWifiInjector.getBuildProperties();
788         mDefaultClientModeManager = mWifiInjector.getDefaultClientModeManager();
789         mCountryCodeTracker = new CountryCodeTracker();
790         mWifiTetheringDisallowed = false;
791         mMultiInternetManager = mWifiInjector.getMultiInternetManager();
792         mDeviceConfigFacade = mWifiInjector.getDeviceConfigFacade();
793         mFeatureFlags = mDeviceConfigFacade.getFeatureFlags();
794         mApplicationQosPolicyRequestHandler = mWifiInjector.getApplicationQosPolicyRequestHandler();
795         mWifiPulledAtomLogger = mWifiInjector.getWifiPulledAtomLogger();
796         mAfcManager = mWifiInjector.getAfcManager();
797         mTwtManager = mWifiInjector.getTwtManager();
798         mWepNetworkUsageController = mWifiInjector.getWepNetworkUsageController();
799         if (Environment.isSdkAtLeastB()) {
800             mIsUsdSupported = mContext.getResources().getBoolean(
801                     mContext.getResources().getIdentifier("config_deviceSupportsWifiUsd", "bool",
802                             "android"));
803         }
804     }
805 
806     /**
807      * Check if Wi-Fi needs to be enabled and start it if needed.
808      *
809      * This function is used only at boot time.
810      */
checkAndStartWifi()811     public void checkAndStartWifi() {
812         mWifiThreadRunner.post(() -> {
813             if (!mWifiConfigManager.loadFromStore()) {
814                 Log.e(TAG, "Failed to load from config store");
815             }
816             mWifiConfigManager.incrementNumRebootsSinceLastUse();
817             // config store is read, check if verbose logging is enabled.
818             enableVerboseLoggingInternal(
819                     mSettingsConfigStore.get(WIFI_VERBOSE_LOGGING_ENABLED)
820                             ? WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED
821                             : WifiManager.VERBOSE_LOGGING_LEVEL_DISABLED);
822             // Check if wi-fi needs to be enabled
823             boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
824             Log.i(TAG,
825                     "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled"));
826 
827             mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility().initialize();
828             mWifiInjector.getWifiNotificationManager().createNotificationChannels();
829             // Old design, flag is disabled.
830             if (!mFeatureFlags.wepDisabledInApm()) {
831                 mWifiGlobals.setWepAllowed(mSettingsConfigStore.get(WIFI_WEP_ALLOWED));
832                 // Align the value between config store (i.e.WifiConfigStore.xml) and WifiGlobals.
833                 mSettingsConfigStore.registerChangeListener(WIFI_WEP_ALLOWED,
834                         (key, value) -> {
835                             if (mWifiGlobals.isWepAllowed() != value) {
836                                 handleWepAllowedChanged(value);
837                                 Log.i(TAG, "Wep allowed is changed to "
838                                         + value);
839                             }
840                         },
841                         new Handler(mWifiHandlerThread.getLooper()));
842             }
843             mContext.registerReceiver(
844                     new BroadcastReceiver() {
845                         @Override
846                         public void onReceive(Context context, Intent intent) {
847                             int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE,
848                                     TelephonyManager.SIM_STATE_UNKNOWN);
849                             if (TelephonyManager.SIM_STATE_ABSENT == state) {
850                                 Log.d(TAG, "resetting networks because SIM was removed");
851                                 resetCarrierNetworks(RESET_SIM_REASON_SIM_REMOVED);
852                             }
853                         }
854                     },
855                     new IntentFilter(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED),
856                     null,
857                     new Handler(mWifiHandlerThread.getLooper()));
858 
859             mContext.registerReceiver(
860                     new BroadcastReceiver() {
861                         @Override
862                         public void onReceive(Context context, Intent intent) {
863                             int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE,
864                                     TelephonyManager.SIM_STATE_UNKNOWN);
865                             if (TelephonyManager.SIM_STATE_LOADED == state) {
866                                 Log.d(TAG, "resetting networks because SIM was loaded");
867                                 resetCarrierNetworks(RESET_SIM_REASON_SIM_INSERTED);
868                             }
869                         }
870                     },
871                     new IntentFilter(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED),
872                     null,
873                     new Handler(mWifiHandlerThread.getLooper()));
874 
875             mContext.registerReceiver(
876                     new BroadcastReceiver() {
877                         private int mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
878                         @Override
879                         public void onReceive(Context context, Intent intent) {
880                             final int subId = intent.getIntExtra("subscription",
881                                     SubscriptionManager.INVALID_SUBSCRIPTION_ID);
882                             if (subId != mLastSubId) {
883                                 Log.d(TAG, "resetting networks as default data SIM is changed");
884                                 resetCarrierNetworks(RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED);
885                                 mLastSubId = subId;
886                                 mWifiDataStall.resetPhoneStateListener();
887                             }
888                         }
889                     },
890                     new IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED),
891                     null,
892                     new Handler(mWifiHandlerThread.getLooper()));
893 
894             mContext.registerReceiver(
895                     new BroadcastReceiver() {
896                         @Override
897                         public void onReceive(Context context, Intent intent) {
898                             String countryCode = intent.getStringExtra(
899                                     TelephonyManager.EXTRA_NETWORK_COUNTRY);
900                             Log.d(TAG, "Country code changed to :" + countryCode);
901                             mCountryCode.setTelephonyCountryCodeAndUpdate(countryCode);
902                         }
903                     },
904                     new IntentFilter(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED),
905                     null,
906                     new Handler(mWifiHandlerThread.getLooper()));
907 
908             mContext.registerReceiver(
909                     new BroadcastReceiver() {
910                         @Override
911                         public void onReceive(Context context, Intent intent) {
912                             Log.d(TAG, "locale changed");
913                             resetNotificationManager();
914                             mResourceCache.handleLocaleChange();
915                         }
916                     },
917                     new IntentFilter(Intent.ACTION_LOCALE_CHANGED),
918                     null,
919                     new Handler(mWifiHandlerThread.getLooper()));
920 
921             if (SdkLevel.isAtLeastT()) {
922                 mContext.registerReceiver(
923                         new BroadcastReceiver() {
924                             @Override
925                             public void onReceive(Context context, Intent intent) {
926                                 Log.d(TAG, "user restrictions changed");
927                                 onUserRestrictionsChanged();
928                             }
929                         },
930                         new IntentFilter(UserManager.ACTION_USER_RESTRICTIONS_CHANGED),
931                         null,
932                         new Handler(mWifiHandlerThread.getLooper()));
933                 mWifiTetheringDisallowed = mUserManager.getUserRestrictions()
934                         .getBoolean(UserManager.DISALLOW_WIFI_TETHERING);
935             }
936 
937             // Adding optimizations of only receiving broadcasts when wifi is enabled
938             // can result in race conditions when apps toggle wifi in the background
939             // without active user involvement. Always receive broadcasts.
940             registerForBroadcasts();
941             mInIdleMode = mPowerManager.isDeviceIdleMode();
942 
943             mActiveModeWarden.start();
944             registerForCarrierConfigChange();
945             mWifiInjector.getAdaptiveConnectivityEnabledSettingObserver().initialize();
946             mIsWifiServiceStarted = true;
947         }, TAG + "#checkAndStartWifi");
948     }
949 
setPulledAtomCallbacks()950     private void setPulledAtomCallbacks() {
951         mWifiPulledAtomLogger.setPullAtomCallback(WifiStatsLog.WIFI_MODULE_INFO);
952         mWifiPulledAtomLogger.setPullAtomCallback(WifiStatsLog.WIFI_SETTING_INFO);
953         mWifiPulledAtomLogger.setPullAtomCallback(WifiStatsLog.WIFI_COMPLEX_SETTING_INFO);
954         mWifiPulledAtomLogger.setPullAtomCallback(WifiStatsLog.WIFI_CONFIGURED_NETWORK_INFO);
955     }
956 
updateLocationMode()957     private void updateLocationMode() {
958         mIsLocationModeEnabled = mWifiPermissionsUtil.isLocationModeEnabled();
959         mWifiConnectivityManager.setLocationModeEnabled(mIsLocationModeEnabled);
960         mWifiNative.setLocationModeEnabled(mIsLocationModeEnabled);
961     }
962 
963     /**
964      * Find which user restrictions have changed and take corresponding actions
965      */
966     @VisibleForTesting
onUserRestrictionsChanged()967     public void onUserRestrictionsChanged() {
968         final Bundle restrictions = mUserManager.getUserRestrictions();
969         final boolean newWifiTetheringDisallowed =
970                 restrictions.getBoolean(UserManager.DISALLOW_WIFI_TETHERING);
971 
972         if (newWifiTetheringDisallowed != mWifiTetheringDisallowed) {
973             if (newWifiTetheringDisallowed) {
974                 mLog.info("stopSoftAp DISALLOW_WIFI_TETHERING set").flush();
975                 stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
976             }
977             mWifiTetheringDisallowed = newWifiTetheringDisallowed;
978         }
979     }
980 
resetCarrierNetworks(@lientModeImpl.ResetSimReason int resetReason)981     private void resetCarrierNetworks(@ClientModeImpl.ResetSimReason int resetReason) {
982         mResourceCache.reset();
983         Log.d(TAG, "resetting carrier networks since SIM was changed");
984         if (resetReason == RESET_SIM_REASON_SIM_INSERTED) {
985             // clear all SIM related notifications since some action was taken to address
986             // "missing" SIM issue
987             mSimRequiredNotifier.dismissSimRequiredNotification();
988         } else {
989             mWifiConfigManager.resetSimNetworks();
990             mWifiNetworkSuggestionsManager.resetSimNetworkSuggestions();
991             mPasspointManager.resetSimPasspointNetwork();
992             mWifiConfigManager.stopRestrictingAutoJoinToSubscriptionId();
993         }
994 
995         // do additional handling if we are current connected to a sim auth network
996         for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) {
997             cmm.resetSimAuthNetworks(resetReason);
998         }
999         mWifiThreadRunner.post(mWifiNetworkSuggestionsManager::updateCarrierPrivilegedApps,
1000                 TAG + "#resetCarrierNetworks$1");
1001         if (resetReason == RESET_SIM_REASON_SIM_INSERTED) {
1002             // clear the blocklists in case any SIM based network were disabled due to the SIM
1003             // not being available.
1004             mWifiConfigManager.enableTemporaryDisabledNetworks();
1005             mWifiConnectivityManager.forceConnectivityScan(ClientModeImpl.WIFI_WORK_SOURCE);
1006         } else {
1007             // Remove ephemeral carrier networks from Carrier unprivileged Apps, which will lead to
1008             // a disconnection. Privileged App will handle by the
1009             // mWifiNetworkSuggestionsManager#updateCarrierPrivilegedApps
1010             mWifiThreadRunner.post(() -> mWifiConfigManager
1011                     .removeEphemeralCarrierNetworks(mWifiCarrierInfoManager
1012                             .getCurrentCarrierPrivilegedPackages()),
1013                     TAG + "#resetCarrierNetworks$2");
1014         }
1015     }
1016 
handleBootCompleted()1017     public void handleBootCompleted() {
1018         mWifiThreadRunner.post(() -> {
1019             Log.d(TAG, "Handle boot completed");
1020             mIsBootComplete = true;
1021             // Register for system broadcasts.
1022             IntentFilter intentFilter = new IntentFilter();
1023             intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1024             intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1025             intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
1026             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
1027             intentFilter.addAction(Intent.ACTION_SHUTDOWN);
1028             mContext.registerReceiver(
1029                     new BroadcastReceiver() {
1030                         @Override
1031                         public void onReceive(Context context, Intent intent) {
1032                             String action = intent.getAction();
1033                             if (Intent.ACTION_USER_REMOVED.equals(action)) {
1034                                 UserHandle userHandle =
1035                                         intent.getParcelableExtra(Intent.EXTRA_USER);
1036                                 if (userHandle == null) {
1037                                     Log.e(TAG,
1038                                             "User removed broadcast received with no user handle");
1039                                     return;
1040                                 }
1041                                 mWifiConfigManager
1042                                         .removeNetworksForUser(userHandle.getIdentifier());
1043                             } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED
1044                                     .equals(action)) {
1045                                 int state = intent.getIntExtra(
1046                                         BluetoothAdapter.EXTRA_CONNECTION_STATE,
1047                                         BluetoothAdapter.STATE_DISCONNECTED);
1048                                 boolean isConnected =
1049                                         state != BluetoothAdapter.STATE_DISCONNECTED;
1050                                 mWifiGlobals.setBluetoothConnected(isConnected);
1051                                 for (ClientModeManager cmm :
1052                                         mActiveModeWarden.getClientModeManagers()) {
1053                                     cmm.onBluetoothConnectionStateChanged();
1054                                 }
1055                             } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
1056                                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
1057                                         BluetoothAdapter.STATE_OFF);
1058                                 boolean isEnabled = state != BluetoothAdapter.STATE_OFF;
1059                                 mWifiGlobals.setBluetoothEnabled(isEnabled);
1060                                 for (ClientModeManager cmm :
1061                                         mActiveModeWarden.getClientModeManagers()) {
1062                                     cmm.onBluetoothConnectionStateChanged();
1063                                 }
1064                             } else if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED
1065                                     .equals(action)) {
1066                                 handleIdleModeChanged();
1067                             } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
1068                                 handleShutDown();
1069                             }
1070                         }
1071                     },
1072                     intentFilter,
1073                     null,
1074                     new Handler(mWifiHandlerThread.getLooper()));
1075             mMemoryStoreImpl.start();
1076             mPasspointManager.initializeProvisioner(
1077                     mWifiInjector.getPasspointProvisionerHandlerThread().getLooper());
1078             mWifiInjector.getWifiNetworkFactory().register();
1079             mWifiInjector.getUntrustedWifiNetworkFactory().register();
1080             mWifiInjector.getRestrictedWifiNetworkFactory().register();
1081             mWifiInjector.getOemWifiNetworkFactory().register();
1082             mWifiInjector.getMultiInternetWifiNetworkFactory().register();
1083             mWifiInjector.getWifiP2pConnection().handleBootCompleted();
1084             // Start to listen country code change to avoid query supported channels causes boot
1085             // time increased.
1086             mCountryCode.registerListener(mCountryCodeTracker);
1087             mWifiInjector.getSarManager().handleBootCompleted();
1088             mWifiInjector.getSsidTranslator().handleBootCompleted();
1089             mWifiInjector.getPasspointManager().handleBootCompleted();
1090             mWifiInjector.getInterfaceConflictManager().handleBootCompleted();
1091             mWifiInjector.getHalDeviceManager().handleBootCompleted();
1092             // HW capabilities is ready after boot completion.
1093             if (!mWifiGlobals.isInsecureEnterpriseConfigurationAllowed()) {
1094                 mWifiConfigManager.updateTrustOnFirstUseFlag(isTrustOnFirstUseSupported());
1095             }
1096             updateVerboseLoggingEnabled();
1097             mWifiInjector.getWifiDeviceStateChangeManager().handleBootCompleted();
1098             if (mFeatureFlags.wepDisabledInApm()
1099                     && mWepNetworkUsageController != null) {
1100                 mWepNetworkUsageController.handleBootCompleted();
1101             }
1102             setPulledAtomCallbacks();
1103             mTwtManager.registerWifiNativeTwtEvents();
1104             mContext.registerReceiverForAllUsers(
1105                     new BroadcastReceiver() {
1106                         @Override
1107                         public void onReceive(Context context, Intent intent) {
1108                             if (mVerboseLoggingEnabled) {
1109                                 Log.v(TAG, "onReceive: MODE_CHANGED_ACTION: intent=" + intent);
1110                             }
1111                             updateLocationMode();
1112                         }
1113                     },
1114                     new IntentFilter(LocationManager.MODE_CHANGED_ACTION),
1115                     null,
1116                     new Handler(mWifiHandlerThread.getLooper()));
1117             updateLocationMode();
1118 
1119             if (SdkLevel.isAtLeastT()) {
1120                 UwbManager uwbManager =
1121                         mContext.getSystemService(UwbManager.class);
1122                 if (uwbManager != null) {
1123                     uwbManager.registerAdapterStateCallback(new HandlerExecutor(new Handler(
1124                             mWifiHandlerThread.getLooper())), new UwbAdapterStateListener());
1125                 }
1126             }
1127 
1128             if (SdkLevel.isAtLeastV()) {
1129                 ThreadNetworkManager threadManager =
1130                         mContext.getSystemService(ThreadNetworkManager.class);
1131                 if (threadManager != null) {
1132                     List<ThreadNetworkController> threadNetworkControllers =
1133                             threadManager.getAllThreadNetworkControllers();
1134                     if (threadNetworkControllers.size() > 0) {
1135                         ThreadNetworkController threadNetworkController =
1136                                 threadNetworkControllers.get(0);
1137                         if (threadNetworkController != null) {
1138                             threadNetworkController.registerStateCallback(
1139                                 new HandlerExecutor(new Handler(mWifiHandlerThread.getLooper())),
1140                                 new ThreadStateListener());
1141                         }
1142                     }
1143                 }
1144             }
1145         }, TAG + "#handleBootCompleted");
1146     }
1147 
handleUserSwitch(int userId)1148     public void handleUserSwitch(int userId) {
1149         Log.d(TAG, "Handle user switch " + userId);
1150 
1151         mWifiThreadRunner.post(() -> {
1152             mWifiConfigManager.handleUserSwitch(userId);
1153             resetNotificationManager();
1154         }, TAG + "#handleUserSwitch");
1155     }
1156 
handleUserUnlock(int userId)1157     public void handleUserUnlock(int userId) {
1158         Log.d(TAG, "Handle user unlock " + userId);
1159         mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserUnlock(userId),
1160                 TAG + "#handleUserUnlock");
1161     }
1162 
handleUserStop(int userId)1163     public void handleUserStop(int userId) {
1164         Log.d(TAG, "Handle user stop " + userId);
1165         mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserStop(userId),
1166                 TAG + "#handleUserStop");
1167     }
1168 
1169     /**
1170      * See {@link android.net.wifi.WifiManager#startScan}
1171      *
1172      * @param packageName Package name of the app that requests wifi scan.
1173      * @param featureId The feature in the package
1174      */
1175     @Override
startScan(String packageName, String featureId)1176     public boolean startScan(String packageName, String featureId) {
1177         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1178             return false;
1179         }
1180         int callingUid = Binder.getCallingUid();
1181         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
1182 
1183         long ident = Binder.clearCallingIdentity();
1184         mLog.info("startScan uid=%").c(callingUid).flush();
1185         synchronized (this) {
1186             if (mInIdleMode) {
1187                 // Need to send an immediate scan result broadcast in case the
1188                 // caller is waiting for a result ..
1189 
1190                 // TODO: investigate if the logic to cancel scans when idle can move to
1191                 // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
1192                 // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
1193                 // be sent directly until b/31398592 is fixed.
1194                 sendFailedScanBroadcast();
1195                 mScanPending = true;
1196                 return false;
1197             }
1198         }
1199         try {
1200             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
1201                     null);
1202             mLastCallerInfoManager.put(WifiManager.API_START_SCAN, Process.myTid(),
1203                     callingUid, Binder.getCallingPid(), packageName, true);
1204             Boolean scanSuccess = mWifiThreadRunner.call(() ->
1205                     mScanRequestProxy.startScan(callingUid, packageName), null,
1206                     TAG + "#startScan");
1207             if (scanSuccess == null) {
1208                 sendFailedScanBroadcast();
1209                 return false;
1210             }
1211             if (!scanSuccess) {
1212                 Log.e(TAG, "Failed to start scan");
1213                 return false;
1214             }
1215         } catch (SecurityException e) {
1216             Log.w(TAG, "Permission violation - startScan not allowed for"
1217                     + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e);
1218             return false;
1219         } finally {
1220             Binder.restoreCallingIdentity(ident);
1221         }
1222         return true;
1223     }
1224 
1225     // Send a failed scan broadcast to indicate the current scan request failed.
sendFailedScanBroadcast()1226     private void sendFailedScanBroadcast() {
1227         // clear calling identity to send broadcast
1228         long callingIdentity = Binder.clearCallingIdentity();
1229         try {
1230             final boolean scanSucceeded = false;
1231             Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
1232             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1233             intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, scanSucceeded);
1234             mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null,
1235                     createBroadcastOptionsForScanResultsAvailable(scanSucceeded));
1236         } finally {
1237             // restore calling identity
1238             Binder.restoreCallingIdentity(callingIdentity);
1239         }
1240 
1241     }
1242 
1243     /**
1244      * WPS support in Client mode is deprecated.  Return null.
1245      */
1246     @Override
getCurrentNetworkWpsNfcConfigurationToken()1247     public String getCurrentNetworkWpsNfcConfigurationToken() {
1248         // while CLs are in flight, return null here, will be removed (b/72423090)
1249         enforceNetworkStackPermission();
1250         if (mVerboseLoggingEnabled) {
1251             mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%")
1252                     .c(Binder.getCallingUid()).flush();
1253         }
1254         return null;
1255     }
1256 
1257     private boolean mInIdleMode;
1258     private boolean mScanPending;
1259 
handleIdleModeChanged()1260     private void handleIdleModeChanged() {
1261         boolean doScan = false;
1262         synchronized (this) {
1263             boolean idle = mPowerManager.isDeviceIdleMode();
1264             if (mInIdleMode != idle) {
1265                 mInIdleMode = idle;
1266                 if (!idle) { // exiting doze mode
1267                     if (mScanPending) {
1268                         mScanPending = false;
1269                         doScan = true;
1270                     }
1271                 }
1272                 mActiveModeWarden.onIdleModeChanged(idle);
1273             }
1274         }
1275         if (doScan) {
1276             // Someone requested a scan while we were idle; do a full scan now.
1277             // A security check of the caller's identity was made when the request arrived via
1278             // Binder. Now we'll pass the current process's identity to startScan().
1279             startScan(mContext.getOpPackageName(), mContext.getAttributionTag());
1280         }
1281     }
1282 
handleShutDown()1283     private void handleShutDown() {
1284         if (mVerboseLoggingEnabled) {
1285             Log.v(TAG, "handleShutDown");
1286         }
1287         // Direct call to notify ActiveModeWarden as soon as possible with the assumption that
1288         // notifyShuttingDown() doesn't have codes that may cause concurrentModificationException,
1289         // e.g., access to a collection.
1290         mActiveModeWarden.notifyShuttingDown();
1291 
1292         // There is no explicit disconnection event in clientModeImpl during shutdown.
1293         // Call resetConnectionState() so that connection duration is calculated
1294         // before memory store write triggered by mMemoryStoreImpl.stop().
1295         mWifiScoreCard.resetAllConnectionStates();
1296         mMemoryStoreImpl.stop();
1297         mWifiConfigManager.writeDataToStorage();
1298         mWifiNetworkSuggestionsManager.handleShutDown();
1299     }
1300 
checkNetworkSettingsPermission(int pid, int uid)1301     private boolean checkNetworkSettingsPermission(int pid, int uid) {
1302         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
1303                 == PERMISSION_GRANTED;
1304     }
1305 
checkNetworkSetupWizardPermission(int pid, int uid)1306     private boolean checkNetworkSetupWizardPermission(int pid, int uid) {
1307         return mContext.checkPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, pid, uid)
1308                 == PackageManager.PERMISSION_GRANTED;
1309     }
1310 
checkMainlineNetworkStackPermission(int pid, int uid)1311     private boolean checkMainlineNetworkStackPermission(int pid, int uid) {
1312         return mContext.checkPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid)
1313                 == PackageManager.PERMISSION_GRANTED;
1314     }
1315 
checkNetworkStackPermission(int pid, int uid)1316     private boolean checkNetworkStackPermission(int pid, int uid) {
1317         return mContext.checkPermission(android.Manifest.permission.NETWORK_STACK, pid, uid)
1318                 == PackageManager.PERMISSION_GRANTED;
1319     }
1320 
checkNetworkManagedProvisioningPermission(int pid, int uid)1321     private boolean checkNetworkManagedProvisioningPermission(int pid, int uid) {
1322         return mContext.checkPermission(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
1323                 pid, uid) == PackageManager.PERMISSION_GRANTED;
1324     }
1325 
checkManageDeviceAdminsPermission(int pid, int uid)1326     private boolean checkManageDeviceAdminsPermission(int pid, int uid) {
1327         return mContext.checkPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS,
1328                 pid, uid) == PackageManager.PERMISSION_GRANTED;
1329     }
1330 
1331     /**
1332      * Helper method to check if the entity initiating the binder call has any of the signature only
1333      * permissions. Not to be confused with the concept of privileged apps, which are system apps
1334      * with allow-listed "privileged" permissions.
1335      */
isPrivileged(int pid, int uid)1336     private boolean isPrivileged(int pid, int uid) {
1337         return checkNetworkSettingsPermission(pid, uid)
1338                 || checkNetworkSetupWizardPermission(pid, uid)
1339                 || checkNetworkStackPermission(pid, uid)
1340                 || checkNetworkManagedProvisioningPermission(pid, uid)
1341                 || mWifiPermissionsUtil.isSignedWithPlatformKey(uid);
1342     }
1343 
1344     /**
1345      * Helper method to check if the entity initiating the binder call has setup wizard or settings
1346      * permissions.
1347      */
isSettingsOrSuw(int pid, int uid)1348     private boolean isSettingsOrSuw(int pid, int uid) {
1349         return checkNetworkSettingsPermission(pid, uid)
1350                 || checkNetworkSetupWizardPermission(pid, uid);
1351     }
1352 
1353     /** Helper method to check if the entity initiating the binder call is a DO/PO app. */
isDeviceOrProfileOwner(int uid, String packageName)1354     private boolean isDeviceOrProfileOwner(int uid, String packageName) {
1355         return mWifiPermissionsUtil.isDeviceOwner(uid, packageName)
1356                 || mWifiPermissionsUtil.isProfileOwner(uid, packageName);
1357     }
1358 
enforceNetworkSettingsPermission()1359     private void enforceNetworkSettingsPermission() {
1360         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
1361                 "WifiService");
1362     }
1363 
checkAnyPermissionOf(String... permissions)1364     private boolean checkAnyPermissionOf(String... permissions) {
1365         for (String permission : permissions) {
1366             if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
1367                 return true;
1368             }
1369         }
1370         return false;
1371     }
1372 
enforceAnyPermissionOf(String... permissions)1373     private void enforceAnyPermissionOf(String... permissions) {
1374         if (!checkAnyPermissionOf(permissions)) {
1375             throw new SecurityException("Requires one of the following permissions: "
1376                     + String.join(", ", permissions) + ".");
1377         }
1378     }
1379 
enforceNetworkStackPermission()1380     private void enforceNetworkStackPermission() {
1381         // TODO(b/142554155): Only check for MAINLINE_NETWORK_STACK permission
1382         boolean granted = mContext.checkCallingOrSelfPermission(
1383                 android.Manifest.permission.NETWORK_STACK)
1384                 == PackageManager.PERMISSION_GRANTED;
1385         if (granted) {
1386             return;
1387         }
1388         mContext.enforceCallingOrSelfPermission(
1389                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "WifiService");
1390     }
1391 
enforceAccessPermission()1392     private void enforceAccessPermission() {
1393         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
1394                 "WifiService");
1395     }
1396 
enforceRestartWifiSubsystemPermission()1397     private void enforceRestartWifiSubsystemPermission() {
1398         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RESTART_WIFI_SUBSYSTEM,
1399                 "WifiService");
1400     }
1401 
1402     /**
1403      * Checks whether the caller can change the wifi state.
1404      * Possible results:
1405      * 1. Operation is allowed. No exception thrown, and AppOpsManager.MODE_ALLOWED returned.
1406      * 2. Operation is not allowed, and caller must be told about this. SecurityException is thrown.
1407      * 3. Operation is not allowed, and caller must not be told about this (i.e. must silently
1408      * ignore the operation). No exception is thrown, and AppOpsManager.MODE_IGNORED returned.
1409      */
1410     @CheckResult
enforceChangePermission(String callingPackage)1411     private int enforceChangePermission(String callingPackage) {
1412         mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
1413         if (checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())) {
1414             return MODE_ALLOWED;
1415         }
1416         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
1417                 "WifiService");
1418 
1419         return mAppOps.noteOp(
1420                 AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Binder.getCallingUid(), callingPackage);
1421     }
1422 
enforceReadCredentialPermission()1423     private void enforceReadCredentialPermission() {
1424         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
1425                                                 "WifiService");
1426     }
1427 
enforceMulticastChangePermission()1428     private void enforceMulticastChangePermission() {
1429         mContext.enforceCallingOrSelfPermission(
1430                 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
1431                 "WifiService");
1432     }
1433 
enforceConnectivityInternalPermission()1434     private void enforceConnectivityInternalPermission() {
1435         mContext.enforceCallingOrSelfPermission(
1436                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
1437                 "ConnectivityService");
1438     }
1439 
enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)1440     private void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) {
1441         mWifiPermissionsUtil.enforceLocationPermission(pkgName, featureId, uid);
1442     }
1443 
enforceCoarseLocationPermission(@ullable String pkgName, @Nullable String featureId, int uid)1444     private void enforceCoarseLocationPermission(@Nullable String pkgName,
1445             @Nullable String featureId, int uid) {
1446         mWifiPermissionsUtil.enforceCoarseLocationPermission(pkgName, featureId, uid);
1447     }
1448 
enforceLocationPermissionInManifest(int uid, boolean isCoarseOnly)1449     private void enforceLocationPermissionInManifest(int uid, boolean isCoarseOnly) {
1450         mWifiPermissionsUtil.enforceLocationPermissionInManifest(uid, isCoarseOnly);
1451     }
1452 
1453     /**
1454      * Validates if the calling user is valid.
1455      *
1456      * @throws a {@link SecurityException} if the calling user is not valid.
1457      */
enforceValidCallingUser()1458     private void enforceValidCallingUser() {
1459         if (!isValidCallingUser()) {
1460             throw new SecurityException(
1461                     "Calling user " + Binder.getCallingUserHandle() + " is not the SYSTEM user, "
1462                             + "the current user, or a profile of the current user, "
1463                             + "thus not allowed to make changes to WIFI.");
1464         }
1465     }
1466 
1467     /**
1468      * Checks if the calling user is valid on Automotive devices..
1469      *
1470      * @return true if any of the following conditions are true:
1471      *     <li>The device is not an Automotive device.
1472      *     <li>the calling user is the system user.
1473      *     <li>the calling user is the current user.
1474      *     <li>the calling user belongs to the same profile group as the current user.
1475      */
isValidCallingUser()1476     private boolean isValidCallingUser() {
1477         // TODO(b/360488316): Ideally UserManager#isVisibleBackgroundUsersEnabled() should be used
1478         // but it is a hidden API. We rely on FEATURE_AUTOMOTIVE only, because we cannot access
1479         // the RRO config for R.bool.config_multiuserVisibleBackgroundUsers.
1480         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
1481             return true;
1482         }
1483         UserHandle callingUser = Binder.getCallingUserHandle();
1484 
1485         final long ident = Binder.clearCallingIdentity();
1486         try {
1487             UserHandle currentUser =
1488                     UserHandle.of(mWifiInjector.getWifiPermissionsWrapper().getCurrentUser());
1489             if (UserHandle.SYSTEM.equals(callingUser)
1490                     || callingUser.equals(currentUser)
1491                     || mUserManager.isSameProfileGroup(callingUser, currentUser)) {
1492                 return true;
1493             }
1494         } finally {
1495             Binder.restoreCallingIdentity(ident);
1496         }
1497 
1498         return false;
1499     }
1500 
1501     /**
1502      * Helper method to check if the app is allowed to access public API's deprecated in
1503      * {@link Build.VERSION_CODES#Q}.
1504      * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name.
1505      */
isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid)1506     private boolean isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid) {
1507         return (mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q, uid)
1508                 && !isGuestUser())
1509                 || isPrivileged(pid, uid)
1510                 || mWifiPermissionsUtil.isAdmin(uid, packageName)
1511                 || mWifiPermissionsUtil.isSystem(packageName, uid);
1512     }
1513 
isGuestUser()1514     private boolean isGuestUser() {
1515         long ident = Binder.clearCallingIdentity();
1516         try {
1517             return mWifiPermissionsUtil.isGuestUser();
1518         } finally {
1519             Binder.restoreCallingIdentity(ident);
1520         }
1521     }
1522 
1523     /**
1524      * Helper method to check if the app is allowed to access public API's deprecated in
1525      * {@link Build.VERSION_CODES#R}.
1526      * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name.
1527      */
isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid)1528     private boolean isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid) {
1529         return (mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.R, uid)
1530                 && !isGuestUser())
1531                 || isPrivileged(pid, uid)
1532                 || mWifiPermissionsUtil.isAdmin(uid, packageName)
1533                 || mWifiPermissionsUtil.isSystem(packageName, uid);
1534     }
1535 
isPlatformOrTargetSdkLessThanT(String packageName, int uid)1536     private boolean isPlatformOrTargetSdkLessThanT(String packageName, int uid) {
1537         if (!SdkLevel.isAtLeastT()) {
1538             return true;
1539         }
1540         return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.TIRAMISU,
1541                 uid);
1542     }
1543 
isPlatformOrTargetSdkLessThanU(String packageName, int uid)1544     private boolean isPlatformOrTargetSdkLessThanU(String packageName, int uid) {
1545         if (!SdkLevel.isAtLeastU()) {
1546             return true;
1547         }
1548         return mWifiPermissionsUtil.isTargetSdkLessThan(packageName,
1549                 Build.VERSION_CODES.UPSIDE_DOWN_CAKE, uid);
1550     }
1551 
1552     /**
1553      * Get the current primary ClientModeManager in a thread safe manner, but blocks on the main
1554      * Wifi thread.
1555      */
getPrimaryClientModeManagerBlockingThreadSafe()1556     private ClientModeManager getPrimaryClientModeManagerBlockingThreadSafe() {
1557         return mWifiThreadRunner.call(
1558                 () -> mActiveModeWarden.getPrimaryClientModeManager(),
1559                 mDefaultClientModeManager, TAG + "#getPrimaryClientModeManagerBlockingThreadSafe");
1560     }
1561 
1562     /**
1563      * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
1564      * @param enable {@code true} to enable, {@code false} to disable.
1565      * @return {@code true} if the enable/disable operation was
1566      *         started or is already in the queue.
1567      */
1568     @Override
setWifiEnabled(String packageName, boolean enable)1569     public synchronized boolean setWifiEnabled(String packageName, boolean enable) {
1570         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
1571             return false;
1572         }
1573         enforceValidCallingUser();
1574         int callingUid = Binder.getCallingUid();
1575         int callingPid = Binder.getCallingPid();
1576         boolean isPrivileged = isPrivileged(callingPid, callingUid);
1577         boolean isThirdParty = !isPrivileged
1578                 && !isDeviceOrProfileOwner(callingUid, packageName)
1579                 && !mWifiPermissionsUtil.isSystem(packageName, callingUid);
1580         boolean isTargetSdkLessThanQ = mWifiPermissionsUtil.isTargetSdkLessThan(packageName,
1581                 Build.VERSION_CODES.Q, callingUid) && !isGuestUser();
1582         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
1583         if (isThirdParty && !isTargetSdkLessThanQ) {
1584             mLog.info("setWifiEnabled not allowed for uid=%").c(callingUid).flush();
1585             return false;
1586         }
1587 
1588         // If Satellite mode is enabled, Wifi can not be turned on/off
1589         if (mSettingsStore.isSatelliteModeOn()) {
1590             mLog.info("setWifiEnabled not allowed as satellite mode is on.").flush();
1591             return false;
1592         }
1593 
1594         // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi
1595         if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) {
1596             mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush();
1597             return false;
1598         }
1599 
1600         // Pre-S interface priority is solely based on interface type, which allows STA to delete AP
1601         // for any requester. To prevent non-privileged apps from deleting a tethering AP by
1602         // enabling Wi-Fi, only allow privileged apps to toggle Wi-Fi if tethering AP is up.
1603         if (!SdkLevel.isAtLeastS() && !isPrivileged
1604                 && mTetheredSoftApTracker.getState().getState() == WIFI_AP_STATE_ENABLED) {
1605             mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush();
1606             return false;
1607         }
1608 
1609         long ident = Binder.clearCallingIdentity();
1610         try {
1611             // If user restriction is set, only DO/PO is allowed to toggle wifi
1612             if (SdkLevel.isAtLeastT() && mUserManager.hasUserRestrictionForUser(
1613                     UserManager.DISALLOW_CHANGE_WIFI_STATE,
1614                     UserHandle.getUserHandleForUid(callingUid))
1615                     && !isDeviceOrProfileOwner(callingUid, packageName)) {
1616                 mLog.err(
1617                         "setWifiEnabled with user restriction: only DO/PO can toggle wifi").flush();
1618                 return false;
1619             }
1620         }  finally {
1621             Binder.restoreCallingIdentity(ident);
1622         }
1623 
1624         // Show a user-confirmation dialog for legacy third-party apps targeting less than Q.
1625         if (enable && isTargetSdkLessThanQ && isThirdParty
1626                 && showDialogWhenThirdPartyAppsEnableWifi()) {
1627             mLog.info("setWifiEnabled must show user confirmation dialog for uid=%").c(callingUid)
1628                     .flush();
1629             mWifiThreadRunner.post(() -> {
1630                 if (mActiveModeWarden.getWifiState()
1631                         == WIFI_STATE_ENABLED) {
1632                     // Wi-Fi already enabled; don't need to show dialog.
1633                     return;
1634                 }
1635                 showWifiEnableRequestDialog(callingUid, callingPid, packageName);
1636             }, TAG + "#setWifiEnabled");
1637             return true;
1638         }
1639         setWifiEnabledInternal(packageName, enable, callingUid, callingPid, isPrivileged);
1640         return true;
1641     }
1642 
1643     @AnyThread
setWifiEnabledInternal(String packageName, boolean enable, int callingUid, int callingPid, boolean isPrivileged)1644     private void setWifiEnabledInternal(String packageName, boolean enable,
1645             int callingUid, int callingPid, boolean isPrivileged) {
1646         mLog.info("setWifiEnabled package=% uid=% enable=% isPrivileged=%").c(packageName)
1647                 .c(callingUid).c(enable).c(isPrivileged).flush();
1648         long ident = Binder.clearCallingIdentity();
1649         try {
1650             if (!mSettingsStore.handleWifiToggled(enable)) {
1651                 // Nothing to do if wifi cannot be toggled
1652                 return;
1653             }
1654         } finally {
1655             Binder.restoreCallingIdentity(ident);
1656         }
1657         if (enable) {
1658             // Clear out all outstanding wifi enable request dialogs.
1659             mWifiThreadRunner.post(() -> {
1660                 for (int i = 0; i < mWifiEnableRequestDialogHandles.size(); i++) {
1661                     mWifiEnableRequestDialogHandles.valueAt(i).dismissDialog();
1662                 }
1663                 mWifiEnableRequestDialogHandles.clear();
1664             }, TAG + "#setWifiEnabledInternal$1");
1665         }
1666         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
1667             if (enable) {
1668                 mWifiThreadRunner.post(
1669                         () -> mWifiConnectivityManager.setAutoJoinEnabledExternal(true, false),
1670                         TAG + "#setWifiEnabledInternal$2");
1671                 mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_ON);
1672             } else {
1673                 WifiInfo wifiInfo = mActiveModeWarden.getConnectionInfo();
1674                 mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_TOGGLE_WIFI_OFF,
1675                         wifiInfo == null ? -1 : wifiInfo.getNetworkId());
1676             }
1677         }
1678         if (!enable) {
1679             mWifiInjector.getInterfaceConflictManager().reset();
1680         }
1681         mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable);
1682         mWifiMetrics.reportWifiStateChanged(enable, mWifiInjector.getWakeupController().isUsable(),
1683                 false);
1684         mActiveModeWarden.wifiToggled(new WorkSource(callingUid, packageName));
1685         mLastCallerInfoManager.put(WifiManager.API_WIFI_ENABLED, Process.myTid(),
1686                 callingUid, callingPid, packageName, enable);
1687     }
1688 
showWifiEnableRequestDialog(int uid, int pid, @NonNull String packageName)1689     private void showWifiEnableRequestDialog(int uid, int pid, @NonNull String packageName) {
1690         String appName;
1691         try {
1692             PackageManager pm = mContext.getPackageManager();
1693             ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
1694             appName = appInfo.loadLabel(pm).toString();
1695         } catch (PackageManager.NameNotFoundException e) {
1696             appName = packageName;
1697         }
1698         WifiDialogManager.SimpleDialogCallback dialogCallback =
1699                 new WifiDialogManager.SimpleDialogCallback() {
1700                     @Override
1701                     public void onPositiveButtonClicked() {
1702                         mLog.info("setWifiEnabled dialog accepted for package=% uid=%")
1703                                 .c(packageName).c(uid).flush();
1704                         mWifiEnableRequestDialogHandles.delete(uid);
1705                         setWifiEnabledInternal(packageName, true, uid, pid, false);
1706                     }
1707 
1708                     @Override
1709                     public void onNegativeButtonClicked() {
1710                         mLog.info("setWifiEnabled dialog declined for package=% uid=%")
1711                                 .c(packageName).c(uid).flush();
1712                         mWifiEnableRequestDialogHandles.delete(uid);
1713                     }
1714 
1715                     @Override
1716                     public void onNeutralButtonClicked() {
1717                         // Not used.
1718                     }
1719 
1720                     @Override
1721                     public void onCancelled() {
1722                         mLog.info("setWifiEnabled dialog cancelled for package=% uid=%")
1723                                 .c(packageName).c(uid).flush();
1724                         mWifiEnableRequestDialogHandles.delete(uid);
1725                     }
1726                 };
1727         Resources res = mContext.getResources();
1728         if (mWifiEnableRequestDialogHandles.get(uid) != null) {
1729             mLog.info("setWifiEnabled dialog already launched for package=% uid=%").c(packageName)
1730                     .c(uid).flush();
1731             return;
1732         }
1733         WifiDialogManager.DialogHandle dialogHandle = mWifiDialogManager.createSimpleDialog(
1734                 res.getString(R.string.wifi_enable_request_dialog_title, appName),
1735                 res.getString(R.string.wifi_enable_request_dialog_message),
1736                 res.getString(R.string.wifi_enable_request_dialog_positive_button),
1737                 res.getString(R.string.wifi_enable_request_dialog_negative_button),
1738                 null /* neutralButtonText */,
1739                 dialogCallback,
1740                 mWifiThreadRunner);
1741         mWifiEnableRequestDialogHandles.put(uid, dialogHandle);
1742         dialogHandle.launchDialog();
1743         mLog.info("setWifiEnabled dialog launched for package=% uid=%").c(packageName)
1744                 .c(uid).flush();
1745     }
1746 
1747     @RequiresApi(Build.VERSION_CODES.S)
1748     @Override
registerSubsystemRestartCallback(ISubsystemRestartCallback callback)1749     public void registerSubsystemRestartCallback(ISubsystemRestartCallback callback) {
1750         if (!SdkLevel.isAtLeastS()) {
1751             throw new UnsupportedOperationException();
1752         }
1753         if (callback == null) {
1754             throw new IllegalArgumentException("Callback is null");
1755         }
1756         enforceAccessPermission();
1757         if (mVerboseLoggingEnabled) {
1758             mLog.info("registerSubsystemRestartCallback uid=%").c(Binder.getCallingUid()).flush();
1759         }
1760 
1761         mWifiThreadRunner.post(() -> {
1762             if (!mActiveModeWarden.registerSubsystemRestartCallback(callback)) {
1763                 Log.e(TAG, "registerSubsystemRestartCallback: Failed to register callback");
1764             }
1765         }, TAG + "#registerSubsystemRestartCallback");
1766     }
1767 
1768     @RequiresApi(Build.VERSION_CODES.S)
1769     @Override
unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback)1770     public void unregisterSubsystemRestartCallback(ISubsystemRestartCallback callback) {
1771         if (!SdkLevel.isAtLeastS()) {
1772             throw new UnsupportedOperationException();
1773         }
1774         if (callback == null) {
1775             throw new IllegalArgumentException("Callback is null");
1776         }
1777         enforceAccessPermission();
1778         if (mVerboseLoggingEnabled) {
1779             mLog.info("unregisterSubsystemRestartCallback uid=%").c(Binder.getCallingUid()).flush();
1780         }
1781         mWifiThreadRunner.post(() -> {
1782             if (!mActiveModeWarden.unregisterSubsystemRestartCallback(callback)) {
1783                 Log.e(TAG, "unregisterSubsystemRestartCallback: Failed to register callback");
1784             }
1785         }, TAG + "#unregisterSubsystemRestartCallback");
1786     }
1787 
1788     /**
1789      * See {@link WifiManager#addWifiNetworkStateChangedListener(
1790      * Executor, WifiManager.WifiNetworkStateChangedListener)}
1791      */
1792     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1793     @Override
addWifiNetworkStateChangedListener(IWifiNetworkStateChangedListener listener)1794     public void addWifiNetworkStateChangedListener(IWifiNetworkStateChangedListener listener) {
1795         if (listener == null) {
1796             throw new IllegalArgumentException();
1797         }
1798         enforceNetworkSettingsPermission();
1799         if (mVerboseLoggingEnabled) {
1800             mLog.info("addWifiNetworkStateChangedListener uid=%").c(Binder.getCallingUid()).flush();
1801         }
1802         mWifiThreadRunner.post(() -> {
1803             mActiveModeWarden.addWifiNetworkStateChangedListener(listener);
1804         }, TAG + "#addWifiNetworkStateChangedListener");
1805     }
1806 
1807     /**
1808      * See {@link WifiManager#removeWifiNetworkStateChangedListener(
1809      * WifiManager.WifiNetworkStateChangedListener)}
1810      * @param listener
1811      */
1812     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
1813     @Override
removeWifiNetworkStateChangedListener(IWifiNetworkStateChangedListener listener)1814     public void removeWifiNetworkStateChangedListener(IWifiNetworkStateChangedListener listener) {
1815         if (listener == null) {
1816             throw new IllegalArgumentException();
1817         }
1818         if (mVerboseLoggingEnabled) {
1819             mLog.info("removeWifiNetworkStateChangedListener uid=%")
1820                     .c(Binder.getCallingUid()).flush();
1821         }
1822         mWifiThreadRunner.post(() -> {
1823             mActiveModeWarden.removeWifiNetworkStateChangedListener(listener);
1824         }, TAG + "#removeWifiNetworkStateChangedListener");
1825     }
1826 
1827     @RequiresApi(Build.VERSION_CODES.S)
1828     @Override
restartWifiSubsystem()1829     public void restartWifiSubsystem() {
1830         if (!SdkLevel.isAtLeastS()) {
1831             throw new UnsupportedOperationException();
1832         }
1833         enforceRestartWifiSubsystemPermission();
1834         if (mVerboseLoggingEnabled) {
1835             mLog.info("restartWifiSubsystem uid=%").c(Binder.getCallingUid()).flush();
1836         }
1837         mWifiThreadRunner.post(() -> {
1838             WifiInfo wifiInfo = mActiveModeWarden.getConnectionInfo();
1839             mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_RESTART_WIFI_SUB_SYSTEM,
1840                     wifiInfo == null ? -1 : wifiInfo.getNetworkId());
1841             mWifiInjector.getSelfRecovery().trigger(REASON_API_CALL);
1842         }, TAG + "#restartWifiSubsystem");
1843     }
1844 
1845     /**
1846      * see {@link WifiManager#getWifiState()}
1847      * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
1848      *         {@link WifiManager#WIFI_STATE_DISABLING},
1849      *         {@link WifiManager#WIFI_STATE_ENABLED},
1850      *         {@link WifiManager#WIFI_STATE_ENABLING},
1851      *         {@link WifiManager#WIFI_STATE_UNKNOWN}
1852      */
1853     @Override
getWifiEnabledState()1854     public int getWifiEnabledState() {
1855         enforceAccessPermission();
1856         int state = mActiveModeWarden.getWifiState();
1857         // If the wifi is enabling, call it on the wifi handler to get the state after wifi enabled.
1858         // This is only needed for pre-T.
1859         if (state == WifiManager.WIFI_STATE_ENABLING && !SdkLevel.isAtLeastT()) {
1860             state = mWifiThreadRunner.call(() -> mActiveModeWarden.getWifiState(),
1861                     WifiManager.WIFI_STATE_ENABLING, TAG + "#getWifiEnabledState");
1862         }
1863         if (mVerboseLoggingEnabled) {
1864             mLog.info("getWifiEnabledState uid=% state=%").c(Binder.getCallingUid()).c(
1865                     state).flush();
1866         }
1867         return state;
1868     }
1869 
1870     /**
1871      * See {@link WifiManager#addWifiStateChangedListener(Executor, WifiStateChangedListener)}
1872      */
addWifiStateChangedListener(@onNull IWifiStateChangedListener listener)1873     public void addWifiStateChangedListener(@NonNull IWifiStateChangedListener listener) {
1874         enforceAccessPermission();
1875         if (listener == null) {
1876             throw new IllegalArgumentException("listener must not be null");
1877         }
1878         if (mVerboseLoggingEnabled) {
1879             mLog.info("addWifiStateChangedListener uid=%").c(Binder.getCallingUid()).flush();
1880         }
1881         mWifiThreadRunner.post(() -> mActiveModeWarden.addWifiStateChangedListener(listener),
1882                 TAG + "#addWifiStateChangedListener");
1883     }
1884 
1885     /**
1886      * See {@link WifiManager#removeWifiStateChangedListener(WifiStateChangedListener)}
1887      */
removeWifiStateChangedListener(@onNull IWifiStateChangedListener listener)1888     public void removeWifiStateChangedListener(@NonNull IWifiStateChangedListener listener) {
1889         enforceAccessPermission();
1890         if (listener == null) {
1891             throw new IllegalArgumentException("listener must not be null");
1892         }
1893         if (mVerboseLoggingEnabled) {
1894             mLog.info("removeWifiStateChangedListener uid=%").c(Binder.getCallingUid()).flush();
1895         }
1896         mWifiThreadRunner.post(() -> mActiveModeWarden.removeWifiStateChangedListener(listener),
1897                 TAG + "#removeWifiStateChangedListener");
1898     }
1899 
1900     /**
1901      * see {@link WifiManager#getWifiApState()}
1902      * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
1903      *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
1904      *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
1905      *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
1906      *         {@link WifiManager#WIFI_AP_STATE_FAILED}
1907      */
1908     @Override
getWifiApEnabledState()1909     public int getWifiApEnabledState() {
1910         enforceAccessPermission();
1911         if (mVerboseLoggingEnabled) {
1912             mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
1913         }
1914         return mTetheredSoftApTracker.getState().getState();
1915     }
1916 
1917     /**
1918      * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
1919      *
1920      * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
1921      *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
1922      *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
1923      *
1924      * @param ifaceName String name of the updated interface
1925      * @param mode new operating mode of the interface
1926      *
1927      * @throws SecurityException if the caller does not have permission to call update
1928      */
1929     @Override
updateInterfaceIpState(String ifaceName, int mode)1930     public void updateInterfaceIpState(String ifaceName, int mode) {
1931         // NETWORK_STACK is a signature only permission.
1932         enforceNetworkStackPermission();
1933         mLog.info("updateInterfaceIpState uid=%").c(Binder.getCallingUid()).flush();
1934         // hand off the work to our handler thread
1935         mWifiThreadRunner.post(() -> mLohsSoftApTracker.updateInterfaceIpState(ifaceName, mode),
1936                 TAG + "#updateInterfaceIpState");
1937     }
1938 
1939     /**
1940      * see {@link WifiManager#isDefaultCoexAlgorithmEnabled()}
1941      * @return {@code true} if the default coex algorithm is enabled. {@code false} otherwise.
1942      */
1943     @Override
isDefaultCoexAlgorithmEnabled()1944     public boolean isDefaultCoexAlgorithmEnabled() {
1945         return mResourceCache.getBoolean(R.bool.config_wifiDefaultCoexAlgorithmEnabled);
1946     }
1947 
1948     /**
1949      * see {@link android.net.wifi.WifiManager#setCoexUnsafeChannels(List, int)}
1950      * @param unsafeChannels List of {@link CoexUnsafeChannel} to avoid.
1951      * @param restrictions Bitmap of {@link CoexRestriction} specifying the mandatory
1952      *                     uses of the specified channels.
1953      */
1954     @Override
1955     @RequiresApi(Build.VERSION_CODES.S)
setCoexUnsafeChannels( @onNull List<CoexUnsafeChannel> unsafeChannels, int restrictions)1956     public void setCoexUnsafeChannels(
1957             @NonNull List<CoexUnsafeChannel> unsafeChannels, int restrictions) {
1958         if (!SdkLevel.isAtLeastS()) {
1959             throw new UnsupportedOperationException();
1960         }
1961         mContext.enforceCallingOrSelfPermission(
1962                 Manifest.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS, "WifiService");
1963         if (unsafeChannels == null) {
1964             throw new IllegalArgumentException("unsafeChannels cannot be null");
1965         }
1966         if (mResourceCache.getBoolean(R.bool.config_wifiDefaultCoexAlgorithmEnabled)) {
1967             Log.e(TAG, "setCoexUnsafeChannels called but default coex algorithm is enabled");
1968             return;
1969         }
1970         mWifiThreadRunner.post(() ->
1971                 mCoexManager.setCoexUnsafeChannels(unsafeChannels, restrictions),
1972                 TAG + "#setCoexUnsafeChannels");
1973     }
1974 
1975     /**
1976      * See {@link WifiManager#registerCoexCallback(WifiManager.CoexCallback)}
1977      */
1978     @Override
1979     @RequiresApi(Build.VERSION_CODES.S)
registerCoexCallback(@onNull ICoexCallback callback)1980     public void registerCoexCallback(@NonNull ICoexCallback callback) {
1981         if (!SdkLevel.isAtLeastS()) {
1982             throw new UnsupportedOperationException();
1983         }
1984         mContext.enforceCallingOrSelfPermission(
1985                 Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS, "WifiService");
1986         if (callback == null) {
1987             throw new IllegalArgumentException("callback must not be null");
1988         }
1989         if (mVerboseLoggingEnabled) {
1990             mLog.info("registerCoexCallback uid=%").c(Binder.getCallingUid()).flush();
1991         }
1992         mWifiThreadRunner.post(() -> mCoexManager.registerRemoteCoexCallback(callback),
1993                 TAG + "#registerCoexCallback");
1994     }
1995 
1996     /**
1997      * Check if input configuration is valid.
1998      *
1999      * Call this before calling {@link startTetheredHotspot(SoftApConfiguration)} or
2000      * {@link #setSoftApConfiguration(softApConfiguration)} to avoid unexpected error duo to
2001      * configuration is invalid.
2002      *
2003      * @param config a configuration would like to be checked.
2004      * @return true if config is valid, otherwise false.
2005      */
2006     @Override
validateSoftApConfiguration(SoftApConfiguration config)2007     public boolean validateSoftApConfiguration(SoftApConfiguration config) {
2008         int uid = Binder.getCallingUid();
2009         boolean privileged = isSettingsOrSuw(Binder.getCallingPid(), uid);
2010         return WifiApConfigStore.validateApWifiConfiguration(
2011                 config, privileged, mContext, mWifiNative);
2012     }
2013 
2014     /**
2015      * See {@link WifiManager#unregisterCoexCallback(WifiManager.CoexCallback)}
2016      */
2017     @Override
2018     @RequiresApi(Build.VERSION_CODES.S)
unregisterCoexCallback(@onNull ICoexCallback callback)2019     public void unregisterCoexCallback(@NonNull ICoexCallback callback) {
2020         if (!SdkLevel.isAtLeastS()) {
2021             throw new UnsupportedOperationException();
2022         }
2023         mContext.enforceCallingOrSelfPermission(
2024                 Manifest.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS, "WifiService");
2025         if (callback == null) {
2026             throw new IllegalArgumentException("callback must not be null");
2027         }
2028         if (mVerboseLoggingEnabled) {
2029             mLog.info("unregisterCoexCallback uid=%").c(Binder.getCallingUid()).flush();
2030         }
2031         mWifiThreadRunner.post(() -> mCoexManager.unregisterRemoteCoexCallback(callback),
2032                 TAG + "#unregisterCoexCallback");
2033     }
2034 
2035     /**
2036      * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
2037      * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
2038      * @return {@code true} if softap start was triggered
2039      * @throws SecurityException if the caller does not have permission to start softap
2040      */
2041     @Override
startSoftAp(WifiConfiguration wifiConfig, String packageName)2042     public boolean startSoftAp(WifiConfiguration wifiConfig, String packageName) {
2043         // NETWORK_STACK is a signature only permission.
2044         enforceNetworkStackPermission();
2045         int callingUid = Binder.getCallingUid();
2046         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
2047 
2048         mLog.info("startSoftAp uid=%").c(callingUid).flush();
2049 
2050         SoftApConfiguration softApConfig = null;
2051         if (wifiConfig != null) {
2052             softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig);
2053             if (softApConfig == null) {
2054                 return false;
2055             }
2056         }
2057 
2058         if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
2059             mLog.err("Tethering is already active or activating.").flush();
2060             return false;
2061         }
2062 
2063         WorkSource requestorWs = new WorkSource(callingUid, packageName);
2064         long id = Binder.clearCallingIdentity();
2065         try {
2066             if (!mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs)) {
2067                 // Take down LOHS if it is up.
2068                 mLohsSoftApTracker.stopAll();
2069             }
2070         } finally {
2071             Binder.restoreCallingIdentity(id);
2072         }
2073 
2074         if (!startSoftApInternal(new SoftApModeConfiguration(
2075                 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
2076                 mTetheredSoftApTracker.getSoftApCapability(),
2077                 mCountryCode.getCountryCode(), null), requestorWs, null)) {
2078             mTetheredSoftApTracker.setFailedWhileEnabling();
2079             return false;
2080         }
2081         mLastCallerInfoManager.put(WifiManager.API_SOFT_AP, Process.myTid(),
2082                 callingUid, Binder.getCallingPid(), packageName, true);
2083         return true;
2084     }
2085 
2086     /**
2087      * see {@link android.net.wifi.WifiManager#startTetheredHotspot(SoftApConfiguration)}
2088      * @param softApConfig SSID, security and channel details as part of SoftApConfiguration
2089      * @return {@code true} if softap start was triggered
2090      * @throws SecurityException if the caller does not have permission to start softap
2091      */
2092     @Override
startTetheredHotspot(@ullable SoftApConfiguration softApConfig, @NonNull String packageName)2093     public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig,
2094             @NonNull String packageName) {
2095         enforceValidCallingUser();
2096 
2097         // NETWORK_STACK is a signature only permission.
2098         enforceNetworkStackPermission();
2099         int callingUid = Binder.getCallingUid();
2100         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
2101 
2102         // If user restriction is set, cannot start softap
2103         if (mWifiTetheringDisallowed) {
2104             mLog.err("startTetheredHotspot with user restriction: not permitted").flush();
2105             return false;
2106         }
2107 
2108         mLog.info("startTetheredHotspot uid=%").c(callingUid).flush();
2109         return startTetheredHotspotInternal(new SoftApModeConfiguration(
2110                 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig,
2111                 mTetheredSoftApTracker.getSoftApCapability(),
2112                 mCountryCode.getCountryCode(), null /* request */), callingUid, packageName, null);
2113     }
2114 
2115     /**
2116      * see {@link WifiManager#startTetheredHotspot(TetheringManager.TetheringRequest, Executor, WifiManager.SoftApCallback)}
2117      * @param request TetheringRequest details of the Soft AP.
2118      * @return {@code true} if softap start was triggered
2119      * @throws SecurityException if the caller does not have permission to start softap
2120      */
2121     @Override
startTetheredHotspotRequest(@onNull TetheringManager.TetheringRequest request, @NonNull ISoftApCallback callback, @NonNull String packageName)2122     public void startTetheredHotspotRequest(@NonNull TetheringManager.TetheringRequest request,
2123             @NonNull ISoftApCallback callback,
2124             @NonNull String packageName) {
2125         if (request == null) {
2126             throw new IllegalArgumentException("TetheringRequest must not be null");
2127         }
2128         if (callback == null) {
2129             throw new IllegalArgumentException("callback must not be null");
2130         }
2131 
2132         enforceValidCallingUser();
2133         // NETWORK_STACK is a signature only permission.
2134         enforceNetworkStackPermission();
2135         int callingUid = Binder.getCallingUid();
2136         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
2137 
2138         // If user restriction is set, cannot start softap
2139         if (mWifiTetheringDisallowed) {
2140             mLog.err("startTetheredHotspotRequest with user restriction: not permitted").flush();
2141             try {
2142                 callback.onStateChanged(new SoftApState(WIFI_AP_STATE_FAILED,
2143                         SAP_START_FAILURE_GENERAL, request, null));
2144             } catch (RemoteException e) {
2145                 Log.e(TAG, "ISoftApCallback.onStateChanged: remote exception -- " + e);
2146             }
2147             return;
2148         }
2149 
2150         mLog.info("startTetheredHotspot uid=%").c(callingUid).flush();
2151         startTetheredHotspotInternal(new SoftApModeConfiguration(
2152                 WifiManager.IFACE_IP_MODE_TETHERED,
2153                 com.android.net.flags.Flags.tetheringWithSoftApConfig()
2154                         ? request.getSoftApConfiguration() : null,
2155                 mTetheredSoftApTracker.getSoftApCapability(),
2156                 mCountryCode.getCountryCode(), request), callingUid, packageName, callback);
2157     }
2158 
2159     /**
2160      * Internal method to start tethered hotspot. Callers of this method should have already checked
2161      * proper permissions beyond the NetworkStack permission.
2162      */
startTetheredHotspotInternal(@onNull SoftApModeConfiguration modeConfig, int callingUid, String packageName, @Nullable ISoftApCallback callback)2163     private boolean startTetheredHotspotInternal(@NonNull SoftApModeConfiguration modeConfig,
2164             int callingUid, String packageName, @Nullable ISoftApCallback callback) {
2165         if (!mTetheredSoftApTracker.setEnablingIfAllowed()) {
2166             mLog.err("Tethering is already active or activating.").flush();
2167             if (callback != null) {
2168                 try {
2169                     callback.onStateChanged(new SoftApState(WIFI_AP_STATE_FAILED,
2170                             SAP_START_FAILURE_GENERAL, modeConfig.getTetheringRequest(), null));
2171                 } catch (RemoteException e) {
2172                     Log.e(TAG, "ISoftApCallback.onStateChanged: remote exception -- " + e);
2173                 }
2174             }
2175             return false;
2176         }
2177 
2178         WorkSource requestorWs = new WorkSource(callingUid, packageName);
2179         long id = Binder.clearCallingIdentity();
2180         try {
2181             if (!mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs)) {
2182                 // Take down LOHS if it is up.
2183                 mLohsSoftApTracker.stopAll();
2184             }
2185         } finally {
2186             Binder.restoreCallingIdentity(id);
2187         }
2188 
2189         if (!startSoftApInternal(modeConfig, requestorWs, callback)) {
2190             mTetheredSoftApTracker.setFailedWhileEnabling();
2191             return false;
2192         }
2193         mLastCallerInfoManager.put(WifiManager.API_TETHERED_HOTSPOT, Process.myTid(),
2194                 callingUid, Binder.getCallingPid(), packageName, true);
2195         return true;
2196     }
2197 
2198     /**
2199      * Internal method to start softap mode. Callers of this method should have already checked
2200      * proper permissions beyond the NetworkStack permission.
2201      */
startSoftApInternal(SoftApModeConfiguration apConfig, WorkSource requestorWs, @Nullable ISoftApCallback callback)2202     private boolean startSoftApInternal(SoftApModeConfiguration apConfig, WorkSource requestorWs,
2203             @Nullable ISoftApCallback callback) {
2204         int uid = Binder.getCallingUid();
2205         boolean privileged = isSettingsOrSuw(Binder.getCallingPid(), uid);
2206         mLog.trace("startSoftApInternal uid=% mode=%")
2207                 .c(uid).c(apConfig.getTargetMode()).flush();
2208 
2209         // null wifiConfig is a meaningful input for CMD_SET_AP; it means to use the persistent
2210         // AP config.
2211         SoftApConfiguration softApConfig = apConfig.getSoftApConfiguration();
2212         if (softApConfig != null
2213                 && (!WifiApConfigStore.validateApWifiConfiguration(
2214                     softApConfig, privileged, mContext, mWifiNative))) {
2215             Log.e(TAG, "Invalid SoftApConfiguration");
2216             if (callback != null) {
2217                 try {
2218                     callback.onStateChanged(new SoftApState(WIFI_AP_STATE_FAILED,
2219                             SAP_START_FAILURE_GENERAL,
2220                             apConfig.getTetheringRequest(), null));
2221                 } catch (RemoteException e) {
2222                     Log.e(TAG, "ISoftApCallback.onStateChanged: remote exception -- " + e);
2223                 }
2224             }
2225             return false;
2226         }
2227         if (apConfig.getTargetMode() == IFACE_IP_MODE_TETHERED) {
2228             mTetheredSoftApTracker.setRequestCallback(callback);
2229         }
2230         mActiveModeWarden.startSoftAp(apConfig, requestorWs);
2231         return true;
2232     }
2233 
2234     /**
2235      * see {@link android.net.wifi.WifiManager#stopSoftAp()}
2236      * @return {@code true} if softap stop was triggered
2237      * @throws SecurityException if the caller does not have permission to stop softap
2238      */
2239     @Override
stopSoftAp()2240     public boolean stopSoftAp() {
2241         enforceValidCallingUser();
2242 
2243         // NETWORK_STACK is a signature only permission.
2244         enforceNetworkStackPermission();
2245 
2246         // only permitted callers are allowed to this point - they must have gone through
2247         // connectivity service since this method is protected with the NETWORK_STACK PERMISSION
2248 
2249         mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
2250 
2251         stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
2252         mLastCallerInfoManager.put(WifiManager.API_SOFT_AP, Process.myTid(),
2253                 Binder.getCallingUid(), Binder.getCallingPid(), "<unknown>", false);
2254         return true;
2255     }
2256 
2257     /**
2258      * Internal method to stop softap mode.
2259      *
2260      * Callers of this method should have already checked
2261      * proper permissions beyond the NetworkStack permission.
2262      *
2263      * @param mode the operating mode of APs to bring down (ex,
2264      *             {@link WifiManager.IFACE_IP_MODE_TETHERED} or
2265      *             {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}).
2266      *             Use {@link WifiManager.IFACE_IP_MODE_UNSPECIFIED} to stop all APs.
2267      */
stopSoftApInternal(int mode)2268     private void stopSoftApInternal(int mode) {
2269         mLog.trace("stopSoftApInternal uid=% mode=%").c(Binder.getCallingUid()).c(mode).flush();
2270 
2271         mActiveModeWarden.stopSoftAp(mode);
2272     }
2273 
2274     /**
2275      * Internal class for tracking country code changed event.
2276      */
2277     @VisibleForTesting
2278     public final class CountryCodeTracker implements WifiCountryCode.ChangeListener {
2279         private final RemoteCallbackList<IOnWifiDriverCountryCodeChangedListener>
2280                 mRegisteredDriverCountryCodeListeners = new RemoteCallbackList<>();
2281 
2282         /**
2283         * Register Driver Country code changed listener.
2284         * Note: Calling API only in handler thread.
2285         *
2286         * @param listener listener for the driver country code changed events.
2287         */
registerDriverCountryCodeChangedListener( @onNull IOnWifiDriverCountryCodeChangedListener listener, @NonNull WifiPermissionsUtil.CallerIdentity identity)2288         public void registerDriverCountryCodeChangedListener(
2289                 @NonNull IOnWifiDriverCountryCodeChangedListener listener,
2290                 @NonNull WifiPermissionsUtil.CallerIdentity identity) {
2291             boolean result = mRegisteredDriverCountryCodeListeners.register(listener, identity);
2292             if (mVerboseLoggingEnabled) {
2293                 Log.i(TAG, "registerDriverCountryCodeChangedListener, listener:" + listener
2294                         + ", CallerIdentity=" + identity.toString() + ", result: " + result);
2295             }
2296         }
2297 
2298 
2299         /**
2300          * Unregister Driver Country code changed listener.
2301          * Note: Calling API only in handler thread.
2302          *
2303          * @param listener listener to remove.
2304          */
unregisterDriverCountryCodeChangedListener( @onNull IOnWifiDriverCountryCodeChangedListener listener)2305         public void unregisterDriverCountryCodeChangedListener(
2306                 @NonNull IOnWifiDriverCountryCodeChangedListener listener) {
2307             boolean result = mRegisteredDriverCountryCodeListeners.unregister(listener);
2308             if (mVerboseLoggingEnabled) {
2309                 Log.i(TAG, "unregisterDriverCountryCodeChangedListener, listener:" + listener
2310                         + ", result:" + result);
2311             }
2312         }
2313 
2314         @Override
onCountryCodeChangePending(@onNull String countryCode)2315         public void onCountryCodeChangePending(@NonNull String countryCode) {
2316             // post operation to handler thread
2317             mWifiThreadRunner.post(() -> {
2318                 if (mTetheredSoftApTracker != null) {
2319                     mTetheredSoftApTracker.notifyNewCountryCodeChangePending(countryCode);
2320                 }
2321                 if (mLohsSoftApTracker != null) {
2322                     mLohsSoftApTracker.notifyNewCountryCodeChangePending(countryCode);
2323                 }
2324             }, this.getClass().getSimpleName() + "#onCountryCodeChangePending");
2325         }
2326 
2327         @Override
onDriverCountryCodeChanged(@ullable String countryCode)2328         public void onDriverCountryCodeChanged(@Nullable String countryCode) {
2329             // post operation to handler thread
2330             mWifiThreadRunner.post(() -> {
2331                 Log.i(TAG, "Receive onDriverCountryCodeChanged to " + countryCode
2332                         + ", update available channel list");
2333                 // Update channel capability when country code is not null.
2334                 // Because the driver country code will reset to null when driver is non-active.
2335                 if (countryCode != null) {
2336                     if (!TextUtils.equals(countryCode,
2337                             mCountryCode.getCurrentDriverCountryCode())) {
2338                         Log.e(TAG, "Country code not consistent! expect " + countryCode + " actual "
2339                                 + mCountryCode.getCurrentDriverCountryCode());
2340                     }
2341                     List<Integer> freqs = new ArrayList<>();
2342                     SparseArray<int[]> channelMap = new SparseArray<>(
2343                             SoftApConfiguration.BAND_TYPES.length);
2344                     for (int band : SoftApConfiguration.BAND_TYPES) {
2345                         if (!ApConfigUtil.isSoftApBandSupported(mContext, band)) {
2346                             continue;
2347                         }
2348                         List<Integer> freqsForBand = ApConfigUtil.getAvailableChannelFreqsForBand(
2349                                 band, mWifiNative, null, true);
2350                         if (freqsForBand != null) {
2351                             freqs.addAll(freqsForBand);
2352                             int[] channel = new int[freqsForBand.size()];
2353                             for (int i = 0; i < freqsForBand.size(); i++) {
2354                                 channel[i] = ScanResult.convertFrequencyMhzToChannelIfSupported(
2355                                         freqsForBand.get(i));
2356                             }
2357                             channelMap.put(band, channel);
2358                         }
2359                     }
2360                     if (!mCountryCode.isDriverCountryCodeWorldMode()
2361                             || TextUtils.isEmpty(mSettingsConfigStore.get(
2362                                     WifiSettingsConfigStore.WIFI_SOFT_AP_COUNTRY_CODE))) {
2363                         // Store Soft AP channels (non-world mode CC or no save before) for
2364                         // reference after a reboot before the driver is up.
2365                         mSettingsConfigStore.put(WifiSettingsConfigStore.WIFI_SOFT_AP_COUNTRY_CODE,
2366                                 countryCode);
2367                         mSettingsConfigStore.put(
2368                                 WifiSettingsConfigStore.WIFI_AVAILABLE_SOFT_AP_FREQS_MHZ,
2369                                 new JSONArray(freqs).toString());
2370                     }
2371                     mTetheredSoftApTracker.updateAvailChannelListInSoftApCapability(countryCode,
2372                             channelMap);
2373                     mLohsSoftApTracker.updateAvailChannelListInSoftApCapability(countryCode,
2374                             channelMap);
2375                     mActiveModeWarden.updateSoftApCapability(
2376                             mTetheredSoftApTracker.getSoftApCapability(),
2377                             WifiManager.IFACE_IP_MODE_TETHERED);
2378                     // TODO: b/197529327 trigger Lohs capability callback & update available
2379                     // channels
2380                     mActiveModeWarden.updateSoftApCapability(
2381                             mLohsSoftApTracker.getSoftApCapability(),
2382                             WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
2383                 }
2384                 if (SdkLevel.isAtLeastT()) {
2385                     int itemCount = mRegisteredDriverCountryCodeListeners.beginBroadcast();
2386                     for (int i = 0; i < itemCount; i++) {
2387                         try {
2388                             WifiPermissionsUtil.CallerIdentity identity =
2389                                     (WifiPermissionsUtil.CallerIdentity)
2390                                     mRegisteredDriverCountryCodeListeners.getBroadcastCookie(i);
2391                             if (!mWifiPermissionsUtil.checkCallersCoarseLocationPermission(
2392                                     identity.getPackageName(), identity.getFeatureId(),
2393                                     identity.getUid(), null)) {
2394                                 Log.i(TAG, "ReceiverIdentity=" + identity.toString()
2395                                         + " doesn't have ACCESS_COARSE_LOCATION permission now");
2396                                 continue;
2397                             }
2398                             if (mVerboseLoggingEnabled) {
2399                                 Log.i(TAG, "onDriverCountryCodeChanged, ReceiverIdentity="
2400                                         + identity.toString());
2401                             }
2402                             mRegisteredDriverCountryCodeListeners.getBroadcastItem(i)
2403                                     .onDriverCountryCodeChanged(countryCode);
2404                         } catch (RemoteException e) {
2405                             Log.e(TAG, "onDriverCountryCodeChanged: remote exception -- " + e);
2406                         }
2407                     }
2408                     mRegisteredDriverCountryCodeListeners.finishBroadcast();
2409                 }
2410                 mAfcManager.onCountryCodeChange(countryCode);
2411             }, this.getClass().getSimpleName() + "#onCountryCodeChangePending");
2412         }
2413     }
2414 
2415     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
2416     class UwbAdapterStateListener implements UwbManager.AdapterStateCallback {
2417         @Override
onStateChanged(int state, int reason)2418         public void onStateChanged(int state, int reason) {
2419             if (mVerboseLoggingEnabled) {
2420                 Log.d(TAG, "UwbManager.AdapterState=" + state);
2421             }
2422             mWifiMetrics.setLastUwbState(state);
2423         }
2424     }
2425 
2426     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
2427     class ThreadStateListener implements ThreadNetworkController.StateCallback {
2428         @Override
onDeviceRoleChanged(int mDeviceRole)2429         public void onDeviceRoleChanged(int mDeviceRole) {
2430             if (mVerboseLoggingEnabled) {
2431                 Log.d(TAG, "ThreadNetworkController.DeviceRole=" + mDeviceRole);
2432             }
2433             mWifiMetrics.setLastThreadDeviceRole(mDeviceRole);
2434         }
2435 
2436         @Override
onPartitionIdChanged(long mPartitionId)2437         public void onPartitionIdChanged(long mPartitionId) {}
2438     }
2439 
2440     /**
2441      * SoftAp callback
2442      */
2443     private class BaseSoftApTracker extends SoftApCallbackInternal {
2444         /**
2445          * State of tethered SoftAP
2446          * One of:  {@link WifiManager#WIFI_AP_STATE_DISABLED},
2447          *          {@link WifiManager#WIFI_AP_STATE_DISABLING},
2448          *          {@link WifiManager#WIFI_AP_STATE_ENABLED},
2449          *          {@link WifiManager#WIFI_AP_STATE_ENABLING},
2450          *          {@link WifiManager#WIFI_AP_STATE_FAILED}
2451          */
2452         private final Object mLock = new Object();
2453         @NonNull
2454         private SoftApState mSoftApState =
2455                 new SoftApState(WIFI_AP_STATE_DISABLED, 0, null, null);
2456         private Map<String, List<WifiClient>> mSoftApConnectedClientsMap = new HashMap();
2457         private Map<String, SoftApInfo> mSoftApInfoMap = new HashMap();
2458         private boolean mIsBridgedMode = false;
2459         // TODO: We need to maintain two capability. One for LTE + SAP and one for WIFI + SAP
2460         protected SoftApCapability mSoftApCapability = null;
2461         protected final RemoteCallbackList<ISoftApCallback> mRegisteredSoftApCallbacks =
2462                 new RemoteCallbackList<>();
2463         // Callback tied to the current SoftAp request.
2464         protected ISoftApCallback mRequestCallback = null;
2465 
getState()2466         public SoftApState getState() {
2467             synchronized (mLock) {
2468                 return mSoftApState;
2469             }
2470         }
2471 
setState(SoftApState softApState)2472         public void setState(SoftApState softApState) {
2473             synchronized (mLock) {
2474                 mSoftApState = softApState;
2475             }
2476         }
2477 
setEnablingIfAllowed()2478         public boolean setEnablingIfAllowed() {
2479             synchronized (mLock) {
2480                 int state = mSoftApState.getState();
2481                 if (state != WIFI_AP_STATE_DISABLED
2482                         && state != WIFI_AP_STATE_FAILED) {
2483                     return false;
2484                 }
2485                 mSoftApState = new SoftApState(
2486                         WIFI_AP_STATE_ENABLING, 0, null, null);
2487                 return true;
2488             }
2489         }
2490 
setFailedWhileEnabling()2491         public void setFailedWhileEnabling() {
2492             synchronized (mLock) {
2493                 int state = mSoftApState.getState();
2494                 if (state == WIFI_AP_STATE_ENABLING) {
2495                     mSoftApState = new SoftApState(
2496                             WIFI_AP_STATE_FAILED, 0, null, null);
2497                 }
2498             }
2499         }
2500 
getConnectedClients()2501         public Map<String, List<WifiClient>> getConnectedClients() {
2502             synchronized (mLock) {
2503                 return mSoftApConnectedClientsMap;
2504             }
2505         }
2506 
getSoftApInfos()2507         public Map<String, SoftApInfo> getSoftApInfos() {
2508             synchronized (mLock) {
2509                 return mSoftApInfoMap;
2510             }
2511         }
2512 
getIsBridgedMode()2513         public boolean getIsBridgedMode() {
2514             synchronized (mLock) {
2515                 return mIsBridgedMode;
2516             }
2517         }
2518 
notifyNewCountryCodeChangePending(@onNull String countryCode)2519         public void notifyNewCountryCodeChangePending(@NonNull String countryCode) {
2520             // If country code not changed, no need to update.
2521             if (mSoftApCapability != null && !TextUtils.equals(mSoftApCapability.getCountryCode(),
2522                     countryCode)) {
2523                 // Country code changed when we can't update channels from HAL, invalidate the soft
2524                 // ap capability for supported channels.
2525                 SoftApCapability newSoftApCapability = new SoftApCapability(
2526                         mSoftApCapability);
2527                 for (int b : SoftApConfiguration.BAND_TYPES) {
2528                     newSoftApCapability.setSupportedChannelList(b, new int[0]);
2529                 }
2530                 // Notify the capability change
2531                 onCapabilityChanged(newSoftApCapability);
2532             }
2533         }
2534 
getSoftApCapability()2535         public SoftApCapability getSoftApCapability() {
2536             synchronized (mLock) {
2537                 if (mSoftApCapability == null) {
2538                     mSoftApCapability = ApConfigUtil.updateCapabilityFromResource(mContext);
2539                     mSoftApCapability = ApConfigUtil.updateCapabilityFromConfigStore(
2540                             mSoftApCapability, mWifiInjector.getSettingsConfigStore());
2541                     // Default country code
2542                     mSoftApCapability = updateSoftApCapabilityWithAvailableChannelList(
2543                             mSoftApCapability, mCountryCode.getCountryCode(), null);
2544                     if (mWifiNative.isMLDApSupportMLO()) {
2545                         mSoftApCapability.setSupportedFeatures(
2546                                 true, SoftApCapability.SOFTAP_FEATURE_MLO);
2547                     }
2548                 }
2549                 return mSoftApCapability;
2550             }
2551         }
2552 
updateSoftApCapabilityWithAvailableChannelList( @onNull SoftApCapability softApCapability, @Nullable String countryCode, @Nullable SparseArray<int[]> channelMap)2553         private SoftApCapability updateSoftApCapabilityWithAvailableChannelList(
2554                 @NonNull SoftApCapability softApCapability, @Nullable String countryCode,
2555                 @Nullable SparseArray<int[]> channelMap) {
2556             if (!mIsBootComplete) {
2557                 // The available channel list is from wificond or HAL.
2558                 // It might be a failure or stuck during wificond or HAL init.
2559                 return softApCapability;
2560             }
2561             if (mCountryCode.getCurrentDriverCountryCode() != null) {
2562                 mSoftApCapability.setCountryCode(countryCode);
2563             }
2564             return ApConfigUtil.updateSoftApCapabilityWithAvailableChannelList(
2565                     softApCapability, mContext, mWifiNative, channelMap);
2566         }
2567 
updateAvailChannelListInSoftApCapability(@ullable String countryCode, @Nullable SparseArray<int[]> channelMap)2568         public void updateAvailChannelListInSoftApCapability(@Nullable String countryCode,
2569                 @Nullable SparseArray<int[]> channelMap) {
2570             onCapabilityChanged(updateSoftApCapabilityWithAvailableChannelList(
2571                     getSoftApCapability(), countryCode, channelMap));
2572         }
2573 
registerSoftApCallback(ISoftApCallback callback, Object cookie)2574         public boolean registerSoftApCallback(ISoftApCallback callback, Object cookie) {
2575             if (!mRegisteredSoftApCallbacks.register(callback, cookie)) {
2576                 return false;
2577             }
2578 
2579             // Update the client about the current state immediately after registering the callback
2580             try {
2581                 callback.onStateChanged(getState());
2582                 callback.onConnectedClientsOrInfoChanged(getSoftApInfos(),
2583                         getConnectedClients(), getIsBridgedMode(), true);
2584                 callback.onCapabilityChanged(getSoftApCapability());
2585             } catch (RemoteException e) {
2586                 Log.e(TAG, "registerSoftApCallback: remote exception -- " + e);
2587             }
2588             return true;
2589         }
2590 
unregisterSoftApCallback(ISoftApCallback callback)2591         public void unregisterSoftApCallback(ISoftApCallback callback) {
2592             mRegisteredSoftApCallbacks.unregister(callback);
2593         }
2594 
2595         /**
2596          * Set the callback to track the state of the current SoftAP request.
2597          */
setRequestCallback(@ullable ISoftApCallback callback)2598         public void setRequestCallback(@Nullable ISoftApCallback callback) {
2599             if (mRequestCallback != null) {
2600                 mRegisteredSoftApCallbacks.unregister(mRequestCallback);
2601             }
2602             mRequestCallback = callback;
2603             if (callback != null) {
2604                 mRegisteredSoftApCallbacks.register(callback);
2605             }
2606         }
2607 
2608         /**
2609          * Called when soft AP state changes.
2610          */
2611         @Override
onStateChanged(SoftApState softApState)2612         public void onStateChanged(SoftApState softApState) {
2613             setState(softApState);
2614             notifyRegisterOnStateChanged(mRegisteredSoftApCallbacks, softApState);
2615         }
2616 
2617         /**
2618          * Called when the connected clients to soft AP changes.
2619          *
2620          * @param clients connected clients to soft AP
2621          */
2622         @Override
onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos, Map<String, List<WifiClient>> clients, boolean isBridged)2623         public void onConnectedClientsOrInfoChanged(Map<String, SoftApInfo> infos,
2624                 Map<String, List<WifiClient>> clients, boolean isBridged) {
2625             synchronized (mLock) {
2626                 mIsBridgedMode = isBridged;
2627                 if (infos.size() == 0 && isBridged) {
2628                     Log.d(TAG, "ShutDown bridged mode, clear isBridged cache in Service");
2629                     mIsBridgedMode = false;
2630                 }
2631                 mSoftApConnectedClientsMap =
2632                         ApConfigUtil.deepCopyForWifiClientListMap(clients);
2633                 mSoftApInfoMap = ApConfigUtil.deepCopyForSoftApInfoMap(infos);
2634             }
2635             notifyRegisterOnConnectedClientsOrInfoChanged(mRegisteredSoftApCallbacks,
2636                     infos, clients, isBridged);
2637         }
2638 
2639         /**
2640          * Called when capability of softap changes.
2641          *
2642          * @param capability is the softap capability. {@link SoftApCapability}
2643          */
2644         @Override
onCapabilityChanged(SoftApCapability capability)2645         public void onCapabilityChanged(SoftApCapability capability) {
2646             synchronized (mLock) {
2647                 if (Objects.equals(capability, mSoftApCapability)) {
2648                     return;
2649                 }
2650                 mSoftApCapability = new SoftApCapability(capability);
2651             }
2652             notifyRegisterOnCapabilityChanged(mRegisteredSoftApCallbacks,
2653                     mSoftApCapability);
2654         }
2655 
2656         /**
2657          * Called when client trying to connect but device blocked the client with specific reason.
2658          *
2659          * @param client the currently blocked client.
2660          * @param blockedReason one of blocked reason from
2661          * {@link WifiManager.SapClientBlockedReason}
2662          */
2663         @Override
onBlockedClientConnecting(WifiClient client, int blockedReason)2664         public void onBlockedClientConnecting(WifiClient client, int blockedReason) {
2665             notifyRegisterOnBlockedClientConnecting(mRegisteredSoftApCallbacks, client,
2666                     blockedReason);
2667         }
2668 
2669         /**
2670          * Called when clients disconnect from a soft AP instance.
2671          *
2672          * @param info The {@link SoftApInfo} of the AP.
2673          * @param clients The clients that have disconnected from the AP instance specified by
2674          *                {@code info}.
2675          */
2676         @Override
onClientsDisconnected(@onNull SoftApInfo info, @NonNull List<WifiClient> clients)2677         public void onClientsDisconnected(@NonNull SoftApInfo info,
2678                 @NonNull List<WifiClient> clients) {
2679             notifyRegisterOnClientsDisconnected(mRegisteredSoftApCallbacks, info, clients);
2680         }
2681     }
2682 
2683     private final class TetheredSoftApTracker extends BaseSoftApTracker {
updateSoftApCapabilityWhenCarrierConfigChanged(int subId)2684         public void updateSoftApCapabilityWhenCarrierConfigChanged(int subId) {
2685             CarrierConfigManager carrierConfigManager =
2686                     mContext.getSystemService(CarrierConfigManager.class);
2687             if (carrierConfigManager == null) return;
2688             PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId);
2689             if (carrierConfig == null) return;
2690             int carrierMaxClient = carrierConfig.getInt(
2691                     CarrierConfigManager.Wifi.KEY_HOTSPOT_MAX_CLIENT_COUNT);
2692             int finalSupportedClientNumber = mResourceCache.getInteger(
2693                     R.integer.config_wifiHardwareSoftapMaxClientCount);
2694             if (carrierMaxClient > 0) {
2695                 finalSupportedClientNumber = Math.min(finalSupportedClientNumber,
2696                         carrierMaxClient);
2697             }
2698             if (finalSupportedClientNumber == getSoftApCapability().getMaxSupportedClients()) {
2699                 return;
2700             }
2701             SoftApCapability newSoftApCapability = new SoftApCapability(mSoftApCapability);
2702             newSoftApCapability.setMaxSupportedClients(
2703                     finalSupportedClientNumber);
2704             onCapabilityChanged(newSoftApCapability);
2705         }
2706 
2707     }
2708 
2709     /**
2710      * Implements LOHS behavior on top of the existing SoftAp API.
2711      */
2712     private final class LohsSoftApTracker extends BaseSoftApTracker {
2713         private static final int UNSPECIFIED_PID = -1;
2714 
2715         @GuardedBy("mLocalOnlyHotspotRequests")
2716         private final HashMap<Integer, LocalOnlyHotspotRequestInfo>
2717                 mLocalOnlyHotspotRequests = new HashMap<>();
2718 
2719         /** Currently-active config, to be sent to shared clients registering later. */
2720         @GuardedBy("mLocalOnlyHotspotRequests")
2721         private SoftApModeConfiguration mActiveConfig = null;
2722 
2723         /**
2724          * Whether we are currently operating in exclusive mode (i.e. whether a custom config is
2725          * active).
2726          */
2727         @GuardedBy("mLocalOnlyHotspotRequests")
2728         private boolean mIsExclusive = false;
2729 
2730         @GuardedBy("mLocalOnlyHotspotRequests")
2731         private WorkSource mCurrentWs = null;
2732 
2733         @GuardedBy("mLocalOnlyHotspotRequests")
2734         private String mLohsInterfaceName;
2735 
2736         @GuardedBy("mLocalOnlyHotspotRequests")
2737         private int mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
2738 
2739         @GuardedBy("mLocalOnlyHotspotRequests")
2740         private int mPidRestartingLohsFor = UNSPECIFIED_PID;
2741         @Override
checkCallbackPermission(@ullable Object broadcastCookie)2742         public boolean checkCallbackPermission(@Nullable Object broadcastCookie) {
2743             if (!SdkLevel.isAtLeastS()) {
2744                 // AttributionSource requires at least S.
2745                 return false;
2746             }
2747             if (!(broadcastCookie instanceof AttributionSource)) {
2748                 return false;
2749             }
2750             return mWifiPermissionsUtil.checkNearbyDevicesPermission(
2751                     (AttributionSource) broadcastCookie,
2752                     false /* checkForLocation */,
2753                     TAG + " " + this.getClass().getSimpleName() + "#checkCallbackPermission");
2754         }
updateInterfaceIpState(String ifaceName, int mode)2755         public void updateInterfaceIpState(String ifaceName, int mode) {
2756             // update interface IP state related to local-only hotspot
2757             synchronized (mLocalOnlyHotspotRequests) {
2758                 Log.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
2759                         + " previous LOHS mode= " + mLohsInterfaceMode);
2760 
2761                 switch (mode) {
2762                     case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
2763                         // first make sure we have registered requests.
2764                         if (mLocalOnlyHotspotRequests.isEmpty()) {
2765                             // we don't have requests...  stop the hotspot
2766                             Log.wtf(TAG, "Starting LOHS without any requests?");
2767                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
2768                             return;
2769                         }
2770                         // LOHS is ready to go!  Call our registered requestors!
2771                         mLohsInterfaceName = ifaceName;
2772                         mLohsInterfaceMode = mode;
2773                         sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked();
2774                         break;
2775                     case WifiManager.IFACE_IP_MODE_TETHERED:
2776                         if (TextUtils.equals(mLohsInterfaceName, ifaceName)) {
2777                             /* This shouldn't happen except in a race, but if it does, tear down
2778                              * the LOHS and let tethering win.
2779                              *
2780                              * If concurrent SAPs are allowed, the interface names will differ,
2781                              * so we don't have to check the config here.
2782                              */
2783                             Log.e(TAG, "Unexpected IP mode change on " + ifaceName);
2784                             mLohsInterfaceName = null;
2785                             mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
2786                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
2787                                     LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
2788                         }
2789                         break;
2790                     case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR:
2791                         if (ifaceName == null) {
2792                             // All softAps
2793                             mLohsInterfaceName = null;
2794                             mLohsInterfaceMode = mode;
2795                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
2796                                     LocalOnlyHotspotCallback.ERROR_GENERIC);
2797                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
2798                         } else if (TextUtils.equals(mLohsInterfaceName, ifaceName)) {
2799                             mLohsInterfaceName = null;
2800                             mLohsInterfaceMode = mode;
2801                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
2802                                     LocalOnlyHotspotCallback.ERROR_GENERIC);
2803                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
2804                         } else {
2805                             // Not for LOHS. This is the wrong place to do this, but...
2806                             stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED);
2807                         }
2808                         break;
2809                     case WifiManager.IFACE_IP_MODE_UNSPECIFIED:
2810                         if (ifaceName == null || ifaceName.equals(mLohsInterfaceName)) {
2811                             mLohsInterfaceName = null;
2812                             mLohsInterfaceMode = mode;
2813                         }
2814                         break;
2815                     default:
2816                         mLog.warn("updateInterfaceIpState: unknown mode %").c(mode).flush();
2817                 }
2818             }
2819         }
2820 
2821         /**
2822          * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest
2823          * callers and clear the registrations.
2824          *
2825          * Callers should already hold the mLocalOnlyHotspotRequests lock.
2826          */
2827         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason)2828         private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason) {
2829             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
2830                 try {
2831                     requestor.sendHotspotFailedMessage(reason);
2832                     requestor.unlinkDeathRecipient();
2833                 } catch (RemoteException e) {
2834                     // This will be cleaned up by binder death handling
2835                 }
2836             }
2837 
2838             // Since all callers were notified, now clear the registrations.
2839             mLocalOnlyHotspotRequests.clear();
2840             mPidRestartingLohsFor = UNSPECIFIED_PID;
2841         }
2842 
2843         /**
2844          * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest
2845          * callers and clear the registrations.
2846          *
2847          * Callers should already hold the mLocalOnlyHotspotRequests lock.
2848          */
2849         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked()2850         private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() {
2851             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
2852                 try {
2853                     requestor.sendHotspotStoppedMessage();
2854                     requestor.unlinkDeathRecipient();
2855                 } catch (RemoteException e) {
2856                     // This will be cleaned up by binder death handling
2857                 }
2858             }
2859 
2860             // Since all callers were notified, now clear the registrations.
2861             mLocalOnlyHotspotRequests.clear();
2862         }
2863 
2864         /**
2865          * Add a new LOHS client
2866          */
start(int pid, LocalOnlyHotspotRequestInfo request)2867         private int start(int pid, LocalOnlyHotspotRequestInfo request) {
2868             synchronized (mLocalOnlyHotspotRequests) {
2869                 // does this caller already have a request?
2870                 if (mLocalOnlyHotspotRequests.get(pid) != null) {
2871                     mLog.trace("caller already has an active request").flush();
2872                     throw new IllegalStateException(
2873                             "Caller already has an active LocalOnlyHotspot request");
2874                 }
2875 
2876                 // Never accept exclusive requests (with custom configuration) at the same time as
2877                 // shared requests.
2878                 if (!mLocalOnlyHotspotRequests.isEmpty()) {
2879                     final boolean requestIsExclusive = request.getCustomConfig() != null;
2880                     final int newRequestorWsPriority = mWifiInjector
2881                             .makeWsHelper(request.getWorkSource()).getRequestorWsPriority();
2882                     final int currentWsPriority = mWifiInjector
2883                             .makeWsHelper(mCurrentWs).getRequestorWsPriority();
2884                     final boolean isCurrentLohsWorksOnNonDefaultBand = mActiveConfig != null
2885                             && mActiveConfig.getSoftApConfiguration().getBand()
2886                                     != SoftApConfiguration.BAND_2GHZ;
2887                     Log.d(TAG, "Receive multiple LOHS requestors,"
2888                                 + ", requestIsExclusive: " + requestIsExclusive
2889                                 + ", mIsExclusive: " + mIsExclusive
2890                                 + ", currentWsPriority: " + currentWsPriority
2891                                 + ", newRequestorWsPriority: " + newRequestorWsPriority);
2892                     if (requestIsExclusive || mIsExclusive
2893                             || (currentWsPriority >= newRequestorWsPriority
2894                                     && isCurrentLohsWorksOnNonDefaultBand)) {
2895                         mLog.trace("Cannot share with existing LOHS request due to custom config")
2896                                 .flush();
2897                         return LocalOnlyHotspotCallback.ERROR_GENERIC;
2898                     }
2899                     if (mFeatureFlags.publicBandsForLohs() && isCurrentLohsWorksOnNonDefaultBand) {
2900                         // Current LOHS is not using 2.4 band, and new caller priority is higher.
2901                         // stop all and logging the new requestor pid.
2902                         mLog.trace("Restarting LOHS to default band for new requestor")
2903                                 .flush();
2904                         mLohsSoftApTracker.stopAll();
2905                         mPidRestartingLohsFor = pid;
2906                     }
2907                 }
2908                 // At this point, the request is accepted.
2909                 if (mLocalOnlyHotspotRequests.isEmpty()) {
2910                     mWifiThreadRunner.post(() -> {
2911                         startForFirstRequestLocked(request);
2912                     }, "LohsSoftApTracker#start");
2913 
2914                 } else if (mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) {
2915                     // LOHS has already started up for an earlier request, so we can send the
2916                     // current config to the incoming request right away.
2917                     try {
2918                         mLog.trace("LOHS already up, trigger onStarted callback").flush();
2919                         request.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration());
2920                     } catch (RemoteException e) {
2921                         return LocalOnlyHotspotCallback.ERROR_GENERIC;
2922                     }
2923                 }
2924                 mLocalOnlyHotspotRequests.put(pid, request);
2925                 return LocalOnlyHotspotCallback.REQUEST_REGISTERED;
2926             }
2927         }
2928 
2929         @GuardedBy("mLocalOnlyHotspotRequests")
startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request)2930         private void startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request) {
2931             mCurrentWs = request.getWorkSource();
2932             final int currentWsPriority = mWifiInjector.makeWsHelper(mCurrentWs)
2933                     .getRequestorWsPriority();
2934             if (mFeatureFlags.publicBandsForLohs() && Environment.isSdkAtLeastB()) {
2935                 mIsExclusive = (request.getCustomConfig() != null)
2936                         && currentWsPriority >= WorkSourceHelper.PRIORITY_SYSTEM;
2937             } else {
2938                 mIsExclusive = (request.getCustomConfig() != null);
2939             }
2940             final SoftApCapability lohsCapability = mLohsSoftApTracker.getSoftApCapability();
2941             SoftApConfiguration softApConfig = mWifiApConfigStore.generateLocalOnlyHotspotConfig(
2942                     mContext, request.getCustomConfig(), lohsCapability, mIsExclusive);
2943 
2944             mActiveConfig = new SoftApModeConfiguration(
2945                     WifiManager.IFACE_IP_MODE_LOCAL_ONLY,
2946                     softApConfig, lohsCapability, mCountryCode.getCountryCode(), null);
2947             // Report the error if we got failure in startSoftApInternal
2948             if (!startSoftApInternal(mActiveConfig, request.getWorkSource(), null)) {
2949                 onStateChanged(new SoftApState(
2950                         WIFI_AP_STATE_FAILED, SAP_START_FAILURE_GENERAL,
2951                         mActiveConfig.getTetheringRequest(), null /* iface */));
2952             }
2953         }
2954 
2955         /**
2956          * Requests that any local-only hotspot be stopped.
2957          */
stopAll()2958         public void stopAll() {
2959             synchronized (mLocalOnlyHotspotRequests) {
2960                 if (!mLocalOnlyHotspotRequests.isEmpty()) {
2961                     // This is used to take down LOHS when tethering starts, and in that
2962                     // case we send failed instead of stopped.
2963                     // TODO check if that is right. Calling onFailed instead of onStopped when the
2964                     // hotspot is already started does not seem to match the documentation
2965                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
2966                             LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
2967                     stopIfEmptyLocked();
2968                 }
2969             }
2970         }
2971 
2972         /**
2973          * Unregisters the LOHS request from the given process and stops LOHS if no other clients.
2974          */
stopByPid(int pid)2975         public void stopByPid(int pid) {
2976             synchronized (mLocalOnlyHotspotRequests) {
2977                 LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.remove(pid);
2978                 if (requestInfo == null) return;
2979                 requestInfo.unlinkDeathRecipient();
2980                 stopIfEmptyLocked();
2981             }
2982         }
2983 
2984         /**
2985          * Unregisters LocalOnlyHotspot request and stops the hotspot if needed.
2986          */
stopByRequest(LocalOnlyHotspotRequestInfo request)2987         public void stopByRequest(LocalOnlyHotspotRequestInfo request) {
2988             synchronized (mLocalOnlyHotspotRequests) {
2989                 if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) {
2990                     mLog.trace("LocalOnlyHotspotRequestInfo not found to remove").flush();
2991                     return;
2992                 }
2993                 stopIfEmptyLocked();
2994             }
2995         }
2996 
2997         @GuardedBy("mLocalOnlyHotspotRequests")
stopIfEmptyLocked()2998         private void stopIfEmptyLocked() {
2999             if (mLocalOnlyHotspotRequests.isEmpty()) {
3000                 mActiveConfig = null;
3001                 mIsExclusive = false;
3002                 mCurrentWs = null;
3003                 mLohsInterfaceName = null;
3004                 mPidRestartingLohsFor = UNSPECIFIED_PID;
3005                 mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
3006                 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
3007             }
3008         }
3009 
3010         /**
3011          * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest
3012          * callers.
3013          *
3014          * Callers should already hold the mLocalOnlyHotspotRequests lock.
3015          */
3016         @GuardedBy("mLocalOnlyHotspotRequests")
sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked()3017         private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() {
3018             if (mActiveConfig == null) {
3019                 Log.e(TAG, "lohs.sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked "
3020                         + "mActiveConfig is null");
3021                 return;
3022             }
3023             for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
3024                 try {
3025                     requestor.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration());
3026                 } catch (RemoteException e) {
3027                     // This will be cleaned up by binder death handling
3028                 }
3029             }
3030         }
3031 
3032         @Override
onStateChanged(SoftApState softApState)3033         public void onStateChanged(SoftApState softApState) {
3034             // The AP state update from ClientModeImpl for softap
3035             synchronized (mLocalOnlyHotspotRequests) {
3036                 Log.d(TAG, "lohs.onStateChanged: " + softApState);
3037                 int state = softApState.getState();
3038                 int failureReason = softApState.getFailureReasonInternal();
3039 
3040                 // check if we have a failure - since it is possible (worst case scenario where
3041                 // WifiController and ClientModeImpl are out of sync wrt modes) to get two FAILED
3042                 // notifications in a row, we need to handle this first.
3043                 if (state == WIFI_AP_STATE_FAILED) {
3044                     // update registered LOHS callbacks if we see a failure
3045                     int errorToReport = ERROR_GENERIC;
3046                     if (failureReason == SAP_START_FAILURE_NO_CHANNEL) {
3047                         errorToReport = ERROR_NO_CHANNEL;
3048                     }
3049                     // holding the required lock: send message to requestors and clear the list
3050                     sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(errorToReport);
3051                     // also need to clear interface ip state
3052                     updateInterfaceIpState(mLohsInterfaceName,
3053                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
3054                     // failed, reset restarting pid info
3055                     mPidRestartingLohsFor = UNSPECIFIED_PID;
3056                 } else if (state == WIFI_AP_STATE_DISABLING || state == WIFI_AP_STATE_DISABLED) {
3057                     // softap is shutting down or is down...  let requestors know via the
3058                     // onStopped call
3059                     // if we are currently in hotspot mode, then trigger onStopped for registered
3060                     // requestors, otherwise something odd happened and we should clear state
3061                     if (mLohsInterfaceName != null
3062                             && mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) {
3063                         // holding the required lock: send message to requestors and clear the list
3064                         sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
3065                     } else {
3066                         // The LOHS is being restarted since there is a mPidRestartingLohsFor,
3067                         // We should expect there will be DISABLING and DISABLED.
3068                         // No need to report error.
3069                         if (mPidRestartingLohsFor == UNSPECIFIED_PID) {
3070                             // LOHS not active: report an error.
3071                             sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
3072                                     ERROR_GENERIC);
3073                         }
3074                     }
3075                     // also clear interface ip state
3076                     updateInterfaceIpState(mLohsInterfaceName,
3077                             WifiManager.IFACE_IP_MODE_UNSPECIFIED);
3078                 } else if (state ==  WIFI_AP_STATE_ENABLING
3079                         && mPidRestartingLohsFor != UNSPECIFIED_PID) {
3080                     // restarting, reset pid info
3081                     mPidRestartingLohsFor = UNSPECIFIED_PID;
3082                 }
3083                 // For enabling and enabled, just record the new state
3084                 setState(softApState);
3085                 notifyRegisterOnStateChanged(mRegisteredSoftApCallbacks, softApState);
3086             }
3087         }
3088     }
3089 
3090     /**
3091      * see {@link android.net.wifi.WifiManager#registerSoftApCallback(Executor,
3092      * WifiManager.SoftApCallback)}
3093      *
3094      * @param callback Soft AP callback to register
3095      *
3096      * @throws SecurityException if the caller does not have permission to register a callback
3097      * @throws RemoteException if remote exception happens
3098      * @throws IllegalArgumentException if the arguments are null or invalid
3099      */
3100     @Override
registerSoftApCallback(ISoftApCallback callback)3101     public void registerSoftApCallback(ISoftApCallback callback) {
3102         // verify arguments
3103         if (callback == null) {
3104             throw new IllegalArgumentException("Callback must not be null");
3105         }
3106 
3107         int uid = Binder.getCallingUid();
3108         int pid = Binder.getCallingPid();
3109         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
3110                 && !checkNetworkSettingsPermission(pid, uid)
3111                 && !checkMainlineNetworkStackPermission(pid, uid)) {
3112             // random apps should not be allowed to read the user specified config
3113             throw new SecurityException("App not allowed to read  WiFi Ap information "
3114                     + "(uid/pid = " + uid + "/" + pid + ")");
3115         }
3116 
3117         if (mVerboseLoggingEnabled) {
3118             mLog.info("registerSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
3119         }
3120 
3121         // post operation to handler thread
3122         mWifiThreadRunner.post(() -> {
3123             if (!mTetheredSoftApTracker.registerSoftApCallback(callback, null)) {
3124                 Log.e(TAG, "registerSoftApCallback: Failed to add callback");
3125                 return;
3126             }
3127         }, TAG + "#registerSoftApCallback");
3128     }
3129 
3130     /**
3131      * see {@link android.net.wifi.WifiManager#unregisterSoftApCallback(WifiManager.SoftApCallback)}
3132      *
3133      * @param callback Soft AP callback to unregister
3134      *
3135      * @throws SecurityException if the caller does not have permission to register a callback
3136      */
3137     @Override
unregisterSoftApCallback(ISoftApCallback callback)3138     public void unregisterSoftApCallback(ISoftApCallback callback) {
3139         int uid = Binder.getCallingUid();
3140         int pid = Binder.getCallingPid();
3141         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
3142                 && !checkNetworkSettingsPermission(pid, uid)
3143                 && !checkMainlineNetworkStackPermission(pid, uid)) {
3144             // random apps should not be allowed to read the user specified config
3145             throw new SecurityException("App not allowed to read  WiFi Ap information "
3146                     + "(uid/pid = " + uid + "/" + pid + ")");
3147         }
3148 
3149         if (mVerboseLoggingEnabled) {
3150             mLog.info("unregisterSoftApCallback uid=%").c(Binder.getCallingUid()).flush();
3151         }
3152 
3153         // post operation to handler thread
3154         mWifiThreadRunner.post(() ->
3155                 mTetheredSoftApTracker.unregisterSoftApCallback(callback),
3156                 TAG + "#unregisterSoftApCallback");
3157     }
3158 
3159     /**
3160      * Temporary method used for testing while start is not fully implemented.  This
3161      * method allows unit tests to register callbacks directly for testing mechanisms triggered by
3162      * softap mode changes.
3163      */
3164     @VisibleForTesting
registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request)3165     int registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) {
3166         return mLohsSoftApTracker.start(pid, request);
3167     }
3168 
3169     /**
3170      * Method to start LocalOnlyHotspot.  In this method, permissions, settings and modes are
3171      * checked to verify that we can enter softapmode.  This method returns
3172      * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise,
3173      * possible startup erros may include tethering being disallowed failure reason {@link
3174      * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason
3175      * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}.
3176      *
3177      * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}
3178      *
3179      * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies.
3180      * @param packageName String name of the calling package.
3181      * @param featureId The feature in the package
3182      * @param customConfig Custom configuration to be applied to the hotspot, or null for a shared
3183      *                     hotspot with framework-generated config.
3184      * @param extras Bundle of extra information
3185      *
3186      * @return int return code for attempt to start LocalOnlyHotspot.
3187      *
3188      * @throws SecurityException if the caller does not have permission to start a Local Only
3189      * Hotspot.
3190      * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they
3191      * have an outstanding request.
3192      */
3193     @Override
startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName, String featureId, SoftApConfiguration customConfig, Bundle extras, boolean isCalledFromSystemApi)3194     public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName,
3195             String featureId, SoftApConfiguration customConfig, Bundle extras,
3196             boolean isCalledFromSystemApi) {
3197         // first check if the caller has permission to start a local only hotspot
3198         // need to check for WIFI_STATE_CHANGE and location permission
3199         final int uid = Binder.getCallingUid();
3200         final int pid = Binder.getCallingPid();
3201         mWifiPermissionsUtil.checkPackage(uid, packageName);
3202 
3203         mLog.info("start lohs uid=% pid=%").c(uid).c(pid).flush();
3204 
3205         // Permission requirements are different with/without custom config.
3206         // From B, the custom config may from public API, check isCalledFromSystemApi
3207         if (customConfig == null
3208                 || (Environment.isSdkAtLeastB() && !isCalledFromSystemApi)) {
3209             if (enforceChangePermission(packageName) != MODE_ALLOWED) {
3210                 return LocalOnlyHotspotCallback.ERROR_GENERIC;
3211             }
3212             if (isPlatformOrTargetSdkLessThanT(packageName, uid)) {
3213                 enforceLocationPermission(packageName, featureId, uid);
3214                 long ident = Binder.clearCallingIdentity();
3215                 try {
3216                     // also need to verify that Locations services are enabled.
3217                     if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
3218                         throw new SecurityException("Location mode is not enabled.");
3219                     }
3220 
3221                 } finally {
3222                     Binder.restoreCallingIdentity(ident);
3223                 }
3224             } else {
3225                 mWifiPermissionsUtil.enforceNearbyDevicesPermission(
3226                         extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE),
3227                         false, TAG + " startLocalOnlyHotspot");
3228             }
3229         } else {
3230             if (isPlatformOrTargetSdkLessThanT(packageName, uid)) {
3231                 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
3232                     throw new SecurityException(TAG + ": Permission denied");
3233                 }
3234             } else {
3235                 mWifiPermissionsUtil.enforceNearbyDevicesPermission(
3236                         extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE),
3237                         false, TAG + " startLocalOnlyHotspot");
3238             }
3239         }
3240 
3241         final WorkSource requestorWs = new WorkSource(uid, packageName);
3242         // the app should be in the foreground
3243         long ident = Binder.clearCallingIdentity();
3244         try {
3245             // verify that tethering is not disabled
3246             if (mUserManager.hasUserRestrictionForUser(
3247                     UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.getUserHandleForUid(uid))) {
3248                 return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
3249             }
3250 
3251             mLastCallerInfoManager.put(WifiManager.API_START_LOCAL_ONLY_HOTSPOT, Process.myTid(),
3252                     uid, Binder.getCallingPid(), packageName, true);
3253             // also need to verify that Locations services are enabled.
3254             // bypass shell with root uid
3255             if (uid != Process.ROOT_UID
3256                     && !mFrameworkFacade.isAppForeground(mContext, uid)) {
3257                 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
3258             }
3259             // check if we are currently tethering
3260             if (!mActiveModeWarden.canRequestMoreSoftApManagers(requestorWs)
3261                     && mTetheredSoftApTracker.getState().getState() == WIFI_AP_STATE_ENABLED) {
3262                 // Tethering is enabled, cannot start LocalOnlyHotspot
3263                 mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.")
3264                         .flush();
3265                 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
3266             }
3267         } finally {
3268             Binder.restoreCallingIdentity(ident);
3269         }
3270 
3271         // now create the new LOHS request info object
3272         LocalOnlyHotspotRequestInfo request = new LocalOnlyHotspotRequestInfo(
3273                 mWifiHandlerThread.getLooper(), requestorWs, callback,
3274                 new LocalOnlyRequestorCallback(), customConfig);
3275 
3276         return mLohsSoftApTracker.start(pid, request);
3277     }
3278 
3279     /**
3280      * see {@link WifiManager#stopLocalOnlyHotspot()}
3281      *
3282      * @throws SecurityException if the caller does not have permission to stop a Local Only
3283      * Hotspot.
3284      */
3285     @Override
stopLocalOnlyHotspot()3286     public void stopLocalOnlyHotspot() {
3287         // don't do a permission check here. if the app's permission to change the wifi state is
3288         // revoked, we still want them to be able to stop a previously created hotspot (otherwise
3289         // it could cost the user money). When the app created the hotspot, its permission was
3290         // checked.
3291         final int uid = Binder.getCallingUid();
3292         final int pid = Binder.getCallingPid();
3293 
3294         mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
3295         // Force to disable lohs when caller is shell with root permission
3296         if (uid == Process.ROOT_UID) {
3297             mLohsSoftApTracker.stopAll();
3298         } else {
3299             mLohsSoftApTracker.stopByPid(pid);
3300         }
3301     }
3302 
3303     @Override
registerLocalOnlyHotspotSoftApCallback(ISoftApCallback callback, Bundle extras)3304     public void registerLocalOnlyHotspotSoftApCallback(ISoftApCallback callback, Bundle extras) {
3305         if (!SdkLevel.isAtLeastT()) {
3306             throw new UnsupportedOperationException();
3307         }
3308 
3309         // verify arguments
3310         if (callback == null) {
3311             throw new IllegalArgumentException("Callback must not be null");
3312         }
3313 
3314         AttributionSource attributionSource =
3315                 extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE);
3316         mWifiPermissionsUtil.enforceNearbyDevicesPermission(attributionSource,
3317                 false, TAG + " registerLocalOnlyHotspotSoftApCallback");
3318 
3319         if (mVerboseLoggingEnabled) {
3320             mLog.info("registerLocalOnlyHotspotSoftApCallback uid=%")
3321                     .c(Binder.getCallingUid()).flush();
3322         }
3323 
3324         // post operation to handler thread
3325         mWifiThreadRunner.post(() -> {
3326             if (!mLohsSoftApTracker.registerSoftApCallback(callback, attributionSource)) {
3327                 Log.e(TAG, "registerLocalOnlyHotspotSoftApCallback: Failed to add callback");
3328             }
3329         }, TAG + "#registerLocalOnlyHotspotSoftApCallback");
3330     }
3331 
3332     @Override
unregisterLocalOnlyHotspotSoftApCallback(ISoftApCallback callback, Bundle extras)3333     public void unregisterLocalOnlyHotspotSoftApCallback(ISoftApCallback callback, Bundle extras) {
3334         // verify arguments
3335         if (callback == null) {
3336             throw new IllegalArgumentException("Callback must not be null");
3337         }
3338 
3339         mWifiPermissionsUtil.enforceNearbyDevicesPermission(
3340                 extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE),
3341                 false, TAG + " registerLocalOnlyHotspotSoftApCallback");
3342 
3343         if (mVerboseLoggingEnabled) {
3344             mLog.info("unregisterLocalOnlyHotspotSoftApCallback uid=%")
3345                     .c(Binder.getCallingUid()).flush();
3346         }
3347 
3348         // post operation to handler thread
3349         mWifiThreadRunner.post(() ->
3350                 mLohsSoftApTracker.unregisterSoftApCallback(callback),
3351                 TAG + "#unregisterLocalOnlyHotspotSoftApCallback");
3352     }
3353 
3354     /**
3355      * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)}
3356      *
3357      * This call requires the android.permission.NETWORK_SETTINGS permission.
3358      *
3359      * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies.
3360      *
3361      * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot
3362      * status updates.
3363      * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with
3364      * an existing subscription.
3365      */
3366     @Override
startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback)3367     public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) {
3368         // NETWORK_SETTINGS is a signature only permission.
3369         enforceNetworkSettingsPermission();
3370 
3371         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
3372     }
3373 
3374     /**
3375      * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()}
3376      */
3377     @Override
stopWatchLocalOnlyHotspot()3378     public void stopWatchLocalOnlyHotspot() {
3379         // NETWORK_STACK is a signature only permission.
3380         enforceNetworkSettingsPermission();
3381         throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
3382     }
3383 
3384     /**
3385      * see {@link WifiManager#getWifiApConfiguration()}
3386      * @return soft access point configuration
3387      * @throws SecurityException if the caller does not have permission to retrieve the softap
3388      * config
3389      */
3390     @Nullable
3391     @Override
getWifiApConfiguration()3392     public WifiConfiguration getWifiApConfiguration() {
3393         enforceAccessPermission();
3394         int uid = Binder.getCallingUid();
3395         // only allow Settings UI to get the saved SoftApConfig
3396         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
3397             // random apps should not be allowed to read the user specified config
3398             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
3399                     + "(uid = " + uid + ")");
3400         }
3401 
3402         if (mVerboseLoggingEnabled) {
3403             mLog.info("getWifiApConfiguration uid=%").c(uid).flush();
3404         }
3405 
3406         final SoftApConfiguration config = mWifiApConfigStore.getApConfiguration();
3407         return config == null ? new SoftApConfiguration.Builder().build().toWifiConfiguration()
3408                 : config.toWifiConfiguration();
3409     }
3410 
3411     /**
3412      * see {@link WifiManager#getSoftApConfiguration()}
3413      * @return soft access point configuration {@link SoftApConfiguration}
3414      * @throws SecurityException if the caller does not have permission to retrieve the softap
3415      * config
3416      */
3417     @NonNull
3418     @Override
getSoftApConfiguration()3419     public SoftApConfiguration getSoftApConfiguration() {
3420         int uid = Binder.getCallingUid();
3421         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
3422                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
3423             // random apps should not be allowed to read the user specified config
3424             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
3425                     + "(uid = " + uid + ")");
3426         }
3427         if (mVerboseLoggingEnabled) {
3428             mLog.info("getSoftApConfiguration uid=%").c(uid).flush();
3429         }
3430 
3431         final SoftApConfiguration config = mWifiApConfigStore.getApConfiguration();
3432         return config == null ? new SoftApConfiguration.Builder().build() : config;
3433     }
3434 
3435     /**
3436      * See {@code WifiManager#queryLastConfiguredTetheredApPassphraseSinceBoot(Executor, Consumer)}
3437      */
3438     @Override
queryLastConfiguredTetheredApPassphraseSinceBoot(IStringListener listener)3439     public void queryLastConfiguredTetheredApPassphraseSinceBoot(IStringListener listener) {
3440         if (listener == null) {
3441             throw new IllegalArgumentException("listener should not be null");
3442         }
3443         int uid = Binder.getCallingUid();
3444         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
3445             throw new SecurityException("App not allowed to read last WiFi AP passphrase "
3446                     + "(uid = " + uid + ")");
3447         }
3448         mWifiThreadRunner.post(() -> {
3449             try {
3450                 listener.onResult(mWifiApConfigStore
3451                         .getLastConfiguredTetheredApPassphraseSinceBoot());
3452             } catch (RemoteException e) {
3453                 Log.e(TAG, e.getMessage(), e);
3454             }
3455         }, TAG + "#queryLastConfiguredTetheredApPassphraseSinceBoot");
3456     }
3457 
3458     /**
3459      * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
3460      * @param wifiConfig WifiConfiguration details for soft access point
3461      * @return boolean indicating success or failure of the operation
3462      * @throws SecurityException if the caller does not have permission to write the softap config
3463      */
3464     @Override
setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName)3465     public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) {
3466         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
3467             return false;
3468         }
3469         int uid = Binder.getCallingUid();
3470         mWifiPermissionsUtil.checkPackage(uid, packageName);
3471         // only allow Settings UI to write the stored SoftApConfig
3472         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
3473             // random apps should not be allowed to read the user specified config
3474             throw new SecurityException("App not allowed to read or update stored WiFi AP config "
3475                     + "(uid = " + uid + ")");
3476         }
3477         mLog.info("setWifiApConfiguration uid=%").c(uid).flush();
3478         if (wifiConfig == null)
3479             return false;
3480         SoftApConfiguration softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig);
3481         if (softApConfig == null) return false;
3482         if (!WifiApConfigStore.validateApWifiConfiguration(
3483                 softApConfig, false, mContext, mWifiNative)) {
3484             Log.e(TAG, "Invalid WifiConfiguration");
3485             return false;
3486         }
3487         mWifiApConfigStore.setApConfiguration(softApConfig);
3488         return true;
3489     }
3490 
3491     /**
3492      * see {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)}
3493      * @param softApConfig {@link SoftApConfiguration} details for soft access point
3494      * @return boolean indicating success or failure of the operation
3495      * @throws SecurityException if the caller does not have permission to write the softap config
3496      */
3497     @Override
setSoftApConfiguration( @onNull SoftApConfiguration softApConfig, @NonNull String packageName)3498     public boolean setSoftApConfiguration(
3499             @NonNull SoftApConfiguration softApConfig, @NonNull String packageName) {
3500         int uid = Binder.getCallingUid();
3501         mWifiPermissionsUtil.checkPackage(uid, packageName);
3502         boolean privileged = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid);
3503         if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)
3504                 && !privileged) {
3505             // random apps should not be allowed to read the user specified config
3506             throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
3507                     + "(uid = " + uid + ")");
3508         }
3509         mLog.info("setSoftApConfiguration uid=%").c(uid).flush();
3510         if (softApConfig == null) return false;
3511         if (WifiApConfigStore.validateApWifiConfiguration(softApConfig, privileged, mContext,
3512                 mWifiNative)) {
3513             mWifiApConfigStore.setApConfiguration(softApConfig);
3514             // Send the message for AP config update after the save is done.
3515             mActiveModeWarden.updateSoftApConfiguration(softApConfig);
3516             return true;
3517         } else {
3518             Log.e(TAG, "Invalid SoftAp Configuration");
3519             return false;
3520         }
3521     }
3522 
3523     /**
3524      * see {@link android.net.wifi.WifiManager#setScanAlwaysAvailable(boolean)}
3525      */
3526     @Override
setScanAlwaysAvailable(boolean isAvailable, String packageName)3527     public void setScanAlwaysAvailable(boolean isAvailable, String packageName) {
3528         enforceNetworkSettingsPermission();
3529         int callingUid = Binder.getCallingUid();
3530         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
3531         mLog.info("setScanAlwaysAvailable uid=% package=% isAvailable=%")
3532                 .c(callingUid)
3533                 .c(packageName)
3534                 .c(isAvailable)
3535                 .flush();
3536         mSettingsStore.handleWifiScanAlwaysAvailableToggled(isAvailable);
3537         long ident = Binder.clearCallingIdentity();
3538         try {
3539             mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility()
3540                     .handleWifiScanAlwaysAvailableToggled(isAvailable);
3541         } finally {
3542             Binder.restoreCallingIdentity(ident);
3543         }
3544         mActiveModeWarden.scanAlwaysModeChanged();
3545     }
3546 
3547     /**
3548      * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
3549      */
3550     @Override
isScanAlwaysAvailable()3551     public boolean isScanAlwaysAvailable() {
3552         enforceAccessPermission();
3553         if (mVerboseLoggingEnabled) {
3554             mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
3555         }
3556         return mSettingsStore.isScanAlwaysAvailableToggleEnabled();
3557     }
3558 
3559     /**
3560      * see {@link android.net.wifi.WifiManager#disconnect()}
3561      */
3562     @Override
disconnect(String packageName)3563     public boolean disconnect(String packageName) {
3564         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
3565             return false;
3566         }
3567         int callingUid = Binder.getCallingUid();
3568         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
3569         if (!isTargetSdkLessThanQOrPrivileged(
3570                 packageName, Binder.getCallingPid(), callingUid)) {
3571             mLog.info("disconnect not allowed for uid=%").c(callingUid).flush();
3572             return false;
3573         }
3574         mLog.info("disconnect uid=%").c(callingUid).flush();
3575         mWifiThreadRunner.post(() -> mActiveModeWarden.getPrimaryClientModeManager().disconnect(),
3576                 TAG + "#disconnect");
3577         return true;
3578     }
3579 
3580     /**
3581      * see {@link android.net.wifi.WifiManager#reconnect()}
3582      */
3583     @Override
reconnect(String packageName)3584     public boolean reconnect(String packageName) {
3585         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
3586             return false;
3587         }
3588         int callingUid = Binder.getCallingUid();
3589         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
3590         if (!isTargetSdkLessThanQOrPrivileged(packageName, Binder.getCallingPid(), callingUid)) {
3591             mLog.info("reconnect not allowed for uid=%").c(callingUid).flush();
3592             return false;
3593         }
3594         mLog.info("reconnect uid=%").c(callingUid).flush();
3595 
3596         mWifiThreadRunner.post(() -> {
3597             mActiveModeWarden.getPrimaryClientModeManager().reconnect(new WorkSource(callingUid));
3598         }, TAG + "#reconnect");
3599         return true;
3600     }
3601 
3602     /**
3603      * see {@link android.net.wifi.WifiManager#reassociate()}
3604      */
3605     @Override
reassociate(String packageName)3606     public boolean reassociate(String packageName) {
3607         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
3608             return false;
3609         }
3610         int callingUid = Binder.getCallingUid();
3611         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
3612         if (!isTargetSdkLessThanQOrPrivileged(
3613                 packageName, Binder.getCallingPid(), callingUid)) {
3614             mLog.info("reassociate not allowed for uid=%").c(callingUid).flush();
3615             return false;
3616         }
3617         mLog.info("reassociate uid=%").c(callingUid).flush();
3618         mWifiThreadRunner.post(() -> mActiveModeWarden.getPrimaryClientModeManager().reassociate(),
3619                 TAG + "#reassociate");
3620         return true;
3621     }
3622 
3623     /**
3624      * Returns true if we should log the call to isFeatureSupported.
3625      *
3626      * Because of the way isFeatureSupported is used in WifiManager, there are
3627      * often clusters of several back-to-back calls; avoid repeated logging if
3628      * the feature set has not changed and the time interval is short.
3629      */
needToLogSupportedFeatures(BitSet features)3630     private boolean needToLogSupportedFeatures(BitSet features) {
3631         if (mVerboseLoggingEnabled) {
3632             long now = mClock.getElapsedSinceBootMillis();
3633             synchronized (this) {
3634                 if (now > mLastLoggedSupportedFeaturesTimestamp + A_FEW_MILLISECONDS
3635                         || !features.equals(mLastLoggedSupportedFeatures)) {
3636                     mLastLoggedSupportedFeaturesTimestamp = now;
3637                     mLastLoggedSupportedFeatures = features;
3638                     return true;
3639                 }
3640             }
3641         }
3642         return false;
3643     }
3644     private static final int A_FEW_MILLISECONDS = 250;
3645     private BitSet mLastLoggedSupportedFeatures = new BitSet();
3646     private long mLastLoggedSupportedFeaturesTimestamp = 0;
3647 
3648     @Override
isFeatureSupported(int feature)3649     public boolean isFeatureSupported(int feature) {
3650         enforceAccessPermission();
3651         BitSet supportedFeatures = getSupportedFeaturesInternal();
3652         if (needToLogSupportedFeatures(supportedFeatures)) {
3653             mLog.info("isFeatureSupported uid=% returns %")
3654                     .c(Binder.getCallingUid())
3655                     .c(FeatureBitsetUtils.formatSupportedFeatures(supportedFeatures))
3656                     .flush();
3657         }
3658         return supportedFeatures.get(feature);
3659     }
3660 
3661     @Override
getWifiActivityEnergyInfoAsync(@onNull IOnWifiActivityEnergyInfoListener listener)3662     public void getWifiActivityEnergyInfoAsync(@NonNull IOnWifiActivityEnergyInfoListener
3663             listener) {
3664         if (listener == null) {
3665             throw new IllegalArgumentException("listener should not be null");
3666         }
3667         enforceAccessPermission();
3668         if (mVerboseLoggingEnabled) {
3669             mLog.info("getWifiActivityEnergyInfoAsync uid=%")
3670                     .c(Binder.getCallingUid())
3671                     .flush();
3672         }
3673         if (!isFeatureSupported(WifiManager.WIFI_FEATURE_LINK_LAYER_STATS)) {
3674             try {
3675                 listener.onWifiActivityEnergyInfo(null);
3676             } catch (RemoteException e) {
3677                 Log.e(TAG, "onWifiActivityEnergyInfo: RemoteException -- ", e);
3678             }
3679             return;
3680         }
3681         mWifiThreadRunner.post(() -> {
3682             try {
3683                 listener.onWifiActivityEnergyInfo(getWifiActivityEnergyInfo());
3684             } catch (RemoteException e) {
3685                 Log.e(TAG, "onWifiActivityEnergyInfo: RemoteException -- ", e);
3686             }
3687         }, TAG + "#getWifiActivityEnergyInfoAsync");
3688     }
3689 
getWifiActivityEnergyInfo()3690     private WifiActivityEnergyInfo getWifiActivityEnergyInfo() {
3691         WifiLinkLayerStats stats = mActiveModeWarden
3692                 .getPrimaryClientModeManager().getWifiLinkLayerStats();
3693         if (stats == null) {
3694             return null;
3695         }
3696         final long rxIdleTimeMillis = stats.on_time - stats.tx_time - stats.rx_time;
3697         if (VDBG || rxIdleTimeMillis < 0 || stats.on_time < 0 || stats.tx_time < 0
3698                 || stats.rx_time < 0 || stats.on_time_scan < 0) {
3699             Log.d(TAG, " getWifiActivityEnergyInfo: "
3700                     + " on_time_millis=" + stats.on_time
3701                     + " tx_time_millis=" + stats.tx_time
3702                     + " rx_time_millis=" + stats.rx_time
3703                     + " rxIdleTimeMillis=" + rxIdleTimeMillis
3704                     + " scan_time_millis=" + stats.on_time_scan);
3705         }
3706         // Convert the LinkLayerStats into WifiActivityEnergyInfo
3707         return new WifiActivityEnergyInfo(
3708                 mClock.getElapsedSinceBootMillis(),
3709                 WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE,
3710                 stats.tx_time,
3711                 stats.rx_time,
3712                 stats.on_time_scan,
3713                 rxIdleTimeMillis);
3714     }
3715 
3716     /**
3717      * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
3718      *
3719      * @param packageName String name of the calling package
3720      * @param featureId The feature in the package
3721      * @param callerNetworksOnly Whether to only return networks created by the caller
3722      * @return the list of configured networks
3723      */
3724     @Override
getConfiguredNetworks(String packageName, String featureId, boolean callerNetworksOnly)3725     public ParceledListSlice<WifiConfiguration> getConfiguredNetworks(String packageName,
3726             String featureId, boolean callerNetworksOnly) {
3727         enforceAccessPermission();
3728         int callingUid = Binder.getCallingUid();
3729         // bypass shell: can get various pkg name
3730         // also bypass if caller is only retrieving networks added by itself
3731         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
3732             mWifiPermissionsUtil.checkPackage(callingUid, packageName);
3733             if (!callerNetworksOnly) {
3734                 long ident = Binder.clearCallingIdentity();
3735                 try {
3736                     mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId,
3737                             callingUid, null);
3738                 } catch (SecurityException e) {
3739                     Log.w(TAG, "Permission violation - getConfiguredNetworks not allowed for uid="
3740                             + callingUid + ", packageName=" + packageName + ", reason=" + e);
3741                     return new ParceledListSlice<>(new ArrayList<>());
3742                 } finally {
3743                     Binder.restoreCallingIdentity(ident);
3744                 }
3745             }
3746         }
3747         boolean isDeviceOrProfileOwner = isDeviceOrProfileOwner(callingUid, packageName);
3748         boolean isCarrierApp = mWifiInjector.makeTelephonyManager()
3749                 .checkCarrierPrivilegesForPackageAnyPhone(packageName)
3750                 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
3751         boolean isPrivileged = isPrivileged(getCallingPid(), callingUid);
3752         // Only DO, PO, carrier app or system app can use callerNetworksOnly argument
3753         if (callerNetworksOnly) {
3754             if (!isDeviceOrProfileOwner && !isCarrierApp && !isPrivileged) {
3755                 throw new SecurityException(
3756                         "Not a DO, PO, carrier or privileged app");
3757             }
3758         }
3759         boolean isTargetSdkLessThanQOrPrivileged = isTargetSdkLessThanQOrPrivileged(
3760                 packageName, Binder.getCallingPid(), callingUid);
3761         if (!isTargetSdkLessThanQOrPrivileged && !isCarrierApp) {
3762             mLog.info("getConfiguredNetworks not allowed for uid=%")
3763                     .c(callingUid).flush();
3764             return new ParceledListSlice<>(new ArrayList<>());
3765         }
3766         if (mVerboseLoggingEnabled) {
3767             mLog.info("getConfiguredNetworks uid=%").c(callingUid).flush();
3768         }
3769 
3770         int targetConfigUid = Process.INVALID_UID; // don't expose any MAC addresses
3771         if (isPrivileged) {
3772             targetConfigUid = WIFI_UID; // expose all MAC addresses
3773         } else if (isCarrierApp || isDeviceOrProfileOwner) {
3774             targetConfigUid = callingUid; // expose only those configs created by the calling App
3775         }
3776         int finalTargetConfigUid = targetConfigUid;
3777         List<WifiConfiguration> configs = mWifiThreadRunner.call(
3778                 () -> mWifiConfigManager.getSavedNetworks(finalTargetConfigUid),
3779                 Collections.emptyList(), TAG + "#getConfiguredNetworks");
3780         if (isTargetSdkLessThanQOrPrivileged && !callerNetworksOnly) {
3781             return new ParceledListSlice<>(
3782                     WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(configs, false));
3783         }
3784         // Should only get its own configs
3785         List<WifiConfiguration> creatorConfigs = new ArrayList<>();
3786         for (WifiConfiguration config : configs) {
3787             if (config.creatorUid == callingUid) {
3788                 creatorConfigs.add(config);
3789             }
3790         }
3791         return new ParceledListSlice<>(
3792                 WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(
3793                         creatorConfigs, true));
3794     }
3795 
3796     /**
3797      * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
3798      *
3799      * @param packageName String name of the calling package
3800      * @param featureId The feature in the package
3801      * @param extras - Bundle of extra information
3802      * @return the list of configured networks with real preSharedKey
3803      */
3804     @Override
getPrivilegedConfiguredNetworks( String packageName, String featureId, Bundle extras)3805     public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks(
3806             String packageName, String featureId, Bundle extras) {
3807         enforceReadCredentialPermission();
3808         enforceAccessPermission();
3809         int callingUid = Binder.getCallingUid();
3810         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
3811         if (isPlatformOrTargetSdkLessThanT(packageName, callingUid)) {
3812             // For backward compatibility, do not check for nearby devices permission on pre-T
3813             // SDK version or if the app targets pre-T.
3814             long ident = Binder.clearCallingIdentity();
3815             try {
3816                 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
3817                         null);
3818             } catch (SecurityException e) {
3819                 Log.w(TAG, "Permission violation - getPrivilegedConfiguredNetworks not allowed"
3820                         + " for uid=" + callingUid + ", packageName=" + packageName + ", reason="
3821                         + e);
3822                 return null;
3823             } finally {
3824                 Binder.restoreCallingIdentity(ident);
3825             }
3826         } else {
3827             try {
3828                 mWifiPermissionsUtil.enforceNearbyDevicesPermission(
3829                         extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE),
3830                         false, TAG + " getPrivilegedConfiguredNetworks");
3831             } catch (SecurityException e) {
3832                 Log.w(TAG, "Permission violation - getPrivilegedConfiguredNetworks not allowed"
3833                         + " for uid=" + callingUid + ", packageName=" + packageName + ", reason="
3834                         + e);
3835                 return null;
3836             }
3837         }
3838         if (mVerboseLoggingEnabled) {
3839             mLog.info("getPrivilegedConfiguredNetworks uid=%").c(callingUid).flush();
3840         }
3841         List<WifiConfiguration> configs = mWifiThreadRunner.call(
3842                 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(),
3843                 Collections.emptyList(), TAG + "#getPrivilegedConfiguredNetworks");
3844         return new ParceledListSlice<>(
3845                 WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(configs, false));
3846     }
3847 
3848     /**
3849      * See {@link WifiManager#getPrivilegedConnectedNetwork()}
3850      */
3851     @Override
getPrivilegedConnectedNetwork(String packageName, String featureId, Bundle extras)3852     public WifiConfiguration getPrivilegedConnectedNetwork(String packageName, String featureId,
3853             Bundle extras) {
3854         enforceReadCredentialPermission();
3855         enforceAccessPermission();
3856         int callingUid = Binder.getCallingUid();
3857         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
3858         if (isPlatformOrTargetSdkLessThanT(packageName, callingUid)) {
3859             mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid,
3860                     null);
3861         } else {
3862             mWifiPermissionsUtil.enforceNearbyDevicesPermission(
3863                     extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE),
3864                     true, TAG + " getPrivilegedConnectedNetwork");
3865         }
3866         if (mVerboseLoggingEnabled) {
3867             mLog.info("getPrivilegedConnectedNetwork uid=%").c(callingUid).flush();
3868         }
3869 
3870         WifiInfo wifiInfo = mActiveModeWarden.getConnectionInfo();
3871         int networkId = wifiInfo.getNetworkId();
3872         if (networkId < 0) {
3873             if (mVerboseLoggingEnabled) {
3874                 mLog.info("getPrivilegedConnectedNetwork primary wifi not connected")
3875                         .flush();
3876             }
3877             return null;
3878         }
3879         WifiConfiguration config = mWifiThreadRunner.call(
3880                 () -> mWifiConfigManager.getConfiguredNetworkWithPassword(networkId), null,
3881                 TAG + "#getPrivilegedConnectedNetwork");
3882         if (config == null) {
3883             if (mVerboseLoggingEnabled) {
3884                 mLog.info("getPrivilegedConnectedNetwork failed to get config").flush();
3885             }
3886             return null;
3887         }
3888         // mask out the randomized MAC address
3889         config.setRandomizedMacAddress(MacAddress.fromString(WifiInfo.DEFAULT_MAC_ADDRESS));
3890         return config;
3891     }
3892 
3893     /**
3894      * See {@link WifiManager#setNetworkSelectionConfig(WifiNetworkSelectionConfig)}
3895      */
3896     @Override
3897     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setNetworkSelectionConfig(@onNull WifiNetworkSelectionConfig nsConfig)3898     public void setNetworkSelectionConfig(@NonNull WifiNetworkSelectionConfig nsConfig) {
3899         if (!SdkLevel.isAtLeastT()) {
3900             throw new UnsupportedOperationException();
3901         }
3902         if (nsConfig == null) {
3903             throw new IllegalArgumentException("Config can not be null");
3904         }
3905         if (!nsConfig.isValid()) {
3906             throw new IllegalArgumentException("Config is invalid.");
3907         }
3908         int uid = Binder.getCallingUid();
3909         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)
3910                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
3911             throw new SecurityException("Uid=" + uid + ", is not allowed to set network selection "
3912                     + "config");
3913         }
3914         mLog.info("uid=% WifiNetworkSelectionConfig=%")
3915                 .c(uid).c(nsConfig.toString()).flush();
3916 
3917         mWifiThreadRunner.post(() -> {
3918             mNetworkSelectionConfig = nsConfig;
3919             mWifiConnectivityManager.setNetworkSelectionConfig(nsConfig);
3920         }, TAG + "#setNetworkSelectionConfig");
3921         mLastCallerInfoManager.put(
3922                 WifiManager.API_SET_NETWORK_SELECTION_CONFIG,
3923                 Process.myTid(),
3924                 uid, Binder.getCallingPid(), "<unknown>", true);
3925     }
3926 
3927     /**
3928      * See {@link WifiManager#getNetworkSelectionConfig(Executor, Consumer)}
3929      */
3930     @Override
3931     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
getNetworkSelectionConfig(@onNull IWifiNetworkSelectionConfigListener listener)3932     public void getNetworkSelectionConfig(@NonNull IWifiNetworkSelectionConfigListener listener) {
3933         if (listener == null) {
3934             throw new IllegalArgumentException("listener should not be null");
3935         }
3936         if (!SdkLevel.isAtLeastT()) {
3937             throw new UnsupportedOperationException();
3938         }
3939         int uid = Binder.getCallingUid();
3940         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)
3941                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
3942             throw new SecurityException("Uid=" + uid + ", is not allowed to get network selection "
3943                     + "config");
3944         }
3945         mWifiThreadRunner.post(() -> {
3946             try {
3947                 if (mNetworkSelectionConfig == null) {
3948                     mNetworkSelectionConfig = new WifiNetworkSelectionConfig.Builder().build();
3949                 }
3950                 WifiNetworkSelectionConfig.Builder builder =
3951                         new WifiNetworkSelectionConfig.Builder(mNetworkSelectionConfig);
3952                 ScoringParams scoringParams = mWifiInjector.getScoringParams();
3953                 if (WifiNetworkSelectionConfig.isRssiThresholdResetArray(
3954                         mNetworkSelectionConfig.getRssiThresholds(WIFI_BAND_24_GHZ))) {
3955                     builder = builder.setRssiThresholds(WIFI_BAND_24_GHZ,
3956                             scoringParams.getRssiArray(ScanResult.BAND_24_GHZ_START_FREQ_MHZ));
3957                 }
3958                 if (WifiNetworkSelectionConfig.isRssiThresholdResetArray(
3959                         mNetworkSelectionConfig.getRssiThresholds(WIFI_BAND_5_GHZ))) {
3960                     builder = builder.setRssiThresholds(WIFI_BAND_5_GHZ,
3961                             scoringParams.getRssiArray(ScanResult.BAND_5_GHZ_START_FREQ_MHZ));
3962                 }
3963                 if (WifiNetworkSelectionConfig.isRssiThresholdResetArray(
3964                         mNetworkSelectionConfig.getRssiThresholds(WIFI_BAND_6_GHZ))) {
3965                     builder = builder.setRssiThresholds(WIFI_BAND_6_GHZ,
3966                             scoringParams.getRssiArray(ScanResult.BAND_6_GHZ_START_FREQ_MHZ));
3967                 }
3968                 mNetworkSelectionConfig = builder.build();
3969                 listener.onResult(mNetworkSelectionConfig);
3970             } catch (RemoteException e) {
3971                 Log.e(TAG, e.getMessage(), e);
3972             }
3973         }, TAG + "#getNetworkSelectionConfig");
3974     }
3975 
3976     /**
3977      * See {@link WifiManager#setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean)}
3978      */
3979     @Override
setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable)3980     public void setThirdPartyAppEnablingWifiConfirmationDialogEnabled(boolean enable) {
3981         int uid = Binder.getCallingUid();
3982         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
3983                 && !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
3984             throw new SecurityException("Uid=" + uid + ", is not allowed to enable warning dialog "
3985                     + "to display when third party apps start wifi");
3986         }
3987         mLog.info("uid=% enableWarningDialog=%").c(uid).c(enable).flush();
3988         mSettingsConfigStore.put(SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI, enable);
3989         mSettingsConfigStore.put(SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI_SET_BY_API, true);
3990         mLastCallerInfoManager.put(
3991                 WifiManager.API_SET_THIRD_PARTY_APPS_ENABLING_WIFI_CONFIRMATION_DIALOG,
3992                 Process.myTid(),
3993                 uid, Binder.getCallingPid(), "<unknown>", enable);
3994     }
3995 
showDialogWhenThirdPartyAppsEnableWifi()3996     private boolean showDialogWhenThirdPartyAppsEnableWifi() {
3997         if (mSettingsConfigStore.get(SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI_SET_BY_API)) {
3998             // API was called to override the overlay value.
3999             return mSettingsConfigStore.get(SHOW_DIALOG_WHEN_THIRD_PARTY_APPS_ENABLE_WIFI);
4000         } else {
4001             return mResourceCache.getBoolean(
4002                     R.bool.config_showConfirmationDialogForThirdPartyAppsEnablingWifi);
4003         }
4004     }
4005 
4006     /**
4007      * See {@link WifiManager#isThirdPartyAppEnablingWifiConfirmationDialogEnabled()}
4008      */
4009     @Override
isThirdPartyAppEnablingWifiConfirmationDialogEnabled()4010     public boolean isThirdPartyAppEnablingWifiConfirmationDialogEnabled() {
4011         int uid = Binder.getCallingUid();
4012         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
4013                 && !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
4014             throw new SecurityException("Uid=" + uid + ", is not allowed to check if warning "
4015                     + "dialog is enabled when third party apps start wifi");
4016         }
4017         return showDialogWhenThirdPartyAppsEnableWifi();
4018     }
4019 
4020     /**
4021      * See {@link WifiManager#setScreenOnScanSchedule(List)}
4022      */
4023     @Override
4024     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setScreenOnScanSchedule(int[] scanScheduleSeconds, int[] scanType)4025     public void setScreenOnScanSchedule(int[] scanScheduleSeconds, int[] scanType) {
4026         if (!SdkLevel.isAtLeastT()) {
4027             throw new UnsupportedOperationException();
4028         }
4029         if ((scanScheduleSeconds == null && scanType != null)
4030                 || (scanScheduleSeconds != null && scanType == null)) {
4031             throw new IllegalArgumentException("scanSchedule and scanType should be either both"
4032                     + " non-null or both null");
4033         }
4034         if (scanScheduleSeconds != null && scanScheduleSeconds.length < 1) {
4035             throw new IllegalArgumentException("scanSchedule should have length > 0, or be null");
4036         }
4037         if (scanType != null) {
4038             if (scanType.length < 1) {
4039                 throw new IllegalArgumentException("scanType should have length > 0, or be null");
4040             }
4041             for (int type : scanType) {
4042                 if (type < 0 || type > WifiScanner.SCAN_TYPE_MAX) {
4043                     throw new IllegalArgumentException("scanType=" + type
4044                             + " is not a valid value");
4045                 }
4046             }
4047         }
4048         int uid = Binder.getCallingUid();
4049         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)
4050                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4051             throw new SecurityException("Uid=" + uid + ", is not allowed to set scan schedule");
4052         }
4053         mLog.info("scanSchedule=% scanType=% uid=%").c(Arrays.toString(scanScheduleSeconds))
4054                 .c(Arrays.toString(scanType)).c(uid).flush();
4055         mWifiThreadRunner.post(() -> mWifiConnectivityManager.setExternalScreenOnScanSchedule(
4056                 scanScheduleSeconds, scanType), TAG + "#setScreenOnScanSchedule");
4057         mLastCallerInfoManager.put(WifiManager.API_SET_SCAN_SCHEDULE, Process.myTid(),
4058                 uid, Binder.getCallingPid(), "<unknown>",
4059                 scanScheduleSeconds != null);
4060     }
4061 
4062     @Override
4063     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
setOneShotScreenOnConnectivityScanDelayMillis(int delayMs)4064     public void setOneShotScreenOnConnectivityScanDelayMillis(int delayMs) {
4065         if (!SdkLevel.isAtLeastT()) {
4066             throw new UnsupportedOperationException();
4067         }
4068         if (delayMs < 0) {
4069             throw new IllegalArgumentException("delayMs should not be negative");
4070         }
4071         int uid = Binder.getCallingUid();
4072         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)
4073                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
4074             throw new SecurityException("Uid=" + uid + ", is not allowed to set screen-on scan "
4075                     + "delay");
4076         }
4077         mLog.info("delayMs=% uid=%").c(delayMs).c(uid).flush();
4078         mWifiThreadRunner.post(() ->
4079                 mWifiConnectivityManager.setOneShotScreenOnConnectivityScanDelayMillis(delayMs),
4080                 TAG + "#setOneShotScreenOnConnectivityScanDelayMillis");
4081         mLastCallerInfoManager.put(WifiManager.API_SET_ONE_SHOT_SCREEN_ON_CONNECTIVITY_SCAN_DELAY,
4082                 Process.myTid(), uid, Binder.getCallingPid(), "<unknown>",
4083                 delayMs > 0);
4084     }
4085 
4086     /**
4087      * Return a map of all matching configurations keys with corresponding scanResults (or an empty
4088      * map if none).
4089      *
4090      * @param scanResults The list of scan results
4091      * @return Map that consists of FQDN (Fully Qualified Domain Name) and corresponding
4092      * scanResults per network type({@link WifiManager#PASSPOINT_HOME_NETWORK} and {@link
4093      * WifiManager#PASSPOINT_ROAMING_NETWORK}).
4094      */
4095     @Override
4096     public Map<String, Map<Integer, List<ScanResult>>>
getAllMatchingPasspointProfilesForScanResults( ParceledListSlice<ScanResult> scanResults)4097             getAllMatchingPasspointProfilesForScanResults(
4098                     ParceledListSlice<ScanResult> scanResults) {
4099         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4100             throw new SecurityException(TAG + ": Permission denied");
4101         }
4102         if (mVerboseLoggingEnabled) {
4103             mLog.info("getMatchingPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
4104         }
4105         if (scanResults == null || !ScanResultUtil.validateScanResultList(scanResults.getList())) {
4106             Log.e(TAG, "Attempt to retrieve passpoint with invalid scanResult List");
4107             return Collections.emptyMap();
4108         }
4109         return mWifiThreadRunner.call(
4110             () -> mPasspointManager.getAllMatchingPasspointProfilesForScanResults(
4111                     scanResults.getList()), Collections.emptyMap(),
4112                 TAG + "#getAllMatchingPasspointProfilesForScanResults");
4113     }
4114 
4115     /**
4116      * See {@link WifiManager#setSsidsAllowlist(Set)}
4117      */
4118     @Override
setSsidsAllowlist(@onNull String packageName, @NonNull ParceledListSlice<WifiSsid> ssids)4119     public void setSsidsAllowlist(@NonNull String packageName,
4120             @NonNull ParceledListSlice<WifiSsid> ssids) {
4121         int uid = Binder.getCallingUid();
4122         mWifiPermissionsUtil.checkPackage(uid, packageName);
4123         boolean hasPermission = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
4124                 || isDeviceOrProfileOwner(uid, packageName);
4125         if (!hasPermission && SdkLevel.isAtLeastT()) {
4126             // MANAGE_WIFI_NETWORK_SELECTION is a new permission added in T.
4127             hasPermission = mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid);
4128         }
4129         if (!hasPermission) {
4130             throw new SecurityException(TAG + "Uid " + uid + ": Permission denied");
4131         }
4132         if (mVerboseLoggingEnabled) {
4133             mLog.info("setSsidsAllowlist uid=%").c(uid).flush();
4134         }
4135         List<WifiSsid> ssidList = ssids == null ? null : ssids.getList();
4136         mWifiThreadRunner.post(() -> mWifiBlocklistMonitor.setSsidsAllowlist(ssidList),
4137                 TAG + "#setSsidsAllowlist");
4138     }
4139 
4140     /**
4141      * See {@link WifiManager#getSsidsAllowlist()}
4142      */
4143     @Override
getSsidsAllowlist(String packageName)4144     public @NonNull ParceledListSlice<WifiSsid> getSsidsAllowlist(String packageName) {
4145         int uid = Binder.getCallingUid();
4146         mWifiPermissionsUtil.checkPackage(uid, packageName);
4147         boolean hasPermission = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
4148                 || isDeviceOrProfileOwner(uid, packageName);
4149         if (!hasPermission && SdkLevel.isAtLeastT()) {
4150             // MANAGE_WIFI_NETWORK_SELECTION is a new permission added in T.
4151             hasPermission = mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid);
4152         }
4153         if (!hasPermission) {
4154             throw new SecurityException(TAG + " Uid " + uid + ": Permission denied");
4155         }
4156         if (mVerboseLoggingEnabled) {
4157             mLog.info("getSsidsAllowlist uid=%").c(uid).flush();
4158         }
4159         return new ParceledListSlice<>(mWifiThreadRunner.call(
4160                 () -> mWifiBlocklistMonitor.getSsidsAllowlist(), Collections.EMPTY_LIST,
4161                 TAG + "#getSsidsAllowlist"));
4162     }
4163 
4164     /**
4165      * Returns list of OSU (Online Sign-Up) providers associated with the given list of ScanResult.
4166      *
4167      * @param scanResults a list of ScanResult that has Passpoint APs.
4168      * @return Map that consists of {@link OsuProvider} and a matching list of {@link ScanResult}.
4169      */
4170     @Override
getMatchingOsuProviders( ParceledListSlice<ScanResult> scanResults)4171     public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
4172             ParceledListSlice<ScanResult> scanResults) {
4173         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4174             throw new SecurityException(TAG + ": Permission denied");
4175         }
4176         if (mVerboseLoggingEnabled) {
4177             mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush();
4178         }
4179         if (scanResults == null || !ScanResultUtil.validateScanResultList(scanResults.getList())) {
4180             Log.w(TAG, "Attempt to retrieve OsuProviders with invalid scanResult List");
4181             return Collections.emptyMap();
4182         }
4183         return mWifiThreadRunner.call(
4184             () -> mPasspointManager.getMatchingOsuProviders(scanResults.getList()),
4185                 Collections.emptyMap(), TAG + "#getMatchingOsuProviders");
4186     }
4187 
4188     /**
4189      * Returns the matching Passpoint configurations for given OSU(Online Sign-Up) providers.
4190      *
4191      * @param osuProviders a list of {@link OsuProvider}
4192      * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}.
4193      */
4194     @Override
getMatchingPasspointConfigsForOsuProviders( ParceledListSlice<OsuProvider> osuProviders)4195     public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
4196             ParceledListSlice<OsuProvider> osuProviders) {
4197         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4198             throw new SecurityException(TAG + ": Permission denied");
4199         }
4200         if (mVerboseLoggingEnabled) {
4201             mLog.info("getMatchingPasspointConfigsForOsuProviders uid=%").c(
4202                     Binder.getCallingUid()).flush();
4203         }
4204         if (osuProviders == null || osuProviders.getList() == null) {
4205             Log.e(TAG, "Attempt to retrieve Passpoint configuration with null osuProviders");
4206             return new HashMap<>();
4207         }
4208         return mWifiThreadRunner.call(
4209             () -> mPasspointManager.getMatchingPasspointConfigsForOsuProviders(
4210                     osuProviders.getList()), Collections.emptyMap(),
4211                 TAG + "#getMatchingPasspointConfigsForOsuProviders");
4212     }
4213 
4214     /**
4215      * Returns the corresponding wifi configurations for given FQDN (Fully Qualified Domain Name)
4216      * list.
4217      *
4218      * An empty list will be returned when no match is found.
4219      *
4220      * @param fqdnList a list of FQDN
4221      * @return List of {@link WifiConfiguration} converted from {@link PasspointProvider}
4222      */
4223     @Override
getWifiConfigsForPasspointProfiles( StringParceledListSlice fqdnList)4224     public ParceledListSlice<WifiConfiguration> getWifiConfigsForPasspointProfiles(
4225             StringParceledListSlice fqdnList) {
4226         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4227             throw new SecurityException(TAG + ": Permission denied");
4228         }
4229         if (mVerboseLoggingEnabled) {
4230             mLog.info("getWifiConfigsForPasspointProfiles uid=%").c(
4231                     Binder.getCallingUid()).flush();
4232         }
4233         if (fqdnList == null || fqdnList.getList() == null || fqdnList.getList().isEmpty()) {
4234             Log.e(TAG, "Attempt to retrieve WifiConfiguration with null fqdn List");
4235             return new ParceledListSlice<>(Collections.emptyList());
4236         }
4237         return new ParceledListSlice<>(mWifiThreadRunner.call(
4238             () -> mPasspointManager.getWifiConfigsForPasspointProfiles(fqdnList.getList()),
4239                 Collections.emptyList(), TAG + "#getWifiConfigsForPasspointProfiles"));
4240     }
4241 
4242     /**
4243      * Returns a list of Wifi configurations for matched available WifiNetworkSuggestion
4244      * corresponding to the given scan results.
4245      *
4246      * An empty list will be returned when no match is found or all matched suggestions is not
4247      * available(not allow user manually connect, user not approved or open network).
4248      *
4249      * @param scanResults a list of {@link ScanResult}.
4250      * @return a list of {@link WifiConfiguration} from matched {@link WifiNetworkSuggestion}.
4251      */
4252     @Override
4253     public ParceledListSlice<WifiConfiguration>
getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( ParceledListSlice<ScanResult> scanResults)4254             getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
4255                     ParceledListSlice<ScanResult> scanResults) {
4256         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4257             throw new SecurityException(TAG + ": Permission denied");
4258         }
4259         if (mVerboseLoggingEnabled) {
4260             mLog.info("getWifiConfigsForMatchedNetworkSuggestions uid=%").c(
4261                     Binder.getCallingUid()).flush();
4262         }
4263         if (scanResults == null || !ScanResultUtil.validateScanResultList(scanResults.getList())) {
4264             Log.w(TAG, "Attempt to retrieve WifiConfiguration with invalid scanResult List");
4265             return new ParceledListSlice<>(Collections.emptyList());
4266         }
4267         return new ParceledListSlice<>(WifiConfigurationUtil.convertMultiTypeConfigsToLegacyConfigs(
4268                 mWifiThreadRunner.call(
4269                 () -> mWifiNetworkSuggestionsManager
4270                         .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(
4271                                 scanResults.getList()), Collections.emptyList(),
4272                 TAG + "#getWifiConfigForMatchedNetworkSuggestionsSharedWithUser"), true));
4273     }
4274 
4275     /**
4276      * see {@link WifiManager#addNetworkPrivileged(WifiConfiguration)}
4277      * @return WifiManager.AddNetworkResult Object.
4278      */
4279     @Override
addOrUpdateNetworkPrivileged( WifiConfiguration config, String packageName)4280     public @NonNull WifiManager.AddNetworkResult addOrUpdateNetworkPrivileged(
4281             WifiConfiguration config, String packageName) {
4282         int pid = Binder.getCallingPid();
4283         int uid = Binder.getCallingUid();
4284         mWifiPermissionsUtil.checkPackage(uid, packageName);
4285         boolean hasPermission = isPrivileged(pid, uid)
4286                 || mWifiPermissionsUtil.isAdmin(uid, packageName)
4287                 || mWifiPermissionsUtil.isSystem(packageName, uid);
4288         if (!hasPermission) {
4289             throw new SecurityException("Caller is not a device owner, profile owner, system app,"
4290                     + " or privileged app");
4291         }
4292         return addOrUpdateNetworkInternal(config, packageName, uid, packageName, false);
4293     }
4294 
4295     /**
4296      * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
4297      * @return the supplicant-assigned identifier for the new or updated
4298      * network if the operation succeeds, or {@code -1} if it fails
4299      */
4300     @Override
addOrUpdateNetwork(WifiConfiguration config, String packageName, Bundle extras)4301     public int addOrUpdateNetwork(WifiConfiguration config, String packageName, Bundle extras) {
4302         int uidToUse = getMockableCallingUid();
4303         String packageNameToUse = packageName;
4304         boolean overrideCreator = false;
4305 
4306         // if we're being called from the SYSTEM_UID then allow usage of the AttributionSource to
4307         // reassign the WifiConfiguration to another app (reassignment == creatorUid)
4308         if (SdkLevel.isAtLeastS() && UserHandle.getAppId(uidToUse) == Process.SYSTEM_UID) {
4309             if (extras == null) {
4310                 throw new SecurityException("extras bundle is null");
4311             }
4312             AttributionSource as = extras.getParcelable(
4313                     WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE);
4314             if (as == null) {
4315                 throw new SecurityException("addOrUpdateNetwork attributionSource is null");
4316             }
4317 
4318             if (!as.checkCallingUid()) {
4319                 throw new SecurityException(
4320                         "addOrUpdateNetwork invalid (checkCallingUid fails) attribution source="
4321                                 + as);
4322             }
4323 
4324             // an attribution chain is either of size 1: unregistered (valid by definition) or
4325             // size >1: in which case all are validated.
4326             if (as.getNext() != null) {
4327                 AttributionSource asIt = as;
4328                 AttributionSource asLast = as;
4329                 do {
4330                     if (!asIt.isTrusted(mContext)) {
4331                         throw new SecurityException(
4332                                 "addOrUpdateNetwork invalid (isTrusted fails) attribution source="
4333                                         + asIt);
4334                     }
4335                     asIt = asIt.getNext();
4336                     if (asIt != null) asLast = asIt;
4337                 } while (asIt != null);
4338 
4339                 // use the last AttributionSource in the chain - i.e. the original caller
4340                 uidToUse = asLast.getUid();
4341                 packageNameToUse = asLast.getPackageName();
4342                 if (config.networkId >= 0) {
4343                     /**
4344                      * only allow to override the creator by calling the
4345                      * {@link WifiManager#updateNetwork(WifiConfiguration)}
4346                      */
4347                     overrideCreator = true;
4348                 }
4349             }
4350         }
4351 
4352         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
4353             return -1;
4354         }
4355 
4356         int callingUid = Binder.getCallingUid();
4357         int callingPid = Binder.getCallingPid();
4358         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
4359         boolean isAdmin = mWifiPermissionsUtil.isAdmin(callingUid, packageName);
4360         boolean isCamera = mWifiPermissionsUtil.checkCameraPermission(callingUid);
4361         boolean isSystem = mWifiPermissionsUtil.isSystem(packageName, callingUid);
4362         boolean isPrivileged = isPrivileged(callingPid, callingUid);
4363         if (!isPrivileged && !isSystem && !isAdmin && config.getBssidAllowlistInternal() != null) {
4364             mLog.info("addOrUpdateNetwork with allow bssid list is not allowed for uid=%")
4365                     .c(callingUid).flush();
4366             return -1;
4367         }
4368 
4369         if (!isTargetSdkLessThanQOrPrivileged(packageName, callingPid, callingUid)) {
4370             mLog.info("addOrUpdateNetwork not allowed for uid=%").c(callingUid).flush();
4371             return -1;
4372         }
4373         long ident = Binder.clearCallingIdentity();
4374         try {
4375             if (mUserManager.hasUserRestrictionForUser(UserManager.DISALLOW_CONFIG_WIFI,
4376                     UserHandle.of(mWifiPermissionsUtil.getCurrentUser()))
4377                     && isCamera && !isAdmin) {
4378                 mLog.info(
4379                         "addOrUpdateNetwork not allowed for the camera apps and therefore the "
4380                                 + "user when DISALLOW_CONFIG_WIFI user restriction is set").flush();
4381                 return -1;
4382             }
4383             if (SdkLevel.isAtLeastT() && mUserManager.hasUserRestrictionForUser(
4384                     UserManager.DISALLOW_ADD_WIFI_CONFIG,
4385                     UserHandle.getUserHandleForUid(callingUid))) {
4386                 if (mWifiPermissionsUtil.isTargetSdkLessThan(
4387                         packageName, Build.VERSION_CODES.Q, callingUid)
4388                         && !(isPrivileged || isAdmin || isSystem)) {
4389                     mLog.info(
4390                             "addOrUpdateNetwork not allowed for normal apps targeting "
4391                                     + "SDK less than Q when the DISALLOW_ADD_WIFI_CONFIG "
4392                                     + "user restriction is set").flush();
4393                     return -1;
4394                 }
4395                 if (isCamera && !isAdmin) {
4396                     mLog.info(
4397                             "addOrUpdateNetwork not allowed for camera apps and therefore the "
4398                                     + "user when the DISALLOW_ADD_WIFI_CONFIG "
4399                                     + "user restriction is set").flush();
4400                     return -1;
4401                 }
4402             }
4403         } finally {
4404             Binder.restoreCallingIdentity(ident);
4405         }
4406 
4407         mLog.info("addOrUpdateNetwork uid=%").c(callingUid).flush();
4408         return addOrUpdateNetworkInternal(config, packageName, uidToUse,
4409                 packageNameToUse, overrideCreator).networkId;
4410     }
4411 
addOrUpdateNetworkInternal(WifiConfiguration config, String packageName, int attributedCreatorUid, String attributedCreatorPackage, boolean overrideCreator)4412     private @NonNull AddNetworkResult addOrUpdateNetworkInternal(WifiConfiguration config,
4413             String packageName, int attributedCreatorUid, String attributedCreatorPackage,
4414             boolean overrideCreator) {
4415         if (config == null) {
4416             Log.e(TAG, "bad network configuration");
4417             return new AddNetworkResult(
4418                     AddNetworkResult.STATUS_INVALID_CONFIGURATION, -1);
4419         }
4420         mWifiMetrics.incrementNumAddOrUpdateNetworkCalls();
4421 
4422         // Previously, this API is overloaded for installing Passpoint profiles.  Now
4423         // that we have a dedicated API for doing it, redirect the call to the dedicated API.
4424         if (config.isPasspoint()) {
4425             PasspointConfiguration passpointConfig =
4426                     PasspointProvider.convertFromWifiConfig(config);
4427             if (passpointConfig == null || passpointConfig.getCredential() == null) {
4428                 Log.e(TAG, "Missing credential for Passpoint profile");
4429                 return new AddNetworkResult(
4430                         AddNetworkResult.STATUS_ADD_PASSPOINT_FAILURE, -1);
4431             }
4432 
4433             // Copy over certificates and keys.
4434             X509Certificate[] x509Certificates = null;
4435             if (config.enterpriseConfig.getCaCertificate() != null) {
4436                 x509Certificates =
4437                         new X509Certificate[]{config.enterpriseConfig.getCaCertificate()};
4438             }
4439             passpointConfig.getCredential().setCaCertificates(x509Certificates);
4440             passpointConfig.getCredential().setClientCertificateChain(
4441                     config.enterpriseConfig.getClientCertificateChain());
4442             passpointConfig.getCredential().setClientPrivateKey(
4443                     config.enterpriseConfig.getClientPrivateKey());
4444             if (!addOrUpdatePasspointConfiguration(passpointConfig, packageName)) {
4445                 Log.e(TAG, "Failed to add Passpoint profile");
4446                 return new AddNetworkResult(
4447                         AddNetworkResult.STATUS_ADD_PASSPOINT_FAILURE, -1);
4448             }
4449             // There is no network ID associated with a Passpoint profile.
4450             return new AddNetworkResult(AddNetworkResult.STATUS_SUCCESS, 0);
4451         }
4452 
4453         mLastCallerInfoManager.put(config.networkId < 0
4454                         ? WifiManager.API_ADD_NETWORK : WifiManager.API_UPDATE_NETWORK,
4455                 Process.myTid(), Binder.getCallingUid(),
4456                 Binder.getCallingPid(), packageName, true);
4457         Log.i("addOrUpdateNetworkInternal", " uid = " + Binder.getCallingUid()
4458                 + " SSID " + config.SSID
4459                 + " nid=" + config.networkId);
4460         NetworkUpdateResult result = mWifiThreadRunner.call(
4461                 () -> mWifiConfigManager.addOrUpdateNetwork(config, attributedCreatorUid,
4462                         attributedCreatorPackage, overrideCreator),
4463                 new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID),
4464                 TAG + "#addOrUpdateNetworkInternal");
4465         return new AddNetworkResult(result.getStatusCode(), result.getNetworkId());
4466     }
4467 
verifyCert(X509Certificate caCert)4468     public static void verifyCert(X509Certificate caCert)
4469             throws GeneralSecurityException, IOException {
4470         CertificateFactory factory = CertificateFactory.getInstance("X.509");
4471         CertPathValidator validator =
4472                 CertPathValidator.getInstance(CertPathValidator.getDefaultType());
4473         CertPath path = factory.generateCertPath(
4474                 Arrays.asList(caCert));
4475         KeyStore ks = KeyStore.getInstance("AndroidCAStore");
4476         ks.load(null, null);
4477         PKIXParameters params = new PKIXParameters(ks);
4478         params.setRevocationEnabled(false);
4479         validator.validate(path, params);
4480     }
4481 
4482     /**
4483      * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
4484      * @param netId the integer that identifies the network configuration
4485      * to the supplicant
4486      * @return {@code true} if the operation succeeded
4487      */
4488     @Override
removeNetwork(int netId, String packageName)4489     public boolean removeNetwork(int netId, String packageName) {
4490         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
4491             return false;
4492         }
4493         int callingUid = Binder.getCallingUid();
4494         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
4495         if (!isTargetSdkLessThanQOrPrivileged(
4496                 packageName, Binder.getCallingPid(), callingUid)) {
4497             mLog.info("removeNetwork not allowed for uid=%").c(callingUid).flush();
4498             return false;
4499         }
4500         mLog.info("removeNetwork uid=%").c(callingUid).flush();
4501         return mWifiThreadRunner.call(
4502                 () -> mWifiConfigManager.removeNetwork(netId, callingUid, packageName), false,
4503                 TAG + "#removeNetwork");
4504     }
4505 
4506     @Override
removeNonCallerConfiguredNetworks(String packageName)4507     public boolean removeNonCallerConfiguredNetworks(String packageName) {
4508         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
4509             throw new SecurityException("Caller does not hold CHANGE_WIFI_STATE permission");
4510         }
4511         final int callingUid = Binder.getCallingUid();
4512         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
4513         if (!mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin(callingUid, packageName)) {
4514             throw new SecurityException("Caller is not device owner or profile owner "
4515                     + "of an organization owned device");
4516         }
4517         return mWifiThreadRunner.call(
4518                 () -> mWifiConfigManager.removeNonCallerConfiguredNetwork(callingUid), false,
4519                 TAG + "#removeNonCallerConfiguredNetworks");
4520     }
4521 
4522     /**
4523      * Trigger a connect request and wait for the callback to return status.
4524      * This preserves the legacy connect API behavior, i.e. {@link WifiManager#enableNetwork(
4525      * int, true)}
4526      * @return
4527      */
triggerConnectAndReturnStatus(int netId, int callingUid, @NonNull String packageName)4528     private boolean triggerConnectAndReturnStatus(int netId, int callingUid,
4529             @NonNull String packageName) {
4530         final CountDownLatch countDownLatch = new CountDownLatch(1);
4531         final Mutable<Boolean> success = new Mutable<>(false);
4532         IActionListener.Stub connectListener = new IActionListener.Stub() {
4533             @Override
4534             public void onSuccess() {
4535                 success.value = true;
4536                 countDownLatch.countDown();
4537             }
4538             @Override
4539             public void onFailure(int reason) {
4540                 success.value = false;
4541                 countDownLatch.countDown();
4542             }
4543         };
4544         mWifiThreadRunner.post(() ->
4545                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
4546                         mConnectHelper.connectToNetwork(
4547                                 new NetworkUpdateResult(netId),
4548                                 new ActionListenerWrapper(connectListener),
4549                                 callingUid, packageName, null)
4550                 ), TAG + "#triggerConnectAndReturnStatus"
4551         );
4552         // now wait for response.
4553         try {
4554             countDownLatch.await(RUN_WITH_SCISSORS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
4555         } catch (InterruptedException e) {
4556             Log.e(TAG, "Failed to retrieve connect status");
4557         }
4558         return success.value;
4559     }
4560 
4561     /**
4562      * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
4563      * @param netId the integer that identifies the network configuration
4564      * to the supplicant
4565      * @param disableOthers if true, disable all other networks.
4566      * @return {@code true} if the operation succeeded
4567      */
4568     @Override
enableNetwork(int netId, boolean disableOthers, @NonNull String packageName)4569     public boolean enableNetwork(int netId, boolean disableOthers, @NonNull String packageName) {
4570         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
4571             return false;
4572         }
4573         if (packageName == null) {
4574             throw new IllegalArgumentException("packageName must not be null");
4575         }
4576         int callingUid = Binder.getCallingUid();
4577         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
4578         if (!isTargetSdkLessThanQOrPrivileged(
4579                 packageName, Binder.getCallingPid(), callingUid)) {
4580             mLog.info("enableNetwork not allowed for uid=%").c(callingUid).flush();
4581             return false;
4582         }
4583         WifiConfiguration configuration = mWifiConfigManager.getConfiguredNetwork(netId);
4584         if (mWifiPermissionsUtil.isAdminRestrictedNetwork(configuration)) {
4585             mLog.info("enableNetwork not allowed for admin restricted network Id=%")
4586                     .c(netId).flush();
4587             return false;
4588         }
4589         if (mWifiGlobals.isDeprecatedSecurityTypeNetwork(configuration)) {
4590             mLog.info("enableNetwork not allowed for deprecated security type network Id=%")
4591                     .c(netId).flush();
4592             return false;
4593         }
4594 
4595         mLastCallerInfoManager.put(WifiManager.API_ENABLE_NETWORK, Process.myTid(),
4596                 callingUid, Binder.getCallingPid(), packageName, disableOthers);
4597         // TODO b/33807876 Log netId
4598         mLog.info("enableNetwork uid=% disableOthers=%")
4599                 .c(callingUid)
4600                 .c(disableOthers).flush();
4601 
4602         mWifiMetrics.incrementNumEnableNetworkCalls();
4603         if (disableOthers) {
4604             return triggerConnectAndReturnStatus(netId, callingUid, packageName);
4605         } else {
4606             return mWifiThreadRunner.call(
4607                     () -> mWifiConfigManager.enableNetwork(netId, false, callingUid, packageName),
4608                     false,
4609                     TAG + "#enableNetwork");
4610         }
4611     }
4612 
4613     /**
4614      * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
4615      * @param netId the integer that identifies the network configuration
4616      * to the supplicant
4617      * @return {@code true} if the operation succeeded
4618      */
4619     @Override
disableNetwork(int netId, String packageName)4620     public boolean disableNetwork(int netId, String packageName) {
4621         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
4622             return false;
4623         }
4624         int callingUid = Binder.getCallingUid();
4625         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
4626         if (!isTargetSdkLessThanQOrPrivileged(
4627                 packageName, Binder.getCallingPid(), callingUid)) {
4628             mLog.info("disableNetwork not allowed for uid=%").c(callingUid).flush();
4629             return false;
4630         }
4631         mLastCallerInfoManager.put(WifiManager.API_DISABLE_NETWORK, Process.myTid(),
4632                 callingUid, Binder.getCallingPid(), packageName, true);
4633         mLog.info("disableNetwork uid=%").c(callingUid).flush();
4634         return mWifiThreadRunner.call(
4635                 () -> mWifiConfigManager.disableNetwork(netId, callingUid, packageName), false,
4636                 TAG + "#disableNetwork");
4637     }
4638 
4639     /**
4640      * See
4641      * {@link android.net.wifi.WifiManager#startRestrictingAutoJoinToSubscriptionId(int)}
4642      * @param subscriptionId the subscription ID of the carrier whose merged wifi networks won't be
4643      *                       disabled.
4644      */
4645     @Override
4646     @RequiresApi(Build.VERSION_CODES.S)
startRestrictingAutoJoinToSubscriptionId(int subscriptionId)4647     public void startRestrictingAutoJoinToSubscriptionId(int subscriptionId) {
4648         if (!SdkLevel.isAtLeastS()) {
4649             throw new UnsupportedOperationException();
4650         }
4651         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4652             throw new SecurityException(TAG + ": Permission denied");
4653         }
4654 
4655         mLog.info("startRestrictingAutoJoinToSubscriptionId=% uid=%").c(subscriptionId)
4656                 .c(Binder.getCallingUid()).flush();
4657         mWifiThreadRunner.post(() -> {
4658             mWifiConfigManager
4659                     .startRestrictingAutoJoinToSubscriptionId(subscriptionId);
4660             // Clear all cached candidates to avoid the imminent disconnect connecting back to a
4661             // cached candidate that's likely no longer valid after
4662             // startRestrictingAutoJoinToSubscriptionId is called. Let the disconnection trigger
4663             // a new scan to ensure proper network selection is done.
4664             mWifiConnectivityManager.clearCachedCandidates();
4665             // always disconnect here and rely on auto-join to find the appropriate carrier network
4666             // to join. Even if we are currently connected to the carrier-merged wifi, it's still
4667             // better to disconnect here because it's possible that carrier wifi offload is
4668             // disabled.
4669             for (ClientModeManager clientModeManager : mActiveModeWarden.getClientModeManagers()) {
4670                 if (!(clientModeManager instanceof ConcreteClientModeManager)) {
4671                     continue;
4672                 }
4673                 ConcreteClientModeManager cmm = (ConcreteClientModeManager) clientModeManager;
4674                 if ((cmm.getRole() == ROLE_CLIENT_SECONDARY_LONG_LIVED && cmm.isSecondaryInternet())
4675                         || cmm.getRole() == ROLE_CLIENT_SECONDARY_TRANSIENT) {
4676                     clientModeManager.disconnect();
4677                 }
4678             }
4679             // Disconnect the primary CMM last to avoid STA+STA features handling the
4680             // primary STA disconnecting (such as promoting the secondary to primary), potentially
4681             // resulting in messy and unexpected state transitions.
4682             mActiveModeWarden.getPrimaryClientModeManager().disconnect();
4683         }, TAG + "#startRestrictingAutoJoinToSubscriptionId");
4684     }
4685 
4686     /**
4687      * See {@link android.net.wifi.WifiManager#stopRestrictingAutoJoinToSubscriptionId()}
4688      */
4689     @Override
4690     @RequiresApi(Build.VERSION_CODES.S)
stopRestrictingAutoJoinToSubscriptionId()4691     public void stopRestrictingAutoJoinToSubscriptionId() {
4692         if (!SdkLevel.isAtLeastS()) {
4693             throw new UnsupportedOperationException();
4694         }
4695         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
4696             throw new SecurityException(TAG + ": Permission denied");
4697         }
4698 
4699         mLog.info("stopRestrictingAutoJoinToSubscriptionId uid=%")
4700                 .c(Binder.getCallingUid()).flush();
4701         mWifiThreadRunner.post(() ->
4702                 mWifiConfigManager.stopRestrictingAutoJoinToSubscriptionId(),
4703                 TAG + "#stopRestrictingAutoJoinToSubscriptionId");
4704     }
4705 
4706     /**
4707      * See {@link android.net.wifi.WifiManager#allowAutojoinGlobal(boolean)}
4708      * @param choice the OEM's choice to allow auto-join
4709      */
4710     @Override
allowAutojoinGlobal(boolean choice, String packageName, Bundle extras)4711     public void allowAutojoinGlobal(boolean choice, String packageName, Bundle extras) {
4712         int callingUid = Binder.getCallingUid();
4713         boolean isDeviceAdmin = mWifiPermissionsUtil.isAdmin(callingUid, packageName);
4714         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)
4715                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(callingUid)
4716                 && !isDeviceAdmin) {
4717             throw new SecurityException("Uid " + callingUid
4718                     + " is not allowed to set wifi global autojoin");
4719         }
4720         mLog.info("allowAutojoinGlobal=% uid=%").c(choice).c(callingUid).flush();
4721         if (!isDeviceAdmin && SdkLevel.isAtLeastS()) {
4722             // direct caller is not device admin but there exists and attribution chain. Check
4723             // if the original caller is device admin.
4724             AttributionSource as = extras.getParcelable(
4725                     WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE);
4726             if (as != null) {
4727                 AttributionSource asLast = as;
4728                 while (asLast.getNext() != null) {
4729                     asLast = asLast.getNext();
4730                 }
4731                 isDeviceAdmin = mWifiPermissionsUtil.isAdmin(asLast.getUid(),
4732                         asLast.getPackageName()) || mWifiPermissionsUtil.isLegacyDeviceAdmin(
4733                                 asLast.getUid(), asLast.getPackageName());
4734             }
4735         }
4736         boolean finalIsDeviceAdmin = isDeviceAdmin;
4737         mWifiThreadRunner.post(() -> mWifiConnectivityManager.setAutoJoinEnabledExternal(choice,
4738                 finalIsDeviceAdmin), TAG + "#allowAutojoinGlobal");
4739         mLastCallerInfoManager.put(WifiManager.API_AUTOJOIN_GLOBAL, Process.myTid(),
4740                 callingUid, Binder.getCallingPid(), "<unknown>", choice);
4741     }
4742 
4743     /**
4744      * See {@link WifiManager#queryAutojoinGlobal(Executor, Consumer)}
4745      */
4746     @Override
queryAutojoinGlobal(@onNull IBooleanListener listener)4747     public void queryAutojoinGlobal(@NonNull IBooleanListener listener) {
4748         if (listener == null) {
4749             throw new IllegalArgumentException("listener should not be null");
4750         }
4751         int callingUid = Binder.getCallingUid();
4752         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)
4753                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(callingUid)
4754                 && !isDeviceOrProfileOwner(callingUid, mContext.getOpPackageName())) {
4755             throw new SecurityException("Uid " + callingUid
4756                     + " is not allowed to get wifi global autojoin");
4757         }
4758         mWifiThreadRunner.post(() -> {
4759             try {
4760                 listener.onResult(mWifiConnectivityManager.getAutoJoinEnabledExternal());
4761             } catch (RemoteException e) {
4762                 Log.e(TAG, e.getMessage(), e);
4763             }
4764         }, TAG + "#queryAutojoinGlobal");
4765     }
4766 
4767     /**
4768      * See {@link android.net.wifi.WifiManager#allowAutojoin(int, boolean)}
4769      * @param netId the integer that identifies the network configuration
4770      * @param choice the user's choice to allow auto-join
4771      */
4772     @Override
allowAutojoin(int netId, boolean choice)4773     public void allowAutojoin(int netId, boolean choice) {
4774         enforceNetworkSettingsPermission();
4775 
4776         int callingUid = Binder.getCallingUid();
4777         mLog.info("allowAutojoin=% uid=%").c(choice).c(callingUid).flush();
4778         mLastCallerInfoManager.put(WifiManager.API_ALLOW_AUTOJOIN, Process.myTid(),
4779                 callingUid, Binder.getCallingPid(), "<unknown>", choice);
4780         mWifiThreadRunner.post(() -> {
4781             WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId);
4782             if (config == null) {
4783                 return;
4784             }
4785             if (config.fromWifiNetworkSpecifier) {
4786                 Log.e(TAG, "Auto-join configuration is not permitted for NetworkSpecifier "
4787                         + "connections: " + config);
4788                 return;
4789             }
4790             if (config.isPasspoint() && !config.isEphemeral()) {
4791                 Log.e(TAG,
4792                         "Auto-join configuration for a non-ephemeral Passpoint network should be "
4793                                 + "configured using FQDN: "
4794                                 + config);
4795                 return;
4796             }
4797             // If the network is a suggestion, store the auto-join configure to the
4798             // WifiNetWorkSuggestionsManager.
4799             if (config.fromWifiNetworkSuggestion) {
4800                 if (!mWifiNetworkSuggestionsManager
4801                         .allowNetworkSuggestionAutojoin(config, choice)) {
4802                     return;
4803                 }
4804             }
4805             // even for Suggestion, modify the current ephemeral configuration so that
4806             // existing configuration auto-connection is updated correctly
4807             if (choice != config.allowAutojoin) {
4808                 mWifiConfigManager.allowAutojoin(netId, choice);
4809                 // do not log this metrics for passpoint networks again here since it's already
4810                 // logged in PasspointManager.
4811                 if (!config.isPasspoint()) {
4812                     mWifiMetrics.logUserActionEvent(choice
4813                             ? UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON
4814                             : UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF, netId);
4815                 }
4816             }
4817         }, TAG + "#allowAutojoin");
4818     }
4819 
4820     /**
4821      * See {@link android.net.wifi.WifiManager#allowAutojoinPasspoint(String, boolean)}
4822      * @param fqdn the FQDN that identifies the passpoint configuration
4823      * @param enableAutojoin true to enable auto-join, false to disable
4824      */
4825     @Override
allowAutojoinPasspoint(String fqdn, boolean enableAutojoin)4826     public void allowAutojoinPasspoint(String fqdn, boolean enableAutojoin) {
4827         enforceNetworkSettingsPermission();
4828         if (fqdn == null) {
4829             throw new IllegalArgumentException("FQDN cannot be null");
4830         }
4831 
4832         int callingUid = Binder.getCallingUid();
4833         mLog.info("allowAutojoinPasspoint=% uid=%").c(enableAutojoin).c(callingUid).flush();
4834         mWifiThreadRunner.post(
4835                 () -> mPasspointManager.enableAutojoin(null, fqdn, enableAutojoin),
4836                 TAG + "#allowAutojoinPasspoint");
4837     }
4838 
4839     /**
4840      * See {@link WifiManager#getBssidBlocklist(List, Executor, Consumer)}
4841      * @param ssids the list of ssids to get BSSID blocklist for.
4842      * @param listener returns the results
4843      */
4844     @Override
getBssidBlocklist(@onNull ParceledListSlice<WifiSsid> ssids, @NonNull IMacAddressListListener listener)4845     public void getBssidBlocklist(@NonNull ParceledListSlice<WifiSsid> ssids,
4846             @NonNull IMacAddressListListener listener) {
4847         if (ssids == null || ssids.getList() == null) {
4848             throw new IllegalArgumentException("Null ssids");
4849         }
4850         if (listener == null) {
4851             throw new IllegalArgumentException("Null listener");
4852         }
4853         int uid = Binder.getCallingUid();
4854         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
4855                 && !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
4856             throw new SecurityException("No permission to call getBssidBlocklist");
4857         }
4858         Set<String> ssidSet;
4859         if (!ssids.getList().isEmpty()) {
4860             ssidSet = new ArraySet<>();
4861             for (WifiSsid ssid : ssids.getList()) {
4862                 ssidSet.add(ssid.toString());
4863             }
4864         } else {
4865             ssidSet = null;
4866         }
4867         mWifiThreadRunner.post(() -> {
4868             try {
4869                 List<String> bssids = mWifiBlocklistMonitor.getBssidBlocklistForSsids(ssidSet);
4870                 List<MacAddress> macAddresses = new ArrayList<>();
4871                 for (String bssid : bssids) {
4872                     try {
4873                         macAddresses.add(MacAddress.fromString(bssid));
4874                     } catch (Exception e) {
4875                         Log.e(TAG, "getBssidBlocklist failed to convert MAC address: " + bssid);
4876                     }
4877                 }
4878                 listener.onResult(new ParceledListSlice(macAddresses));
4879             } catch (RemoteException e) {
4880                 Log.e(TAG, e.getMessage(), e);
4881             }
4882         }, TAG + "#getBssidBlocklist");
4883     }
4884 
4885     /**
4886      * See {@link android.net.wifi.WifiManager
4887      * #setMacRandomizationSettingPasspointEnabled(String, boolean)}
4888      * @param fqdn the FQDN that identifies the passpoint configuration
4889      * @param enable true to enable mac randomization, false to disable
4890      */
4891     @Override
setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable)4892     public void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable) {
4893         enforceNetworkSettingsPermission();
4894         if (fqdn == null) {
4895             throw new IllegalArgumentException("FQDN cannot be null");
4896         }
4897 
4898         int callingUid = Binder.getCallingUid();
4899         mLog.info("setMacRandomizationSettingPasspointEnabled=% uid=%")
4900                 .c(enable).c(callingUid).flush();
4901         mWifiThreadRunner.post(
4902                 () -> mPasspointManager.enableMacRandomization(fqdn, enable),
4903                 TAG + "#setMacRandomizationSettingPasspointEnabled");
4904     }
4905 
4906     /**
4907      * See {@link android.net.wifi.WifiManager#setPasspointMeteredOverride(String, boolean)}
4908      * @param fqdn the FQDN that identifies the passpoint configuration
4909      * @param meteredOverride One of the values in {@link MeteredOverride}
4910      */
4911     @Override
setPasspointMeteredOverride(String fqdn, int meteredOverride)4912     public void setPasspointMeteredOverride(String fqdn, int meteredOverride) {
4913         enforceNetworkSettingsPermission();
4914         if (fqdn == null) {
4915             throw new IllegalArgumentException("FQDN cannot be null");
4916         }
4917 
4918         int callingUid = Binder.getCallingUid();
4919         mLog.info("setPasspointMeteredOverride=% uid=%")
4920                 .c(meteredOverride).c(callingUid).flush();
4921         mWifiThreadRunner.post(
4922                 () -> mPasspointManager.setMeteredOverride(fqdn, meteredOverride),
4923                 TAG + "#setPasspointMeteredOverride");
4924     }
4925 
4926     /**
4927      * Provides backward compatibility for apps using
4928      * {@link WifiManager#getConnectionInfo()}, {@link WifiManager#getDhcpInfo()} when a
4929      * secondary STA is created as a result of a request from their app (peer to peer
4930      * WifiNetworkSpecifier request or oem paid/private suggestion).
4931      */
getClientModeManagerIfSecondaryCmmRequestedByCallerPresent( int callingUid, @NonNull String callingPackageName)4932     private ClientModeManager getClientModeManagerIfSecondaryCmmRequestedByCallerPresent(
4933             int callingUid, @NonNull String callingPackageName) {
4934         List<ConcreteClientModeManager> secondaryCmms = null;
4935         ActiveModeManager.ClientConnectivityRole roleSecondaryLocalOnly =
4936                 ROLE_CLIENT_LOCAL_ONLY;
4937         ActiveModeManager.ClientInternetConnectivityRole roleSecondaryLongLived =
4938                 ROLE_CLIENT_SECONDARY_LONG_LIVED;
4939         try {
4940             secondaryCmms = mActiveModeWarden.getClientModeManagersInRoles(
4941                     roleSecondaryLocalOnly, roleSecondaryLongLived);
4942         } catch (Exception e) {
4943             // print debug info and then rethrow the exception
4944             Log.e(TAG, "Failed to call getClientModeManagersInRoles on "
4945                     + roleSecondaryLocalOnly + ", and " + roleSecondaryLongLived);
4946             throw e;
4947         }
4948 
4949         for (ConcreteClientModeManager cmm : secondaryCmms) {
4950             WorkSource reqWs = new WorkSource(cmm.getRequestorWs());
4951             if (reqWs.size() > 1 && cmm.getRole() == roleSecondaryLocalOnly) {
4952                 // Remove promoted settings WorkSource if present
4953                 reqWs.remove(mFrameworkFacade.getSettingsWorkSource(mContext));
4954             }
4955             WorkSource withCaller = new WorkSource(reqWs);
4956             withCaller.add(new WorkSource(callingUid, callingPackageName));
4957             // If there are more than 1 secondary CMM for same app, return any one (should not
4958             // happen currently since we don't support 3 STA's concurrently).
4959             if (reqWs.equals(withCaller)) {
4960                 mLog.info("getConnectionInfo providing secondary CMM info").flush();
4961                 return cmm;
4962             }
4963         }
4964         // No secondary CMM's created for the app, return primary CMM.
4965         return mActiveModeWarden.getPrimaryClientModeManager();
4966     }
4967 
4968     /**
4969      * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
4970      * @return the Wi-Fi information, contained in {@link WifiInfo}.
4971      */
4972     @Override
getConnectionInfo(@onNull String callingPackage, @Nullable String callingFeatureId)4973     public WifiInfo getConnectionInfo(@NonNull String callingPackage,
4974             @Nullable String callingFeatureId) {
4975         enforceAccessPermission();
4976         int uid = Binder.getCallingUid();
4977         if (mVerboseLoggingEnabled) {
4978             mLog.info("getConnectionInfo uid=%").c(uid).flush();
4979         }
4980         mWifiPermissionsUtil.checkPackage(uid, callingPackage);
4981         if (mActiveModeWarden.getWifiState() != WIFI_STATE_ENABLED) {
4982             return new WifiInfo();
4983         }
4984         WifiInfo wifiInfo;
4985         if (isCurrentRequestWsContainsCaller(uid, callingPackage)) {
4986             wifiInfo =
4987                     mWifiThreadRunner.call(
4988                             () ->
4989                                     getClientModeManagerIfSecondaryCmmRequestedByCallerPresent(
4990                                                     uid, callingPackage)
4991                                             .getConnectionInfo(),
4992                             new WifiInfo(), TAG + "#getConnectionInfo");
4993         } else {
4994             // If no caller
4995             wifiInfo = mActiveModeWarden.getConnectionInfo();
4996         }
4997         long ident = Binder.clearCallingIdentity();
4998         try {
4999             long redactions = wifiInfo.getApplicableRedactions();
5000             if (mWifiPermissionsUtil.checkLocalMacAddressPermission(uid)) {
5001                 if (mVerboseLoggingEnabled) {
5002                     Log.v(TAG, "Clearing REDACT_FOR_LOCAL_MAC_ADDRESS for " + callingPackage
5003                             + "(uid=" + uid + ")");
5004                 }
5005                 redactions &= ~NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
5006             }
5007             if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
5008                     || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
5009                 if (mVerboseLoggingEnabled) {
5010                     Log.v(TAG, "Clearing REDACT_FOR_NETWORK_SETTINGS for " + callingPackage
5011                             + "(uid=" + uid + ")");
5012                 }
5013                 redactions &= ~NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
5014             }
5015             try {
5016                 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
5017                         uid, null);
5018                 if (mVerboseLoggingEnabled) {
5019                     Log.v(TAG, "Clearing REDACT_FOR_ACCESS_FINE_LOCATION for " + callingPackage
5020                             + "(uid=" + uid + ")");
5021                 }
5022                 redactions &= ~NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
5023             } catch (SecurityException ignored) {
5024                 if (mVerboseLoggingEnabled) {
5025                     Log.v(TAG, "Keeping REDACT_FOR_ACCESS_FINE_LOCATION:" + ignored);
5026                 }
5027             }
5028             return wifiInfo.makeCopy(redactions);
5029         } finally {
5030             Binder.restoreCallingIdentity(ident);
5031         }
5032     }
5033 
isCurrentRequestWsContainsCaller(int uid, String callingPackage)5034     private boolean isCurrentRequestWsContainsCaller(int uid, String callingPackage) {
5035         Set<WorkSource> requestWs = mActiveModeWarden.getSecondaryRequestWs();
5036         for (WorkSource ws : requestWs) {
5037             WorkSource reqWs = new WorkSource(ws);
5038             if (reqWs.size() > 1) {
5039                 // Remove promoted settings WorkSource if present
5040                 reqWs.remove(mFrameworkFacade.getSettingsWorkSource(mContext));
5041             }
5042             WorkSource withCaller = new WorkSource(reqWs);
5043             withCaller.add(new WorkSource(uid, callingPackage));
5044             if (reqWs.equals(withCaller)) {
5045                 return true;
5046             }
5047         }
5048         return false;
5049     }
5050 
5051     /**
5052      * Return the results of the most recent access point scan, in the form of
5053      * a list of {@link ScanResult} objects.
5054      * @return the list of results
5055      */
5056     @Override
getScanResults(String callingPackage, String callingFeatureId)5057     @Nullable public ParceledListSlice<ScanResult> getScanResults(String callingPackage,
5058             String callingFeatureId) {
5059         enforceAccessPermission();
5060         int uid = Binder.getCallingUid();
5061         long ident = Binder.clearCallingIdentity();
5062         if (mVerboseLoggingEnabled) {
5063             mLog.info("getScanResults uid=%").c(uid).flush();
5064         }
5065         try {
5066             mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
5067                     uid, null);
5068             List<ScanResult> scanResults = mWifiThreadRunner.call(
5069                     mScanRequestProxy::getScanResults, Collections.emptyList(),
5070                     TAG + "#getScanResults");
5071             if (scanResults.size() > 200) {
5072                 Log.i(TAG, "too many scan results, may break binder transaction");
5073             }
5074             return new ParceledListSlice<>(scanResults);
5075         } catch (SecurityException e) {
5076             Log.w(TAG, "Permission violation - getScanResults not allowed for uid="
5077                     + uid + ", packageName=" + callingPackage + ", reason=" + e);
5078             return null;
5079         } finally {
5080             Binder.restoreCallingIdentity(ident);
5081         }
5082     }
5083 
5084     /**
5085      * See {@link WifiManager#getChannelData(Executor, Consumer)}
5086      */
5087     @Override
5088     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
getChannelData(@onNull IListListener listener, String packageName, Bundle extras)5089     public void getChannelData(@NonNull IListListener listener, String packageName,
5090             Bundle extras) {
5091         if (!SdkLevel.isAtLeastT()) {
5092             throw new UnsupportedOperationException();
5093         }
5094         if (listener == null) {
5095             throw new IllegalArgumentException("listener should not be null");
5096         }
5097         mWifiPermissionsUtil.enforceNearbyDevicesPermission(
5098                 extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE), false,
5099                 TAG + " getChannelData");
5100         mWifiThreadRunner.post(() -> {
5101             try {
5102                 listener.onResult(getChannelDataInternal());
5103             } catch (RemoteException e) {
5104                 Log.e(TAG, e.getMessage(), e);
5105             }
5106         }, TAG + "#getChannelData");
5107     }
5108 
getChannelDataInternal()5109     private List<Bundle> getChannelDataInternal() {
5110         SparseIntArray dataSparseIntArray = new SparseIntArray();
5111         List<ScanResult> scanResults = mScanRequestProxy.getScanResults();
5112         if (scanResults != null) {
5113             for (ScanResult scanResultItem : scanResults) {
5114                 if (scanResultItem.level >= CHANNEL_USAGE_WEAK_SCAN_RSSI_DBM) {
5115                     dataSparseIntArray.put(scanResultItem.frequency,
5116                             dataSparseIntArray.get(scanResultItem.frequency, 0) + 1);
5117                 }
5118             }
5119         }
5120 
5121         List<Bundle> dataArray = new ArrayList<>();
5122         for (int i = 0; i < dataSparseIntArray.size(); i++) {
5123             Bundle dataBundle = new Bundle();
5124             dataBundle.putInt(CHANNEL_DATA_KEY_FREQUENCY_MHZ, dataSparseIntArray.keyAt(i));
5125             dataBundle.putInt(CHANNEL_DATA_KEY_NUM_AP, dataSparseIntArray.valueAt(i));
5126             dataArray.add(dataBundle);
5127         }
5128         return dataArray;
5129     }
5130 
5131     /**
5132      * Return the filtered ScanResults which may be authenticated by the suggested network
5133      * configurations.
5134      * @return The map of {@link WifiNetworkSuggestion} and the list of {@link ScanResult} which
5135      * may be authenticated by the corresponding network configuration.
5136      */
5137     @Override
5138     @NonNull
getMatchingScanResults( @onNull ParceledListSlice<WifiNetworkSuggestion> networkSuggestions, @Nullable ParceledListSlice<ScanResult> scanResults, String callingPackage, String callingFeatureId)5139     public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
5140             @NonNull ParceledListSlice<WifiNetworkSuggestion> networkSuggestions,
5141             @Nullable ParceledListSlice<ScanResult> scanResults,
5142             String callingPackage, String callingFeatureId) {
5143         enforceAccessPermission();
5144         int uid = Binder.getCallingUid();
5145         long ident = Binder.clearCallingIdentity();
5146         if (networkSuggestions == null || networkSuggestions.getList() == null) {
5147             throw new IllegalArgumentException("networkSuggestions must not be null.");
5148         }
5149         try {
5150             mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId,
5151                     uid, null);
5152 
5153             return mWifiThreadRunner.call(
5154                     () -> {
5155                         if (scanResults == null
5156                                 || !ScanResultUtil.validateScanResultList(scanResults.getList())) {
5157                             return mWifiNetworkSuggestionsManager.getMatchingScanResults(
5158                                     networkSuggestions.getList(),
5159                                     mScanRequestProxy.getScanResults());
5160                         } else {
5161                             return mWifiNetworkSuggestionsManager.getMatchingScanResults(
5162                                     networkSuggestions.getList(), scanResults.getList());
5163                         }
5164                     },
5165                     Collections.emptyMap(), TAG + "#getMatchingScanResults");
5166         } catch (SecurityException e) {
5167             Log.w(TAG, "Permission violation - getMatchingScanResults not allowed for uid="
5168                     + uid + ", packageName=" + callingPackage + ", reason + e");
5169         } finally {
5170             Binder.restoreCallingIdentity(ident);
5171         }
5172 
5173         return Collections.emptyMap();
5174     }
5175 
5176     /**
5177      * Add or update a Passpoint configuration.
5178      *
5179      * @param config The Passpoint configuration to be added
5180      * @return true on success or false on failure
5181      */
5182     @Override
5183     public boolean addOrUpdatePasspointConfiguration(
5184             PasspointConfiguration config, String packageName) {
5185         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
5186             return false;
5187         }
5188         int callingUid = Binder.getCallingUid();
5189         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
5190         if (!isTargetSdkLessThanROrPrivileged(
5191                 packageName, Binder.getCallingPid(), callingUid)) {
5192             mLog.info("addOrUpdatePasspointConfiguration not allowed for uid=%")
5193                     .c(callingUid).flush();
5194             return false;
5195         }
5196         long ident = Binder.clearCallingIdentity();
5197         try {
5198             if (SdkLevel.isAtLeastT() && mUserManager.hasUserRestrictionForUser(
5199                     UserManager.DISALLOW_ADD_WIFI_CONFIG,
5200                     UserHandle.getUserHandleForUid(callingUid))
5201                     && !mWifiPermissionsUtil.isAdmin(callingUid, packageName)) {
5202                 mLog.info("addOrUpdatePasspointConfiguration only allowed for admin"
5203                         + "when the DISALLOW_ADD_WIFI_CONFIG user restriction is set").flush();
5204                 return false;
5205             }
5206         } finally {
5207             Binder.restoreCallingIdentity(ident);
5208         }
5209         mLog.info("addorUpdatePasspointConfiguration uid=%").c(callingUid).flush();
5210         return mWifiThreadRunner.call(
5211                 () -> {
5212                     boolean success = mPasspointManager.addOrUpdateProvider(config, callingUid,
5213                             packageName, false, true, false);
5214                     if (success && TextUtils.equals(CERT_INSTALLER_PKG, packageName)) {
5215                         int networkId = mActiveModeWarden.getConnectionInfo().getNetworkId();
5216                         WifiConfiguration currentConfig =
5217                                 mWifiConfigManager.getConfiguredNetworkWithPassword(networkId);
5218                         if (currentConfig != null
5219                                 && !currentConfig.getNetworkSelectionStatus()
5220                                     .hasNeverDetectedCaptivePortal()) {
5221                             mActiveModeWarden.getPrimaryClientModeManager().disconnect();
5222                         }
5223                     }
5224                     return success;
5225                 }, false, TAG + "#addOrUpdatePasspointConfiguration");
5226     }
5227 
5228     /**
5229      * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
5230      *
5231      * @param fqdn The FQDN of the Passpoint configuration to be removed
5232      * @return true on success or false on failure
5233      */
5234     @Override
5235     public boolean removePasspointConfiguration(String fqdn, String packageName) {
5236         mWifiPermissionsUtil.checkPackage(Binder.getCallingUid(), packageName);
5237         return removePasspointConfigurationInternal(fqdn, null);
5238     }
5239 
5240     /**
5241      * Remove a Passpoint profile based on either FQDN (multiple matching profiles) or a unique
5242      * identifier (one matching profile).
5243      *
5244      * @param fqdn The FQDN of the Passpoint configuration to be removed
5245      * @param uniqueId The unique identifier of the Passpoint configuration to be removed
5246      * @return true on success or false on failure
5247      */
5248     private boolean removePasspointConfigurationInternal(String fqdn, String uniqueId) {
5249         final int uid = Binder.getCallingUid();
5250         boolean privileged = false;
5251         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
5252                 || mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(uid)) {
5253             privileged = true;
5254         }
5255         mLog.info("removePasspointConfigurationInternal uid=%").c(Binder.getCallingUid()).flush();
5256         final boolean privilegedFinal = privileged;
5257         return mWifiThreadRunner.call(
5258                 () -> mPasspointManager.removeProvider(uid, privilegedFinal, uniqueId, fqdn),
5259                 false, TAG + "#removePasspointConfigurationInternal");
5260     }
5261 
5262     /**
5263      * Return the list of the installed Passpoint configurations.
5264      *
5265      * An empty list will be returned when no configuration is installed.
5266      * @param packageName String name of the calling package
5267      * @return A list of {@link PasspointConfiguration}.
5268      */
5269     @Override
5270     public ParceledListSlice<PasspointConfiguration> getPasspointConfigurations(
5271             String packageName) {
5272         final int uid = Binder.getCallingUid();
5273         mWifiPermissionsUtil.checkPackage(uid, packageName);
5274         boolean privileged = false;
5275         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
5276                 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) {
5277             privileged = true;
5278         }
5279         if (mVerboseLoggingEnabled) {
5280             mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
5281         }
5282         final boolean privilegedFinal = privileged;
5283         return new ParceledListSlice<>(mWifiThreadRunner.call(
5284             () -> mPasspointManager.getProviderConfigs(uid, privilegedFinal),
5285             Collections.emptyList(), TAG + "#getPasspointConfigurations"));
5286     }
5287 
5288     /**
5289      * Query for a Hotspot 2.0 release 2 OSU icon
5290      * @param bssid The BSSID of the AP
5291      * @param fileName Icon file name
5292      */
5293     @Override
5294     public void queryPasspointIcon(long bssid, String fileName) {
5295         enforceAccessPermission();
5296         mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
5297         mWifiThreadRunner.post(() -> {
5298             mActiveModeWarden.getPrimaryClientModeManager().syncQueryPasspointIcon(bssid, fileName);
5299         }, TAG + "#queryPasspointIcon");
5300     }
5301 
5302     /**
5303      * Match the currently associated network against the SP matching the given FQDN
5304      * @param fqdn FQDN of the SP
5305      * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
5306      */
5307     @Override
5308     public int matchProviderWithCurrentNetwork(String fqdn) {
5309         mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
5310         return 0;
5311     }
5312 
5313     /**
5314      * see {@link android.net.wifi.WifiManager#addDriverCountryCodeChangedListener(
5315      * WifiManager.OnDriverCountryCodeChangedListener)}
5316      *
5317      * @param listener country code listener to register
5318      * @param packageName Package name of the calling app
5319      * @param featureId The feature in the package
5320      *
5321      * @throws SecurityException if the caller does not have permission to register a callback
5322      * @throws RemoteException if remote exception happens
5323      * @throws IllegalArgumentException if the arguments are null or invalid
5324      */
5325     @Override
5326     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
5327     public void registerDriverCountryCodeChangedListener(@NonNull
5328             IOnWifiDriverCountryCodeChangedListener listener, @Nullable String packageName,
5329             @Nullable String featureId) {
5330         if (!SdkLevel.isAtLeastT()) {
5331             throw new UnsupportedOperationException();
5332         }
5333         // verify arguments
5334         if (listener == null) {
5335             throw new IllegalArgumentException("listener must not be null");
5336         }
5337         int uid = Binder.getCallingUid();
5338         int pid = Binder.getCallingPid();
5339         mWifiPermissionsUtil.checkPackage(uid, packageName);
5340         // Allow to register if caller owns location permission in the manifest.
5341         enforceLocationPermissionInManifest(uid, true /* isCoarseOnly */);
5342         if (mVerboseLoggingEnabled) {
5343             mLog.info("registerDriverCountryCodeChangedListener uid=%")
5344                     .c(Binder.getCallingUid()).flush();
5345         }
5346 
5347         // post operation to handler thread
5348         mWifiThreadRunner.post(() -> {
5349             mCountryCodeTracker.registerDriverCountryCodeChangedListener(listener,
5350                     new WifiPermissionsUtil.CallerIdentity(uid, pid, packageName, featureId));
5351             // Update the client about the current driver country code immediately
5352             // after registering if the client owns location permission and global location setting
5353             // is on.
5354             try {
5355                 if (mWifiPermissionsUtil.checkCallersCoarseLocationPermission(
5356                         packageName, featureId, uid, null)) {
5357                     listener.onDriverCountryCodeChanged(mCountryCode.getCurrentDriverCountryCode());
5358                 } else {
5359                     Log.i(TAG, "drop to notify to listener (maybe location off?) for"
5360                             + " DriverCountryCodeChangedListener, uid=" + uid);
5361                 }
5362             } catch (RemoteException e) {
5363                 Log.e(TAG, "registerDriverCountryCodeChangedListener: remote exception -- " + e);
5364             }
5365         }, TAG + "#registerDriverCountryCodeChangedListener");
5366     }
5367 
5368     /**
5369      * see {@link android.net.wifi.WifiManager#removeDriverCountryCodeChangedListener(Executor,
5370      * WifiManager.OnDriverCountryCodeChangedListener)}
5371      *
5372      * @param listener country code listener to register
5373      *
5374      * @throws RemoteException if remote exception happens
5375      * @throws IllegalArgumentException if the arguments are null or invalid
5376      */
5377     @Override
5378     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
5379     public void unregisterDriverCountryCodeChangedListener(@NonNull
5380             IOnWifiDriverCountryCodeChangedListener listener) {
5381         if (!SdkLevel.isAtLeastT()) {
5382             throw new UnsupportedOperationException();
5383         }
5384         // verify arguments
5385         if (listener == null) {
5386             throw new IllegalArgumentException("listener must not be null");
5387         }
5388         int uid = Binder.getCallingUid();
5389         if (mVerboseLoggingEnabled) {
5390             mLog.info("unregisterDriverCountryCodeChangedListener uid=%")
5391                     .c(Binder.getCallingUid()).flush();
5392         }
5393 
5394         // post operation to handler thread
5395         mWifiThreadRunner.post(() ->
5396                 mCountryCodeTracker.unregisterDriverCountryCodeChangedListener(listener),
5397                 TAG + "#unregisterDriverCountryCodeChangedListener");
5398     }
5399 
5400      /**
5401      * Get the country code
5402      * @return Get the best choice country code for wifi, regardless of if it was set or
5403      * not.
5404      * Returns null when there is no country code available.
5405      */
5406     @Override
5407     public String getCountryCode(String packageName, String featureId) {
5408         int uid = Binder.getCallingUid();
5409         mWifiPermissionsUtil.checkPackage(uid, packageName);
5410         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
5411                 && !mWifiPermissionsUtil.checkCallersCoarseLocationPermission(
5412                         packageName, featureId, uid, "getCountryCode")) {
5413             throw new SecurityException("Caller has no permission to get country code.");
5414         }
5415         if (mVerboseLoggingEnabled) {
5416             mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
5417         }
5418         return mCountryCode.getCountryCode();
5419     }
5420 
5421     /**
5422      * Set the Wifi country code. This call will override the country code set by telephony.
5423      * @param countryCode A 2-Character alphanumeric country code.
5424      *
5425      */
5426     @RequiresApi(Build.VERSION_CODES.S)
5427     @Override
5428     public void setOverrideCountryCode(@NonNull String countryCode) {
5429         if (!SdkLevel.isAtLeastS()) {
5430             throw new UnsupportedOperationException();
5431         }
5432         mContext.enforceCallingOrSelfPermission(
5433                 Manifest.permission.MANAGE_WIFI_COUNTRY_CODE, "WifiService");
5434         if (!WifiCountryCode.isValid(countryCode)) {
5435             throw new IllegalArgumentException("Country code must be a 2-Character alphanumeric"
5436                     + " code. But got countryCode " + countryCode
5437                     + " instead");
5438         }
5439         if (mVerboseLoggingEnabled) {
5440             mLog.info("setOverrideCountryCode uid=% countryCode=%")
5441                     .c(Binder.getCallingUid()).c(countryCode).flush();
5442         }
5443         // Post operation to handler thread
5444         mWifiThreadRunner.post(() -> mCountryCode.setOverrideCountryCode(countryCode),
5445                 TAG + "#setOverrideCountryCode");
5446     }
5447 
5448     /**
5449      * Clear the country code previously set through setOverrideCountryCode method.
5450      *
5451      */
5452     @RequiresApi(Build.VERSION_CODES.S)
5453     @Override
5454     public void clearOverrideCountryCode() {
5455         if (!SdkLevel.isAtLeastS()) {
5456             throw new UnsupportedOperationException();
5457         }
5458         mContext.enforceCallingOrSelfPermission(
5459                 Manifest.permission.MANAGE_WIFI_COUNTRY_CODE, "WifiService");
5460         if (mVerboseLoggingEnabled) {
5461             mLog.info("clearCountryCode uid=%").c(Binder.getCallingUid()).flush();
5462         }
5463         // Post operation to handler thread
5464         mWifiThreadRunner.post(() -> mCountryCode.clearOverrideCountryCode(),
5465                 TAG + "#clearOverrideCountryCode");
5466     }
5467 
5468     /**
5469      * Change the default country code previously set from ro.boot.wificountrycode.
5470      * @param countryCode A 2-Character alphanumeric country code.
5471      *
5472      */
5473     @RequiresApi(Build.VERSION_CODES.S)
5474     @Override
5475     public void setDefaultCountryCode(@NonNull String countryCode) {
5476         if (!SdkLevel.isAtLeastS()) {
5477             throw new UnsupportedOperationException();
5478         }
5479         mContext.enforceCallingOrSelfPermission(
5480                 Manifest.permission.MANAGE_WIFI_COUNTRY_CODE, "WifiService");
5481         if (!WifiCountryCode.isValid(countryCode)) {
5482             throw new IllegalArgumentException("Country code must be a 2-Character alphanumeric"
5483                     + " code. But got countryCode " + countryCode
5484                     + " instead");
5485         }
5486         if (mVerboseLoggingEnabled) {
5487             mLog.info("setDefaultCountryCode uid=% countryCode=%")
5488                     .c(Binder.getCallingUid()).c(countryCode).flush();
5489         }
5490         // Post operation to handler thread
5491         mWifiThreadRunner.post(() -> mCountryCode.setDefaultCountryCode(countryCode),
5492                 TAG + "#setDefaultCountryCode");
5493     }
5494 
5495     @Override
5496     public boolean is24GHzBandSupported() {
5497         if (mVerboseLoggingEnabled) {
5498             mLog.info("is24GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
5499         }
5500 
5501         return is24GhzBandSupportedInternal();
5502     }
5503 
5504     private boolean is24GhzBandSupportedInternal() {
5505         if (mResourceCache.getBoolean(R.bool.config_wifi24ghzSupport)) {
5506             return true;
5507         }
5508         return mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_24_GHZ);
5509     }
5510 
5511 
5512     @Override
5513     public boolean is5GHzBandSupported() {
5514         if (mVerboseLoggingEnabled) {
5515             mLog.info("is5GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
5516         }
5517 
5518         return is5GhzBandSupportedInternal();
5519     }
5520 
5521     private boolean is5GhzBandSupportedInternal() {
5522         if (mResourceCache.getBoolean(R.bool.config_wifi5ghzSupport)) {
5523             return true;
5524         }
5525         return mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_5_GHZ);
5526     }
5527 
5528     @Override
5529     public boolean is6GHzBandSupported() {
5530         if (mVerboseLoggingEnabled) {
5531             mLog.info("is6GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
5532         }
5533 
5534         return is6GhzBandSupportedInternal();
5535     }
5536 
5537     private boolean is6GhzBandSupportedInternal() {
5538         if (mResourceCache.getBoolean(R.bool.config_wifi6ghzSupport)) {
5539             return true;
5540         }
5541         return mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_6_GHZ);
5542     }
5543 
5544     @Override
5545     public boolean is60GHzBandSupported() {
5546         if (!SdkLevel.isAtLeastS()) {
5547             throw new UnsupportedOperationException();
5548         }
5549 
5550         if (mVerboseLoggingEnabled) {
5551             mLog.info("is60GHzBandSupported uid=%").c(Binder.getCallingUid()).flush();
5552         }
5553 
5554         return is60GhzBandSupportedInternal();
5555     }
5556 
5557     private boolean is60GhzBandSupportedInternal() {
5558         if (mResourceCache.getBoolean(R.bool.config_wifi60ghzSupport)) {
5559             return true;
5560         }
5561         return mActiveModeWarden.isBandSupportedForSta(WifiScanner.WIFI_BAND_60_GHZ);
5562     }
5563 
5564     @Override
5565     public boolean isWifiStandardSupported(@WifiStandard int standard) {
5566         return mWifiThreadRunner.call(
5567                 () -> mActiveModeWarden.getPrimaryClientModeManager().isWifiStandardSupported(
5568                         standard), false, TAG + "#isWifiStandardSupported");
5569     }
5570 
5571     /**
5572      * Return the DHCP-assigned addresses from the last successful DHCP request,
5573      * if any.
5574      * @return the DHCP information
5575      * @deprecated
5576      */
5577     @Override
5578     public DhcpInfo getDhcpInfo(@NonNull String packageName) {
5579         enforceAccessPermission();
5580         int callingUid = Binder.getCallingUid();
5581         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
5582         if (mVerboseLoggingEnabled) {
5583             mLog.info("getDhcpInfo uid=%").c(callingUid).flush();
5584         }
5585         DhcpResultsParcelable dhcpResults = mWifiThreadRunner.call(
5586                 () -> getClientModeManagerIfSecondaryCmmRequestedByCallerPresent(
5587                         callingUid, packageName)
5588                         .syncGetDhcpResultsParcelable(), new DhcpResultsParcelable(),
5589                 TAG + "#getDhcpInfo");
5590 
5591         DhcpInfo info = new DhcpInfo();
5592 
5593         if (dhcpResults.baseConfiguration != null) {
5594             if (dhcpResults.baseConfiguration.getIpAddress() != null
5595                     && dhcpResults.baseConfiguration.getIpAddress().getAddress()
5596                     instanceof Inet4Address) {
5597                 info.ipAddress = Inet4AddressUtils.inet4AddressToIntHTL(
5598                         (Inet4Address) dhcpResults.baseConfiguration.getIpAddress().getAddress());
5599             }
5600 
5601             if (dhcpResults.baseConfiguration.getGateway() != null) {
5602                 info.gateway = Inet4AddressUtils.inet4AddressToIntHTL(
5603                         (Inet4Address) dhcpResults.baseConfiguration.getGateway());
5604             }
5605 
5606             int dnsFound = 0;
5607             for (InetAddress dns : dhcpResults.baseConfiguration.getDnsServers()) {
5608                 if (dns instanceof Inet4Address) {
5609                     if (dnsFound == 0) {
5610                         info.dns1 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns);
5611                     } else {
5612                         info.dns2 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns);
5613                     }
5614                     if (++dnsFound > 1) break;
5615                 }
5616             }
5617         }
5618         String serverAddress = dhcpResults.serverAddress;
5619         if (serverAddress != null) {
5620             InetAddress serverInetAddress = InetAddresses.parseNumericAddress(serverAddress);
5621             info.serverAddress =
5622                     Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) serverInetAddress);
5623         }
5624         info.leaseDuration = dhcpResults.leaseDuration;
5625 
5626         return info;
5627     }
5628 
5629     /**
5630      * enable TDLS for the local NIC to remote NIC
5631      * The APPs don't know the remote MAC address to identify NIC though,
5632      * so we need to do additional work to find it from remote IP address
5633      */
5634 
5635     private static class TdlsTaskParams {
5636         String mRemoteIpAddress;
5637         boolean mEnable;
5638     }
5639 
5640     private class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
5641         @Override
5642         protected Integer doInBackground(TdlsTaskParams... params) {
5643 
5644             // Retrieve parameters for the call
5645             TdlsTaskParams param = params[0];
5646             String remoteIpAddress = param.mRemoteIpAddress.trim();
5647             boolean enable = param.mEnable;
5648 
5649             // Get MAC address of Remote IP
5650             String macAddress = null;
5651 
5652             try (BufferedReader reader = new BufferedReader(new FileReader("/proc/net/arp"))) {
5653                 // Skip over the line bearing column titles
5654                 reader.readLine();
5655 
5656                 String line;
5657                 while ((line = reader.readLine()) != null) {
5658                     String[] tokens = line.split("[ ]+");
5659                     if (tokens.length < 6) {
5660                         continue;
5661                     }
5662 
5663                     // ARP column format is
5664                     // Address HWType HWAddress Flags Mask IFace
5665                     String ip = tokens[0];
5666                     String mac = tokens[3];
5667 
5668                     if (TextUtils.equals(remoteIpAddress, ip)) {
5669                         macAddress = mac;
5670                         break;
5671                     }
5672                 }
5673 
5674                 if (macAddress == null) {
5675                     Log.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in "
5676                             + "/proc/net/arp");
5677                 } else {
5678                     enableTdlsWithMacAddress(macAddress, enable);
5679                 }
5680 
5681             } catch (FileNotFoundException e) {
5682                 Log.e(TAG, "Could not open /proc/net/arp to lookup mac address");
5683             } catch (IOException e) {
5684                 Log.e(TAG, "Could not read /proc/net/arp to lookup mac address");
5685             }
5686             return 0;
5687         }
5688     }
5689 
5690     @Override
5691     public void enableTdls(String remoteAddress, boolean enable) {
5692         if (remoteAddress == null) {
5693           throw new IllegalArgumentException("remoteAddress cannot be null");
5694         }
5695         mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
5696         TdlsTaskParams params = new TdlsTaskParams();
5697         params.mRemoteIpAddress = remoteAddress;
5698         params.mEnable = enable;
5699         mLastCallerInfoManager.put(WifiManager.API_SET_TDLS_ENABLED, Process.myTid(),
5700                 Binder.getCallingUid(), Binder.getCallingPid(), "<unknown>", enable);
5701         new TdlsTask().execute(params);
5702     }
5703 
5704     /**
5705      * See {@link WifiManager#setTdlsEnabled(InetAddress, boolean, Executor, Consumer)}
5706      */
5707     @Override
5708     public void enableTdlsWithRemoteIpAddress(String remoteAddress, boolean enable,
5709             @NonNull IBooleanListener listener) {
5710         if (remoteAddress == null) {
5711             throw new NullPointerException("remoteAddress cannot be null");
5712         }
5713         if (listener == null) {
5714             throw new NullPointerException("listener should not be null");
5715         }
5716 
5717         mLog.info("enableTdlsWithRemoteIpAddress uid=% enable=%")
5718                 .c(Binder.getCallingUid()).c(enable).flush();
5719         mLastCallerInfoManager.put(WifiManager.API_SET_TDLS_ENABLED,
5720                 Process.myTid(), Binder.getCallingUid(), Binder.getCallingPid(), "<unknown>",
5721                 enable);
5722 
5723         mWifiThreadRunner.post(() -> {
5724             try {
5725                 listener.onResult(
5726                         mActiveModeWarden.getPrimaryClientModeManager()
5727                                 .enableTdlsWithRemoteIpAddress(remoteAddress, enable));
5728             } catch (RemoteException e) {
5729                 Log.e(TAG, e.getMessage(), e);
5730             }
5731         }, TAG + "#enableTdlsWithRemoteIpAddress");
5732     }
5733 
5734     @Override
5735     public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
5736         mLog.info("enableTdlsWithMacAddress uid=% enable=%")
5737                 .c(Binder.getCallingUid())
5738                 .c(enable)
5739                 .flush();
5740         if (remoteMacAddress == null) {
5741           throw new IllegalArgumentException("remoteMacAddress cannot be null");
5742         }
5743         mLastCallerInfoManager.put(WifiManager.API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS,
5744                 Process.myTid(), Binder.getCallingUid(), Binder.getCallingPid(), "<unknown>",
5745                 enable);
5746         mWifiThreadRunner.post(() ->
5747                 mActiveModeWarden.getPrimaryClientModeManager().enableTdls(
5748                         remoteMacAddress, enable), TAG + "#enableTdlsWithMacAddress");
5749     }
5750 
5751     /**
5752      * See {@link WifiManager#setTdlsEnabledWithMacAddress(String, boolean, Executor, Consumer)}
5753      */
5754     @Override
5755     public void enableTdlsWithRemoteMacAddress(String remoteMacAddress, boolean enable,
5756             @NonNull IBooleanListener listener) {
5757         if (remoteMacAddress == null) {
5758             throw new NullPointerException("remoteAddress cannot be null");
5759         }
5760         if (listener == null) {
5761             throw new NullPointerException("listener should not be null");
5762         }
5763 
5764         mLog.info("enableTdlsWithRemoteMacAddress uid=% enable=%")
5765                 .c(Binder.getCallingUid()).c(enable).flush();
5766         mLastCallerInfoManager.put(
5767                 WifiManager.API_SET_TDLS_ENABLED_WITH_MAC_ADDRESS,
5768                 Process.myTid(), Binder.getCallingUid(), Binder.getCallingPid(), "<unknown>",
5769                 enable);
5770 
5771         mWifiThreadRunner.post(() -> {
5772             try {
5773                 listener.onResult(
5774                         mActiveModeWarden.getPrimaryClientModeManager()
5775                                 .enableTdls(remoteMacAddress, enable));
5776             } catch (RemoteException e) {
5777                 Log.e(TAG, e.getMessage(), e);
5778             }
5779         }, TAG + "#enableTdlsWithRemoteMacAddress");
5780     }
5781 
5782     /**
5783      * See {@link WifiManager#isTdlsOperationCurrentlyAvailable(Executor, Consumer)}
5784      */
5785     @Override
5786     public void isTdlsOperationCurrentlyAvailable(@NonNull IBooleanListener listener) {
5787         if (listener == null) {
5788             throw new NullPointerException("listener should not be null");
5789         }
5790         mWifiThreadRunner.post(() -> {
5791             try {
5792                 listener.onResult(
5793                         mActiveModeWarden.getPrimaryClientModeManager()
5794                                 .isTdlsOperationCurrentlyAvailable());
5795             } catch (RemoteException e) {
5796                 Log.e(TAG, e.getMessage(), e);
5797             }
5798         }, TAG + "#isTdlsOperationCurrentlyAvailable");
5799     }
5800 
5801     /**
5802      *  See {@link WifiManager#getMaxSupportedConcurrentTdlsSessions(Executor, Consumer)}
5803      */
5804     @Override
5805     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
5806     public void getMaxSupportedConcurrentTdlsSessions(@NonNull IIntegerListener listener) {
5807         if (!SdkLevel.isAtLeastU()) {
5808             throw new UnsupportedOperationException("SDK level too old");
5809         }
5810         if (listener == null) {
5811             throw new NullPointerException("listener should not be null");
5812         }
5813         mWifiThreadRunner.post(() -> {
5814             try {
5815                 listener.onResult(
5816                         mActiveModeWarden.getPrimaryClientModeManager()
5817                                 .getMaxSupportedConcurrentTdlsSessions());
5818             } catch (RemoteException e) {
5819                 Log.e(TAG, e.getMessage(), e);
5820             }
5821         }, TAG + "#getMaxSupportedConcurrentTdlsSessions");
5822     }
5823 
5824     /**
5825      *  See {@link WifiManager#getNumberOfEnabledTdlsSessions(Executor, Consumer)}
5826      */
5827     @Override
5828     public void getNumberOfEnabledTdlsSessions(@NonNull IIntegerListener listener) {
5829         if (listener == null) {
5830             throw new NullPointerException("listener should not be null");
5831         }
5832         mWifiThreadRunner.post(() -> {
5833             try {
5834                 listener.onResult(
5835                         mActiveModeWarden.getPrimaryClientModeManager()
5836                                 .getNumberOfEnabledTdlsSessions());
5837             } catch (RemoteException e) {
5838                 Log.e(TAG, e.getMessage(), e);
5839             }
5840         }, TAG + "#getNumberOfEnabledTdlsSessions");
5841     }
5842 
5843     /**
5844      * Temporarily disable a network, should be trigger when user disconnect a network
5845      */
5846     @Override
5847     public void disableEphemeralNetwork(String network, String packageName) {
5848         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
5849                 "WifiService");
5850         int callingUid = Binder.getCallingUid();
5851         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
5852         if (!isPrivileged(Binder.getCallingPid(), callingUid)) {
5853             mLog.info("disableEphemeralNetwork not allowed for uid=%").c(callingUid).flush();
5854             return;
5855         }
5856         mLog.info("disableEphemeralNetwork uid=%").c(callingUid).flush();
5857         mWifiThreadRunner.post(() -> mWifiConfigManager.userTemporarilyDisabledNetwork(network,
5858                 callingUid), TAG + "#disableEphemeralNetwork");
5859     }
5860 
5861     private void removeAppStateInternal(int uid, @NonNull String pkgName) {
5862         ApplicationInfo ai = new ApplicationInfo();
5863         ai.packageName = pkgName;
5864         ai.uid = uid;
5865         mWifiConfigManager.removeNetworksForApp(ai);
5866         mScanRequestProxy.clearScanRequestTimestampsForApp(pkgName, uid);
5867 
5868         // Remove all suggestions from the package.
5869         mWifiNetworkSuggestionsManager.removeApp(pkgName);
5870         mWifiInjector.getWifiNetworkFactory().removeApp(pkgName);
5871 
5872         // Remove all Passpoint profiles from package.
5873         mWifiInjector.getPasspointManager().removePasspointProviderWithPackage(
5874                 pkgName);
5875     }
5876 
5877     private void registerForBroadcasts() {
5878         IntentFilter intentFilter = new IntentFilter();
5879         intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
5880         intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
5881         intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
5882         intentFilter.addDataScheme("package");
5883         mContext.registerReceiver(
5884                 new BroadcastReceiver() {
5885                     @Override
5886                     public void onReceive(Context context, Intent intent) {
5887                         final String action = intent.getAction();
5888                         if (action == null) {
5889                             return;
5890                         }
5891                         int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
5892                         Uri uri = intent.getData();
5893                         if (uid == -1 || uri == null) {
5894                             Log.e(TAG, "Uid or Uri is missing for action:" + action);
5895                             return;
5896                         }
5897                         String pkgName = uri.getSchemeSpecificPart();
5898                         PackageManager pm = context.getPackageManager();
5899                         PackageInfo packageInfo = null;
5900                         try {
5901                             packageInfo = pm.getPackageInfo(pkgName, 0);
5902                         } catch (PackageManager.NameNotFoundException e) {
5903                             Log.w(TAG, "Couldn't get PackageInfo for package:" + pkgName);
5904                         }
5905                         // If app is updating or replacing, just ignore
5906                         if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
5907                                 && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
5908                             return;
5909                         }
5910                         // If package is not removed or disabled, just ignore.
5911                         if (packageInfo != null
5912                                 && packageInfo.applicationInfo != null
5913                                 && packageInfo.applicationInfo.enabled) {
5914                             return;
5915                         }
5916                         Log.d(TAG, "Remove settings for package:" + pkgName);
5917                         removeAppStateInternal(uid, pkgName);
5918                     }
5919                 },
5920                 intentFilter,
5921                 null,
5922                 new Handler(mWifiHandlerThread.getLooper()));
5923     }
5924 
5925     private void registerForCarrierConfigChange() {
5926         IntentFilter filter = new IntentFilter();
5927         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
5928         mContext.registerReceiver(
5929                 new BroadcastReceiver() {
5930                     @Override
5931                     public void onReceive(Context context, Intent intent) {
5932                         final int subId = SubscriptionManager.getActiveDataSubscriptionId();
5933                         Log.d(TAG, "ACTION_CARRIER_CONFIG_CHANGED, active subId: " + subId);
5934                         // Tether mode only since carrier requirement only for tethered SoftAp.
5935                         mTetheredSoftApTracker
5936                                 .updateSoftApCapabilityWhenCarrierConfigChanged(subId);
5937                         mActiveModeWarden.updateSoftApCapability(
5938                                 mTetheredSoftApTracker.getSoftApCapability(),
5939                                 WifiManager.IFACE_IP_MODE_TETHERED);
5940                     }
5941                 },
5942                 filter,
5943                 null,
5944                 new Handler(mWifiHandlerThread.getLooper()));
5945 
5946         WifiPhoneStateListener phoneStateListener = new WifiPhoneStateListener(
5947                 mWifiHandlerThread.getLooper());
5948 
5949         mContext.getSystemService(TelephonyManager.class).listen(
5950                 phoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
5951     }
5952 
5953     @Override
5954     public int handleShellCommand(@NonNull ParcelFileDescriptor in,
5955             @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
5956             @NonNull String[] args) {
5957         if (!mIsBootComplete) {
5958             Log.w(TAG, "Received shell command when boot is not complete!");
5959             return -1;
5960         }
5961 
5962         WifiShellCommand shellCommand =  mWifiInjector.makeWifiShellCommand(this);
5963         return shellCommand.exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
5964                 err.getFileDescriptor(), args);
5965     }
5966 
5967 
5968     private void updateWifiMetrics() {
5969         mWifiMetrics.updateSavedNetworks(mWifiConfigManager.getSavedNetworks(WIFI_UID));
5970         mActiveModeWarden.updateMetrics();
5971         mPasspointManager.updateMetrics();
5972         boolean isNonPersistentMacRandEnabled = mFrameworkFacade.getIntegerSetting(mContext,
5973                 WifiConfigManager.NON_PERSISTENT_MAC_RANDOMIZATION_FEATURE_FORCE_ENABLE_FLAG, 0)
5974                 == 1 ? true : false;
5975         mWifiMetrics.setNonPersistentMacRandomizationForceEnabled(isNonPersistentMacRandEnabled);
5976         mWifiMetrics.setIsScanningAlwaysEnabled(
5977                 mSettingsStore.isScanAlwaysAvailableToggleEnabled());
5978         mWifiMetrics.setVerboseLoggingEnabled(mVerboseLoggingEnabled);
5979         mWifiMetrics.setWifiWakeEnabled(mWifiInjector.getWakeupController().isEnabled());
5980     }
5981 
5982     @Override
5983     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5984         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
5985                 != PERMISSION_GRANTED) {
5986             pw.println("Permission Denial: can't dump WifiService from from pid="
5987                     + Binder.getCallingPid()
5988                     + ", uid=" + Binder.getCallingUid());
5989             return;
5990         }
5991         if (!mIsWifiServiceStarted) {
5992             pw.println("Wifi Service is not started. no dump available");
5993             return;
5994         }
5995         mWifiThreadRunner.run(() -> {
5996             String arg0 = args != null && args.length > 0 ? args[0] : null;
5997             if (WifiMetrics.PROTO_DUMP_ARG.equals(arg0)) {
5998                 // WifiMetrics proto bytes were requested. Dump only these.
5999                 updateWifiMetrics();
6000                 mWifiMetrics.dump(fd, pw, args);
6001             } else if (IpClientUtil.DUMP_ARG.equals(arg0)) {
6002                 // IpClient dump was requested. Pass it along and take no further action.
6003                 String[] ipClientArgs = new String[args.length - 1];
6004                 System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length);
6005                 mActiveModeWarden.getPrimaryClientModeManager().dumpIpClient(fd, pw, ipClientArgs);
6006             } else if (WifiScoreReport.DUMP_ARG.equals(arg0)) {
6007                 mActiveModeWarden.getPrimaryClientModeManager().dumpWifiScoreReport(fd, pw, args);
6008             } else if (WifiScoreCard.DUMP_ARG.equals(arg0)) {
6009                 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
6010                 String networkListBase64 = wifiScoreCard.getNetworkListBase64(true);
6011                 pw.println(networkListBase64);
6012             } else {
6013                 pw.println("Verbose logging is " + (mVerboseLoggingEnabled ? "on" : "off"));
6014                 pw.println("mVerboseLoggingLevel " + mVerboseLoggingLevel);
6015                 pw.println("Stay-awake conditions: " + mFacade.getIntegerSetting(
6016                         mContext, Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
6017                 pw.println("mInIdleMode " + mInIdleMode);
6018                 pw.println("mScanPending " + mScanPending);
6019                 pw.println("SupportedFeatures: " + getSupportedFeaturesString());
6020                 pw.println("SettingsStore:");
6021                 mSettingsStore.dump(fd, pw, args);
6022                 mActiveModeWarden.dump(fd, pw, args);
6023                 mMakeBeforeBreakManager.dump(fd, pw, args);
6024                 pw.println();
6025                 mWifiInjector.getInterfaceConflictManager().dump(fd, pw, args);
6026                 pw.println();
6027                 mWifiTrafficPoller.dump(fd, pw, args);
6028                 pw.println();
6029                 pw.println("Locks held:");
6030                 mWifiLockManager.dump(pw);
6031                 pw.println();
6032                 mWifiMulticastLockManager.dump(pw);
6033                 pw.println();
6034                 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard();
6035                 String networkListBase64 = wifiScoreCard.getNetworkListBase64(true);
6036                 pw.println("WifiScoreCard:");
6037                 pw.println(networkListBase64);
6038 
6039                 updateWifiMetrics();
6040                 mWifiMetrics.dump(fd, pw, args);
6041 
6042                 pw.println();
6043                 mWifiNetworkSuggestionsManager.dump(fd, pw, args);
6044                 pw.println();
6045                 mWifiBackupRestore.dump(fd, pw, args);
6046                 pw.println();
6047                 mBackupRestoreController.dump(fd, pw, args);
6048                 pw.println();
6049                 pw.println("ScoringParams: " + mWifiInjector.getScoringParams());
6050                 pw.println();
6051                 mSettingsConfigStore.dump(fd, pw, args);
6052                 pw.println();
6053                 mCountryCode.dump(fd, pw, args);
6054                 mWifiInjector.getWifiNetworkFactory().dump(fd, pw, args);
6055                 mWifiInjector.getUntrustedWifiNetworkFactory().dump(fd, pw, args);
6056                 mWifiInjector.getOemWifiNetworkFactory().dump(fd, pw, args);
6057                 mWifiInjector.getRestrictedWifiNetworkFactory().dump(fd, pw, args);
6058                 mWifiInjector.getMultiInternetWifiNetworkFactory().dump(fd, pw, args);
6059                 mWifiInjector.getSsidTranslator().dump(pw);
6060                 pw.println("Wlan Wake Reasons:" + mWifiNative.getWlanWakeReasonCount());
6061                 pw.println();
6062                 mWifiConfigManager.dump(fd, pw, args);
6063                 pw.println();
6064                 pw.println("WifiApConfigStore config: " + mWifiApConfigStore.getApConfiguration());
6065                 pw.println();
6066                 mPasspointManager.dump(pw);
6067                 mWifiInjector.getPasspointNetworkNominateHelper().dump(pw);
6068                 pw.println();
6069                 mWifiInjector.getWifiDiagnostics().captureBugReportData(
6070                         WifiDiagnostics.REPORT_REASON_USER_ACTION);
6071                 mWifiInjector.getWifiDiagnostics().dump(fd, pw, args);
6072                 mWifiConnectivityManager.dump(fd, pw, args);
6073                 mWifiHealthMonitor.dump(fd, pw, args);
6074                 mWifiScoreCard.dump(fd, pw, args);
6075                 mWifiInjector.getWakeupController().dump(fd, pw, args);
6076                 mWifiInjector.getWifiLastResortWatchdog().dump(fd, pw, args);
6077                 mWifiInjector.getAdaptiveConnectivityEnabledSettingObserver().dump(fd, pw, args);
6078                 mWifiInjector.getWifiGlobals().dump(fd, pw, args);
6079                 mWifiInjector.getSarManager().dump(fd, pw, args);
6080                 pw.println();
6081                 mLastCallerInfoManager.dump(pw);
6082                 pw.println();
6083                 mWifiNative.dump(pw);
6084                 pw.println();
6085                 mWifiInjector.getWifiRoamingModeManager().dump(fd, pw, args);
6086                 if (SdkLevel.isAtLeastV() && mWifiInjector.getWifiVoipDetector() != null) {
6087                     pw.println();
6088                     mWifiInjector.getWifiVoipDetector().dump(fd, pw, args);
6089                 }
6090                 pw.println();
6091                 mResourceCache.dump(pw);
6092                 if (mFeatureFlags.wepDisabledInApm()
6093                         && mWepNetworkUsageController != null) {
6094                     pw.println();
6095                     mWepNetworkUsageController.dump(fd, pw, args);
6096                 }
6097                 if (mScorerServiceConnection != null) {
6098                     pw.println("boundToExternalScorer successfully");
6099                 } else {
6100                     pw.println("boundToExternalScorer=failure, lastScorerBindingState="
6101                             + mLastScorerBindingState);
6102                 }
6103             }
6104         }, TAG + "#dump");
6105     }
6106 
6107     @Override
6108     public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws,
6109             @NonNull String packageName, Bundle extras) {
6110         mLog.info("acquireWifiLock uid=% lockMode=% packageName=%")
6111                 .c(Binder.getCallingUid())
6112                 .c(lockMode).c(getPackageName(extras)).flush();
6113 
6114         if (packageName == null) {
6115             throw new NullPointerException("Package name should not be null");
6116         }
6117 
6118         // Check on permission to make this call
6119         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
6120 
6121         // If no UID is provided in worksource, use the calling UID
6122         WorkSource updatedWs = (ws == null || ws.isEmpty())
6123                 ? new WorkSource(Binder.getCallingUid(), packageName) : ws;
6124 
6125         if (!WifiLockManager.isValidLockMode(lockMode)) {
6126             throw new IllegalArgumentException("lockMode =" + lockMode);
6127         }
6128 
6129         return mWifiThreadRunner.call(() ->
6130                 mWifiLockManager.acquireWifiLock(lockMode, tag, binder, updatedWs), false,
6131                 TAG + "#acquireWifiLock");
6132     }
6133 
6134     @Override
6135     public void updateWifiLockWorkSource(IBinder binder, WorkSource ws, String packageName,
6136             Bundle extras) {
6137         mLog.info("updateWifiLockWorkSource uid=% package name=%")
6138                 .c(Binder.getCallingUid())
6139                 .c(getPackageName(extras)).flush();
6140 
6141         // Check on permission to make this call
6142         mContext.enforceCallingOrSelfPermission(
6143                 android.Manifest.permission.UPDATE_DEVICE_STATS, null);
6144 
6145         // If no UID is provided in worksource, use the calling UID
6146         WorkSource updatedWs = (ws == null || ws.isEmpty())
6147                 ? new WorkSource(Binder.getCallingUid(), packageName) : ws;
6148 
6149         mWifiThreadRunner.run(() ->
6150                 mWifiLockManager.updateWifiLockWorkSource(binder, updatedWs),
6151                 TAG + "#updateWifiLockWorkSource");
6152     }
6153 
6154     @Override
6155     public boolean releaseWifiLock(IBinder binder) {
6156         mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
6157 
6158         // Check on permission to make this call
6159         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
6160 
6161         return mWifiThreadRunner.call(() ->
6162                 mWifiLockManager.releaseWifiLock(binder), false,
6163                 TAG + "#releaseWifiLock");
6164     }
6165 
6166     @Override
6167     public void initializeMulticastFiltering() {
6168         enforceMulticastChangePermission();
6169         mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
6170         mWifiMulticastLockManager.startFilteringMulticastPackets();
6171     }
6172 
6173     @Override
6174     public void acquireMulticastLock(IBinder binder, String lockTag, String attributionTag,
6175             String packageName) {
6176         enforceMulticastChangePermission();
6177         int uid = Binder.getCallingUid();
6178         mLog.info("acquireMulticastLock uid=% lockTag=%").c(uid).c(lockTag).flush();
6179         mWifiMulticastLockManager.acquireLock(uid, binder, lockTag, attributionTag, packageName);
6180     }
6181 
6182     @Override
6183     public void releaseMulticastLock(IBinder binder, String lockTag) {
6184         enforceMulticastChangePermission();
6185         int uid = Binder.getCallingUid();
6186         mLog.info("releaseMulticastLock uid=% lockTag=%").c(uid).c(lockTag).flush();
6187         mWifiMulticastLockManager.releaseLock(uid, binder, lockTag);
6188     }
6189 
6190     @Override
6191     public boolean isMulticastEnabled() {
6192         enforceAccessPermission();
6193         if (mVerboseLoggingEnabled) {
6194             mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
6195         }
6196         return mWifiMulticastLockManager.isMulticastEnabled();
6197     }
6198 
6199     @Override
6200     public void enableVerboseLogging(int verbose) {
6201         enforceAccessPermission();
6202         if (!checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())
6203                 && mContext.checkPermission(android.Manifest.permission.DUMP,
6204                 Binder.getCallingPid(), Binder.getCallingUid()) != PERMISSION_GRANTED) {
6205             throw new SecurityException("Caller has neither NETWORK_SETTING nor dump permissions");
6206         }
6207         mLog.info("enableVerboseLogging uid=% verbose=%")
6208                 .c(Binder.getCallingUid())
6209                 .c(verbose).flush();
6210         boolean enabled = verbose == WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED
6211                 || verbose == WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY;
6212         mSettingsConfigStore.put(WIFI_VERBOSE_LOGGING_ENABLED, enabled);
6213         mSettingsConfigStore.put(
6214                 WIFI_AWARE_VERBOSE_LOGGING_ENABLED,
6215                 enabled || verbose == VERBOSE_LOGGING_LEVEL_WIFI_AWARE_ENABLED_ONLY);
6216         onVerboseLoggingStatusChanged(enabled);
6217         enableVerboseLoggingInternal(verbose);
6218     }
6219 
6220     private void onVerboseLoggingStatusChanged(boolean enabled) {
6221         synchronized (mRegisteredWifiLoggingStatusListeners) {
6222             int itemCount = mRegisteredWifiLoggingStatusListeners.beginBroadcast();
6223             try {
6224                 for (int i = 0; i < itemCount; i++) {
6225                     try {
6226                         mRegisteredWifiLoggingStatusListeners
6227                                 .getBroadcastItem(i)
6228                                 .onStatusChanged(enabled);
6229                     } catch (RemoteException e) {
6230                         Log.e(TAG, "onVerboseLoggingStatusChanged: RemoteException -- ", e);
6231                     }
6232                 }
6233             } finally {
6234                 mRegisteredWifiLoggingStatusListeners.finishBroadcast();
6235             }
6236         }
6237     }
6238 
6239     private void updateVerboseLoggingEnabled() {
6240         final int verboseAlwaysOnLevel = mResourceCache.getInteger(
6241                 R.integer.config_wifiVerboseLoggingAlwaysOnLevel);
6242         mVerboseLoggingEnabled = WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED == mVerboseLoggingLevel
6243                 || WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY == mVerboseLoggingLevel
6244                 || mFrameworkFacade.isVerboseLoggingAlwaysOn(verboseAlwaysOnLevel,
6245                 mBuildProperties);
6246     }
6247 
6248     private void enableVerboseLoggingInternal(int verboseLoggingLevel) {
6249         if (verboseLoggingLevel == WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY
6250                 && mBuildProperties.isUserBuild()) {
6251             throw new SecurityException(TAG + ": Not allowed for the user build.");
6252         }
6253         mVerboseLoggingLevel = verboseLoggingLevel;
6254 
6255         // Update wifi globals before sending the verbose logging change.
6256         mWifiThreadRunner.removeCallbacks(mAutoDisableShowKeyVerboseLoggingModeRunnable);
6257         mWifiGlobals.setVerboseLoggingLevel(verboseLoggingLevel);
6258         if (WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY == mVerboseLoggingLevel) {
6259             mWifiThreadRunner.postDelayed(mAutoDisableShowKeyVerboseLoggingModeRunnable,
6260                     AUTO_DISABLE_SHOW_KEY_COUNTDOWN_MILLIS,
6261                     TAG + "#AutoDisableShowKeyVerboseLoggingMode");
6262         }
6263         updateVerboseLoggingEnabled();
6264         final boolean halVerboseEnabled =
6265                 WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED == mVerboseLoggingLevel
6266                         || WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED_SHOW_KEY
6267                         == mVerboseLoggingLevel;
6268         mAfcManager.enableVerboseLogging(mVerboseLoggingEnabled);
6269         mActiveModeWarden.enableVerboseLogging(mVerboseLoggingEnabled);
6270         mWifiLockManager.enableVerboseLogging(mVerboseLoggingEnabled);
6271         mWifiMulticastLockManager.enableVerboseLogging(mVerboseLoggingEnabled);
6272         mWifiInjector.enableVerboseLogging(mVerboseLoggingEnabled, halVerboseEnabled);
6273         mWifiInjector.getSarManager().enableVerboseLogging(mVerboseLoggingEnabled);
6274         mWifiThreadRunner.mVerboseLoggingEnabled = mVerboseLoggingEnabled;
6275         WifiScanner wifiScanner = mWifiInjector.getWifiScanner();
6276         if (wifiScanner != null) {
6277             wifiScanner.enableVerboseLogging(mVerboseLoggingEnabled);
6278         }
6279         ApConfigUtil.enableVerboseLogging(mVerboseLoggingEnabled);
6280         mApplicationQosPolicyRequestHandler.enableVerboseLogging(mVerboseLoggingEnabled);
6281         mWifiSettingsBackupRestore.enableVerboseLogging(mVerboseLoggingEnabled);
6282         mBackupRestoreController.enableVerboseLogging(mVerboseLoggingEnabled);
6283         if (SdkLevel.isAtLeastV() && mWifiInjector.getWifiVoipDetector() != null) {
6284             mWifiInjector.getWifiVoipDetector().enableVerboseLogging(mVerboseLoggingEnabled);
6285         }
6286         if (mFeatureFlags.wepDisabledInApm()
6287                 && mWepNetworkUsageController != null) {
6288             mWepNetworkUsageController.enableVerboseLogging(mVerboseLoggingEnabled);
6289         }
6290     }
6291 
6292     @Override
6293     public int getVerboseLoggingLevel() {
6294         if (mVerboseLoggingEnabled) {
6295             mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
6296         }
6297         return mVerboseLoggingLevel;
6298     }
6299 
6300     private Runnable mAutoDisableShowKeyVerboseLoggingModeRunnable = new Runnable() {
6301         @Override
6302         public void run() {
6303             // If still enabled, fallback to the regular verbose logging mode.
6304             if (mVerboseLoggingEnabled) {
6305                 enableVerboseLoggingInternal(WifiManager.VERBOSE_LOGGING_LEVEL_ENABLED);
6306             }
6307         }
6308     };
6309 
6310     @Override
6311     public void factoryReset(String packageName) {
6312         enforceNetworkSettingsPermission();
6313         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
6314             return;
6315         }
6316         int callingUid = Binder.getCallingUid();
6317         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
6318         mLog.info("factoryReset uid=%").c(callingUid).flush();
6319         long ident = Binder.clearCallingIdentity();
6320         try {
6321             if (mUserManager.hasUserRestrictionForUser(
6322                     UserManager.DISALLOW_NETWORK_RESET,
6323                     UserHandle.getUserHandleForUid(callingUid))) {
6324                 return;
6325             }
6326             if (!mUserManager.hasUserRestrictionForUser(
6327                     UserManager.DISALLOW_CONFIG_TETHERING,
6328                     UserHandle.getUserHandleForUid(callingUid))) {
6329                 // Turn mobile hotspot off
6330                 stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED);
6331             }
6332             if (mUserManager.hasUserRestrictionForUser(
6333                     UserManager.DISALLOW_CONFIG_WIFI,
6334                     UserHandle.getUserHandleForUid(callingUid))) {
6335                 return;
6336             }
6337         } finally {
6338             Binder.restoreCallingIdentity(ident);
6339         }
6340         // Delete all Wifi SSIDs
6341         mWifiThreadRunner.run(() -> {
6342             List<WifiConfiguration> networks = mWifiConfigManager
6343                     .getSavedNetworks(WIFI_UID);
6344             EventLog.writeEvent(0x534e4554, "231985227", -1,
6345                     "Remove certs for factory reset");
6346             for (WifiConfiguration network : networks) {
6347                 if (network.isEnterprise()) {
6348                     mWifiInjector.getWifiKeyStore().removeKeys(network.enterpriseConfig, true);
6349                 }
6350                 mWifiConfigManager.removeNetwork(network.networkId, callingUid, packageName);
6351             }
6352         }, TAG + "#factoryReset1");
6353         // Delete all Passpoint configurations
6354         List<PasspointConfiguration> configs = mWifiThreadRunner.call(
6355                 () -> mPasspointManager.getProviderConfigs(WIFI_UID /* ignored */, true),
6356                 Collections.emptyList(), TAG + "#factoryReset2");
6357         for (PasspointConfiguration config : configs) {
6358             removePasspointConfigurationInternal(null, config.getUniqueId());
6359         }
6360         mWifiThreadRunner.post(
6361                 () -> {
6362                     // Reset SoftApConfiguration to default configuration
6363                     mWifiApConfigStore.setApConfiguration(null);
6364                     mPasspointManager.clearAnqpRequestsAndFlushCache();
6365                     mWifiConfigManager.clearUserTemporarilyDisabledList();
6366                     mWifiConfigManager.removeAllEphemeralOrPasspointConfiguredNetworks();
6367                     mWifiInjector.getWifiNetworkFactory().clear();
6368                     mWifiNetworkSuggestionsManager.clear();
6369                     mWifiInjector.getWifiScoreCard().clear();
6370                     mWifiHealthMonitor.clear();
6371                     mWifiCarrierInfoManager.clear();
6372                     notifyFactoryReset();
6373                     mContext.resetResourceCache();
6374                 }, TAG + "#factoryReset3");
6375     }
6376 
6377     /**
6378      * Notify the Factory Reset Event to application who may installed wifi configurations.
6379      */
6380     private void notifyFactoryReset() {
6381         Intent intent = new Intent(WifiManager.ACTION_NETWORK_SETTINGS_RESET);
6382 
6383         // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts
6384         // to wake them up (if they're in background).
6385         List<ResolveInfo> resolveInfos =
6386                 mContext.getPackageManager().queryBroadcastReceiversAsUser(
6387                         intent, 0,
6388                         UserHandle.of(mWifiInjector.getWifiPermissionsWrapper().getCurrentUser()));
6389         if (resolveInfos == null || resolveInfos.isEmpty()) return; // No need to send broadcast.
6390 
6391         for (ResolveInfo resolveInfo : resolveInfos) {
6392             Intent intentToSend = new Intent(intent);
6393             intentToSend.setComponent(new ComponentName(
6394                     resolveInfo.activityInfo.applicationInfo.packageName,
6395                     resolveInfo.activityInfo.name));
6396             mContext.sendBroadcastAsUser(intentToSend, UserHandle.CURRENT,
6397                     android.Manifest.permission.NETWORK_CARRIER_PROVISIONING);
6398         }
6399     }
6400 
6401     @Override
6402     public Network getCurrentNetwork() {
6403         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
6404             throw new SecurityException(TAG + ": Permission denied");
6405         }
6406         if (mVerboseLoggingEnabled) {
6407             mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
6408         }
6409         return mActiveModeWarden.getCurrentNetwork();
6410     }
6411 
6412     public static String toHexString(String s) {
6413         if (s == null) {
6414             return "null";
6415         }
6416         StringBuilder sb = new StringBuilder();
6417         sb.append('\'').append(s).append('\'');
6418         for (int n = 0; n < s.length(); n++) {
6419             sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
6420         }
6421         return sb.toString();
6422     }
6423 
6424     /**
6425      * Retrieve the data to be backed to save the current state.
6426      *
6427      * The data includes:
6428      * 1. Wifi Settings (WifiSettingsConfigStore)
6429      * 2. WifiConfiguration/IpConfiguration (original backup by retrieveBackupData)
6430      * 3. SoftApConfiguration (original backup by retrieveSoftApBackupData)
6431      *
6432      * @param listener the listener to be used to receive backup data.
6433      */
6434     @Override
6435     public void retrieveWifiBackupData(IByteArrayListener listener) {
6436         if (!SdkLevel.isAtLeastV()) {
6437             throw new UnsupportedOperationException("SDK level too old");
6438         }
6439         enforceNetworkSettingsPermission();
6440         mLog.info("retrieveWifiBackupData uid=%").c(Binder.getCallingUid()).flush();
6441         if (listener == null) {
6442             throw new IllegalArgumentException("listener should not be null");
6443         }
6444         mWifiThreadRunner.post(() -> {
6445             try {
6446                 listener.onResult(mBackupRestoreController.retrieveBackupData());
6447             } catch (RemoteException e) {
6448                 Log.e(TAG, e.getMessage(), e);
6449             }
6450         }, TAG + "#retrieveWifiBackupData");
6451     }
6452 
6453     /**
6454      * Restore state from the backed up data.
6455      *
6456      * The api will guarantee the device would not damage when adding new XML tag.
6457      *
6458      * @param data Raw byte stream of the backed up data.
6459      */
6460     @Override
6461     public void restoreWifiBackupData(byte[] data) {
6462         if (!SdkLevel.isAtLeastV()) {
6463             throw new UnsupportedOperationException("SDK level too old");
6464         }
6465         enforceNetworkSettingsPermission();
6466         mWifiThreadRunner.post(() -> {
6467             mLog.info("restoreWifiBackupData uid=%").c(Binder.getCallingUid()).flush();
6468             mBackupRestoreController.parserBackupDataAndDispatch(data);
6469         }, TAG + "#restoreWifiBackupData");
6470     }
6471 
6472     /**
6473      * Retrieve the data to be backed to save the current state.
6474      *
6475      * @return  Raw byte stream of the data to be backed up.
6476      */
6477     @Override
6478     public byte[] retrieveBackupData() {
6479         enforceNetworkSettingsPermission();
6480         mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
6481         Log.d(TAG, "Retrieving backup data");
6482         List<WifiConfiguration> wifiConfigurations = mWifiThreadRunner.call(
6483                 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(), null,
6484                 TAG + "#retrieveBackupData");
6485         byte[] backupData =
6486                 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
6487         Log.d(TAG, "Retrieved backup data");
6488         return backupData;
6489     }
6490 
6491     /**
6492      * Helper method to restore networks retrieved from backup data.
6493      *
6494      * @param configurations list of WifiConfiguration objects parsed from the backup data.
6495      */
6496     @VisibleForTesting
6497     void restoreNetworks(List<WifiConfiguration> configurations) {
6498         if (configurations == null) {
6499             Log.w(TAG, "No wifi configuration to restore.");
6500             return;
6501         }
6502         int callingUid = Binder.getCallingUid();
6503         if (configurations.isEmpty()) return;
6504         mWifiThreadRunner.post(() -> {
6505             boolean notOverrideExisting = CompatChanges
6506                     .isChangeEnabled(NOT_OVERRIDE_EXISTING_NETWORKS_ON_RESTORE, callingUid);
6507             int networkId;
6508             for (WifiConfiguration configuration : configurations) {
6509                 if (notOverrideExisting) {
6510                     networkId = mWifiConfigManager.addNetwork(configuration, callingUid)
6511                             .getNetworkId();
6512                 } else {
6513                     networkId = mWifiConfigManager.addOrUpdateNetwork(configuration, callingUid)
6514                             .getNetworkId();
6515                 }
6516                 if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
6517                     Log.e(TAG, "Restore network failed: "
6518                             + configuration.getProfileKey() + ", network might already exist in the"
6519                             + " database");
6520                 } else {
6521                     // Enable all networks restored.
6522                     mWifiConfigManager.enableNetwork(networkId, false, callingUid, null);
6523                     // Restore auto-join param.
6524                     mWifiConfigManager.allowAutojoin(networkId, configuration.allowAutojoin);
6525                 }
6526             }
6527         }, TAG + "#restoreNetworks");
6528     }
6529 
6530     /**
6531      * Restore state from the backed up data.
6532      *
6533      * @param data Raw byte stream of the backed up data.
6534      */
6535     @Override
6536     public void restoreBackupData(byte[] data) {
6537         enforceNetworkSettingsPermission();
6538         mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
6539         Log.d(TAG, "Restoring backup data");
6540         restoreNetworks(mWifiBackupRestore.retrieveConfigurationsFromBackupData(data));
6541     }
6542 
6543     /**
6544      * Retrieve the soft ap config data to be backed to save current config data.
6545      *
6546      * @return  Raw byte stream of the data to be backed up.
6547      */
6548     @Override
6549     public byte[] retrieveSoftApBackupData() {
6550         enforceNetworkSettingsPermission();
6551         mLog.info("retrieveSoftApBackupData uid=%").c(Binder.getCallingUid()).flush();
6552         SoftApConfiguration config = mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration,
6553                 new SoftApConfiguration.Builder().build(), TAG + "#retrieveSoftApBackupData");
6554         byte[] backupData =
6555                 mSoftApBackupRestore.retrieveBackupDataFromSoftApConfiguration(config);
6556         Log.d(TAG, "Retrieved soft ap backup data");
6557         return backupData;
6558     }
6559 
6560     /**
6561      * Restore soft ap config from the backed up data.
6562      *
6563      * @param data Raw byte stream of the backed up data.
6564      * @return restored SoftApConfiguration or Null if data is invalid.
6565      */
6566     @Override
6567     public SoftApConfiguration restoreSoftApBackupData(byte[] data) {
6568         enforceNetworkSettingsPermission();
6569         mLog.info("restoreSoftApBackupData uid=%").c(Binder.getCallingUid()).flush();
6570         SoftApConfiguration softApConfig =
6571                 mSoftApBackupRestore.retrieveSoftApConfigurationFromBackupData(data);
6572         if (softApConfig != null) {
6573             mWifiApConfigStore.setApConfiguration(
6574                     mWifiApConfigStore.resetToDefaultForUnsupportedConfig(
6575                             mWifiApConfigStore.upgradeSoftApConfiguration(softApConfig)));
6576             Log.d(TAG, "Restored soft ap backup data");
6577         }
6578         return softApConfig;
6579     }
6580 
6581     /**
6582      * Restore state from the older supplicant back up data. The old backup data was essentially a
6583      * backup of wpa_supplicant.conf & ipconfig.txt file.
6584      *
6585      * @param supplicantData Raw byte stream of wpa_supplicant.conf
6586      * @param ipConfigData Raw byte stream of ipconfig.txt
6587      */
6588     @Override
6589     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
6590         enforceNetworkSettingsPermission();
6591         mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
6592         Log.d(TAG, "Restoring supplicant backup data");
6593         restoreNetworks(mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
6594                 supplicantData, ipConfigData));
6595     }
6596 
6597     /**
6598      * Starts subscription provisioning with a provider.
6599      *
6600      * @param provider {@link OsuProvider} the provider to provision with
6601      * @param callback {@link IProvisioningCallback} the callback object to inform status
6602      */
6603     @Override
6604     public void startSubscriptionProvisioning(OsuProvider provider,
6605             IProvisioningCallback callback) {
6606         if (provider == null) {
6607             throw new IllegalArgumentException("Provider must not be null");
6608         }
6609         if (callback == null) {
6610             throw new IllegalArgumentException("Callback must not be null");
6611         }
6612         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
6613             throw new SecurityException(TAG + ": Permission denied");
6614         }
6615         final int uid = Binder.getCallingUid();
6616         mLog.trace("startSubscriptionProvisioning uid=%").c(uid).flush();
6617         if (getPrimaryClientModeManagerBlockingThreadSafe()
6618                 .syncStartSubscriptionProvisioning(uid, provider, callback)) {
6619             mLog.trace("Subscription provisioning started with %")
6620                     .c(provider.toString()).flush();
6621         }
6622     }
6623 
6624     /**
6625      * See
6626      * {@link WifiManager#registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)}
6627      *
6628      * @param callback Traffic State callback to register
6629      *
6630      * @throws SecurityException if the caller does not have permission to register a callback
6631      * @throws RemoteException if remote exception happens
6632      * @throws IllegalArgumentException if the arguments are null or invalid
6633      */
6634     @Override
6635     public void registerTrafficStateCallback(ITrafficStateCallback callback) {
6636         // verify arguments
6637         if (callback == null) {
6638             throw new IllegalArgumentException("Callback must not be null");
6639         }
6640         enforceNetworkSettingsPermission();
6641         if (mVerboseLoggingEnabled) {
6642             mLog.info("registerTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
6643         }
6644         // Post operation to handler thread
6645         mWifiThreadRunner.post(() -> mWifiTrafficPoller.addCallback(callback),
6646                 TAG + "#registerTrafficStateCallback");
6647     }
6648 
6649     /**
6650      * see {@link android.net.wifi.WifiManager#unregisterTrafficStateCallback(
6651      * WifiManager.TrafficStateCallback)}
6652      *
6653      * @param callback Traffic State callback to unregister
6654      *
6655      * @throws SecurityException if the caller does not have permission to register a callback
6656      */
6657     @Override
6658     public void unregisterTrafficStateCallback(ITrafficStateCallback callback) {
6659         enforceNetworkSettingsPermission();
6660         if (mVerboseLoggingEnabled) {
6661             mLog.info("unregisterTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush();
6662         }
6663         // Post operation to handler thread
6664         mWifiThreadRunner.post(() -> mWifiTrafficPoller.removeCallback(callback),
6665                 TAG + "#unregisterTrafficStateCallback");
6666     }
6667 
6668     protected String getSupportedFeaturesString() {
6669         return FeatureBitsetUtils.formatSupportedFeatures(getSupportedFeaturesInternal());
6670     }
6671 
6672     private BitSet getSupportedFeaturesInternal() {
6673         return mActiveModeWarden.getSupportedFeatureSet();
6674     }
6675 
6676     /**
6677      * See
6678      * {@link WifiManager#registerNetworkRequestMatchCallback(
6679      * Executor, WifiManager.NetworkRequestMatchCallback)}
6680      *
6681      * @param callback Network Request Match callback to register
6682      *
6683      * @throws SecurityException if the caller does not have permission to register a callback
6684      * @throws RemoteException if remote exception happens
6685      * @throws IllegalArgumentException if the arguments are null or invalid
6686      */
6687     @Override
6688     public void registerNetworkRequestMatchCallback(INetworkRequestMatchCallback callback) {
6689         // verify arguments
6690         if (callback == null) {
6691             throw new IllegalArgumentException("Callback must not be null");
6692         }
6693         enforceNetworkSettingsPermission();
6694         if (mVerboseLoggingEnabled) {
6695             mLog.info("registerNetworkRequestMatchCallback uid=%")
6696                     .c(Binder.getCallingUid()).flush();
6697         }
6698         // Post operation to handler thread
6699         mWifiThreadRunner.post(() ->
6700                 mWifiInjector.getWifiNetworkFactory().addCallback(callback),
6701                 TAG + "#registerNetworkRequestMatchCallback");
6702     }
6703 
6704     /**
6705      * see {@link android.net.wifi.WifiManager#unregisterNetworkRequestMatchCallback(
6706      * WifiManager.NetworkRequestMatchCallback)}
6707      *
6708      * @param callback Network Request Match callback to unregister
6709      *
6710      * @throws SecurityException if the caller does not have permission to register a callback
6711      */
6712     @Override
6713     public void unregisterNetworkRequestMatchCallback(INetworkRequestMatchCallback callback) {
6714         enforceNetworkSettingsPermission();
6715         if (mVerboseLoggingEnabled) {
6716             mLog.info("unregisterNetworkRequestMatchCallback uid=%")
6717                     .c(Binder.getCallingUid()).flush();
6718         }
6719         // Post operation to handler thread
6720         mWifiThreadRunner.post(() ->
6721                 mWifiInjector.getWifiNetworkFactory().removeCallback(callback),
6722                 TAG + "#unregisterNetworkRequestMatchCallback");
6723     }
6724 
6725     /**
6726      * See {@link android.net.wifi.WifiManager#addNetworkSuggestions(List)}
6727      *
6728      * @param networkSuggestions List of network suggestions to be added.
6729      * @param callingPackageName Package Name of the app adding the suggestions.
6730      * @param callingFeatureId Feature in the calling package
6731      * @throws SecurityException if the caller does not have permission.
6732      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
6733      */
6734     @Override
6735     public int addNetworkSuggestions(
6736             ParceledListSlice<WifiNetworkSuggestion> networkSuggestions, String callingPackageName,
6737             String callingFeatureId) {
6738         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
6739             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
6740         }
6741         int callingUid = Binder.getCallingUid();
6742         int callingPid = Binder.getCallingPid();
6743 
6744         long ident = Binder.clearCallingIdentity();
6745         try {
6746             if (SdkLevel.isAtLeastT()) {
6747                 boolean isUserRestrictionSet = mUserManager.hasUserRestrictionForUser(
6748                         UserManager.DISALLOW_ADD_WIFI_CONFIG,
6749                         UserHandle.getUserHandleForUid(callingUid));
6750                 boolean isCarrierApp = mWifiInjector.makeTelephonyManager()
6751                         .checkCarrierPrivilegesForPackageAnyPhone(callingPackageName)
6752                         == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
6753                 boolean hasPermission = !isUserRestrictionSet
6754                         || isCarrierApp
6755                         || isPrivileged(callingPid, callingUid)
6756                         || mWifiPermissionsUtil.isSystem(callingPackageName, callingUid)
6757                         || mWifiPermissionsUtil.isAdmin(callingUid, callingPackageName);
6758                 if (!hasPermission) {
6759                     return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_RESTRICTED_BY_ADMIN;
6760                 }
6761             }
6762         } finally {
6763             Binder.restoreCallingIdentity(ident);
6764         }
6765 
6766         if (mVerboseLoggingEnabled) {
6767             mLog.info("addNetworkSuggestions uid=%").c(callingUid).flush();
6768         }
6769         if (networkSuggestions == null) {
6770             return STATUS_NETWORK_SUGGESTIONS_SUCCESS;
6771         }
6772 
6773         int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.add(
6774                 networkSuggestions.getList(), callingUid, callingPackageName, callingFeatureId),
6775                 WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
6776                 TAG + "#addNetworkSuggestions");
6777         if (success != STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
6778             Log.e(TAG, "Failed to add network suggestions");
6779         }
6780         return success;
6781     }
6782 
6783     /**
6784      * See {@link android.net.wifi.WifiManager#removeNetworkSuggestions(List)}
6785      *
6786      * @param networkSuggestions List of network suggestions to be removed.
6787      * @param callingPackageName Package Name of the app removing the suggestions.
6788      * @throws SecurityException if the caller does not have permission.
6789      * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}.
6790      */
6791     @Override
6792     public int removeNetworkSuggestions(
6793             ParceledListSlice<WifiNetworkSuggestion> networkSuggestions, String callingPackageName,
6794             @WifiManager.ActionAfterRemovingSuggestion int action) {
6795         if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) {
6796             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED;
6797         }
6798         if (mVerboseLoggingEnabled) {
6799             mLog.info("removeNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush();
6800         }
6801         if (action != WifiManager.ACTION_REMOVE_SUGGESTION_DISCONNECT
6802                 && action != WifiManager.ACTION_REMOVE_SUGGESTION_LINGER) {
6803             return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_REMOVE_INVALID;
6804         }
6805         int callingUid = Binder.getCallingUid();
6806 
6807         if (networkSuggestions == null) {
6808             return STATUS_NETWORK_SUGGESTIONS_SUCCESS;
6809         }
6810         int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.remove(
6811                 networkSuggestions.getList(), callingUid, callingPackageName,
6812                 action), WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL,
6813                 TAG + "#removeNetworkSuggestions");
6814         if (success != STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
6815             Log.e(TAG, "Failed to remove network suggestions");
6816         }
6817         return success;
6818     }
6819 
6820     /**
6821      * See {@link android.net.wifi.WifiManager#getNetworkSuggestions()}
6822      * @param callingPackageName Package Name of the app getting the suggestions.
6823      * @return a list of network suggestions suggested by this app
6824      */
6825     @Override
6826     public ParceledListSlice<WifiNetworkSuggestion> getNetworkSuggestions(
6827             String callingPackageName) {
6828         int callingUid = Binder.getCallingUid();
6829         mAppOps.checkPackage(callingUid, callingPackageName);
6830         enforceAccessPermission();
6831         if (mVerboseLoggingEnabled) {
6832             mLog.info("getNetworkSuggestionList uid=%").c(Binder.getCallingUid()).flush();
6833         }
6834         return new ParceledListSlice<>(mWifiThreadRunner.call(() ->
6835                 mWifiNetworkSuggestionsManager.get(callingPackageName, callingUid),
6836                 Collections.emptyList(), TAG + "#getNetworkSuggestions"));
6837     }
6838 
6839     /**
6840      * Gets the factory Wi-Fi MAC addresses.
6841      * @throws SecurityException if the caller does not have permission.
6842      * @return Array of String representing Wi-Fi MAC addresses, or empty array if failed.
6843      */
6844     @Override
6845     public String[] getFactoryMacAddresses() {
6846         final int uid = Binder.getCallingUid();
6847         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
6848             throw new SecurityException("App not allowed to get Wi-Fi factory MAC address "
6849                     + "(uid = " + uid + ")");
6850         }
6851         // Check the ConfigStore cache first
6852         if (mWifiGlobals.isSaveFactoryMacToConfigStoreEnabled()) {
6853             String factoryMacAddressStr = mSettingsConfigStore.get(WIFI_STA_FACTORY_MAC_ADDRESS);
6854             if (factoryMacAddressStr != null) return new String[] {factoryMacAddressStr};
6855         }
6856         String result = mWifiThreadRunner.call(
6857                 () -> mActiveModeWarden.getPrimaryClientModeManager().getFactoryMacAddress(),
6858                 null, TAG + "#getFactoryMacAddresses");
6859         // result can be empty array if either: WifiThreadRunner.call() timed out, or
6860         // ClientModeImpl.getFactoryMacAddress() returned null.
6861         // In this particular instance, we don't differentiate the two types of nulls.
6862         if (result == null) {
6863             return new String[0];
6864         }
6865         return new String[]{result};
6866     }
6867 
6868     /**
6869      * Sets the current device mobility state.
6870      * @param state the new device mobility state
6871      */
6872     @Override
6873     public void setDeviceMobilityState(@DeviceMobilityState int state) {
6874         mContext.enforceCallingOrSelfPermission(
6875                 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE, "WifiService");
6876 
6877         if (mVerboseLoggingEnabled) {
6878             mLog.info("setDeviceMobilityState uid=% state=%")
6879                     .c(Binder.getCallingUid())
6880                     .c(state)
6881                     .flush();
6882         }
6883         // Post operation to handler thread
6884         mWifiThreadRunner.post(() -> {
6885             mWifiConnectivityManager.setDeviceMobilityState(state);
6886             mWifiHealthMonitor.setDeviceMobilityState(state);
6887             mWifiDataStall.setDeviceMobilityState(state);
6888             mActiveModeWarden.setDeviceMobilityState(state);
6889         }, TAG + "#setDeviceMobilityState");
6890     }
6891 
6892     /**
6893      * Proxy for the final native call of the parent class. Enables mocking of
6894      * the function.
6895      */
6896     public int getMockableCallingUid() {
6897         return getCallingUid();
6898     }
6899 
6900     /**
6901      * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping
6902      * with a peer, and send the SSID and password of the selected network.
6903      *
6904      * @param binder Caller's binder context
6905      * @param packageName Package name of the calling app
6906      * @param enrolleeUri URI of the Enrollee obtained externally (e.g. QR code scanning)
6907      * @param selectedNetworkId Selected network ID to be sent to the peer
6908      * @param netRole The network role of the enrollee
6909      * @param callback Callback for status updates
6910      */
6911     @Override
6912     public void startDppAsConfiguratorInitiator(IBinder binder, @NonNull String packageName,
6913             String enrolleeUri, int selectedNetworkId, int netRole, IDppCallback callback) {
6914         // verify arguments
6915         if (binder == null) {
6916             throw new IllegalArgumentException("Binder must not be null");
6917         }
6918         if (TextUtils.isEmpty(enrolleeUri)) {
6919             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
6920         }
6921         if (selectedNetworkId < 0) {
6922             throw new IllegalArgumentException("Selected network ID invalid");
6923         }
6924         if (callback == null) {
6925             throw new IllegalArgumentException("Callback must not be null");
6926         }
6927 
6928         final int uid = getMockableCallingUid();
6929 
6930         int callingUid = Binder.getCallingUid();
6931         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
6932         mAppOps.checkPackage(callingUid, packageName);
6933         if (!isSettingsOrSuw(Binder.getCallingPid(), callingUid)) {
6934             throw new SecurityException(TAG + ": Permission denied");
6935         }
6936         // Stop MBB (if in progress) when DPP is initiated. Otherwise, DPP operation will fail
6937         // when the previous primary iface is removed after MBB completion.
6938         mWifiThreadRunner.post(() ->
6939                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
6940                         mDppManager.startDppAsConfiguratorInitiator(
6941                                 uid, packageName,
6942                                 mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
6943                                 binder, enrolleeUri, selectedNetworkId, netRole, callback)),
6944                 TAG + "#startDppAsConfiguratorInitiator");
6945     }
6946 
6947     /**
6948      * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping
6949      * with a peer, and receive the SSID and password from the peer configurator.
6950      *
6951      * @param binder Caller's binder context
6952      * @param configuratorUri URI of the Configurator obtained externally (e.g. QR code scanning)
6953      * @param callback Callback for status updates
6954      */
6955     @Override
6956     public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri,
6957             IDppCallback callback) {
6958         // verify arguments
6959         if (binder == null) {
6960             throw new IllegalArgumentException("Binder must not be null");
6961         }
6962         if (TextUtils.isEmpty(configuratorUri)) {
6963             throw new IllegalArgumentException("Enrollee URI must not be null or empty");
6964         }
6965         if (callback == null) {
6966             throw new IllegalArgumentException("Callback must not be null");
6967         }
6968 
6969         final int uid = getMockableCallingUid();
6970 
6971         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
6972             throw new SecurityException(TAG + ": Permission denied");
6973         }
6974 
6975         // Stop MBB (if in progress) when DPP is initiated. Otherwise, DPP operation will fail
6976         // when the previous primary iface is removed after MBB completion.
6977         mWifiThreadRunner.post(() ->
6978                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
6979                         mDppManager.startDppAsEnrolleeInitiator(uid,
6980                                 mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
6981                                 binder, configuratorUri, callback)),
6982                 TAG + "#startDppAsEnrolleeInitiator");
6983     }
6984 
6985     /**
6986      * Start DPP in Enrollee-Responder role. The current device will generate the
6987      * bootstrap code and wait for the peer device to start the DPP authentication process.
6988      *
6989      * @param binder Caller's binder context
6990      * @param deviceInfo Device specific info to display in QR code(e.g. Easy_connect_demo)
6991      * @param curve Elliptic curve cryptography type used to generate DPP public/private key pair.
6992      * @param callback Callback for status updates
6993      */
6994     @Override
6995     @RequiresApi(Build.VERSION_CODES.S)
6996     public void startDppAsEnrolleeResponder(IBinder binder, @Nullable String deviceInfo,
6997             @WifiManager.EasyConnectCryptographyCurve int curve, IDppCallback callback) {
6998         if (!SdkLevel.isAtLeastS()) {
6999             throw new UnsupportedOperationException();
7000         }
7001         // verify arguments
7002         if (binder == null) {
7003             throw new IllegalArgumentException("Binder must not be null");
7004         }
7005         if (callback == null) {
7006             throw new IllegalArgumentException("Callback must not be null");
7007         }
7008 
7009         final int uid = getMockableCallingUid();
7010 
7011         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
7012             throw new SecurityException(TAG + ": Permission denied");
7013         }
7014 
7015         if (deviceInfo != null) {
7016             int deviceInfoLen = deviceInfo.length();
7017             if (deviceInfoLen > WifiManager.getEasyConnectMaxAllowedResponderDeviceInfoLength()) {
7018                 throw new IllegalArgumentException("Device info length: " + deviceInfoLen
7019                         + " must be less than "
7020                         + WifiManager.getEasyConnectMaxAllowedResponderDeviceInfoLength());
7021             }
7022             char c;
7023             for (int i = 0; i < deviceInfoLen; i++) {
7024                 c = deviceInfo.charAt(i);
7025                 if (c < '!' || c > '~' || c == ';') {
7026                     throw new IllegalArgumentException("Allowed Range of ASCII characters in"
7027                             + "deviceInfo - %x20-7E; semicolon and space are not allowed!"
7028                             + "Found c: " + c);
7029                 }
7030             }
7031         }
7032 
7033         // Stop MBB (if in progress) when DPP is initiated. Otherwise, DPP operation will fail
7034         // when the previous primary iface is removed after MBB completion.
7035         mWifiThreadRunner.post(() ->
7036                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
7037                         mDppManager.startDppAsEnrolleeResponder(uid,
7038                                 mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
7039                                 binder, deviceInfo, curve, callback)),
7040                 TAG + "#startDppAsEnrolleeResponder");
7041     }
7042 
7043     /**
7044      * Stop or abort a current DPP session.
7045      */
7046     @Override
7047     public void stopDppSession() throws RemoteException {
7048         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
7049             throw new SecurityException(TAG + ": Permission denied");
7050         }
7051         final int uid = getMockableCallingUid();
7052 
7053         mWifiThreadRunner.post(() -> mDppManager.stopDppSession(uid),
7054                 TAG + "#stopDppSession");
7055     }
7056 
7057     /**
7058      * see {@link android.net.wifi.WifiManager#addWifiVerboseLoggingStatusChangedListener(Executor,
7059      * WifiManager.WifiVerboseLoggingStatusChangedListener)}
7060      *
7061      * @param listener IWifiVerboseLoggingStatusChangedListener listener to add
7062      *
7063      * @throws SecurityException if the caller does not have permission to add a listener.
7064      * @throws IllegalArgumentException if the argument is null.
7065      */
7066     @Override
7067     public void addWifiVerboseLoggingStatusChangedListener(
7068             IWifiVerboseLoggingStatusChangedListener listener) {
7069         if (listener == null) {
7070             throw new IllegalArgumentException("Listener must not be null");
7071         }
7072         enforceAccessPermission();
7073         mRegisteredWifiLoggingStatusListeners.register(listener);
7074     }
7075 
7076     /**
7077      * see {@link android.net.wifi.WifiManager#unregisterWifiVerboseLoggingStatusCallback
7078      * (WifiManager.WifiVerboseLoggingStatusCallback)}
7079      *
7080      * @param listener the listener to be removed.
7081      *
7082      * @throws SecurityException if the caller does not have permission to add a listener.
7083      * @throws IllegalArgumentException if the argument is null.
7084      */
7085     @Override
7086     public void removeWifiVerboseLoggingStatusChangedListener(
7087             IWifiVerboseLoggingStatusChangedListener listener) {
7088         if (listener == null) {
7089             throw new IllegalArgumentException("Listener must not be null");
7090         }
7091         enforceAccessPermission();
7092         mRegisteredWifiLoggingStatusListeners.unregister(listener);
7093     }
7094 
7095     /**
7096      * see {@link android.net.wifi.WifiManager#addOnWifiUsabilityStatsListener(Executor,
7097      * WifiManager.OnWifiUsabilityStatsListener)}
7098      *
7099      * @param listener WifiUsabilityStatsEntry listener to add
7100      *
7101      * @throws SecurityException if the caller does not have permission to add a listener
7102      * @throws RemoteException if remote exception happens
7103      * @throws IllegalArgumentException if the arguments are null or invalid
7104      */
7105     @Override
7106     public void addOnWifiUsabilityStatsListener(IOnWifiUsabilityStatsListener listener) {
7107         if (listener == null) {
7108             throw new IllegalArgumentException("Listener must not be null");
7109         }
7110         mContext.enforceCallingOrSelfPermission(
7111                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
7112         if (mVerboseLoggingEnabled) {
7113             mLog.info("addOnWifiUsabilityStatsListener uid=%")
7114                 .c(Binder.getCallingUid()).flush();
7115         }
7116         // Post operation to handler thread
7117         mWifiThreadRunner.post(() ->
7118                 mWifiMetrics.addOnWifiUsabilityListener(listener),
7119                 TAG + "#addOnWifiUsabilityStatsListener");
7120     }
7121 
7122     /**
7123      * see {@link android.net.wifi.WifiManager#removeOnWifiUsabilityStatsListener
7124      * (WifiManager.OnWifiUsabilityStatsListener)}
7125      *
7126      * @param listener listener to be removed.
7127      *
7128      * @throws SecurityException if the caller does not have permission to add a listener
7129      */
7130     @Override
7131     public void removeOnWifiUsabilityStatsListener(IOnWifiUsabilityStatsListener listener) {
7132         if (listener == null) {
7133             throw new IllegalArgumentException("Listener must not be null");
7134         }
7135         mContext.enforceCallingOrSelfPermission(
7136                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
7137         if (mVerboseLoggingEnabled) {
7138             mLog.info("removeOnWifiUsabilityStatsListener uid=%")
7139                     .c(Binder.getCallingUid()).flush();
7140         }
7141         // Post operation to handler thread
7142         mWifiThreadRunner.post(() ->
7143                 mWifiMetrics.removeOnWifiUsabilityListener(listener),
7144                 TAG + "#removeOnWifiUsabilityStatsListener");
7145     }
7146 
7147     /**
7148      * Updates the Wi-Fi usability score.
7149      * @param seqNum Sequence number of the Wi-Fi usability score.
7150      * @param score The Wi-Fi usability score.
7151      * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second.
7152      */
7153     @Override
7154     public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) {
7155         mContext.enforceCallingOrSelfPermission(
7156                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
7157 
7158         if (mVerboseLoggingEnabled) {
7159             mLog.info("updateWifiUsabilityScore uid=% seqNum=% score=% predictionHorizonSec=%")
7160                     .c(Binder.getCallingUid())
7161                     .c(seqNum)
7162                     .c(score)
7163                     .c(predictionHorizonSec)
7164                     .flush();
7165         }
7166         // Post operation to handler thread
7167         mWifiThreadRunner.post(() -> {
7168             String ifaceName = mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName();
7169             mWifiMetrics.incrementWifiUsabilityScoreCount(
7170                     ifaceName, seqNum, score, predictionHorizonSec);
7171         }, TAG + "#updateWifiUsabilityScore");
7172     }
7173 
7174     /**
7175      * Notify interested parties if a wifi config has been changed.
7176      *
7177      * @param wifiCredentialEventType WIFI_CREDENTIAL_SAVED or WIFI_CREDENTIAL_FORGOT
7178      * @param config Must have a WifiConfiguration object to succeed
7179      */
7180     private void broadcastWifiCredentialChanged(int wifiCredentialEventType,
7181             WifiConfiguration config) {
7182         Intent intent = new Intent(WifiManager.WIFI_CREDENTIAL_CHANGED_ACTION);
7183         if (config != null && config.SSID != null && mWifiPermissionsUtil.isLocationModeEnabled()) {
7184             intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_SSID, config.SSID);
7185         }
7186         intent.putExtra(WifiManager.EXTRA_WIFI_CREDENTIAL_EVENT_TYPE,
7187                 wifiCredentialEventType);
7188         mContext.createContextAsUser(UserHandle.CURRENT, 0)
7189                 .sendBroadcastWithMultiplePermissions(
7190                         intent,
7191                         new String[]{
7192                                 android.Manifest.permission.RECEIVE_WIFI_CREDENTIAL_CHANGE,
7193                                 android.Manifest.permission.ACCESS_FINE_LOCATION,
7194                         });
7195     }
7196 
7197     /**
7198      * Connects to a network.
7199      *
7200      * If the supplied config is not null, then the netId argument will be ignored and the config
7201      * will be saved (or updated if its networkId or profile key already exist) and connected to.
7202      *
7203      * If the supplied config is null, then the netId argument will be matched to a saved config to
7204      * be connected to.
7205      *
7206      * @param config New or existing config to add/update and connect to
7207      * @param netId Network ID of existing config to connect to if the supplied config is null
7208      * @param callback Listener to notify action result
7209      * @param packageName Package name of the requesting App
7210      * @param extras Bundle of extras
7211      *
7212      * see: {@link WifiManager#connect(WifiConfiguration, WifiManager.ActionListener)}
7213      *      {@link WifiManager#connect(int, WifiManager.ActionListener)}
7214      */
7215     @Override
7216     public void connect(WifiConfiguration config, int netId, @Nullable IActionListener callback,
7217             @NonNull String packageName, Bundle extras) {
7218         int uid = getMockableCallingUid();
7219         if (!isPrivileged(Binder.getCallingPid(), uid)
7220                 // TODO(b/343881335): Longer term, we need a specific permission
7221                 // for NFC.
7222                 && UserHandle.getAppId(uid) != Process.NFC_UID) {
7223             throw new SecurityException(TAG + ": Permission denied");
7224         }
7225         if (packageName == null) {
7226             throw new IllegalArgumentException("packageName must not be null");
7227         }
7228         final String attributionTagToUse;
7229         final int uidToUse;
7230         final String packageNameToUse;
7231         if (SdkLevel.isAtLeastS() && UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
7232             AttributionSource as = extras.getParcelable(
7233                     WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE);
7234             if (as == null) {
7235                 throw new SecurityException("connect attributionSource is null");
7236             }
7237             if (!as.checkCallingUid()) {
7238                 throw new SecurityException(
7239                         "connect invalid (checkCallingUid fails) attribution source="
7240                                 + as);
7241             }
7242             // an attribution chain is either of size 1: unregistered (valid by definition) or
7243             // size >1: in which case all are validated.
7244             AttributionSource asIt = as;
7245             AttributionSource asLast = as;
7246             if (as.getNext() != null) {
7247                 do {
7248                     if (!asIt.isTrusted(mContext)) {
7249                         throw new SecurityException(
7250                                 "connect invalid (isTrusted fails) attribution source="
7251                                         + asIt);
7252                     }
7253                     asIt = asIt.getNext();
7254                     if (asIt != null) asLast = asIt;
7255                 } while (asIt != null);
7256             }
7257             // use the last AttributionSource in the chain - i.e. the original caller
7258             attributionTagToUse = asLast.getAttributionTag();
7259             uidToUse = asLast.getUid();
7260             packageNameToUse = asLast.getPackageName();
7261         } else {
7262             attributionTagToUse = mContext.getAttributionTag();
7263             uidToUse = uid;
7264             packageNameToUse = packageName;
7265         }
7266         mLog.info("connect uid=% uidToUse=% packageNameToUse=% attributionTagToUse=%")
7267                 .c(uid).c(uidToUse).c(packageNameToUse).c(attributionTagToUse).flush();
7268         mLastCallerInfoManager.put(config != null
7269                         ? WifiManager.API_CONNECT_CONFIG : WifiManager.API_CONNECT_NETWORK_ID,
7270                 Process.myTid(), uid, Binder.getCallingPid(), packageName, true);
7271         mWifiThreadRunner.post(
7272                 () -> {
7273                     ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
7274                     final NetworkUpdateResult result;
7275                     // if connecting using WifiConfiguration, save the network first
7276                     if (config != null) {
7277                         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
7278                             mWifiMetrics.logUserActionEvent(
7279                                     UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK, config.networkId);
7280                         }
7281                         result = mWifiConfigManager.addOrUpdateNetwork(config, uid);
7282                         if (!result.isSuccess()) {
7283                             Log.e(TAG, "connect adding/updating config=" + config + " failed");
7284                             wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7285                             return;
7286                         }
7287                         broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
7288                     } else {
7289                         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
7290                             mWifiMetrics.logUserActionEvent(
7291                                     UserActionEvent.EVENT_MANUAL_CONNECT, netId);
7292                         }
7293                         result = new NetworkUpdateResult(netId);
7294                     }
7295                     WifiConfiguration configuration =
7296                             mWifiConfigManager.getConfiguredNetwork(result.getNetworkId());
7297                     if (configuration == null) {
7298                         Log.e(TAG, "connect to Invalid network Id=" + netId);
7299                         wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7300                         return;
7301                     }
7302                     if (mWifiPermissionsUtil.isAdminRestrictedNetwork(configuration)) {
7303                         Log.e(TAG, "connect to network Id=" + netId + "restricted by admin");
7304                         wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7305                         return;
7306                     }
7307                     if (mWifiGlobals.isDeprecatedSecurityTypeNetwork(configuration)) {
7308                         Log.e(TAG, "connect to network Id=" + netId + " security type deprecated.");
7309                         wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7310                         return;
7311                     }
7312                     if (configuration.enterpriseConfig != null
7313                             && configuration.enterpriseConfig.isAuthenticationSimBased()) {
7314                         int subId =
7315                                 mWifiCarrierInfoManager.getBestMatchSubscriptionId(configuration);
7316                         if (!mWifiCarrierInfoManager.isSimReady(subId)) {
7317                             Log.e(
7318                                     TAG,
7319                                     "connect to SIM-based config="
7320                                             + configuration
7321                                             + "while SIM is absent");
7322                             wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7323                             return;
7324                         }
7325                         if (mWifiCarrierInfoManager.requiresImsiEncryption(subId)
7326                                 && !mWifiCarrierInfoManager.isImsiEncryptionInfoAvailable(subId)) {
7327                             Log.e(
7328                                     TAG,
7329                                     "Imsi protection required but not available for Network="
7330                                             + configuration);
7331                             wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7332                             return;
7333                         }
7334                         if (mWifiCarrierInfoManager.isOobPseudonymFeatureEnabled(
7335                                 configuration.carrierId)) {
7336                             Optional<PseudonymInfo> pseudonymInfo =
7337                                     mWifiPseudonymManager.getValidPseudonymInfo(
7338                                             configuration.carrierId);
7339                             if (pseudonymInfo.isEmpty()) {
7340                                 Log.e(
7341                                         TAG,
7342                                         "There isn't any valid pseudonym to update the Network="
7343                                                 + configuration);
7344                                 mWifiPseudonymManager.retrievePseudonymOnFailureTimeoutExpired(
7345                                         configuration);
7346                                 // TODO(b/274148786): new error code and UX for this failure.
7347                                 wrapper.sendFailure(
7348                                         WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7349                                 return;
7350                             } else {
7351                                 mWifiPseudonymManager.updateWifiConfiguration(configuration);
7352                             }
7353                         }
7354                     }
7355 
7356                     // Tear down already connected secondary internet CMMs to avoid MCC.
7357                     // Also tear down secondary CMMs that are already connected to the same network
7358                     // to make sure the user's manual connection succeeds.
7359                     ScanResultMatchInfo targetMatchInfo =
7360                             ScanResultMatchInfo.fromWifiConfiguration(configuration);
7361                     for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) {
7362                         if (!cmm.isConnected()) {
7363                             continue;
7364                         }
7365                         ActiveModeManager.ClientRole role = cmm.getRole();
7366                         if (role == ROLE_CLIENT_LOCAL_ONLY
7367                                 || role == ROLE_CLIENT_SECONDARY_LONG_LIVED) {
7368                             WifiConfiguration connectedConfig = cmm.getConnectedWifiConfiguration();
7369                             if (connectedConfig == null) {
7370                                 continue;
7371                             }
7372                             ScanResultMatchInfo connectedMatchInfo =
7373                                     ScanResultMatchInfo.fromWifiConfiguration(connectedConfig);
7374                             ConcreteClientModeManager concreteCmm = (ConcreteClientModeManager) cmm;
7375                             if (concreteCmm.isSecondaryInternet()
7376                                     || targetMatchInfo.matchForNetworkSelection(connectedMatchInfo)
7377                                     != null) {
7378                                 if (mVerboseLoggingEnabled) {
7379                                     Log.v(
7380                                             TAG,
7381                                             "Shutting down client mode manager to satisfy user "
7382                                                     + "connection: "
7383                                                     + cmm);
7384                                 }
7385                                 cmm.stop();
7386                             }
7387                         }
7388                     }
7389 
7390                     mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(
7391                             () ->
7392                                     mConnectHelper.connectToNetwork(
7393                                             result, wrapper, uidToUse, packageNameToUse,
7394                                             attributionTagToUse));
7395                 }, TAG + "#connect");
7396     }
7397 
7398     /**
7399      * see {@link android.net.wifi.WifiManager#save(WifiConfiguration,
7400      * WifiManager.ActionListener)}
7401      */
7402     @Override
7403     public void save(WifiConfiguration config, @Nullable IActionListener callback,
7404             @NonNull String packageName) {
7405         int uid = Binder.getCallingUid();
7406         if (!isPrivileged(Binder.getCallingPid(), uid)) {
7407             throw new SecurityException(TAG + ": Permission denied");
7408         }
7409         if (packageName == null) {
7410             throw new IllegalArgumentException("packageName must not be null");
7411         }
7412         mLog.info("save uid=%").c(uid).flush();
7413         mLastCallerInfoManager.put(WifiManager.API_SAVE, Process.myTid(),
7414                 uid, Binder.getCallingPid(), packageName, true);
7415         mWifiThreadRunner.post(() -> {
7416             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
7417             NetworkUpdateResult result =
7418                     mWifiConfigManager.updateBeforeSaveNetwork(config, uid, packageName);
7419             if (result.isSuccess()) {
7420                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
7421                 mMakeBeforeBreakManager.stopAllSecondaryTransientClientModeManagers(() ->
7422                         mActiveModeWarden.getPrimaryClientModeManager()
7423                                 .saveNetwork(result, wrapper, uid, packageName));
7424                 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
7425                     mWifiMetrics.logUserActionEvent(
7426                             UserActionEvent.EVENT_ADD_OR_UPDATE_NETWORK, config.networkId);
7427                 }
7428             } else {
7429                 wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7430             }
7431         }, TAG + "#save");
7432     }
7433 
7434     /**
7435      * see {@link android.net.wifi.WifiManager#forget(int, WifiManager.ActionListener)}
7436      */
7437     @Override
7438     public void forget(int netId, @Nullable IActionListener callback) {
7439         int uid = Binder.getCallingUid();
7440         if (!isPrivileged(Binder.getCallingPid(), uid)) {
7441             throw new SecurityException(TAG + ": Permission denied");
7442         }
7443         mLog.info("forget uid=%").c(Binder.getCallingUid()).flush();
7444         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
7445             // It's important to log this metric before the actual forget executes because
7446             // the netId becomes invalid after the forget operation.
7447             mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_FORGET_WIFI, netId);
7448         }
7449         mLastCallerInfoManager.put(WifiManager.API_FORGET, Process.myTid(),
7450                 uid, Binder.getCallingPid(), "<unknown>", true);
7451         mWifiThreadRunner.post(() -> {
7452             WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId);
7453             boolean success = mWifiConfigManager.removeNetwork(netId, uid, null);
7454             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
7455             if (success) {
7456                 wrapper.sendSuccess();
7457                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_FORGOT, config);
7458             } else {
7459                 Log.e(TAG, "Failed to remove network");
7460                 wrapper.sendFailure(WifiManager.ActionListener.FAILURE_INTERNAL_ERROR);
7461             }
7462         }, TAG + "#forget");
7463     }
7464 
7465     /**
7466      * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)}
7467      */
7468     @Override
7469     public void registerScanResultsCallback(@NonNull IScanResultsCallback callback) {
7470         if (callback == null) {
7471             throw new IllegalArgumentException("callback must not be null");
7472         }
7473         enforceAccessPermission();
7474 
7475         if (mVerboseLoggingEnabled) {
7476             mLog.info("registerScanResultsCallback uid=%").c(Binder.getCallingUid()).flush();
7477         }
7478         mWifiThreadRunner.post(() -> {
7479             if (!mWifiInjector.getScanRequestProxy().registerScanResultsCallback(callback)) {
7480                 Log.e(TAG, "registerScanResultsCallback: Failed to register callback");
7481             }
7482         }, TAG + "#registerScanResultsCallback");
7483     }
7484 
7485     /**
7486      * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)}
7487      */
7488     public void unregisterScanResultsCallback(@NonNull IScanResultsCallback callback) {
7489         if (callback == null) {
7490             throw new IllegalArgumentException("callback must not be null");
7491         }
7492         enforceAccessPermission();
7493 
7494         if (mVerboseLoggingEnabled) {
7495             mLog.info("unregisterScanResultCallback uid=%").c(Binder.getCallingUid()).flush();
7496         }
7497         // post operation to handler thread
7498         mWifiThreadRunner.post(() -> mWifiInjector.getScanRequestProxy()
7499                         .unregisterScanResultsCallback(callback),
7500                 TAG + "#unregisterScanResultsCallback");
7501 
7502     }
7503 
7504     /**
7505      * See {@link WifiManager#addSuggestionConnectionStatusListener(Executor,
7506      * SuggestionConnectionStatusListener)}
7507      */
7508     public void registerSuggestionConnectionStatusListener(
7509             @NonNull ISuggestionConnectionStatusListener listener, String packageName,
7510             @Nullable String featureId) {
7511         if (listener == null) {
7512             throw new IllegalArgumentException("listener must not be null");
7513         }
7514         final int uid = Binder.getCallingUid();
7515         mWifiPermissionsUtil.checkPackage(uid, packageName);
7516         enforceAccessPermission();
7517         if (SdkLevel.isAtLeastT()) {
7518             enforceLocationPermissionInManifest(uid, false /* isCoarseOnly */);
7519         } else {
7520             enforceLocationPermission(packageName, featureId, uid);
7521         }
7522         if (mVerboseLoggingEnabled) {
7523             mLog.info("registerSuggestionConnectionStatusListener uid=%").c(uid).flush();
7524         }
7525         mWifiThreadRunner.post(() ->
7526                 mWifiNetworkSuggestionsManager
7527                         .registerSuggestionConnectionStatusListener(listener, packageName, uid),
7528                 TAG + "#registerSuggestionConnectionStatusListener");
7529     }
7530 
7531     /**
7532      * See {@link WifiManager#removeSuggestionConnectionStatusListener(
7533      * SuggestionConnectionStatusListener)}
7534      */
7535     public void unregisterSuggestionConnectionStatusListener(
7536             @NonNull ISuggestionConnectionStatusListener listener, String packageName) {
7537         if (listener == null) {
7538             throw new IllegalArgumentException("listener must not be null");
7539         }
7540         enforceAccessPermission();
7541         int uid = Binder.getCallingUid();
7542         mWifiPermissionsUtil.checkPackage(uid, packageName);
7543         if (mVerboseLoggingEnabled) {
7544             mLog.info("unregisterSuggestionConnectionStatusListener uid=%")
7545                     .c(uid).flush();
7546         }
7547         mWifiThreadRunner.post(() ->
7548                 mWifiNetworkSuggestionsManager
7549                         .unregisterSuggestionConnectionStatusListener(listener, packageName, uid),
7550                 TAG + "#unregisterSuggestionConnectionStatusListener");
7551     }
7552 
7553     /**
7554      * {@link WifiManager#addLocalOnlyConnectionFailureListener(Executor, WifiManager.LocalOnlyConnectionFailureListener)}
7555      */
7556     @Override
7557     public void addLocalOnlyConnectionStatusListener(ILocalOnlyConnectionStatusListener listener,
7558             String packageName, String featureId) {
7559         if (listener == null) {
7560             throw new IllegalArgumentException("listener must not be null");
7561         }
7562 
7563         final int uid = Binder.getCallingUid();
7564         mWifiPermissionsUtil.checkPackage(uid, packageName);
7565         enforceAccessPermission();
7566         long callingIdentity = Binder.clearCallingIdentity();
7567         try {
7568             if (!mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(uid)) {
7569                 Log.e(TAG, "UID " + uid + " not visible to the current user");
7570                 throw new SecurityException("UID " + uid + " not visible to the current user");
7571             }
7572         } finally {
7573             // restore calling identity
7574             Binder.restoreCallingIdentity(callingIdentity);
7575         }
7576         if (mVerboseLoggingEnabled) {
7577             mLog.info("addLocalOnlyConnectionFailureListener uid=%").c(uid).flush();
7578         }
7579         mWifiThreadRunner.post(() ->
7580                 mWifiNetworkFactory.addLocalOnlyConnectionStatusListener(listener, packageName,
7581                         featureId), TAG + "#addLocalOnlyConnectionStatusListener");
7582     }
7583 
7584     /**
7585      * {@link WifiManager#removeLocalOnlyConnectionFailureListener(WifiManager.LocalOnlyConnectionFailureListener)}
7586      */
7587     @Override
7588     public void removeLocalOnlyConnectionStatusListener(ILocalOnlyConnectionStatusListener listener,
7589             String packageName) {
7590         if (listener == null) {
7591             throw new IllegalArgumentException("listener must not be null");
7592         }
7593         enforceAccessPermission();
7594         int uid = Binder.getCallingUid();
7595         mWifiPermissionsUtil.checkPackage(uid, packageName);
7596         long callingIdentity = Binder.clearCallingIdentity();
7597         try {
7598             if (!mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(uid)) {
7599                 Log.e(TAG, "UID " + uid + " not visible to the current user");
7600                 throw new SecurityException("UID " + uid + " not visible to the current user");
7601             }
7602         } finally {
7603             // restore calling identity
7604             Binder.restoreCallingIdentity(callingIdentity);
7605         }
7606         if (mVerboseLoggingEnabled) {
7607             mLog.info("removeLocalOnlyConnectionFailureListener uid=%")
7608                     .c(uid).flush();
7609         }
7610         mWifiThreadRunner.post(() ->
7611                 mWifiNetworkFactory.removeLocalOnlyConnectionStatusListener(listener, packageName),
7612                 TAG + "#removeLocalOnlyConnectionStatusListener");
7613     }
7614 
7615     @Override
7616     public int calculateSignalLevel(int rssi) {
7617         return RssiUtil.calculateSignalLevel(mContext, rssi);
7618     }
7619 
7620     /**
7621      * See {@link WifiManager#setPnoScanState(int)}
7622      */
7623     @Override
7624     public void setPnoScanEnabled(boolean enabled, boolean enablePnoScanAfterWifiToggle,
7625             String packageName) {
7626         int callingUid = Binder.getCallingUid();
7627         boolean hasPermission = mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)
7628                 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(callingUid);
7629         if (!hasPermission && SdkLevel.isAtLeastT()) {
7630             // MANAGE_WIFI_NETWORK_SELECTION is a new permission added in T.
7631             hasPermission = mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(
7632                     callingUid);
7633         }
7634         if (!hasPermission) {
7635             throw new SecurityException("Uid " + callingUid
7636                     + " is not allowed to set PNO scan state");
7637         }
7638 
7639         if (mVerboseLoggingEnabled) {
7640             Log.v(TAG, "setPnoScanEnabled " + Binder.getCallingUid() + " enabled=" + enabled
7641                     + ", enablePnoScanAfterWifiToggle=" + enablePnoScanAfterWifiToggle);
7642         }
7643         mLastCallerInfoManager.put(
7644                 WifiManager.API_SET_PNO_SCAN_ENABLED,
7645                 Process.myTid(), Binder.getCallingUid(), Binder.getCallingPid(), packageName,
7646                 enabled);
7647         mWifiThreadRunner.post(() -> {
7648             mWifiConnectivityManager.setPnoScanEnabledByFramework(enabled,
7649                     enablePnoScanAfterWifiToggle);
7650         }, TAG + "#setPnoScanEnabled");
7651     }
7652 
7653     /**
7654      * See {@link WifiManager#setExternalPnoScanRequest(List, int[], Executor,
7655      * WifiManager.PnoScanResultsCallback)}.
7656      */
7657     @Override
7658     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
7659     public void setExternalPnoScanRequest(@NonNull IBinder binder,
7660             @NonNull IPnoScanResultsCallback callback,
7661             @NonNull List<WifiSsid> ssids, @NonNull int[] frequencies,
7662             @NonNull String packageName, @NonNull String featureId) {
7663         if (!SdkLevel.isAtLeastT()) {
7664             throw new UnsupportedOperationException("SDK level too old");
7665         }
7666         if (binder == null) throw new IllegalArgumentException("binder cannot be null");
7667         if (callback == null) throw new IllegalArgumentException("callback cannot be null");
7668         if (ssids == null || ssids.isEmpty()) throw new IllegalStateException(
7669                 "Ssids can't be null or empty");
7670         if (ssids.size() > 2) {
7671             throw new IllegalArgumentException("Ssid list can't be greater than 2");
7672         }
7673         if (frequencies == null) {
7674             throw new IllegalArgumentException("frequencies should not be null");
7675         }
7676         if (frequencies.length > 10) {
7677             throw new IllegalArgumentException("Length of frequencies must be smaller than 10");
7678         }
7679         int uid = Binder.getCallingUid();
7680         mWifiPermissionsUtil.checkPackage(uid, packageName);
7681         if (!mWifiPermissionsUtil.checkRequestCompanionProfileAutomotiveProjectionPermission(uid)
7682                 || !mWifiPermissionsUtil.checkCallersLocationPermissionInManifest(uid, false)) {
7683             throw new SecurityException(TAG + " Caller uid " + uid + " has no permission");
7684         }
7685         if (mVerboseLoggingEnabled) {
7686             mLog.info("setExternalPnoScanRequest uid=%").c(uid).flush();
7687         }
7688         mWifiThreadRunner.post(() -> {
7689             try {
7690                 if (!isPnoSupported()) {
7691                     callback.onRegisterFailed(REGISTER_PNO_CALLBACK_PNO_NOT_SUPPORTED);
7692                     return;
7693                 }
7694                 mWifiConnectivityManager.setExternalPnoScanRequest(
7695                         uid, packageName, binder, callback, ssids, frequencies);
7696             } catch (RemoteException e) {
7697                 Log.e(TAG, e.getMessage(), e);
7698             }
7699         }, TAG + "#setExternalPnoScanRequest");
7700     }
7701 
7702     /**
7703      * See {@link WifiManager#clearExternalPnoScanRequest()}
7704      */
7705     @Override
7706     public void clearExternalPnoScanRequest() {
7707         int uid = Binder.getCallingUid();
7708         if (!SdkLevel.isAtLeastT()) {
7709             throw new UnsupportedOperationException();
7710         }
7711         if (mVerboseLoggingEnabled) {
7712             mLog.info("setExternalPnoScanRequest uid=%").c(uid).flush();
7713         }
7714         mWifiThreadRunner.post(() -> {
7715             mWifiConnectivityManager.clearExternalPnoScanRequest(uid);
7716         }, TAG + "#clearExternalPnoScanRequest");
7717     }
7718 
7719     /**
7720      * See {@link WifiManager#getLastCallerInfoForApi(int, Executor, BiConsumer)}.
7721      */
7722     @Override
7723     public void getLastCallerInfoForApi(int apiType, @NonNull ILastCallerListener listener) {
7724         if (listener == null) {
7725             throw new IllegalArgumentException("listener should not be null");
7726         }
7727         if (apiType < WifiManager.API_SCANNING_ENABLED || apiType > WifiManager.API_MAX) {
7728             throw new IllegalArgumentException("Invalid apiType " + apiType);
7729         }
7730         int uid = Binder.getCallingUid();
7731         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
7732                 && !mWifiPermissionsUtil.checkNetworkStackPermission(uid)
7733                 && !mWifiPermissionsUtil.checkMainlineNetworkStackPermission(uid)) {
7734             throw new SecurityException("Caller uid " + uid + " has no permission");
7735         }
7736 
7737         if (mVerboseLoggingEnabled) {
7738             Log.v(TAG, "getLastCallerInfoForApi " + Binder.getCallingUid());
7739         }
7740         mWifiThreadRunner.post(() -> {
7741             LastCallerInfoManager.LastCallerInfo lastCallerInfo =
7742                     mLastCallerInfoManager.get(apiType);
7743             try {
7744                 if (lastCallerInfo == null) {
7745                     listener.onResult(null, false);
7746                     return;
7747                 }
7748                 listener.onResult(lastCallerInfo.getPackageName(), lastCallerInfo.getToggleState());
7749             } catch (RemoteException e) {
7750                 Log.e(TAG, e.getMessage(), e);
7751             }
7752         }, TAG + "#getLastCallerInfoForApi");
7753     }
7754 
7755     /**
7756      * See {@link android.net.wifi.WifiManager#setWifiConnectedNetworkScorer(Executor,
7757      * WifiManager.WifiConnectedNetworkScorer)}
7758      *
7759      * @param binder IBinder instance to allow cleanup if the app dies.
7760      * @param scorer Wifi connected network scorer to set.
7761      * @return true Scorer is set successfully.
7762      *
7763      * @throws RemoteException if remote exception happens
7764      * @throws IllegalArgumentException if the arguments are null or invalid
7765      */
7766     @Override
7767     public boolean setWifiConnectedNetworkScorer(IBinder binder,
7768             IWifiConnectedNetworkScorer scorer) {
7769         if (binder == null) {
7770             throw new IllegalArgumentException("Binder must not be null");
7771         }
7772         if (scorer == null) {
7773             throw new IllegalArgumentException("Scorer must not be null");
7774         }
7775         mContext.enforceCallingOrSelfPermission(
7776                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
7777         int callingUid = Binder.getCallingUid();
7778         if (mVerboseLoggingEnabled) {
7779             mLog.info("setWifiConnectedNetworkScorer uid=%").c(callingUid).flush();
7780         }
7781         mWifiThreadRunner.post(() -> bindScorerService(callingUid));
7782         // Post operation to handler thread
7783         return mWifiThreadRunner.call(
7784                 () -> mActiveModeWarden.setWifiConnectedNetworkScorer(binder, scorer, callingUid),
7785                 false, TAG + "#setWifiConnectedNetworkScorer");
7786     }
7787 
7788     /**
7789      * See {@link WifiManager#clearWifiConnectedNetworkScorer()}
7790      */
7791     @Override
7792     public void clearWifiConnectedNetworkScorer() {
7793         mContext.enforceCallingOrSelfPermission(
7794                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
7795         if (mVerboseLoggingEnabled) {
7796             mLog.info("clearWifiConnectedNetworkScorer uid=%").c(Binder.getCallingUid()).flush();
7797         }
7798         mWifiThreadRunner.post(() -> unbindScorerService(SCORER_BINDING_STATE_CLEARED));
7799         // Post operation to handler thread
7800         mWifiThreadRunner.post(() -> mActiveModeWarden.clearWifiConnectedNetworkScorer(),
7801                 TAG + "#clearWifiConnectedNetworkScorer");
7802     }
7803 
7804     /**
7805      * See {@link android.net.wifi.WifiManager#setScanThrottleEnabled(boolean)}
7806      */
7807     @Override
7808     public void setScanThrottleEnabled(boolean enable) {
7809         enforceNetworkSettingsPermission();
7810         mLog.info("setScanThrottleEnabled uid=% enable=%")
7811                 .c(Binder.getCallingUid())
7812                 .c(enable).flush();
7813         mScanRequestProxy.setScanThrottleEnabled(enable);
7814     }
7815 
7816     /**
7817      * See {@link android.net.wifi.WifiManager#isScanThrottleEnabled()}
7818      */
7819     @Override
7820     public boolean isScanThrottleEnabled() {
7821         enforceAccessPermission();
7822         final boolean enable = mScanRequestProxy.isScanThrottleEnabled();
7823         if (mVerboseLoggingEnabled) {
7824             mLog.info("isScanThrottleEnabled uid=% enable=%")
7825                     .c(Binder.getCallingUid()).c(enable).flush();
7826         }
7827         return enable;
7828     }
7829 
7830     /**
7831      * See {@link android.net.wifi.WifiManager#setAutoWakeupEnabled(boolean)}
7832      */
7833     @Override
7834     public void setAutoWakeupEnabled(boolean enable) {
7835         enforceNetworkSettingsPermission();
7836         mLog.info("setWalkeupEnabled uid=% verbose=%")
7837                 .c(Binder.getCallingUid())
7838                 .c(enable).flush();
7839         long ident = Binder.clearCallingIdentity();
7840         try {
7841             mWifiInjector.getWakeupController().setEnabled(enable);
7842         } finally {
7843             Binder.restoreCallingIdentity(ident);
7844         }
7845     }
7846 
7847     /**
7848      * See {@link android.net.wifi.WifiManager#isAutoWakeupEnabled()}
7849      */
7850     @Override
7851     public boolean isAutoWakeupEnabled() {
7852         enforceAccessPermission();
7853         if (mVerboseLoggingEnabled) {
7854             mLog.info("isAutoWakeupEnabled uid=%").c(Binder.getCallingUid()).flush();
7855         }
7856         long ident = Binder.clearCallingIdentity();
7857         try {
7858             return mWifiInjector.getWakeupController().isEnabled();
7859         } finally {
7860             Binder.restoreCallingIdentity(ident);
7861         }
7862     }
7863 
7864     /**
7865      * See {@link android.net.wifi.WifiManager#setCarrierNetworkOffloadEnabled(int, boolean, boolean)}
7866      */
7867     @Override
7868     public void setCarrierNetworkOffloadEnabled(int subscriptionId, boolean merged,
7869             boolean enabled) {
7870         if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) {
7871             throw new SecurityException(TAG + ": Permission denied");
7872         }
7873         if (mVerboseLoggingEnabled) {
7874             mLog.info("setCarrierNetworkOffloadEnabled uid=%").c(Binder.getCallingUid()).flush();
7875         }
7876         long ident = Binder.clearCallingIdentity();
7877         try {
7878             mWifiCarrierInfoManager.setCarrierNetworkOffloadEnabled(subscriptionId, merged,
7879                     enabled);
7880         } finally {
7881             Binder.restoreCallingIdentity(ident);
7882         }
7883     }
7884 
7885     /**
7886      * See {@link android.net.wifi.WifiManager#isCarrierNetworkOffloadEnabled(int, boolean)}
7887      */
7888     @Override
7889     public boolean isCarrierNetworkOffloadEnabled(int subId, boolean merged) {
7890         enforceAccessPermission();
7891         if (mVerboseLoggingEnabled) {
7892             mLog.info("isCarrierNetworkOffload uid=%").c(Binder.getCallingUid()).flush();
7893         }
7894         long ident = Binder.clearCallingIdentity();
7895         try {
7896             return mWifiCarrierInfoManager.isCarrierNetworkOffloadEnabled(subId, merged);
7897         } finally {
7898             Binder.restoreCallingIdentity(ident);
7899         }
7900     }
7901 
7902     /**
7903      * See {@link android.net.wifi.WifiManager#addSuggestionUserApprovalStatusListener(Executor,
7904      * WifiManager.SuggestionUserApprovalStatusListener)}
7905      */
7906     @Override
7907     public void addSuggestionUserApprovalStatusListener(
7908             ISuggestionUserApprovalStatusListener listener, String packageName) {
7909         if (listener == null) {
7910             throw new NullPointerException("listener must not be null");
7911         }
7912         final int uid = Binder.getCallingUid();
7913         enforceAccessPermission();
7914         mWifiPermissionsUtil.checkPackage(uid, packageName);
7915         long callingIdentity = Binder.clearCallingIdentity();
7916         try {
7917             if (!mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(uid)) {
7918                 Log.e(TAG, "UID " + uid + " not visible to the current user");
7919                 throw new SecurityException("UID " + uid + " not visible to the current user");
7920             }
7921         } finally {
7922             // restore calling identity
7923             Binder.restoreCallingIdentity(callingIdentity);
7924         }
7925         if (mVerboseLoggingEnabled) {
7926             mLog.info("addSuggestionUserApprovalStatusListener uid=%").c(uid).flush();
7927         }
7928         mWifiThreadRunner.post(() -> mWifiNetworkSuggestionsManager
7929                 .addSuggestionUserApprovalStatusListener(listener, packageName, uid),
7930                 TAG + "#addSuggestionUserApprovalStatusListener");
7931     }
7932 
7933     /**
7934      * See {@link android.net.wifi.WifiManager#removeSuggestionUserApprovalStatusListener(
7935      * WifiManager.SuggestionUserApprovalStatusListener)}
7936      */
7937     @Override
7938     public void removeSuggestionUserApprovalStatusListener(
7939             ISuggestionUserApprovalStatusListener listener, String packageName) {
7940         enforceAccessPermission();
7941         int uid = Binder.getCallingUid();
7942         mWifiPermissionsUtil.checkPackage(uid, packageName);
7943         long callingIdentity = Binder.clearCallingIdentity();
7944         try {
7945             if (!mWifiPermissionsUtil.doesUidBelongToCurrentUserOrDeviceOwner(uid)) {
7946                 Log.e(TAG, "UID " + uid + " not visible to the current user");
7947                 throw new SecurityException("UID " + uid + " not visible to the current user");
7948             }
7949         } finally {
7950             // restore calling identity
7951             Binder.restoreCallingIdentity(callingIdentity);
7952         }
7953         if (mVerboseLoggingEnabled) {
7954             mLog.info("removeSuggestionUserApprovalStatusListener uid=%")
7955                     .c(uid).flush();
7956         }
7957         mWifiThreadRunner.post(() ->
7958                 mWifiNetworkSuggestionsManager
7959                         .removeSuggestionUserApprovalStatusListener(listener, packageName, uid),
7960                 TAG + "#removeSuggestionUserApprovalStatusListener");
7961     }
7962 
7963     /**
7964      * See {@link android.net.wifi.WifiManager#setEmergencyScanRequestInProgress(boolean)}.
7965      */
7966     @Override
7967     public void setEmergencyScanRequestInProgress(boolean inProgress) {
7968         enforceNetworkStackPermission();
7969         int uid = Binder.getCallingUid();
7970         mLog.info("setEmergencyScanRequestInProgress uid=%").c(uid).flush();
7971         mActiveModeWarden.setEmergencyScanRequestInProgress(inProgress);
7972     }
7973 
7974     /**
7975      * See {@link android.net.wifi.WifiManager#removeAppState(int, String)}.
7976      */
7977     @Override
7978     public void removeAppState(int targetAppUid, @NonNull String targetAppPackageName) {
7979         enforceNetworkSettingsPermission();
7980         mLog.info("removeAppState uid=%").c(Binder.getCallingUid()).flush();
7981 
7982         mWifiThreadRunner.post(() -> {
7983             removeAppStateInternal(targetAppUid, targetAppPackageName);
7984         }, TAG + "#removeAppState");
7985     }
7986 
7987     /**
7988      * See {@link android.net.wifi.WifiManager#setWifiScoringEnabled(boolean)}.
7989      */
7990     @Override
7991     public boolean setWifiScoringEnabled(boolean enabled) {
7992         mContext.enforceCallingOrSelfPermission(
7993                 android.Manifest.permission.NETWORK_SETTINGS, "WifiService");
7994         // Post operation to handler thread
7995         return mSettingsStore.handleWifiScoringEnabled(enabled);
7996     }
7997 
7998     /**
7999      * See {@link android.net.wifi.WifiManager#storeCapturedData(Executor, IntConsumer, int,
8000      * booloan, long, long)}.
8001      */
8002     @Override
8003     public void storeCapturedData(int triggerType, boolean isFullCapture,
8004             long triggerStartTimeMillis, long triggerStopTimeMillis,
8005             @NonNull IIntegerListener listener) {
8006         if (listener == null) {
8007             throw new IllegalArgumentException("listener should not be null");
8008         }
8009         mContext.enforceCallingOrSelfPermission(
8010                 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService");
8011         mWifiThreadRunner.post(() -> {
8012             try {
8013                 listener.onResult(mWifiMetrics.storeCapturedData(triggerType, isFullCapture,
8014                         triggerStartTimeMillis, triggerStopTimeMillis));
8015             } catch (RemoteException e) {
8016                 Log.e(TAG, e.getMessage(), e);
8017             }
8018         }, TAG + "#storeCapturedData");
8019     }
8020 
8021     @VisibleForTesting
8022     static boolean isValidBandForGetUsableChannels(@WifiScanner.WifiBand int band) {
8023         switch (band) {
8024             case WifiScanner.WIFI_BAND_UNSPECIFIED:
8025             case WifiScanner.WIFI_BAND_24_GHZ:
8026             case WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS:
8027             case WifiScanner.WIFI_BAND_BOTH_WITH_DFS:
8028             case WifiScanner.WIFI_BAND_6_GHZ:
8029             case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_GHZ:
8030             case WifiScanner.WIFI_BAND_60_GHZ:
8031             case WifiScanner.WIFI_BAND_24_5_WITH_DFS_6_60_GHZ:
8032                 return true;
8033             default:
8034                 return false;
8035         }
8036     }
8037 
8038     private List<WifiAvailableChannel> getStoredSoftApAvailableChannels(
8039             @WifiScanner.WifiBand int band) {
8040         List<Integer> freqs = new ArrayList<>();
8041         try {
8042             JSONArray json =
8043                     new JSONArray(
8044                             mSettingsConfigStore.get(
8045                                     WifiSettingsConfigStore.WIFI_AVAILABLE_SOFT_AP_FREQS_MHZ));
8046             for (int i = 0; i < json.length(); i++) {
8047                 freqs.add(json.getInt(i));
8048             }
8049         } catch (JSONException e) {
8050             Log.i(TAG, "Failed to read stored JSON for available Soft AP channels: " + e);
8051         }
8052         List<WifiAvailableChannel> channels = new ArrayList<>();
8053         for (int freq : freqs) {
8054             if ((band & ScanResult.toBand(freq)) == 0) {
8055                 continue;
8056             }
8057             // TODO b/340956906: Save and retrieve channel width in config store along with
8058             //  frequency.
8059             channels.add(new WifiAvailableChannel(freq, WifiAvailableChannel.OP_MODE_SAP,
8060                     ScanResult.CHANNEL_WIDTH_20MHZ));
8061         }
8062         return channels;
8063     }
8064 
8065     /**
8066      * See {@link android.net.wifi.WifiManager#getUsableChannels(int, int) and
8067      * See {@link android.net.wifi.WifiManager#getAllowedChannels(int, int).
8068      *
8069      * @throws SecurityException if the caller does not have permission
8070      * or IllegalArgumentException if the band is invalid for this method.
8071      */
8072     @Override
8073     public List<WifiAvailableChannel> getUsableChannels(@WifiScanner.WifiBand int band,
8074             @WifiAvailableChannel.OpMode int mode, @WifiAvailableChannel.Filter int filter,
8075             String packageName, Bundle extras) {
8076         final int uid = Binder.getCallingUid();
8077         if (isPlatformOrTargetSdkLessThanU(packageName, uid)) {
8078             // Location mode must be enabled
8079             long ident = Binder.clearCallingIdentity();
8080             try {
8081                 if (!mWifiPermissionsUtil.isLocationModeEnabled()) {
8082                     throw new SecurityException("Location mode is disabled for the device");
8083                 }
8084             } finally {
8085                 Binder.restoreCallingIdentity(ident);
8086             }
8087             if (!mWifiPermissionsUtil.checkCallersHardwareLocationPermission(uid)) {
8088                 throw new SecurityException(
8089                         "UID " + uid + " does not have location h/w permission");
8090             }
8091         } else {
8092             mWifiPermissionsUtil.enforceNearbyDevicesPermission(
8093                     extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE),
8094                     true, TAG + " getUsableChannels");
8095         }
8096         if (mVerboseLoggingEnabled) {
8097             mLog.info("getUsableChannels uid=% band=% mode=% filter=%").c(Binder.getCallingUid()).c(
8098                     band).c(mode).c(filter).flush();
8099         }
8100         if (!isValidBandForGetUsableChannels(band)) {
8101             throw new IllegalArgumentException("Unsupported band: " + band);
8102         }
8103         // Use stored values if the HAL isn't started and the stored country code matches.
8104         // This is to show the band availability based on the regulatory domain.
8105         if (mWifiNative.isHalSupported() && !mWifiNative.isHalStarted()
8106                 && mode == WifiAvailableChannel.OP_MODE_SAP
8107                 && filter == WifiAvailableChannel.FILTER_REGULATORY
8108                 && TextUtils.equals(
8109                         mSettingsConfigStore.get(WifiSettingsConfigStore.WIFI_SOFT_AP_COUNTRY_CODE),
8110                         mCountryCode.getCountryCode())) {
8111             List<WifiAvailableChannel> storedChannels = getStoredSoftApAvailableChannels(band);
8112             if (!storedChannels.isEmpty()) {
8113                 return storedChannels;
8114             }
8115         }
8116         List<WifiAvailableChannel> channels = mWifiThreadRunner.call(
8117                 () -> mWifiNative.getUsableChannels(band, mode, filter), null,
8118                 TAG + "#getUsableChannels");
8119         if (channels == null) {
8120             throw new UnsupportedOperationException();
8121         }
8122         return channels;
8123     }
8124 
8125     private void resetNotificationManager() {
8126         mWifiInjector.getWifiNotificationManager().createNotificationChannels();
8127         mWifiInjector.getOpenNetworkNotifier().clearPendingNotification(false);
8128         mWifiCarrierInfoManager.resetNotification();
8129         mWifiNetworkSuggestionsManager.resetNotification();
8130         mWifiInjector.getWakeupController().resetNotification();
8131     }
8132 
8133     /**
8134      * See {@link android.net.wifi.WifiManager#flushPasspointAnqpCache()}.
8135      */
8136     @Override
8137     public void flushPasspointAnqpCache(@NonNull String packageName) {
8138         int callingUid = Binder.getCallingUid();
8139         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
8140 
8141         if (!isDeviceOrProfileOwner(callingUid, packageName)) {
8142             enforceAnyPermissionOf(android.Manifest.permission.NETWORK_SETTINGS,
8143                     android.Manifest.permission.NETWORK_MANAGED_PROVISIONING,
8144                     android.Manifest.permission.NETWORK_CARRIER_PROVISIONING);
8145         }
8146         mWifiThreadRunner.post(mPasspointManager::clearAnqpRequestsAndFlushCache,
8147                 TAG + "#flushPasspointAnqpCache");
8148     }
8149 
8150     /**
8151      * See {@link android.net.wifi.WifiManager#isWifiPasspointEnabled()}.
8152      */
8153     @Override
8154     public boolean isWifiPasspointEnabled() {
8155         enforceAccessPermission();
8156 
8157         if (mVerboseLoggingEnabled) {
8158             mLog.info("isWifiPasspointEnabled uid=%").c(Binder.getCallingUid()).flush();
8159         }
8160         // Post operation to handler thread
8161         return mWifiThreadRunner.call(() -> mPasspointManager.isWifiPasspointEnabled(), false,
8162                 TAG + "#isWifiPasspointEnabled");
8163     }
8164 
8165     /**
8166      * See {@link android.net.wifi.WifiManager#setWifiPasspointEnabled()}.
8167      */
8168     @Override
8169     public void setWifiPasspointEnabled(boolean enabled) {
8170         int uid = Binder.getCallingUid();
8171         int pid = Binder.getCallingPid();
8172         if (!isSettingsOrSuw(pid, uid)) {
8173             throw new SecurityException(TAG + ": Permission denied");
8174         }
8175 
8176         if (mVerboseLoggingEnabled) {
8177             mLog.info("setWifiPasspointEnabled uid=% pid=% enable=%")
8178                 .c(uid).c(pid).c(enabled)
8179                 .flush();
8180         }
8181 
8182         // Post operation to handler thread
8183         mWifiThreadRunner.post(() -> mPasspointManager.setWifiPasspointEnabled(enabled),
8184                 TAG + "#setWifiPasspointEnabled"
8185         );
8186     }
8187 
8188     /**
8189      * See {@link android.net.wifi.WifiManager#isPreferredNetworkOffloadSupported()}.
8190      */
8191     @Override
8192     public boolean isPnoSupported() {
8193         boolean featureSetSupportsPno = isFeatureSupported(WifiManager.WIFI_FEATURE_PNO);
8194         return mWifiGlobals.isSwPnoEnabled()
8195                 || (mWifiGlobals.isBackgroundScanSupported() && featureSetSupportsPno);
8196     }
8197 
8198     private boolean isAggressiveRoamingModeSupported() {
8199         return isFeatureSupported(WifiManager.WIFI_FEATURE_AGGRESSIVE_ROAMING_MODE_SUPPORT);
8200     }
8201 
8202     /**
8203      * @return true if this device supports Trust On First Use
8204      */
8205     private boolean isTrustOnFirstUseSupported() {
8206         return isFeatureSupported(WifiManager.WIFI_FEATURE_TRUST_ON_FIRST_USE);
8207     }
8208 
8209     /**
8210      * See {@link android.net.wifi.WifiManager#getStaConcurrencyForMultiInternetMode()}.
8211      */
8212     @Override
8213     public @WifiManager.WifiMultiInternetMode int getStaConcurrencyForMultiInternetMode() {
8214         if (!SdkLevel.isAtLeastT()) {
8215             throw new UnsupportedOperationException();
8216         }
8217         enforceAccessPermission();
8218 
8219         if (mVerboseLoggingEnabled) {
8220             mLog.info("getStaConcurrencyForMultiInternetMode uid=%")
8221                     .c(Binder.getCallingUid()).flush();
8222         }
8223         // Post operation to handler thread
8224         return mWifiThreadRunner.call(
8225                 () -> mMultiInternetManager.getStaConcurrencyForMultiInternetMode(),
8226                 WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED,
8227                 TAG + "#getStaConcurrencyForMultiInternetMode");
8228     }
8229 
8230     /**
8231      * See {@link android.net.wifi.WifiManager#setStaConcurrencyForMultiInternetMode()}.
8232      */
8233     @Override
8234     public boolean setStaConcurrencyForMultiInternetMode(
8235             @WifiManager.WifiMultiInternetMode int mode) {
8236         if (!SdkLevel.isAtLeastT()) {
8237             throw new UnsupportedOperationException();
8238         }
8239         int uid = Binder.getCallingUid();
8240         int pid = Binder.getCallingPid();
8241         if (!isSettingsOrSuw(pid, uid)) {
8242             throw new SecurityException(TAG + ": Permission denied");
8243         }
8244 
8245         if (mVerboseLoggingEnabled) {
8246             mLog.info("setStaConcurrencyForMultiInternetMode uid=% pid=% mode=%")
8247                 .c(uid).c(pid).c(mode)
8248                 .flush();
8249         }
8250         // Post operation to handler thread
8251         return mWifiThreadRunner.call(() ->
8252                 mMultiInternetManager.setStaConcurrencyForMultiInternetMode(mode), false,
8253                 TAG + "#setStaConcurrencyForMultiInternetMode");
8254     }
8255 
8256     /**
8257      * See {@link android.net.wifi.WifiManager#notifyMinimumRequiredWifiSecurityLevelChanged(int)}.
8258      */
8259     @Override
8260     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
8261     public void notifyMinimumRequiredWifiSecurityLevelChanged(int adminMinimumSecurityLevel) {
8262         if (!SdkLevel.isAtLeastT()) {
8263             throw new UnsupportedOperationException();
8264         }
8265         if (!Arrays.asList(DevicePolicyManager.WIFI_SECURITY_OPEN,
8266                 DevicePolicyManager.WIFI_SECURITY_PERSONAL,
8267                 DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_EAP,
8268                 DevicePolicyManager.WIFI_SECURITY_ENTERPRISE_192)
8269                 .contains(adminMinimumSecurityLevel)) {
8270             throw new IllegalArgumentException("Input security level is invalid");
8271         }
8272         if (!checkManageDeviceAdminsPermission(Binder.getCallingPid(), Binder.getCallingUid())) {
8273             throw new SecurityException("Caller does not have MANAGE_DEVICE_ADMINS permission");
8274         }
8275         mWifiThreadRunner.post(() -> {
8276             for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) {
8277                 WifiInfo wifiInfo = cmm.getConnectionInfo();
8278                 if (wifiInfo == null) continue;
8279 
8280                 //check minimum security level restriction
8281                 int currentSecurityLevel = WifiInfo.convertSecurityTypeToDpmWifiSecurity(
8282                         wifiInfo.getCurrentSecurityType());
8283 
8284                 // Unknown security type is permitted when security type restriction is not set
8285                 if (adminMinimumSecurityLevel == DevicePolicyManager.WIFI_SECURITY_OPEN
8286                         && currentSecurityLevel == WifiInfo.DPM_SECURITY_TYPE_UNKNOWN) {
8287                     continue;
8288                 }
8289                 if (adminMinimumSecurityLevel > currentSecurityLevel) {
8290                     cmm.disconnect();
8291                     mLog.info("disconnect admin restricted network").flush();
8292                     continue;
8293                 }
8294             }
8295         }, TAG + "#notifyMinimumRequiredWifiSecurityLevelChanged");
8296     }
8297 
8298     /**
8299      * See {@link android.net.wifi.WifiManager#notifyWifiSsidPolicyChanged(WifiSsidPolicy)}.
8300      */
8301     @Override
8302     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
8303     public void notifyWifiSsidPolicyChanged(int policyType, ParceledListSlice<WifiSsid> ssids) {
8304         if (!SdkLevel.isAtLeastT()) {
8305             throw new UnsupportedOperationException();
8306         }
8307         if (ssids == null || ssids.getList() == null) {
8308             throw new IllegalArgumentException("SSID list may not be null");
8309         }
8310         if (!checkManageDeviceAdminsPermission(Binder.getCallingPid(), Binder.getCallingUid())) {
8311             throw new SecurityException("Caller does not have MANAGE_DEVICE_ADMINS permission");
8312         }
8313         mWifiThreadRunner.post(() -> {
8314             for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) {
8315                 WifiInfo wifiInfo = cmm.getConnectionInfo();
8316                 if (wifiInfo == null) continue;
8317 
8318                 //skip SSID restriction check for Osu and Passpoint networks
8319                 if (wifiInfo.isOsuAp() || wifiInfo.isPasspointAp()) continue;
8320 
8321                 WifiSsid ssid = wifiInfo.getWifiSsid();
8322 
8323                 if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_ALLOWLIST
8324                         && !ssids.getList().contains(ssid)) {
8325                     cmm.disconnect();
8326                     mLog.info("disconnect admin restricted network").flush();
8327                     continue;
8328                 }
8329                 if (policyType == WifiSsidPolicy.WIFI_SSID_POLICY_TYPE_DENYLIST
8330                         && ssids.getList().contains(ssid)) {
8331                     cmm.disconnect();
8332                     mLog.info("disconnect admin restricted network").flush();
8333                     continue;
8334                 }
8335             }
8336         }, TAG + "#notifyWifiSsidPolicyChanged");
8337     }
8338 
8339     /**
8340      * See {@link WifiManager#replyToSimpleDialog(int, int)}
8341      */
8342     public void replyToSimpleDialog(int dialogId, @WifiManager.DialogReply int reply) {
8343         int uid = Binder.getCallingUid();
8344         int pid = Binder.getCallingPid();
8345         mWifiPermissionsUtil.checkPackage(uid, mContext.getWifiDialogApkPkgName());
8346         if (mVerboseLoggingEnabled) {
8347             mLog.info("replyToSimpleDialog uid=% pid=%"
8348                             + " dialogId=% reply=%")
8349                     .c(uid).c(pid).c(dialogId).c(reply)
8350                     .flush();
8351         }
8352         mWifiThreadRunner.post(() -> mWifiDialogManager.replyToSimpleDialog(dialogId, reply),
8353                 TAG + "#replyToSimpleDialog");
8354     }
8355 
8356     /**
8357      * See {@link WifiManager#replyToP2pInvitationReceivedDialog(int, boolean, String)}
8358      */
8359     @Override
8360     public void replyToP2pInvitationReceivedDialog(
8361             int dialogId, boolean accepted, @Nullable String optionalPin) {
8362         int uid = Binder.getCallingUid();
8363         int pid = Binder.getCallingPid();
8364         mWifiPermissionsUtil.checkPackage(uid, mContext.getWifiDialogApkPkgName());
8365         if (mVerboseLoggingEnabled) {
8366             mLog.info("replyToP2pInvitationReceivedDialog uid=% pid=%"
8367                             + " dialogId=% accepted=% optionalPin=%")
8368                     .c(uid).c(pid).c(dialogId).c(accepted).c(optionalPin)
8369                     .flush();
8370         }
8371         mWifiThreadRunner.post(() -> mWifiDialogManager.replyToP2pInvitationReceivedDialog(
8372                 dialogId, accepted, optionalPin), TAG + "#replyToP2pInvitationReceivedDialog"
8373         );
8374     }
8375 
8376     /**
8377      * See {@link android.net.wifi.WifiManager#addCustomDhcpOptions}.
8378      */
8379     @Override
8380     public void addCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui,
8381             @NonNull ParceledListSlice<DhcpOption> options) {
8382         enforceAnyPermissionOf(android.Manifest.permission.NETWORK_SETTINGS,
8383                 android.Manifest.permission.OVERRIDE_WIFI_CONFIG);
8384         if (mVerboseLoggingEnabled) {
8385             Log.v(TAG, "addCustomDhcpOptions: ssid="
8386                     + ssid + ", oui=" + Arrays.toString(oui) + ", options=" + options);
8387         }
8388         List<DhcpOption> dhcpOptionList = options == null ? null : options.getList();
8389         mWifiThreadRunner.post(() -> mWifiConfigManager.addCustomDhcpOptions(ssid, oui,
8390                         dhcpOptionList),
8391                 TAG + "#addCustomDhcpOptions");
8392     }
8393 
8394     /**
8395      * See {@link android.net.wifi.WifiManager#removeCustomDhcpOptions}.
8396      */
8397     @Override
8398     public void removeCustomDhcpOptions(@NonNull WifiSsid ssid, @NonNull byte[] oui) {
8399         enforceAnyPermissionOf(android.Manifest.permission.NETWORK_SETTINGS,
8400                 android.Manifest.permission.OVERRIDE_WIFI_CONFIG);
8401         if (mVerboseLoggingEnabled) {
8402             Log.v(TAG, "removeCustomDhcpOptions: ssid=" + ssid + ", oui=" + Arrays.toString(oui));
8403         }
8404         mWifiThreadRunner.post(() -> mWifiConfigManager.removeCustomDhcpOptions(ssid, oui),
8405                 TAG + "#removeCustomDhcpOptions");
8406     }
8407 
8408     /**
8409      * See {@link android.net.wifi.WifiManager#getOemPrivilegedWifiAdminPackages
8410      */
8411     @Override
8412     public String[] getOemPrivilegedWifiAdminPackages() {
8413         return mResourceCache
8414                 .getStringArray(R.array.config_oemPrivilegedWifiAdminPackages);
8415     }
8416 
8417     /**
8418      * See {@link WifiManager#reportImpactToCreateIfaceRequest(int, boolean, Executor, BiConsumer)}.
8419      */
8420     @Override
8421     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
8422     public void reportCreateInterfaceImpact(String packageName, int interfaceType,
8423             boolean requireNewInterface, IInterfaceCreationInfoCallback callback) {
8424         if (!SdkLevel.isAtLeastT()) {
8425             throw new UnsupportedOperationException("SDK level too old");
8426         }
8427 
8428         final SparseIntArray hdmIfaceToWifiIfaceMap = new SparseIntArray() {{
8429                 put(HDM_CREATE_IFACE_STA, WIFI_INTERFACE_TYPE_STA);
8430                 put(HDM_CREATE_IFACE_AP, WIFI_INTERFACE_TYPE_AP);
8431                 put(HDM_CREATE_IFACE_AP_BRIDGE, WIFI_INTERFACE_TYPE_AP);
8432                 put(HDM_CREATE_IFACE_P2P, WIFI_INTERFACE_TYPE_DIRECT);
8433                 put(HDM_CREATE_IFACE_NAN, WIFI_INTERFACE_TYPE_AWARE);
8434             }};
8435         final SparseIntArray wifiIfaceToHdmIfaceMap = new SparseIntArray() {{
8436                 put(WIFI_INTERFACE_TYPE_STA, HDM_CREATE_IFACE_STA);
8437                 put(WIFI_INTERFACE_TYPE_AP, HDM_CREATE_IFACE_AP);
8438                 put(WIFI_INTERFACE_TYPE_AWARE, HDM_CREATE_IFACE_NAN);
8439                 put(WIFI_INTERFACE_TYPE_DIRECT, HDM_CREATE_IFACE_P2P);
8440             }};
8441 
8442         if (packageName == null) throw new IllegalArgumentException("Null packageName");
8443         if (callback == null) throw new IllegalArgumentException("Null callback");
8444         if (interfaceType != WIFI_INTERFACE_TYPE_STA && interfaceType != WIFI_INTERFACE_TYPE_AP
8445                 && interfaceType != WIFI_INTERFACE_TYPE_AWARE
8446                 && interfaceType != WIFI_INTERFACE_TYPE_DIRECT) {
8447             throw new IllegalArgumentException("Invalid interfaceType");
8448         }
8449         enforceAccessPermission();
8450         int callingUid = getMockableCallingUid();
8451         if (!mWifiPermissionsUtil.checkManageWifiInterfacesPermission(callingUid)) {
8452             throw new SecurityException(
8453                     TAG + " Uid " + callingUid + " Missing MANAGE_WIFI_INTERFACES permission");
8454         }
8455         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
8456         mWifiThreadRunner.post(() -> {
8457             List<Pair<Integer, WorkSource>> details =
8458                     mHalDeviceManager.reportImpactToCreateIface(
8459                             wifiIfaceToHdmIfaceMap.get(interfaceType), requireNewInterface,
8460                             new WorkSource(callingUid, packageName));
8461             try {
8462                 if (details == null) {
8463                     callback.onResults(false, null, null);
8464                 } else {
8465                     int[] interfaces = new int[details.size()];
8466                     String[] packagesForInterfaces = new String[details.size()];
8467                     int i = 0;
8468                     for (Pair<Integer, WorkSource> detail: details) {
8469                         interfaces[i] = hdmIfaceToWifiIfaceMap.get(detail.first);
8470                         if (detail.second.size() == 1
8471                                 && detail.second.getUid(0) == WIFI_UID) {
8472                             i++;
8473                             continue;
8474                         }
8475                         StringBuilder packages = new StringBuilder();
8476                         for (int j = 0; j < detail.second.size(); ++j) {
8477                             if (j != 0) packages.append(",");
8478                             packages.append(detail.second.getPackageName(j));
8479                             mContext.getPackageManager().makeUidVisible(callingUid,
8480                                     detail.second.getUid(j));
8481                         }
8482                         packagesForInterfaces[i] = packages.toString();
8483                         ++i;
8484                     }
8485                     callback.onResults(true, interfaces, packagesForInterfaces);
8486                 }
8487             } catch (RemoteException e) {
8488                 Log.e(TAG,
8489                         "Failed calling back with results of isItPossibleToCreateInterface - " + e);
8490             }
8491         }, TAG + "#reportCreateInterfaceImpact");
8492     }
8493     @Override
8494     public int getMaxNumberOfChannelsPerRequest() {
8495         return mResourceCache
8496                 .getInteger(R.integer.config_wifiNetworkSpecifierMaxPreferredChannels);
8497     }
8498 
8499     private boolean policyIdsAreUnique(List<QosPolicyParams> policies) {
8500         Set<Integer> policyIdSet = new HashSet<>();
8501         for (QosPolicyParams policy : policies) {
8502             policyIdSet.add(policy.getPolicyId());
8503         }
8504         return policyIdSet.size() == policies.size();
8505     }
8506 
8507     private boolean policyIdsAreUnique(int[] policyIds) {
8508         Set<Integer> policyIdSet = new HashSet<>();
8509         for (int policyId : policyIds) {
8510             policyIdSet.add(policyId);
8511         }
8512         return policyIdSet.size() == policyIds.length;
8513     }
8514 
8515     private boolean policiesHaveSameDirection(List<QosPolicyParams> policyList) {
8516         int direction = policyList.get(0).getDirection();
8517         for (QosPolicyParams policy : policyList) {
8518             if (policy.getDirection() != direction) {
8519                 return false;
8520             }
8521         }
8522         return true;
8523     }
8524 
8525     private void rejectAllQosPolicies(
8526             List<QosPolicyParams> policyParamsList, IListListener listener) {
8527         try {
8528             List<Integer> statusList = new ArrayList<>();
8529             for (QosPolicyParams policy : policyParamsList) {
8530                 statusList.add(WifiManager.QOS_REQUEST_STATUS_FAILURE_UNKNOWN);
8531             }
8532             listener.onResult(statusList);
8533         } catch (RemoteException e) {
8534             Log.e(TAG, e.getMessage(), e);
8535         }
8536     }
8537 
8538     /**
8539      * See {@link WifiManager#addQosPolicies(List, Executor, Consumer)}.
8540      */
8541     @Override
8542     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
8543     public void addQosPolicies(@NonNull ParceledListSlice<QosPolicyParams> policyParamsList,
8544             @NonNull IBinder binder, @NonNull String packageName,
8545             @NonNull IListListener listener) {
8546         if (!SdkLevel.isAtLeastU()) {
8547             throw new UnsupportedOperationException("SDK level too old");
8548         }
8549 
8550         int uid = Binder.getCallingUid();
8551         mWifiPermissionsUtil.checkPackage(uid, packageName);
8552         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
8553                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8554             throw new SecurityException("Uid=" + uid + " is not allowed to add QoS policies");
8555         }
8556 
8557         Objects.requireNonNull(policyParamsList, "policyParamsList cannot be null");
8558         Objects.requireNonNull(policyParamsList.getList(),
8559             "policyParamsList contents cannot be null");
8560         Objects.requireNonNull(binder, "binder cannot be null");
8561         Objects.requireNonNull(listener, "listener cannot be null");
8562 
8563         if (policyParamsList.getList().size() == 0
8564                 || policyParamsList.getList().size()
8565                 > WifiManager.getMaxNumberOfPoliciesPerQosRequest()
8566                 || !policyIdsAreUnique(policyParamsList.getList())
8567                 || !policiesHaveSameDirection(policyParamsList.getList())) {
8568             throw new IllegalArgumentException("policyParamsList is invalid");
8569         }
8570 
8571         if (!mApplicationQosPolicyRequestHandler.isFeatureEnabled()) {
8572             Log.i(TAG, "addQosPolicies is disabled on this device");
8573             rejectAllQosPolicies(policyParamsList.getList(), listener);
8574             return;
8575         }
8576 
8577 
8578 
8579         if (!(SdkLevel.isAtLeastV() && isWifiStandardSupported(ScanResult.WIFI_STANDARD_11AX))
8580                 && policyParamsList.getList().get(0).getDirection()
8581                 == QosPolicyParams.DIRECTION_UPLINK) {
8582             Log.e(TAG, "Uplink QoS policies are only supported on devices with SDK >= V"
8583                     + " and 11ax support");
8584             rejectAllQosPolicies(policyParamsList.getList(), listener);
8585             return;
8586         }
8587 
8588         mWifiThreadRunner.post(() -> {
8589             mApplicationQosPolicyRequestHandler.queueAddRequest(
8590                     policyParamsList.getList(), listener, binder, uid);
8591         }, TAG + "#addQosPolicies");
8592     }
8593 
8594     /**
8595      * See {@link WifiManager#removeQosPolicies(int[])}.
8596      */
8597     @Override
8598     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
8599     public void removeQosPolicies(@NonNull int[] policyIds, @NonNull String packageName) {
8600         if (!SdkLevel.isAtLeastU()) {
8601             throw new UnsupportedOperationException("SDK level too old");
8602         } else if (!mApplicationQosPolicyRequestHandler.isFeatureEnabled()) {
8603             Log.i(TAG, "removeQosPolicies is disabled on this device");
8604             return;
8605         }
8606         int uid = Binder.getCallingUid();
8607         mWifiPermissionsUtil.checkPackage(uid, packageName);
8608         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
8609                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8610             throw new SecurityException("Uid=" + uid + " is not allowed to remove QoS policies");
8611         }
8612         Objects.requireNonNull(policyIds, "policyIdList cannot be null");
8613         if (policyIds.length == 0
8614                 || policyIds.length > WifiManager.getMaxNumberOfPoliciesPerQosRequest()
8615                 || !policyIdsAreUnique(policyIds)) {
8616             throw new IllegalArgumentException("policyIdList is invalid");
8617         }
8618 
8619         List<Integer> policyIdList = Arrays.stream(policyIds).boxed().toList();
8620         mWifiThreadRunner.post(() -> {
8621             mApplicationQosPolicyRequestHandler.queueRemoveRequest(policyIdList, uid);
8622         }, TAG + "#removeQosPolicies");
8623     }
8624 
8625     /**
8626      * See {@link WifiManager#removeAllQosPolicies()}.
8627      */
8628     @Override
8629     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
8630     public void removeAllQosPolicies(@NonNull String packageName) {
8631         if (!SdkLevel.isAtLeastU()) {
8632             throw new UnsupportedOperationException("SDK level too old");
8633         } else if (!mApplicationQosPolicyRequestHandler.isFeatureEnabled()) {
8634             Log.i(TAG, "removeAllQosPolicies is disabled on this device");
8635             return;
8636         }
8637         int uid = Binder.getCallingUid();
8638         mWifiPermissionsUtil.checkPackage(uid, packageName);
8639         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
8640                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8641             throw new SecurityException("Uid=" + uid + " is not allowed to remove QoS policies");
8642         }
8643 
8644         mWifiThreadRunner.post(() -> {
8645             mApplicationQosPolicyRequestHandler.queueRemoveAllRequest(uid);
8646         }, TAG + "#removeAllQosPolicies");
8647     }
8648 
8649     /**
8650      * See {@link WifiManager#setLinkLayerStatsPollingInterval(int)}.
8651      */
8652     @Override
8653     public void setLinkLayerStatsPollingInterval(int intervalMs) {
8654         if (!SdkLevel.isAtLeastT()) {
8655             throw new UnsupportedOperationException("SDK level too old");
8656         }
8657         enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION);
8658         if (intervalMs < 0) {
8659             throw new IllegalArgumentException("intervalMs should not be smaller than 0");
8660         }
8661         mWifiThreadRunner.post(() -> mActiveModeWarden.getPrimaryClientModeManager()
8662                     .setLinkLayerStatsPollingInterval(intervalMs),
8663                 TAG + "#setLinkLayerStatsPollingInterval");
8664     }
8665 
8666     /**
8667      * See {@link WifiManager#getLinkLayerStatsPollingInterval(Executor, Consumer)}.
8668      */
8669     @Override
8670     public void getLinkLayerStatsPollingInterval(@NonNull IIntegerListener listener) {
8671         if (!SdkLevel.isAtLeastT()) {
8672             throw new UnsupportedOperationException("SDK level too old");
8673         }
8674         if (listener == null) {
8675             throw new NullPointerException("listener should not be null");
8676         }
8677         enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION);
8678         mWifiThreadRunner.post(() -> {
8679             try {
8680                 listener.onResult(mWifiGlobals.getPollRssiIntervalMillis());
8681             } catch (RemoteException e) {
8682                 Log.e(TAG, e.getMessage(), e);
8683             }
8684         }, TAG + "#getLinkLayerStatsPollingInterval");
8685     }
8686 
8687     /**
8688      * See {@link WifiManager#setMloMode(int, Executor, Consumer)}
8689      */
8690     @Override
8691     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
8692     public void setMloMode(@WifiManager.MloMode int mode, @NonNull IBooleanListener listener) {
8693         // SDK check.
8694         if (!SdkLevel.isAtLeastU()) {
8695             throw new UnsupportedOperationException("SDK level too old");
8696         }
8697         // Permission check.
8698         int uid = Binder.getCallingUid();
8699         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8700             throw new SecurityException("Uid=" + uid + " is not allowed to set MLO mode");
8701         }
8702         // Argument check
8703         Objects.requireNonNull(listener, "listener cannot be null");
8704         if (mode < WifiManager.MLO_MODE_DEFAULT || mode > WifiManager.MLO_MODE_LOW_POWER) {
8705             throw new IllegalArgumentException("invalid mode: " + mode);
8706         }
8707         // Set MLO mode and process error status.
8708         mWifiThreadRunner.post(() -> {
8709             try {
8710                 listener.onResult(mWifiNative.setMloMode(mode) == WifiStatusCode.SUCCESS);
8711             } catch (RemoteException e) {
8712                 Log.e(TAG, e.getMessage(), e);
8713             }
8714         }, TAG + "#setMloMode");
8715     }
8716 
8717     /**
8718      * See {@link WifiManager#getMloMode(Executor, Consumer)}
8719      */
8720     @Override
8721     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
8722     public void getMloMode(IIntegerListener listener) {
8723         // SDK check.
8724         if (!SdkLevel.isAtLeastU()) {
8725             throw new UnsupportedOperationException("SDK level too old");
8726         }
8727         // Permission check.
8728         int uid = Binder.getCallingUid();
8729         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8730             throw new SecurityException("Uid=" + uid + " is not allowed to get MLO mode");
8731         }
8732         // Argument check
8733         Objects.requireNonNull(listener, "listener cannot be null");
8734         // Get MLO mode.
8735         mWifiThreadRunner.post(() -> {
8736             try {
8737                 listener.onResult(mWifiNative.getMloMode());
8738             } catch (RemoteException e) {
8739                 Log.e(TAG, e.getMessage(), e);
8740             }
8741         }, TAG + "#getMloMode");
8742     }
8743 
8744     /**
8745      * See {@link WifiManager#addWifiLowLatencyLockListener(Executor,
8746      * WifiManager.WifiLowLatencyLockListener)}
8747      */
8748     public void addWifiLowLatencyLockListener(IWifiLowLatencyLockListener listener) {
8749         if (listener == null) {
8750             throw new IllegalArgumentException();
8751         }
8752         int callingUid = Binder.getCallingUid();
8753         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(callingUid)
8754                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
8755             throw new SecurityException(TAG + " Uid " + callingUid
8756                     + " Missing MANAGE_WIFI_NETWORK_SELECTION permission");
8757         }
8758         if (mVerboseLoggingEnabled) {
8759             mLog.info("addWifiLowLatencyLockListener uid=%").c(Binder.getCallingUid()).flush();
8760         }
8761         mWifiThreadRunner.post(() -> {
8762             mWifiLockManager.addWifiLowLatencyLockListener(listener);
8763         }, TAG + "#addWifiLowLatencyLockListener");
8764     }
8765 
8766     /**
8767      * See {@link WifiManager#removeWifiLowLatencyLockListener(
8768      * WifiManager.WifiLowLatencyLockListener)}
8769      */
8770     @Override
8771     public void removeWifiLowLatencyLockListener(IWifiLowLatencyLockListener listener) {
8772         if (listener == null) {
8773             throw new IllegalArgumentException();
8774         }
8775         if (mVerboseLoggingEnabled) {
8776             mLog.info("removeWifiLowLatencyLockListener uid=%").c(Binder.getCallingUid()).flush();
8777         }
8778         mWifiThreadRunner.post(() -> {
8779             mWifiLockManager.removeWifiLowLatencyLockListener(listener);
8780         }, TAG + "#removeWifiLowLatencyLockListener");
8781     }
8782 
8783     private String getPackageName(Bundle extras) {
8784         // AttributionSource#getPackageName() is added in API level 31.
8785         if (!SdkLevel.isAtLeastS() || extras == null) {
8786             return PACKAGE_NAME_NOT_AVAILABLE;
8787         }
8788         AttributionSource attributionSource = extras.getParcelable(
8789                 WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE);
8790         if (attributionSource == null) return PACKAGE_NAME_NOT_AVAILABLE;
8791         String packageName = attributionSource.getPackageName();
8792         if (packageName == null) return PACKAGE_NAME_NOT_AVAILABLE;
8793         return packageName;
8794     }
8795 
8796     /**
8797      * See {@link WifiManager#getMaxMloAssociationLinkCount(Executor, Consumer)}
8798      */
8799     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
8800     @Override
8801     public void getMaxMloAssociationLinkCount(@NonNull IIntegerListener listener, Bundle extras) {
8802         // SDK check.
8803         if (!SdkLevel.isAtLeastU()) {
8804             throw new UnsupportedOperationException("SDK level too old");
8805         }
8806         // Permission check.
8807         int uid = Binder.getCallingUid();
8808         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8809             throw new SecurityException(
8810                     "Caller does not have MANAGE_WIFI_NETWORK_SELECTION permission");
8811         }
8812 
8813         Objects.requireNonNull(listener, "listener cannot be null");
8814         if (mVerboseLoggingEnabled) {
8815             mLog.info("getMaxMloAssociationLinkCount: Uid=% Package Name=%").c(
8816                     Binder.getCallingUid()).c(getPackageName(extras)).flush();
8817         }
8818 
8819         mWifiThreadRunner.post(() -> {
8820             try {
8821                 listener.onResult(mWifiNative.getMaxMloAssociationLinkCount(
8822                         mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName()));
8823             } catch (RemoteException e) {
8824                 Log.e(TAG, e.getMessage(), e);
8825             }
8826         }, TAG + "#getMaxMloAssociationLinkCount");
8827     }
8828 
8829     /**
8830      * See {@link WifiManager#getMaxMloStrLinkCount(Executor, Consumer)}
8831      */
8832     @Override
8833     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
8834     public void getMaxMloStrLinkCount(@NonNull IIntegerListener listener, Bundle extras) {
8835         // SDK check.
8836         if (!SdkLevel.isAtLeastU()) {
8837             throw new UnsupportedOperationException("SDK level too old");
8838         }
8839         // Permission check.
8840         int uid = Binder.getCallingUid();
8841         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8842             throw new SecurityException(
8843                     "Caller does not have MANAGE_WIFI_NETWORK_SELECTION permission");
8844         }
8845 
8846         Objects.requireNonNull(listener, "listener cannot be null");
8847         if (mVerboseLoggingEnabled) {
8848             mLog.info("getMaxMloStrLinkCount:  Uid=% Package Name=%").c(
8849                     Binder.getCallingUid()).c(getPackageName(extras)).flush();
8850         }
8851 
8852         mWifiThreadRunner.post(() -> {
8853             try {
8854                 listener.onResult(mWifiNative.getMaxMloStrLinkCount(
8855                         mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName()));
8856             } catch (RemoteException e) {
8857                 Log.e(TAG, e.getMessage(), e);
8858             }
8859         }, TAG + "#getMaxMloStrLinkCount");
8860     }
8861 
8862     /**
8863      * See {@link WifiManager#getSupportedSimultaneousBandCombinations(Executor, Consumer)}.
8864      */
8865     @Override
8866     public void getSupportedSimultaneousBandCombinations(@NonNull IWifiBandsListener listener,
8867             Bundle extras) {
8868         // SDK check.
8869         if (!SdkLevel.isAtLeastU()) {
8870             throw new UnsupportedOperationException("SDK level too old");
8871         }
8872         // Permission check.
8873         int uid = Binder.getCallingUid();
8874         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8875             throw new SecurityException(
8876                     "Caller does not have MANAGE_WIFI_NETWORK_SELECTION permission");
8877         }
8878         // Argument check.
8879         Objects.requireNonNull(listener, "listener cannot be null");
8880         if (mVerboseLoggingEnabled) {
8881             mLog.info("getSupportedSimultaneousBandCombinations:  Uid=% Package Name=%").c(
8882                     Binder.getCallingUid()).c(getPackageName(extras)).flush();
8883         }
8884         // Get supported band combinations from chip.
8885         mWifiThreadRunner.post(() -> {
8886             try {
8887                 Set<List<Integer>> bandsSet = mWifiNative.getSupportedBandCombinations(
8888                         mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName());
8889                 if (bandsSet == null) {
8890                     listener.onResult(new WifiBands[0]);
8891                     return;
8892                 }
8893                 WifiBands[] supportedBands = new WifiBands[bandsSet.size()];
8894                 int i = 0;
8895                 for (List<Integer> bands : bandsSet) {
8896                     supportedBands[i] = new WifiBands();
8897                     supportedBands[i].bands = bands.stream().mapToInt(
8898                             Integer::intValue).toArray();
8899                     i++;
8900                 }
8901                 listener.onResult(supportedBands);
8902             } catch (RemoteException e) {
8903                 Log.e(TAG, e.getMessage(), e);
8904             }
8905         }, TAG + "#getSupportedSimultaneousBandCombinations");
8906     }
8907 
8908     /**
8909      * Set the mock wifi service for testing
8910      */
8911     public void setMockWifiService(String serviceName) {
8912         int uid = Binder.getCallingUid();
8913         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
8914             throw new SecurityException(TAG + " Uid " + uid
8915                     + " Missing NETWORK_SETTINGS permission");
8916         }
8917         mWifiNative.setMockWifiService(serviceName);
8918     }
8919 
8920     /**
8921      * Set the mock wifi methods for testing
8922      */
8923     public boolean setMockWifiMethods(String methods) {
8924         int uid = Binder.getCallingUid();
8925         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
8926             throw new SecurityException(TAG + " Uid " + uid
8927                     + " Missing NETWORK_SETTINGS permission");
8928         }
8929         return mWifiNative.setMockWifiMethods(methods);
8930     }
8931 
8932     /**
8933      * See {@link WifiManager#setWepAllowed(boolean)}.
8934      */
8935     @Override
8936     public void setWepAllowed(boolean isAllowed) {
8937         int callingUid = Binder.getCallingUid();
8938         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
8939             throw new SecurityException("Uid " + callingUid
8940                     + " is not allowed to set wifi web allowed by user");
8941         }
8942         mLog.info("setWepAllowed=% uid=%").c(isAllowed).c(callingUid).flush();
8943         mSettingsConfigStore.put(WIFI_WEP_ALLOWED, isAllowed);
8944     }
8945 
8946     /**
8947      * @deprecated Use mWepNetworkUsageController.handleWepAllowedChanged() instead.
8948      */
8949     private void handleWepAllowedChanged(boolean isAllowed) {
8950         mWifiGlobals.setWepAllowed(isAllowed);
8951         if (!isAllowed) {
8952             for (ClientModeManager clientModeManager
8953                     : mActiveModeWarden.getClientModeManagers()) {
8954                 if (!(clientModeManager instanceof ConcreteClientModeManager)) {
8955                     continue;
8956                 }
8957                 ConcreteClientModeManager cmm = (ConcreteClientModeManager) clientModeManager;
8958                 WifiInfo info = cmm.getConnectionInfo();
8959                 if (info != null
8960                         && info.getCurrentSecurityType() == WifiInfo.SECURITY_TYPE_WEP) {
8961                     clientModeManager.disconnect();
8962                 }
8963             }
8964         }
8965     }
8966 
8967     /**
8968      * See {@link WifiManager#queryWepAllowed(Executor, Consumer)}
8969      */
8970     @Override
8971     public void queryWepAllowed(@NonNull IBooleanListener listener) {
8972         if (listener == null) {
8973             throw new IllegalArgumentException("listener should not be null");
8974         }
8975         int callingUid = Binder.getCallingUid();
8976         if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(callingUid)) {
8977             throw new SecurityException("Uid " + callingUid
8978                     + " is not allowed to get wifi web allowed by user");
8979         }
8980         mWifiThreadRunner.post(() -> {
8981             try {
8982                 listener.onResult(mSettingsConfigStore.get(WIFI_WEP_ALLOWED));
8983             } catch (RemoteException e) {
8984                 Log.e(TAG, e.getMessage(), e);
8985             }
8986         }, TAG + "#setWepAllowed");
8987     }
8988 
8989     /**
8990      * See {@link WifiManager#enableMscs(MscsParams)}
8991      */
8992     @Override
8993     public void enableMscs(@NonNull MscsParams mscsParams) {
8994         int uid = Binder.getCallingUid();
8995         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
8996             throw new SecurityException(
8997                     "UID=" + uid + " is not allowed to set network selection config");
8998         }
8999         Objects.requireNonNull(mscsParams);
9000         mWifiThreadRunner.post(() -> {
9001             List<ClientModeManager> clientModeManagers =
9002                     mActiveModeWarden.getInternetConnectivityClientModeManagers();
9003             for (ClientModeManager cmm : clientModeManagers) {
9004                 mWifiNative.enableMscs(mscsParams, cmm.getInterfaceName());
9005             }
9006         }, TAG + "#enableMscs");
9007     }
9008 
9009     /**
9010      * See {@link WifiManager#disableMscs()}
9011      */
9012     @Override
9013     public void disableMscs() {
9014         int uid = Binder.getCallingUid();
9015         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
9016             throw new SecurityException(
9017                     "UID=" + uid + " is not allowed to set network selection config");
9018         }
9019         mWifiThreadRunner.post(() -> {
9020             List<ClientModeManager> clientModeManagers =
9021                     mActiveModeWarden.getInternetConnectivityClientModeManagers();
9022             for (ClientModeManager cmm : clientModeManagers) {
9023                 mWifiNative.disableMscs(cmm.getInterfaceName());
9024             }
9025         }, TAG + "#disableMscs");
9026     }
9027 
9028     /**
9029      * See {@link android.net.wifi.WifiManager#setSendDhcpHostnameRestriction(int)}.
9030      */
9031     public void setSendDhcpHostnameRestriction(@NonNull String packageName,
9032             @WifiManager.SendDhcpHostnameRestriction int restriction) {
9033         int callingUid = Binder.getCallingUid();
9034         int callingPid = Binder.getCallingPid();
9035         if (mVerboseLoggingEnabled) {
9036             mLog.info("setSendDhcpHostnameRestriction:% uid=% package=%").c(restriction)
9037                     .c(callingUid).c(packageName).flush();
9038         }
9039         if ((restriction
9040                 & ~WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_OPEN
9041                 & ~WifiManager.FLAG_SEND_DHCP_HOSTNAME_RESTRICTION_SECURE) != 0) {
9042             throw new IllegalArgumentException("Unknown dhcp hostname restriction flags: "
9043                     + restriction);
9044         }
9045         if (!isSettingsOrSuw(callingPid, callingUid)
9046                 && !mWifiPermissionsUtil.isDeviceOwner(callingUid, packageName)) {
9047             throw new SecurityException("Uid " + callingUid
9048                     + " is not allowed to query the global dhcp hostname restriction");
9049         }
9050         mWifiThreadRunner.post(() -> mWifiGlobals.setSendDhcpHostnameRestriction(restriction),
9051                 TAG + "#setSendDhcpHostnameRestriction");
9052     }
9053 
9054     /**
9055      * See {@link WifiManager#querySendDhcpHostnameRestriction(Executor, IntConsumer)}
9056      */
9057     @Override
9058     public void querySendDhcpHostnameRestriction(@NonNull String packageName,
9059             @NonNull IIntegerListener listener) {
9060         if (listener == null) {
9061             throw new IllegalArgumentException("listener should not be null");
9062         }
9063         int callingUid = Binder.getCallingUid();
9064         int callingPid = Binder.getCallingPid();
9065         if (mVerboseLoggingEnabled) {
9066             mLog.info("querySendDhcpHostnameRestriction: uid=% package=%")
9067                     .c(callingUid).c(packageName).flush();
9068         }
9069         if (!isSettingsOrSuw(callingPid, callingUid)
9070                 && !mWifiPermissionsUtil.isDeviceOwner(callingUid, packageName)) {
9071             throw new SecurityException("Uid " + callingUid
9072                     + " is not allowed to query the global dhcp hostname restriction");
9073         }
9074         mWifiThreadRunner.post(() -> {
9075             try {
9076                 listener.onResult(mWifiGlobals.getSendDhcpHostnameRestriction());
9077             } catch (RemoteException e) {
9078                 Log.e(TAG, e.getMessage(), e);
9079             }
9080         }, TAG + "#querySendDhcpHostnameRestriction");
9081     }
9082 
9083     /**
9084      * See {@link WifiManager#setPerSsidRoamingMode(WifiSsid, int)}
9085      */
9086     @Override
9087     public void setPerSsidRoamingMode(WifiSsid ssid, @RoamingMode int roamingMode,
9088             @NonNull String packageName) {
9089         if (!SdkLevel.isAtLeastV()) {
9090             throw new UnsupportedOperationException("SDK level too old");
9091         }
9092         if (!isAggressiveRoamingModeSupported() && roamingMode == ROAMING_MODE_AGGRESSIVE) {
9093             throw new UnsupportedOperationException("Aggressive roaming mode not supported");
9094         }
9095         Objects.requireNonNull(ssid, "ssid cannot be null");
9096         Objects.requireNonNull(packageName, "packageName cannot be null");
9097 
9098         if (roamingMode < WifiManager.ROAMING_MODE_NONE
9099                 || roamingMode > WifiManager.ROAMING_MODE_AGGRESSIVE) {
9100             throw new IllegalArgumentException("invalid roaming mode: " + roamingMode);
9101         }
9102 
9103         int uid = Binder.getCallingUid();
9104         mWifiPermissionsUtil.checkPackage(uid, packageName);
9105         boolean isDeviceOwner = mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin(
9106                 uid, packageName);
9107         if (!isDeviceOwner && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
9108                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
9109             throw new SecurityException("Uid=" + uid + " is not allowed to add roaming policies");
9110         }
9111 
9112         //Store Roaming Mode per ssid
9113         mWifiThreadRunner.post(() -> {
9114             mWifiInjector.getWifiRoamingModeManager().setPerSsidRoamingMode(ssid,
9115                     roamingMode, isDeviceOwner);
9116         }, TAG + "#setPerSsidRoamingMode");
9117     }
9118 
9119     /**
9120      * See {@link WifiManager#removePerSsidRoamingMode(WifiSsid)}
9121      */
9122     @Override
9123     public void removePerSsidRoamingMode(WifiSsid ssid, @NonNull String packageName) {
9124         if (!SdkLevel.isAtLeastV()) {
9125             throw new UnsupportedOperationException("SDK level too old");
9126         }
9127         Objects.requireNonNull(ssid, "ssid cannot be null");
9128         Objects.requireNonNull(packageName, "packageName cannot be null");
9129 
9130         int uid = Binder.getCallingUid();
9131         mWifiPermissionsUtil.checkPackage(uid, packageName);
9132         boolean isDeviceOwner = mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin(
9133                 uid, packageName);
9134         if (!isDeviceOwner && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
9135                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
9136             throw new SecurityException("Uid=" + uid + " is not allowed "
9137                     + "to remove roaming policies");
9138         }
9139 
9140         // Remove Roaming Mode per ssid
9141         mWifiThreadRunner.post(() -> {
9142             mWifiInjector.getWifiRoamingModeManager().removePerSsidRoamingMode(
9143                     ssid, isDeviceOwner);
9144         }, TAG + "#removePerSsidRoamingMode");
9145     }
9146 
9147     /**
9148      * See {@link WifiManager#getPerSsidRoamingModes(Executor, Consumer)}
9149      */
9150     @Override
9151     public void getPerSsidRoamingModes(@NonNull String packageName,
9152             @NonNull IMapListener listener) {
9153         if (!SdkLevel.isAtLeastV()) {
9154             throw new UnsupportedOperationException("SDK level too old");
9155         }
9156         Objects.requireNonNull(packageName, "packageName cannot be null");
9157         Objects.requireNonNull(listener, "listener cannot be null");
9158 
9159         int uid = Binder.getCallingUid();
9160         boolean isDeviceOwner = mWifiPermissionsUtil.isOrganizationOwnedDeviceAdmin(
9161                 uid, packageName);
9162         mWifiPermissionsUtil.checkPackage(uid, packageName);
9163         if (!isDeviceOwner && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)
9164                 && !mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
9165             throw new SecurityException("Uid=" + uid + " is not allowed to get roaming policies");
9166         }
9167 
9168         // Get Roaming Modes per ssid
9169         mWifiThreadRunner.post(() -> {
9170             try {
9171                 Map<String, Integer> roamingPolicies =
9172                         mWifiInjector.getWifiRoamingModeManager().getPerSsidRoamingModes(
9173                                 isDeviceOwner);
9174                 listener.onResult(roamingPolicies);
9175             } catch (RemoteException e) {
9176                 Log.e(TAG, e.getMessage(), e);
9177             }
9178         }, TAG + "#getPerSsidRoamingModes");
9179     }
9180 
9181     /**
9182      * See {@link WifiManager#getTwtCapabilities(Executor, Consumer)}
9183      */
9184     @Override
9185     public void getTwtCapabilities(ITwtCapabilitiesListener listener, Bundle extras) {
9186         if (!SdkLevel.isAtLeastV()) {
9187             throw new UnsupportedOperationException("SDK level too old");
9188         }
9189         enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION);
9190         if (mVerboseLoggingEnabled) {
9191             mLog.info("getTwtCapabilities:  Uid=% Package Name=%").c(Binder.getCallingUid()).c(
9192                     getPackageName(extras)).flush();
9193         }
9194         if (listener == null) {
9195             throw new IllegalArgumentException("listener should not be null");
9196         }
9197         mWifiThreadRunner.post(() -> {
9198             mTwtManager.getTwtCapabilities(
9199                     mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(), listener);
9200         }, TAG + "#getTwtCapabilities");
9201     }
9202 
9203     /**
9204      * See {@link WifiManager#setupTwtSession(TwtRequest, Executor, TwtSessionCallback)}
9205      */
9206     @Override
9207     public void setupTwtSession(TwtRequest twtRequest, ITwtCallback iTwtCallback, Bundle extras) {
9208         if (!SdkLevel.isAtLeastV()) {
9209             throw new UnsupportedOperationException("SDK level too old");
9210         }
9211         if (iTwtCallback == null) {
9212             throw new IllegalArgumentException("Callback should not be null");
9213         }
9214         if (twtRequest == null) {
9215             throw new IllegalArgumentException("twtRequest should not be null");
9216         }
9217         enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION);
9218         int callingUid = Binder.getCallingUid();
9219         if (mVerboseLoggingEnabled) {
9220             mLog.info("setupTwtSession:  Uid=% Package Name=%").c(callingUid).c(
9221                     getPackageName(extras)).flush();
9222         }
9223         mWifiThreadRunner.post(() -> {
9224             try {
9225                 String bssid = mActiveModeWarden.getPrimaryClientModeManager().getConnectedBssid();
9226                 if (!mActiveModeWarden.getPrimaryClientModeManager().isConnected()
9227                         || bssid == null) {
9228                     iTwtCallback.onFailure(TwtSessionCallback.TWT_ERROR_CODE_NOT_AVAILABLE);
9229                     return;
9230                 }
9231                 mTwtManager.setupTwtSession(
9232                         mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
9233                         twtRequest, iTwtCallback, callingUid, bssid);
9234             } catch (RemoteException e) {
9235                 Log.e(TAG, e.getMessage(), e);
9236             }
9237         }, TAG + "#setupTwtSession");
9238     }
9239 
9240     /**
9241     /**
9242      * See {@link TwtSession#getStats(Executor, Consumer)}}
9243      */
9244     @Override
9245     public void getStatsTwtSession(int sessionId, ITwtStatsListener iTwtStatsListener,
9246             Bundle extras) {
9247         if (!SdkLevel.isAtLeastV()) {
9248             throw new UnsupportedOperationException("SDK level too old");
9249         }
9250         if (iTwtStatsListener == null) {
9251             throw new IllegalArgumentException("Callback should not be null");
9252         }
9253         enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION);
9254         if (mVerboseLoggingEnabled) {
9255             mLog.info("getStatsTwtSession:  Uid=% Package Name=%").c(Binder.getCallingUid()).c(
9256                     getPackageName(extras)).flush();
9257         }
9258         mWifiThreadRunner.post(() -> {
9259             mTwtManager.getStatsTwtSession(
9260                     mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
9261                     iTwtStatsListener, sessionId);
9262         }, TAG + "#getStatsTwtSession");
9263     }
9264 
9265     /**
9266      * See {@link TwtSession#teardown()}
9267      */
9268     @Override
9269     public void teardownTwtSession(int sessionId, Bundle extras) {
9270         if (!SdkLevel.isAtLeastV()) {
9271             throw new UnsupportedOperationException("SDK level too old");
9272         }
9273         enforceAnyPermissionOf(android.Manifest.permission.MANAGE_WIFI_NETWORK_SELECTION);
9274         if (mVerboseLoggingEnabled) {
9275             mLog.info("teardownTwtSession:  Uid=% Package Name=%").c(Binder.getCallingUid()).c(
9276                     getPackageName(extras)).flush();
9277         }
9278         mWifiThreadRunner.post(() -> {
9279             mTwtManager.tearDownTwtSession(
9280                     mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(), sessionId);
9281         }, TAG + "#teardownTwtSession");
9282     }
9283 
9284     /**
9285      * See {@link WifiManager#setD2dAllowedWhenInfraStaDisabled(boolean)}.
9286      */
9287     @Override
9288     public void setD2dAllowedWhenInfraStaDisabled(boolean isAllowed) {
9289         int callingUid = Binder.getCallingUid();
9290         if (!isSettingsOrSuw(Binder.getCallingPid(), callingUid)) {
9291             throw new SecurityException("Uid " + callingUid
9292                     + " is not allowed to set d2d allowed when infra Sta is disabled");
9293         }
9294         mLog.info("setD2dAllowedWhenInfraStaDisabled=% uid=%").c(isAllowed).c(callingUid).flush();
9295         mWifiThreadRunner.post(
9296                 () -> mSettingsConfigStore.put(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED, isAllowed),
9297                 TAG + "#setD2dAllowedWhenInfraStaDisabled");
9298     }
9299 
9300     /**
9301      * See {@link WifiManager#queryD2dAllowedWhenInfraStaDisabled(Executor, Consumer)}
9302      */
9303     @Override
9304     public void queryD2dAllowedWhenInfraStaDisabled(@NonNull IBooleanListener listener) {
9305         if (listener == null) {
9306             throw new IllegalArgumentException("listener should not be null");
9307         }
9308         mWifiThreadRunner.post(() -> {
9309             try {
9310                 listener.onResult(mSettingsConfigStore.get(D2D_ALLOWED_WHEN_INFRA_STA_DISABLED));
9311             } catch (RemoteException e) {
9312                 Log.e(TAG, e.getMessage(), e);
9313             }
9314         }, TAG + "#queryD2dAllowedWhenInfraStaDisabled");
9315     }
9316 
9317     /**
9318      * See {@link WifiManager#setAutojoinDisallowedSecurityTypes(int)}
9319      * @param restrictions The autojoin restriction security types to be set.
9320      * @throws SecurityException if the caller does not have permission.
9321      * @throws IllegalArgumentException if the arguments are null or invalid
9322      */
9323     @Override
9324     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
9325     public void setAutojoinDisallowedSecurityTypes(int restrictions, @NonNull Bundle extras) {
9326         // SDK check.
9327         if (!SdkLevel.isAtLeastT()) {
9328             throw new UnsupportedOperationException("SDK level too old");
9329         }
9330         // Check null argument
9331         if (extras == null) {
9332             throw new IllegalArgumentException("extras cannot be null");
9333         }
9334         // Check invalid argument
9335         if ((restrictions & (0x1 << WifiInfo.SECURITY_TYPE_OPEN)) == 0
9336                 && (restrictions & (0x1 << WifiInfo.SECURITY_TYPE_OWE)) != 0) {
9337             throw new IllegalArgumentException("Restricting OWE but not OPEN is not allowed");
9338         }
9339         if ((restrictions & (0x1 << WifiInfo.SECURITY_TYPE_PSK)) == 0
9340                 && (restrictions & (0x1 << WifiInfo.SECURITY_TYPE_SAE)) != 0) {
9341             throw new IllegalArgumentException("Restricting SAE but not PSK is not allowed");
9342         }
9343         if ((restrictions & (0x1 << WifiInfo.SECURITY_TYPE_EAP)) == 0
9344                 && (restrictions & (0x1 << WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE)) != 0) {
9345             throw new IllegalArgumentException(
9346                     "Restricting EAP_WPA3_ENTERPRISE but not EAP is not allowed");
9347         }
9348         // Permission check.
9349         int uid = Binder.getCallingUid();
9350         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)
9351                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
9352             throw new SecurityException(
9353                     "Uid=" + uid + " is not allowed to set AutoJoinRestrictionSecurityTypes");
9354         }
9355         if (mVerboseLoggingEnabled) {
9356             mLog.info("setAutojoinDisallowedSecurityTypes uid=% Package Name=% restrictions=%")
9357                     .c(uid).c(getPackageName(extras)).c(restrictions).flush();
9358         }
9359         mWifiThreadRunner.post(() -> {
9360             mWifiConnectivityManager.setAutojoinDisallowedSecurityTypes(restrictions);
9361         }, TAG + "#setAutojoinDisallowedSecurityTypes");
9362     }
9363 
9364     /**
9365      * See {@link WifiManager#getAutojoinDisallowedSecurityTypes(Executor, Consumer)}
9366      */
9367     @Override
9368     @RequiresApi(Build.VERSION_CODES.TIRAMISU)
9369     public void getAutojoinDisallowedSecurityTypes(@NonNull IIntegerListener listener,
9370             @NonNull Bundle extras) {
9371         // SDK check.
9372         if (!SdkLevel.isAtLeastT()) {
9373             throw new UnsupportedOperationException("SDK level too old");
9374         }
9375         // Argument check
9376         if (listener == null) {
9377             throw new IllegalArgumentException("listener cannot be null");
9378         }
9379         if (extras == null) {
9380             throw new IllegalArgumentException("extras cannot be null");
9381         }
9382         // Permission check.
9383         int uid = Binder.getCallingUid();
9384         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)
9385                 && !mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
9386             throw new SecurityException(
9387                     "Uid=" + uid + " is not allowed to get AutoJoinRestrictionSecurityTypes");
9388         }
9389         if (mVerboseLoggingEnabled) {
9390             mLog.info("getAutojoinDisallowedSecurityTypes:  Uid=% Package Name=%").c(
9391                     Binder.getCallingUid()).c(getPackageName(extras)).flush();
9392         }
9393 
9394         mWifiThreadRunner.post(() -> {
9395             try {
9396                 listener.onResult(mWifiConnectivityManager.getAutojoinDisallowedSecurityTypes());
9397             } catch (RemoteException e) {
9398                 Log.e(TAG, e.getMessage(), e);
9399             }
9400         }, TAG + "#getAutojoinDisallowedSecurityTypes");
9401     }
9402 
9403     @Override
9404     public void disallowCurrentSuggestedNetwork(@NonNull BlockingOption option,
9405             @NonNull String packageName) {
9406         Objects.requireNonNull(option, "blockingOption cannot be null");
9407         int callingUid = Binder.getCallingUid();
9408         mWifiPermissionsUtil.checkPackage(callingUid, packageName);
9409         if (enforceChangePermission(packageName) != MODE_ALLOWED) {
9410             throw new SecurityException("Caller does not hold CHANGE_WIFI_STATE permission");
9411         }
9412         if (mVerboseLoggingEnabled) {
9413             mLog.info("disallowCurrentSuggestedNetwork:  Uid=% Package Name=%").c(
9414                     callingUid).c(option.toString()).flush();
9415         }
9416         if (mActiveModeWarden.getWifiState() != WIFI_STATE_ENABLED) {
9417             return;
9418         }
9419         WifiInfo info = mActiveModeWarden.getConnectionInfo();
9420         if (!packageName.equals(info.getRequestingPackageName())) {
9421             return;
9422         }
9423         mWifiThreadRunner.post(
9424                 () -> mActiveModeWarden.getPrimaryClientModeManager().blockNetwork(option),
9425                 "disallowCurrentSuggestedNetwork");
9426     }
9427 
9428     /**
9429      * See {@link WifiManager#isUsdSubscriberSupported()}
9430      */
9431     @Override
9432     public boolean isUsdSubscriberSupported() {
9433         if (!Environment.isSdkAtLeastB()) {
9434             throw new UnsupportedOperationException("SDK level too old");
9435         }
9436         int uid = getMockableCallingUid();
9437         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
9438             throw new SecurityException("App not allowed to use USD (uid = " + uid + ")");
9439         }
9440         if (!mIsUsdSupported) {
9441             return false;
9442         }
9443         return mWifiNative.isUsdSubscriberSupported();
9444     }
9445 
9446     /**
9447      * See {@link WifiManager#isUsdPublisherSupported()}
9448      */
9449     @Override
9450     public boolean isUsdPublisherSupported() {
9451         if (!Environment.isSdkAtLeastB()) {
9452             throw new UnsupportedOperationException("SDK level too old");
9453         }
9454         int uid = getMockableCallingUid();
9455         if (!mWifiPermissionsUtil.checkManageWifiNetworkSelectionPermission(uid)) {
9456             throw new SecurityException("App not allowed to use USD (uid = " + uid + ")");
9457         }
9458         if (!mIsUsdSupported) {
9459             return false;
9460         }
9461         return mWifiNative.isUsdPublisherSupported();
9462     }
9463 }
9464