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