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.EXTRA_PREVIOUS_WIFI_AP_STATE; 22 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON; 23 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; 24 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; 25 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; 26 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC; 27 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL; 28 import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL; 29 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED; 30 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING; 31 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED; 32 import static android.net.wifi.WifiManager.WIFI_FEATURE_INFRA_5G; 33 34 import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR; 35 import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED; 36 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED; 37 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED; 38 import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED; 39 import static com.android.server.wifi.WifiController.CMD_SET_AP; 40 import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; 41 42 import android.Manifest; 43 import android.annotation.CheckResult; 44 import android.app.ActivityManager; 45 import android.app.ActivityManager.RunningAppProcessInfo; 46 import android.app.AppOpsManager; 47 import android.app.admin.DeviceAdminInfo; 48 import android.app.admin.DevicePolicyManagerInternal; 49 import android.bluetooth.BluetoothAdapter; 50 import android.content.BroadcastReceiver; 51 import android.content.Context; 52 import android.content.Intent; 53 import android.content.IntentFilter; 54 import android.content.pm.ApplicationInfo; 55 import android.content.pm.PackageManager; 56 import android.content.pm.ParceledListSlice; 57 import android.database.ContentObserver; 58 import android.net.DhcpInfo; 59 import android.net.DhcpResults; 60 import android.net.Network; 61 import android.net.NetworkUtils; 62 import android.net.Uri; 63 import android.net.ip.IpClientUtil; 64 import android.net.wifi.IDppCallback; 65 import android.net.wifi.INetworkRequestMatchCallback; 66 import android.net.wifi.IOnWifiUsabilityStatsListener; 67 import android.net.wifi.ISoftApCallback; 68 import android.net.wifi.ITrafficStateCallback; 69 import android.net.wifi.ScanResult; 70 import android.net.wifi.WifiActivityEnergyInfo; 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.WifiNetworkSuggestion; 77 import android.net.wifi.WifiSsid; 78 import android.net.wifi.hotspot2.IProvisioningCallback; 79 import android.net.wifi.hotspot2.OsuProvider; 80 import android.net.wifi.hotspot2.PasspointConfiguration; 81 import android.os.AsyncTask; 82 import android.os.BatteryStats; 83 import android.os.Binder; 84 import android.os.Build; 85 import android.os.Bundle; 86 import android.os.Handler; 87 import android.os.HandlerThread; 88 import android.os.IBinder; 89 import android.os.Looper; 90 import android.os.Message; 91 import android.os.Messenger; 92 import android.os.PowerManager; 93 import android.os.Process; 94 import android.os.RemoteException; 95 import android.os.ResultReceiver; 96 import android.os.ShellCallback; 97 import android.os.UserHandle; 98 import android.os.UserManager; 99 import android.os.WorkSource; 100 import android.provider.Settings; 101 import android.telephony.TelephonyManager; 102 import android.text.TextUtils; 103 import android.util.Log; 104 import android.util.MutableInt; 105 import android.util.Slog; 106 107 import com.android.internal.annotations.GuardedBy; 108 import com.android.internal.annotations.VisibleForTesting; 109 import com.android.internal.os.PowerProfile; 110 import com.android.internal.telephony.IccCardConstants; 111 import com.android.internal.telephony.PhoneConstants; 112 import com.android.internal.telephony.TelephonyIntents; 113 import com.android.internal.util.AsyncChannel; 114 import com.android.server.wifi.hotspot2.PasspointProvider; 115 import com.android.server.wifi.util.ExternalCallbackTracker; 116 import com.android.server.wifi.util.GeneralUtil.Mutable; 117 import com.android.server.wifi.util.WifiHandler; 118 import com.android.server.wifi.util.WifiPermissionsUtil; 119 120 import java.io.BufferedReader; 121 import java.io.FileDescriptor; 122 import java.io.FileNotFoundException; 123 import java.io.FileReader; 124 import java.io.IOException; 125 import java.io.PrintWriter; 126 import java.net.Inet4Address; 127 import java.net.InetAddress; 128 import java.security.GeneralSecurityException; 129 import java.security.KeyStore; 130 import java.security.cert.CertPath; 131 import java.security.cert.CertPathValidator; 132 import java.security.cert.CertificateFactory; 133 import java.security.cert.PKIXParameters; 134 import java.security.cert.X509Certificate; 135 import java.util.ArrayList; 136 import java.util.Arrays; 137 import java.util.HashMap; 138 import java.util.Iterator; 139 import java.util.List; 140 import java.util.Map; 141 import java.util.concurrent.ConcurrentHashMap; 142 143 /** 144 * WifiService handles remote WiFi operation requests by implementing 145 * the IWifiManager interface. 146 * 147 * @hide 148 */ 149 public class WifiServiceImpl extends BaseWifiService { 150 private static final String TAG = "WifiService"; 151 private static final boolean VDBG = false; 152 153 // Default scan background throttling interval if not overriden in settings 154 private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000; 155 156 // Apps with importance higher than this value is considered as background app. 157 private static final int BACKGROUND_IMPORTANCE_CUTOFF = 158 RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; 159 160 // Max wait time for posting blocking runnables 161 private static final int RUN_WITH_SCISSORS_TIMEOUT_MILLIS = 4000; 162 163 final ClientModeImpl mClientModeImpl; 164 final ActiveModeWarden mActiveModeWarden; 165 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 ActivityManager mActivityManager; 175 private final WifiCountryCode mCountryCode; 176 // Debug counter tracking scan requests sent by WifiManager 177 private int scanRequestCounter = 0; 178 179 /* Polls traffic stats and notifies clients */ 180 private WifiTrafficPoller mWifiTrafficPoller; 181 /* Tracks the persisted states for wi-fi & airplane mode */ 182 final WifiSettingsStore mSettingsStore; 183 /* Logs connection events and some general router and scan stats */ 184 private final WifiMetrics mWifiMetrics; 185 186 private final WifiInjector mWifiInjector; 187 /* Backup/Restore Module */ 188 private final WifiBackupRestore mWifiBackupRestore; 189 private final WifiNetworkSuggestionsManager mWifiNetworkSuggestionsManager; 190 191 private WifiLog mLog; 192 /** 193 * Verbose logging flag. Toggled by developer options. 194 */ 195 private boolean mVerboseLoggingEnabled = false; 196 197 /** 198 * Asynchronous channel to ClientModeImpl 199 */ 200 @VisibleForTesting 201 AsyncChannel mClientModeImplChannel; 202 203 private final FrameworkFacade mFrameworkFacade; 204 205 private WifiPermissionsUtil mWifiPermissionsUtil; 206 207 @GuardedBy("mLocalOnlyHotspotRequests") 208 private final HashMap<Integer, LocalOnlyHotspotRequestInfo> mLocalOnlyHotspotRequests; 209 @GuardedBy("mLocalOnlyHotspotRequests") 210 private WifiConfiguration mLocalOnlyHotspotConfig = null; 211 @GuardedBy("mLocalOnlyHotspotRequests") 212 private final ConcurrentHashMap<String, Integer> mIfaceIpModes; 213 214 private final ExternalCallbackTracker<ISoftApCallback> mRegisteredSoftApCallbacks; 215 216 /** 217 * One of: {@link WifiManager#WIFI_AP_STATE_DISABLED}, 218 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 219 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 220 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 221 * {@link WifiManager#WIFI_AP_STATE_FAILED} 222 * 223 * Access/maintenance MUST be done on the wifi service thread 224 */ 225 // TODO: (b/71714381) Remove mWifiApState and broadcast mechanism, keep mSoftApState as the only 226 // field to store soft AP state. Then rename mSoftApState and mSoftApNumClients to 227 // mWifiApState and mWifiApNumClients, to match the constants (i.e. WIFI_AP_STATE_*) 228 private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED; 229 private int mSoftApState = WifiManager.WIFI_AP_STATE_DISABLED; 230 private int mSoftApNumClients = 0; 231 232 /** 233 * Power profile 234 */ 235 PowerProfile mPowerProfile; 236 237 /** 238 * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death. 239 * 240 * @hide 241 */ 242 public final class LocalOnlyRequestorCallback 243 implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback { 244 /** 245 * Called with requesting app has died. 246 */ 247 @Override onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor)248 public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) { 249 unregisterCallingAppAndStopLocalOnlyHotspot(requestor); 250 }; 251 } 252 253 /** 254 * Handles client connections 255 */ 256 private class AsyncChannelExternalClientHandler extends WifiHandler { 257 AsyncChannelExternalClientHandler(String tag, Looper looper)258 AsyncChannelExternalClientHandler(String tag, Looper looper) { 259 super(tag, looper); 260 } 261 262 @Override handleMessage(Message msg)263 public void handleMessage(Message msg) { 264 super.handleMessage(msg); 265 switch (msg.what) { 266 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 267 AsyncChannel ac = mFrameworkFacade.makeWifiAsyncChannel(TAG); 268 ac.connect(mContext, this, msg.replyTo); 269 break; 270 } 271 case WifiManager.CONNECT_NETWORK: { 272 if (checkPrivilegedPermissionsAndReplyIfNotAuthorized( 273 msg, WifiManager.CONNECT_NETWORK_FAILED)) { 274 WifiConfiguration config = (WifiConfiguration) msg.obj; 275 int networkId = msg.arg1; 276 Slog.d(TAG, "CONNECT " 277 + " nid=" + Integer.toString(networkId) 278 + " config=" + config 279 + " uid=" + msg.sendingUid 280 + " name=" 281 + mContext.getPackageManager().getNameForUid(msg.sendingUid)); 282 if (config != null) { 283 /* Command is forwarded to state machine */ 284 mClientModeImpl.sendMessage(Message.obtain(msg)); 285 } else if (config == null 286 && networkId != WifiConfiguration.INVALID_NETWORK_ID) { 287 mClientModeImpl.sendMessage(Message.obtain(msg)); 288 } else { 289 Slog.e(TAG, "AsyncChannelExternalClientHandler.handleMessage " 290 + "ignoring invalid msg=" + msg); 291 replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED, 292 WifiManager.INVALID_ARGS); 293 } 294 } 295 break; 296 } 297 case WifiManager.SAVE_NETWORK: { 298 if (checkPrivilegedPermissionsAndReplyIfNotAuthorized( 299 msg, WifiManager.SAVE_NETWORK_FAILED)) { 300 WifiConfiguration config = (WifiConfiguration) msg.obj; 301 int networkId = msg.arg1; 302 Slog.d(TAG, "SAVE" 303 + " nid=" + Integer.toString(networkId) 304 + " config=" + config 305 + " uid=" + msg.sendingUid 306 + " name=" 307 + mContext.getPackageManager().getNameForUid(msg.sendingUid)); 308 if (config != null) { 309 /* Command is forwarded to state machine */ 310 mClientModeImpl.sendMessage(Message.obtain(msg)); 311 } else { 312 Slog.e(TAG, "AsyncChannelExternalClientHandler.handleMessage " 313 + "ignoring invalid msg=" + msg); 314 replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED, 315 WifiManager.INVALID_ARGS); 316 } 317 } 318 break; 319 } 320 case WifiManager.FORGET_NETWORK: 321 if (checkPrivilegedPermissionsAndReplyIfNotAuthorized( 322 msg, WifiManager.FORGET_NETWORK_FAILED)) { 323 mClientModeImpl.sendMessage(Message.obtain(msg)); 324 } 325 break; 326 case WifiManager.DISABLE_NETWORK: 327 if (checkPrivilegedPermissionsAndReplyIfNotAuthorized( 328 msg, WifiManager.DISABLE_NETWORK_FAILED)) { 329 mClientModeImpl.sendMessage(Message.obtain(msg)); 330 } 331 break; 332 case WifiManager.RSSI_PKTCNT_FETCH: { 333 if (checkChangePermissionAndReplyIfNotAuthorized( 334 msg, WifiManager.RSSI_PKTCNT_FETCH_FAILED)) { 335 mClientModeImpl.sendMessage(Message.obtain(msg)); 336 } 337 break; 338 } 339 default: { 340 Slog.d(TAG, "AsyncChannelExternalClientHandler.handleMessage " 341 + "ignoring msg=" + msg); 342 break; 343 } 344 } 345 } 346 347 /** 348 * Helper method to check if the sender of the message holds the 349 * {@link Manifest.permission#CHANGE_WIFI_STATE} permission, and reply with a failure if it 350 * doesn't 351 * 352 * @param msg Incoming message. 353 * @param replyWhat Param to be filled in the {@link Message#what} field of the failure 354 * reply. 355 * @return true if the sender holds the permission, false otherwise. 356 */ checkChangePermissionAndReplyIfNotAuthorized(Message msg, int replyWhat)357 private boolean checkChangePermissionAndReplyIfNotAuthorized(Message msg, int replyWhat) { 358 if (!mWifiPermissionsUtil.checkChangePermission(msg.sendingUid)) { 359 Slog.e(TAG, "AsyncChannelExternalClientHandler.handleMessage " 360 + "ignoring unauthorized msg=" + msg); 361 replyFailed(msg, replyWhat, WifiManager.NOT_AUTHORIZED); 362 return false; 363 } 364 return true; 365 } 366 367 /** 368 * Helper method to check if the sender of the message holds one of 369 * {@link Manifest.permission#NETWORK_SETTINGS}, 370 * {@link Manifest.permission#NETWORK_SETUP_WIZARD} or 371 * {@link Manifest.permission#NETWORK_STACK} permission, and reply with a failure if it 372 * doesn't 373 * 374 * @param msg Incoming message. 375 * @param replyWhat Param to be filled in the {@link Message#what} field of the failure 376 * reply. 377 * @return true if the sender holds the permission, false otherwise. 378 */ checkPrivilegedPermissionsAndReplyIfNotAuthorized( Message msg, int replyWhat)379 private boolean checkPrivilegedPermissionsAndReplyIfNotAuthorized( 380 Message msg, int replyWhat) { 381 if (!isPrivileged(-1, msg.sendingUid)) { 382 Slog.e(TAG, "ClientHandler.handleMessage ignoring unauthorized msg=" + msg); 383 replyFailed(msg, replyWhat, WifiManager.NOT_AUTHORIZED); 384 return false; 385 } 386 return true; 387 } 388 replyFailed(Message msg, int what, int why)389 private void replyFailed(Message msg, int what, int why) { 390 if (msg.replyTo == null) return; 391 Message reply = Message.obtain(); 392 reply.what = what; 393 reply.arg1 = why; 394 try { 395 msg.replyTo.send(reply); 396 } catch (RemoteException e) { 397 // There's not much we can do if reply can't be sent! 398 } 399 } 400 } 401 private AsyncChannelExternalClientHandler mAsyncChannelExternalClientHandler; 402 403 /** 404 * Handles interaction with ClientModeImpl 405 */ 406 private class ClientModeImplHandler extends WifiHandler { 407 private AsyncChannel mCmiChannel; 408 ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel)409 ClientModeImplHandler(String tag, Looper looper, AsyncChannel asyncChannel) { 410 super(tag, looper); 411 mCmiChannel = asyncChannel; 412 mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler()); 413 } 414 415 @Override handleMessage(Message msg)416 public void handleMessage(Message msg) { 417 super.handleMessage(msg); 418 switch (msg.what) { 419 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 420 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 421 mClientModeImplChannel = mCmiChannel; 422 } else { 423 Slog.e(TAG, "ClientModeImpl connection failure, error=" + msg.arg1); 424 mClientModeImplChannel = null; 425 } 426 break; 427 } 428 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 429 Slog.e(TAG, "ClientModeImpl channel lost, msg.arg1 =" + msg.arg1); 430 mClientModeImplChannel = null; 431 //Re-establish connection to state machine 432 mCmiChannel.connect(mContext, this, mClientModeImpl.getHandler()); 433 break; 434 } 435 default: { 436 Slog.d(TAG, "ClientModeImplHandler.handleMessage ignoring msg=" + msg); 437 break; 438 } 439 } 440 } 441 } 442 443 ClientModeImplHandler mClientModeImplHandler; 444 private WifiController mWifiController; 445 private final WifiLockManager mWifiLockManager; 446 private final WifiMulticastLockManager mWifiMulticastLockManager; 447 private final DppManager mDppManager; 448 449 private WifiApConfigStore mWifiApConfigStore; 450 WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel)451 public WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel) { 452 mContext = context; 453 mWifiInjector = wifiInjector; 454 mClock = wifiInjector.getClock(); 455 456 mFacade = mWifiInjector.getFrameworkFacade(); 457 mWifiMetrics = mWifiInjector.getWifiMetrics(); 458 mWifiTrafficPoller = mWifiInjector.getWifiTrafficPoller(); 459 mUserManager = mWifiInjector.getUserManager(); 460 mCountryCode = mWifiInjector.getWifiCountryCode(); 461 mClientModeImpl = mWifiInjector.getClientModeImpl(); 462 mActiveModeWarden = mWifiInjector.getActiveModeWarden(); 463 mClientModeImpl.enableRssiPolling(true); 464 mScanRequestProxy = mWifiInjector.getScanRequestProxy(); 465 mSettingsStore = mWifiInjector.getWifiSettingsStore(); 466 mPowerManager = mContext.getSystemService(PowerManager.class); 467 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 468 mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); 469 mWifiLockManager = mWifiInjector.getWifiLockManager(); 470 mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager(); 471 HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread(); 472 mAsyncChannelExternalClientHandler = 473 new AsyncChannelExternalClientHandler(TAG, wifiServiceHandlerThread.getLooper()); 474 mClientModeImplHandler = new ClientModeImplHandler(TAG, 475 wifiServiceHandlerThread.getLooper(), asyncChannel); 476 mWifiController = mWifiInjector.getWifiController(); 477 mWifiBackupRestore = mWifiInjector.getWifiBackupRestore(); 478 mWifiApConfigStore = mWifiInjector.getWifiApConfigStore(); 479 mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil(); 480 mLog = mWifiInjector.makeLog(TAG); 481 mFrameworkFacade = wifiInjector.getFrameworkFacade(); 482 mIfaceIpModes = new ConcurrentHashMap<>(); 483 mLocalOnlyHotspotRequests = new HashMap<>(); 484 enableVerboseLoggingInternal(getVerboseLoggingLevel()); 485 mRegisteredSoftApCallbacks = 486 new ExternalCallbackTracker<ISoftApCallback>(mClientModeImplHandler); 487 488 mWifiInjector.getActiveModeWarden().registerSoftApCallback(new SoftApCallbackImpl()); 489 mPowerProfile = mWifiInjector.getPowerProfile(); 490 mWifiNetworkSuggestionsManager = mWifiInjector.getWifiNetworkSuggestionsManager(); 491 mDppManager = mWifiInjector.getDppManager(); 492 } 493 494 /** 495 * Provide a way for unit tests to set valid log object in the WifiHandler 496 * @param log WifiLog object to assign to the clientHandler 497 */ 498 @VisibleForTesting setWifiHandlerLogForTest(WifiLog log)499 public void setWifiHandlerLogForTest(WifiLog log) { 500 mAsyncChannelExternalClientHandler.setWifiLog(log); 501 } 502 503 /** 504 * Check if we are ready to start wifi. 505 * 506 * First check if we will be restarting system services to decrypt the device. If the device is 507 * not encrypted, check if Wi-Fi needs to be enabled and start if needed 508 * 509 * This function is used only at boot time. 510 */ checkAndStartWifi()511 public void checkAndStartWifi() { 512 // First check if we will end up restarting WifiService 513 if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) { 514 Log.d(TAG, "Device still encrypted. Need to restart SystemServer. Do not start wifi."); 515 return; 516 } 517 518 // Check if wi-fi needs to be enabled 519 boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); 520 Slog.i(TAG, "WifiService starting up with Wi-Fi " + 521 (wifiEnabled ? "enabled" : "disabled")); 522 523 registerForScanModeChange(); 524 mContext.registerReceiver( 525 new BroadcastReceiver() { 526 @Override 527 public void onReceive(Context context, Intent intent) { 528 if (mSettingsStore.handleAirplaneModeToggled()) { 529 mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED); 530 } 531 if (mSettingsStore.isAirplaneModeOn()) { 532 Log.d(TAG, "resetting country code because Airplane mode is ON"); 533 mCountryCode.airplaneModeEnabled(); 534 } 535 } 536 }, 537 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 538 539 mContext.registerReceiver( 540 new BroadcastReceiver() { 541 @Override 542 public void onReceive(Context context, Intent intent) { 543 String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 544 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) { 545 Log.d(TAG, "resetting networks because SIM was removed"); 546 mClientModeImpl.resetSimAuthNetworks(false); 547 } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) { 548 Log.d(TAG, "resetting networks because SIM was loaded"); 549 mClientModeImpl.resetSimAuthNetworks(true); 550 } 551 } 552 }, 553 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); 554 555 mContext.registerReceiver( 556 new BroadcastReceiver() { 557 @Override 558 public void onReceive(Context context, Intent intent) { 559 final int currState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, 560 WIFI_AP_STATE_DISABLED); 561 final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE, 562 WIFI_AP_STATE_DISABLED); 563 final int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON, 564 HOTSPOT_NO_ERROR); 565 final String ifaceName = 566 intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME); 567 final int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, 568 WifiManager.IFACE_IP_MODE_UNSPECIFIED); 569 handleWifiApStateChange(currState, prevState, errorCode, ifaceName, mode); 570 } 571 }, 572 new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)); 573 574 // Adding optimizations of only receiving broadcasts when wifi is enabled 575 // can result in race conditions when apps toggle wifi in the background 576 // without active user involvement. Always receive broadcasts. 577 registerForBroadcasts(); 578 mInIdleMode = mPowerManager.isDeviceIdleMode(); 579 580 if (!mClientModeImpl.syncInitialize(mClientModeImplChannel)) { 581 Log.wtf(TAG, "Failed to initialize ClientModeImpl"); 582 } 583 mWifiController.start(); 584 585 // If we are already disabled (could be due to airplane mode), avoid changing persist 586 // state here 587 if (wifiEnabled) { 588 setWifiEnabled(mContext.getPackageName(), wifiEnabled); 589 } 590 } 591 handleBootCompleted()592 public void handleBootCompleted() { 593 Log.d(TAG, "Handle boot completed"); 594 mClientModeImpl.handleBootCompleted(); 595 } 596 handleUserSwitch(int userId)597 public void handleUserSwitch(int userId) { 598 Log.d(TAG, "Handle user switch " + userId); 599 mClientModeImpl.handleUserSwitch(userId); 600 } 601 handleUserUnlock(int userId)602 public void handleUserUnlock(int userId) { 603 Log.d(TAG, "Handle user unlock " + userId); 604 mClientModeImpl.handleUserUnlock(userId); 605 } 606 handleUserStop(int userId)607 public void handleUserStop(int userId) { 608 Log.d(TAG, "Handle user stop " + userId); 609 mClientModeImpl.handleUserStop(userId); 610 } 611 612 /** 613 * See {@link android.net.wifi.WifiManager#startScan} 614 * 615 * @param packageName Package name of the app that requests wifi scan. 616 */ 617 @Override startScan(String packageName)618 public boolean startScan(String packageName) { 619 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 620 return false; 621 } 622 623 int callingUid = Binder.getCallingUid(); 624 long ident = Binder.clearCallingIdentity(); 625 mLog.info("startScan uid=%").c(callingUid).flush(); 626 synchronized (this) { 627 if (mInIdleMode) { 628 // Need to send an immediate scan result broadcast in case the 629 // caller is waiting for a result .. 630 631 // TODO: investigate if the logic to cancel scans when idle can move to 632 // WifiScanningServiceImpl. This will 1 - clean up WifiServiceImpl and 2 - 633 // avoid plumbing an awkward path to report a cancelled/failed scan. This will 634 // be sent directly until b/31398592 is fixed. 635 sendFailedScanBroadcast(); 636 mScanPending = true; 637 return false; 638 } 639 } 640 try { 641 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid); 642 Mutable<Boolean> scanSuccess = new Mutable<>(); 643 boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler() 644 .runWithScissors(() -> { 645 scanSuccess.value = mScanRequestProxy.startScan(callingUid, packageName); 646 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 647 if (!runWithScissorsSuccess) { 648 Log.e(TAG, "Failed to post runnable to start scan"); 649 sendFailedScanBroadcast(); 650 return false; 651 } 652 if (!scanSuccess.value) { 653 Log.e(TAG, "Failed to start scan"); 654 return false; 655 } 656 } catch (SecurityException e) { 657 Slog.e(TAG, "Permission violation - startScan not allowed for" 658 + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e); 659 return false; 660 } finally { 661 Binder.restoreCallingIdentity(ident); 662 } 663 return true; 664 } 665 666 // Send a failed scan broadcast to indicate the current scan request failed. sendFailedScanBroadcast()667 private void sendFailedScanBroadcast() { 668 // clear calling identity to send broadcast 669 long callingIdentity = Binder.clearCallingIdentity(); 670 try { 671 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 672 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 673 intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false); 674 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 675 } finally { 676 // restore calling identity 677 Binder.restoreCallingIdentity(callingIdentity); 678 } 679 680 } 681 682 /** 683 * WPS support in Client mode is deprecated. Return null. 684 */ 685 @Override getCurrentNetworkWpsNfcConfigurationToken()686 public String getCurrentNetworkWpsNfcConfigurationToken() { 687 // while CLs are in flight, return null here, will be removed (b/72423090) 688 enforceConnectivityInternalPermission(); 689 if (mVerboseLoggingEnabled) { 690 mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%") 691 .c(Binder.getCallingUid()).flush(); 692 } 693 return null; 694 } 695 696 boolean mInIdleMode; 697 boolean mScanPending; 698 handleIdleModeChanged()699 void handleIdleModeChanged() { 700 boolean doScan = false; 701 synchronized (this) { 702 boolean idle = mPowerManager.isDeviceIdleMode(); 703 if (mInIdleMode != idle) { 704 mInIdleMode = idle; 705 if (!idle) { 706 if (mScanPending) { 707 mScanPending = false; 708 doScan = true; 709 } 710 } 711 } 712 } 713 if (doScan) { 714 // Someone requested a scan while we were idle; do a full scan now. 715 // A security check of the caller's identity was made when the request arrived via 716 // Binder. Now we'll pass the current process's identity to startScan(). 717 startScan(mContext.getOpPackageName()); 718 } 719 } 720 checkNetworkSettingsPermission(int pid, int uid)721 private boolean checkNetworkSettingsPermission(int pid, int uid) { 722 return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid) 723 == PERMISSION_GRANTED; 724 } 725 checkNetworkSetupWizardPermission(int pid, int uid)726 private boolean checkNetworkSetupWizardPermission(int pid, int uid) { 727 return mContext.checkPermission(android.Manifest.permission.NETWORK_SETUP_WIZARD, pid, uid) 728 == PackageManager.PERMISSION_GRANTED; 729 } 730 checkNetworkStackPermission(int pid, int uid)731 private boolean checkNetworkStackPermission(int pid, int uid) { 732 return mContext.checkPermission(android.Manifest.permission.NETWORK_STACK, pid, uid) 733 == PackageManager.PERMISSION_GRANTED; 734 } 735 checkNetworkManagedProvisioningPermission(int pid, int uid)736 private boolean checkNetworkManagedProvisioningPermission(int pid, int uid) { 737 return mContext.checkPermission(android.Manifest.permission.NETWORK_MANAGED_PROVISIONING, 738 pid, uid) == PackageManager.PERMISSION_GRANTED; 739 } 740 741 // Helper method to check if the entity initiating the binder call has any of the signature only 742 // permissions. isPrivileged(int pid, int uid)743 private boolean isPrivileged(int pid, int uid) { 744 return checkNetworkSettingsPermission(pid, uid) 745 || checkNetworkSetupWizardPermission(pid, uid) 746 || checkNetworkStackPermission(pid, uid) 747 || checkNetworkManagedProvisioningPermission(pid, uid); 748 } 749 750 // Helper method to check if the entity initiating the binder call has setup wizard or settings 751 // permissions. isSettingsOrSuw(int pid, int uid)752 private boolean isSettingsOrSuw(int pid, int uid) { 753 return checkNetworkSettingsPermission(pid, uid) 754 || checkNetworkSetupWizardPermission(pid, uid); 755 } 756 757 // Helper method to check if the entity initiating the binder call is a system app. isSystem(String packageName)758 private boolean isSystem(String packageName) { 759 long ident = Binder.clearCallingIdentity(); 760 try { 761 ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName, 0); 762 return info.isSystemApp() || info.isUpdatedSystemApp(); 763 } catch (PackageManager.NameNotFoundException e) { 764 // In case of exception, assume unknown app (more strict checking) 765 // Note: This case will never happen since checkPackage is 766 // called to verify validity before checking App's version. 767 } finally { 768 Binder.restoreCallingIdentity(ident); 769 } 770 return false; 771 } 772 773 // Helper method to check if the entity initiating the binder call is a DO/PO app. isDeviceOrProfileOwner(int uid)774 private boolean isDeviceOrProfileOwner(int uid) { 775 final DevicePolicyManagerInternal dpmi = 776 mWifiInjector.getWifiPermissionsWrapper().getDevicePolicyManagerInternal(); 777 if (dpmi == null) return false; 778 return dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) 779 || dpmi.isActiveAdminWithPolicy(uid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); 780 } 781 enforceNetworkSettingsPermission()782 private void enforceNetworkSettingsPermission() { 783 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS, 784 "WifiService"); 785 } 786 enforceNetworkStackPermission()787 private void enforceNetworkStackPermission() { 788 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK, 789 "WifiService"); 790 } 791 enforceAccessPermission()792 private void enforceAccessPermission() { 793 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 794 "WifiService"); 795 } 796 797 /** 798 * Checks whether the caller can change the wifi state. 799 * Possible results: 800 * 1. Operation is allowed. No exception thrown, and AppOpsManager.MODE_ALLOWED returned. 801 * 2. Operation is not allowed, and caller must be told about this. SecurityException is thrown. 802 * 3. Operation is not allowed, and caller must not be told about this (i.e. must silently 803 * ignore the operation). No exception is thrown, and AppOpsManager.MODE_IGNORED returned. 804 */ 805 @CheckResult enforceChangePermission(String callingPackage)806 private int enforceChangePermission(String callingPackage) { 807 mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); 808 if (checkNetworkSettingsPermission(Binder.getCallingPid(), Binder.getCallingUid())) { 809 return MODE_ALLOWED; 810 } 811 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 812 "WifiService"); 813 814 return mAppOps.noteOp( 815 AppOpsManager.OPSTR_CHANGE_WIFI_STATE, Binder.getCallingUid(), callingPackage); 816 } 817 enforceLocationHardwarePermission()818 private void enforceLocationHardwarePermission() { 819 mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, 820 "LocationHardware"); 821 } 822 enforceReadCredentialPermission()823 private void enforceReadCredentialPermission() { 824 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL, 825 "WifiService"); 826 } 827 enforceWorkSourcePermission()828 private void enforceWorkSourcePermission() { 829 mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 830 "WifiService"); 831 832 } 833 enforceMulticastChangePermission()834 private void enforceMulticastChangePermission() { 835 mContext.enforceCallingOrSelfPermission( 836 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 837 "WifiService"); 838 } 839 enforceConnectivityInternalPermission()840 private void enforceConnectivityInternalPermission() { 841 mContext.enforceCallingOrSelfPermission( 842 android.Manifest.permission.CONNECTIVITY_INTERNAL, 843 "ConnectivityService"); 844 } 845 enforceLocationPermission(String pkgName, int uid)846 private void enforceLocationPermission(String pkgName, int uid) { 847 mWifiPermissionsUtil.enforceLocationPermission(pkgName, uid); 848 } 849 850 /** 851 * Helper method to check if the app is allowed to access public API's deprecated in 852 * {@link Build.VERSION_CODES.Q}. 853 * Note: Invoke mAppOps.checkPackage(uid, packageName) before to ensure correct package name. 854 */ isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid)855 private boolean isTargetSdkLessThanQOrPrivileged(String packageName, int pid, int uid) { 856 return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q) 857 || isPrivileged(pid, uid) 858 // DO/PO apps should be able to add/modify saved networks. 859 || isDeviceOrProfileOwner(uid) 860 // TODO: Remove this system app bypass once Q is released. 861 || isSystem(packageName) 862 || mWifiPermissionsUtil.checkSystemAlertWindowPermission(uid, packageName); 863 } 864 865 /** 866 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 867 * @param enable {@code true} to enable, {@code false} to disable. 868 * @return {@code true} if the enable/disable operation was 869 * started or is already in the queue. 870 */ 871 @Override setWifiEnabled(String packageName, boolean enable)872 public synchronized boolean setWifiEnabled(String packageName, boolean enable) { 873 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 874 return false; 875 } 876 boolean isPrivileged = isPrivileged(Binder.getCallingPid(), Binder.getCallingUid()); 877 if (!isPrivileged 878 && !mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q)) { 879 mLog.info("setWifiEnabled not allowed for uid=%") 880 .c(Binder.getCallingUid()).flush(); 881 return false; 882 } 883 // If Airplane mode is enabled, only privileged apps are allowed to toggle Wifi 884 if (mSettingsStore.isAirplaneModeOn() && !isPrivileged) { 885 mLog.err("setWifiEnabled in Airplane mode: only Settings can toggle wifi").flush(); 886 return false; 887 } 888 889 // If SoftAp is enabled, only privileged apps are allowed to toggle wifi 890 boolean apEnabled = mWifiApState == WifiManager.WIFI_AP_STATE_ENABLED; 891 if (apEnabled && !isPrivileged) { 892 mLog.err("setWifiEnabled SoftAp enabled: only Settings can toggle wifi").flush(); 893 return false; 894 } 895 896 mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName) 897 .c(Binder.getCallingUid()).c(enable).flush(); 898 long ident = Binder.clearCallingIdentity(); 899 try { 900 if (!mSettingsStore.handleWifiToggled(enable)) { 901 // Nothing to do if wifi cannot be toggled 902 return true; 903 } 904 } finally { 905 Binder.restoreCallingIdentity(ident); 906 } 907 mWifiMetrics.incrementNumWifiToggles(isPrivileged, enable); 908 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 909 return true; 910 } 911 912 /** 913 * see {@link WifiManager#getWifiState()} 914 * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, 915 * {@link WifiManager#WIFI_STATE_DISABLING}, 916 * {@link WifiManager#WIFI_STATE_ENABLED}, 917 * {@link WifiManager#WIFI_STATE_ENABLING}, 918 * {@link WifiManager#WIFI_STATE_UNKNOWN} 919 */ 920 @Override getWifiEnabledState()921 public int getWifiEnabledState() { 922 enforceAccessPermission(); 923 if (mVerboseLoggingEnabled) { 924 mLog.info("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush(); 925 } 926 return mClientModeImpl.syncGetWifiState(); 927 } 928 929 /** 930 * see {@link WifiManager#getWifiApState()} 931 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 932 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 933 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 934 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 935 * {@link WifiManager#WIFI_AP_STATE_FAILED} 936 */ 937 @Override getWifiApEnabledState()938 public int getWifiApEnabledState() { 939 enforceAccessPermission(); 940 if (mVerboseLoggingEnabled) { 941 mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush(); 942 } 943 944 // hand off work to our handler thread 945 MutableInt apState = new MutableInt(WifiManager.WIFI_AP_STATE_DISABLED); 946 mWifiInjector.getClientModeImplHandler().runWithScissors(() -> { 947 apState.value = mWifiApState; 948 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 949 return apState.value; 950 } 951 952 /** 953 * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)} 954 * 955 * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED}, 956 * {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY}, 957 * {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR} 958 * 959 * @param ifaceName String name of the updated interface 960 * @param mode new operating mode of the interface 961 * 962 * @throws SecurityException if the caller does not have permission to call update 963 */ 964 @Override updateInterfaceIpState(String ifaceName, int mode)965 public void updateInterfaceIpState(String ifaceName, int mode) { 966 // NETWORK_STACK is a signature only permission. 967 enforceNetworkStackPermission(); 968 mLog.info("updateInterfaceIpState uid=%").c(Binder.getCallingUid()).flush(); 969 970 // hand off the work to our handler thread 971 mWifiInjector.getClientModeImplHandler().post(() -> { 972 updateInterfaceIpStateInternal(ifaceName, mode); 973 }); 974 } 975 updateInterfaceIpStateInternal(String ifaceName, int mode)976 private void updateInterfaceIpStateInternal(String ifaceName, int mode) { 977 // update interface IP state related to tethering and hotspot 978 synchronized (mLocalOnlyHotspotRequests) { 979 // update the mode tracker here - we clear out state below 980 Integer previousMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED; 981 if (ifaceName != null) { 982 previousMode = mIfaceIpModes.put(ifaceName, mode); 983 } 984 Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode 985 + " previous mode= " + previousMode); 986 987 switch (mode) { 988 case WifiManager.IFACE_IP_MODE_LOCAL_ONLY: 989 // first make sure we have registered requests.. otherwise clean up 990 if (mLocalOnlyHotspotRequests.isEmpty()) { 991 // we don't have requests... stop the hotspot 992 stopSoftAp(); 993 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED); 994 return; 995 } 996 // LOHS is ready to go! Call our registered requestors! 997 sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked(); 998 break; 999 case WifiManager.IFACE_IP_MODE_TETHERED: 1000 if (!isConcurrentLohsAndTetheringSupported()) { 1001 /* We have tethered an interface. We don't really act on this now other than 1002 * if we have LOHS requests, and this is an issue. Return incompatible mode 1003 * for onFailed for the registered requestors since this can result from a 1004 * race between a tether request and a hotspot request (tethering wins). */ 1005 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked( 1006 LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE); 1007 } 1008 break; 1009 case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR: 1010 Slog.d(TAG, "IP mode config error - need to clean up"); 1011 if (mLocalOnlyHotspotRequests.isEmpty()) { 1012 Slog.d(TAG, "no LOHS requests, stop softap"); 1013 stopSoftAp(); 1014 } else { 1015 Slog.d(TAG, "we have LOHS requests, clean them up"); 1016 // there was an error setting up the hotspot... trigger onFailed for the 1017 // registered LOHS requestors 1018 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked( 1019 LocalOnlyHotspotCallback.ERROR_GENERIC); 1020 } 1021 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED); 1022 break; 1023 case WifiManager.IFACE_IP_MODE_UNSPECIFIED: 1024 if (ifaceName == null) { 1025 // interface name is null, this is due to softap teardown. clear all 1026 // entries for now. 1027 // TODO: Deal with individual interfaces when we receive updates for them 1028 mIfaceIpModes.clear(); 1029 return; 1030 } 1031 break; 1032 default: 1033 mLog.warn("updateInterfaceIpStateInternal: unknown mode %").c(mode).flush(); 1034 } 1035 } 1036 } 1037 1038 /** 1039 * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)} 1040 * @param wifiConfig SSID, security and channel details as part of WifiConfiguration 1041 * @return {@code true} if softap start was triggered 1042 * @throws SecurityException if the caller does not have permission to start softap 1043 */ 1044 @Override startSoftAp(WifiConfiguration wifiConfig)1045 public boolean startSoftAp(WifiConfiguration wifiConfig) { 1046 // NETWORK_STACK is a signature only permission. 1047 enforceNetworkStackPermission(); 1048 1049 mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush(); 1050 1051 synchronized (mLocalOnlyHotspotRequests) { 1052 // If a tethering request comes in while we have an existing tethering session, return 1053 // error. 1054 if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) { 1055 mLog.err("Tethering is already active.").flush(); 1056 return false; 1057 } 1058 // If a tethering request comes in while we have LOHS running (or requested), call stop 1059 // for softap mode and restart softap with the tethering config. 1060 if (!isConcurrentLohsAndTetheringSupported() && !mLocalOnlyHotspotRequests.isEmpty()) { 1061 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); 1062 } 1063 return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED); 1064 } 1065 } 1066 1067 /** 1068 * Internal method to start softap mode. Callers of this method should have already checked 1069 * proper permissions beyond the NetworkStack permission. 1070 */ startSoftApInternal(WifiConfiguration wifiConfig, int mode)1071 private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) { 1072 mLog.trace("startSoftApInternal uid=% mode=%") 1073 .c(Binder.getCallingUid()).c(mode).flush(); 1074 1075 // null wifiConfig is a meaningful input for CMD_SET_AP 1076 if (wifiConfig == null || WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) { 1077 SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig); 1078 mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig); 1079 return true; 1080 } 1081 Slog.e(TAG, "Invalid WifiConfiguration"); 1082 return false; 1083 } 1084 1085 /** 1086 * see {@link android.net.wifi.WifiManager#stopSoftAp()} 1087 * @return {@code true} if softap stop was triggered 1088 * @throws SecurityException if the caller does not have permission to stop softap 1089 */ 1090 @Override stopSoftAp()1091 public boolean stopSoftAp() { 1092 // NETWORK_STACK is a signature only permission. 1093 enforceNetworkStackPermission(); 1094 1095 // only permitted callers are allowed to this point - they must have gone through 1096 // connectivity service since this method is protected with the NETWORK_STACK PERMISSION 1097 1098 mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush(); 1099 1100 synchronized (mLocalOnlyHotspotRequests) { 1101 // If a tethering request comes in while we have LOHS running (or requested), call stop 1102 // for softap mode and restart softap with the tethering config. 1103 if (!mLocalOnlyHotspotRequests.isEmpty()) { 1104 // This shouldn't affect devices that support concurrent LOHS and tethering 1105 mLog.trace("Call to stop Tethering while LOHS is active," 1106 + " Registered LOHS callers will be updated when softap stopped.").flush(); 1107 } 1108 1109 return stopSoftApInternal(WifiManager.IFACE_IP_MODE_TETHERED); 1110 } 1111 } 1112 1113 /** 1114 * Internal method to stop softap mode. Callers of this method should have already checked 1115 * proper permissions beyond the NetworkStack permission. 1116 */ stopSoftApInternal(int mode)1117 private boolean stopSoftApInternal(int mode) { 1118 mLog.trace("stopSoftApInternal uid=%").c(Binder.getCallingUid()).flush(); 1119 1120 mWifiController.sendMessage(CMD_SET_AP, 0, mode); 1121 return true; 1122 } 1123 1124 /** 1125 * Callback to use with ClientModeImpl to receive events from ClientModeImpl 1126 * 1127 * @hide 1128 */ 1129 private final class SoftApCallbackImpl implements WifiManager.SoftApCallback { 1130 /** 1131 * Called when soft AP state changes. 1132 * 1133 * @param state new new AP state. One of {@link #WIFI_AP_STATE_DISABLED}, 1134 * {@link #WIFI_AP_STATE_DISABLING}, {@link #WIFI_AP_STATE_ENABLED}, 1135 * {@link #WIFI_AP_STATE_ENABLING}, {@link #WIFI_AP_STATE_FAILED} 1136 * @param failureReason reason when in failed state. One of 1137 * {@link #SAP_START_FAILURE_GENERAL}, {@link #SAP_START_FAILURE_NO_CHANNEL} 1138 */ 1139 @Override onStateChanged(int state, int failureReason)1140 public void onStateChanged(int state, int failureReason) { 1141 mSoftApState = state; 1142 1143 Iterator<ISoftApCallback> iterator = 1144 mRegisteredSoftApCallbacks.getCallbacks().iterator(); 1145 while (iterator.hasNext()) { 1146 ISoftApCallback callback = iterator.next(); 1147 try { 1148 callback.onStateChanged(state, failureReason); 1149 } catch (RemoteException e) { 1150 Log.e(TAG, "onStateChanged: remote exception -- " + e); 1151 iterator.remove(); 1152 } 1153 } 1154 } 1155 1156 /** 1157 * Called when number of connected clients to soft AP changes. 1158 * 1159 * @param numClients number of connected clients to soft AP 1160 */ 1161 @Override onNumClientsChanged(int numClients)1162 public void onNumClientsChanged(int numClients) { 1163 mSoftApNumClients = numClients; 1164 1165 Iterator<ISoftApCallback> iterator = 1166 mRegisteredSoftApCallbacks.getCallbacks().iterator(); 1167 while (iterator.hasNext()) { 1168 ISoftApCallback callback = iterator.next(); 1169 try { 1170 callback.onNumClientsChanged(numClients); 1171 } catch (RemoteException e) { 1172 Log.e(TAG, "onNumClientsChanged: remote exception -- " + e); 1173 iterator.remove(); 1174 } 1175 } 1176 } 1177 } 1178 1179 /** 1180 * see {@link android.net.wifi.WifiManager#registerSoftApCallback(SoftApCallback, Handler)} 1181 * 1182 * @param binder IBinder instance to allow cleanup if the app dies 1183 * @param callback Soft AP callback to register 1184 * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to 1185 * unregister the callback. See {@link unregisterSoftApCallback(int)} 1186 * 1187 * @throws SecurityException if the caller does not have permission to register a callback 1188 * @throws RemoteException if remote exception happens 1189 * @throws IllegalArgumentException if the arguments are null or invalid 1190 */ 1191 @Override registerSoftApCallback(IBinder binder, ISoftApCallback callback, int callbackIdentifier)1192 public void registerSoftApCallback(IBinder binder, ISoftApCallback callback, 1193 int callbackIdentifier) { 1194 // verify arguments 1195 if (binder == null) { 1196 throw new IllegalArgumentException("Binder must not be null"); 1197 } 1198 if (callback == null) { 1199 throw new IllegalArgumentException("Callback must not be null"); 1200 } 1201 1202 enforceNetworkSettingsPermission(); 1203 if (mVerboseLoggingEnabled) { 1204 mLog.info("registerSoftApCallback uid=%").c(Binder.getCallingUid()).flush(); 1205 } 1206 1207 // post operation to handler thread 1208 mWifiInjector.getClientModeImplHandler().post(() -> { 1209 if (!mRegisteredSoftApCallbacks.add(binder, callback, callbackIdentifier)) { 1210 Log.e(TAG, "registerSoftApCallback: Failed to add callback"); 1211 return; 1212 } 1213 // Update the client about the current state immediately after registering the callback 1214 try { 1215 callback.onStateChanged(mSoftApState, 0); 1216 callback.onNumClientsChanged(mSoftApNumClients); 1217 } catch (RemoteException e) { 1218 Log.e(TAG, "registerSoftApCallback: remote exception -- " + e); 1219 } 1220 1221 }); 1222 } 1223 1224 /** 1225 * see {@link android.net.wifi.WifiManager#unregisterSoftApCallback(SoftApCallback)} 1226 * 1227 * @param callbackIdentifier Unique ID of the callback to be unregistered. 1228 * 1229 * @throws SecurityException if the caller does not have permission to register a callback 1230 */ 1231 @Override unregisterSoftApCallback(int callbackIdentifier)1232 public void unregisterSoftApCallback(int callbackIdentifier) { 1233 1234 enforceNetworkSettingsPermission(); 1235 if (mVerboseLoggingEnabled) { 1236 mLog.info("unregisterSoftApCallback uid=%").c(Binder.getCallingUid()).flush(); 1237 } 1238 1239 // post operation to handler thread 1240 mWifiInjector.getClientModeImplHandler().post(() -> { 1241 mRegisteredSoftApCallbacks.remove(callbackIdentifier); 1242 }); 1243 } 1244 1245 /** 1246 * Private method to handle SoftAp state changes 1247 * 1248 * <p> MUST be called from the ClientModeImpl thread. 1249 */ handleWifiApStateChange( int currentState, int previousState, int errorCode, String ifaceName, int mode)1250 private void handleWifiApStateChange( 1251 int currentState, int previousState, int errorCode, String ifaceName, int mode) { 1252 // The AP state update from ClientModeImpl for softap 1253 Slog.d(TAG, "handleWifiApStateChange: currentState=" + currentState 1254 + " previousState=" + previousState + " errorCode= " + errorCode 1255 + " ifaceName=" + ifaceName + " mode=" + mode); 1256 1257 // update the tracking ap state variable 1258 mWifiApState = currentState; 1259 1260 // check if we have a failure - since it is possible (worst case scenario where 1261 // WifiController and ClientModeImpl are out of sync wrt modes) to get two FAILED 1262 // notifications in a row, we need to handle this first. 1263 if (currentState == WIFI_AP_STATE_FAILED) { 1264 // update registered LOHS callbacks if we see a failure 1265 synchronized (mLocalOnlyHotspotRequests) { 1266 int errorToReport = ERROR_GENERIC; 1267 if (errorCode == SAP_START_FAILURE_NO_CHANNEL) { 1268 errorToReport = ERROR_NO_CHANNEL; 1269 } 1270 // holding the required lock: send message to requestors and clear the list 1271 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked( 1272 errorToReport); 1273 // also need to clear interface ip state - send null for now since we don't know 1274 // what interface (and we have one anyway) 1275 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED); 1276 } 1277 return; 1278 } 1279 1280 if (currentState == WIFI_AP_STATE_DISABLING || currentState == WIFI_AP_STATE_DISABLED) { 1281 // softap is shutting down or is down... let requestors know via the onStopped call 1282 synchronized (mLocalOnlyHotspotRequests) { 1283 // if we are currently in hotspot mode, then trigger onStopped for registered 1284 // requestors, otherwise something odd happened and we should clear state 1285 if (mIfaceIpModes.getOrDefault(ifaceName, WifiManager.IFACE_IP_MODE_UNSPECIFIED) 1286 == WifiManager.IFACE_IP_MODE_LOCAL_ONLY) { 1287 // holding the required lock: send message to requestors and clear the list 1288 sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked(); 1289 } else if (!isConcurrentLohsAndTetheringSupported()) { 1290 // LOHS not active: report an error (still holding the required lock) 1291 sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC); 1292 } 1293 // also clear interface ip state - send null for now since we don't know what 1294 // interface (and we only have one anyway) 1295 updateInterfaceIpState(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED); 1296 } 1297 return; 1298 } 1299 1300 // remaining states are enabling or enabled... those are not used for the callbacks 1301 } 1302 1303 /** 1304 * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest 1305 * callers and clear the registrations. 1306 * 1307 * Callers should already hold the mLocalOnlyHotspotRequests lock. 1308 */ 1309 @GuardedBy("mLocalOnlyHotspotRequests") sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int arg1)1310 private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int arg1) { 1311 for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) { 1312 try { 1313 requestor.sendHotspotFailedMessage(arg1); 1314 requestor.unlinkDeathRecipient(); 1315 } catch (RemoteException e) { 1316 // This will be cleaned up by binder death handling 1317 } 1318 } 1319 1320 // Since all callers were notified, now clear the registrations. 1321 mLocalOnlyHotspotRequests.clear(); 1322 } 1323 1324 /** 1325 * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest 1326 * callers and clear the registrations. 1327 * 1328 * Callers should already hold the mLocalOnlyHotspotRequests lock. 1329 */ 1330 @GuardedBy("mLocalOnlyHotspotRequests") sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked()1331 private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() { 1332 for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) { 1333 try { 1334 requestor.sendHotspotStoppedMessage(); 1335 requestor.unlinkDeathRecipient(); 1336 } catch (RemoteException e) { 1337 // This will be cleaned up by binder death handling 1338 } 1339 } 1340 1341 // Since all callers were notified, now clear the registrations. 1342 mLocalOnlyHotspotRequests.clear(); 1343 } 1344 1345 /** 1346 * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest 1347 * callers. 1348 * 1349 * Callers should already hold the mLocalOnlyHotspotRequests lock. 1350 */ 1351 @GuardedBy("mLocalOnlyHotspotRequests") sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked()1352 private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() { 1353 for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) { 1354 try { 1355 requestor.sendHotspotStartedMessage(mLocalOnlyHotspotConfig); 1356 } catch (RemoteException e) { 1357 // This will be cleaned up by binder death handling 1358 } 1359 } 1360 } 1361 1362 /** 1363 * Temporary method used for testing while startLocalOnlyHotspot is not fully implemented. This 1364 * method allows unit tests to register callbacks directly for testing mechanisms triggered by 1365 * softap mode changes. 1366 */ 1367 @VisibleForTesting registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request)1368 void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) { 1369 mLocalOnlyHotspotRequests.put(pid, request); 1370 } 1371 1372 /** 1373 * Method to start LocalOnlyHotspot. In this method, permissions, settings and modes are 1374 * checked to verify that we can enter softapmode. This method returns 1375 * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise, 1376 * possible startup erros may include tethering being disallowed failure reason {@link 1377 * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason 1378 * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}. 1379 * 1380 * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)} 1381 * 1382 * @param messenger Messenger to send messages to the corresponding WifiManager. 1383 * @param binder IBinder instance to allow cleanup if the app dies 1384 * @param packageName String name of the calling package 1385 * 1386 * @return int return code for attempt to start LocalOnlyHotspot. 1387 * 1388 * @throws SecurityException if the caller does not have permission to start a Local Only 1389 * Hotspot. 1390 * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they 1391 * have an outstanding request. 1392 */ 1393 @Override startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName)1394 public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) { 1395 // first check if the caller has permission to start a local only hotspot 1396 // need to check for WIFI_STATE_CHANGE and location permission 1397 final int uid = Binder.getCallingUid(); 1398 final int pid = Binder.getCallingPid(); 1399 1400 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1401 return LocalOnlyHotspotCallback.ERROR_GENERIC; 1402 } 1403 enforceLocationPermission(packageName, uid); 1404 long ident = Binder.clearCallingIdentity(); 1405 try { 1406 // also need to verify that Locations services are enabled. 1407 if (!mWifiPermissionsUtil.isLocationModeEnabled()) { 1408 throw new SecurityException("Location mode is not enabled."); 1409 } 1410 } finally { 1411 Binder.restoreCallingIdentity(ident); 1412 } 1413 1414 // verify that tethering is not disabled 1415 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { 1416 return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED; 1417 } 1418 1419 // the app should be in the foreground 1420 if (!mFrameworkFacade.isAppForeground(uid)) { 1421 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE; 1422 } 1423 1424 mLog.info("startLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush(); 1425 1426 synchronized (mLocalOnlyHotspotRequests) { 1427 // check if we are currently tethering 1428 // TODO(b/123227116): handle all interface combinations just by changing the HAL. 1429 if (!isConcurrentLohsAndTetheringSupported() 1430 && mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) { 1431 // Tethering is enabled, cannot start LocalOnlyHotspot 1432 mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.").flush(); 1433 return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE; 1434 } 1435 1436 // does this caller already have a request? 1437 LocalOnlyHotspotRequestInfo request = mLocalOnlyHotspotRequests.get(pid); 1438 if (request != null) { 1439 mLog.trace("caller already has an active request").flush(); 1440 throw new IllegalStateException( 1441 "Caller already has an active LocalOnlyHotspot request"); 1442 } 1443 1444 // now create the new LOHS request info object 1445 request = new LocalOnlyHotspotRequestInfo(binder, messenger, 1446 new LocalOnlyRequestorCallback()); 1447 1448 // check current operating state and take action if needed 1449 if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) { 1450 // LOHS is already active, send out what is running 1451 try { 1452 mLog.trace("LOHS already up, trigger onStarted callback").flush(); 1453 request.sendHotspotStartedMessage(mLocalOnlyHotspotConfig); 1454 } catch (RemoteException e) { 1455 return LocalOnlyHotspotCallback.ERROR_GENERIC; 1456 } 1457 } else if (mLocalOnlyHotspotRequests.isEmpty()) { 1458 // this is the first request, then set up our config and start LOHS 1459 boolean is5Ghz = hasAutomotiveFeature(mContext) 1460 && mContext.getResources().getBoolean( 1461 com.android.internal.R.bool.config_wifi_local_only_hotspot_5ghz) 1462 && is5GhzSupported(); 1463 1464 mLocalOnlyHotspotConfig = WifiApConfigStore.generateLocalOnlyHotspotConfig(mContext, 1465 is5Ghz ? WifiConfiguration.AP_BAND_5GHZ : WifiConfiguration.AP_BAND_2GHZ); 1466 1467 startSoftApInternal(mLocalOnlyHotspotConfig, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); 1468 } 1469 1470 mLocalOnlyHotspotRequests.put(pid, request); 1471 return LocalOnlyHotspotCallback.REQUEST_REGISTERED; 1472 } 1473 } 1474 1475 /** 1476 * see {@link WifiManager#stopLocalOnlyHotspot()} 1477 * 1478 * @throws SecurityException if the caller does not have permission to stop a Local Only 1479 * Hotspot. 1480 */ 1481 @Override stopLocalOnlyHotspot()1482 public void stopLocalOnlyHotspot() { 1483 // don't do a permission check here. if the app's permission to change the wifi state is 1484 // revoked, we still want them to be able to stop a previously created hotspot (otherwise 1485 // it could cost the user money). When the app created the hotspot, its permission was 1486 // checked. 1487 final int uid = Binder.getCallingUid(); 1488 final int pid = Binder.getCallingPid(); 1489 1490 mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush(); 1491 1492 synchronized (mLocalOnlyHotspotRequests) { 1493 // was the caller already registered? check request tracker - return false if not 1494 LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.get(pid); 1495 if (requestInfo == null) { 1496 return; 1497 } 1498 requestInfo.unlinkDeathRecipient(); 1499 unregisterCallingAppAndStopLocalOnlyHotspot(requestInfo); 1500 } // end synchronized 1501 } 1502 1503 /** 1504 * Helper method to unregister LocalOnlyHotspot requestors and stop the hotspot if needed. 1505 */ unregisterCallingAppAndStopLocalOnlyHotspot(LocalOnlyHotspotRequestInfo request)1506 private void unregisterCallingAppAndStopLocalOnlyHotspot(LocalOnlyHotspotRequestInfo request) { 1507 mLog.trace("unregisterCallingAppAndStopLocalOnlyHotspot pid=%").c(request.getPid()).flush(); 1508 1509 synchronized (mLocalOnlyHotspotRequests) { 1510 if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) { 1511 mLog.trace("LocalOnlyHotspotRequestInfo not found to remove").flush(); 1512 return; 1513 } 1514 1515 if (mLocalOnlyHotspotRequests.isEmpty()) { 1516 mLocalOnlyHotspotConfig = null; 1517 updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED); 1518 // if that was the last caller, then call stopSoftAp as WifiService 1519 long identity = Binder.clearCallingIdentity(); 1520 try { 1521 stopSoftApInternal(WifiManager.IFACE_IP_MODE_LOCAL_ONLY); 1522 } finally { 1523 Binder.restoreCallingIdentity(identity); 1524 } 1525 } 1526 } 1527 } 1528 1529 /** 1530 * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)} 1531 * 1532 * This call requires the android.permission.NETWORK_SETTINGS permission. 1533 * 1534 * @param messenger Messenger to send messages to the corresponding WifiManager. 1535 * @param binder IBinder instance to allow cleanup if the app dies 1536 * 1537 * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot 1538 * status updates. 1539 * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with 1540 * an existing subscription. 1541 */ 1542 @Override startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder)1543 public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) { 1544 // NETWORK_SETTINGS is a signature only permission. 1545 enforceNetworkSettingsPermission(); 1546 1547 throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); 1548 } 1549 1550 /** 1551 * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()} 1552 */ 1553 @Override stopWatchLocalOnlyHotspot()1554 public void stopWatchLocalOnlyHotspot() { 1555 // NETWORK_STACK is a signature only permission. 1556 enforceNetworkSettingsPermission(); 1557 throw new UnsupportedOperationException("LocalOnlyHotspot is still in development"); 1558 } 1559 1560 /** 1561 * see {@link WifiManager#getWifiApConfiguration()} 1562 * @return soft access point configuration 1563 * @throws SecurityException if the caller does not have permission to retrieve the softap 1564 * config 1565 */ 1566 @Override getWifiApConfiguration()1567 public WifiConfiguration getWifiApConfiguration() { 1568 enforceAccessPermission(); 1569 int uid = Binder.getCallingUid(); 1570 // only allow Settings UI to get the saved SoftApConfig 1571 if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { 1572 // random apps should not be allowed to read the user specified config 1573 throw new SecurityException("App not allowed to read or update stored WiFi Ap config " 1574 + "(uid = " + uid + ")"); 1575 } 1576 mLog.info("getWifiApConfiguration uid=%").c(uid).flush(); 1577 1578 // hand off work to the ClientModeImpl handler thread to sync work between calls 1579 // and SoftApManager starting up softap 1580 final Mutable<WifiConfiguration> config = new Mutable(); 1581 boolean success = mWifiInjector.getClientModeImplHandler().runWithScissors(() -> { 1582 config.value = mWifiApConfigStore.getApConfiguration(); 1583 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 1584 if (success) { 1585 return config.value; 1586 } 1587 Log.e(TAG, "Failed to post runnable to fetch ap config"); 1588 return new WifiConfiguration(); 1589 } 1590 1591 /** 1592 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)} 1593 * @param wifiConfig WifiConfiguration details for soft access point 1594 * @return boolean indicating success or failure of the operation 1595 * @throws SecurityException if the caller does not have permission to write the softap config 1596 */ 1597 @Override setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName)1598 public boolean setWifiApConfiguration(WifiConfiguration wifiConfig, String packageName) { 1599 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1600 return false; 1601 } 1602 int uid = Binder.getCallingUid(); 1603 // only allow Settings UI to write the stored SoftApConfig 1604 if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) { 1605 // random apps should not be allowed to read the user specified config 1606 throw new SecurityException("App not allowed to read or update stored WiFi AP config " 1607 + "(uid = " + uid + ")"); 1608 } 1609 mLog.info("setWifiApConfiguration uid=%").c(uid).flush(); 1610 if (wifiConfig == null) 1611 return false; 1612 if (WifiApConfigStore.validateApWifiConfiguration(wifiConfig)) { 1613 mClientModeImplHandler.post(() -> { 1614 mWifiApConfigStore.setApConfiguration(wifiConfig); 1615 }); 1616 return true; 1617 } else { 1618 Slog.e(TAG, "Invalid WifiConfiguration"); 1619 return false; 1620 } 1621 } 1622 1623 /** 1624 * Method used to inform user of Ap Configuration conversion due to hardware. 1625 */ 1626 @Override notifyUserOfApBandConversion(String packageName)1627 public void notifyUserOfApBandConversion(String packageName) { 1628 enforceNetworkSettingsPermission(); 1629 1630 if (mVerboseLoggingEnabled) { 1631 mLog.info("notifyUserOfApBandConversion uid=% packageName=%") 1632 .c(Binder.getCallingUid()).c(packageName).flush(); 1633 } 1634 1635 mWifiApConfigStore.notifyUserOfApBandConversion(packageName); 1636 } 1637 1638 /** 1639 * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()} 1640 */ 1641 @Override isScanAlwaysAvailable()1642 public boolean isScanAlwaysAvailable() { 1643 enforceAccessPermission(); 1644 if (mVerboseLoggingEnabled) { 1645 mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush(); 1646 } 1647 return mSettingsStore.isScanAlwaysAvailable(); 1648 } 1649 1650 /** 1651 * see {@link android.net.wifi.WifiManager#disconnect()} 1652 */ 1653 @Override disconnect(String packageName)1654 public boolean disconnect(String packageName) { 1655 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1656 return false; 1657 } 1658 if (!isTargetSdkLessThanQOrPrivileged( 1659 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 1660 mLog.info("disconnect not allowed for uid=%") 1661 .c(Binder.getCallingUid()).flush(); 1662 return false; 1663 } 1664 mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush(); 1665 mClientModeImpl.disconnectCommand(); 1666 return true; 1667 } 1668 1669 /** 1670 * see {@link android.net.wifi.WifiManager#reconnect()} 1671 */ 1672 @Override reconnect(String packageName)1673 public boolean reconnect(String packageName) { 1674 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1675 return false; 1676 } 1677 if (!isTargetSdkLessThanQOrPrivileged( 1678 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 1679 mLog.info("reconnect not allowed for uid=%") 1680 .c(Binder.getCallingUid()).flush(); 1681 return false; 1682 } 1683 mLog.info("reconnect uid=%").c(Binder.getCallingUid()).flush(); 1684 mClientModeImpl.reconnectCommand(new WorkSource(Binder.getCallingUid())); 1685 return true; 1686 } 1687 1688 /** 1689 * see {@link android.net.wifi.WifiManager#reassociate()} 1690 */ 1691 @Override reassociate(String packageName)1692 public boolean reassociate(String packageName) { 1693 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 1694 return false; 1695 } 1696 if (!isTargetSdkLessThanQOrPrivileged( 1697 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 1698 mLog.info("reassociate not allowed for uid=%") 1699 .c(Binder.getCallingUid()).flush(); 1700 return false; 1701 } 1702 mLog.info("reassociate uid=%").c(Binder.getCallingUid()).flush(); 1703 mClientModeImpl.reassociateCommand(); 1704 return true; 1705 } 1706 1707 /** 1708 * see {@link android.net.wifi.WifiManager#getSupportedFeatures} 1709 */ 1710 @Override getSupportedFeatures()1711 public long getSupportedFeatures() { 1712 enforceAccessPermission(); 1713 if (mVerboseLoggingEnabled) { 1714 mLog.info("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush(); 1715 } 1716 return getSupportedFeaturesInternal(); 1717 } 1718 1719 @Override requestActivityInfo(ResultReceiver result)1720 public void requestActivityInfo(ResultReceiver result) { 1721 Bundle bundle = new Bundle(); 1722 if (mVerboseLoggingEnabled) { 1723 mLog.info("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush(); 1724 } 1725 bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo()); 1726 result.send(0, bundle); 1727 } 1728 1729 /** 1730 * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)} 1731 */ 1732 @Override reportActivityInfo()1733 public WifiActivityEnergyInfo reportActivityInfo() { 1734 enforceAccessPermission(); 1735 if (mVerboseLoggingEnabled) { 1736 mLog.info("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush(); 1737 } 1738 if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) { 1739 return null; 1740 } 1741 WifiLinkLayerStats stats; 1742 WifiActivityEnergyInfo energyInfo = null; 1743 if (mClientModeImplChannel != null) { 1744 stats = mClientModeImpl.syncGetLinkLayerStats(mClientModeImplChannel); 1745 if (stats != null) { 1746 final double rxIdleCurrent = mPowerProfile.getAveragePower( 1747 PowerProfile.POWER_WIFI_CONTROLLER_IDLE); 1748 final double rxCurrent = mPowerProfile.getAveragePower( 1749 PowerProfile.POWER_WIFI_CONTROLLER_RX); 1750 final double txCurrent = mPowerProfile.getAveragePower( 1751 PowerProfile.POWER_WIFI_CONTROLLER_TX); 1752 final double voltage = mPowerProfile.getAveragePower( 1753 PowerProfile.POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE) / 1000.0; 1754 final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time; 1755 final long[] txTimePerLevel; 1756 if (stats.tx_time_per_level != null) { 1757 txTimePerLevel = new long[stats.tx_time_per_level.length]; 1758 for (int i = 0; i < txTimePerLevel.length; i++) { 1759 txTimePerLevel[i] = stats.tx_time_per_level[i]; 1760 // TODO(b/27227497): Need to read the power consumed per level from config 1761 } 1762 } else { 1763 // This will happen if the HAL get link layer API returned null. 1764 txTimePerLevel = new long[0]; 1765 } 1766 final long energyUsed = (long)((stats.tx_time * txCurrent + 1767 stats.rx_time * rxCurrent + 1768 rxIdleTime * rxIdleCurrent) * voltage); 1769 if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 || 1770 stats.rx_time < 0 || stats.on_time_scan < 0 || energyUsed < 0) { 1771 StringBuilder sb = new StringBuilder(); 1772 sb.append(" rxIdleCur=" + rxIdleCurrent); 1773 sb.append(" rxCur=" + rxCurrent); 1774 sb.append(" txCur=" + txCurrent); 1775 sb.append(" voltage=" + voltage); 1776 sb.append(" on_time=" + stats.on_time); 1777 sb.append(" tx_time=" + stats.tx_time); 1778 sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel)); 1779 sb.append(" rx_time=" + stats.rx_time); 1780 sb.append(" rxIdleTime=" + rxIdleTime); 1781 sb.append(" scan_time=" + stats.on_time_scan); 1782 sb.append(" energy=" + energyUsed); 1783 Log.d(TAG, " reportActivityInfo: " + sb.toString()); 1784 } 1785 1786 // Convert the LinkLayerStats into EnergyActivity 1787 energyInfo = new WifiActivityEnergyInfo(mClock.getElapsedSinceBootMillis(), 1788 WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time, 1789 txTimePerLevel, stats.rx_time, stats.on_time_scan, rxIdleTime, energyUsed); 1790 } 1791 if (energyInfo != null && energyInfo.isValid()) { 1792 return energyInfo; 1793 } else { 1794 return null; 1795 } 1796 } else { 1797 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 1798 return null; 1799 } 1800 } 1801 1802 /** 1803 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 1804 * 1805 * @param packageName String name of the calling package 1806 * @return the list of configured networks 1807 */ 1808 @Override getConfiguredNetworks(String packageName)1809 public ParceledListSlice<WifiConfiguration> getConfiguredNetworks(String packageName) { 1810 enforceAccessPermission(); 1811 int callingUid = Binder.getCallingUid(); 1812 // bypass shell: can get varioud pkg name 1813 if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { 1814 long ident = Binder.clearCallingIdentity(); 1815 try { 1816 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid); 1817 } catch (SecurityException e) { 1818 Slog.e(TAG, "Permission violation - getConfiguredNetworks not allowed for uid=" 1819 + callingUid + ", packageName=" + packageName + ", reason=" + e); 1820 return new ParceledListSlice<>(new ArrayList<>()); 1821 } finally { 1822 Binder.restoreCallingIdentity(ident); 1823 } 1824 } 1825 boolean isTargetSdkLessThanQOrPrivileged = isTargetSdkLessThanQOrPrivileged( 1826 packageName, Binder.getCallingPid(), callingUid); 1827 boolean isCarrierApp = mWifiInjector.makeTelephonyManager() 1828 .checkCarrierPrivilegesForPackageAnyPhone(packageName) 1829 == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; 1830 if (!isTargetSdkLessThanQOrPrivileged && !isCarrierApp) { 1831 mLog.info("getConfiguredNetworks not allowed for uid=%") 1832 .c(callingUid).flush(); 1833 return new ParceledListSlice<>(new ArrayList<>()); 1834 } 1835 if (mVerboseLoggingEnabled) { 1836 mLog.info("getConfiguredNetworks uid=%").c(callingUid).flush(); 1837 } 1838 1839 int targetConfigUid = Process.INVALID_UID; // don't expose any MAC addresses 1840 if (isPrivileged(getCallingPid(), callingUid) || isDeviceOrProfileOwner(callingUid)) { 1841 targetConfigUid = Process.WIFI_UID; // expose all MAC addresses 1842 } else if (isCarrierApp) { 1843 targetConfigUid = callingUid; // expose only those configs created by the Carrier App 1844 } 1845 1846 if (mClientModeImplChannel != null) { 1847 List<WifiConfiguration> configs = mClientModeImpl.syncGetConfiguredNetworks( 1848 callingUid, mClientModeImplChannel, targetConfigUid); 1849 if (configs != null) { 1850 if (isTargetSdkLessThanQOrPrivileged) { 1851 return new ParceledListSlice<WifiConfiguration>(configs); 1852 } else { // Carrier app: should only get its own configs 1853 List<WifiConfiguration> creatorConfigs = new ArrayList<>(); 1854 for (WifiConfiguration config : configs) { 1855 if (config.creatorUid == callingUid) { 1856 creatorConfigs.add(config); 1857 } 1858 } 1859 return new ParceledListSlice<WifiConfiguration>(creatorConfigs); 1860 } 1861 } 1862 } else { 1863 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 1864 } 1865 return null; 1866 } 1867 1868 /** 1869 * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()} 1870 * 1871 * @param packageName String name of the calling package 1872 * @return the list of configured networks with real preSharedKey 1873 */ 1874 @Override 1875 public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks(String packageName)1876 getPrivilegedConfiguredNetworks(String packageName) { 1877 enforceReadCredentialPermission(); 1878 enforceAccessPermission(); 1879 int callingUid = Binder.getCallingUid(); 1880 long ident = Binder.clearCallingIdentity(); 1881 try { 1882 mWifiPermissionsUtil.enforceCanAccessScanResults(packageName, callingUid); 1883 } catch (SecurityException e) { 1884 Slog.e(TAG, "Permission violation - getPrivilegedConfiguredNetworks not allowed for" 1885 + " uid=" + callingUid + ", packageName=" + packageName + ", reason=" + e); 1886 return null; 1887 } finally { 1888 Binder.restoreCallingIdentity(ident); 1889 } 1890 if (mVerboseLoggingEnabled) { 1891 mLog.info("getPrivilegedConfiguredNetworks uid=%").c(callingUid).flush(); 1892 } 1893 if (mClientModeImplChannel != null) { 1894 List<WifiConfiguration> configs = 1895 mClientModeImpl.syncGetPrivilegedConfiguredNetwork(mClientModeImplChannel); 1896 if (configs != null) { 1897 return new ParceledListSlice<WifiConfiguration>(configs); 1898 } 1899 } else { 1900 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 1901 } 1902 return null; 1903 } 1904 1905 /** 1906 * Returns the list of FQDN (Fully Qualified Domain Name) to installed Passpoint configurations. 1907 * 1908 * Return the map of all matching configurations with corresponding scanResults (or an empty map 1909 * if none). 1910 * 1911 * @param scanResults The list of scan results 1912 * @return Map that consists of FQDN (Fully Qualified Domain Name) and corresponding 1913 * scanResults per network type({@link WifiManager#PASSPOINT_HOME_NETWORK} and {@link 1914 * WifiManager#PASSPOINT_ROAMING_NETWORK}). 1915 */ 1916 @Override getAllMatchingFqdnsForScanResults( List<ScanResult> scanResults)1917 public Map<String, Map<Integer, List<ScanResult>>> getAllMatchingFqdnsForScanResults( 1918 List<ScanResult> scanResults) { 1919 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 1920 throw new SecurityException(TAG + ": Permission denied"); 1921 } 1922 if (mVerboseLoggingEnabled) { 1923 mLog.info("getMatchingPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush(); 1924 } 1925 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) { 1926 return new HashMap<>(); 1927 } 1928 return mClientModeImpl.syncGetAllMatchingFqdnsForScanResults(scanResults, 1929 mClientModeImplChannel); 1930 } 1931 1932 /** 1933 * Returns list of OSU (Online Sign-Up) providers associated with the given list of ScanResult. 1934 * 1935 * @param scanResults a list of ScanResult that has Passpoint APs. 1936 * @return Map that consists of {@link OsuProvider} and a matching list of {@link ScanResult}. 1937 */ 1938 @Override getMatchingOsuProviders( List<ScanResult> scanResults)1939 public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders( 1940 List<ScanResult> scanResults) { 1941 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 1942 throw new SecurityException(TAG + ": Permission denied"); 1943 } 1944 if (mVerboseLoggingEnabled) { 1945 mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush(); 1946 } 1947 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) { 1948 return new HashMap<>(); 1949 } 1950 return mClientModeImpl.syncGetMatchingOsuProviders(scanResults, mClientModeImplChannel); 1951 } 1952 1953 /** 1954 * Returns the matching Passpoint configurations for given OSU(Online Sign-Up) providers. 1955 * 1956 * @param osuProviders a list of {@link OsuProvider} 1957 * @return Map that consists of {@link OsuProvider} and matching {@link PasspointConfiguration}. 1958 */ 1959 @Override getMatchingPasspointConfigsForOsuProviders( List<OsuProvider> osuProviders)1960 public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders( 1961 List<OsuProvider> osuProviders) { 1962 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 1963 throw new SecurityException(TAG + ": Permission denied"); 1964 } 1965 if (mVerboseLoggingEnabled) { 1966 mLog.info("getMatchingPasspointConfigsForOsuProviders uid=%").c( 1967 Binder.getCallingUid()).flush(); 1968 } 1969 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) { 1970 return new HashMap<>(); 1971 } 1972 if (osuProviders == null) { 1973 Log.e(TAG, "Attempt to retrieve Passpoint configuration with null osuProviders"); 1974 return new HashMap<>(); 1975 } 1976 return mClientModeImpl.syncGetMatchingPasspointConfigsForOsuProviders(osuProviders, 1977 mClientModeImplChannel); 1978 } 1979 1980 /** 1981 * Returns the corresponding wifi configurations for given FQDN (Fully Qualified Domain Name) 1982 * list. 1983 * 1984 * An empty list will be returned when no match is found. 1985 * 1986 * @param fqdnList a list of FQDN 1987 * @return List of {@link WifiConfiguration} converted from {@link PasspointProvider} 1988 */ 1989 @Override getWifiConfigsForPasspointProfiles(List<String> fqdnList)1990 public List<WifiConfiguration> getWifiConfigsForPasspointProfiles(List<String> fqdnList) { 1991 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 1992 throw new SecurityException(TAG + ": Permission denied"); 1993 } 1994 if (mVerboseLoggingEnabled) { 1995 mLog.info("getWifiConfigsForPasspointProfiles uid=%").c( 1996 Binder.getCallingUid()).flush(); 1997 } 1998 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) { 1999 return new ArrayList<>(); 2000 } 2001 if (fqdnList == null) { 2002 Log.e(TAG, "Attempt to retrieve WifiConfiguration with null fqdn List"); 2003 return new ArrayList<>(); 2004 } 2005 return mClientModeImpl.syncGetWifiConfigsForPasspointProfiles(fqdnList, 2006 mClientModeImplChannel); 2007 } 2008 2009 /** 2010 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 2011 * @return the supplicant-assigned identifier for the new or updated 2012 * network if the operation succeeds, or {@code -1} if it fails 2013 */ 2014 @Override addOrUpdateNetwork(WifiConfiguration config, String packageName)2015 public int addOrUpdateNetwork(WifiConfiguration config, String packageName) { 2016 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2017 return -1; 2018 } 2019 if (!isTargetSdkLessThanQOrPrivileged( 2020 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2021 mLog.info("addOrUpdateNetwork not allowed for uid=%") 2022 .c(Binder.getCallingUid()).flush(); 2023 return -1; 2024 } 2025 mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush(); 2026 2027 if (config == null) { 2028 Slog.e(TAG, "bad network configuration"); 2029 return -1; 2030 } 2031 mWifiMetrics.incrementNumAddOrUpdateNetworkCalls(); 2032 2033 // Previously, this API is overloaded for installing Passpoint profiles. Now 2034 // that we have a dedicated API for doing it, redirect the call to the dedicated API. 2035 if (config.isPasspoint()) { 2036 PasspointConfiguration passpointConfig = 2037 PasspointProvider.convertFromWifiConfig(config); 2038 if (passpointConfig.getCredential() == null) { 2039 Slog.e(TAG, "Missing credential for Passpoint profile"); 2040 return -1; 2041 } 2042 2043 // Copy over certificates and keys. 2044 X509Certificate[] x509Certificates = null; 2045 if (config.enterpriseConfig.getCaCertificate() != null) { 2046 x509Certificates = 2047 new X509Certificate[]{config.enterpriseConfig.getCaCertificate()}; 2048 } 2049 passpointConfig.getCredential().setCaCertificates(x509Certificates); 2050 passpointConfig.getCredential().setClientCertificateChain( 2051 config.enterpriseConfig.getClientCertificateChain()); 2052 passpointConfig.getCredential().setClientPrivateKey( 2053 config.enterpriseConfig.getClientPrivateKey()); 2054 if (!addOrUpdatePasspointConfiguration(passpointConfig, packageName)) { 2055 Slog.e(TAG, "Failed to add Passpoint profile"); 2056 return -1; 2057 } 2058 // There is no network ID associated with a Passpoint profile. 2059 return 0; 2060 } 2061 2062 //TODO: pass the Uid the ClientModeImpl as a message parameter 2063 Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid()) 2064 + " SSID " + config.SSID 2065 + " nid=" + Integer.toString(config.networkId)); 2066 if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) { 2067 config.creatorUid = Binder.getCallingUid(); 2068 } else { 2069 config.lastUpdateUid = Binder.getCallingUid(); 2070 } 2071 if (mClientModeImplChannel != null) { 2072 return mClientModeImpl.syncAddOrUpdateNetwork(mClientModeImplChannel, config); 2073 } else { 2074 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 2075 return -1; 2076 } 2077 } 2078 verifyCert(X509Certificate caCert)2079 public static void verifyCert(X509Certificate caCert) 2080 throws GeneralSecurityException, IOException { 2081 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 2082 CertPathValidator validator = 2083 CertPathValidator.getInstance(CertPathValidator.getDefaultType()); 2084 CertPath path = factory.generateCertPath( 2085 Arrays.asList(caCert)); 2086 KeyStore ks = KeyStore.getInstance("AndroidCAStore"); 2087 ks.load(null, null); 2088 PKIXParameters params = new PKIXParameters(ks); 2089 params.setRevocationEnabled(false); 2090 validator.validate(path, params); 2091 } 2092 2093 /** 2094 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 2095 * @param netId the integer that identifies the network configuration 2096 * to the supplicant 2097 * @return {@code true} if the operation succeeded 2098 */ 2099 @Override removeNetwork(int netId, String packageName)2100 public boolean removeNetwork(int netId, String packageName) { 2101 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2102 return false; 2103 } 2104 if (!isTargetSdkLessThanQOrPrivileged( 2105 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2106 mLog.info("removeNetwork not allowed for uid=%") 2107 .c(Binder.getCallingUid()).flush(); 2108 return false; 2109 } 2110 mLog.info("removeNetwork uid=%").c(Binder.getCallingUid()).flush(); 2111 // TODO Add private logging for netId b/33807876 2112 if (mClientModeImplChannel != null) { 2113 return mClientModeImpl.syncRemoveNetwork(mClientModeImplChannel, netId); 2114 } else { 2115 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 2116 return false; 2117 } 2118 } 2119 2120 /** 2121 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 2122 * @param netId the integer that identifies the network configuration 2123 * to the supplicant 2124 * @param disableOthers if true, disable all other networks. 2125 * @return {@code true} if the operation succeeded 2126 */ 2127 @Override enableNetwork(int netId, boolean disableOthers, String packageName)2128 public boolean enableNetwork(int netId, boolean disableOthers, String packageName) { 2129 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2130 return false; 2131 } 2132 if (!isTargetSdkLessThanQOrPrivileged( 2133 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2134 mLog.info("enableNetwork not allowed for uid=%") 2135 .c(Binder.getCallingUid()).flush(); 2136 return false; 2137 } 2138 // TODO b/33807876 Log netId 2139 mLog.info("enableNetwork uid=% disableOthers=%") 2140 .c(Binder.getCallingUid()) 2141 .c(disableOthers).flush(); 2142 2143 mWifiMetrics.incrementNumEnableNetworkCalls(); 2144 if (mClientModeImplChannel != null) { 2145 return mClientModeImpl.syncEnableNetwork(mClientModeImplChannel, netId, 2146 disableOthers); 2147 } else { 2148 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 2149 return false; 2150 } 2151 } 2152 2153 /** 2154 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 2155 * @param netId the integer that identifies the network configuration 2156 * to the supplicant 2157 * @return {@code true} if the operation succeeded 2158 */ 2159 @Override disableNetwork(int netId, String packageName)2160 public boolean disableNetwork(int netId, String packageName) { 2161 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2162 return false; 2163 } 2164 if (!isTargetSdkLessThanQOrPrivileged( 2165 packageName, Binder.getCallingPid(), Binder.getCallingUid())) { 2166 mLog.info("disableNetwork not allowed for uid=%") 2167 .c(Binder.getCallingUid()).flush(); 2168 return false; 2169 } 2170 // TODO b/33807876 Log netId 2171 mLog.info("disableNetwork uid=%").c(Binder.getCallingUid()).flush(); 2172 2173 if (mClientModeImplChannel != null) { 2174 return mClientModeImpl.syncDisableNetwork(mClientModeImplChannel, netId); 2175 } else { 2176 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 2177 return false; 2178 } 2179 } 2180 2181 /** 2182 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 2183 * @return the Wi-Fi information, contained in {@link WifiInfo}. 2184 */ 2185 @Override getConnectionInfo(String callingPackage)2186 public WifiInfo getConnectionInfo(String callingPackage) { 2187 enforceAccessPermission(); 2188 int uid = Binder.getCallingUid(); 2189 if (mVerboseLoggingEnabled) { 2190 mLog.info("getConnectionInfo uid=%").c(uid).flush(); 2191 } 2192 long ident = Binder.clearCallingIdentity(); 2193 try { 2194 WifiInfo result = mClientModeImpl.syncRequestConnectionInfo(); 2195 boolean hideDefaultMacAddress = true; 2196 boolean hideBssidSsidAndNetworkId = true; 2197 2198 try { 2199 if (mWifiInjector.getWifiPermissionsWrapper().getLocalMacAddressPermission(uid) 2200 == PERMISSION_GRANTED) { 2201 hideDefaultMacAddress = false; 2202 } 2203 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid); 2204 hideBssidSsidAndNetworkId = false; 2205 } catch (RemoteException e) { 2206 Log.e(TAG, "Error checking receiver permission", e); 2207 } catch (SecurityException e) { 2208 } 2209 if (hideDefaultMacAddress) { 2210 result.setMacAddress(WifiInfo.DEFAULT_MAC_ADDRESS); 2211 } 2212 if (hideBssidSsidAndNetworkId) { 2213 result.setBSSID(WifiInfo.DEFAULT_MAC_ADDRESS); 2214 result.setSSID(WifiSsid.createFromHex(null)); 2215 result.setNetworkId(WifiConfiguration.INVALID_NETWORK_ID); 2216 } 2217 if (mVerboseLoggingEnabled && (hideBssidSsidAndNetworkId || hideDefaultMacAddress)) { 2218 mLog.v("getConnectionInfo: hideBssidSsidAndNetworkId=" 2219 + hideBssidSsidAndNetworkId 2220 + ", hideDefaultMacAddress=" 2221 + hideDefaultMacAddress); 2222 } 2223 return result; 2224 } finally { 2225 Binder.restoreCallingIdentity(ident); 2226 } 2227 } 2228 2229 /** 2230 * Return the results of the most recent access point scan, in the form of 2231 * a list of {@link ScanResult} objects. 2232 * @return the list of results 2233 */ 2234 @Override getScanResults(String callingPackage)2235 public List<ScanResult> getScanResults(String callingPackage) { 2236 enforceAccessPermission(); 2237 int uid = Binder.getCallingUid(); 2238 long ident = Binder.clearCallingIdentity(); 2239 if (mVerboseLoggingEnabled) { 2240 mLog.info("getScanResults uid=%").c(uid).flush(); 2241 } 2242 try { 2243 mWifiPermissionsUtil.enforceCanAccessScanResults(callingPackage, uid); 2244 final List<ScanResult> scanResults = new ArrayList<>(); 2245 boolean success = mWifiInjector.getClientModeImplHandler().runWithScissors(() -> { 2246 scanResults.addAll(mScanRequestProxy.getScanResults()); 2247 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 2248 if (!success) { 2249 Log.e(TAG, "Failed to post runnable to fetch scan results"); 2250 return new ArrayList<ScanResult>(); 2251 } 2252 return scanResults; 2253 } catch (SecurityException e) { 2254 Slog.e(TAG, "Permission violation - getScanResults not allowed for uid=" 2255 + uid + ", packageName=" + callingPackage + ", reason=" + e); 2256 return new ArrayList<ScanResult>(); 2257 } finally { 2258 Binder.restoreCallingIdentity(ident); 2259 } 2260 } 2261 2262 /** 2263 * Add or update a Passpoint configuration. 2264 * 2265 * @param config The Passpoint configuration to be added 2266 * @return true on success or false on failure 2267 */ 2268 @Override addOrUpdatePasspointConfiguration( PasspointConfiguration config, String packageName)2269 public boolean addOrUpdatePasspointConfiguration( 2270 PasspointConfiguration config, String packageName) { 2271 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2272 return false; 2273 } 2274 mLog.info("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush(); 2275 if (!mContext.getPackageManager().hasSystemFeature( 2276 PackageManager.FEATURE_WIFI_PASSPOINT)) { 2277 return false; 2278 } 2279 return mClientModeImpl.syncAddOrUpdatePasspointConfig(mClientModeImplChannel, config, 2280 Binder.getCallingUid(), packageName); 2281 } 2282 2283 /** 2284 * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name). 2285 * 2286 * @param fqdn The FQDN of the Passpoint configuration to be removed 2287 * @return true on success or false on failure 2288 */ 2289 @Override removePasspointConfiguration(String fqdn, String packageName)2290 public boolean removePasspointConfiguration(String fqdn, String packageName) { 2291 final int uid = Binder.getCallingUid(); 2292 if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) 2293 && !mWifiPermissionsUtil.checkNetworkCarrierProvisioningPermission(uid)) { 2294 if (mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q)) { 2295 return false; 2296 } 2297 throw new SecurityException(TAG + ": Permission denied"); 2298 } 2299 mLog.info("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush(); 2300 if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI_PASSPOINT)) { 2301 return false; 2302 } 2303 return mClientModeImpl.syncRemovePasspointConfig(mClientModeImplChannel, fqdn); 2304 } 2305 2306 /** 2307 * Return the list of the installed Passpoint configurations. 2308 * 2309 * An empty list will be returned when no configuration is installed. 2310 * @param packageName String name of the calling package 2311 * @return A list of {@link PasspointConfiguration}. 2312 */ 2313 @Override getPasspointConfigurations(String packageName)2314 public List<PasspointConfiguration> getPasspointConfigurations(String packageName) { 2315 final int uid = Binder.getCallingUid(); 2316 mAppOps.checkPackage(uid, packageName); 2317 if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid) 2318 && !mWifiPermissionsUtil.checkNetworkSetupWizardPermission(uid)) { 2319 if (mWifiPermissionsUtil.isTargetSdkLessThan(packageName, Build.VERSION_CODES.Q)) { 2320 return new ArrayList<>(); 2321 } 2322 throw new SecurityException(TAG + ": Permission denied"); 2323 } 2324 if (mVerboseLoggingEnabled) { 2325 mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush(); 2326 } 2327 if (!mContext.getPackageManager().hasSystemFeature( 2328 PackageManager.FEATURE_WIFI_PASSPOINT)) { 2329 return new ArrayList<>(); 2330 } 2331 return mClientModeImpl.syncGetPasspointConfigs(mClientModeImplChannel); 2332 } 2333 2334 /** 2335 * Query for a Hotspot 2.0 release 2 OSU icon 2336 * @param bssid The BSSID of the AP 2337 * @param fileName Icon file name 2338 */ 2339 @Override queryPasspointIcon(long bssid, String fileName)2340 public void queryPasspointIcon(long bssid, String fileName) { 2341 enforceAccessPermission(); 2342 mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush(); 2343 if (!mContext.getPackageManager().hasSystemFeature( 2344 PackageManager.FEATURE_WIFI_PASSPOINT)) { 2345 throw new UnsupportedOperationException("Passpoint not enabled"); 2346 } 2347 mClientModeImpl.syncQueryPasspointIcon(mClientModeImplChannel, bssid, fileName); 2348 } 2349 2350 /** 2351 * Match the currently associated network against the SP matching the given FQDN 2352 * @param fqdn FQDN of the SP 2353 * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined] 2354 */ 2355 @Override matchProviderWithCurrentNetwork(String fqdn)2356 public int matchProviderWithCurrentNetwork(String fqdn) { 2357 mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush(); 2358 return mClientModeImpl.matchProviderWithCurrentNetwork(mClientModeImplChannel, fqdn); 2359 } 2360 2361 /** 2362 * Deauthenticate and set the re-authentication hold off time for the current network 2363 * @param holdoff hold off time in milliseconds 2364 * @param ess set if the hold off pertains to an ESS rather than a BSS 2365 */ 2366 @Override deauthenticateNetwork(long holdoff, boolean ess)2367 public void deauthenticateNetwork(long holdoff, boolean ess) { 2368 mLog.info("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush(); 2369 mClientModeImpl.deauthenticateNetwork(mClientModeImplChannel, holdoff, ess); 2370 } 2371 2372 /** 2373 * Set the country code 2374 * @param countryCode ISO 3166 country code. 2375 * 2376 */ 2377 @Override setCountryCode(String countryCode)2378 public void setCountryCode(String countryCode) { 2379 Slog.i(TAG, "WifiService trying to set country code to " + countryCode); 2380 enforceConnectivityInternalPermission(); 2381 mLog.info("setCountryCode uid=%").c(Binder.getCallingUid()).flush(); 2382 final long token = Binder.clearCallingIdentity(); 2383 mCountryCode.setCountryCode(countryCode); 2384 Binder.restoreCallingIdentity(token); 2385 } 2386 2387 /** 2388 * Get the country code 2389 * @return Get the best choice country code for wifi, regardless of if it was set or 2390 * not. 2391 * Returns null when there is no country code available. 2392 */ 2393 @Override getCountryCode()2394 public String getCountryCode() { 2395 enforceConnectivityInternalPermission(); 2396 if (mVerboseLoggingEnabled) { 2397 mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush(); 2398 } 2399 String country = mCountryCode.getCountryCode(); 2400 return country; 2401 } 2402 2403 @Override isDualBandSupported()2404 public boolean isDualBandSupported() { 2405 //TODO (b/123227116): pull it from the HAL 2406 if (mVerboseLoggingEnabled) { 2407 mLog.info("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush(); 2408 } 2409 2410 return mContext.getResources().getBoolean( 2411 com.android.internal.R.bool.config_wifi_dual_band_support); 2412 } 2413 getMaxApInterfacesCount()2414 private int getMaxApInterfacesCount() { 2415 //TODO (b/123227116): pull it from the HAL 2416 return mContext.getResources().getInteger( 2417 com.android.internal.R.integer.config_wifi_max_ap_interfaces); 2418 } 2419 isConcurrentLohsAndTetheringSupported()2420 private boolean isConcurrentLohsAndTetheringSupported() { 2421 // TODO(b/110697252): handle all configurations in the wifi stack (just by changing the HAL) 2422 return getMaxApInterfacesCount() >= 2; 2423 } 2424 2425 /** 2426 * Method allowing callers with NETWORK_SETTINGS permission to check if this is a dual mode 2427 * capable device (STA+AP). 2428 * 2429 * @return true if a dual mode capable device 2430 */ 2431 @Override needs5GHzToAnyApBandConversion()2432 public boolean needs5GHzToAnyApBandConversion() { 2433 enforceNetworkSettingsPermission(); 2434 2435 if (mVerboseLoggingEnabled) { 2436 mLog.info("needs5GHzToAnyApBandConversion uid=%").c(Binder.getCallingUid()).flush(); 2437 } 2438 return mContext.getResources().getBoolean( 2439 com.android.internal.R.bool.config_wifi_convert_apband_5ghz_to_any); 2440 } 2441 2442 /** 2443 * Return the DHCP-assigned addresses from the last successful DHCP request, 2444 * if any. 2445 * @return the DHCP information 2446 * @deprecated 2447 */ 2448 @Override 2449 @Deprecated getDhcpInfo()2450 public DhcpInfo getDhcpInfo() { 2451 enforceAccessPermission(); 2452 if (mVerboseLoggingEnabled) { 2453 mLog.info("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush(); 2454 } 2455 DhcpResults dhcpResults = mClientModeImpl.syncGetDhcpResults(); 2456 2457 DhcpInfo info = new DhcpInfo(); 2458 2459 if (dhcpResults.ipAddress != null && 2460 dhcpResults.ipAddress.getAddress() instanceof Inet4Address) { 2461 info.ipAddress = NetworkUtils.inetAddressToInt( 2462 (Inet4Address) dhcpResults.ipAddress.getAddress()); 2463 } 2464 2465 if (dhcpResults.gateway != null) { 2466 info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway); 2467 } 2468 2469 int dnsFound = 0; 2470 for (InetAddress dns : dhcpResults.dnsServers) { 2471 if (dns instanceof Inet4Address) { 2472 if (dnsFound == 0) { 2473 info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 2474 } else { 2475 info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 2476 } 2477 if (++dnsFound > 1) break; 2478 } 2479 } 2480 Inet4Address serverAddress = dhcpResults.serverAddress; 2481 if (serverAddress != null) { 2482 info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress); 2483 } 2484 info.leaseDuration = dhcpResults.leaseDuration; 2485 2486 return info; 2487 } 2488 2489 /** 2490 * enable TDLS for the local NIC to remote NIC 2491 * The APPs don't know the remote MAC address to identify NIC though, 2492 * so we need to do additional work to find it from remote IP address 2493 */ 2494 2495 class TdlsTaskParams { 2496 public String remoteIpAddress; 2497 public boolean enable; 2498 } 2499 2500 class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> { 2501 @Override doInBackground(TdlsTaskParams... params)2502 protected Integer doInBackground(TdlsTaskParams... params) { 2503 2504 // Retrieve parameters for the call 2505 TdlsTaskParams param = params[0]; 2506 String remoteIpAddress = param.remoteIpAddress.trim(); 2507 boolean enable = param.enable; 2508 2509 // Get MAC address of Remote IP 2510 String macAddress = null; 2511 2512 BufferedReader reader = null; 2513 2514 try { 2515 reader = new BufferedReader(new FileReader("/proc/net/arp")); 2516 2517 // Skip over the line bearing colum titles 2518 String line = reader.readLine(); 2519 2520 while ((line = reader.readLine()) != null) { 2521 String[] tokens = line.split("[ ]+"); 2522 if (tokens.length < 6) { 2523 continue; 2524 } 2525 2526 // ARP column format is 2527 // Address HWType HWAddress Flags Mask IFace 2528 String ip = tokens[0]; 2529 String mac = tokens[3]; 2530 2531 if (remoteIpAddress.equals(ip)) { 2532 macAddress = mac; 2533 break; 2534 } 2535 } 2536 2537 if (macAddress == null) { 2538 Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " + 2539 "/proc/net/arp"); 2540 } else { 2541 enableTdlsWithMacAddress(macAddress, enable); 2542 } 2543 2544 } catch (FileNotFoundException e) { 2545 Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address"); 2546 } catch (IOException e) { 2547 Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address"); 2548 } finally { 2549 try { 2550 if (reader != null) { 2551 reader.close(); 2552 } 2553 } 2554 catch (IOException e) { 2555 // Do nothing 2556 } 2557 } 2558 2559 return 0; 2560 } 2561 } 2562 2563 @Override enableTdls(String remoteAddress, boolean enable)2564 public void enableTdls(String remoteAddress, boolean enable) { 2565 if (remoteAddress == null) { 2566 throw new IllegalArgumentException("remoteAddress cannot be null"); 2567 } 2568 mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush(); 2569 TdlsTaskParams params = new TdlsTaskParams(); 2570 params.remoteIpAddress = remoteAddress; 2571 params.enable = enable; 2572 new TdlsTask().execute(params); 2573 } 2574 2575 2576 @Override enableTdlsWithMacAddress(String remoteMacAddress, boolean enable)2577 public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) { 2578 mLog.info("enableTdlsWithMacAddress uid=% enable=%") 2579 .c(Binder.getCallingUid()) 2580 .c(enable) 2581 .flush(); 2582 if (remoteMacAddress == null) { 2583 throw new IllegalArgumentException("remoteMacAddress cannot be null"); 2584 } 2585 2586 mClientModeImpl.enableTdls(remoteMacAddress, enable); 2587 } 2588 2589 /** 2590 * Get a reference to handler. This is used by a client to establish 2591 * an AsyncChannel communication with WifiService 2592 */ 2593 @Override getWifiServiceMessenger(String packageName)2594 public Messenger getWifiServiceMessenger(String packageName) { 2595 enforceAccessPermission(); 2596 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2597 // We don't have a good way of creating a fake Messenger, and returning null would 2598 // immediately break callers. 2599 throw new SecurityException("Could not create wifi service messenger"); 2600 } 2601 mLog.info("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush(); 2602 return new Messenger(mAsyncChannelExternalClientHandler); 2603 } 2604 2605 /** 2606 * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer 2607 */ 2608 @Override disableEphemeralNetwork(String SSID, String packageName)2609 public void disableEphemeralNetwork(String SSID, String packageName) { 2610 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 2611 "WifiService"); 2612 if (!isPrivileged(Binder.getCallingPid(), Binder.getCallingUid())) { 2613 mLog.info("disableEphemeralNetwork not allowed for uid=%") 2614 .c(Binder.getCallingUid()).flush(); 2615 return; 2616 } 2617 mLog.info("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush(); 2618 mClientModeImpl.disableEphemeralNetwork(SSID); 2619 } 2620 2621 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 2622 @Override 2623 public void onReceive(Context context, Intent intent) { 2624 String action = intent.getAction(); 2625 if (action.equals(Intent.ACTION_USER_REMOVED)) { 2626 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 2627 mClientModeImpl.removeUserConfigs(userHandle); 2628 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { 2629 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 2630 BluetoothAdapter.STATE_DISCONNECTED); 2631 mClientModeImpl.sendBluetoothAdapterStateChange(state); 2632 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 2633 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false); 2634 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0); 2635 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) { 2636 boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false); 2637 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0); 2638 } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) { 2639 handleIdleModeChanged(); 2640 } 2641 } 2642 }; 2643 2644 /** 2645 * Observes settings changes to scan always mode. 2646 */ registerForScanModeChange()2647 private void registerForScanModeChange() { 2648 ContentObserver contentObserver = new ContentObserver(null) { 2649 @Override 2650 public void onChange(boolean selfChange) { 2651 mSettingsStore.handleWifiScanAlwaysAvailableToggled(); 2652 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED); 2653 } 2654 }; 2655 mFrameworkFacade.registerContentObserver(mContext, 2656 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE), 2657 false, contentObserver); 2658 2659 } 2660 registerForBroadcasts()2661 private void registerForBroadcasts() { 2662 IntentFilter intentFilter = new IntentFilter(); 2663 intentFilter.addAction(Intent.ACTION_USER_PRESENT); 2664 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 2665 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 2666 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 2667 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 2668 2669 boolean trackEmergencyCallState = mContext.getResources().getBoolean( 2670 com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call); 2671 if (trackEmergencyCallState) { 2672 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); 2673 } 2674 mContext.registerReceiver(mReceiver, intentFilter); 2675 2676 intentFilter = new IntentFilter(); 2677 intentFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED); 2678 intentFilter.addDataScheme("package"); 2679 mContext.registerReceiver(new BroadcastReceiver() { 2680 @Override 2681 public void onReceive(Context context, Intent intent) { 2682 String action = intent.getAction(); 2683 if (action.equals(Intent.ACTION_PACKAGE_FULLY_REMOVED)) { 2684 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 2685 Uri uri = intent.getData(); 2686 if (uid == -1 || uri == null) { 2687 return; 2688 } 2689 String pkgName = uri.getSchemeSpecificPart(); 2690 mClientModeImpl.removeAppConfigs(pkgName, uid); 2691 2692 // Call the method in ClientModeImpl thread. 2693 mWifiInjector.getClientModeImplHandler().post(() -> { 2694 mScanRequestProxy.clearScanRequestTimestampsForApp(pkgName, uid); 2695 2696 // Remove all suggestions from the package. 2697 mWifiNetworkSuggestionsManager.removeApp(pkgName); 2698 mClientModeImpl.removeNetworkRequestUserApprovedAccessPointsForApp(pkgName); 2699 2700 // Remove all Passpoint profiles from package. 2701 mWifiInjector.getPasspointManager().removePasspointProviderWithPackage( 2702 pkgName); 2703 2704 }); 2705 } 2706 } 2707 }, intentFilter); 2708 } 2709 2710 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)2711 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 2712 String[] args, ShellCallback callback, ResultReceiver resultReceiver) { 2713 (new WifiShellCommand(mWifiInjector)).exec(this, in, out, err, 2714 args, callback, resultReceiver); 2715 } 2716 2717 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)2718 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2719 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2720 != PERMISSION_GRANTED) { 2721 pw.println("Permission Denial: can't dump WifiService from from pid=" 2722 + Binder.getCallingPid() 2723 + ", uid=" + Binder.getCallingUid()); 2724 return; 2725 } 2726 if (args != null && args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) { 2727 // WifiMetrics proto bytes were requested. Dump only these. 2728 mClientModeImpl.updateWifiMetrics(); 2729 mWifiMetrics.dump(fd, pw, args); 2730 } else if (args != null && args.length > 0 && IpClientUtil.DUMP_ARG.equals(args[0])) { 2731 // IpClient dump was requested. Pass it along and take no further action. 2732 String[] ipClientArgs = new String[args.length - 1]; 2733 System.arraycopy(args, 1, ipClientArgs, 0, ipClientArgs.length); 2734 mClientModeImpl.dumpIpClient(fd, pw, ipClientArgs); 2735 } else if (args != null && args.length > 0 && WifiScoreReport.DUMP_ARG.equals(args[0])) { 2736 WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport(); 2737 if (wifiScoreReport != null) wifiScoreReport.dump(fd, pw, args); 2738 } else if (args != null && args.length > 0 && WifiScoreCard.DUMP_ARG.equals(args[0])) { 2739 mWifiInjector.getClientModeImplHandler().runWithScissors(() -> { 2740 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard(); 2741 if (wifiScoreCard != null) { 2742 pw.println(wifiScoreCard.getNetworkListBase64(true)); 2743 } 2744 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 2745 } else { 2746 // Polls link layer stats and RSSI. This allows the stats to show up in 2747 // WifiScoreReport's dump() output when taking a bug report even if the screen is off. 2748 mClientModeImpl.updateLinkLayerStatsRssiAndScoreReport(); 2749 pw.println("Wi-Fi is " + mClientModeImpl.syncGetWifiStateByName()); 2750 pw.println("Verbose logging is " + (mVerboseLoggingEnabled ? "on" : "off")); 2751 pw.println("Stay-awake conditions: " + 2752 mFacade.getIntegerSetting(mContext, 2753 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); 2754 pw.println("mInIdleMode " + mInIdleMode); 2755 pw.println("mScanPending " + mScanPending); 2756 mWifiController.dump(fd, pw, args); 2757 mSettingsStore.dump(fd, pw, args); 2758 mWifiTrafficPoller.dump(fd, pw, args); 2759 pw.println(); 2760 pw.println("Locks held:"); 2761 mWifiLockManager.dump(pw); 2762 pw.println(); 2763 mWifiMulticastLockManager.dump(pw); 2764 pw.println(); 2765 mActiveModeWarden.dump(fd, pw, args); 2766 pw.println(); 2767 mClientModeImpl.dump(fd, pw, args); 2768 pw.println(); 2769 mWifiInjector.getClientModeImplHandler().runWithScissors(() -> { 2770 WifiScoreCard wifiScoreCard = mWifiInjector.getWifiScoreCard(); 2771 if (wifiScoreCard != null) { 2772 pw.println("WifiScoreCard:"); 2773 pw.println(wifiScoreCard.getNetworkListBase64(true)); 2774 } 2775 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 2776 mClientModeImpl.updateWifiMetrics(); 2777 mWifiMetrics.dump(fd, pw, args); 2778 pw.println(); 2779 mWifiInjector.getClientModeImplHandler().runWithScissors(() -> { 2780 mWifiNetworkSuggestionsManager.dump(fd, pw, args); 2781 pw.println(); 2782 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 2783 mWifiBackupRestore.dump(fd, pw, args); 2784 pw.println(); 2785 pw.println("ScoringParams: settings put global " + Settings.Global.WIFI_SCORE_PARAMS 2786 + " " + mWifiInjector.getScoringParams()); 2787 pw.println(); 2788 WifiScoreReport wifiScoreReport = mClientModeImpl.getWifiScoreReport(); 2789 if (wifiScoreReport != null) { 2790 pw.println("WifiScoreReport:"); 2791 wifiScoreReport.dump(fd, pw, args); 2792 } 2793 pw.println(); 2794 SarManager sarManager = mWifiInjector.getSarManager(); 2795 if (sarManager != null) { 2796 sarManager.dump(fd, pw, args); 2797 } 2798 pw.println(); 2799 } 2800 } 2801 2802 @Override acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws)2803 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { 2804 mLog.info("acquireWifiLock uid=% lockMode=%") 2805 .c(Binder.getCallingUid()) 2806 .c(lockMode).flush(); 2807 2808 // Check on permission to make this call 2809 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 2810 2811 // If no UID is provided in worksource, use the calling UID 2812 WorkSource updatedWs = (ws == null || ws.isEmpty()) 2813 ? new WorkSource(Binder.getCallingUid()) : ws; 2814 2815 Mutable<Boolean> lockSuccess = new Mutable<>(); 2816 boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors( 2817 () -> { 2818 lockSuccess.value = mWifiLockManager.acquireWifiLock( 2819 lockMode, tag, binder, updatedWs); 2820 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 2821 if (!runWithScissorsSuccess) { 2822 Log.e(TAG, "Failed to post runnable to acquireWifiLock"); 2823 return false; 2824 } 2825 2826 return lockSuccess.value; 2827 } 2828 2829 @Override updateWifiLockWorkSource(IBinder binder, WorkSource ws)2830 public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) { 2831 mLog.info("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush(); 2832 2833 // Check on permission to make this call 2834 mContext.enforceCallingOrSelfPermission( 2835 android.Manifest.permission.UPDATE_DEVICE_STATS, null); 2836 2837 // If no UID is provided in worksource, use the calling UID 2838 WorkSource updatedWs = (ws == null || ws.isEmpty()) 2839 ? new WorkSource(Binder.getCallingUid()) : ws; 2840 2841 boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors( 2842 () -> { 2843 mWifiLockManager.updateWifiLockWorkSource(binder, updatedWs); 2844 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 2845 if (!runWithScissorsSuccess) { 2846 Log.e(TAG, "Failed to post runnable to updateWifiLockWorkSource"); 2847 } 2848 } 2849 2850 @Override releaseWifiLock(IBinder binder)2851 public boolean releaseWifiLock(IBinder binder) { 2852 mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush(); 2853 2854 // Check on permission to make this call 2855 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 2856 Mutable<Boolean> lockSuccess = new Mutable<>(); 2857 boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors( 2858 () -> { 2859 lockSuccess.value = mWifiLockManager.releaseWifiLock(binder); 2860 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 2861 if (!runWithScissorsSuccess) { 2862 Log.e(TAG, "Failed to post runnable to releaseWifiLock"); 2863 return false; 2864 } 2865 return lockSuccess.value; 2866 } 2867 2868 @Override initializeMulticastFiltering()2869 public void initializeMulticastFiltering() { 2870 enforceMulticastChangePermission(); 2871 mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush(); 2872 mWifiMulticastLockManager.initializeFiltering(); 2873 } 2874 2875 @Override acquireMulticastLock(IBinder binder, String tag)2876 public void acquireMulticastLock(IBinder binder, String tag) { 2877 enforceMulticastChangePermission(); 2878 mLog.info("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush(); 2879 mWifiMulticastLockManager.acquireLock(binder, tag); 2880 } 2881 2882 @Override releaseMulticastLock(String tag)2883 public void releaseMulticastLock(String tag) { 2884 enforceMulticastChangePermission(); 2885 mLog.info("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush(); 2886 mWifiMulticastLockManager.releaseLock(tag); 2887 } 2888 2889 @Override isMulticastEnabled()2890 public boolean isMulticastEnabled() { 2891 enforceAccessPermission(); 2892 if (mVerboseLoggingEnabled) { 2893 mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush(); 2894 } 2895 return mWifiMulticastLockManager.isMulticastEnabled(); 2896 } 2897 2898 @Override enableVerboseLogging(int verbose)2899 public void enableVerboseLogging(int verbose) { 2900 enforceAccessPermission(); 2901 enforceNetworkSettingsPermission(); 2902 mLog.info("enableVerboseLogging uid=% verbose=%") 2903 .c(Binder.getCallingUid()) 2904 .c(verbose).flush(); 2905 mFacade.setIntegerSetting( 2906 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose); 2907 enableVerboseLoggingInternal(verbose); 2908 } 2909 enableVerboseLoggingInternal(int verbose)2910 void enableVerboseLoggingInternal(int verbose) { 2911 mVerboseLoggingEnabled = verbose > 0; 2912 mClientModeImpl.enableVerboseLogging(verbose); 2913 mWifiLockManager.enableVerboseLogging(verbose); 2914 mWifiMulticastLockManager.enableVerboseLogging(verbose); 2915 mWifiInjector.enableVerboseLogging(verbose); 2916 } 2917 2918 @Override getVerboseLoggingLevel()2919 public int getVerboseLoggingLevel() { 2920 if (mVerboseLoggingEnabled) { 2921 mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush(); 2922 } 2923 return mFacade.getIntegerSetting( 2924 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0); 2925 } 2926 2927 @Override factoryReset(String packageName)2928 public void factoryReset(String packageName) { 2929 enforceConnectivityInternalPermission(); 2930 if (enforceChangePermission(packageName) != MODE_ALLOWED) { 2931 return; 2932 } 2933 mLog.info("factoryReset uid=%").c(Binder.getCallingUid()).flush(); 2934 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) { 2935 return; 2936 } 2937 2938 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { 2939 // Turn mobile hotspot off 2940 stopSoftApInternal(WifiManager.IFACE_IP_MODE_UNSPECIFIED); 2941 } 2942 2943 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) { 2944 if (mClientModeImplChannel != null) { 2945 // Delete all Wifi SSIDs 2946 List<WifiConfiguration> networks = mClientModeImpl.syncGetConfiguredNetworks( 2947 Binder.getCallingUid(), mClientModeImplChannel, Process.WIFI_UID); 2948 if (networks != null) { 2949 for (WifiConfiguration config : networks) { 2950 removeNetwork(config.networkId, packageName); 2951 } 2952 } 2953 2954 // Delete all Passpoint configurations 2955 if (mContext.getPackageManager().hasSystemFeature( 2956 PackageManager.FEATURE_WIFI_PASSPOINT)) { 2957 List<PasspointConfiguration> configs = mClientModeImpl.syncGetPasspointConfigs( 2958 mClientModeImplChannel); 2959 if (configs != null) { 2960 for (PasspointConfiguration config : configs) { 2961 removePasspointConfiguration(config.getHomeSp().getFqdn(), packageName); 2962 } 2963 } 2964 } 2965 } 2966 2967 mWifiInjector.getClientModeImplHandler().post(() -> { 2968 mWifiInjector.getWifiConfigManager().clearDeletedEphemeralNetworks(); 2969 mClientModeImpl.clearNetworkRequestUserApprovedAccessPoints(); 2970 mWifiNetworkSuggestionsManager.clear(); 2971 mWifiInjector.getWifiScoreCard().clear(); 2972 }); 2973 } 2974 } 2975 2976 /* private methods */ logAndReturnFalse(String s)2977 static boolean logAndReturnFalse(String s) { 2978 Log.d(TAG, s); 2979 return false; 2980 } 2981 2982 @Override getCurrentNetwork()2983 public Network getCurrentNetwork() { 2984 enforceAccessPermission(); 2985 if (mVerboseLoggingEnabled) { 2986 mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush(); 2987 } 2988 return mClientModeImpl.getCurrentNetwork(); 2989 } 2990 toHexString(String s)2991 public static String toHexString(String s) { 2992 if (s == null) { 2993 return "null"; 2994 } 2995 StringBuilder sb = new StringBuilder(); 2996 sb.append('\'').append(s).append('\''); 2997 for (int n = 0; n < s.length(); n++) { 2998 sb.append(String.format(" %02x", s.charAt(n) & 0xffff)); 2999 } 3000 return sb.toString(); 3001 } 3002 3003 /** 3004 * Enable/disable WifiConnectivityManager at runtime 3005 * 3006 * @param enabled true-enable; false-disable 3007 */ 3008 @Override enableWifiConnectivityManager(boolean enabled)3009 public void enableWifiConnectivityManager(boolean enabled) { 3010 enforceConnectivityInternalPermission(); 3011 mLog.info("enableWifiConnectivityManager uid=% enabled=%") 3012 .c(Binder.getCallingUid()) 3013 .c(enabled).flush(); 3014 mClientModeImpl.enableWifiConnectivityManager(enabled); 3015 } 3016 3017 /** 3018 * Retrieve the data to be backed to save the current state. 3019 * 3020 * @return Raw byte stream of the data to be backed up. 3021 */ 3022 @Override retrieveBackupData()3023 public byte[] retrieveBackupData() { 3024 enforceNetworkSettingsPermission(); 3025 mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush(); 3026 if (mClientModeImplChannel == null) { 3027 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 3028 return null; 3029 } 3030 3031 Slog.d(TAG, "Retrieving backup data"); 3032 List<WifiConfiguration> wifiConfigurations = 3033 mClientModeImpl.syncGetPrivilegedConfiguredNetwork(mClientModeImplChannel); 3034 byte[] backupData = 3035 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations); 3036 Slog.d(TAG, "Retrieved backup data"); 3037 return backupData; 3038 } 3039 3040 /** 3041 * Helper method to restore networks retrieved from backup data. 3042 * 3043 * @param configurations list of WifiConfiguration objects parsed from the backup data. 3044 */ restoreNetworks(List<WifiConfiguration> configurations)3045 private void restoreNetworks(List<WifiConfiguration> configurations) { 3046 if (configurations == null) { 3047 Slog.e(TAG, "Backup data parse failed"); 3048 return; 3049 } 3050 for (WifiConfiguration configuration : configurations) { 3051 int networkId = mClientModeImpl.syncAddOrUpdateNetwork( 3052 mClientModeImplChannel, configuration); 3053 if (networkId == WifiConfiguration.INVALID_NETWORK_ID) { 3054 Slog.e(TAG, "Restore network failed: " + configuration.configKey()); 3055 continue; 3056 } 3057 // Enable all networks restored. 3058 mClientModeImpl.syncEnableNetwork(mClientModeImplChannel, networkId, false); 3059 } 3060 } 3061 3062 /** 3063 * Restore state from the backed up data. 3064 * 3065 * @param data Raw byte stream of the backed up data. 3066 */ 3067 @Override restoreBackupData(byte[] data)3068 public void restoreBackupData(byte[] data) { 3069 enforceNetworkSettingsPermission(); 3070 mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush(); 3071 if (mClientModeImplChannel == null) { 3072 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 3073 return; 3074 } 3075 3076 Slog.d(TAG, "Restoring backup data"); 3077 List<WifiConfiguration> wifiConfigurations = 3078 mWifiBackupRestore.retrieveConfigurationsFromBackupData(data); 3079 restoreNetworks(wifiConfigurations); 3080 Slog.d(TAG, "Restored backup data"); 3081 } 3082 3083 /** 3084 * Restore state from the older supplicant back up data. 3085 * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file. 3086 * 3087 * @param supplicantData Raw byte stream of wpa_supplicant.conf 3088 * @param ipConfigData Raw byte stream of ipconfig.txt 3089 */ restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData)3090 public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) { 3091 enforceNetworkSettingsPermission(); 3092 mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush(); 3093 if (mClientModeImplChannel == null) { 3094 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 3095 return; 3096 } 3097 3098 Slog.d(TAG, "Restoring supplicant backup data"); 3099 List<WifiConfiguration> wifiConfigurations = 3100 mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData( 3101 supplicantData, ipConfigData); 3102 restoreNetworks(wifiConfigurations); 3103 Slog.d(TAG, "Restored supplicant backup data"); 3104 } 3105 3106 /** 3107 * Starts subscription provisioning with a provider. 3108 * 3109 * @param provider {@link OsuProvider} the provider to provision with 3110 * @param callback {@link IProvisioningCallback} the callback object to inform status 3111 */ 3112 @Override startSubscriptionProvisioning(OsuProvider provider, IProvisioningCallback callback)3113 public void startSubscriptionProvisioning(OsuProvider provider, 3114 IProvisioningCallback callback) { 3115 if (provider == null) { 3116 throw new IllegalArgumentException("Provider must not be null"); 3117 } 3118 if (callback == null) { 3119 throw new IllegalArgumentException("Callback must not be null"); 3120 } 3121 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 3122 throw new SecurityException(TAG + ": Permission denied"); 3123 } 3124 if (!mContext.getPackageManager().hasSystemFeature( 3125 PackageManager.FEATURE_WIFI_PASSPOINT)) { 3126 throw new UnsupportedOperationException("Passpoint not enabled"); 3127 } 3128 final int uid = Binder.getCallingUid(); 3129 mLog.trace("startSubscriptionProvisioning uid=%").c(uid).flush(); 3130 if (mClientModeImpl.syncStartSubscriptionProvisioning(uid, provider, 3131 callback, mClientModeImplChannel)) { 3132 mLog.trace("Subscription provisioning started with %") 3133 .c(provider.toString()).flush(); 3134 } 3135 } 3136 3137 /** 3138 * see {@link android.net.wifi.WifiManager#registerTrafficStateCallback( 3139 * WifiManager.TrafficStateCallback, Handler)} 3140 * 3141 * @param binder IBinder instance to allow cleanup if the app dies 3142 * @param callback Traffic State callback to register 3143 * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to 3144 * unregister the callback. See {@link unregisterTrafficStateCallback(int)} 3145 * 3146 * @throws SecurityException if the caller does not have permission to register a callback 3147 * @throws RemoteException if remote exception happens 3148 * @throws IllegalArgumentException if the arguments are null or invalid 3149 */ 3150 @Override registerTrafficStateCallback(IBinder binder, ITrafficStateCallback callback, int callbackIdentifier)3151 public void registerTrafficStateCallback(IBinder binder, ITrafficStateCallback callback, 3152 int callbackIdentifier) { 3153 // verify arguments 3154 if (binder == null) { 3155 throw new IllegalArgumentException("Binder must not be null"); 3156 } 3157 if (callback == null) { 3158 throw new IllegalArgumentException("Callback must not be null"); 3159 } 3160 enforceNetworkSettingsPermission(); 3161 if (mVerboseLoggingEnabled) { 3162 mLog.info("registerTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush(); 3163 } 3164 // Post operation to handler thread 3165 mWifiInjector.getClientModeImplHandler().post(() -> { 3166 mWifiTrafficPoller.addCallback(binder, callback, callbackIdentifier); 3167 }); 3168 } 3169 3170 /** 3171 * see {@link android.net.wifi.WifiManager#unregisterTrafficStateCallback( 3172 * WifiManager.TrafficStateCallback)} 3173 * 3174 * @param callbackIdentifier Unique ID of the callback to be unregistered. 3175 * 3176 * @throws SecurityException if the caller does not have permission to register a callback 3177 */ 3178 @Override unregisterTrafficStateCallback(int callbackIdentifier)3179 public void unregisterTrafficStateCallback(int callbackIdentifier) { 3180 enforceNetworkSettingsPermission(); 3181 if (mVerboseLoggingEnabled) { 3182 mLog.info("unregisterTrafficStateCallback uid=%").c(Binder.getCallingUid()).flush(); 3183 } 3184 // Post operation to handler thread 3185 mWifiInjector.getClientModeImplHandler().post(() -> { 3186 mWifiTrafficPoller.removeCallback(callbackIdentifier); 3187 }); 3188 } 3189 is5GhzSupported()3190 private boolean is5GhzSupported() { 3191 return (getSupportedFeaturesInternal() & WIFI_FEATURE_INFRA_5G) == WIFI_FEATURE_INFRA_5G; 3192 } 3193 getSupportedFeaturesInternal()3194 private long getSupportedFeaturesInternal() { 3195 final AsyncChannel channel = mClientModeImplChannel; 3196 if (channel != null) { 3197 return mClientModeImpl.syncGetSupportedFeatures(channel); 3198 } else { 3199 Slog.e(TAG, "mClientModeImplChannel is not initialized"); 3200 return 0; 3201 } 3202 } 3203 hasAutomotiveFeature(Context context)3204 private static boolean hasAutomotiveFeature(Context context) { 3205 return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 3206 } 3207 3208 /** 3209 * see {@link android.net.wifi.WifiManager#registerNetworkRequestMatchCallback( 3210 * WifiManager.NetworkRequestMatchCallback, Handler)} ( 3211 * 3212 * @param binder IBinder instance to allow cleanup if the app dies 3213 * @param callback Network Request Match callback to register 3214 * @param callbackIdentifier Unique ID of the registering callback. This ID will be used to 3215 * unregister the callback. 3216 * See {@link #unregisterNetworkRequestMatchCallback(int)} (int)} 3217 * 3218 * @throws SecurityException if the caller does not have permission to register a callback 3219 * @throws RemoteException if remote exception happens 3220 * @throws IllegalArgumentException if the arguments are null or invalid 3221 */ 3222 @Override registerNetworkRequestMatchCallback(IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier)3223 public void registerNetworkRequestMatchCallback(IBinder binder, 3224 INetworkRequestMatchCallback callback, 3225 int callbackIdentifier) { 3226 // verify arguments 3227 if (binder == null) { 3228 throw new IllegalArgumentException("Binder must not be null"); 3229 } 3230 if (callback == null) { 3231 throw new IllegalArgumentException("Callback must not be null"); 3232 } 3233 enforceNetworkSettingsPermission(); 3234 if (mVerboseLoggingEnabled) { 3235 mLog.info("registerNetworkRequestMatchCallback uid=%") 3236 .c(Binder.getCallingUid()).flush(); 3237 } 3238 // Post operation to handler thread 3239 mWifiInjector.getClientModeImplHandler().post(() -> { 3240 mClientModeImpl.addNetworkRequestMatchCallback(binder, callback, callbackIdentifier); 3241 }); 3242 } 3243 3244 /** 3245 * see {@link android.net.wifi.WifiManager#unregisterNetworkRequestMatchCallback( 3246 * WifiManager.NetworkRequestMatchCallback)} 3247 * 3248 * @param callbackIdentifier Unique ID of the callback to be unregistered. 3249 * 3250 * @throws SecurityException if the caller does not have permission to register a callback 3251 */ 3252 @Override unregisterNetworkRequestMatchCallback(int callbackIdentifier)3253 public void unregisterNetworkRequestMatchCallback(int callbackIdentifier) { 3254 enforceNetworkSettingsPermission(); 3255 if (mVerboseLoggingEnabled) { 3256 mLog.info("unregisterNetworkRequestMatchCallback uid=%") 3257 .c(Binder.getCallingUid()).flush(); 3258 } 3259 // Post operation to handler thread 3260 mWifiInjector.getClientModeImplHandler().post(() -> { 3261 mClientModeImpl.removeNetworkRequestMatchCallback(callbackIdentifier); 3262 }); 3263 } 3264 3265 /** 3266 * See {@link android.net.wifi.WifiManager#addNetworkSuggestions(List)} 3267 * 3268 * @param networkSuggestions List of network suggestions to be added. 3269 * @param callingPackageName Package Name of the app adding the suggestions. 3270 * @throws SecurityException if the caller does not have permission. 3271 * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}. 3272 */ 3273 @Override addNetworkSuggestions( List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName)3274 public int addNetworkSuggestions( 3275 List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) { 3276 if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) { 3277 return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED; 3278 } 3279 if (mVerboseLoggingEnabled) { 3280 mLog.info("addNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush(); 3281 } 3282 int callingUid = Binder.getCallingUid(); 3283 Mutable<Integer> success = new Mutable<>(); 3284 boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors( 3285 () -> { 3286 success.value = mWifiNetworkSuggestionsManager.add( 3287 networkSuggestions, callingUid, callingPackageName); 3288 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 3289 if (!runWithScissorsSuccess) { 3290 Log.e(TAG, "Failed to post runnable to add network suggestions"); 3291 return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL; 3292 } 3293 if (success.value != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { 3294 Log.e(TAG, "Failed to add network suggestions"); 3295 } 3296 return success.value; 3297 } 3298 3299 /** 3300 * See {@link android.net.wifi.WifiManager#removeNetworkSuggestions(List)} 3301 * 3302 * @param networkSuggestions List of network suggestions to be removed. 3303 * @param callingPackageName Package Name of the app removing the suggestions. 3304 * @throws SecurityException if the caller does not have permission. 3305 * @return One of status codes from {@link WifiManager.NetworkSuggestionsStatusCode}. 3306 */ 3307 @Override removeNetworkSuggestions( List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName)3308 public int removeNetworkSuggestions( 3309 List<WifiNetworkSuggestion> networkSuggestions, String callingPackageName) { 3310 if (enforceChangePermission(callingPackageName) != MODE_ALLOWED) { 3311 return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_APP_DISALLOWED; 3312 } 3313 if (mVerboseLoggingEnabled) { 3314 mLog.info("removeNetworkSuggestions uid=%").c(Binder.getCallingUid()).flush(); 3315 } 3316 Mutable<Integer> success = new Mutable<>(); 3317 boolean runWithScissorsSuccess = mWifiInjector.getClientModeImplHandler().runWithScissors( 3318 () -> { 3319 success.value = mWifiNetworkSuggestionsManager.remove( 3320 networkSuggestions, callingPackageName); 3321 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 3322 if (!runWithScissorsSuccess) { 3323 Log.e(TAG, "Failed to post runnable to remove network suggestions"); 3324 return WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_INTERNAL; 3325 } 3326 if (success.value != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) { 3327 Log.e(TAG, "Failed to remove network suggestions"); 3328 } 3329 return success.value; 3330 } 3331 3332 /** 3333 * Gets the factory Wi-Fi MAC addresses. 3334 * @throws SecurityException if the caller does not have permission. 3335 * @return Array of String representing Wi-Fi MAC addresses, or null if failed. 3336 */ 3337 @Override getFactoryMacAddresses()3338 public String[] getFactoryMacAddresses() { 3339 final int uid = Binder.getCallingUid(); 3340 if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) { 3341 throw new SecurityException("App not allowed to get Wi-Fi factory MAC address " 3342 + "(uid = " + uid + ")"); 3343 } 3344 final List<String> result = new ArrayList<>(); 3345 boolean success = mWifiInjector.getClientModeImplHandler().runWithScissors(() -> { 3346 final String mac = mClientModeImpl.getFactoryMacAddress(); 3347 if (mac != null) { 3348 result.add(mac); 3349 } 3350 }, RUN_WITH_SCISSORS_TIMEOUT_MILLIS); 3351 if (success) { 3352 return result.isEmpty() ? null : result.stream().toArray(String[]::new); 3353 } 3354 return null; 3355 } 3356 3357 /** 3358 * Sets the current device mobility state. 3359 * @param state the new device mobility state 3360 */ 3361 @Override setDeviceMobilityState(@eviceMobilityState int state)3362 public void setDeviceMobilityState(@DeviceMobilityState int state) { 3363 mContext.enforceCallingPermission( 3364 android.Manifest.permission.WIFI_SET_DEVICE_MOBILITY_STATE, "WifiService"); 3365 3366 if (mVerboseLoggingEnabled) { 3367 mLog.info("setDeviceMobilityState uid=% state=%") 3368 .c(Binder.getCallingUid()) 3369 .c(state) 3370 .flush(); 3371 } 3372 // Post operation to handler thread 3373 mWifiInjector.getClientModeImplHandler().post( 3374 () -> mClientModeImpl.setDeviceMobilityState(state)); 3375 } 3376 3377 /** 3378 * Proxy for the final native call of the parent class. Enables mocking of 3379 * the function. 3380 */ getMockableCallingUid()3381 public int getMockableCallingUid() { 3382 return getCallingUid(); 3383 } 3384 3385 /** 3386 * Start DPP in Configurator-Initiator role. The current device will initiate DPP bootstrapping 3387 * with a peer, and send the SSID and password of the selected network. 3388 * 3389 * @param binder Caller's binder context 3390 * @param enrolleeUri URI of the Enrollee obtained externally (e.g. QR code scanning) 3391 * @param selectedNetworkId Selected network ID to be sent to the peer 3392 * @param netRole The network role of the enrollee 3393 * @param callback Callback for status updates 3394 */ 3395 @Override startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri, int selectedNetworkId, int netRole, IDppCallback callback)3396 public void startDppAsConfiguratorInitiator(IBinder binder, String enrolleeUri, 3397 int selectedNetworkId, int netRole, IDppCallback callback) { 3398 // verify arguments 3399 if (binder == null) { 3400 throw new IllegalArgumentException("Binder must not be null"); 3401 } 3402 if (TextUtils.isEmpty(enrolleeUri)) { 3403 throw new IllegalArgumentException("Enrollee URI must not be null or empty"); 3404 } 3405 if (selectedNetworkId < 0) { 3406 throw new IllegalArgumentException("Selected network ID invalid"); 3407 } 3408 if (callback == null) { 3409 throw new IllegalArgumentException("Callback must not be null"); 3410 } 3411 3412 final int uid = getMockableCallingUid(); 3413 3414 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 3415 throw new SecurityException(TAG + ": Permission denied"); 3416 } 3417 3418 mDppManager.mHandler.post(() -> { 3419 mDppManager.startDppAsConfiguratorInitiator(uid, binder, enrolleeUri, 3420 selectedNetworkId, netRole, callback); 3421 }); 3422 } 3423 3424 /** 3425 * Start DPP in Enrollee-Initiator role. The current device will initiate DPP bootstrapping 3426 * with a peer, and receive the SSID and password from the peer configurator. 3427 * 3428 * @param binder Caller's binder context 3429 * @param configuratorUri URI of the Configurator obtained externally (e.g. QR code scanning) 3430 * @param callback Callback for status updates 3431 */ 3432 @Override startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri, IDppCallback callback)3433 public void startDppAsEnrolleeInitiator(IBinder binder, String configuratorUri, 3434 IDppCallback callback) { 3435 // verify arguments 3436 if (binder == null) { 3437 throw new IllegalArgumentException("Binder must not be null"); 3438 } 3439 if (TextUtils.isEmpty(configuratorUri)) { 3440 throw new IllegalArgumentException("Enrollee URI must not be null or empty"); 3441 } 3442 if (callback == null) { 3443 throw new IllegalArgumentException("Callback must not be null"); 3444 } 3445 3446 final int uid = getMockableCallingUid(); 3447 3448 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 3449 throw new SecurityException(TAG + ": Permission denied"); 3450 } 3451 3452 mDppManager.mHandler.post(() -> { 3453 mDppManager.startDppAsEnrolleeInitiator(uid, binder, configuratorUri, callback); 3454 }); 3455 } 3456 3457 /** 3458 * Stop or abort a current DPP session. 3459 */ 3460 @Override stopDppSession()3461 public void stopDppSession() throws android.os.RemoteException { 3462 if (!isSettingsOrSuw(Binder.getCallingPid(), Binder.getCallingUid())) { 3463 throw new SecurityException(TAG + ": Permission denied"); 3464 } 3465 final int uid = getMockableCallingUid(); 3466 3467 mDppManager.mHandler.post(() -> { 3468 mDppManager.stopDppSession(uid); 3469 }); 3470 } 3471 3472 /** 3473 * see {@link android.net.wifi.WifiManager#addOnWifiUsabilityStatsListener(Executor, 3474 * OnWifiUsabilityStatsListener)} 3475 * 3476 * @param binder IBinder instance to allow cleanup if the app dies 3477 * @param listener WifiUsabilityStatsEntry listener to add 3478 * @param listenerIdentifier Unique ID of the adding listener. This ID will be used to 3479 * remove the listener. See {@link removeOnWifiUsabilityStatsListener(int)} 3480 * 3481 * @throws SecurityException if the caller does not have permission to add a listener 3482 * @throws RemoteException if remote exception happens 3483 * @throws IllegalArgumentException if the arguments are null or invalid 3484 */ 3485 @Override addOnWifiUsabilityStatsListener(IBinder binder, IOnWifiUsabilityStatsListener listener, int listenerIdentifier)3486 public void addOnWifiUsabilityStatsListener(IBinder binder, 3487 IOnWifiUsabilityStatsListener listener, int listenerIdentifier) { 3488 // verify arguments 3489 if (binder == null) { 3490 throw new IllegalArgumentException("Binder must not be null"); 3491 } 3492 if (listener == null) { 3493 throw new IllegalArgumentException("Listener must not be null"); 3494 } 3495 mContext.enforceCallingPermission( 3496 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 3497 if (mVerboseLoggingEnabled) { 3498 mLog.info("addOnWifiUsabilityStatsListener uid=%") 3499 .c(Binder.getCallingUid()).flush(); 3500 } 3501 // Post operation to handler thread 3502 mWifiInjector.getClientModeImplHandler().post(() -> { 3503 mWifiMetrics.addOnWifiUsabilityListener(binder, listener, listenerIdentifier); 3504 }); 3505 } 3506 3507 /** 3508 * see {@link android.net.wifi.WifiManager#removeOnWifiUsabilityStatsListener( 3509 * OnWifiUsabilityStatsListener)} 3510 * 3511 * @param listenerIdentifier Unique ID of the listener to be removed. 3512 * 3513 * @throws SecurityException if the caller does not have permission to add a listener 3514 */ 3515 @Override removeOnWifiUsabilityStatsListener(int listenerIdentifier)3516 public void removeOnWifiUsabilityStatsListener(int listenerIdentifier) { 3517 mContext.enforceCallingPermission( 3518 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 3519 if (mVerboseLoggingEnabled) { 3520 mLog.info("removeOnWifiUsabilityStatsListener uid=%") 3521 .c(Binder.getCallingUid()).flush(); 3522 } 3523 // Post operation to handler thread 3524 mWifiInjector.getClientModeImplHandler().post(() -> { 3525 mWifiMetrics.removeOnWifiUsabilityListener(listenerIdentifier); 3526 }); 3527 } 3528 3529 /** 3530 * Updates the Wi-Fi usability score. 3531 * @param seqNum Sequence number of the Wi-Fi usability score. 3532 * @param score The Wi-Fi usability score. 3533 * @param predictionHorizonSec Prediction horizon of the Wi-Fi usability score in second. 3534 */ 3535 @Override updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec)3536 public void updateWifiUsabilityScore(int seqNum, int score, int predictionHorizonSec) { 3537 mContext.enforceCallingPermission( 3538 android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE, "WifiService"); 3539 3540 if (mVerboseLoggingEnabled) { 3541 mLog.info("updateWifiUsabilityScore uid=% seqNum=% score=% predictionHorizonSec=%") 3542 .c(Binder.getCallingUid()) 3543 .c(seqNum) 3544 .c(score) 3545 .c(predictionHorizonSec) 3546 .flush(); 3547 } 3548 // Post operation to handler thread 3549 mWifiInjector.getClientModeImplHandler().post( 3550 () -> mClientModeImpl.updateWifiUsabilityScore(seqNum, score, 3551 predictionHorizonSec)); 3552 } 3553 } 3554