WifiServiceImpl.java revision f09b6de086d5a00417613886aa43402285d2a8ab
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 17package com.android.server.wifi; 18 19import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED; 20import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED; 21import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED; 22import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED; 23import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED; 24import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED; 25import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; 26import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; 27import static com.android.server.wifi.WifiController.CMD_SET_AP; 28import static com.android.server.wifi.WifiController.CMD_USER_PRESENT; 29import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; 30 31import android.Manifest; 32import android.app.AppOpsManager; 33import android.bluetooth.BluetoothAdapter; 34import android.content.BroadcastReceiver; 35import android.content.Context; 36import android.content.Intent; 37import android.content.IntentFilter; 38import android.content.pm.ApplicationInfo; 39import android.content.pm.PackageManager; 40import android.database.ContentObserver; 41import android.net.ConnectivityManager; 42import android.net.DhcpInfo; 43import android.net.DhcpResults; 44import android.net.Network; 45import android.net.NetworkUtils; 46import android.net.Uri; 47import android.net.ip.IpManager; 48import android.net.wifi.IWifiManager; 49import android.net.wifi.ScanResult; 50import android.net.wifi.ScanSettings; 51import android.net.wifi.WifiActivityEnergyInfo; 52import android.net.wifi.WifiConfiguration; 53import android.net.wifi.WifiConnectionStatistics; 54import android.net.wifi.WifiEnterpriseConfig; 55import android.net.wifi.WifiInfo; 56import android.net.wifi.WifiLinkLayerStats; 57import android.net.wifi.WifiManager; 58import android.net.wifi.WifiScanner; 59import android.net.wifi.hotspot2.PasspointConfiguration; 60import android.os.AsyncTask; 61import android.os.BatteryStats; 62import android.os.Binder; 63import android.os.Build; 64import android.os.Bundle; 65import android.os.Handler; 66import android.os.HandlerThread; 67import android.os.IBinder; 68import android.os.Looper; 69import android.os.Message; 70import android.os.Messenger; 71import android.os.PowerManager; 72import android.os.Process; 73import android.os.RemoteException; 74import android.os.ResultReceiver; 75import android.os.SystemClock; 76import android.os.UserHandle; 77import android.os.UserManager; 78import android.os.WorkSource; 79import android.provider.Settings; 80import android.text.TextUtils; 81import android.util.Log; 82import android.util.Slog; 83 84import com.android.internal.telephony.IccCardConstants; 85import com.android.internal.telephony.PhoneConstants; 86import com.android.internal.telephony.TelephonyIntents; 87import com.android.internal.util.AsyncChannel; 88import com.android.server.wifi.hotspot2.PasspointManager; 89import com.android.server.wifi.util.WifiPermissionsUtil; 90 91import java.io.BufferedReader; 92import java.io.FileDescriptor; 93import java.io.FileNotFoundException; 94import java.io.FileReader; 95import java.io.IOException; 96import java.io.PrintWriter; 97import java.net.Inet4Address; 98import java.net.InetAddress; 99import java.security.GeneralSecurityException; 100import java.security.KeyStore; 101import java.security.cert.CertPath; 102import java.security.cert.CertPathValidator; 103import java.security.cert.CertPathValidatorException; 104import java.security.cert.CertificateFactory; 105import java.security.cert.PKIXParameters; 106import java.security.cert.X509Certificate; 107import java.util.ArrayList; 108import java.util.Arrays; 109import java.util.List; 110 111/** 112 * WifiService handles remote WiFi operation requests by implementing 113 * the IWifiManager interface. 114 * 115 * @hide 116 */ 117public class WifiServiceImpl extends IWifiManager.Stub { 118 private static final String TAG = "WifiService"; 119 private static final boolean DBG = true; 120 private static final boolean VDBG = false; 121 122 // Dumpsys argument to enable/disable disconnect on IP reachability failures. 123 private static final String DUMP_ARG_SET_IPREACH_DISCONNECT = "set-ipreach-disconnect"; 124 private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED = "enabled"; 125 private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED = "disabled"; 126 127 final WifiStateMachine mWifiStateMachine; 128 129 private final Context mContext; 130 private final FrameworkFacade mFacade; 131 132 private final PowerManager mPowerManager; 133 private final AppOpsManager mAppOps; 134 private final UserManager mUserManager; 135 private final WifiCountryCode mCountryCode; 136 // Debug counter tracking scan requests sent by WifiManager 137 private int scanRequestCounter = 0; 138 139 /* Tracks the open wi-fi network notification */ 140 private WifiNotificationController mNotificationController; 141 private WifiWakeupController mWifiWakeupController; 142 /* Polls traffic stats and notifies clients */ 143 private WifiTrafficPoller mTrafficPoller; 144 /* Tracks the persisted states for wi-fi & airplane mode */ 145 final WifiSettingsStore mSettingsStore; 146 /* Logs connection events and some general router and scan stats */ 147 private final WifiMetrics mWifiMetrics; 148 /* Manages affiliated certificates for current user */ 149 private final WifiCertManager mCertManager; 150 151 private final WifiInjector mWifiInjector; 152 /* Backup/Restore Module */ 153 private final WifiBackupRestore mWifiBackupRestore; 154 155 private WifiScanner mWifiScanner; 156 157 /** 158 * Asynchronous channel to WifiStateMachine 159 */ 160 private AsyncChannel mWifiStateMachineChannel; 161 162 private WifiPermissionsUtil mWifiPermissionsUtil; 163 164 private final boolean mPermissionReviewRequired; 165 private final PasspointManager mPasspointManager; 166 167 /** 168 * Handles client connections 169 */ 170 private class ClientHandler extends Handler { 171 172 ClientHandler(Looper looper) { 173 super(looper); 174 } 175 176 @Override 177 public void handleMessage(Message msg) { 178 switch (msg.what) { 179 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 180 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 181 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); 182 // We track the clients by the Messenger 183 // since it is expected to be always available 184 mTrafficPoller.addClient(msg.replyTo); 185 } else { 186 Slog.e(TAG, "Client connection failure, error=" + msg.arg1); 187 } 188 break; 189 } 190 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 191 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 192 if (DBG) Slog.d(TAG, "Send failed, client connection lost"); 193 } else { 194 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); 195 } 196 mTrafficPoller.removeClient(msg.replyTo); 197 break; 198 } 199 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 200 AsyncChannel ac = new AsyncChannel(); 201 ac.connect(mContext, this, msg.replyTo); 202 break; 203 } 204 /* Client commands are forwarded to state machine */ 205 case WifiManager.CONNECT_NETWORK: 206 case WifiManager.SAVE_NETWORK: { 207 WifiConfiguration config = (WifiConfiguration) msg.obj; 208 int networkId = msg.arg1; 209 if (msg.what == WifiManager.SAVE_NETWORK) { 210 Slog.d("WiFiServiceImpl ", "SAVE" 211 + " nid=" + Integer.toString(networkId) 212 + " uid=" + msg.sendingUid 213 + " name=" 214 + mContext.getPackageManager().getNameForUid(msg.sendingUid)); 215 } 216 if (msg.what == WifiManager.CONNECT_NETWORK) { 217 Slog.d("WiFiServiceImpl ", "CONNECT " 218 + " nid=" + Integer.toString(networkId) 219 + " uid=" + msg.sendingUid 220 + " name=" 221 + mContext.getPackageManager().getNameForUid(msg.sendingUid)); 222 } 223 224 if (config != null && isValid(config)) { 225 if (DBG) Slog.d(TAG, "Connect with config" + config); 226 mWifiStateMachine.sendMessage(Message.obtain(msg)); 227 } else if (config == null 228 && networkId != WifiConfiguration.INVALID_NETWORK_ID) { 229 if (DBG) Slog.d(TAG, "Connect with networkId" + networkId); 230 mWifiStateMachine.sendMessage(Message.obtain(msg)); 231 } else { 232 Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg); 233 if (msg.what == WifiManager.CONNECT_NETWORK) { 234 replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED, 235 WifiManager.INVALID_ARGS); 236 } else { 237 replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED, 238 WifiManager.INVALID_ARGS); 239 } 240 } 241 break; 242 } 243 case WifiManager.FORGET_NETWORK: 244 mWifiStateMachine.sendMessage(Message.obtain(msg)); 245 break; 246 case WifiManager.START_WPS: 247 case WifiManager.CANCEL_WPS: 248 case WifiManager.DISABLE_NETWORK: 249 case WifiManager.RSSI_PKTCNT_FETCH: { 250 mWifiStateMachine.sendMessage(Message.obtain(msg)); 251 break; 252 } 253 default: { 254 Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg); 255 break; 256 } 257 } 258 } 259 260 private void replyFailed(Message msg, int what, int why) { 261 Message reply = Message.obtain(); 262 reply.what = what; 263 reply.arg1 = why; 264 try { 265 msg.replyTo.send(reply); 266 } catch (RemoteException e) { 267 // There's not much we can do if reply can't be sent! 268 } 269 } 270 } 271 private ClientHandler mClientHandler; 272 273 /** 274 * Handles interaction with WifiStateMachine 275 */ 276 private class WifiStateMachineHandler extends Handler { 277 private AsyncChannel mWsmChannel; 278 279 WifiStateMachineHandler(Looper looper) { 280 super(looper); 281 mWsmChannel = new AsyncChannel(); 282 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 283 } 284 285 @Override 286 public void handleMessage(Message msg) { 287 switch (msg.what) { 288 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 289 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 290 mWifiStateMachineChannel = mWsmChannel; 291 } else { 292 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1); 293 mWifiStateMachineChannel = null; 294 } 295 break; 296 } 297 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 298 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1); 299 mWifiStateMachineChannel = null; 300 //Re-establish connection to state machine 301 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 302 break; 303 } 304 default: { 305 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg); 306 break; 307 } 308 } 309 } 310 } 311 312 WifiStateMachineHandler mWifiStateMachineHandler; 313 private WifiController mWifiController; 314 private final WifiLockManager mWifiLockManager; 315 private final WifiMulticastLockManager mWifiMulticastLockManager; 316 317 public WifiServiceImpl(Context context) { 318 mContext = context; 319 mWifiInjector = new WifiInjector(context); 320 321 mFacade = mWifiInjector.getFrameworkFacade(); 322 mWifiMetrics = mWifiInjector.getWifiMetrics(); 323 mTrafficPoller = mWifiInjector.getWifiTrafficPoller(); 324 mUserManager = UserManager.get(mContext); 325 mCountryCode = mWifiInjector.getWifiCountryCode(); 326 mWifiStateMachine = mWifiInjector.getWifiStateMachine(); 327 mWifiStateMachine.enableRssiPolling(true); 328 mSettingsStore = mWifiInjector.getWifiSettingsStore(); 329 mPowerManager = mContext.getSystemService(PowerManager.class); 330 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 331 mCertManager = mWifiInjector.getWifiCertManager(); 332 333 mNotificationController = mWifiInjector.getWifiNotificationController(); 334 mWifiWakeupController = mWifiInjector.getWifiWakeupController(); 335 336 mWifiLockManager = mWifiInjector.getWifiLockManager(); 337 mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager(); 338 HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread(); 339 mClientHandler = new ClientHandler(wifiServiceHandlerThread.getLooper()); 340 mWifiStateMachineHandler = 341 new WifiStateMachineHandler(wifiServiceHandlerThread.getLooper()); 342 mWifiController = mWifiInjector.getWifiController(); 343 mWifiBackupRestore = mWifiInjector.getWifiBackupRestore(); 344 mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED 345 || context.getResources().getBoolean( 346 com.android.internal.R.bool.config_permissionReviewRequired); 347 mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil(); 348 mPasspointManager = mWifiInjector.getPasspointManager(); 349 350 enableVerboseLoggingInternal(getVerboseLoggingLevel()); 351 } 352 353 354 /** 355 * Check if Wi-Fi needs to be enabled and start 356 * if needed 357 * 358 * This function is used only at boot time 359 */ 360 public void checkAndStartWifi() { 361 /* Check if wi-fi needs to be enabled */ 362 boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); 363 Slog.i(TAG, "WifiService starting up with Wi-Fi " + 364 (wifiEnabled ? "enabled" : "disabled")); 365 366 registerForScanModeChange(); 367 mContext.registerReceiver( 368 new BroadcastReceiver() { 369 @Override 370 public void onReceive(Context context, Intent intent) { 371 if (mSettingsStore.handleAirplaneModeToggled()) { 372 mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED); 373 } 374 if (mSettingsStore.isAirplaneModeOn()) { 375 Log.d(TAG, "resetting country code because Airplane mode is ON"); 376 mCountryCode.airplaneModeEnabled(); 377 } 378 } 379 }, 380 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 381 382 mContext.registerReceiver( 383 new BroadcastReceiver() { 384 @Override 385 public void onReceive(Context context, Intent intent) { 386 String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); 387 if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) { 388 Log.d(TAG, "resetting networks because SIM was removed"); 389 mWifiStateMachine.resetSimAuthNetworks(false); 390 Log.d(TAG, "resetting country code because SIM is removed"); 391 mCountryCode.simCardRemoved(); 392 } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) { 393 Log.d(TAG, "resetting networks because SIM was loaded"); 394 mWifiStateMachine.resetSimAuthNetworks(true); 395 } 396 } 397 }, 398 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); 399 400 // Adding optimizations of only receiving broadcasts when wifi is enabled 401 // can result in race conditions when apps toggle wifi in the background 402 // without active user involvement. Always receive broadcasts. 403 registerForBroadcasts(); 404 registerForPackageOrUserRemoval(); 405 mInIdleMode = mPowerManager.isDeviceIdleMode(); 406 407 mWifiController.start(); 408 409 // If we are already disabled (could be due to airplane mode), avoid changing persist 410 // state here 411 if (wifiEnabled) { 412 try { 413 setWifiEnabled(mContext.getPackageName(), wifiEnabled); 414 } catch (RemoteException e) { 415 /* ignore - local call */ 416 } 417 } 418 } 419 420 public void handleUserSwitch(int userId) { 421 mWifiStateMachine.handleUserSwitch(userId); 422 } 423 424 public void handleUserUnlock(int userId) { 425 mWifiStateMachine.handleUserUnlock(userId); 426 } 427 428 public void handleUserStop(int userId) { 429 mWifiStateMachine.handleUserStop(userId); 430 } 431 432 /** 433 * see {@link android.net.wifi.WifiManager#pingSupplicant()} 434 * @return {@code true} if the operation succeeds, {@code false} otherwise 435 */ 436 @Override 437 public boolean pingSupplicant() { 438 enforceAccessPermission(); 439 if (mWifiStateMachineChannel != null) { 440 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel); 441 } else { 442 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 443 return false; 444 } 445 } 446 447 /** 448 * see {@link android.net.wifi.WifiManager#startScan} 449 * and {@link android.net.wifi.WifiManager#startCustomizedScan} 450 * 451 * @param settings If null, use default parameter, i.e. full scan. 452 * @param workSource If null, all blame is given to the calling uid. 453 */ 454 @Override 455 public void startScan(ScanSettings settings, WorkSource workSource) { 456 enforceChangePermission(); 457 synchronized (this) { 458 if (mWifiScanner == null) { 459 mWifiScanner = mWifiInjector.getWifiScanner(); 460 } 461 if (mInIdleMode) { 462 // Need to send an immediate scan result broadcast in case the 463 // caller is waiting for a result .. 464 465 // clear calling identity to send broadcast 466 long callingIdentity = Binder.clearCallingIdentity(); 467 try { 468 // TODO: investigate if the logic to cancel scans when idle can move to 469 // WifiScanningServiceImpl. This will 1 - clean up WifiServiceImpl and 2 - 470 // avoid plumbing an awkward path to report a cancelled/failed scan. This will 471 // be sent directly until b/31398592 is fixed. 472 Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 473 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 474 intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false); 475 mContext.sendBroadcastAsUser(intent, UserHandle.ALL); 476 } finally { 477 // restore calling identity 478 Binder.restoreCallingIdentity(callingIdentity); 479 } 480 mScanPending = true; 481 return; 482 } 483 } 484 if (settings != null) { 485 settings = new ScanSettings(settings); 486 if (!settings.isValid()) { 487 Slog.e(TAG, "invalid scan setting"); 488 return; 489 } 490 } 491 if (workSource != null) { 492 enforceWorkSourcePermission(); 493 // WifiManager currently doesn't use names, so need to clear names out of the 494 // supplied WorkSource to allow future WorkSource combining. 495 workSource.clearNames(); 496 } 497 if (workSource == null && Binder.getCallingUid() >= 0) { 498 workSource = new WorkSource(Binder.getCallingUid()); 499 } 500 mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++, 501 settings, workSource); 502 } 503 504 @Override 505 public String getWpsNfcConfigurationToken(int netId) { 506 enforceConnectivityInternalPermission(); 507 return mWifiStateMachine.syncGetWpsNfcConfigurationToken(netId); 508 } 509 510 boolean mInIdleMode; 511 boolean mScanPending; 512 513 void handleIdleModeChanged() { 514 boolean doScan = false; 515 synchronized (this) { 516 boolean idle = mPowerManager.isDeviceIdleMode(); 517 if (mInIdleMode != idle) { 518 mInIdleMode = idle; 519 if (!idle) { 520 if (mScanPending) { 521 mScanPending = false; 522 doScan = true; 523 } 524 } 525 } 526 } 527 if (doScan) { 528 // Someone requested a scan while we were idle; do a full scan now. 529 startScan(null, null); 530 } 531 } 532 533 private void enforceAccessPermission() { 534 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 535 "WifiService"); 536 } 537 538 private void enforceChangePermission() { 539 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 540 "WifiService"); 541 } 542 543 private void enforceLocationHardwarePermission() { 544 mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE, 545 "LocationHardware"); 546 } 547 548 private void enforceReadCredentialPermission() { 549 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL, 550 "WifiService"); 551 } 552 553 private void enforceWorkSourcePermission() { 554 mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 555 "WifiService"); 556 557 } 558 559 private void enforceMulticastChangePermission() { 560 mContext.enforceCallingOrSelfPermission( 561 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 562 "WifiService"); 563 } 564 565 private void enforceConnectivityInternalPermission() { 566 mContext.enforceCallingOrSelfPermission( 567 android.Manifest.permission.CONNECTIVITY_INTERNAL, 568 "ConnectivityService"); 569 } 570 571 /** 572 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 573 * @param enable {@code true} to enable, {@code false} to disable. 574 * @return {@code true} if the enable/disable operation was 575 * started or is already in the queue. 576 */ 577 @Override 578 public synchronized boolean setWifiEnabled(String packageName, boolean enable) 579 throws RemoteException { 580 enforceChangePermission(); 581 Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() 582 + ", uid=" + Binder.getCallingUid()); 583 584 /* 585 * Caller might not have WRITE_SECURE_SETTINGS, 586 * only CHANGE_WIFI_STATE is enforced 587 */ 588 long ident = Binder.clearCallingIdentity(); 589 try { 590 if (! mSettingsStore.handleWifiToggled(enable)) { 591 // Nothing to do if wifi cannot be toggled 592 return true; 593 } 594 } finally { 595 Binder.restoreCallingIdentity(ident); 596 } 597 598 599 if (mPermissionReviewRequired) { 600 final int wiFiEnabledState = getWifiEnabledState(); 601 if (enable) { 602 if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING 603 || wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) { 604 if (startConsentUiIfNeeded(packageName, Binder.getCallingUid(), 605 WifiManager.ACTION_REQUEST_ENABLE)) { 606 return true; 607 } 608 } 609 } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING 610 || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) { 611 if (startConsentUiIfNeeded(packageName, Binder.getCallingUid(), 612 WifiManager.ACTION_REQUEST_DISABLE)) { 613 return true; 614 } 615 } 616 } 617 618 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 619 return true; 620 } 621 622 /** 623 * see {@link WifiManager#getWifiState()} 624 * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, 625 * {@link WifiManager#WIFI_STATE_DISABLING}, 626 * {@link WifiManager#WIFI_STATE_ENABLED}, 627 * {@link WifiManager#WIFI_STATE_ENABLING}, 628 * {@link WifiManager#WIFI_STATE_UNKNOWN} 629 */ 630 @Override 631 public int getWifiEnabledState() { 632 enforceAccessPermission(); 633 return mWifiStateMachine.syncGetWifiState(); 634 } 635 636 /** 637 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)} 638 * @param wifiConfig SSID, security and channel details as 639 * part of WifiConfiguration 640 * @param enabled true to enable and false to disable 641 */ 642 @Override 643 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 644 enforceChangePermission(); 645 ConnectivityManager.enforceTetherChangePermission(mContext); 646 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { 647 throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user."); 648 } 649 // null wifiConfig is a meaningful input for CMD_SET_AP 650 if (wifiConfig == null || isValid(wifiConfig)) { 651 mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget(); 652 } else { 653 Slog.e(TAG, "Invalid WifiConfiguration"); 654 } 655 } 656 657 /** 658 * see {@link WifiManager#getWifiApState()} 659 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 660 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 661 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 662 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 663 * {@link WifiManager#WIFI_AP_STATE_FAILED} 664 */ 665 @Override 666 public int getWifiApEnabledState() { 667 enforceAccessPermission(); 668 return mWifiStateMachine.syncGetWifiApState(); 669 } 670 671 /** 672 * see {@link WifiManager#getWifiApConfiguration()} 673 * @return soft access point configuration 674 */ 675 @Override 676 public WifiConfiguration getWifiApConfiguration() { 677 enforceAccessPermission(); 678 return mWifiStateMachine.syncGetWifiApConfiguration(); 679 } 680 681 /** 682 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)} 683 * @param wifiConfig WifiConfiguration details for soft access point 684 */ 685 @Override 686 public void setWifiApConfiguration(WifiConfiguration wifiConfig) { 687 enforceChangePermission(); 688 if (wifiConfig == null) 689 return; 690 if (isValid(wifiConfig)) { 691 mWifiStateMachine.setWifiApConfiguration(wifiConfig); 692 } else { 693 Slog.e(TAG, "Invalid WifiConfiguration"); 694 } 695 } 696 697 /** 698 * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()} 699 */ 700 @Override 701 public boolean isScanAlwaysAvailable() { 702 enforceAccessPermission(); 703 return mSettingsStore.isScanAlwaysAvailable(); 704 } 705 706 /** 707 * see {@link android.net.wifi.WifiManager#disconnect()} 708 */ 709 @Override 710 public void disconnect() { 711 enforceChangePermission(); 712 mWifiStateMachine.disconnectCommand(); 713 } 714 715 /** 716 * see {@link android.net.wifi.WifiManager#reconnect()} 717 */ 718 @Override 719 public void reconnect() { 720 enforceChangePermission(); 721 mWifiStateMachine.reconnectCommand(); 722 } 723 724 /** 725 * see {@link android.net.wifi.WifiManager#reassociate()} 726 */ 727 @Override 728 public void reassociate() { 729 enforceChangePermission(); 730 mWifiStateMachine.reassociateCommand(); 731 } 732 733 /** 734 * see {@link android.net.wifi.WifiManager#getSupportedFeatures} 735 */ 736 @Override 737 public int getSupportedFeatures() { 738 enforceAccessPermission(); 739 if (mWifiStateMachineChannel != null) { 740 return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel); 741 } else { 742 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 743 return 0; 744 } 745 } 746 747 @Override 748 public void requestActivityInfo(ResultReceiver result) { 749 Bundle bundle = new Bundle(); 750 bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo()); 751 result.send(0, bundle); 752 } 753 754 /** 755 * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)} 756 */ 757 @Override 758 public WifiActivityEnergyInfo reportActivityInfo() { 759 enforceAccessPermission(); 760 if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) { 761 return null; 762 } 763 WifiLinkLayerStats stats; 764 WifiActivityEnergyInfo energyInfo = null; 765 if (mWifiStateMachineChannel != null) { 766 stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel); 767 if (stats != null) { 768 final long rxIdleCurrent = mContext.getResources().getInteger( 769 com.android.internal.R.integer.config_wifi_idle_receive_cur_ma); 770 final long rxCurrent = mContext.getResources().getInteger( 771 com.android.internal.R.integer.config_wifi_active_rx_cur_ma); 772 final long txCurrent = mContext.getResources().getInteger( 773 com.android.internal.R.integer.config_wifi_tx_cur_ma); 774 final double voltage = mContext.getResources().getInteger( 775 com.android.internal.R.integer.config_wifi_operating_voltage_mv) 776 / 1000.0; 777 778 final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time; 779 final long[] txTimePerLevel; 780 if (stats.tx_time_per_level != null) { 781 txTimePerLevel = new long[stats.tx_time_per_level.length]; 782 for (int i = 0; i < txTimePerLevel.length; i++) { 783 txTimePerLevel[i] = stats.tx_time_per_level[i]; 784 // TODO(b/27227497): Need to read the power consumed per level from config 785 } 786 } else { 787 // This will happen if the HAL get link layer API returned null. 788 txTimePerLevel = new long[0]; 789 } 790 final long energyUsed = (long)((stats.tx_time * txCurrent + 791 stats.rx_time * rxCurrent + 792 rxIdleTime * rxIdleCurrent) * voltage); 793 if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 || 794 stats.rx_time < 0 || energyUsed < 0) { 795 StringBuilder sb = new StringBuilder(); 796 sb.append(" rxIdleCur=" + rxIdleCurrent); 797 sb.append(" rxCur=" + rxCurrent); 798 sb.append(" txCur=" + txCurrent); 799 sb.append(" voltage=" + voltage); 800 sb.append(" on_time=" + stats.on_time); 801 sb.append(" tx_time=" + stats.tx_time); 802 sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel)); 803 sb.append(" rx_time=" + stats.rx_time); 804 sb.append(" rxIdleTime=" + rxIdleTime); 805 sb.append(" energy=" + energyUsed); 806 Log.d(TAG, " reportActivityInfo: " + sb.toString()); 807 } 808 809 // Convert the LinkLayerStats into EnergyActivity 810 energyInfo = new WifiActivityEnergyInfo(SystemClock.elapsedRealtime(), 811 WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time, 812 txTimePerLevel, stats.rx_time, rxIdleTime, energyUsed); 813 } 814 if (energyInfo != null && energyInfo.isValid()) { 815 return energyInfo; 816 } else { 817 return null; 818 } 819 } else { 820 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 821 return null; 822 } 823 } 824 825 /** 826 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 827 * @return the list of configured networks 828 */ 829 @Override 830 public List<WifiConfiguration> getConfiguredNetworks() { 831 enforceAccessPermission(); 832 if (mWifiStateMachineChannel != null) { 833 return mWifiStateMachine.syncGetConfiguredNetworks(Binder.getCallingUid(), 834 mWifiStateMachineChannel); 835 } else { 836 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 837 return null; 838 } 839 } 840 841 /** 842 * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()} 843 * @return the list of configured networks with real preSharedKey 844 */ 845 @Override 846 public List<WifiConfiguration> getPrivilegedConfiguredNetworks() { 847 enforceReadCredentialPermission(); 848 enforceAccessPermission(); 849 if (mWifiStateMachineChannel != null) { 850 return mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel); 851 } else { 852 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 853 return null; 854 } 855 } 856 857 /** 858 * Returns a WifiConfiguration matching this ScanResult 859 * @param scanResult scanResult that represents the BSSID 860 * @return {@link WifiConfiguration} that matches this BSSID or null 861 */ 862 @Override 863 public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) { 864 enforceAccessPermission(); 865 return mWifiStateMachine.syncGetMatchingWifiConfig(scanResult, mWifiStateMachineChannel); 866 } 867 868 /** 869 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 870 * @return the supplicant-assigned identifier for the new or updated 871 * network if the operation succeeds, or {@code -1} if it fails 872 */ 873 @Override 874 public int addOrUpdateNetwork(WifiConfiguration config) { 875 enforceChangePermission(); 876 if (isValid(config) && isValidPasspoint(config)) { 877 878 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; 879 880 if (config.isPasspoint() && 881 (enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS || 882 enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS)) { 883 if (config.updateIdentifier != null) { 884 enforceAccessPermission(); 885 } 886 else { 887 try { 888 verifyCert(enterpriseConfig.getCaCertificate()); 889 } catch (CertPathValidatorException cpve) { 890 Slog.e(TAG, "CA Cert " + 891 enterpriseConfig.getCaCertificate().getSubjectX500Principal() + 892 " untrusted: " + cpve.getMessage()); 893 return -1; 894 } catch (GeneralSecurityException | IOException e) { 895 Slog.e(TAG, "Failed to verify certificate" + 896 enterpriseConfig.getCaCertificate().getSubjectX500Principal() + 897 ": " + e); 898 return -1; 899 } 900 } 901 } 902 903 //TODO: pass the Uid the WifiStateMachine as a message parameter 904 Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid()) 905 + " SSID " + config.SSID 906 + " nid=" + Integer.toString(config.networkId)); 907 if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) { 908 config.creatorUid = Binder.getCallingUid(); 909 } else { 910 config.lastUpdateUid = Binder.getCallingUid(); 911 } 912 if (mWifiStateMachineChannel != null) { 913 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config); 914 } else { 915 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 916 return -1; 917 } 918 } else { 919 Slog.e(TAG, "bad network configuration"); 920 return -1; 921 } 922 } 923 924 public static void verifyCert(X509Certificate caCert) 925 throws GeneralSecurityException, IOException { 926 CertificateFactory factory = CertificateFactory.getInstance("X.509"); 927 CertPathValidator validator = 928 CertPathValidator.getInstance(CertPathValidator.getDefaultType()); 929 CertPath path = factory.generateCertPath( 930 Arrays.asList(caCert)); 931 KeyStore ks = KeyStore.getInstance("AndroidCAStore"); 932 ks.load(null, null); 933 PKIXParameters params = new PKIXParameters(ks); 934 params.setRevocationEnabled(false); 935 validator.validate(path, params); 936 } 937 938 /** 939 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 940 * @param netId the integer that identifies the network configuration 941 * to the supplicant 942 * @return {@code true} if the operation succeeded 943 */ 944 @Override 945 public boolean removeNetwork(int netId) { 946 enforceChangePermission(); 947 948 if (mWifiStateMachineChannel != null) { 949 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId); 950 } else { 951 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 952 return false; 953 } 954 } 955 956 /** 957 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 958 * @param netId the integer that identifies the network configuration 959 * to the supplicant 960 * @param disableOthers if true, disable all other networks. 961 * @return {@code true} if the operation succeeded 962 */ 963 @Override 964 public boolean enableNetwork(int netId, boolean disableOthers) { 965 enforceChangePermission(); 966 if (mWifiStateMachineChannel != null) { 967 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId, 968 disableOthers); 969 } else { 970 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 971 return false; 972 } 973 } 974 975 /** 976 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 977 * @param netId the integer that identifies the network configuration 978 * to the supplicant 979 * @return {@code true} if the operation succeeded 980 */ 981 @Override 982 public boolean disableNetwork(int netId) { 983 enforceChangePermission(); 984 if (mWifiStateMachineChannel != null) { 985 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId); 986 } else { 987 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 988 return false; 989 } 990 } 991 992 /** 993 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 994 * @return the Wi-Fi information, contained in {@link WifiInfo}. 995 */ 996 @Override 997 public WifiInfo getConnectionInfo() { 998 enforceAccessPermission(); 999 /* 1000 * Make sure we have the latest information, by sending 1001 * a status request to the supplicant. 1002 */ 1003 return mWifiStateMachine.syncRequestConnectionInfo(); 1004 } 1005 1006 /** 1007 * Return the results of the most recent access point scan, in the form of 1008 * a list of {@link ScanResult} objects. 1009 * @return the list of results 1010 */ 1011 @Override 1012 public List<ScanResult> getScanResults(String callingPackage) { 1013 enforceAccessPermission(); 1014 int uid = Binder.getCallingUid(); 1015 long ident = Binder.clearCallingIdentity(); 1016 try { 1017 if (!mWifiPermissionsUtil.canAccessScanResults(callingPackage, 1018 uid, Build.VERSION_CODES.M)) { 1019 return new ArrayList<ScanResult>(); 1020 } 1021 if (mWifiScanner == null) { 1022 mWifiScanner = mWifiInjector.getWifiScanner(); 1023 } 1024 return mWifiScanner.getSingleScanResults(); 1025 } finally { 1026 Binder.restoreCallingIdentity(ident); 1027 } 1028 } 1029 1030 /** 1031 * Add a Passpoint configuration. 1032 * 1033 * @param config The Passpoint configuration to be added 1034 * @return true on success or false on failure 1035 */ 1036 @Override 1037 public boolean addPasspointConfiguration(PasspointConfiguration config) { 1038 enforceChangePermission(); 1039 return mPasspointManager.addProvider(config); 1040 } 1041 1042 /** 1043 * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name). 1044 * 1045 * @param fqdn The FQDN of the Passpoint configuration to be removed 1046 * @return true on success or false on failure 1047 */ 1048 @Override 1049 public boolean removePasspointConfiguration(String fqdn) { 1050 enforceChangePermission(); 1051 return mPasspointManager.removeProvider(fqdn); 1052 } 1053 1054 /** 1055 * Return the list of the installed Passpoint configurations. 1056 * 1057 * @return A list of {@link PasspointConfiguration} or null 1058 */ 1059 @Override 1060 public List<PasspointConfiguration> getPasspointConfigurations() { 1061 enforceAccessPermission(); 1062 return mPasspointManager.getProviderConfigs(); 1063 } 1064 1065 /** 1066 * Query for a Hotspot 2.0 release 2 OSU icon 1067 * @param bssid The BSSID of the AP 1068 * @param fileName Icon file name 1069 */ 1070 @Override 1071 public void queryPasspointIcon(long bssid, String fileName) { 1072 mWifiStateMachine.syncQueryPasspointIcon(mWifiStateMachineChannel, bssid, fileName); 1073 } 1074 1075 /** 1076 * Match the currently associated network against the SP matching the given FQDN 1077 * @param fqdn FQDN of the SP 1078 * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined] 1079 */ 1080 @Override 1081 public int matchProviderWithCurrentNetwork(String fqdn) { 1082 return mWifiStateMachine.matchProviderWithCurrentNetwork(mWifiStateMachineChannel, fqdn); 1083 } 1084 1085 /** 1086 * Deauthenticate and set the re-authentication hold off time for the current network 1087 * @param holdoff hold off time in milliseconds 1088 * @param ess set if the hold off pertains to an ESS rather than a BSS 1089 */ 1090 @Override 1091 public void deauthenticateNetwork(long holdoff, boolean ess) { 1092 mWifiStateMachine.deauthenticateNetwork(mWifiStateMachineChannel, holdoff, ess); 1093 } 1094 1095 /** 1096 * Tell the supplicant to persist the current list of configured networks. 1097 * @return {@code true} if the operation succeeded 1098 * 1099 * TODO: deprecate this 1100 */ 1101 @Override 1102 public boolean saveConfiguration() { 1103 enforceChangePermission(); 1104 if (mWifiStateMachineChannel != null) { 1105 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel); 1106 } else { 1107 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 1108 return false; 1109 } 1110 } 1111 1112 /** 1113 * Set the country code 1114 * @param countryCode ISO 3166 country code. 1115 * @param persist {@code true} if the setting should be remembered. 1116 * 1117 * The persist behavior exists so that wifi can fall back to the last 1118 * persisted country code on a restart, when the locale information is 1119 * not available from telephony. 1120 */ 1121 @Override 1122 public void setCountryCode(String countryCode, boolean persist) { 1123 Slog.i(TAG, "WifiService trying to set country code to " + countryCode + 1124 " with persist set to " + persist); 1125 enforceConnectivityInternalPermission(); 1126 final long token = Binder.clearCallingIdentity(); 1127 try { 1128 if (mCountryCode.setCountryCode(countryCode, persist) && persist) { 1129 // Save this country code to persistent storage 1130 mFacade.setStringSetting(mContext, 1131 Settings.Global.WIFI_COUNTRY_CODE, 1132 countryCode); 1133 } 1134 } finally { 1135 Binder.restoreCallingIdentity(token); 1136 } 1137 } 1138 1139 /** 1140 * Get the country code 1141 * @return Get the best choice country code for wifi, regardless of if it was set or 1142 * not. 1143 * Returns null when there is no country code available. 1144 */ 1145 @Override 1146 public String getCountryCode() { 1147 enforceConnectivityInternalPermission(); 1148 String country = mCountryCode.getCountryCode(); 1149 return country; 1150 } 1151 1152 @Override 1153 public boolean isDualBandSupported() { 1154 //TODO: Should move towards adding a driver API that checks at runtime 1155 return mContext.getResources().getBoolean( 1156 com.android.internal.R.bool.config_wifi_dual_band_support); 1157 } 1158 1159 /** 1160 * Return the DHCP-assigned addresses from the last successful DHCP request, 1161 * if any. 1162 * @return the DHCP information 1163 * @deprecated 1164 */ 1165 @Override 1166 @Deprecated 1167 public DhcpInfo getDhcpInfo() { 1168 enforceAccessPermission(); 1169 DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults(); 1170 1171 DhcpInfo info = new DhcpInfo(); 1172 1173 if (dhcpResults.ipAddress != null && 1174 dhcpResults.ipAddress.getAddress() instanceof Inet4Address) { 1175 info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress()); 1176 } 1177 1178 if (dhcpResults.gateway != null) { 1179 info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway); 1180 } 1181 1182 int dnsFound = 0; 1183 for (InetAddress dns : dhcpResults.dnsServers) { 1184 if (dns instanceof Inet4Address) { 1185 if (dnsFound == 0) { 1186 info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 1187 } else { 1188 info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 1189 } 1190 if (++dnsFound > 1) break; 1191 } 1192 } 1193 Inet4Address serverAddress = dhcpResults.serverAddress; 1194 if (serverAddress != null) { 1195 info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress); 1196 } 1197 info.leaseDuration = dhcpResults.leaseDuration; 1198 1199 return info; 1200 } 1201 1202 /** 1203 * enable TDLS for the local NIC to remote NIC 1204 * The APPs don't know the remote MAC address to identify NIC though, 1205 * so we need to do additional work to find it from remote IP address 1206 */ 1207 1208 class TdlsTaskParams { 1209 public String remoteIpAddress; 1210 public boolean enable; 1211 } 1212 1213 class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> { 1214 @Override 1215 protected Integer doInBackground(TdlsTaskParams... params) { 1216 1217 // Retrieve parameters for the call 1218 TdlsTaskParams param = params[0]; 1219 String remoteIpAddress = param.remoteIpAddress.trim(); 1220 boolean enable = param.enable; 1221 1222 // Get MAC address of Remote IP 1223 String macAddress = null; 1224 1225 BufferedReader reader = null; 1226 1227 try { 1228 reader = new BufferedReader(new FileReader("/proc/net/arp")); 1229 1230 // Skip over the line bearing colum titles 1231 String line = reader.readLine(); 1232 1233 while ((line = reader.readLine()) != null) { 1234 String[] tokens = line.split("[ ]+"); 1235 if (tokens.length < 6) { 1236 continue; 1237 } 1238 1239 // ARP column format is 1240 // Address HWType HWAddress Flags Mask IFace 1241 String ip = tokens[0]; 1242 String mac = tokens[3]; 1243 1244 if (remoteIpAddress.equals(ip)) { 1245 macAddress = mac; 1246 break; 1247 } 1248 } 1249 1250 if (macAddress == null) { 1251 Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " + 1252 "/proc/net/arp"); 1253 } else { 1254 enableTdlsWithMacAddress(macAddress, enable); 1255 } 1256 1257 } catch (FileNotFoundException e) { 1258 Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address"); 1259 } catch (IOException e) { 1260 Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address"); 1261 } finally { 1262 try { 1263 if (reader != null) { 1264 reader.close(); 1265 } 1266 } 1267 catch (IOException e) { 1268 // Do nothing 1269 } 1270 } 1271 1272 return 0; 1273 } 1274 } 1275 1276 @Override 1277 public void enableTdls(String remoteAddress, boolean enable) { 1278 if (remoteAddress == null) { 1279 throw new IllegalArgumentException("remoteAddress cannot be null"); 1280 } 1281 1282 TdlsTaskParams params = new TdlsTaskParams(); 1283 params.remoteIpAddress = remoteAddress; 1284 params.enable = enable; 1285 new TdlsTask().execute(params); 1286 } 1287 1288 1289 @Override 1290 public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) { 1291 if (remoteMacAddress == null) { 1292 throw new IllegalArgumentException("remoteMacAddress cannot be null"); 1293 } 1294 1295 mWifiStateMachine.enableTdls(remoteMacAddress, enable); 1296 } 1297 1298 /** 1299 * Get a reference to handler. This is used by a client to establish 1300 * an AsyncChannel communication with WifiService 1301 */ 1302 @Override 1303 public Messenger getWifiServiceMessenger() { 1304 enforceAccessPermission(); 1305 enforceChangePermission(); 1306 return new Messenger(mClientHandler); 1307 } 1308 1309 /** 1310 * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer 1311 */ 1312 @Override 1313 public void disableEphemeralNetwork(String SSID) { 1314 enforceAccessPermission(); 1315 enforceChangePermission(); 1316 mWifiStateMachine.disableEphemeralNetwork(SSID); 1317 } 1318 1319 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 1320 @Override 1321 public void onReceive(Context context, Intent intent) { 1322 String action = intent.getAction(); 1323 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1324 mWifiController.sendMessage(CMD_SCREEN_ON); 1325 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 1326 mWifiController.sendMessage(CMD_USER_PRESENT); 1327 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1328 mWifiController.sendMessage(CMD_SCREEN_OFF); 1329 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 1330 int pluggedType = intent.getIntExtra("plugged", 0); 1331 mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null); 1332 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { 1333 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 1334 BluetoothAdapter.STATE_DISCONNECTED); 1335 mWifiStateMachine.sendBluetoothAdapterStateChange(state); 1336 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 1337 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false); 1338 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0); 1339 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) { 1340 boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false); 1341 mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0); 1342 } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) { 1343 handleIdleModeChanged(); 1344 } 1345 } 1346 }; 1347 1348 private boolean startConsentUiIfNeeded(String packageName, 1349 int callingUid, String intentAction) throws RemoteException { 1350 if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) { 1351 return false; 1352 } 1353 try { 1354 // Validate the package only if we are going to use it 1355 ApplicationInfo applicationInfo = mContext.getPackageManager() 1356 .getApplicationInfoAsUser(packageName, 1357 PackageManager.MATCH_DEBUG_TRIAGED_MISSING, 1358 UserHandle.getUserId(callingUid)); 1359 if (applicationInfo.uid != callingUid) { 1360 throw new SecurityException("Package " + callingUid 1361 + " not in uid " + callingUid); 1362 } 1363 1364 // Legacy apps in permission review mode trigger a user prompt 1365 if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { 1366 Intent intent = new Intent(intentAction); 1367 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 1368 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 1369 intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName); 1370 mContext.startActivity(intent); 1371 return true; 1372 } 1373 } catch (PackageManager.NameNotFoundException e) { 1374 throw new RemoteException(e.getMessage()); 1375 } 1376 return false; 1377 } 1378 1379 /** 1380 * Observes settings changes to scan always mode. 1381 */ 1382 private void registerForScanModeChange() { 1383 ContentObserver contentObserver = new ContentObserver(null) { 1384 @Override 1385 public void onChange(boolean selfChange) { 1386 mSettingsStore.handleWifiScanAlwaysAvailableToggled(); 1387 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED); 1388 } 1389 }; 1390 1391 mContext.getContentResolver().registerContentObserver( 1392 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE), 1393 false, contentObserver); 1394 } 1395 1396 private void registerForBroadcasts() { 1397 IntentFilter intentFilter = new IntentFilter(); 1398 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 1399 intentFilter.addAction(Intent.ACTION_USER_PRESENT); 1400 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 1401 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 1402 intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1403 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 1404 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 1405 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); 1406 1407 boolean trackEmergencyCallState = mContext.getResources().getBoolean( 1408 com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call); 1409 if (trackEmergencyCallState) { 1410 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED); 1411 } 1412 1413 mContext.registerReceiver(mReceiver, intentFilter); 1414 } 1415 1416 private void registerForPackageOrUserRemoval() { 1417 IntentFilter intentFilter = new IntentFilter(); 1418 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 1419 intentFilter.addAction(Intent.ACTION_USER_REMOVED); 1420 mContext.registerReceiverAsUser(new BroadcastReceiver() { 1421 @Override 1422 public void onReceive(Context context, Intent intent) { 1423 switch (intent.getAction()) { 1424 case Intent.ACTION_PACKAGE_REMOVED: { 1425 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 1426 return; 1427 } 1428 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); 1429 Uri uri = intent.getData(); 1430 if (uid == -1 || uri == null) { 1431 return; 1432 } 1433 String pkgName = uri.getSchemeSpecificPart(); 1434 mWifiStateMachine.removeAppConfigs(pkgName, uid); 1435 break; 1436 } 1437 case Intent.ACTION_USER_REMOVED: { 1438 int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); 1439 mWifiStateMachine.removeUserConfigs(userHandle); 1440 break; 1441 } 1442 } 1443 } 1444 }, UserHandle.ALL, intentFilter, null, null); 1445 } 1446 1447 @Override 1448 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1449 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1450 != PackageManager.PERMISSION_GRANTED) { 1451 pw.println("Permission Denial: can't dump WifiService from from pid=" 1452 + Binder.getCallingPid() 1453 + ", uid=" + Binder.getCallingUid()); 1454 return; 1455 } 1456 if (args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) { 1457 // WifiMetrics proto bytes were requested. Dump only these. 1458 mWifiStateMachine.updateWifiMetrics(); 1459 mWifiMetrics.dump(fd, pw, args); 1460 } else if (args.length > 0 && IpManager.DUMP_ARG.equals(args[0])) { 1461 // IpManager dump was requested. Pass it along and take no further action. 1462 String[] ipManagerArgs = new String[args.length - 1]; 1463 System.arraycopy(args, 1, ipManagerArgs, 0, ipManagerArgs.length); 1464 mWifiStateMachine.dumpIpManager(fd, pw, ipManagerArgs); 1465 } else if (args.length > 0 && DUMP_ARG_SET_IPREACH_DISCONNECT.equals(args[0])) { 1466 if (args.length > 1) { 1467 if (DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED.equals(args[1])) { 1468 mWifiStateMachine.setIpReachabilityDisconnectEnabled(true); 1469 } else if (DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED.equals(args[1])) { 1470 mWifiStateMachine.setIpReachabilityDisconnectEnabled(false); 1471 } 1472 } 1473 pw.println("IPREACH_DISCONNECT state is " 1474 + mWifiStateMachine.getIpReachabilityDisconnectEnabled()); 1475 return; 1476 } else { 1477 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName()); 1478 pw.println("Stay-awake conditions: " + 1479 Settings.Global.getInt(mContext.getContentResolver(), 1480 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); 1481 pw.println("mInIdleMode " + mInIdleMode); 1482 pw.println("mScanPending " + mScanPending); 1483 mWifiController.dump(fd, pw, args); 1484 mSettingsStore.dump(fd, pw, args); 1485 mNotificationController.dump(fd, pw, args); 1486 mWifiWakeupController.dump(fd, pw, args); 1487 mTrafficPoller.dump(fd, pw, args); 1488 pw.println(); 1489 pw.println("Locks held:"); 1490 mWifiLockManager.dump(pw); 1491 pw.println(); 1492 mWifiMulticastLockManager.dump(pw); 1493 pw.println(); 1494 mWifiStateMachine.dump(fd, pw, args); 1495 pw.println(); 1496 mWifiBackupRestore.dump(fd, pw, args); 1497 pw.println(); 1498 } 1499 } 1500 1501 @Override 1502 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { 1503 if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) { 1504 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1505 return true; 1506 } 1507 return false; 1508 } 1509 1510 @Override 1511 public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) { 1512 mWifiLockManager.updateWifiLockWorkSource(binder, ws); 1513 } 1514 1515 @Override 1516 public boolean releaseWifiLock(IBinder binder) { 1517 if (mWifiLockManager.releaseWifiLock(binder)) { 1518 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1519 return true; 1520 } 1521 return false; 1522 } 1523 1524 @Override 1525 public void initializeMulticastFiltering() { 1526 enforceMulticastChangePermission(); 1527 mWifiMulticastLockManager.initializeFiltering(); 1528 } 1529 1530 @Override 1531 public void acquireMulticastLock(IBinder binder, String tag) { 1532 enforceMulticastChangePermission(); 1533 mWifiMulticastLockManager.acquireLock(binder, tag); 1534 } 1535 1536 @Override 1537 public void releaseMulticastLock() { 1538 enforceMulticastChangePermission(); 1539 mWifiMulticastLockManager.releaseLock(); 1540 } 1541 1542 @Override 1543 public boolean isMulticastEnabled() { 1544 enforceAccessPermission(); 1545 return mWifiMulticastLockManager.isMulticastEnabled(); 1546 } 1547 1548 @Override 1549 public void enableVerboseLogging(int verbose) { 1550 enforceAccessPermission(); 1551 mFacade.setIntegerSetting( 1552 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose); 1553 enableVerboseLoggingInternal(verbose); 1554 } 1555 1556 private void enableVerboseLoggingInternal(int verbose) { 1557 mWifiStateMachine.enableVerboseLogging(verbose); 1558 mWifiLockManager.enableVerboseLogging(verbose); 1559 mWifiMulticastLockManager.enableVerboseLogging(verbose); 1560 mWifiInjector.getWifiLastResortWatchdog().enableVerboseLogging(verbose); 1561 mWifiInjector.getWifiBackupRestore().enableVerboseLogging(verbose); 1562 } 1563 1564 @Override 1565 public int getVerboseLoggingLevel() { 1566 enforceAccessPermission(); 1567 return mFacade.getIntegerSetting( 1568 mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0); 1569 } 1570 1571 @Override 1572 public void enableAggressiveHandover(int enabled) { 1573 enforceAccessPermission(); 1574 mWifiStateMachine.enableAggressiveHandover(enabled); 1575 } 1576 1577 @Override 1578 public int getAggressiveHandover() { 1579 enforceAccessPermission(); 1580 return mWifiStateMachine.getAggressiveHandover(); 1581 } 1582 1583 @Override 1584 public void setAllowScansWithTraffic(int enabled) { 1585 enforceAccessPermission(); 1586 mWifiStateMachine.setAllowScansWithTraffic(enabled); 1587 } 1588 1589 @Override 1590 public int getAllowScansWithTraffic() { 1591 enforceAccessPermission(); 1592 return mWifiStateMachine.getAllowScansWithTraffic(); 1593 } 1594 1595 @Override 1596 public boolean setEnableAutoJoinWhenAssociated(boolean enabled) { 1597 enforceChangePermission(); 1598 return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled); 1599 } 1600 1601 @Override 1602 public boolean getEnableAutoJoinWhenAssociated() { 1603 enforceAccessPermission(); 1604 return mWifiStateMachine.getEnableAutoJoinWhenAssociated(); 1605 } 1606 1607 /* Return the Wifi Connection statistics object */ 1608 @Override 1609 public WifiConnectionStatistics getConnectionStatistics() { 1610 enforceAccessPermission(); 1611 enforceReadCredentialPermission(); 1612 if (mWifiStateMachineChannel != null) { 1613 return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel); 1614 } else { 1615 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 1616 return null; 1617 } 1618 } 1619 1620 @Override 1621 public void factoryReset() { 1622 enforceConnectivityInternalPermission(); 1623 1624 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) { 1625 return; 1626 } 1627 1628 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) { 1629 // Turn mobile hotspot off 1630 setWifiApEnabled(null, false); 1631 } 1632 1633 if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) { 1634 // Enable wifi 1635 try { 1636 setWifiEnabled(mContext.getOpPackageName(), true); 1637 } catch (RemoteException e) { 1638 /* ignore - local call */ 1639 } 1640 // Delete all Wifi SSIDs 1641 List<WifiConfiguration> networks = getConfiguredNetworks(); 1642 if (networks != null) { 1643 for (WifiConfiguration config : networks) { 1644 removeNetwork(config.networkId); 1645 } 1646 saveConfiguration(); 1647 } 1648 } 1649 } 1650 1651 /* private methods */ 1652 static boolean logAndReturnFalse(String s) { 1653 Log.d(TAG, s); 1654 return false; 1655 } 1656 1657 public static boolean isValid(WifiConfiguration config) { 1658 String validity = checkValidity(config); 1659 return validity == null || logAndReturnFalse(validity); 1660 } 1661 1662 public static boolean isValidPasspoint(WifiConfiguration config) { 1663 String validity = checkPasspointValidity(config); 1664 return validity == null || logAndReturnFalse(validity); 1665 } 1666 1667 public static String checkValidity(WifiConfiguration config) { 1668 if (config.allowedKeyManagement == null) 1669 return "allowed kmgmt"; 1670 1671 if (config.allowedKeyManagement.cardinality() > 1) { 1672 if (config.allowedKeyManagement.cardinality() != 2) { 1673 return "cardinality != 2"; 1674 } 1675 if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) { 1676 return "not WPA_EAP"; 1677 } 1678 if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) 1679 && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) { 1680 return "not PSK or 8021X"; 1681 } 1682 } 1683 return null; 1684 } 1685 1686 public static String checkPasspointValidity(WifiConfiguration config) { 1687 if (!TextUtils.isEmpty(config.FQDN)) { 1688 /* this is passpoint configuration; it must not have an SSID */ 1689 if (!TextUtils.isEmpty(config.SSID)) { 1690 return "SSID not expected for Passpoint: '" + config.SSID + 1691 "' FQDN " + toHexString(config.FQDN); 1692 } 1693 /* this is passpoint configuration; it must have a providerFriendlyName */ 1694 if (TextUtils.isEmpty(config.providerFriendlyName)) { 1695 return "no provider friendly name"; 1696 } 1697 WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig; 1698 /* this is passpoint configuration; it must have enterprise config */ 1699 if (enterpriseConfig == null 1700 || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) { 1701 return "no enterprise config"; 1702 } 1703 if ((enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS || 1704 enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS || 1705 enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) && 1706 enterpriseConfig.getCaCertificate() == null) { 1707 return "no CA certificate"; 1708 } 1709 } 1710 return null; 1711 } 1712 1713 @Override 1714 public Network getCurrentNetwork() { 1715 enforceAccessPermission(); 1716 return mWifiStateMachine.getCurrentNetwork(); 1717 } 1718 1719 public static String toHexString(String s) { 1720 if (s == null) { 1721 return "null"; 1722 } 1723 StringBuilder sb = new StringBuilder(); 1724 sb.append('\'').append(s).append('\''); 1725 for (int n = 0; n < s.length(); n++) { 1726 sb.append(String.format(" %02x", s.charAt(n) & 0xffff)); 1727 } 1728 return sb.toString(); 1729 } 1730 1731 public void hideCertFromUnaffiliatedUsers(String alias) { 1732 mCertManager.hideCertFromUnaffiliatedUsers(alias); 1733 } 1734 1735 public String[] listClientCertsForCurrentUser() { 1736 return mCertManager.listClientCertsForCurrentUser(); 1737 } 1738 1739 /** 1740 * Enable/disable WifiConnectivityManager at runtime 1741 * 1742 * @param enabled true-enable; false-disable 1743 */ 1744 @Override 1745 public void enableWifiConnectivityManager(boolean enabled) { 1746 enforceConnectivityInternalPermission(); 1747 mWifiStateMachine.enableWifiConnectivityManager(enabled); 1748 } 1749 1750 /** 1751 * Retrieve the data to be backed to save the current state. 1752 * 1753 * @return Raw byte stream of the data to be backed up. 1754 */ 1755 @Override 1756 public byte[] retrieveBackupData() { 1757 enforceReadCredentialPermission(); 1758 enforceAccessPermission(); 1759 if (mWifiStateMachineChannel == null) { 1760 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 1761 return null; 1762 } 1763 1764 Slog.d(TAG, "Retrieving backup data"); 1765 List<WifiConfiguration> wifiConfigurations = 1766 mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel); 1767 byte[] backupData = 1768 mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations); 1769 Slog.d(TAG, "Retrieved backup data"); 1770 return backupData; 1771 } 1772 1773 /** 1774 * Helper method to restore networks retrieved from backup data. 1775 * 1776 * @param configurations list of WifiConfiguration objects parsed from the backup data. 1777 */ 1778 private void restoreNetworks(List<WifiConfiguration> configurations) { 1779 if (configurations == null) { 1780 Slog.e(TAG, "Backup data parse failed"); 1781 return; 1782 } 1783 for (WifiConfiguration configuration : configurations) { 1784 int networkId = mWifiStateMachine.syncAddOrUpdateNetwork( 1785 mWifiStateMachineChannel, configuration); 1786 if (networkId == WifiConfiguration.INVALID_NETWORK_ID) { 1787 Slog.e(TAG, "Restore network failed: " + configuration.configKey()); 1788 continue; 1789 } 1790 // Enable all networks restored. 1791 mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false); 1792 } 1793 } 1794 1795 /** 1796 * Restore state from the backed up data. 1797 * 1798 * @param data Raw byte stream of the backed up data. 1799 */ 1800 @Override 1801 public void restoreBackupData(byte[] data) { 1802 enforceChangePermission(); 1803 if (mWifiStateMachineChannel == null) { 1804 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 1805 return; 1806 } 1807 1808 Slog.d(TAG, "Restoring backup data"); 1809 List<WifiConfiguration> wifiConfigurations = 1810 mWifiBackupRestore.retrieveConfigurationsFromBackupData(data); 1811 restoreNetworks(wifiConfigurations); 1812 Slog.d(TAG, "Restored backup data"); 1813 } 1814 1815 /** 1816 * Restore state from the older supplicant back up data. 1817 * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file. 1818 * 1819 * @param supplicantData Raw byte stream of wpa_supplicant.conf 1820 * @param ipConfigData Raw byte stream of ipconfig.txt 1821 */ 1822 public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) { 1823 enforceChangePermission(); 1824 if (mWifiStateMachineChannel == null) { 1825 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 1826 return; 1827 } 1828 1829 Slog.d(TAG, "Restoring supplicant backup data"); 1830 List<WifiConfiguration> wifiConfigurations = 1831 mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData( 1832 supplicantData, ipConfigData); 1833 restoreNetworks(wifiConfigurations); 1834 Slog.d(TAG, "Restored supplicant backup data"); 1835 } 1836} 1837