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