1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 21 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC; 22 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL; 23 import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL; 24 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 25 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 26 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; 27 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING; 28 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 29 30 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED; 31 32 import android.annotation.CheckResult; 33 import android.annotation.NonNull; 34 import android.annotation.Nullable; 35 import android.app.AppOpsManager; 36 import android.bluetooth.BluetoothAdapter; 37 import android.content.BroadcastReceiver; 38 import android.content.ComponentName; 39 import android.content.Context; 40 import android.content.Intent; 41 import android.content.IntentFilter; 42 import android.content.pm.ApplicationInfo; 43 import android.content.pm.PackageInfo; 44 import android.content.pm.PackageManager; 45 import android.content.pm.ParceledListSlice; 46 import android.content.pm.ResolveInfo; 47 import android.net.DhcpInfo; 48 import android.net.DhcpResultsParcelable; 49 import android.net.InetAddresses; 50 import android.net.Network; 51 import android.net.NetworkStack; 52 import android.net.Uri; 53 import android.net.ip.IpClientUtil; 54 import android.net.wifi.IActionListener; 55 import android.net.wifi.IDppCallback; 56 import android.net.wifi.ILocalOnlyHotspotCallback; 57 import android.net.wifi.INetworkRequestMatchCallback; 58 import android.net.wifi.IOnWifiActivityEnergyInfoListener; 59 import android.net.wifi.IOnWifiUsabilityStatsListener; 60 import android.net.wifi.IScanResultsCallback; 61 import android.net.wifi.ISoftApCallback; 62 import android.net.wifi.ISuggestionConnectionStatusListener; 63 import android.net.wifi.ITrafficStateCallback; 64 import android.net.wifi.IWifiConnectedNetworkScorer; 65 import android.net.wifi.ScanResult; 66 import android.net.wifi.SoftApCapability; 67 import android.net.wifi.SoftApConfiguration; 68 import android.net.wifi.SoftApInfo; 69 import android.net.wifi.WifiAnnotations.WifiStandard; 70 import android.net.wifi.WifiClient; 71 import android.net.wifi.WifiConfiguration; 72 import android.net.wifi.WifiInfo; 73 import android.net.wifi.WifiManager; 74 import android.net.wifi.WifiManager.DeviceMobilityState; 75 import android.net.wifi.WifiManager.LocalOnlyHotspotCallback; 76 import android.net.wifi.WifiManager.SuggestionConnectionStatusListener; 77 import android.net.wifi.WifiNetworkSuggestion; 78 import android.net.wifi.WifiScanner; 79 import android.net.wifi.WifiSsid; 80 import android.net.wifi.hotspot2.IProvisioningCallback; 81 import android.net.wifi.hotspot2.OsuProvider; 82 import android.net.wifi.hotspot2.PasspointConfiguration; 83 import android.os.AsyncTask; 84 import android.os.Binder; 85 import android.os.Build; 86 import android.os.Handler; 87 import android.os.HandlerExecutor; 88 import android.os.IBinder; 89 import android.os.Looper; 90 import android.os.Message; 91 import android.os.ParcelFileDescriptor; 92 import android.os.PersistableBundle; 93 import android.os.PowerManager; 94 import android.os.Process; 95 import android.os.RemoteException; 96 import android.os.UserHandle; 97 import android.os.UserManager; 98 import android.os.WorkSource; 99 import android.os.connectivity.WifiActivityEnergyInfo; 100 import android.provider.Settings; 101 import android.telephony.CarrierConfigManager; 102 import android.telephony.PhoneStateListener; 103 import android.telephony.SubscriptionManager; 104 import android.telephony.TelephonyManager; 105 import android.text.TextUtils; 106 import android.util.Log; 107 import android.util.MutableBoolean; 108 109 import com.android.internal.annotations.GuardedBy; 110 import com.android.internal.annotations.VisibleForTesting; 111 import com.android.internal.util.AsyncChannel; 112 import com.android.net.module.util.Inet4AddressUtils; 113 import com.android.server.wifi.hotspot2.PasspointManager; 114 import com.android.server.wifi.hotspot2.PasspointProvider; 115 import com.android.server.wifi.proto.nano.WifiMetricsProto.UserActionEvent; 116 import com.android.server.wifi.util.ApConfigUtil; 117 import com.android.server.wifi.util.ExternalCallbackTracker; 118 import com.android.server.wifi.util.RssiUtil; 119 import com.android.server.wifi.util.ScanResultUtil; 120 import com.android.server.wifi.util.WifiHandler; 121 import com.android.server.wifi.util.WifiPermissionsUtil; 122 import com.android.wifi.resources.R; 123 124 import java.io.BufferedReader; 125 import java.io.FileDescriptor; 126 import java.io.FileNotFoundException; 127 import java.io.FileReader; 128 import java.io.IOException; 129 import java.io.PrintWriter; 130 import java.net.Inet4Address; 131 import java.net.InetAddress; 132 import java.security.GeneralSecurityException; 133 import java.security.KeyStore; 134 import java.security.cert.CertPath; 135 import java.security.cert.CertPathValidator; 136 import java.security.cert.CertificateFactory; 137 import java.security.cert.PKIXParameters; 138 import java.security.cert.X509Certificate; 139 import java.util.ArrayList; 140 import java.util.Arrays; 141 import java.util.Collections; 142 import java.util.HashMap; 143 import java.util.Iterator; 144 import java.util.List; 145 import java.util.Map; 146 import java.util.concurrent.CountDownLatch; 147 import java.util.concurrent.Executor; 148 import java.util.concurrent.TimeUnit; 149 150 /** 151 * WifiService handles remote WiFi operation requests by implementing 152 * the IWifiManager interface. 153 */ 154 public class WifiServiceImpl extends BaseWifiService { 155 private static final String TAG = "WifiService"; 156 private static final int APP_INFO_FLAGS_SYSTEM_APP = 157 ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; 158 private static final boolean VDBG = false; 159 160 /** Max wait time for posting blocking runnables */ 161 private static final int RUN_WITH_SCISSORS_TIMEOUT_MILLIS = 4000; 162 163 private final ClientModeImpl mClientModeImpl; 164 private final ActiveModeWarden mActiveModeWarden; 165 private final ScanRequestProxy mScanRequestProxy; 166 167 private final Context mContext; 168 private final FrameworkFacade mFacade; 169 private final Clock mClock; 170 171 private final PowerManager mPowerManager; 172 private final AppOpsManager mAppOps; 173 private final UserManager mUserManager; 174 private final WifiCountryCode mCountryCode; 175 176 /** Polls traffic stats and notifies clients */ 177 private final WifiTrafficPoller mWifiTrafficPoller; 178 /** Tracks the persisted states for wi-fi & airplane mode */ 179 private final WifiSettingsStore mSettingsStore; 180 /** Logs connection events and some general router and scan stats */ 181 private final WifiMetrics mWifiMetrics; 182 183 private final WifiInjector mWifiInjector; 184 /** Backup/Restore Module */ 185 private final WifiBackupRestore mWifiBackupRestore; 186 private final SoftApBackupRestore mSoftApBackupRestore; 187 private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; 188 private final WifiConfigManager mWifiConfigManager; 189 private final PasspointManager mPasspointManager; 190 private final WifiLog mLog; 191 /** 192 * Verbose logging flag. Toggled by developer options. 193 */ 194 private boolean mVerboseLoggingEnabled = false; 195 196 /** 197 * Asynchronous channel to ClientModeImpl 198 */ 199 @VisibleForTesting 200 AsyncChannel mClientModeImplChannel; 201 202 private final FrameworkFacade mFrameworkFacade; 203 204 private final WifiPermissionsUtil mWifiPermissionsUtil; 205 206 private final TetheredSoftApTracker mTetheredSoftApTracker; 207 208 private final LohsSoftApTracker mLohsSoftApTracker; 209 210 private WifiScanner mWifiScanner; 211 212 /** 213 * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death. 214 */ 215 public final class LocalOnlyRequestorCallback 216 implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback { 217 /** 218 * Called with requesting app has died. 219 */ 220 @Override onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor)221 public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) { 222 mLog.trace("onLocalOnlyHotspotRequestorDeath pid=%") 223 .c(requestor.getPid()).flush(); 224 mLohsSoftApTracker.stopByRequest(requestor); 225 } 226 } 227 228 /** 229 * Handles interaction with ClientModeImpl 230 */ 231 private class ClientModeImplHandler extends WifiHandler { 232 private AsyncChannel mCmiChannel; 233 ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel)234 ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel) { 235 super(tag, looper); 236 mCmiChannel = asyncChannel; 237 mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler()); 238 } 239 240 @Override handleMessage(Message msg)241 public void handleMessage(Message msg) { 242 super.handleMessage(msg); 243 switch (msg.what) { 244 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 245 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 246 mClientModeImplChannel = mCmiChannel; 247 } else { 248 Log.e(TAG, "ClientModeImpl connection failure, error=" + msg.arg1); 249 mClientModeImplChannel = null; 250 } 251 break; 252 } 253 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 254 Log.e(TAG, "ClientModeImpl channel lost, msg.arg1 =" + msg.arg1); 255 mClientModeImplChannel = null; 256 //Re-establish connection to state machine 257 mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler()); 258 break; 259 } 260 default: { 261 Log.d(TAG, "ClientModeImplHandler.handleMessage ignoring msg=" + msg); 262 break; 263 } 264 } 265 } 266 } 267 268 /** 269 * Listen for phone call state events to get active data subcription id. 270 */ 271 private class WifiPhoneStateListener extends PhoneStateListener { WifiPhoneStateListener(Looper looper)272 WifiPhoneStateListener(Looper looper) { 273 super(new HandlerExecutor(new Handler(looper))); 274 } 275 276 @Override onActiveDataSubscriptionIdChanged(int subId)277 public void onActiveDataSubscriptionIdChanged(int subId) { 278 Log.d(TAG, "OBSERVED active data subscription change, subId: " + subId); 279 280 mTetheredSoftApTracker.updateSoftApCapability(subId); 281 mActiveModeWarden.updateSoftApCapability(mTetheredSoftApTracker.getSoftApCapability()); 282 } 283 } 284 285 private final ClientModeImplHandler mClientModeImplHandler; 286 private final WifiLockManager mWifiLockManager; 287 private final WifiMulticastLockManager mWifiMulticastLockManager; 288 private final DppManager mDppManager; 289 private final WifiApConfigStore mWifiApConfigStore; 290 private final WifiThreadRunner mWifiThreadRunner; 291 private final MemoryStoreImpl mMemoryStoreImpl; 292 private final WifiScoreCard mWifiScoreCard; 293 WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel)294 public WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel) { 295 mContext = context; 296 mWifiInjector = wifiInjector; 297 mClock = wifiInjector.getClock(); 298 299 mFacade = mWifiInjector.getFrameworkFacade(); 300 mWifiMetrics = mWifiInjector.getWifiMetrics(); 301 mWifiTrafficPoller = mWifiInjector.getWifiTrafficPoller(); 302 mUserManager = mWifiInjector.getUserManager(); 303 mCountryCode = mWifiInjector.getWifiCountryCode(); 304 mClientModeImpl = mWifiInjector.getClientModeImpl(); 305 mActiveModeWarden = mWifiInjector.getActiveModeWarden(); 306 mScanRequestProxy = mWifiInjector.getScanRequestProxy(); 307 mSettingsStore = mWifiInjector.getWifiSettingsStore(); 308 mPowerManager = mContext.getSystemService(PowerManager.class); 309 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 310 mWifiLockManager = mWifiInjector.getWifiLockManager(); 311 mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager(); 312 mClientModeImplHandler = new ClientModeImplHandler(TAG, 313 mWifiInjector.getAsyncChannelHandlerThread().getLooper(), asyncChannel); 314 mWifiBackupRestore = mWifiInjector.getWifiBackupRestore(); 315 mSoftApBackupRestore = mWifiInjector.getSoftApBackupRestore(); 316 mWifiApConfigStore = mWifiInjector.getWifiApConfigStore(); 317 mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil(); 318 mLog = mWifiInjector.makeLog(TAG); 319 mFrameworkFacade = wifiInjector.getFrameworkFacade(); 320 mTetheredSoftApTracker = new TetheredSoftApTracker(); 321 mActiveModeWarden.registerSoftApCallback(mTetheredSoftApTracker); 322 mLohsSoftApTracker = new LohsSoftApTracker(); 323 mActiveModeWarden.registerLohsCallback(mLohsSoftApTracker); 324 mWifiNetworkSuggestionsManager = mWifiInjector.getWifiNetworkSuggestionsManager(); 325 mDppManager = mWifiInjector.getDppManager(); 326 mWifiThreadRunner = mWifiInjector.getWifiThreadRunner(); 327 mWifiConfigManager = mWifiInjector.getWifiConfigManager(); 328 mPasspointManager = mWifiInjector.getPasspointManager(); 329 mWifiScoreCard = mWifiInjector.getWifiScoreCard(); 330 mMemoryStoreImpl = new MemoryStoreImpl(mContext, mWifiInjector, 331 mWifiScoreCard, mWifiInjector.getWifiHealthMonitor()); 332 } 333 334 /** 335 * Check if we are ready to start wifi. 336 * 337 * First check if we will be restarting system services to decrypt the device. If the device is 338 * not encrypted, check if Wi-Fi needs to be enabled and start if needed 339 * 340 * This function is used only at boot time. 341 */ checkAndStartWifi()342 public void checkAndStartWifi() { 343 mWifiThreadRunner.post(() -> { 344 if (!mWifiConfigManager.loadFromStore()) { 345 Log.e(TAG, "Failed to load from config store"); 346 } 347 // config store is read, check if verbose logging is enabled. 348 enableVerboseLoggingInternal(getVerboseLoggingLevel()); 349 // Check if wi-fi needs to be enabled 350 boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); 351 Log.i(TAG, 352 "WifiService starting up with Wi-Fi " + (wifiEnabled ? "enabled" : "disabled")); 353 354 mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility().initialize(); 355 mContext.registerReceiver( 356 new BroadcastReceiver() { 357 @Override 358 public void onReceive(Context context, Intent intent) { 359 if (mSettingsStore.handleAirplaneModeToggled()) { 360 mActiveModeWarden.airplaneModeToggled(); 361 } 362 } 363 }, 364 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 365 366 mContext.registerReceiver( 367 new BroadcastReceiver() { 368 @Override 369 public void onReceive(Context context, Intent intent) { 370 int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, 371 TelephonyManager.SIM_STATE_UNKNOWN); 372 if (TelephonyManager.SIM_STATE_ABSENT == state) { 373 Log.d(TAG, "resetting networks because SIM was removed"); 374 mClientModeImpl.resetSimAuthNetworks( 375 ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED); 376 } 377 } 378 }, 379 new IntentFilter(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED)); 380 381 mContext.registerReceiver( 382 new BroadcastReceiver() { 383 @Override 384 public void onReceive(Context context, Intent intent) { 385 int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, 386 TelephonyManager.SIM_STATE_UNKNOWN); 387 if (TelephonyManager.SIM_STATE_LOADED == state) { 388 Log.d(TAG, "resetting networks because SIM was loaded"); 389 mClientModeImpl.resetSimAuthNetworks( 390 ClientModeImpl.RESET_SIM_REASON_SIM_INSERTED); 391 } 392 } 393 }, 394 new IntentFilter(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)); 395 396 mContext.registerReceiver( 397 new BroadcastReceiver() { 398 private int mLastSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 399 @Override 400 public void onReceive(Context context, Intent intent) { 401 final int subId = intent.getIntExtra("subscription", 402 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 403 if (subId != mLastSubId) { 404 Log.d(TAG, "resetting networks as default data SIM is changed"); 405 mClientModeImpl.resetSimAuthNetworks( 406 ClientModeImpl.RESET_SIM_REASON_DEFAULT_DATA_SIM_CHANGED); 407 mLastSubId = subId; 408 } 409 } 410 }, 411 new IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); 412 413 // Adding optimizations of only receiving broadcasts when wifi is enabled 414 // can result in race conditions when apps toggle wifi in the background 415 // without active user involvement. Always receive broadcasts. 416 registerForBroadcasts(); 417 mInIdleMode = mPowerManager.isDeviceIdleMode(); 418 419 mClientModeImpl.initialize(); 420 mActiveModeWarden.start(); 421 registerForCarrierConfigChange(); 422 }); 423 } 424 handleBootCompleted()425 public void handleBootCompleted() { 426 mWifiThreadRunner.post(() -> { 427 Log.d(TAG, "Handle boot completed"); 428 429 // Register for system broadcasts. 430 IntentFilter intentFilter = new IntentFilter(); 431 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 432 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 433 intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); 434 intentFilter.addAction(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 435 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 436 intentFilter.addAction(Intent.ACTION_SHUTDOWN); 437 boolean trackEmergencyCallState = mContext.getResources().getBoolean( 438 R.bool.config_wifi_turn_off_during_emergency_call); 439 if (trackEmergencyCallState) { 440 intentFilter.addAction(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED); 441 } 442 mContext.registerReceiver(mReceiver, intentFilter); 443 mMemoryStoreImpl.start(); 444 mPasspointManager.initializeProvisioner( 445 mWifiInjector.getPasspointProvisionerHandlerThread().getLooper()); 446 mClientModeImpl.handleBootCompleted(); 447 }); 448 } 449 handleUserSwitch(int userId)450 public void handleUserSwitch(int userId) { 451 Log.d(TAG, "Handle user switch " + userId); 452 mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserSwitch(userId)); 453 } 454 handleUserUnlock(int userId)455 public void handleUserUnlock(int userId) { 456 Log.d(TAG, "Handle user unlock " + userId); 457 mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserUnlock(userId)); 458 } 459 handleUserStop(int userId)460 public void handleUserStop(int userId) { 461 Log.d(TAG, "Handle user stop " + userId); 462 mWifiThreadRunner.post(() -> mWifiConfigManager.handleUserStop(userId)); 463 } 464 465 /** 466 * See {@link android.net.wifi.WifiManager#startScan} 467 * 468 * @param packageName Package name of the app that requests wifi scan. 469 * @param featureId The feature in the package 470 */ 471 @Override startScan(String packageName, String featureId)472 public boolean startScan(String packageName, String featureId) { 473 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 474 return false; 475 } 476 477 int callingUid = Binder.getCallingUid(); 478 long ident = Binder.clearCallingIdentity(); 479 mLog.info("startScan uid=%").c(callingUid).flush(); 480 synchronized (this) { 481 if (mInIdleMode) { 482 // Need to send an immediate scan result broadcast in case the 483 // caller is waiting for a result .. 484 485 // TODO: investigate if the logic to cancel scans when idle can move to 486 // WifiScanningServiceImpl. This will 1 - clean up WifiServiceImpl and 2 - 487 // avoid plumbing an awkward path to report a cancelled/failed scan. This will 488 // be sent directly until b/31398592 is fixed. 489 sendFailedScanBroadcast(); 490 mScanPending = true; 491 return false; 492 } 493 } 494 try { 495 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid, 496 null); 497 Boolean scanSuccess = mWifiThreadRunner.call(() -> 498 mScanRequestProxy.startScan(callingUid, packageName), null); 499 if (scanSuccess == null) { 500 sendFailedScanBroadcast(); 501 return false; 502 } 503 if (!scanSuccess) { 504 Log.e(TAG, "Failed to start scan"); 505 return false; 506 } 507 } catch (SecurityException e) { 508 Log.e(TAG, "Permission violation - startScan not allowed for" 509 + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e); 510 return false; 511 } finally { 512 Binder.restoreCallingIdentity(ident); 513 } 514 return true; 515 } 516 517 // Send a failed scan broadcast to indicate the current scan request failed. sendFailedScanBroadcast()518 private void sendFailedScanBroadcast() { 519 // clear calling identity to send broadcast 520 long callingIdentity = Binder.clearCallingIdentity(); 521 try { 522 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 523 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 524 intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false); 525 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 526 } finally { 527 // restore calling identity 528 Binder.restoreCallingIdentity(callingIdentity); 529 } 530 531 } 532 533 /** 534 * WPS support in Client mode is deprecated. Return null. 535 */ 536 @Override getCurrentNetworkWpsNfcConfigurationToken()537 public String getCurrentNetworkWpsNfcConfigurationToken() { 538 // while CLs are in flight, return null here, will be removed (b/72423090) 539 enforceNetworkStackPermission(); 540 if (mVerboseLoggingEnabled) { 541 mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%") 542 .c(Binder.getCallingUid()).flush(); 543 } 544 return null; 545 } 546 547 private boolean mInIdleMode; 548 private boolean mScanPending; 549 handleIdleModeChanged()550 private void handleIdleModeChanged() { 551 boolean doScan = false; 552 synchronized (this) { 553 boolean idle = mPowerManager.isDeviceIdleMode(); 554 if (mInIdleMode != idle) { 555 mInIdleMode = idle; 556 if (!idle) { 557 if (mScanPending) { 558 mScanPending = false; 559 doScan = true; 560 } 561 } 562 } 563 } 564 if (doScan) { 565 // Someone requested a scan while we were idle; do a full scan now. 566 // A security check of the caller's identity was made when the request arrived via 567 // Binder. Now we'll pass the current process's identity to startScan(). 568 startScan(mContext.getOpPackageName(), mContext.getAttributionTag()); 569 } 570 } 571 handleShutDown()572 private void handleShutDown() { 573 // Direct call to notify ActiveModeWarden as soon as possible with the assumption that 574 // notifyShuttingDown() doesn't have codes that may cause concurrentModificationException, 575 // e.g., access to a collection. 576 mActiveModeWarden.notifyShuttingDown(); 577 mWifiThreadRunner.post(()-> { 578 // There is no explicit disconnection event in clientModeImpl during shutdown. 579 // Call resetConnectionState() so that connection duration is calculated 580 // before memory store write triggered by mMemoryStoreImpl.stop(). 581 mWifiScoreCard.resetConnectionState(); 582 mMemoryStoreImpl.stop(); 583 }); 584 } 585 checkNetworkSettingsPermission(int pid, int uid)586 private boolean checkNetworkSettingsPermission(int pid, int uid) { 587 return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid) 588 == PERMISSION_GRANTED; 589 } 590 checkNetworkSetupWizardPermission(int pid, int uid)591 private boolean checkNetworkSetupWizardPermission(int pid, int uid) { 592 return mContext.checkPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, pid, uid) 593 == PackageManager.PERMISSION_GRANTED; 594 } 595 checkNetworkStackPermission(int pid, int uid)596 private boolean checkNetworkStackPermission(int pid, int uid) { 597 return mContext.checkPermission(android.Manifest.permission.NETWORK_STACK, pid, uid) 598 == PackageManager.PERMISSION_GRANTED; 599 } 600 checkNetworkManagedProvisioningPermission(int pid, int uid)601 private boolean checkNetworkManagedProvisioningPermission(int pid, int uid) { 602 return mContext.checkPermission(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING, 603 pid, uid) == PackageManager.PERMISSION_GRANTED; 604 } 605 606 /** 607 * Helper method to check if the entity initiating the binder call has any of the signature only 608 * permissions. 609 */ isPrivileged(int pid, int uid)610 private boolean isPrivileged(int pid, int uid) { 611 return checkNetworkSettingsPermission(pid, uid) 612 || checkNetworkSetupWizardPermission(pid, uid) 613 || checkNetworkStackPermission(pid, uid) 614 || checkNetworkManagedProvisioningPermission(pid, uid); 615 } 616 617 /** 618 * Helper method to check if the entity initiating the binder call has setup wizard or settings 619 * permissions. 620 */ isSettingsOrSuw(int pid, int uid)621 private boolean isSettingsOrSuw(int pid, int uid) { 622 return checkNetworkSettingsPermission(pid, uid) 623 || checkNetworkSetupWizardPermission(pid, uid); 624 } 625 626 /** Helper method to check if the entity initiating the binder call is a system app. */ isSystem(String packageName, int uid)627 private boolean isSystem(String packageName, int uid) { 628 long ident = Binder.clearCallingIdentity(); 629 try { 630 ApplicationInfo info = mContext.getPackageManager().getApplicationInfoAsUser( 631 packageName, 0, UserHandle.getUserHandleForUid(uid)); 632 return (info.flags & APP_INFO_FLAGS_SYSTEM_APP) != 0; 633 } catch (PackageManager.NameNotFoundException e) { 634 // In case of exception, assume unknown app (more strict checking) 635 // Note: This case will never happen since checkPackage is 636 // called to verify validity before checking App's version. 637 } finally { 638 Binder.restoreCallingIdentity(ident); 639 } 640 return false; 641 } 642 643 /** Helper method to check if the entity initiating the binder call is a DO/PO app. */ isDeviceOrProfileOwner(int uid, String packageName)644 private boolean isDeviceOrProfileOwner(int uid, String packageName) { 645 return mWifiPermissionsUtil.isDeviceOwner(uid, packageName) 646 || mWifiPermissionsUtil.isProfileOwner(uid, packageName); 647 } 648 enforceNetworkSettingsPermission()649 private void enforceNetworkSettingsPermission() { 650 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS, 651 "WifiService"); 652 } 653 checkAnyPermissionOf(String... permissions)654 private boolean checkAnyPermissionOf(String... permissions) { 655 for (String permission : permissions) { 656 if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { 657 return true; 658 } 659 } 660 return false; 661 } 662 enforceAnyPermissionOf(String... permissions)663 private void enforceAnyPermissionOf(String... permissions) { 664 if (!checkAnyPermissionOf(permissions)) { 665 throw new SecurityException("Requires one of the following permissions: " 666 + String.join(", ", permissions) + "."); 667 } 668 } 669 enforceNetworkStackOrSettingsPermission()670 private void enforceNetworkStackOrSettingsPermission() { 671 enforceAnyPermissionOf( 672 android.Manifest.permission.NETWORK_SETTINGS, 673 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); 674 } 675 enforceNetworkStackPermission()676 private void enforceNetworkStackPermission() { 677 // TODO(b/142554155): Only check for MAINLINE_NETWORK_STACK permission 678 boolean granted = mContext.checkCallingOrSelfPermission( 679 android.Manifest.permission.NETWORK_STACK) 680 == PackageManager.PERMISSION_GRANTED; 681 if (granted) { 682 return; 683 } 684 mContext.enforceCallingOrSelfPermission( 685 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "WifiService"); 686 } 687 enforceAccessPermission()688 private void enforceAccessPermission() { 689 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 690 "WifiService"); 691 } 692 693 /** 694 * Checks whether the caller can change the wifi state. 695 * Possible results: 696 * 1. Operation is allowed. No exception thrown, and AppOpsManager.MODE_ALLOWED returned. 697 * 2. Operation is not allowed, and caller must be told about this. SecurityException is thrown. 698 * 3. Operation is not allowed, and caller must not be told about this (i.e. must silently 699 * ignore the operation). No exception is thrown, and AppOpsManager.MODE_IGNORED returned. 700 */ 701 @CheckResult enforceChangePermission(String callingPackage)702 private int enforceChangePermission(String callingPackage) { 703 mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); 704 if (checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())) { 705 return MODE_ALLOWED; 706 } 707 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 708 "WifiService"); 709 710 return mAppOps.noteOp( 711 AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Binder.getCallingUid(), callingPackage); 712 } 713 enforceReadCredentialPermission()714 private void enforceReadCredentialPermission() { 715 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL, 716 "WifiService"); 717 } 718 enforceMulticastChangePermission()719 private void enforceMulticastChangePermission() { 720 mContext.enforceCallingOrSelfPermission( 721 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 722 "WifiService"); 723 } 724 enforceConnectivityInternalPermission()725 private void enforceConnectivityInternalPermission() { 726 mContext.enforceCallingOrSelfPermission( 727 android.Manifest.permission.CONNECTIVITY_INTERNAL, 728 "ConnectivityService"); 729 } 730 enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)731 private void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) { 732 mWifiPermissionsUtil.enforceLocationPermission(pkgName, featureId, uid); 733 } 734 735 /** 736 * Helper method to check if the app is allowed to access public API's deprecated in 737 * {@link Build.VERSION_CODES#Q}. 738 * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name. 739 */ isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid)740 private boolean isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid) { 741 return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q, uid) 742 || isPrivileged(pid, uid) 743 || isDeviceOrProfileOwner(uid, packageName) 744 || isSystem(packageName, uid) 745 // TODO(b/140540984): Remove this bypass. 746 || mWifiPermissionsUtil.checkSystemAlertWindowPermission(uid, packageName); 747 } 748 749 /** 750 * Helper method to check if the app is allowed to access public API's deprecated in 751 * {@link Build.VERSION_CODES#R}. 752 * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name. 753 */ isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid)754 private boolean isTargetSdkLessThanROrPrivileged(String packageName, int pid, int uid) { 755 return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.R, uid) 756 || isPrivileged(pid, uid) 757 || isDeviceOrProfileOwner(uid, packageName) 758 || isSystem(packageName, uid); 759 } 760 761 /** 762 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 763 * @param enable {@code true} to enable, {@code false} to disable. 764 * @return {@code true} if the enable/disable operation was 765 * started or is already in the queue. 766 */ 767 @Override setWifiEnabled(String packageName, boolean enable)768 public synchronized boolean setWifiEnabled(String packageName, boolean enable) { 769 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 770 return false; 771 } 772 boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid()); 773 if (!isPrivileged && !isDeviceOrProfileOwner(Binder.getCallingUid(), packageName) 774 && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q, 775 Binder.getCallingUid()) 776 && !isSystem(packageName, Binder.getCallingUid())) { 777 mLog.info("setWifiEnabled not allowed for uid=%") 778 .c(Binder.getCallingUid()).flush(); 779 return false; 780 } 781 // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi 782 if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) { 783 mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush(); 784 return false; 785 } 786 787 // If SoftAp is enabled, only privileged apps are allowed to toggle wifi 788 if (!isPrivileged && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) { 789 mLog.err("setWifiEnabled with SoftAp enabled: only Settings can toggle wifi").flush(); 790 return false; 791 } 792 793 mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName) 794 .c(Binder.getCallingUid()).c(enable).flush(); 795 long ident = Binder.clearCallingIdentity(); 796 try { 797 if (!mSettingsStore.handleWifiToggled(enable)) { 798 // Nothing to do if wifi cannot be toggled 799 return true; 800 } 801 } finally { 802 Binder.restoreCallingIdentity(ident); 803 } 804 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) { 805 mWifiMetrics.logUserActionEvent(enable ? UserActionEvent.EVENT_TOGGLE_WIFI_ON 806 : UserActionEvent.EVENT_TOGGLE_WIFI_OFF); 807 } 808 mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable); 809 mActiveModeWarden.wifiToggled(); 810 return true; 811 } 812 813 /** 814 * see {@link WifiManager#getWifiState()} 815 * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, 816 * {@link WifiManager#WIFI_STATE_DISABLING}, 817 * {@link WifiManager#WIFI_STATE_ENABLED}, 818 * {@link WifiManager#WIFI_STATE_ENABLING}, 819 * {@link WifiManager#WIFI_STATE_UNKNOWN} 820 */ 821 @Override getWifiEnabledState()822 public int getWifiEnabledState() { 823 enforceAccessPermission(); 824 if (mVerboseLoggingEnabled) { 825 mLog.info("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush(); 826 } 827 return mClientModeImpl.syncGetWifiState(); 828 } 829 830 /** 831 * see {@link WifiManager#getWifiApState()} 832 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 833 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 834 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 835 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 836 * {@link WifiManager#WIFI_AP_STATE_FAILED} 837 */ 838 @Override getWifiApEnabledState()839 public int getWifiApEnabledState() { 840 enforceAccessPermission(); 841 if (mVerboseLoggingEnabled) { 842 mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush(); 843 } 844 return mTetheredSoftApTracker.getState(); 845 } 846 847 /** 848 * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)} 849 * 850 * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED}, 851 * {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY}, 852 * {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR} 853 * 854 * @param ifaceName String name of the updated interface 855 * @param mode new operating mode of the interface 856 * 857 * @throws SecurityException if the caller does not have permission to call update 858 */ 859 @Override updateInterfaceIpState(String ifaceName, int mode)860 public void updateInterfaceIpState(String ifaceName, int mode) { 861 // NETWORK_STACK is a signature only permission. 862 enforceNetworkStackPermission(); 863 mLog.info("updateInterfaceIpState uid=%").c(Binder.getCallingUid()).flush(); 864 865 // hand off the work to our handler thread 866 mWifiThreadRunner.post(() -> mLohsSoftApTracker.updateInterfaceIpState(ifaceName, mode)); 867 } 868 869 /** 870 * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)} 871 * @param wifiConfig SSID, security and channel details as part of WifiConfiguration 872 * @return {@code true} if softap start was triggered 873 * @throws SecurityException if the caller does not have permission to start softap 874 */ 875 @Override startSoftAp(WifiConfiguration wifiConfig)876 public boolean startSoftAp(WifiConfiguration wifiConfig) { 877 // NETWORK_STACK is a signature only permission. 878 enforceNetworkStackPermission(); 879 880 mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush(); 881 882 SoftApConfiguration softApConfig = null; 883 if (wifiConfig != null) { 884 softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig); 885 if (softApConfig == null) { 886 return false; 887 } 888 } 889 890 if (!mTetheredSoftApTracker.setEnablingIfAllowed()) { 891 mLog.err("Tethering is already active.").flush(); 892 return false; 893 } 894 895 if (!mWifiThreadRunner.call( 896 () -> mActiveModeWarden.canRequestMoreSoftApManagers(), false)) { 897 // Take down LOHS if it is up. 898 mLohsSoftApTracker.stopAll(); 899 } 900 901 if (!startSoftApInternal(new SoftApModeConfiguration( 902 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, 903 mTetheredSoftApTracker.getSoftApCapability()))) { 904 mTetheredSoftApTracker.setFailedWhileEnabling(); 905 return false; 906 } 907 908 return true; 909 } 910 validateSoftApBand(int apBand)911 private boolean validateSoftApBand(int apBand) { 912 if (!ApConfigUtil.isBandValid(apBand)) { 913 mLog.err("Invalid SoftAp band. ").flush(); 914 return false; 915 } 916 917 if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_5GHZ) 918 && !is5GhzBandSupportedInternal()) { 919 mLog.err("Can not start softAp with 5GHz band, not supported.").flush(); 920 return false; 921 } 922 923 if (ApConfigUtil.containsBand(apBand, SoftApConfiguration.BAND_6GHZ)) { 924 if (!is6GhzBandSupportedInternal() 925 || !mContext.getResources().getBoolean( 926 R.bool.config_wifiSoftap6ghzSupported)) { 927 mLog.err("Can not start softAp with 6GHz band, not supported.").flush(); 928 return false; 929 } 930 } 931 932 return true; 933 } 934 935 /** 936 * see {@link android.net.wifi.WifiManager#startTetheredHotspot(SoftApConfiguration)} 937 * @param softApConfig SSID, security and channel details as part of SoftApConfiguration 938 * @return {@code true} if softap start was triggered 939 * @throws SecurityException if the caller does not have permission to start softap 940 */ 941 @Override startTetheredHotspot(@ullable SoftApConfiguration softApConfig)942 public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) { 943 // NETWORK_STACK is a signature only permission. 944 enforceNetworkStackPermission(); 945 946 mLog.info("startTetheredHotspot uid=%").c(Binder.getCallingUid()).flush(); 947 948 if (!mTetheredSoftApTracker.setEnablingIfAllowed()) { 949 mLog.err("Tethering is already active.").flush(); 950 return false; 951 } 952 953 if (!mWifiThreadRunner.call( 954 () -> mActiveModeWarden.canRequestMoreSoftApManagers(), false)) { 955 // Take down LOHS if it is up. 956 mLohsSoftApTracker.stopAll(); 957 } 958 959 if (!startSoftApInternal(new SoftApModeConfiguration( 960 WifiManager.IFACE_IP_MODE_TETHERED, softApConfig, 961 mTetheredSoftApTracker.getSoftApCapability()))) { 962 mTetheredSoftApTracker.setFailedWhileEnabling(); 963 return false; 964 } 965 966 return true; 967 } 968 969 /** 970 * Internal method to start softap mode. Callers of this method should have already checked 971 * proper permissions beyond the NetworkStack permission. 972 */ startSoftApInternal(SoftApModeConfiguration apConfig)973 private boolean startSoftApInternal(SoftApModeConfiguration apConfig) { 974 int uid = Binder.getCallingUid(); 975 boolean privileged = isSettingsOrSuw(Binder.getCallingPid(), uid); 976 mLog.trace("startSoftApInternal uid=% mode=%") 977 .c(uid).c(apConfig.getTargetMode()).flush(); 978 979 // null wifiConfig is a meaningful input for CMD_SET_AP; it means to use the persistent 980 // AP config. 981 SoftApConfiguration softApConfig = apConfig.getSoftApConfiguration(); 982 if (softApConfig != null 983 && (!WifiApConfigStore.validateApWifiConfiguration(softApConfig, privileged) 984 || !validateSoftApBand(softApConfig.getBand()))) { 985 Log.e(TAG, "Invalid SoftApConfiguration"); 986 return false; 987 } 988 989 mActiveModeWarden.startSoftAp(apConfig); 990 return true; 991 } 992 993 /** 994 * see {@link android.net.wifi.WifiManager#stopSoftAp()} 995 * @return {@code true} if softap stop was triggered 996 * @throws SecurityException if the caller does not have permission to stop softap 997 */ 998 @Override stopSoftAp()999 public boolean stopSoftAp() { 1000 // NETWORK_STACK is a signature only permission. 1001 enforceNetworkStackPermission(); 1002 1003 // only permitted callers are allowed to this point - they must have gone through 1004 // connectivity service since this method is protected with the NETWORK_STACK PERMISSION 1005 1006 mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush(); 1007 1008 stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED); 1009 return true; 1010 } 1011 1012 /** 1013 * Internal method to stop softap mode. 1014 * 1015 * Callers of this method should have already checked 1016 * proper permissions beyond the NetworkStack permission. 1017 * 1018 * @param mode the operating mode of APs to bring down (ex, 1019 * {@link WifiManager.IFACE_IP_MODE_TETHERED} or 1020 * {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}). 1021 * Use {@link WifiManager.IFACE_IP_MODE_UNSPECIFIED} to stop all APs. 1022 */ stopSoftApInternal(int mode)1023 private void stopSoftApInternal(int mode) { 1024 mLog.trace("stopSoftApInternal uid=% mode=%").c(Binder.getCallingUid()).c(mode).flush(); 1025 1026 mActiveModeWarden.stopSoftAp(mode); 1027 } 1028 1029 /** 1030 * SoftAp callback 1031 */ 1032 private final class TetheredSoftApTracker implements WifiManager.SoftApCallback { 1033 /** 1034 * State of tethered SoftAP 1035 * One of: {@link WifiManager#WIFI_AP_STATE_DISABLED}, 1036 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 1037 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 1038 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 1039 * {@link WifiManager#WIFI_AP_STATE_FAILED} 1040 */ 1041 private final Object mLock = new Object(); 1042 private int mTetheredSoftApState = WIFI_AP_STATE_DISABLED; 1043 private List<WifiClient> mTetheredSoftApConnectedClients = new ArrayList<>(); 1044 private SoftApInfo mTetheredSoftApInfo = new SoftApInfo(); 1045 // TODO: We need to maintain two capability. One for LTE + SAP and one for WIFI + SAP 1046 private SoftApCapability mTetheredSoftApCapability = null; 1047 getState()1048 public int getState() { 1049 synchronized (mLock) { 1050 return mTetheredSoftApState; 1051 } 1052 } 1053 setEnablingIfAllowed()1054 public boolean setEnablingIfAllowed() { 1055 synchronized (mLock) { 1056 if (mTetheredSoftApState != WIFI_AP_STATE_DISABLED 1057 && mTetheredSoftApState != WIFI_AP_STATE_FAILED) { 1058 return false; 1059 } 1060 mTetheredSoftApState = WIFI_AP_STATE_ENABLING; 1061 return true; 1062 } 1063 } 1064 setFailedWhileEnabling()1065 public void setFailedWhileEnabling() { 1066 synchronized (mLock) { 1067 if (mTetheredSoftApState == WIFI_AP_STATE_ENABLING) { 1068 mTetheredSoftApState = WIFI_AP_STATE_FAILED; 1069 } 1070 } 1071 } 1072 getConnectedClients()1073 public List<WifiClient> getConnectedClients() { 1074 synchronized (mLock) { 1075 return mTetheredSoftApConnectedClients; 1076 } 1077 } 1078 getSoftApInfo()1079 public SoftApInfo getSoftApInfo() { 1080 synchronized (mLock) { 1081 return mTetheredSoftApInfo; 1082 } 1083 } 1084 getSoftApCapability()1085 public SoftApCapability getSoftApCapability() { 1086 synchronized (mLock) { 1087 if (mTetheredSoftApCapability == null) { 1088 mTetheredSoftApCapability = ApConfigUtil.updateCapabilityFromResource(mContext); 1089 } 1090 return mTetheredSoftApCapability; 1091 } 1092 } 1093 updateSoftApCapability(int subId)1094 public void updateSoftApCapability(int subId) { 1095 synchronized (mLock) { 1096 CarrierConfigManager carrierConfigManager = 1097 (CarrierConfigManager) mContext.getSystemService( 1098 Context.CARRIER_CONFIG_SERVICE); 1099 if (carrierConfigManager == null) return; 1100 PersistableBundle carrierConfig = carrierConfigManager.getConfigForSubId(subId); 1101 if (carrierConfig == null) return; 1102 int carrierMaxClient = carrierConfig.getInt( 1103 CarrierConfigManager.Wifi.KEY_HOTSPOT_MAX_CLIENT_COUNT); 1104 int finalSupportedClientNumber = mContext.getResources().getInteger( 1105 R.integer.config_wifiHardwareSoftapMaxClientCount); 1106 if (carrierMaxClient > 0) { 1107 finalSupportedClientNumber = Math.min(finalSupportedClientNumber, 1108 carrierMaxClient); 1109 } 1110 if (finalSupportedClientNumber == getSoftApCapability().getMaxSupportedClients()) { 1111 return; 1112 } 1113 mTetheredSoftApCapability.setMaxSupportedClients( 1114 finalSupportedClientNumber); 1115 } 1116 onCapabilityChanged(mTetheredSoftApCapability); 1117 } 1118 1119 private final ExternalCallbackTracker<ISoftApCallback> mRegisteredSoftApCallbacks = 1120 new ExternalCallbackTracker<>(mClientModeImplHandler); 1121 registerSoftApCallback(IBinder binder, ISoftApCallback callback, int callbackIdentifier)1122 public boolean registerSoftApCallback(IBinder binder, ISoftApCallback callback, 1123 int callbackIdentifier) { 1124 return mRegisteredSoftApCallbacks.add(binder, callback, callbackIdentifier); 1125 } 1126 unregisterSoftApCallback(int callbackIdentifier)1127 public void unregisterSoftApCallback(int callbackIdentifier) { 1128 mRegisteredSoftApCallbacks.remove(callbackIdentifier); 1129 } 1130 1131 /** 1132 * Called when soft AP state changes. 1133 * 1134 * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED}, 1135 * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, 1136 * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} 1137 * @param failureReason reason when in failed state. One of 1138 * {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL} 1139 */ 1140 @Override onStateChanged(int state, int failureReason)1141 public void onStateChanged(int state, int failureReason) { 1142 synchronized (mLock) { 1143 mTetheredSoftApState = state; 1144 } 1145 1146 Iterator<ISoftApCallback> iterator = 1147 mRegisteredSoftApCallbacks.getCallbacks().iterator(); 1148 while (iterator.hasNext()) { 1149 ISoftApCallback callback = iterator.next(); 1150 try { 1151 callback.onStateChanged(state, failureReason); 1152 } catch (RemoteException e) { 1153 Log.e(TAG, "onStateChanged: remote exception -- " + e); 1154 // TODO(b/138863863) remove does nothing, getCallbacks() returns a copy 1155 iterator.remove(); 1156 } 1157 } 1158 } 1159 1160 /** 1161 * Called when the connected clients to soft AP changes. 1162 * 1163 * @param clients connected clients to soft AP 1164 */ 1165 @Override onConnectedClientsChanged(List<WifiClient> clients)1166 public void onConnectedClientsChanged(List<WifiClient> clients) { 1167 synchronized (mLock) { 1168 mTetheredSoftApConnectedClients = new ArrayList<>(clients); 1169 } 1170 1171 Iterator<ISoftApCallback> iterator = 1172 mRegisteredSoftApCallbacks.getCallbacks().iterator(); 1173 while (iterator.hasNext()) { 1174 ISoftApCallback callback = iterator.next(); 1175 try { 1176 callback.onConnectedClientsChanged(mTetheredSoftApConnectedClients); 1177 } catch (RemoteException e) { 1178 Log.e(TAG, "onConnectedClientsChanged: remote exception -- " + e); 1179 // TODO(b/138863863) remove does nothing, getCallbacks() returns a copy 1180 iterator.remove(); 1181 } 1182 } 1183 } 1184 1185 /** 1186 * Called when information of softap changes. 1187 * 1188 * @param softApInfo is the softap information. {@link SoftApInfo} 1189 */ 1190 @Override onInfoChanged(SoftApInfo softApInfo)1191 public void onInfoChanged(SoftApInfo softApInfo) { 1192 synchronized (mLock) { 1193 mTetheredSoftApInfo = new SoftApInfo(softApInfo); 1194 } 1195 1196 Iterator<ISoftApCallback> iterator = 1197 mRegisteredSoftApCallbacks.getCallbacks().iterator(); 1198 while (iterator.hasNext()) { 1199 ISoftApCallback callback = iterator.next(); 1200 try { 1201 callback.onInfoChanged(mTetheredSoftApInfo); 1202 } catch (RemoteException e) { 1203 Log.e(TAG, "onInfoChanged: remote exception -- " + e); 1204 } 1205 } 1206 } 1207 1208 /** 1209 * Called when capability of softap changes. 1210 * 1211 * @param capability is the softap capability. {@link SoftApCapability} 1212 */ 1213 @Override onCapabilityChanged(SoftApCapability capability)1214 public void onCapabilityChanged(SoftApCapability capability) { 1215 synchronized (mLock) { 1216 mTetheredSoftApCapability = new SoftApCapability(capability); 1217 } 1218 1219 Iterator<ISoftApCallback> iterator = 1220 mRegisteredSoftApCallbacks.getCallbacks().iterator(); 1221 while (iterator.hasNext()) { 1222 ISoftApCallback callback = iterator.next(); 1223 try { 1224 callback.onCapabilityChanged(mTetheredSoftApCapability); 1225 } catch (RemoteException e) { 1226 Log.e(TAG, "onCapabiliyChanged: remote exception -- " + e); 1227 } 1228 } 1229 } 1230 1231 /** 1232 * Called when client trying to connect but device blocked the client with specific reason. 1233 * 1234 * @param client the currently blocked client. 1235 * @param blockedReason one of blocked reason from 1236 * {@link WifiManager.SapClientBlockedReason} 1237 */ 1238 @Override onBlockedClientConnecting(WifiClient client, int blockedReason)1239 public void onBlockedClientConnecting(WifiClient client, int blockedReason) { 1240 Iterator<ISoftApCallback> iterator = 1241 mRegisteredSoftApCallbacks.getCallbacks().iterator(); 1242 while (iterator.hasNext()) { 1243 ISoftApCallback callback = iterator.next(); 1244 try { 1245 callback.onBlockedClientConnecting(client, blockedReason); 1246 } catch (RemoteException e) { 1247 Log.e(TAG, "onBlockedClientConnecting: remote exception -- " + e); 1248 } 1249 } 1250 } 1251 } 1252 1253 /** 1254 * Implements LOHS behavior on top of the existing SoftAp API. 1255 */ 1256 private final class LohsSoftApTracker implements WifiManager.SoftApCallback { 1257 @GuardedBy("mLocalOnlyHotspotRequests") 1258 private final HashMap<Integer, LocalOnlyHotspotRequestInfo> 1259 mLocalOnlyHotspotRequests = new HashMap<>(); 1260 1261 /** Currently-active config, to be sent to shared clients registering later. */ 1262 @GuardedBy("mLocalOnlyHotspotRequests") 1263 private SoftApModeConfiguration mActiveConfig = null; 1264 1265 /** 1266 * Whether we are currently operating in exclusive mode (i.e. whether a custom config is 1267 * active). 1268 */ 1269 @GuardedBy("mLocalOnlyHotspotRequests") 1270 private boolean mIsExclusive = false; 1271 1272 @GuardedBy("mLocalOnlyHotspotRequests") 1273 private String mLohsInterfaceName; 1274 1275 /** 1276 * State of local-only hotspot 1277 * One of: {@link WifiManager#WIFI_AP_STATE_DISABLED}, 1278 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 1279 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 1280 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 1281 * {@link WifiManager#WIFI_AP_STATE_FAILED} 1282 */ 1283 @GuardedBy("mLocalOnlyHotspotRequests") 1284 private int mLohsState = WIFI_AP_STATE_DISABLED; 1285 1286 @GuardedBy("mLocalOnlyHotspotRequests") 1287 private int mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED; 1288 1289 private SoftApCapability mLohsSoftApCapability = null; 1290 getSoftApCapability()1291 public SoftApCapability getSoftApCapability() { 1292 if (mLohsSoftApCapability == null) { 1293 mLohsSoftApCapability = ApConfigUtil.updateCapabilityFromResource(mContext); 1294 } 1295 return mLohsSoftApCapability; 1296 } 1297 updateInterfaceIpState(String ifaceName, int mode)1298 public void updateInterfaceIpState(String ifaceName, int mode) { 1299 // update interface IP state related to local-only hotspot 1300 synchronized (mLocalOnlyHotspotRequests) { 1301 Log.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode 1302 + " previous LOHS mode= " + mLohsInterfaceMode); 1303 1304 switch (mode) { 1305 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY: 1306 // first make sure we have registered requests. 1307 if (mLocalOnlyHotspotRequests.isEmpty()) { 1308 // we don't have requests... stop the hotspot 1309 Log.wtf(TAG, "Starting LOHS without any requests?"); 1310 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); 1311 return; 1312 } 1313 // LOHS is ready to go! Call our registered requestors! 1314 mLohsInterfaceName = ifaceName; 1315 mLohsInterfaceMode = mode; 1316 sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked(); 1317 break; 1318 case WifiManager.IFACE_IP_MODE_TETHERED: 1319 if (mLohsInterfaceName != null 1320 && mLohsInterfaceName.equals(ifaceName)) { 1321 /* This shouldn't happen except in a race, but if it does, tear down 1322 * the LOHS and let tethering win. 1323 * 1324 * If concurrent SAPs are allowed, the interface names will differ, 1325 * so we don't have to check the config here. 1326 */ 1327 Log.e(TAG, "Unexpected IP mode change on " + ifaceName); 1328 mLohsInterfaceName = null; 1329 mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED; 1330 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked( 1331 LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE); 1332 } 1333 break; 1334 case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR: 1335 if (ifaceName == null) { 1336 // All softAps 1337 mLohsInterfaceName = null; 1338 mLohsInterfaceMode = mode; 1339 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked( 1340 LocalOnlyHotspotCallback.ERROR_GENERIC); 1341 stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED); 1342 } else if (ifaceName.equals(mLohsInterfaceName)) { 1343 mLohsInterfaceName = null; 1344 mLohsInterfaceMode = mode; 1345 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked( 1346 LocalOnlyHotspotCallback.ERROR_GENERIC); 1347 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); 1348 } else { 1349 // Not for LOHS. This is the wrong place to do this, but... 1350 stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED); 1351 } 1352 break; 1353 case WifiManager.IFACE_IP_MODE_UNSPECIFIED: 1354 if (ifaceName == null || ifaceName.equals(mLohsInterfaceName)) { 1355 mLohsInterfaceName = null; 1356 mLohsInterfaceMode = mode; 1357 } 1358 break; 1359 default: 1360 mLog.warn("updateInterfaceIpState: unknown mode %").c(mode).flush(); 1361 } 1362 } 1363 } 1364 1365 /** 1366 * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest 1367 * callers and clear the registrations. 1368 * 1369 * Callers should already hold the mLocalOnlyHotspotRequests lock. 1370 */ 1371 @GuardedBy("mLocalOnlyHotspotRequests") sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason)1372 private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int reason) { 1373 for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) { 1374 try { 1375 requestor.sendHotspotFailedMessage(reason); 1376 requestor.unlinkDeathRecipient(); 1377 } catch (RemoteException e) { 1378 // This will be cleaned up by binder death handling 1379 } 1380 } 1381 1382 // Since all callers were notified, now clear the registrations. 1383 mLocalOnlyHotspotRequests.clear(); 1384 } 1385 1386 /** 1387 * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest 1388 * callers and clear the registrations. 1389 * 1390 * Callers should already hold the mLocalOnlyHotspotRequests lock. 1391 */ 1392 @GuardedBy("mLocalOnlyHotspotRequests") sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked()1393 private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() { 1394 for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) { 1395 try { 1396 requestor.sendHotspotStoppedMessage(); 1397 requestor.unlinkDeathRecipient(); 1398 } catch (RemoteException e) { 1399 // This will be cleaned up by binder death handling 1400 } 1401 } 1402 1403 // Since all callers were notified, now clear the registrations. 1404 mLocalOnlyHotspotRequests.clear(); 1405 } 1406 1407 /** 1408 * Add a new LOHS client 1409 */ start(int pid, LocalOnlyHotspotRequestInfo request)1410 private int start(int pid, LocalOnlyHotspotRequestInfo request) { 1411 synchronized (mLocalOnlyHotspotRequests) { 1412 // does this caller already have a request? 1413 if (mLocalOnlyHotspotRequests.get(pid) != null) { 1414 mLog.trace("caller already has an active request").flush(); 1415 throw new IllegalStateException( 1416 "Caller already has an active LocalOnlyHotspot request"); 1417 } 1418 1419 // Never accept exclusive requests (with custom configuration) at the same time as 1420 // shared requests. 1421 if (!mLocalOnlyHotspotRequests.isEmpty()) { 1422 boolean requestIsExclusive = request.getCustomConfig() != null; 1423 if (mIsExclusive || requestIsExclusive) { 1424 mLog.trace("Cannot share with existing LOHS request due to custom config") 1425 .flush(); 1426 return LocalOnlyHotspotCallback.ERROR_GENERIC; 1427 } 1428 } 1429 1430 // At this point, the request is accepted. 1431 if (mLocalOnlyHotspotRequests.isEmpty()) { 1432 startForFirstRequestLocked(request); 1433 } else if (mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) { 1434 // LOHS has already started up for an earlier request, so we can send the 1435 // current config to the incoming request right away. 1436 try { 1437 mLog.trace("LOHS already up, trigger onStarted callback").flush(); 1438 request.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration()); 1439 } catch (RemoteException e) { 1440 return LocalOnlyHotspotCallback.ERROR_GENERIC; 1441 } 1442 } 1443 1444 mLocalOnlyHotspotRequests.put(pid, request); 1445 return LocalOnlyHotspotCallback.REQUEST_REGISTERED; 1446 } 1447 } 1448 1449 @GuardedBy("mLocalOnlyHotspotRequests") startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request)1450 private void startForFirstRequestLocked(LocalOnlyHotspotRequestInfo request) { 1451 int band = SoftApConfiguration.BAND_2GHZ; 1452 1453 // For auto only 1454 if (hasAutomotiveFeature(mContext)) { 1455 if (mContext.getResources().getBoolean(R.bool.config_wifiLocalOnlyHotspot6ghz) 1456 && mContext.getResources().getBoolean(R.bool.config_wifiSoftap6ghzSupported) 1457 && is6GhzBandSupportedInternal()) { 1458 band = SoftApConfiguration.BAND_6GHZ; 1459 } else if (mContext.getResources().getBoolean( 1460 R.bool.config_wifi_local_only_hotspot_5ghz) 1461 && is5GhzBandSupportedInternal()) { 1462 band = SoftApConfiguration.BAND_5GHZ; 1463 } 1464 } 1465 1466 SoftApConfiguration softApConfig = WifiApConfigStore.generateLocalOnlyHotspotConfig( 1467 mContext, band, request.getCustomConfig()); 1468 1469 mActiveConfig = new SoftApModeConfiguration( 1470 WifiManager.IFACE_IP_MODE_LOCAL_ONLY, 1471 softApConfig, mLohsSoftApTracker.getSoftApCapability()); 1472 mIsExclusive = (request.getCustomConfig() != null); 1473 1474 startSoftApInternal(mActiveConfig); 1475 } 1476 1477 /** 1478 * Requests that any local-only hotspot be stopped. 1479 */ stopAll()1480 public void stopAll() { 1481 synchronized (mLocalOnlyHotspotRequests) { 1482 if (!mLocalOnlyHotspotRequests.isEmpty()) { 1483 // This is used to take down LOHS when tethering starts, and in that 1484 // case we send failed instead of stopped. 1485 // TODO check if that is right. Calling onFailed instead of onStopped when the 1486 // hotspot is already started does not seem to match the documentation 1487 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked( 1488 LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE); 1489 stopIfEmptyLocked(); 1490 } 1491 } 1492 } 1493 1494 /** 1495 * Unregisters the LOHS request from the given process and stops LOHS if no other clients. 1496 */ stopByPid(int pid)1497 public void stopByPid(int pid) { 1498 synchronized (mLocalOnlyHotspotRequests) { 1499 LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.remove(pid); 1500 if (requestInfo == null) return; 1501 requestInfo.unlinkDeathRecipient(); 1502 stopIfEmptyLocked(); 1503 } 1504 } 1505 1506 /** 1507 * Unregisters LocalOnlyHotspot request and stops the hotspot if needed. 1508 */ stopByRequest(LocalOnlyHotspotRequestInfo request)1509 public void stopByRequest(LocalOnlyHotspotRequestInfo request) { 1510 synchronized (mLocalOnlyHotspotRequests) { 1511 if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) { 1512 mLog.trace("LocalOnlyHotspotRequestInfo not found to remove").flush(); 1513 return; 1514 } 1515 stopIfEmptyLocked(); 1516 } 1517 } 1518 1519 @GuardedBy("mLocalOnlyHotspotRequests") stopIfEmptyLocked()1520 private void stopIfEmptyLocked() { 1521 if (mLocalOnlyHotspotRequests.isEmpty()) { 1522 mActiveConfig = null; 1523 mIsExclusive = false; 1524 mLohsInterfaceName = null; 1525 mLohsInterfaceMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED; 1526 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); 1527 } 1528 } 1529 1530 /** 1531 * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest 1532 * callers. 1533 * 1534 * Callers should already hold the mLocalOnlyHotspotRequests lock. 1535 */ 1536 @GuardedBy("mLocalOnlyHotspotRequests") sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked()1537 private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() { 1538 for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) { 1539 try { 1540 requestor.sendHotspotStartedMessage(mActiveConfig.getSoftApConfiguration()); 1541 } catch (RemoteException e) { 1542 // This will be cleaned up by binder death handling 1543 } 1544 } 1545 } 1546 1547 @Override onStateChanged(int state, int failureReason)1548 public void onStateChanged(int state, int failureReason) { 1549 // The AP state update from ClientModeImpl for softap 1550 synchronized (mLocalOnlyHotspotRequests) { 1551 Log.d(TAG, "lohs.onStateChanged: currentState=" + state 1552 + " previousState=" + mLohsState + " errorCode= " + failureReason 1553 + " ifaceName=" + mLohsInterfaceName); 1554 1555 // check if we have a failure - since it is possible (worst case scenario where 1556 // WifiController and ClientModeImpl are out of sync wrt modes) to get two FAILED 1557 // notifications in a row, we need to handle this first. 1558 if (state == WIFI_AP_STATE_FAILED) { 1559 // update registered LOHS callbacks if we see a failure 1560 int errorToReport = ERROR_GENERIC; 1561 if (failureReason == SAP_START_FAILURE_NO_CHANNEL) { 1562 errorToReport = ERROR_NO_CHANNEL; 1563 } 1564 // holding the required lock: send message to requestors and clear the list 1565 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(errorToReport); 1566 // also need to clear interface ip state 1567 updateInterfaceIpState(mLohsInterfaceName, 1568 WifiManager.IFACE_IP_MODE_UNSPECIFIED); 1569 } else if (state == WIFI_AP_STATE_DISABLING || state == WIFI_AP_STATE_DISABLED) { 1570 // softap is shutting down or is down... let requestors know via the 1571 // onStopped call 1572 // if we are currently in hotspot mode, then trigger onStopped for registered 1573 // requestors, otherwise something odd happened and we should clear state 1574 if (mLohsInterfaceName != null 1575 && mLohsInterfaceMode == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) { 1576 // holding the required lock: send message to requestors and clear the list 1577 sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked(); 1578 } else { 1579 // LOHS not active: report an error (still holding the required lock) 1580 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC); 1581 } 1582 // also clear interface ip state 1583 updateInterfaceIpState(mLohsInterfaceName, 1584 WifiManager.IFACE_IP_MODE_UNSPECIFIED); 1585 } 1586 // For enabling and enabled, just record the new state 1587 mLohsState = state; 1588 } 1589 } 1590 1591 @Override onConnectedClientsChanged(List<WifiClient> clients)1592 public void onConnectedClientsChanged(List<WifiClient> clients) { 1593 // Nothing to do 1594 } 1595 1596 /** 1597 * Called when information of softap changes. 1598 * 1599 * @param softApInfo is the softap information. {@link SoftApInfo} 1600 */ 1601 @Override onInfoChanged(SoftApInfo softApInfo)1602 public void onInfoChanged(SoftApInfo softApInfo) { 1603 // Nothing to do 1604 } 1605 1606 /** 1607 * Called when capability of softap changes. 1608 * 1609 * @param capability is the softap information. {@link SoftApCapability} 1610 */ 1611 @Override onCapabilityChanged(SoftApCapability capability)1612 public void onCapabilityChanged(SoftApCapability capability) { 1613 // Nothing to do 1614 } 1615 1616 /** 1617 * Called when client trying to connect but device blocked the client with specific reason. 1618 * 1619 * @param client the currently blocked client. 1620 * @param blockedReason one of blocked reason from 1621 * {@link WifiManager.SapClientBlockedReason} 1622 */ 1623 @Override onBlockedClientConnecting(WifiClient client, int blockedReason)1624 public void onBlockedClientConnecting(WifiClient client, int blockedReason) { 1625 // Nothing to do 1626 } 1627 } 1628 1629 /** 1630 * see {@link android.net.wifi.WifiManager#registerSoftApCallback(Executor, SoftApCallback)} 1631 * 1632 * @param binder IBinder instance to allow cleanup if the app dies 1633 * @param callback Soft AP callback to register 1634 * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to 1635 * unregister the callback. See {@link unregisterSoftApCallback(int)} 1636 * 1637 * @throws SecurityException if the caller does not have permission to register a callback 1638 * @throws RemoteException if remote exception happens 1639 * @throws IllegalArgumentException if the arguments are null or invalid 1640 */ 1641 @Override registerSoftApCallback(IBinder binder, ISoftApCallback callback, int callbackIdentifier)1642 public void registerSoftApCallback(IBinder binder, ISoftApCallback callback, 1643 int callbackIdentifier) { 1644 // verify arguments 1645 if (binder == null) { 1646 throw new IllegalArgumentException("Binder must not be null"); 1647 } 1648 if (callback == null) { 1649 throw new IllegalArgumentException("Callback must not be null"); 1650 } 1651 1652 enforceNetworkStackOrSettingsPermission(); 1653 1654 if (mVerboseLoggingEnabled) { 1655 mLog.info("registerSoftApCallback uid=%").c(Binder.getCallingUid()).flush(); 1656 } 1657 1658 // post operation to handler thread 1659 mWifiThreadRunner.post(() -> { 1660 if (!mTetheredSoftApTracker.registerSoftApCallback(binder, callback, 1661 callbackIdentifier)) { 1662 Log.e(TAG, "registerSoftApCallback: Failed to add callback"); 1663 return; 1664 } 1665 // Update the client about the current state immediately after registering the callback 1666 try { 1667 callback.onStateChanged(mTetheredSoftApTracker.getState(), 0); 1668 callback.onConnectedClientsChanged(mTetheredSoftApTracker.getConnectedClients()); 1669 callback.onInfoChanged(mTetheredSoftApTracker.getSoftApInfo()); 1670 callback.onCapabilityChanged(mTetheredSoftApTracker.getSoftApCapability()); 1671 } catch (RemoteException e) { 1672 Log.e(TAG, "registerSoftApCallback: remote exception -- " + e); 1673 } 1674 }); 1675 } 1676 1677 /** 1678 * see {@link android.net.wifi.WifiManager#unregisterSoftApCallback(SoftApCallback)} 1679 * 1680 * @param callbackIdentifier Unique ID of the callback to be unregistered. 1681 * 1682 * @throws SecurityException if the caller does not have permission to register a callback 1683 */ 1684 @Override unregisterSoftApCallback(int callbackIdentifier)1685 public void unregisterSoftApCallback(int callbackIdentifier) { 1686 enforceNetworkStackOrSettingsPermission(); 1687 1688 if (mVerboseLoggingEnabled) { 1689 mLog.info("unregisterSoftApCallback uid=%").c(Binder.getCallingUid()).flush(); 1690 } 1691 1692 // post operation to handler thread 1693 mWifiThreadRunner.post(() -> 1694 mTetheredSoftApTracker.unregisterSoftApCallback(callbackIdentifier)); 1695 } 1696 1697 /** 1698 * Temporary method used for testing while start is not fully implemented. This 1699 * method allows unit tests to register callbacks directly for testing mechanisms triggered by 1700 * softap mode changes. 1701 */ 1702 @VisibleForTesting registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request)1703 void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) { 1704 mLohsSoftApTracker.start(pid, request); 1705 } 1706 1707 /** 1708 * Method to start LocalOnlyHotspot. In this method, permissions, settings and modes are 1709 * checked to verify that we can enter softapmode. This method returns 1710 * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise, 1711 * possible startup erros may include tethering being disallowed failure reason {@link 1712 * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason 1713 * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}. 1714 * 1715 * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)} 1716 * 1717 * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies. 1718 * @param packageName String name of the calling package. 1719 * @param featureId The feature in the package 1720 * @param customConfig Custom configuration to be applied to the hotspot, or null for a shared 1721 * hotspot with framework-generated config. 1722 * 1723 * @return int return code for attempt to start LocalOnlyHotspot. 1724 * 1725 * @throws SecurityException if the caller does not have permission to start a Local Only 1726 * Hotspot. 1727 * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they 1728 * have an outstanding request. 1729 */ 1730 @Override startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName, String featureId, SoftApConfiguration customConfig)1731 public int startLocalOnlyHotspot(ILocalOnlyHotspotCallback callback, String packageName, 1732 String featureId, SoftApConfiguration customConfig) { 1733 // first check if the caller has permission to start a local only hotspot 1734 // need to check for WIFI_STATE_CHANGE and location permission 1735 final int uid = Binder.getCallingUid(); 1736 final int pid = Binder.getCallingPid(); 1737 1738 mLog.info("start uid=% pid=%").c(uid).c(pid).flush(); 1739 1740 // Permission requirements are different with/without custom config. 1741 if (customConfig == null) { 1742 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1743 return LocalOnlyHotspotCallback.ERROR_GENERIC; 1744 } 1745 enforceLocationPermission(packageName, featureId, uid); 1746 long ident = Binder.clearCallingIdentity(); 1747 try { 1748 // also need to verify that Locations services are enabled. 1749 if (!mWifiPermissionsUtil.isLocationModeEnabled()) { 1750 throw new SecurityException("Location mode is not enabled."); 1751 } 1752 } finally { 1753 Binder.restoreCallingIdentity(ident); 1754 } 1755 } else { 1756 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 1757 throw new SecurityException(TAG + ": Permission denied"); 1758 } 1759 } 1760 1761 // verify that tethering is not disabled 1762 if (mUserManager.hasUserRestrictionForUser( 1763 UserManager.DISALLOW_CONFIG_TETHERING, UserHandle.getUserHandleForUid(uid))) { 1764 return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED; 1765 } 1766 1767 // the app should be in the foreground 1768 long ident = Binder.clearCallingIdentity(); 1769 try { 1770 // also need to verify that Locations services are enabled. 1771 if (!mFrameworkFacade.isAppForeground(mContext, uid)) { 1772 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE; 1773 } 1774 } finally { 1775 Binder.restoreCallingIdentity(ident); 1776 } 1777 1778 // check if we are currently tethering 1779 if (!mActiveModeWarden.canRequestMoreSoftApManagers() 1780 && mTetheredSoftApTracker.getState() == WIFI_AP_STATE_ENABLED) { 1781 // Tethering is enabled, cannot start LocalOnlyHotspot 1782 mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.") 1783 .flush(); 1784 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE; 1785 } 1786 1787 // now create the new LOHS request info object 1788 LocalOnlyHotspotRequestInfo request = new LocalOnlyHotspotRequestInfo(callback, 1789 new LocalOnlyRequestorCallback(), customConfig); 1790 1791 return mLohsSoftApTracker.start(pid, request); 1792 } 1793 1794 /** 1795 * see {@link WifiManager#stopLocalOnlyHotspot()} 1796 * 1797 * @throws SecurityException if the caller does not have permission to stop a Local Only 1798 * Hotspot. 1799 */ 1800 @Override stopLocalOnlyHotspot()1801 public void stopLocalOnlyHotspot() { 1802 // don't do a permission check here. if the app's permission to change the wifi state is 1803 // revoked, we still want them to be able to stop a previously created hotspot (otherwise 1804 // it could cost the user money). When the app created the hotspot, its permission was 1805 // checked. 1806 final int uid = Binder.getCallingUid(); 1807 final int pid = Binder.getCallingPid(); 1808 1809 mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush(); 1810 1811 mLohsSoftApTracker.stopByPid(pid); 1812 } 1813 1814 /** 1815 * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)} 1816 * 1817 * This call requires the android.permission.NETWORK_SETTINGS permission. 1818 * 1819 * @param callback Callback to communicate with WifiManager and allow cleanup if the app dies. 1820 * 1821 * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot 1822 * status updates. 1823 * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with 1824 * an existing subscription. 1825 */ 1826 @Override startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback)1827 public void startWatchLocalOnlyHotspot(ILocalOnlyHotspotCallback callback) { 1828 // NETWORK_SETTINGS is a signature only permission. 1829 enforceNetworkSettingsPermission(); 1830 1831 throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); 1832 } 1833 1834 /** 1835 * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()} 1836 */ 1837 @Override stopWatchLocalOnlyHotspot()1838 public void stopWatchLocalOnlyHotspot() { 1839 // NETWORK_STACK is a signature only permission. 1840 enforceNetworkSettingsPermission(); 1841 throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); 1842 } 1843 1844 /** 1845 * see {@link WifiManager#getWifiApConfiguration()} 1846 * @return soft access point configuration 1847 * @throws SecurityException if the caller does not have permission to retrieve the softap 1848 * config 1849 */ 1850 @Nullable 1851 @Override getWifiApConfiguration()1852 public WifiConfiguration getWifiApConfiguration() { 1853 enforceAccessPermission(); 1854 int uid = Binder.getCallingUid(); 1855 // only allow Settings UI to get the saved SoftApConfig 1856 if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { 1857 // random apps should not be allowed to read the user specified config 1858 throw new SecurityException("App not allowed to read or update stored WiFi Ap config " 1859 + "(uid = " + uid + ")"); 1860 } 1861 1862 if (mVerboseLoggingEnabled) { 1863 mLog.info("getWifiApConfiguration uid=%").c(uid).flush(); 1864 } 1865 1866 // hand off work to the ClientModeImpl handler thread to sync work between calls 1867 // and SoftApManager starting up softap 1868 return (mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration, 1869 new SoftApConfiguration.Builder().build())).toWifiConfiguration(); 1870 } 1871 1872 /** 1873 * see {@link WifiManager#getSoftApConfiguration()} 1874 * @return soft access point configuration {@link SoftApConfiguration} 1875 * @throws SecurityException if the caller does not have permission to retrieve the softap 1876 * config 1877 */ 1878 @NonNull 1879 @Override getSoftApConfiguration()1880 public SoftApConfiguration getSoftApConfiguration() { 1881 enforceNetworkSettingsPermission(); 1882 int uid = Binder.getCallingUid(); 1883 if (mVerboseLoggingEnabled) { 1884 mLog.info("getSoftApConfiguration uid=%").c(uid).flush(); 1885 } 1886 1887 // hand off work to the ClientModeImpl handler thread to sync work between calls 1888 // and SoftApManager starting up softap 1889 return mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration, 1890 new SoftApConfiguration.Builder().build()); 1891 } 1892 1893 /** 1894 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)} 1895 * @param wifiConfig WifiConfiguration details for soft access point 1896 * @return boolean indicating success or failure of the operation 1897 * @throws SecurityException if the caller does not have permission to write the softap config 1898 */ 1899 @Override setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName)1900 public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) { 1901 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1902 return false; 1903 } 1904 int uid = Binder.getCallingUid(); 1905 // only allow Settings UI to write the stored SoftApConfig 1906 if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { 1907 // random apps should not be allowed to read the user specified config 1908 throw new SecurityException("App not allowed to read or update stored WiFi AP config " 1909 + "(uid = " + uid + ")"); 1910 } 1911 mLog.info("setWifiApConfiguration uid=%").c(uid).flush(); 1912 if (wifiConfig == null) 1913 return false; 1914 SoftApConfiguration softApConfig = ApConfigUtil.fromWifiConfiguration(wifiConfig); 1915 if (softApConfig == null) return false; 1916 if (WifiApConfigStore.validateApWifiConfiguration( 1917 softApConfig, false)) { 1918 mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(softApConfig)); 1919 return true; 1920 } else { 1921 Log.e(TAG, "Invalid WifiConfiguration"); 1922 return false; 1923 } 1924 } 1925 1926 /** 1927 * see {@link WifiManager#setSoftApConfiguration(SoftApConfiguration)} 1928 * @param softApConfig {@link SoftApConfiguration} details for soft access point 1929 * @return boolean indicating success or failure of the operation 1930 * @throws SecurityException if the caller does not have permission to write the softap config 1931 */ 1932 @Override setSoftApConfiguration( @onNull SoftApConfiguration softApConfig, @NonNull String packageName)1933 public boolean setSoftApConfiguration( 1934 @NonNull SoftApConfiguration softApConfig, @NonNull String packageName) { 1935 enforceNetworkSettingsPermission(); 1936 int uid = Binder.getCallingUid(); 1937 boolean privileged = mWifiPermissionsUtil.checkNetworkSettingsPermission(uid); 1938 mLog.info("setSoftApConfiguration uid=%").c(uid).flush(); 1939 if (softApConfig == null) return false; 1940 if (WifiApConfigStore.validateApWifiConfiguration(softApConfig, privileged)) { 1941 mActiveModeWarden.updateSoftApConfiguration(softApConfig); 1942 mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration(softApConfig)); 1943 return true; 1944 } else { 1945 Log.e(TAG, "Invalid SoftAp Configuration"); 1946 return false; 1947 } 1948 } 1949 1950 /** 1951 * see {@link android.net.wifi.WifiManager#setScanAlwaysAvailable(boolean)} 1952 */ 1953 @Override setScanAlwaysAvailable(boolean isAvailable)1954 public void setScanAlwaysAvailable(boolean isAvailable) { 1955 enforceNetworkSettingsPermission(); 1956 mLog.info("setScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush(); 1957 mSettingsStore.handleWifiScanAlwaysAvailableToggled(isAvailable); 1958 long ident = Binder.clearCallingIdentity(); 1959 try { 1960 mWifiInjector.getWifiScanAlwaysAvailableSettingsCompatibility() 1961 .handleWifiScanAlwaysAvailableToggled(isAvailable); 1962 } finally { 1963 Binder.restoreCallingIdentity(ident); 1964 } 1965 mActiveModeWarden.scanAlwaysModeChanged(); 1966 } 1967 1968 /** 1969 * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()} 1970 */ 1971 @Override isScanAlwaysAvailable()1972 public boolean isScanAlwaysAvailable() { 1973 enforceAccessPermission(); 1974 if (mVerboseLoggingEnabled) { 1975 mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush(); 1976 } 1977 return mSettingsStore.isScanAlwaysAvailable(); 1978 } 1979 1980 /** 1981 * see {@link android.net.wifi.WifiManager#disconnect()} 1982 */ 1983 @Override disconnect(String packageName)1984 public boolean disconnect(String packageName) { 1985 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1986 return false; 1987 } 1988 if (!isTargetSdkLessThanQOrPrivileged( 1989 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 1990 mLog.info("disconnect not allowed for uid=%") 1991 .c(Binder.getCallingUid()).flush(); 1992 return false; 1993 } 1994 mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush(); 1995 mClientModeImpl.disconnectCommand(); 1996 return true; 1997 } 1998 1999 /** 2000 * see {@link android.net.wifi.WifiManager#reconnect()} 2001 */ 2002 @Override reconnect(String packageName)2003 public boolean reconnect(String packageName) { 2004 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2005 return false; 2006 } 2007 if (!isTargetSdkLessThanQOrPrivileged( 2008 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2009 mLog.info("reconnect not allowed for uid=%") 2010 .c(Binder.getCallingUid()).flush(); 2011 return false; 2012 } 2013 mLog.info("reconnect uid=%").c(Binder.getCallingUid()).flush(); 2014 mClientModeImpl.reconnectCommand(new WorkSource(Binder.getCallingUid())); 2015 return true; 2016 } 2017 2018 /** 2019 * see {@link android.net.wifi.WifiManager#reassociate()} 2020 */ 2021 @Override reassociate(String packageName)2022 public boolean reassociate(String packageName) { 2023 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2024 return false; 2025 } 2026 if (!isTargetSdkLessThanQOrPrivileged( 2027 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2028 mLog.info("reassociate not allowed for uid=%") 2029 .c(Binder.getCallingUid()).flush(); 2030 return false; 2031 } 2032 mLog.info("reassociate uid=%").c(Binder.getCallingUid()).flush(); 2033 mClientModeImpl.reassociateCommand(); 2034 return true; 2035 } 2036 2037 /** 2038 * see {@link android.net.wifi.WifiManager#getSupportedFeatures} 2039 */ 2040 @Override getSupportedFeatures()2041 public long getSupportedFeatures() { 2042 enforceAccessPermission(); 2043 if (mVerboseLoggingEnabled) { 2044 mLog.info("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush(); 2045 } 2046 return getSupportedFeaturesInternal(); 2047 } 2048 2049 @Override getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener)2050 public void getWifiActivityEnergyInfoAsync(IOnWifiActivityEnergyInfoListener listener) { 2051 if (mVerboseLoggingEnabled) { 2052 mLog.info("getWifiActivityEnergyInfoAsync uid=%") 2053 .c(Binder.getCallingUid()) 2054 .flush(); 2055 } 2056 // getWifiActivityEnergyInfo() performs permission checking 2057 WifiActivityEnergyInfo info = getWifiActivityEnergyInfo(); 2058 try { 2059 listener.onWifiActivityEnergyInfo(info); 2060 } catch (RemoteException e) { 2061 Log.e(TAG, "onWifiActivityEnergyInfo: RemoteException -- ", e); 2062 } 2063 } 2064 getWifiActivityEnergyInfo()2065 private WifiActivityEnergyInfo getWifiActivityEnergyInfo() { 2066 enforceAccessPermission(); 2067 if (mVerboseLoggingEnabled) { 2068 mLog.info("getWifiActivityEnergyInfo uid=%").c(Binder.getCallingUid()).flush(); 2069 } 2070 if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) { 2071 return null; 2072 } 2073 if (mClientModeImplChannel == null) { 2074 Log.e(TAG, "mClientModeImplChannel is not initialized"); 2075 return null; 2076 } 2077 WifiLinkLayerStats stats = mClientModeImpl.syncGetLinkLayerStats(mClientModeImplChannel); 2078 if (stats == null) { 2079 return null; 2080 } 2081 2082 final long rxIdleTimeMillis = stats.on_time - stats.tx_time - stats.rx_time; 2083 final long[] txTimePerLevelMillis; 2084 if (stats.tx_time_per_level == null) { 2085 // This will happen if the HAL get link layer API returned null. 2086 txTimePerLevelMillis = new long[0]; 2087 } else { 2088 // need to manually copy since we are converting an int[] to a long[] 2089 txTimePerLevelMillis = new long[stats.tx_time_per_level.length]; 2090 for (int i = 0; i < txTimePerLevelMillis.length; i++) { 2091 txTimePerLevelMillis[i] = stats.tx_time_per_level[i]; 2092 // TODO(b/27227497): Need to read the power consumed per level from config 2093 } 2094 } 2095 if (VDBG || rxIdleTimeMillis < 0 || stats.on_time < 0 || stats.tx_time < 0 2096 || stats.rx_time < 0 || stats.on_time_scan < 0) { 2097 Log.d(TAG, " getWifiActivityEnergyInfo: " 2098 + " on_time_millis=" + stats.on_time 2099 + " tx_time_millis=" + stats.tx_time 2100 + " tx_time_per_level_millis=" + Arrays.toString(txTimePerLevelMillis) 2101 + " rx_time_millis=" + stats.rx_time 2102 + " rxIdleTimeMillis=" + rxIdleTimeMillis 2103 + " scan_time_millis=" + stats.on_time_scan); 2104 } 2105 2106 // Convert the LinkLayerStats into WifiActivityEnergyInfo 2107 return new WifiActivityEnergyInfo( 2108 mClock.getElapsedSinceBootMillis(), 2109 WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, 2110 stats.tx_time, 2111 stats.rx_time, 2112 stats.on_time_scan, 2113 rxIdleTimeMillis); 2114 } 2115 2116 /** 2117 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 2118 * 2119 * @param packageName String name of the calling package 2120 * @param featureId The feature in the package 2121 * @return the list of configured networks 2122 */ 2123 @Override getConfiguredNetworks(String packageName, String featureId)2124 public ParceledListSlice<WifiConfiguration> getConfiguredNetworks(String packageName, 2125 String featureId) { 2126 enforceAccessPermission(); 2127 int callingUid = Binder.getCallingUid(); 2128 // bypass shell: can get varioud pkg name 2129 if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { 2130 long ident = Binder.clearCallingIdentity(); 2131 try { 2132 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, 2133 callingUid, null); 2134 } catch (SecurityException e) { 2135 Log.e(TAG, "Permission violation - getConfiguredNetworks not allowed for uid=" 2136 + callingUid + ", packageName=" + packageName + ", reason=" + e); 2137 return new ParceledListSlice<>(new ArrayList<>()); 2138 } finally { 2139 Binder.restoreCallingIdentity(ident); 2140 } 2141 } 2142 boolean isTargetSdkLessThanQOrPrivileged = isTargetSdkLessThanQOrPrivileged( 2143 packageName, Binder.getCallingPid(), callingUid); 2144 boolean isCarrierApp = mWifiInjector.makeTelephonyManager() 2145 .checkCarrierPrivilegesForPackageAnyPhone(packageName) 2146 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 2147 if (!isTargetSdkLessThanQOrPrivileged && !isCarrierApp) { 2148 mLog.info("getConfiguredNetworks not allowed for uid=%") 2149 .c(callingUid).flush(); 2150 return new ParceledListSlice<>(new ArrayList<>()); 2151 } 2152 if (mVerboseLoggingEnabled) { 2153 mLog.info("getConfiguredNetworks uid=%").c(callingUid).flush(); 2154 } 2155 2156 int targetConfigUid = Process.INVALID_UID; // don't expose any MAC addresses 2157 if (isPrivileged(getCallingPid(), callingUid) 2158 || isDeviceOrProfileOwner(callingUid, packageName)) { 2159 targetConfigUid = Process.WIFI_UID; // expose all MAC addresses 2160 } else if (isCarrierApp) { 2161 targetConfigUid = callingUid; // expose only those configs created by the Carrier App 2162 } 2163 int finalTargetConfigUid = targetConfigUid; 2164 List<WifiConfiguration> configs = mWifiThreadRunner.call( 2165 () -> mWifiConfigManager.getSavedNetworks(finalTargetConfigUid), 2166 Collections.emptyList()); 2167 if (isTargetSdkLessThanQOrPrivileged) { 2168 return new ParceledListSlice<>(configs); 2169 } 2170 // Carrier app: should only get its own configs 2171 List<WifiConfiguration> creatorConfigs = new ArrayList<>(); 2172 for (WifiConfiguration config : configs) { 2173 if (config.creatorUid == callingUid) { 2174 creatorConfigs.add(config); 2175 } 2176 } 2177 return new ParceledListSlice<>(creatorConfigs); 2178 } 2179 2180 /** 2181 * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()} 2182 * 2183 * @param packageName String name of the calling package 2184 * @param featureId The feature in the package 2185 * @return the list of configured networks with real preSharedKey 2186 */ 2187 @Override getPrivilegedConfiguredNetworks( String packageName, String featureId)2188 public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks( 2189 String packageName, String featureId) { 2190 enforceReadCredentialPermission(); 2191 enforceAccessPermission(); 2192 int callingUid = Binder.getCallingUid(); 2193 long ident = Binder.clearCallingIdentity(); 2194 try { 2195 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, featureId, callingUid, 2196 null); 2197 } catch (SecurityException e) { 2198 Log.e(TAG, "Permission violation - getPrivilegedConfiguredNetworks not allowed for" 2199 + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e); 2200 return null; 2201 } finally { 2202 Binder.restoreCallingIdentity(ident); 2203 } 2204 if (mVerboseLoggingEnabled) { 2205 mLog.info("getPrivilegedConfiguredNetworks uid=%").c(callingUid).flush(); 2206 } 2207 List<WifiConfiguration> configs = mWifiThreadRunner.call( 2208 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(), 2209 Collections.emptyList()); 2210 return new ParceledListSlice<>(configs); 2211 } 2212 2213 /** 2214 * Return a map of all matching configurations keys with corresponding scanResults (or an empty 2215 * map if none). 2216 * 2217 * @param scanResults The list of scan results 2218 * @return Map that consists of FQDN (Fully Qualified Domain Name) and corresponding 2219 * scanResults per network type({@link WifiManager#PASSPOINT_HOME_NETWORK} and {@link 2220 * WifiManager#PASSPOINT_ROAMING_NETWORK}). 2221 */ 2222 @Override 2223 public Map<String, Map<Integer, List<ScanResult>>> getAllMatchingPasspointProfilesForScanResults(List<ScanResult> scanResults)2224 getAllMatchingPasspointProfilesForScanResults(List<ScanResult> scanResults) { 2225 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 2226 throw new SecurityException(TAG + ": Permission denied"); 2227 } 2228 if (mVerboseLoggingEnabled) { 2229 mLog.info("getMatchingPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush(); 2230 } 2231 if (!ScanResultUtil.validateScanResultList(scanResults)) { 2232 Log.e(TAG, "Attempt to retrieve passpoint with invalid scanResult List"); 2233 return Collections.emptyMap(); 2234 } 2235 return mWifiThreadRunner.call( 2236 () -> mPasspointManager.getAllMatchingPasspointProfilesForScanResults(scanResults), 2237 Collections.emptyMap()); 2238 } 2239 2240 /** 2241 * Returns list of OSU (Online Sign-Up) providers associated with the given list of ScanResult. 2242 * 2243 * @param scanResults a list of ScanResult that has Passpoint APs. 2244 * @return Map that consists of {@link OsuProvider} and a matching list of {@link ScanResult}. 2245 */ 2246 @Override getMatchingOsuProviders( List<ScanResult> scanResults)2247 public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders( 2248 List<ScanResult> scanResults) { 2249 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 2250 throw new SecurityException(TAG + ": Permission denied"); 2251 } 2252 if (mVerboseLoggingEnabled) { 2253 mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush(); 2254 } 2255 2256 if (!ScanResultUtil.validateScanResultList(scanResults)) { 2257 Log.e(TAG, "Attempt to retrieve OsuProviders with invalid scanResult List"); 2258 return Collections.emptyMap(); 2259 } 2260 return mWifiThreadRunner.call( 2261 () -> mPasspointManager.getMatchingOsuProviders(scanResults), Collections.emptyMap()); 2262 } 2263 2264 /** 2265 * Returns the matching Passpoint configurations for given OSU(Online Sign-Up) providers. 2266 * 2267 * @param osuProviders a list of {@link OsuProvider} 2268 * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}. 2269 */ 2270 @Override getMatchingPasspointConfigsForOsuProviders( List<OsuProvider> osuProviders)2271 public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders( 2272 List<OsuProvider> osuProviders) { 2273 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 2274 throw new SecurityException(TAG + ": Permission denied"); 2275 } 2276 if (mVerboseLoggingEnabled) { 2277 mLog.info("getMatchingPasspointConfigsForOsuProviders uid=%").c( 2278 Binder.getCallingUid()).flush(); 2279 } 2280 if (osuProviders == null) { 2281 Log.e(TAG, "Attempt to retrieve Passpoint configuration with null osuProviders"); 2282 return new HashMap<>(); 2283 } 2284 return mWifiThreadRunner.call( 2285 () -> mPasspointManager.getMatchingPasspointConfigsForOsuProviders(osuProviders), 2286 Collections.emptyMap()); 2287 } 2288 2289 /** 2290 * Returns the corresponding wifi configurations for given FQDN (Fully Qualified Domain Name) 2291 * list. 2292 * 2293 * An empty list will be returned when no match is found. 2294 * 2295 * @param fqdnList a list of FQDN 2296 * @return List of {@link WifiConfiguration} converted from {@link PasspointProvider} 2297 */ 2298 @Override getWifiConfigsForPasspointProfiles(List<String> fqdnList)2299 public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) { 2300 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 2301 throw new SecurityException(TAG + ": Permission denied"); 2302 } 2303 if (mVerboseLoggingEnabled) { 2304 mLog.info("getWifiConfigsForPasspointProfiles uid=%").c( 2305 Binder.getCallingUid()).flush(); 2306 } 2307 if (fqdnList == null) { 2308 Log.e(TAG, "Attempt to retrieve WifiConfiguration with null fqdn List"); 2309 return new ArrayList<>(); 2310 } 2311 return mWifiThreadRunner.call( 2312 () -> mPasspointManager.getWifiConfigsForPasspointProfiles(fqdnList), 2313 Collections.emptyList()); 2314 } 2315 2316 /** 2317 * Returns a list of Wifi configurations for matched available WifiNetworkSuggestion 2318 * corresponding to the given scan results. 2319 * 2320 * An empty list will be returned when no match is found or all matched suggestions is not 2321 * available(not allow user manually connect, user not approved or open network). 2322 * 2323 * @param scanResults a list of {@link ScanResult}. 2324 * @return a list of {@link WifiConfiguration} from matched {@link WifiNetworkSuggestion}. 2325 */ 2326 @Override getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( List<ScanResult> scanResults)2327 public List<WifiConfiguration> getWifiConfigForMatchedNetworkSuggestionsSharedWithUser( 2328 List<ScanResult> scanResults) { 2329 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 2330 throw new SecurityException(TAG + ": Permission denied"); 2331 } 2332 if (mVerboseLoggingEnabled) { 2333 mLog.info("getWifiConfigsForMatchedNetworkSuggestions uid=%").c( 2334 Binder.getCallingUid()).flush(); 2335 } 2336 if (!ScanResultUtil.validateScanResultList(scanResults)) { 2337 Log.e(TAG, "Attempt to retrieve WifiConfiguration with invalid scanResult List"); 2338 return new ArrayList<>(); 2339 } 2340 return mWifiThreadRunner.call( 2341 () -> mWifiNetworkSuggestionsManager 2342 .getWifiConfigForMatchedNetworkSuggestionsSharedWithUser(scanResults), 2343 Collections.emptyList()); 2344 } 2345 2346 /** 2347 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 2348 * @return the supplicant-assigned identifier for the new or updated 2349 * network if the operation succeeds, or {@code -1} if it fails 2350 */ 2351 @Override addOrUpdateNetwork(WifiConfiguration config, String packageName)2352 public int addOrUpdateNetwork(WifiConfiguration config, String packageName) { 2353 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2354 return -1; 2355 } 2356 int callingUid = Binder.getCallingUid(); 2357 if (!isTargetSdkLessThanQOrPrivileged( 2358 packageName, Binder.getCallingPid(), callingUid)) { 2359 mLog.info("addOrUpdateNetwork not allowed for uid=%") 2360 .c(Binder.getCallingUid()).flush(); 2361 return -1; 2362 } 2363 mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush(); 2364 2365 if (config == null) { 2366 Log.e(TAG, "bad network configuration"); 2367 return -1; 2368 } 2369 mWifiMetrics.incrementNumAddOrUpdateNetworkCalls(); 2370 2371 // Previously, this API is overloaded for installing Passpoint profiles. Now 2372 // that we have a dedicated API for doing it, redirect the call to the dedicated API. 2373 if (config.isPasspoint()) { 2374 PasspointConfiguration passpointConfig = 2375 PasspointProvider.convertFromWifiConfig(config); 2376 if (passpointConfig == null || passpointConfig.getCredential() == null) { 2377 Log.e(TAG, "Missing credential for Passpoint profile"); 2378 return -1; 2379 } 2380 2381 // Copy over certificates and keys. 2382 X509Certificate[] x509Certificates = null; 2383 if (config.enterpriseConfig.getCaCertificate() != null) { 2384 x509Certificates = 2385 new X509Certificate[]{config.enterpriseConfig.getCaCertificate()}; 2386 } 2387 passpointConfig.getCredential().setCaCertificates(x509Certificates); 2388 passpointConfig.getCredential().setClientCertificateChain( 2389 config.enterpriseConfig.getClientCertificateChain()); 2390 passpointConfig.getCredential().setClientPrivateKey( 2391 config.enterpriseConfig.getClientPrivateKey()); 2392 if (!addOrUpdatePasspointConfiguration(passpointConfig, packageName)) { 2393 Log.e(TAG, "Failed to add Passpoint profile"); 2394 return -1; 2395 } 2396 // There is no network ID associated with a Passpoint profile. 2397 return 0; 2398 } 2399 2400 Log.i("addOrUpdateNetwork", " uid = " + Binder.getCallingUid() 2401 + " SSID " + config.SSID 2402 + " nid=" + config.networkId); 2403 return mWifiThreadRunner.call( 2404 () -> mWifiConfigManager.addOrUpdateNetwork(config, callingUid, packageName) 2405 .getNetworkId(), 2406 WifiConfiguration.INVALID_NETWORK_ID); 2407 } 2408 verifyCert(X509Certificate caCert)2409 public static void verifyCert(X509Certificate caCert) 2410 throws GeneralSecurityException, IOException { 2411 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 2412 CertPathValidator validator = 2413 CertPathValidator.getInstance(CertPathValidator.getDefaultType()); 2414 CertPath path = factory.generateCertPath( 2415 Arrays.asList(caCert)); 2416 KeyStore ks = KeyStore.getInstance("AndroidCAStore"); 2417 ks.load(null, null); 2418 PKIXParameters params = new PKIXParameters(ks); 2419 params.setRevocationEnabled(false); 2420 validator.validate(path, params); 2421 } 2422 2423 /** 2424 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 2425 * @param netId the integer that identifies the network configuration 2426 * to the supplicant 2427 * @return {@code true} if the operation succeeded 2428 */ 2429 @Override removeNetwork(int netId, String packageName)2430 public boolean removeNetwork(int netId, String packageName) { 2431 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2432 return false; 2433 } 2434 if (!isTargetSdkLessThanQOrPrivileged( 2435 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2436 mLog.info("removeNetwork not allowed for uid=%") 2437 .c(Binder.getCallingUid()).flush(); 2438 return false; 2439 } 2440 int callingUid = Binder.getCallingUid(); 2441 mLog.info("removeNetwork uid=%").c(callingUid).flush(); 2442 return mWifiThreadRunner.call( 2443 () -> mWifiConfigManager.removeNetwork(netId, callingUid, packageName), false); 2444 } 2445 2446 /** 2447 * Trigger a connect request and wait for the callback to return status. 2448 * This preserves the legacy connect API behavior, i.e. {@link WifiManager#enableNetwork( 2449 * int, true)} 2450 * @return 2451 */ triggerConnectAndReturnStatus(int netId, int callingUid)2452 private boolean triggerConnectAndReturnStatus(int netId, int callingUid) { 2453 final CountDownLatch countDownLatch = new CountDownLatch(1); 2454 final MutableBoolean success = new MutableBoolean(false); 2455 IActionListener.Stub connectListener = new IActionListener.Stub() { 2456 @Override 2457 public void onSuccess() { 2458 success.value = true; 2459 countDownLatch.countDown(); 2460 } 2461 @Override 2462 public void onFailure(int reason) { 2463 success.value = false; 2464 countDownLatch.countDown(); 2465 } 2466 }; 2467 mClientModeImpl.connect(null, netId, new Binder(), connectListener, 2468 connectListener.hashCode(), callingUid); 2469 // now wait for response. 2470 try { 2471 countDownLatch.await(RUN_WITH_SCISSORS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); 2472 } catch (InterruptedException e) { 2473 Log.e(TAG, "Failed to retrieve connect status"); 2474 } 2475 return success.value; 2476 } 2477 2478 /** 2479 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 2480 * @param netId the integer that identifies the network configuration 2481 * to the supplicant 2482 * @param disableOthers if true, disable all other networks. 2483 * @return {@code true} if the operation succeeded 2484 */ 2485 @Override enableNetwork(int netId, boolean disableOthers, String packageName)2486 public boolean enableNetwork(int netId, boolean disableOthers, String packageName) { 2487 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2488 return false; 2489 } 2490 if (!isTargetSdkLessThanQOrPrivileged( 2491 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2492 mLog.info("enableNetwork not allowed for uid=%") 2493 .c(Binder.getCallingUid()).flush(); 2494 return false; 2495 } 2496 int callingUid = Binder.getCallingUid(); 2497 // TODO b/33807876 Log netId 2498 mLog.info("enableNetwork uid=% disableOthers=%") 2499 .c(callingUid) 2500 .c(disableOthers).flush(); 2501 2502 mWifiMetrics.incrementNumEnableNetworkCalls(); 2503 if (disableOthers) { 2504 return triggerConnectAndReturnStatus(netId, callingUid); 2505 } else { 2506 return mWifiThreadRunner.call( 2507 () -> mWifiConfigManager.enableNetwork(netId, false, callingUid, packageName), 2508 false); 2509 } 2510 } 2511 2512 /** 2513 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 2514 * @param netId the integer that identifies the network configuration 2515 * to the supplicant 2516 * @return {@code true} if the operation succeeded 2517 */ 2518 @Override disableNetwork(int netId, String packageName)2519 public boolean disableNetwork(int netId, String packageName) { 2520 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2521 return false; 2522 } 2523 if (!isTargetSdkLessThanQOrPrivileged( 2524 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2525 mLog.info("disableNetwork not allowed for uid=%") 2526 .c(Binder.getCallingUid()).flush(); 2527 return false; 2528 } 2529 int callingUid = Binder.getCallingUid(); 2530 mLog.info("disableNetwork uid=%").c(callingUid).flush(); 2531 return mWifiThreadRunner.call( 2532 () -> mWifiConfigManager.disableNetwork(netId, callingUid, packageName), false); 2533 } 2534 2535 /** 2536 * See {@link android.net.wifi.WifiManager#allowAutojoinGlobal(boolean)} 2537 * @param choice the OEM's choice to allow auto-join 2538 */ 2539 @Override allowAutojoinGlobal(boolean choice)2540 public void allowAutojoinGlobal(boolean choice) { 2541 enforceNetworkSettingsPermission(); 2542 2543 int callingUid = Binder.getCallingUid(); 2544 mLog.info("allowAutojoin=% uid=%").c(choice).c(callingUid).flush(); 2545 2546 mWifiThreadRunner.post(() -> mClientModeImpl.allowAutoJoinGlobal(choice)); 2547 } 2548 2549 /** 2550 * See {@link android.net.wifi.WifiManager#allowAutojoin(int, boolean)} 2551 * @param netId the integer that identifies the network configuration 2552 * @param choice the user's choice to allow auto-join 2553 */ 2554 @Override allowAutojoin(int netId, boolean choice)2555 public void allowAutojoin(int netId, boolean choice) { 2556 enforceNetworkSettingsPermission(); 2557 2558 int callingUid = Binder.getCallingUid(); 2559 mLog.info("allowAutojoin=% uid=%").c(choice).c(callingUid).flush(); 2560 mWifiThreadRunner.post(() -> { 2561 WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId); 2562 if (config == null) { 2563 return; 2564 } 2565 if (config.fromWifiNetworkSpecifier) { 2566 Log.e(TAG, "Auto-join configuration is not permitted for NetworkSpecifier " 2567 + "connections: " + config); 2568 return; 2569 } 2570 if (config.isPasspoint() && !config.isEphemeral()) { 2571 Log.e(TAG, 2572 "Auto-join configuration for a non-ephemeral Passpoint network should be " 2573 + "configured using FQDN: " 2574 + config); 2575 return; 2576 } 2577 // If the network is a suggestion, store the auto-join configure to the 2578 // WifiNetWorkSuggestionsManager. 2579 if (config.fromWifiNetworkSuggestion) { 2580 if (!mWifiNetworkSuggestionsManager 2581 .allowNetworkSuggestionAutojoin(config, choice)) { 2582 return; 2583 } 2584 } 2585 // even for Suggestion, modify the current ephemeral configuration so that 2586 // existing configuration auto-connection is updated correctly 2587 if (choice != config.allowAutojoin) { 2588 mWifiConfigManager.allowAutojoin(netId, choice); 2589 // do not log this metrics for passpoint networks again here since it's already 2590 // logged in PasspointManager. 2591 if (!config.isPasspoint()) { 2592 mWifiMetrics.logUserActionEvent(choice 2593 ? UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON 2594 : UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF, netId); 2595 } 2596 } 2597 }); 2598 } 2599 2600 /** 2601 * See {@link android.net.wifi.WifiManager#allowAutojoinPasspoint(String, boolean)} 2602 * @param fqdn the FQDN that identifies the passpoint configuration 2603 * @param enableAutojoin true to enable auto-join, false to disable 2604 */ 2605 @Override allowAutojoinPasspoint(String fqdn, boolean enableAutojoin)2606 public void allowAutojoinPasspoint(String fqdn, boolean enableAutojoin) { 2607 enforceNetworkSettingsPermission(); 2608 if (fqdn == null) { 2609 throw new IllegalArgumentException("FQDN cannot be null"); 2610 } 2611 2612 int callingUid = Binder.getCallingUid(); 2613 mLog.info("allowAutojoinPasspoint=% uid=%").c(enableAutojoin).c(callingUid).flush(); 2614 mWifiThreadRunner.post( 2615 () -> mPasspointManager.enableAutojoin(null, fqdn, enableAutojoin)); 2616 } 2617 2618 /** 2619 * See {@link android.net.wifi.WifiManager 2620 * #setMacRandomizationSettingPasspointEnabled(String, boolean)} 2621 * @param fqdn the FQDN that identifies the passpoint configuration 2622 * @param enable true to enable mac randomization, false to disable 2623 */ 2624 @Override setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable)2625 public void setMacRandomizationSettingPasspointEnabled(String fqdn, boolean enable) { 2626 enforceNetworkSettingsPermission(); 2627 if (fqdn == null) { 2628 throw new IllegalArgumentException("FQDN cannot be null"); 2629 } 2630 2631 int callingUid = Binder.getCallingUid(); 2632 mLog.info("setMacRandomizationSettingPasspointEnabled=% uid=%") 2633 .c(enable).c(callingUid).flush(); 2634 mWifiThreadRunner.post( 2635 () -> mPasspointManager.enableMacRandomization(fqdn, enable)); 2636 } 2637 2638 /** 2639 * See {@link android.net.wifi.WifiManager#setPasspointMeteredOverride(String, boolean)} 2640 * @param fqdn the FQDN that identifies the passpoint configuration 2641 * @param meteredOverride One of the values in {@link MeteredOverride} 2642 */ 2643 @Override setPasspointMeteredOverride(String fqdn, int meteredOverride)2644 public void setPasspointMeteredOverride(String fqdn, int meteredOverride) { 2645 enforceNetworkSettingsPermission(); 2646 if (fqdn == null) { 2647 throw new IllegalArgumentException("FQDN cannot be null"); 2648 } 2649 2650 int callingUid = Binder.getCallingUid(); 2651 mLog.info("setPasspointMeteredOverride=% uid=%") 2652 .c(meteredOverride).c(callingUid).flush(); 2653 mWifiThreadRunner.post( 2654 () -> mPasspointManager.setMeteredOverride(fqdn, meteredOverride)); 2655 } 2656 2657 /** 2658 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 2659 * @return the Wi-Fi information, contained in {@link WifiInfo}. 2660 */ 2661 @Override getConnectionInfo(String callingPackage, String callingFeatureId)2662 public WifiInfo getConnectionInfo(String callingPackage, String callingFeatureId) { 2663 enforceAccessPermission(); 2664 int uid = Binder.getCallingUid(); 2665 if (mVerboseLoggingEnabled) { 2666 mLog.info("getConnectionInfo uid=%").c(uid).flush(); 2667 } 2668 long ident = Binder.clearCallingIdentity(); 2669 try { 2670 WifiInfo result = mClientModeImpl.syncRequestConnectionInfo(); 2671 boolean hideDefaultMacAddress = true; 2672 boolean hideBssidSsidNetworkIdAndFqdn = true; 2673 2674 try { 2675 if (mWifiInjector.getWifiPermissionsWrapper().getLocalMacAddressPermission(uid) 2676 == PERMISSION_GRANTED) { 2677 hideDefaultMacAddress = false; 2678 } 2679 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId, 2680 uid, null); 2681 hideBssidSsidNetworkIdAndFqdn = false; 2682 } catch (SecurityException ignored) { 2683 } 2684 if (hideDefaultMacAddress) { 2685 result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS); 2686 } 2687 if (hideBssidSsidNetworkIdAndFqdn) { 2688 result.setBSSID(WifiInfo.DEFAULT_MAC_ADDRESS); 2689 result.setSSID(WifiSsid.createFromHex(null)); 2690 result.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2691 result.setFQDN(null); 2692 result.setProviderFriendlyName(null); 2693 result.setPasspointUniqueId(null); 2694 } 2695 2696 if (mVerboseLoggingEnabled 2697 && (hideBssidSsidNetworkIdAndFqdn || hideDefaultMacAddress)) { 2698 mLog.v("getConnectionInfo: hideBssidSsidAndNetworkId=" 2699 + hideBssidSsidNetworkIdAndFqdn 2700 + ", hideDefaultMacAddress=" 2701 + hideDefaultMacAddress); 2702 } 2703 return result; 2704 } finally { 2705 Binder.restoreCallingIdentity(ident); 2706 } 2707 } 2708 2709 /** 2710 * Return the results of the most recent access point scan, in the form of 2711 * a list of {@link ScanResult} objects. 2712 * @return the list of results 2713 */ 2714 @Override getScanResults(String callingPackage, String callingFeatureId)2715 public List<ScanResult> getScanResults(String callingPackage, String callingFeatureId) { 2716 enforceAccessPermission(); 2717 int uid = Binder.getCallingUid(); 2718 long ident = Binder.clearCallingIdentity(); 2719 if (mVerboseLoggingEnabled) { 2720 mLog.info("getScanResults uid=%").c(uid).flush(); 2721 } 2722 try { 2723 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId, 2724 uid, null); 2725 List<ScanResult> scanResults = mWifiThreadRunner.call( 2726 mScanRequestProxy::getScanResults, Collections.emptyList()); 2727 return scanResults; 2728 } catch (SecurityException e) { 2729 Log.e(TAG, "Permission violation - getScanResults not allowed for uid=" 2730 + uid + ", packageName=" + callingPackage + ", reason=" + e); 2731 return new ArrayList<>(); 2732 } finally { 2733 Binder.restoreCallingIdentity(ident); 2734 } 2735 } 2736 2737 /** 2738 * Return the filtered ScanResults which may be authenticated by the suggested network 2739 * configurations. 2740 * @return The map of {@link WifiNetworkSuggestion} and the list of {@link ScanResult} which 2741 * may be authenticated by the corresponding network configuration. 2742 */ 2743 @Override 2744 @NonNull getMatchingScanResults( @onNull List<WifiNetworkSuggestion> networkSuggestions, @Nullable List<ScanResult> scanResults, String callingPackage, String callingFeatureId)2745 public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults( 2746 @NonNull List<WifiNetworkSuggestion> networkSuggestions, 2747 @Nullable List<ScanResult> scanResults, 2748 String callingPackage, String callingFeatureId) { 2749 enforceAccessPermission(); 2750 int uid = Binder.getCallingUid(); 2751 long ident = Binder.clearCallingIdentity(); 2752 try { 2753 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, callingFeatureId, 2754 uid, null); 2755 2756 return mWifiThreadRunner.call( 2757 () -> { 2758 if (!ScanResultUtil.validateScanResultList(scanResults)) { 2759 return mWifiNetworkSuggestionsManager.getMatchingScanResults( 2760 networkSuggestions, mScanRequestProxy.getScanResults()); 2761 } else { 2762 return mWifiNetworkSuggestionsManager.getMatchingScanResults( 2763 networkSuggestions, scanResults); 2764 } 2765 }, 2766 Collections.emptyMap()); 2767 } catch (SecurityException e) { 2768 Log.e(TAG, "Permission violation - getMatchingScanResults not allowed for uid=" 2769 + uid + ", packageName=" + callingPackage + ", reason + e"); 2770 } finally { 2771 Binder.restoreCallingIdentity(ident); 2772 } 2773 2774 return Collections.emptyMap(); 2775 } 2776 2777 /** 2778 * Add or update a Passpoint configuration. 2779 * 2780 * @param config The Passpoint configuration to be added 2781 * @return true on success or false on failure 2782 */ 2783 @Override 2784 public boolean addOrUpdatePasspointConfiguration( 2785 PasspointConfiguration config, String packageName) { 2786 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2787 return false; 2788 } 2789 int callingUid = Binder.getCallingUid(); 2790 if (!isTargetSdkLessThanROrPrivileged( 2791 packageName, Binder.getCallingPid(), callingUid)) { 2792 mLog.info("addOrUpdatePasspointConfiguration not allowed for uid=%") 2793 .c(Binder.getCallingUid()).flush(); 2794 return false; 2795 } 2796 mLog.info("addorUpdatePasspointConfiguration uid=%").c(callingUid).flush(); 2797 return mWifiThreadRunner.call( 2798 () -> mPasspointManager.addOrUpdateProvider(config, callingUid, packageName, 2799 false, true), false); 2800 } 2801 2802 /** 2803 * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name). 2804 * 2805 * @param fqdn The FQDN of the Passpoint configuration to be removed 2806 * @return true on success or false on failure 2807 */ 2808 @Override 2809 public boolean removePasspointConfiguration(String fqdn, String packageName) { 2810 return removePasspointConfigurationInternal(fqdn, null); 2811 } 2812 2813 /** 2814 * Remove a Passpoint profile based on either FQDN (multiple matching profiles) or a unique 2815 * identifier (one matching profile). 2816 * 2817 * @param fqdn The FQDN of the Passpoint configuration to be removed 2818 * @param uniqueId The unique identifier of the Passpoint configuration to be removed 2819 * @return true on success or false on failure 2820 */ 2821 private boolean removePasspointConfigurationInternal(String fqdn, String uniqueId) { 2822 final int uid = Binder.getCallingUid(); 2823 boolean privileged = false; 2824 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) 2825 || mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(uid)) { 2826 privileged = true; 2827 } 2828 mLog.info("removePasspointConfigurationInternal uid=%").c(Binder.getCallingUid()).flush(); 2829 final boolean privilegedFinal = privileged; 2830 return mWifiThreadRunner.call( 2831 () -> mPasspointManager.removeProvider(uid, privilegedFinal, uniqueId, fqdn), 2832 false); 2833 } 2834 2835 /** 2836 * Return the list of the installed Passpoint configurations. 2837 * 2838 * An empty list will be returned when no configuration is installed. 2839 * @param packageName String name of the calling package 2840 * @return A list of {@link PasspointConfiguration}. 2841 */ 2842 @Override 2843 public List<PasspointConfiguration> getPasspointConfigurations(String packageName) { 2844 final int uid = Binder.getCallingUid(); 2845 boolean privileged = false; 2846 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) 2847 || mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) { 2848 privileged = true; 2849 } 2850 if (mVerboseLoggingEnabled) { 2851 mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush(); 2852 } 2853 final boolean privilegedFinal = privileged; 2854 return mWifiThreadRunner.call( 2855 () -> mPasspointManager.getProviderConfigs(uid, privilegedFinal), 2856 Collections.emptyList()); 2857 } 2858 2859 /** 2860 * Query for a Hotspot 2.0 release 2 OSU icon 2861 * @param bssid The BSSID of the AP 2862 * @param fileName Icon file name 2863 */ 2864 @Override 2865 public void queryPasspointIcon(long bssid, String fileName) { 2866 enforceAccessPermission(); 2867 mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush(); 2868 mClientModeImpl.syncQueryPasspointIcon(mClientModeImplChannel, bssid, fileName); 2869 } 2870 2871 /** 2872 * Match the currently associated network against the SP matching the given FQDN 2873 * @param fqdn FQDN of the SP 2874 * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined] 2875 */ 2876 @Override 2877 public int matchProviderWithCurrentNetwork(String fqdn) { 2878 mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush(); 2879 return 0; 2880 } 2881 2882 /** 2883 * Deauthenticate and set the re-authentication hold off time for the current network 2884 * @param holdoff hold off time in milliseconds 2885 * @param ess set if the hold off pertains to an ESS rather than a BSS 2886 */ 2887 @Override 2888 public void deauthenticateNetwork(long holdoff, boolean ess) { 2889 mLog.info("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush(); 2890 mClientModeImpl.deauthenticateNetwork(mClientModeImplChannel, holdoff, ess); 2891 } 2892 2893 /** 2894 * Get the country code 2895 * @return Get the best choice country code for wifi, regardless of if it was set or 2896 * not. 2897 * Returns null when there is no country code available. 2898 */ 2899 @Override 2900 public String getCountryCode() { 2901 enforceNetworkSettingsPermission(); 2902 if (mVerboseLoggingEnabled) { 2903 mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush(); 2904 } 2905 return mCountryCode.getCountryCode(); 2906 } 2907 2908 @Override 2909 public boolean is5GHzBandSupported() { 2910 if (mVerboseLoggingEnabled) { 2911 mLog.info("is5GHzBandSupported uid=%").c(Binder.getCallingUid()).flush(); 2912 } 2913 2914 return is5GhzBandSupportedInternal(); 2915 } 2916 2917 private boolean is5GhzBandSupportedInternal() { 2918 return mWifiThreadRunner.call( 2919 () -> mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_5_GHZ), false); 2920 } 2921 2922 @Override 2923 public boolean is6GHzBandSupported() { 2924 if (mVerboseLoggingEnabled) { 2925 mLog.info("is6GHzBandSupported uid=%").c(Binder.getCallingUid()).flush(); 2926 } 2927 2928 return is6GhzBandSupportedInternal(); 2929 } 2930 2931 private boolean is6GhzBandSupportedInternal() { 2932 return mWifiThreadRunner.call( 2933 () -> mClientModeImpl.isWifiBandSupported(WifiScanner.WIFI_BAND_6_GHZ), false); 2934 } 2935 2936 @Override 2937 public boolean isWifiStandardSupported(@WifiStandard int standard) { 2938 return mWifiThreadRunner.call( 2939 () -> mClientModeImpl.isWifiStandardSupported(standard), false); 2940 } 2941 2942 /** 2943 * Return the DHCP-assigned addresses from the last successful DHCP request, 2944 * if any. 2945 * @return the DHCP information 2946 * @deprecated 2947 */ 2948 @Override 2949 @Deprecated 2950 public DhcpInfo getDhcpInfo() { 2951 enforceAccessPermission(); 2952 if (mVerboseLoggingEnabled) { 2953 mLog.info("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush(); 2954 } 2955 DhcpResultsParcelable dhcpResults = mClientModeImpl.syncGetDhcpResultsParcelable(); 2956 2957 DhcpInfo info = new DhcpInfo(); 2958 2959 if (dhcpResults.baseConfiguration != null) { 2960 if (dhcpResults.baseConfiguration.getIpAddress() != null 2961 && dhcpResults.baseConfiguration.getIpAddress().getAddress() 2962 instanceof Inet4Address) { 2963 info.ipAddress = Inet4AddressUtils.inet4AddressToIntHTL( 2964 (Inet4Address) dhcpResults.baseConfiguration.getIpAddress().getAddress()); 2965 } 2966 2967 if (dhcpResults.baseConfiguration.getGateway() != null) { 2968 info.gateway = Inet4AddressUtils.inet4AddressToIntHTL( 2969 (Inet4Address) dhcpResults.baseConfiguration.getGateway()); 2970 } 2971 2972 int dnsFound = 0; 2973 for (InetAddress dns : dhcpResults.baseConfiguration.getDnsServers()) { 2974 if (dns instanceof Inet4Address) { 2975 if (dnsFound == 0) { 2976 info.dns1 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns); 2977 } else { 2978 info.dns2 = Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) dns); 2979 } 2980 if (++dnsFound > 1) break; 2981 } 2982 } 2983 } 2984 String serverAddress = dhcpResults.serverAddress; 2985 if (serverAddress != null) { 2986 InetAddress serverInetAddress = InetAddresses.parseNumericAddress(serverAddress); 2987 info.serverAddress = 2988 Inet4AddressUtils.inet4AddressToIntHTL((Inet4Address) serverInetAddress); 2989 } 2990 info.leaseDuration = dhcpResults.leaseDuration; 2991 2992 return info; 2993 } 2994 2995 /** 2996 * enable TDLS for the local NIC to remote NIC 2997 * The APPs don't know the remote MAC address to identify NIC though, 2998 * so we need to do additional work to find it from remote IP address 2999 */ 3000 3001 private static class TdlsTaskParams { 3002 String mRemoteIpAddress; 3003 boolean mEnable; 3004 } 3005 3006 private class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> { 3007 @Override 3008 protected Integer doInBackground(TdlsTaskParams... params) { 3009 3010 // Retrieve parameters for the call 3011 TdlsTaskParams param = params[0]; 3012 String remoteIpAddress = param.mRemoteIpAddress.trim(); 3013 boolean enable = param.mEnable; 3014 3015 // Get MAC address of Remote IP 3016 String macAddress = null; 3017 3018 try (BufferedReader reader = new BufferedReader(new FileReader("/proc/net/arp"))) { 3019 // Skip over the line bearing column titles 3020 reader.readLine(); 3021 3022 String line; 3023 while ((line = reader.readLine()) != null) { 3024 String[] tokens = line.split("[ ]+"); 3025 if (tokens.length < 6) { 3026 continue; 3027 } 3028 3029 // ARP column format is 3030 // Address HWType HWAddress Flags Mask IFace 3031 String ip = tokens[0]; 3032 String mac = tokens[3]; 3033 3034 if (remoteIpAddress.equals(ip)) { 3035 macAddress = mac; 3036 break; 3037 } 3038 } 3039 3040 if (macAddress == null) { 3041 Log.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " 3042 + "/proc/net/arp"); 3043 } else { 3044 enableTdlsWithMacAddress(macAddress, enable); 3045 } 3046 3047 } catch (FileNotFoundException e) { 3048 Log.e(TAG, "Could not open /proc/net/arp to lookup mac address"); 3049 } catch (IOException e) { 3050 Log.e(TAG, "Could not read /proc/net/arp to lookup mac address"); 3051 } 3052 return 0; 3053 } 3054 } 3055 3056 @Override 3057 public void enableTdls(String remoteAddress, boolean enable) { 3058 if (remoteAddress == null) { 3059 throw new IllegalArgumentException("remoteAddress cannot be null"); 3060 } 3061 mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush(); 3062 TdlsTaskParams params = new TdlsTaskParams(); 3063 params.mRemoteIpAddress = remoteAddress; 3064 params.mEnable = enable; 3065 new TdlsTask().execute(params); 3066 } 3067 3068 3069 @Override 3070 public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) { 3071 mLog.info("enableTdlsWithMacAddress uid=% enable=%") 3072 .c(Binder.getCallingUid()) 3073 .c(enable) 3074 .flush(); 3075 if (remoteMacAddress == null) { 3076 throw new IllegalArgumentException("remoteMacAddress cannot be null"); 3077 } 3078 3079 mClientModeImpl.enableTdls(remoteMacAddress, enable); 3080 } 3081 3082 /** 3083 * Temporarily disable a network, should be trigger when user disconnect a network 3084 */ 3085 @Override 3086 public void disableEphemeralNetwork(String network, String packageName) { 3087 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 3088 "WifiService"); 3089 if (!isPrivileged(Binder.getCallingPid(), Binder.getCallingUid())) { 3090 mLog.info("disableEphemeralNetwork not allowed for uid=%") 3091 .c(Binder.getCallingUid()).flush(); 3092 return; 3093 } 3094 mLog.info("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush(); 3095 mWifiThreadRunner.post(() -> mWifiConfigManager.userTemporarilyDisabledNetwork(network, 3096 Binder.getCallingUid())); 3097 } 3098 3099 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 3100 @Override 3101 public void onReceive(Context context, Intent intent) { 3102 String action = intent.getAction(); 3103 if (action.equals(Intent.ACTION_USER_REMOVED)) { 3104 UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); 3105 if (userHandle == null) { 3106 Log.e(TAG, "User removed broadcast received with no user handle"); 3107 return; 3108 } 3109 mWifiThreadRunner.post(() -> 3110 mWifiConfigManager.removeNetworksForUser(userHandle.getIdentifier())); 3111 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { 3112 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 3113 BluetoothAdapter.STATE_DISCONNECTED); 3114 mClientModeImpl.sendBluetoothAdapterConnectionStateChange(state); 3115 } else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { 3116 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 3117 BluetoothAdapter.STATE_OFF); 3118 mClientModeImpl.sendBluetoothAdapterStateChange(state); 3119 } else if (action.equals(TelephonyManager.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 3120 boolean emergencyMode = 3121 intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false); 3122 mActiveModeWarden.emergencyCallbackModeChanged(emergencyMode); 3123 } else if (action.equals(TelephonyManager.ACTION_EMERGENCY_CALL_STATE_CHANGED)) { 3124 boolean inCall = 3125 intent.getBooleanExtra( 3126 TelephonyManager.EXTRA_PHONE_IN_EMERGENCY_CALL, false); 3127 mActiveModeWarden.emergencyCallStateChanged(inCall); 3128 } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) { 3129 handleIdleModeChanged(); 3130 } else if (action.equals(Intent.ACTION_SHUTDOWN)) { 3131 handleShutDown(); 3132 } 3133 } 3134 }; 3135 3136 private void registerForBroadcasts() { 3137 IntentFilter intentFilter = new IntentFilter(); 3138 intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); 3139 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 3140 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 3141 intentFilter.addDataScheme("package"); 3142 mContext.registerReceiver(new BroadcastReceiver() { 3143 @Override 3144 public void onReceive(Context context, Intent intent) { 3145 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 3146 Uri uri = intent.getData(); 3147 if (uid == -1 || uri == null) { 3148 Log.e(TAG, "Uid or Uri is missing for action:" + intent.getAction()); 3149 return; 3150 } 3151 String pkgName = uri.getSchemeSpecificPart(); 3152 PackageManager pm = context.getPackageManager(); 3153 PackageInfo packageInfo = null; 3154 try { 3155 packageInfo = pm.getPackageInfo(pkgName, 0); 3156 } catch (PackageManager.NameNotFoundException e) { 3157 Log.w(TAG, "Couldn't get PackageInfo for package:" + pkgName); 3158 } 3159 // If package is not removed or disabled, just ignore. 3160 if (packageInfo != null 3161 && packageInfo.applicationInfo != null 3162 && packageInfo.applicationInfo.enabled) { 3163 return; 3164 } 3165 Log.d(TAG, "Remove settings for package:" + pkgName); 3166 // Call the method in the main Wifi thread. 3167 mWifiThreadRunner.post(() -> { 3168 ApplicationInfo ai = new ApplicationInfo(); 3169 ai.packageName = pkgName; 3170 ai.uid = uid; 3171 mWifiConfigManager.removeNetworksForApp(ai); 3172 mScanRequestProxy.clearScanRequestTimestampsForApp(pkgName, uid); 3173 3174 // Remove all suggestions from the package. 3175 mWifiNetworkSuggestionsManager.removeApp(pkgName); 3176 mClientModeImpl.removeNetworkRequestUserApprovedAccessPointsForApp(pkgName); 3177 3178 // Remove all Passpoint profiles from package. 3179 mWifiInjector.getPasspointManager().removePasspointProviderWithPackage( 3180 pkgName); 3181 }); 3182 } 3183 }, intentFilter); 3184 } 3185 3186 private void registerForCarrierConfigChange() { 3187 IntentFilter filter = new IntentFilter(); 3188 filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); 3189 mContext.registerReceiver(new BroadcastReceiver() { 3190 @Override 3191 public void onReceive(Context context, Intent intent) { 3192 final int subId = SubscriptionManager.getActiveDataSubscriptionId(); 3193 Log.d(TAG, "ACTION_CARRIER_CONFIG_CHANGED, active subId: " + subId); 3194 3195 mTetheredSoftApTracker.updateSoftApCapability(subId); 3196 mActiveModeWarden.updateSoftApCapability( 3197 mTetheredSoftApTracker.getSoftApCapability()); 3198 } 3199 }, filter); 3200 3201 WifiPhoneStateListener phoneStateListener = new WifiPhoneStateListener( 3202 mWifiInjector.getWifiHandlerThread().getLooper()); 3203 3204 mContext.getSystemService(TelephonyManager.class).listen( 3205 phoneStateListener, PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE); 3206 } 3207 3208 @Override 3209 public int handleShellCommand(@NonNull ParcelFileDescriptor in, 3210 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, 3211 @NonNull String[] args) { 3212 return new WifiShellCommand(mWifiInjector, this, mContext).exec( 3213 this, in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), 3214 args); 3215 } 3216 3217 private void updateWifiMetrics() { 3218 mWifiThreadRunner.run(() -> { 3219 mWifiMetrics.updateSavedNetworks( 3220 mWifiConfigManager.getSavedNetworks(Process.WIFI_UID)); 3221 mPasspointManager.updateMetrics(); 3222 }); 3223 boolean isEnhancedMacRandEnabled = mFrameworkFacade.getIntegerSetting(mContext, 3224 WifiConfigManager.ENHANCED_MAC_RANDOMIZATION_FEATURE_FORCE_ENABLE_FLAG, 0) == 1 3225 ? true : false; 3226 mWifiMetrics.setEnhancedMacRandomizationForceEnabled(isEnhancedMacRandEnabled); 3227 mWifiMetrics.setIsScanningAlwaysEnabled(mSettingsStore.isScanAlwaysAvailable()); 3228 mWifiMetrics.setVerboseLoggingEnabled(mVerboseLoggingEnabled); 3229 mWifiMetrics.setWifiWakeEnabled(mWifiInjector.getWakeupController().isEnabled()); 3230 } 3231 3232 @Override 3233 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3234 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 3235 != PERMISSION_GRANTED) { 3236 pw.println("Permission Denial: can't dump WifiService from from pid=" 3237 + Binder.getCallingPid() 3238 + ", uid=" + Binder.getCallingUid()); 3239 return; 3240 } 3241 if (args != null && args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) { 3242 // WifiMetrics proto bytes were requested. Dump only these. 3243 updateWifiMetrics(); 3244 mWifiMetrics.dump(fd, pw, args); 3245 } else if (args != null && args.length > 0 && IpClientUtil.DUMP_ARG.equals(args[0])) { 3246 // IpClient dump was requested. Pass it along and take no further action. 3247 String[] ipClientArgs = new String[args.length - 1]; 3248 System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length); 3249 mClientModeImpl.dumpIpClient(fd, pw, ipClientArgs); 3250 } else if (args != null && args.length > 0 && WifiScoreReport.DUMP_ARG.equals(args[0])) { 3251 WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport(); 3252 if (wifiScoreReport != null) wifiScoreReport.dump(fd, pw, args); 3253 } else if (args != null && args.length > 0 && WifiScoreCard.DUMP_ARG.equals(args[0])) { 3254 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard(); 3255 String networkListBase64 = mWifiThreadRunner.call(() -> 3256 wifiScoreCard.getNetworkListBase64(true), ""); 3257 pw.println(networkListBase64); 3258 } else { 3259 // Polls link layer stats and RSSI. This allows the stats to show up in 3260 // WifiScoreReport's dump() output when taking a bug report even if the screen is off. 3261 mClientModeImpl.updateLinkLayerStatsRssiAndScoreReport(); 3262 pw.println("Wi-Fi is " + mClientModeImpl.syncGetWifiStateByName()); 3263 pw.println("Verbose logging is " + (mVerboseLoggingEnabled ? "on" : "off")); 3264 pw.println("Stay-awake conditions: " + 3265 mFacade.getIntegerSetting(mContext, 3266 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); 3267 pw.println("mInIdleMode " + mInIdleMode); 3268 pw.println("mScanPending " + mScanPending); 3269 mSettingsStore.dump(fd, pw, args); 3270 mWifiTrafficPoller.dump(fd, pw, args); 3271 pw.println(); 3272 pw.println("Locks held:"); 3273 mWifiLockManager.dump(pw); 3274 pw.println(); 3275 mWifiMulticastLockManager.dump(pw); 3276 pw.println(); 3277 mActiveModeWarden.dump(fd, pw, args); 3278 pw.println(); 3279 mClientModeImpl.dump(fd, pw, args); 3280 pw.println(); 3281 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard(); 3282 String networkListBase64 = mWifiThreadRunner.call(() -> 3283 wifiScoreCard.getNetworkListBase64(true), ""); 3284 pw.println("WifiScoreCard:"); 3285 pw.println(networkListBase64); 3286 3287 updateWifiMetrics(); 3288 mWifiMetrics.dump(fd, pw, args); 3289 3290 pw.println(); 3291 mWifiThreadRunner.run(() -> mWifiNetworkSuggestionsManager.dump(fd, pw, args)); 3292 pw.println(); 3293 mWifiBackupRestore.dump(fd, pw, args); 3294 pw.println(); 3295 pw.println("ScoringParams: " + mWifiInjector.getScoringParams()); 3296 pw.println(); 3297 pw.println("WifiScoreReport:"); 3298 WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport(); 3299 wifiScoreReport.dump(fd, pw, args); 3300 pw.println(); 3301 SarManager sarManager = mWifiInjector.getSarManager(); 3302 sarManager.dump(fd, pw, args); 3303 pw.println(); 3304 mWifiThreadRunner.run(() -> { 3305 mWifiInjector.getWifiNetworkScoreCache().dumpWithLatestScanResults( 3306 fd, pw, args, mScanRequestProxy.getScanResults()); 3307 mWifiInjector.getSettingsConfigStore().dump(fd, pw, args); 3308 }); 3309 pw.println(); 3310 } 3311 } 3312 3313 @Override 3314 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { 3315 mLog.info("acquireWifiLock uid=% lockMode=%") 3316 .c(Binder.getCallingUid()) 3317 .c(lockMode).flush(); 3318 3319 // Check on permission to make this call 3320 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 3321 3322 // If no UID is provided in worksource, use the calling UID 3323 WorkSource updatedWs = (ws == null || ws.isEmpty()) 3324 ? new WorkSource(Binder.getCallingUid()) : ws; 3325 3326 if (!WifiLockManager.isValidLockMode(lockMode)) { 3327 throw new IllegalArgumentException("lockMode =" + lockMode); 3328 } 3329 3330 return mWifiThreadRunner.call(() -> 3331 mWifiLockManager.acquireWifiLock(lockMode, tag, binder, updatedWs), false); 3332 } 3333 3334 @Override 3335 public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) { 3336 mLog.info("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush(); 3337 3338 // Check on permission to make this call 3339 mContext.enforceCallingOrSelfPermission( 3340 android.Manifest.permission.UPDATE_DEVICE_STATS, null); 3341 3342 // If no UID is provided in worksource, use the calling UID 3343 WorkSource updatedWs = (ws == null || ws.isEmpty()) 3344 ? new WorkSource(Binder.getCallingUid()) : ws; 3345 3346 mWifiThreadRunner.run(() -> 3347 mWifiLockManager.updateWifiLockWorkSource(binder, updatedWs)); 3348 } 3349 3350 @Override 3351 public boolean releaseWifiLock(IBinder binder) { 3352 mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush(); 3353 3354 // Check on permission to make this call 3355 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 3356 3357 return mWifiThreadRunner.call(() -> 3358 mWifiLockManager.releaseWifiLock(binder), false); 3359 } 3360 3361 @Override 3362 public void initializeMulticastFiltering() { 3363 enforceMulticastChangePermission(); 3364 mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush(); 3365 mWifiMulticastLockManager.initializeFiltering(); 3366 } 3367 3368 @Override 3369 public void acquireMulticastLock(IBinder binder, String tag) { 3370 enforceMulticastChangePermission(); 3371 mLog.info("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush(); 3372 mWifiMulticastLockManager.acquireLock(binder, tag); 3373 } 3374 3375 @Override 3376 public void releaseMulticastLock(String tag) { 3377 enforceMulticastChangePermission(); 3378 mLog.info("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush(); 3379 mWifiMulticastLockManager.releaseLock(tag); 3380 } 3381 3382 @Override 3383 public boolean isMulticastEnabled() { 3384 enforceAccessPermission(); 3385 if (mVerboseLoggingEnabled) { 3386 mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush(); 3387 } 3388 return mWifiMulticastLockManager.isMulticastEnabled(); 3389 } 3390 3391 @Override 3392 public void enableVerboseLogging(int verbose) { 3393 enforceAccessPermission(); 3394 enforceNetworkSettingsPermission(); 3395 mLog.info("enableVerboseLogging uid=% verbose=%") 3396 .c(Binder.getCallingUid()) 3397 .c(verbose).flush(); 3398 mWifiInjector.getSettingsConfigStore().put(WIFI_VERBOSE_LOGGING_ENABLED, verbose > 0); 3399 enableVerboseLoggingInternal(verbose); 3400 } 3401 3402 private void enableVerboseLoggingInternal(int verbose) { 3403 mVerboseLoggingEnabled = verbose > 0; 3404 mClientModeImpl.enableVerboseLogging(verbose); 3405 mWifiLockManager.enableVerboseLogging(verbose); 3406 mWifiMulticastLockManager.enableVerboseLogging(verbose); 3407 mWifiInjector.enableVerboseLogging(verbose); 3408 } 3409 3410 @Override 3411 public int getVerboseLoggingLevel() { 3412 if (mVerboseLoggingEnabled) { 3413 mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush(); 3414 } 3415 return mWifiInjector.getSettingsConfigStore().get(WIFI_VERBOSE_LOGGING_ENABLED) ? 1 : 0; 3416 } 3417 3418 @Override 3419 public void factoryReset(String packageName) { 3420 enforceNetworkSettingsPermission(); 3421 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 3422 return; 3423 } 3424 mLog.info("factoryReset uid=%").c(Binder.getCallingUid()).flush(); 3425 if (mUserManager.hasUserRestrictionForUser( 3426 UserManager.DISALLOW_NETWORK_RESET, 3427 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) { 3428 return; 3429 } 3430 if (!mUserManager.hasUserRestrictionForUser( 3431 UserManager.DISALLOW_CONFIG_TETHERING, 3432 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) { 3433 // Turn mobile hotspot off 3434 stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED); 3435 } 3436 3437 if (mUserManager.hasUserRestrictionForUser( 3438 UserManager.DISALLOW_CONFIG_WIFI, 3439 UserHandle.getUserHandleForUid(Binder.getCallingUid()))) { 3440 return; 3441 } 3442 // Delete all Wifi SSIDs 3443 List<WifiConfiguration> networks = mWifiThreadRunner.call( 3444 () -> mWifiConfigManager.getSavedNetworks(Process.WIFI_UID), 3445 Collections.emptyList()); 3446 for (WifiConfiguration network : networks) { 3447 removeNetwork(network.networkId, packageName); 3448 } 3449 // Delete all Passpoint configurations 3450 List<PasspointConfiguration> configs = mWifiThreadRunner.call( 3451 () -> mPasspointManager.getProviderConfigs(Process.WIFI_UID /* ignored */, true), 3452 Collections.emptyList()); 3453 for (PasspointConfiguration config : configs) { 3454 removePasspointConfigurationInternal(null, config.getUniqueId()); 3455 } 3456 mWifiThreadRunner.post(() -> { 3457 mPasspointManager.clearAnqpRequestsAndFlushCache(); 3458 mWifiConfigManager.clearUserTemporarilyDisabledList(); 3459 mWifiConfigManager.removeAllEphemeralOrPasspointConfiguredNetworks(); 3460 mClientModeImpl.clearNetworkRequestUserApprovedAccessPoints(); 3461 mWifiNetworkSuggestionsManager.clear(); 3462 mWifiInjector.getWifiScoreCard().clear(); 3463 mWifiInjector.getWifiHealthMonitor().clear(); 3464 notifyFactoryReset(); 3465 }); 3466 } 3467 3468 /** 3469 * Notify the Factory Reset Event to application who may installed wifi configurations. 3470 */ 3471 private void notifyFactoryReset() { 3472 Intent intent = new Intent(WifiManager.ACTION_NETWORK_SETTINGS_RESET); 3473 3474 // Retrieve list of broadcast receivers for this broadcast & send them directed broadcasts 3475 // to wake them up (if they're in background). 3476 List<ResolveInfo> resolveInfos = 3477 mContext.getPackageManager().queryBroadcastReceiversAsUser( 3478 intent, 0, 3479 UserHandle.of(mWifiInjector.getWifiPermissionsWrapper().getCurrentUser())); 3480 if (resolveInfos == null || resolveInfos.isEmpty()) return; // No need to send broadcast. 3481 3482 for (ResolveInfo resolveInfo : resolveInfos) { 3483 Intent intentToSend = new Intent(intent); 3484 intentToSend.setComponent(new ComponentName( 3485 resolveInfo.activityInfo.applicationInfo.packageName, 3486 resolveInfo.activityInfo.name)); 3487 mContext.sendBroadcastAsUser(intentToSend, UserHandle.ALL, 3488 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING); 3489 } 3490 } 3491 3492 @Override 3493 public Network getCurrentNetwork() { 3494 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 3495 throw new SecurityException(TAG + ": Permission denied"); 3496 } 3497 if (mVerboseLoggingEnabled) { 3498 mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush(); 3499 } 3500 return mClientModeImpl.syncGetCurrentNetwork(mClientModeImplChannel); 3501 } 3502 3503 public static String toHexString(String s) { 3504 if (s == null) { 3505 return "null"; 3506 } 3507 StringBuilder sb = new StringBuilder(); 3508 sb.append('\'').append(s).append('\''); 3509 for (int n = 0; n < s.length(); n++) { 3510 sb.append(String.format(" %02x", s.charAt(n) & 0xffff)); 3511 } 3512 return sb.toString(); 3513 } 3514 3515 /** 3516 * Retrieve the data to be backed to save the current state. 3517 * 3518 * @return Raw byte stream of the data to be backed up. 3519 */ 3520 @Override 3521 public byte[] retrieveBackupData() { 3522 enforceNetworkSettingsPermission(); 3523 mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush(); 3524 if (mClientModeImplChannel == null) { 3525 Log.e(TAG, "mClientModeImplChannel is not initialized"); 3526 return null; 3527 } 3528 3529 Log.d(TAG, "Retrieving backup data"); 3530 List<WifiConfiguration> wifiConfigurations = mWifiThreadRunner.call( 3531 () -> mWifiConfigManager.getConfiguredNetworksWithPasswords(), null); 3532 byte[] backupData = 3533 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations); 3534 Log.d(TAG, "Retrieved backup data"); 3535 return backupData; 3536 } 3537 3538 /** 3539 * Helper method to restore networks retrieved from backup data. 3540 * 3541 * @param configurations list of WifiConfiguration objects parsed from the backup data. 3542 */ 3543 private void restoreNetworks(List<WifiConfiguration> configurations) { 3544 if (configurations == null) { 3545 Log.e(TAG, "Backup data parse failed"); 3546 return; 3547 } 3548 int callingUid = Binder.getCallingUid(); 3549 mWifiThreadRunner.run( 3550 () -> { 3551 for (WifiConfiguration configuration : configurations) { 3552 int networkId = 3553 mWifiConfigManager.addOrUpdateNetwork(configuration, callingUid) 3554 .getNetworkId(); 3555 if (networkId == WifiConfiguration.INVALID_NETWORK_ID) { 3556 Log.e(TAG, "Restore network failed: " + configuration.getKey()); 3557 continue; 3558 } 3559 // Enable all networks restored. 3560 mWifiConfigManager.enableNetwork(networkId, false, callingUid, null); 3561 // Restore auto-join param. 3562 mWifiConfigManager.allowAutojoin(networkId, configuration.allowAutojoin); 3563 } 3564 }); 3565 } 3566 3567 /** 3568 * Restore state from the backed up data. 3569 * 3570 * @param data Raw byte stream of the backed up data. 3571 */ 3572 @Override 3573 public void restoreBackupData(byte[] data) { 3574 enforceNetworkSettingsPermission(); 3575 mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush(); 3576 if (mClientModeImplChannel == null) { 3577 Log.e(TAG, "mClientModeImplChannel is not initialized"); 3578 return; 3579 } 3580 3581 Log.d(TAG, "Restoring backup data"); 3582 List<WifiConfiguration> wifiConfigurations = 3583 mWifiBackupRestore.retrieveConfigurationsFromBackupData(data); 3584 restoreNetworks(wifiConfigurations); 3585 Log.d(TAG, "Restored backup data"); 3586 } 3587 3588 /** 3589 * Retrieve the soft ap config data to be backed to save current config data. 3590 * 3591 * @return Raw byte stream of the data to be backed up. 3592 */ 3593 @Override 3594 public byte[] retrieveSoftApBackupData() { 3595 enforceNetworkSettingsPermission(); 3596 mLog.info("retrieveSoftApBackupData uid=%").c(Binder.getCallingUid()).flush(); 3597 SoftApConfiguration config = mWifiThreadRunner.call(mWifiApConfigStore::getApConfiguration, 3598 new SoftApConfiguration.Builder().build()); 3599 byte[] backupData = 3600 mSoftApBackupRestore.retrieveBackupDataFromSoftApConfiguration(config); 3601 Log.d(TAG, "Retrieved soft ap backup data"); 3602 return backupData; 3603 } 3604 3605 /** 3606 * Restore soft ap config from the backed up data. 3607 * 3608 * @param data Raw byte stream of the backed up data. 3609 * @return restored SoftApConfiguration or Null if data is invalid. 3610 */ 3611 @Override 3612 public SoftApConfiguration restoreSoftApBackupData(byte[] data) { 3613 enforceNetworkSettingsPermission(); 3614 mLog.info("restoreSoftApBackupData uid=%").c(Binder.getCallingUid()).flush(); 3615 SoftApConfiguration softApConfig = 3616 mSoftApBackupRestore.retrieveSoftApConfigurationFromBackupData(data); 3617 if (softApConfig != null) { 3618 mWifiThreadRunner.post(() -> mWifiApConfigStore.setApConfiguration( 3619 mWifiApConfigStore.resetToDefaultForUnsupportedConfig(softApConfig))); 3620 Log.d(TAG, "Restored soft ap backup data"); 3621 } 3622 return softApConfig; 3623 } 3624 3625 3626 /** 3627 * Restore state from the older supplicant back up data. 3628 * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file. 3629 * 3630 * @param supplicantData Raw byte stream of wpa_supplicant.conf 3631 * @param ipConfigData Raw byte stream of ipconfig.txt 3632 */ 3633 public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) { 3634 enforceNetworkSettingsPermission(); 3635 mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush(); 3636 if (mClientModeImplChannel == null) { 3637 Log.e(TAG, "mClientModeImplChannel is not initialized"); 3638 return; 3639 } 3640 3641 Log.d(TAG, "Restoring supplicant backup data"); 3642 List<WifiConfiguration> wifiConfigurations = 3643 mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData( 3644 supplicantData, ipConfigData); 3645 restoreNetworks(wifiConfigurations); 3646 Log.d(TAG, "Restored supplicant backup data"); 3647 } 3648 3649 /** 3650 * Starts subscription provisioning with a provider. 3651 * 3652 * @param provider {@link OsuProvider} the provider to provision with 3653 * @param callback {@link IProvisioningCallback} the callback object to inform status 3654 */ 3655 @Override 3656 public void startSubscriptionProvisioning(OsuProvider provider, 3657 IProvisioningCallback callback) { 3658 if (provider == null) { 3659 throw new IllegalArgumentException("Provider must not be null"); 3660 } 3661 if (callback == null) { 3662 throw new IllegalArgumentException("Callback must not be null"); 3663 } 3664 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 3665 throw new SecurityException(TAG + ": Permission denied"); 3666 } 3667 final int uid = Binder.getCallingUid(); 3668 mLog.trace("startSubscriptionProvisioning uid=%").c(uid).flush(); 3669 if (mClientModeImpl.syncStartSubscriptionProvisioning(uid, provider, 3670 callback, mClientModeImplChannel)) { 3671 mLog.trace("Subscription provisioning started with %") 3672 .c(provider.toString()).flush(); 3673 } 3674 } 3675 3676 /** 3677 * See 3678 * {@link WifiManager#registerTrafficStateCallback(Executor, WifiManager.TrafficStateCallback)} 3679 * 3680 * @param binder IBinder instance to allow cleanup if the app dies 3681 * @param callback Traffic State callback to register 3682 * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to 3683 * unregister the callback. See {@link unregisterTrafficStateCallback(int)} 3684 * 3685 * @throws SecurityException if the caller does not have permission to register a callback 3686 * @throws RemoteException if remote exception happens 3687 * @throws IllegalArgumentException if the arguments are null or invalid 3688 */ 3689 @Override 3690 public void registerTrafficStateCallback(IBinder binder, ITrafficStateCallback callback, 3691 int callbackIdentifier) { 3692 // verify arguments 3693 if (binder == null) { 3694 throw new IllegalArgumentException("Binder must not be null"); 3695 } 3696 if (callback == null) { 3697 throw new IllegalArgumentException("Callback must not be null"); 3698 } 3699 enforceNetworkSettingsPermission(); 3700 if (mVerboseLoggingEnabled) { 3701 mLog.info("registerTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush(); 3702 } 3703 // Post operation to handler thread 3704 mWifiThreadRunner.post(() -> 3705 mWifiTrafficPoller.addCallback(binder, callback, callbackIdentifier)); 3706 } 3707 3708 /** 3709 * see {@link android.net.wifi.WifiManager#unregisterTrafficStateCallback( 3710 * WifiManager.TrafficStateCallback)} 3711 * 3712 * @param callbackIdentifier Unique ID of the callback to be unregistered. 3713 * 3714 * @throws SecurityException if the caller does not have permission to register a callback 3715 */ 3716 @Override 3717 public void unregisterTrafficStateCallback(int callbackIdentifier) { 3718 enforceNetworkSettingsPermission(); 3719 if (mVerboseLoggingEnabled) { 3720 mLog.info("unregisterTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush(); 3721 } 3722 // Post operation to handler thread 3723 mWifiThreadRunner.post(() -> 3724 mWifiTrafficPoller.removeCallback(callbackIdentifier)); 3725 } 3726 3727 private long getSupportedFeaturesInternal() { 3728 final AsyncChannel channel = mClientModeImplChannel; 3729 long supportedFeatureSet = 0L; 3730 if (channel != null) { 3731 supportedFeatureSet = mClientModeImpl.syncGetSupportedFeatures(channel); 3732 } else { 3733 Log.e(TAG, "mClientModeImplChannel is not initialized"); 3734 return supportedFeatureSet; 3735 } 3736 // Mask the feature set against system properties. 3737 boolean rttSupported = mContext.getPackageManager().hasSystemFeature( 3738 PackageManager.FEATURE_WIFI_RTT); 3739 if (!rttSupported) { 3740 // flags filled in by vendor HAL, remove if overlay disables it. 3741 supportedFeatureSet &= 3742 ~(WifiManager.WIFI_FEATURE_D2D_RTT | WifiManager.WIFI_FEATURE_D2AP_RTT); 3743 } 3744 if (!mContext.getResources().getBoolean( 3745 R.bool.config_wifi_p2p_mac_randomization_supported)) { 3746 // flags filled in by vendor HAL, remove if overlay disables it. 3747 supportedFeatureSet &= ~WifiManager.WIFI_FEATURE_P2P_RAND_MAC; 3748 } 3749 if (mContext.getResources().getBoolean( 3750 R.bool.config_wifi_connected_mac_randomization_supported)) { 3751 // no corresponding flags in vendor HAL, set if overlay enables it. 3752 supportedFeatureSet |= WifiManager.WIFI_FEATURE_CONNECTED_RAND_MAC; 3753 } 3754 if (mContext.getResources().getBoolean( 3755 R.bool.config_wifi_ap_mac_randomization_supported)) { 3756 // no corresponding flags in vendor HAL, set if overlay enables it. 3757 supportedFeatureSet |= WifiManager.WIFI_FEATURE_AP_RAND_MAC; 3758 } 3759 if (mWifiThreadRunner.call( 3760 () -> mActiveModeWarden.isStaApConcurrencySupported(), 3761 false)) { 3762 supportedFeatureSet |= WifiManager.WIFI_FEATURE_AP_STA; 3763 } 3764 return supportedFeatureSet; 3765 } 3766 3767 private static boolean hasAutomotiveFeature(Context context) { 3768 return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 3769 } 3770 3771 /** 3772 * See 3773 * {@link WifiManager#registerNetworkRequestMatchCallback( 3774 * Executor, WifiManager.NetworkRequestMatchCallback)} 3775 * 3776 * @param binder IBinder instance to allow cleanup if the app dies 3777 * @param callback Network Request Match callback to register 3778 * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to 3779 * unregister the callback. 3780 * See {@link #unregisterNetworkRequestMatchCallback(int)} (int)} 3781 * 3782 * @throws SecurityException if the caller does not have permission to register a callback 3783 * @throws RemoteException if remote exception happens 3784 * @throws IllegalArgumentException if the arguments are null or invalid 3785 */ 3786 @Override 3787 public void registerNetworkRequestMatchCallback(IBinder binder, 3788 INetworkRequestMatchCallback callback, 3789 int callbackIdentifier) { 3790 // verify arguments 3791 if (binder == null) { 3792 throw new IllegalArgumentException("Binder must not be null"); 3793 } 3794 if (callback == null) { 3795 throw new IllegalArgumentException("Callback must not be null"); 3796 } 3797 enforceNetworkSettingsPermission(); 3798 if (mVerboseLoggingEnabled) { 3799 mLog.info("registerNetworkRequestMatchCallback uid=%") 3800 .c(Binder.getCallingUid()).flush(); 3801 } 3802 // Post operation to handler thread 3803 mWifiThreadRunner.post(() -> mClientModeImpl.addNetworkRequestMatchCallback( 3804 binder, callback, callbackIdentifier)); 3805 } 3806 3807 /** 3808 * see {@link android.net.wifi.WifiManager#unregisterNetworkRequestMatchCallback( 3809 * WifiManager.NetworkRequestMatchCallback)} 3810 * 3811 * @param callbackIdentifier Unique ID of the callback to be unregistered. 3812 * 3813 * @throws SecurityException if the caller does not have permission to register a callback 3814 */ 3815 @Override 3816 public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) { 3817 enforceNetworkSettingsPermission(); 3818 if (mVerboseLoggingEnabled) { 3819 mLog.info("unregisterNetworkRequestMatchCallback uid=%") 3820 .c(Binder.getCallingUid()).flush(); 3821 } 3822 // Post operation to handler thread 3823 mWifiThreadRunner.post(() -> 3824 mClientModeImpl.removeNetworkRequestMatchCallback(callbackIdentifier)); 3825 } 3826 3827 /** 3828 * See {@link android.net.wifi.WifiManager#addNetworkSuggestions(List)} 3829 * 3830 * @param networkSuggestions List of network suggestions to be added. 3831 * @param callingPackageName Package Name of the app adding the suggestions. 3832 * @param callingFeatureId Feature in the calling package 3833 * @throws SecurityException if the caller does not have permission. 3834 * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}. 3835 */ 3836 @Override 3837 public int addNetworkSuggestions( 3838 List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName, 3839 String callingFeatureId) { 3840 if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) { 3841 return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED; 3842 } 3843 if (mVerboseLoggingEnabled) { 3844 mLog.info("addNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush(); 3845 } 3846 int callingUid = Binder.getCallingUid(); 3847 3848 int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.add( 3849 networkSuggestions, callingUid, callingPackageName, callingFeatureId), 3850 WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL); 3851 if (success != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { 3852 Log.e(TAG, "Failed to add network suggestions"); 3853 } 3854 return success; 3855 } 3856 3857 /** 3858 * See {@link android.net.wifi.WifiManager#removeNetworkSuggestions(List)} 3859 * 3860 * @param networkSuggestions List of network suggestions to be removed. 3861 * @param callingPackageName Package Name of the app removing the suggestions. 3862 * @throws SecurityException if the caller does not have permission. 3863 * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}. 3864 */ 3865 @Override 3866 public int removeNetworkSuggestions( 3867 List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) { 3868 if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) { 3869 return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED; 3870 } 3871 if (mVerboseLoggingEnabled) { 3872 mLog.info("removeNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush(); 3873 } 3874 int callingUid = Binder.getCallingUid(); 3875 3876 int success = mWifiThreadRunner.call(() -> mWifiNetworkSuggestionsManager.remove( 3877 networkSuggestions, callingUid, callingPackageName), 3878 WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL); 3879 if (success != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { 3880 Log.e(TAG, "Failed to remove network suggestions"); 3881 } 3882 return success; 3883 } 3884 3885 /** 3886 * See {@link android.net.wifi.WifiManager#getNetworkSuggestions()} 3887 * @param callingPackageName Package Name of the app getting the suggestions. 3888 * @return a list of network suggestions suggested by this app 3889 */ 3890 public List<WifiNetworkSuggestion> getNetworkSuggestions(String callingPackageName) { 3891 mAppOps.checkPackage(Binder.getCallingUid(), callingPackageName); 3892 enforceAccessPermission(); 3893 if (mVerboseLoggingEnabled) { 3894 mLog.info("getNetworkSuggestionList uid=%").c(Binder.getCallingUid()).flush(); 3895 } 3896 return mWifiThreadRunner.call(() -> 3897 mWifiNetworkSuggestionsManager.get(callingPackageName), Collections.emptyList()); 3898 } 3899 3900 /** 3901 * Gets the factory Wi-Fi MAC addresses. 3902 * @throws SecurityException if the caller does not have permission. 3903 * @return Array of String representing Wi-Fi MAC addresses, or empty array if failed. 3904 */ 3905 @Override 3906 public String[] getFactoryMacAddresses() { 3907 final int uid = Binder.getCallingUid(); 3908 if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { 3909 throw new SecurityException("App not allowed to get Wi-Fi factory MAC address " 3910 + "(uid = " + uid + ")"); 3911 } 3912 String result = mWifiThreadRunner.call(mClientModeImpl::getFactoryMacAddress, null); 3913 // result can be empty array if either: WifiThreadRunner.call() timed out, or 3914 // ClientModeImpl.getFactoryMacAddress() returned null. 3915 // In this particular instance, we don't differentiate the two types of nulls. 3916 if (result == null) { 3917 return new String[0]; 3918 } 3919 return new String[]{result}; 3920 } 3921 3922 /** 3923 * Sets the current device mobility state. 3924 * @param state the new device mobility state 3925 */ 3926 @Override 3927 public void setDeviceMobilityState(@DeviceMobilityState int state) { 3928 mContext.enforceCallingOrSelfPermission( 3929 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE, "WifiService"); 3930 3931 if (mVerboseLoggingEnabled) { 3932 mLog.info("setDeviceMobilityState uid=% state=%") 3933 .c(Binder.getCallingUid()) 3934 .c(state) 3935 .flush(); 3936 } 3937 // Post operation to handler thread 3938 mWifiThreadRunner.post(() -> mClientModeImpl.setDeviceMobilityState(state)); 3939 } 3940 3941 /** 3942 * Proxy for the final native call of the parent class. Enables mocking of 3943 * the function. 3944 */ 3945 public int getMockableCallingUid() { 3946 return getCallingUid(); 3947 } 3948 3949 /** 3950 * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping 3951 * with a peer, and send the SSID and password of the selected network. 3952 * 3953 * @param binder Caller's binder context 3954 * @param enrolleeUri URI of the Enrollee obtained externally (e.g. QR code scanning) 3955 * @param selectedNetworkId Selected network ID to be sent to the peer 3956 * @param netRole The network role of the enrollee 3957 * @param callback Callback for status updates 3958 */ 3959 @Override 3960 public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri, 3961 int selectedNetworkId, int netRole, IDppCallback callback) { 3962 // verify arguments 3963 if (binder == null) { 3964 throw new IllegalArgumentException("Binder must not be null"); 3965 } 3966 if (TextUtils.isEmpty(enrolleeUri)) { 3967 throw new IllegalArgumentException("Enrollee URI must not be null or empty"); 3968 } 3969 if (selectedNetworkId < 0) { 3970 throw new IllegalArgumentException("Selected network ID invalid"); 3971 } 3972 if (callback == null) { 3973 throw new IllegalArgumentException("Callback must not be null"); 3974 } 3975 3976 final int uid = getMockableCallingUid(); 3977 3978 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 3979 throw new SecurityException(TAG + ": Permission denied"); 3980 } 3981 3982 mWifiThreadRunner.post(() -> mDppManager.startDppAsConfiguratorInitiator( 3983 uid, binder, enrolleeUri, selectedNetworkId, netRole, callback)); 3984 } 3985 3986 /** 3987 * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping 3988 * with a peer, and receive the SSID and password from the peer configurator. 3989 * 3990 * @param binder Caller's binder context 3991 * @param configuratorUri URI of the Configurator obtained externally (e.g. QR code scanning) 3992 * @param callback Callback for status updates 3993 */ 3994 @Override 3995 public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri, 3996 IDppCallback callback) { 3997 // verify arguments 3998 if (binder == null) { 3999 throw new IllegalArgumentException("Binder must not be null"); 4000 } 4001 if (TextUtils.isEmpty(configuratorUri)) { 4002 throw new IllegalArgumentException("Enrollee URI must not be null or empty"); 4003 } 4004 if (callback == null) { 4005 throw new IllegalArgumentException("Callback must not be null"); 4006 } 4007 4008 final int uid = getMockableCallingUid(); 4009 4010 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 4011 throw new SecurityException(TAG + ": Permission denied"); 4012 } 4013 4014 mWifiThreadRunner.post(() -> 4015 mDppManager.startDppAsEnrolleeInitiator(uid, binder, configuratorUri, callback)); 4016 } 4017 4018 /** 4019 * Stop or abort a current DPP session. 4020 */ 4021 @Override 4022 public void stopDppSession() throws RemoteException { 4023 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 4024 throw new SecurityException(TAG + ": Permission denied"); 4025 } 4026 final int uid = getMockableCallingUid(); 4027 4028 mWifiThreadRunner.post(() -> mDppManager.stopDppSession(uid)); 4029 } 4030 4031 /** 4032 * see {@link android.net.wifi.WifiManager#addOnWifiUsabilityStatsListener(Executor, 4033 * OnWifiUsabilityStatsListener)} 4034 * 4035 * @param binder IBinder instance to allow cleanup if the app dies 4036 * @param listener WifiUsabilityStatsEntry listener to add 4037 * @param listenerIdentifier Unique ID of the adding listener. This ID will be used to 4038 * remove the listener. See {@link removeOnWifiUsabilityStatsListener(int)} 4039 * 4040 * @throws SecurityException if the caller does not have permission to add a listener 4041 * @throws RemoteException if remote exception happens 4042 * @throws IllegalArgumentException if the arguments are null or invalid 4043 */ 4044 @Override 4045 public void addOnWifiUsabilityStatsListener(IBinder binder, 4046 IOnWifiUsabilityStatsListener listener, int listenerIdentifier) { 4047 // verify arguments 4048 if (binder == null) { 4049 throw new IllegalArgumentException("Binder must not be null"); 4050 } 4051 if (listener == null) { 4052 throw new IllegalArgumentException("Listener must not be null"); 4053 } 4054 mContext.enforceCallingOrSelfPermission( 4055 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 4056 if (mVerboseLoggingEnabled) { 4057 mLog.info("addOnWifiUsabilityStatsListener uid=%") 4058 .c(Binder.getCallingUid()).flush(); 4059 } 4060 // Post operation to handler thread 4061 mWifiThreadRunner.post(() -> 4062 mWifiMetrics.addOnWifiUsabilityListener(binder, listener, listenerIdentifier)); 4063 } 4064 4065 /** 4066 * see {@link android.net.wifi.WifiManager#removeOnWifiUsabilityStatsListener( 4067 * OnWifiUsabilityStatsListener)} 4068 * 4069 * @param listenerIdentifier Unique ID of the listener to be removed. 4070 * 4071 * @throws SecurityException if the caller does not have permission to add a listener 4072 */ 4073 @Override 4074 public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) { 4075 mContext.enforceCallingOrSelfPermission( 4076 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 4077 if (mVerboseLoggingEnabled) { 4078 mLog.info("removeOnWifiUsabilityStatsListener uid=%") 4079 .c(Binder.getCallingUid()).flush(); 4080 } 4081 // Post operation to handler thread 4082 mWifiThreadRunner.post(() -> 4083 mWifiMetrics.removeOnWifiUsabilityListener(listenerIdentifier)); 4084 } 4085 4086 /** 4087 * Updates the Wi-Fi usability score. 4088 * @param seqNum Sequence number of the Wi-Fi usability score. 4089 * @param score The Wi-Fi usability score. 4090 * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second. 4091 */ 4092 @Override 4093 public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) { 4094 mContext.enforceCallingOrSelfPermission( 4095 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 4096 4097 if (mVerboseLoggingEnabled) { 4098 mLog.info("updateWifiUsabilityScore uid=% seqNum=% score=% predictionHorizonSec=%") 4099 .c(Binder.getCallingUid()) 4100 .c(seqNum) 4101 .c(score) 4102 .c(predictionHorizonSec) 4103 .flush(); 4104 } 4105 // Post operation to handler thread 4106 mWifiThreadRunner.post(() -> 4107 mClientModeImpl.updateWifiUsabilityScore(seqNum, score, predictionHorizonSec)); 4108 } 4109 4110 /** 4111 * see {@link android.net.wifi.WifiManager#connect(int, WifiManager.ActionListener)} 4112 */ 4113 @Override 4114 public void connect(WifiConfiguration config, int netId, IBinder binder, 4115 @Nullable IActionListener callback, int callbackIdentifier) { 4116 int uid = Binder.getCallingUid(); 4117 if (!isPrivileged(Binder.getCallingPid(), uid)) { 4118 throw new SecurityException(TAG + ": Permission denied"); 4119 } 4120 mLog.info("connect uid=%").c(uid).flush(); 4121 mClientModeImpl.connect(config, netId, binder, callback, callbackIdentifier, uid); 4122 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { 4123 mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_MANUAL_CONNECT, netId); 4124 } 4125 } 4126 4127 /** 4128 * see {@link android.net.wifi.WifiManager#save(WifiConfiguration, 4129 * WifiManager.ActionListener)} 4130 */ 4131 @Override 4132 public void save(WifiConfiguration config, IBinder binder, @Nullable IActionListener callback, 4133 int callbackIdentifier) { 4134 if (!isPrivileged(Binder.getCallingPid(), Binder.getCallingUid())) { 4135 throw new SecurityException(TAG + ": Permission denied"); 4136 } 4137 mLog.info("save uid=%").c(Binder.getCallingUid()).flush(); 4138 mClientModeImpl.save( 4139 config, binder, callback, callbackIdentifier, Binder.getCallingUid()); 4140 } 4141 4142 /** 4143 * see {@link android.net.wifi.WifiManager#forget(int, WifiManager.ActionListener)} 4144 */ 4145 @Override 4146 public void forget(int netId, IBinder binder, @Nullable IActionListener callback, 4147 int callbackIdentifier) { 4148 int uid = Binder.getCallingUid(); 4149 if (!isPrivileged(Binder.getCallingPid(), uid)) { 4150 throw new SecurityException(TAG + ": Permission denied"); 4151 } 4152 mLog.info("forget uid=%").c(Binder.getCallingUid()).flush(); 4153 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { 4154 // It's important to log this metric before the actual forget executes because 4155 // the netId becomes invalid after the forget operation. 4156 mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_FORGET_WIFI, netId); 4157 } 4158 mClientModeImpl.forget(netId, binder, callback, callbackIdentifier, uid); 4159 } 4160 4161 /** 4162 * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)} 4163 */ 4164 public void registerScanResultsCallback(@NonNull IScanResultsCallback callback) { 4165 if (callback == null) { 4166 throw new IllegalArgumentException("callback must not be null"); 4167 } 4168 enforceAccessPermission(); 4169 4170 if (mVerboseLoggingEnabled) { 4171 mLog.info("registerScanResultsCallback uid=%").c(Binder.getCallingUid()).flush(); 4172 } 4173 mWifiThreadRunner.post(() -> { 4174 if (!mWifiInjector.getScanRequestProxy().registerScanResultsCallback(callback)) { 4175 Log.e(TAG, "registerScanResultsCallback: Failed to register callback"); 4176 } 4177 }); 4178 } 4179 4180 /** 4181 * See {@link WifiManager#registerScanResultsCallback(WifiManager.ScanResultsCallback)} 4182 */ 4183 public void unregisterScanResultsCallback(@NonNull IScanResultsCallback callback) { 4184 if (mVerboseLoggingEnabled) { 4185 mLog.info("unregisterScanResultCallback uid=%").c(Binder.getCallingUid()).flush(); 4186 } 4187 enforceAccessPermission(); 4188 // post operation to handler thread 4189 mWifiThreadRunner.post(() -> mWifiInjector.getScanRequestProxy() 4190 .unregisterScanResultsCallback(callback)); 4191 4192 } 4193 4194 /** 4195 * See {@link WifiManager#addSuggestionConnectionStatusListener(Executor, 4196 * SuggestionConnectionStatusListener)} 4197 */ 4198 public void registerSuggestionConnectionStatusListener(IBinder binder, 4199 @NonNull ISuggestionConnectionStatusListener listener, 4200 int listenerIdentifier, String packageName, @Nullable String featureId) { 4201 if (binder == null) { 4202 throw new IllegalArgumentException("Binder must not be null"); 4203 } 4204 if (listener == null) { 4205 throw new IllegalArgumentException("listener must not be null"); 4206 } 4207 final int uid = Binder.getCallingUid(); 4208 enforceAccessPermission(); 4209 enforceLocationPermission(packageName, featureId, uid); 4210 if (mVerboseLoggingEnabled) { 4211 mLog.info("registerSuggestionConnectionStatusListener uid=%").c(uid).flush(); 4212 } 4213 mWifiThreadRunner.post(() -> 4214 mWifiNetworkSuggestionsManager 4215 .registerSuggestionConnectionStatusListener(binder, listener, 4216 listenerIdentifier, packageName)); 4217 } 4218 4219 /** 4220 * See {@link WifiManager#removeSuggestionConnectionStatusListener( 4221 * SuggestionConnectionStatusListener)} 4222 */ 4223 public void unregisterSuggestionConnectionStatusListener( 4224 int listenerIdentifier, String packageName) { 4225 enforceAccessPermission(); 4226 if (mVerboseLoggingEnabled) { 4227 mLog.info("unregisterSuggestionConnectionStatusListener uid=%") 4228 .c(Binder.getCallingUid()).flush(); 4229 } 4230 mWifiThreadRunner.post(() -> 4231 mWifiNetworkSuggestionsManager 4232 .unregisterSuggestionConnectionStatusListener(listenerIdentifier, 4233 packageName)); 4234 } 4235 4236 @Override 4237 public int calculateSignalLevel(int rssi) { 4238 return RssiUtil.calculateSignalLevel(mContext, rssi); 4239 } 4240 4241 /** 4242 * See {@link android.net.wifi.WifiManager#setWifiConnectedNetworkScorer(Executor, 4243 * WifiConnectedNetworkScorer)} 4244 * 4245 * @param binder IBinder instance to allow cleanup if the app dies. 4246 * @param scorer Wifi connected network scorer to set. 4247 * @return true Scorer is set successfully. 4248 * 4249 * @throws RemoteException if remote exception happens 4250 * @throws IllegalArgumentException if the arguments are null or invalid 4251 */ 4252 @Override 4253 public boolean setWifiConnectedNetworkScorer(IBinder binder, 4254 IWifiConnectedNetworkScorer scorer) { 4255 if (binder == null) { 4256 throw new IllegalArgumentException("Binder must not be null"); 4257 } 4258 if (scorer == null) { 4259 throw new IllegalArgumentException("Scorer must not be null"); 4260 } 4261 mContext.enforceCallingOrSelfPermission( 4262 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 4263 if (mVerboseLoggingEnabled) { 4264 mLog.info("setWifiConnectedNetworkScorer uid=%").c(Binder.getCallingUid()).flush(); 4265 } 4266 // Post operation to handler thread 4267 WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport(); 4268 return mWifiThreadRunner.call(() -> wifiScoreReport.setWifiConnectedNetworkScorer( 4269 binder, scorer), false); 4270 } 4271 /** 4272 * See {@link android.net.wifi.WifiManager#clearWifiConnectedNetworkScorer( 4273 * WifiConnectedNetworkScorer)} 4274 */ 4275 @Override 4276 public void clearWifiConnectedNetworkScorer() { 4277 mContext.enforceCallingOrSelfPermission( 4278 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 4279 if (mVerboseLoggingEnabled) { 4280 mLog.info("clearWifiConnectedNetworkScorer uid=%").c(Binder.getCallingUid()).flush(); 4281 } 4282 // Post operation to handler thread 4283 WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport(); 4284 mWifiThreadRunner.post(() -> 4285 wifiScoreReport.clearWifiConnectedNetworkScorer()); 4286 } 4287 4288 /** 4289 * See {@link android.net.wifi.WifiManager#setScanThrottleEnabled(boolean)} 4290 */ 4291 @Override 4292 public void setScanThrottleEnabled(boolean enable) { 4293 enforceNetworkSettingsPermission(); 4294 mLog.info("setScanThrottleEnabled uid=% verbose=%") 4295 .c(Binder.getCallingUid()) 4296 .c(enable).flush(); 4297 mWifiThreadRunner.post(()-> mScanRequestProxy.setScanThrottleEnabled(enable)); 4298 } 4299 4300 /** 4301 * See {@link android.net.wifi.WifiManager#isScanThrottleEnabled()} 4302 */ 4303 @Override 4304 public boolean isScanThrottleEnabled() { 4305 enforceAccessPermission(); 4306 if (mVerboseLoggingEnabled) { 4307 mLog.info("isScanThrottleEnabled uid=%").c(Binder.getCallingUid()).flush(); 4308 } 4309 return mWifiThreadRunner.call(()-> mScanRequestProxy.isScanThrottleEnabled(), true); 4310 } 4311 4312 /** 4313 * See {@link android.net.wifi.WifiManager#setAutoWakeupEnabled(boolean)} 4314 */ 4315 @Override 4316 public void setAutoWakeupEnabled(boolean enable) { 4317 enforceNetworkSettingsPermission(); 4318 mLog.info("setWalkeupEnabled uid=% verbose=%") 4319 .c(Binder.getCallingUid()) 4320 .c(enable).flush(); 4321 mWifiThreadRunner.post(()-> mWifiInjector.getWakeupController().setEnabled(enable)); 4322 } 4323 4324 /** 4325 * See {@link android.net.wifi.WifiManager#isAutoWakeupEnabled()} 4326 */ 4327 @Override 4328 public boolean isAutoWakeupEnabled() { 4329 enforceAccessPermission(); 4330 if (mVerboseLoggingEnabled) { 4331 mLog.info("isAutoWakeupEnabled uid=%").c(Binder.getCallingUid()).flush(); 4332 } 4333 return mWifiThreadRunner.call(()-> mWifiInjector.getWakeupController().isEnabled(), false); 4334 } 4335 } 4336