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