1 /* 2 * Copyright (C) 2008 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; 18 19 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED; 20 import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 21 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 22 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 23 import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN; 24 25 import android.app.AlarmManager; 26 import android.app.PendingIntent; 27 import android.bluetooth.BluetoothA2dp; 28 import android.content.BroadcastReceiver; 29 import android.content.ContentResolver; 30 import android.content.Context; 31 import android.content.Intent; 32 import android.content.IntentFilter; 33 import android.content.pm.PackageManager; 34 import android.net.wifi.IWifiManager; 35 import android.net.wifi.WifiInfo; 36 import android.net.wifi.WifiManager; 37 import android.net.wifi.WifiNative; 38 import android.net.wifi.WifiStateTracker; 39 import android.net.wifi.ScanResult; 40 import android.net.wifi.WifiConfiguration; 41 import android.net.wifi.SupplicantState; 42 import android.net.NetworkStateTracker; 43 import android.net.DhcpInfo; 44 import android.net.NetworkUtils; 45 import android.os.Binder; 46 import android.os.Handler; 47 import android.os.HandlerThread; 48 import android.os.IBinder; 49 import android.os.Looper; 50 import android.os.Message; 51 import android.os.PowerManager; 52 import android.os.Process; 53 import android.os.RemoteException; 54 import android.os.ServiceManager; 55 import android.provider.Settings; 56 import android.util.Log; 57 import android.text.TextUtils; 58 59 import java.util.ArrayList; 60 import java.util.BitSet; 61 import java.util.HashMap; 62 import java.util.LinkedHashMap; 63 import java.util.List; 64 import java.util.Map; 65 import java.util.regex.Pattern; 66 import java.io.FileDescriptor; 67 import java.io.PrintWriter; 68 69 import com.android.internal.app.IBatteryStats; 70 import android.backup.IBackupManager; 71 import com.android.server.am.BatteryStatsService; 72 73 /** 74 * WifiService handles remote WiFi operation requests by implementing 75 * the IWifiManager interface. It also creates a WifiMonitor to listen 76 * for Wifi-related events. 77 * 78 * @hide 79 */ 80 public class WifiService extends IWifiManager.Stub { 81 private static final String TAG = "WifiService"; 82 private static final boolean DBG = false; 83 private static final Pattern scanResultPattern = Pattern.compile("\t+"); 84 private final WifiStateTracker mWifiStateTracker; 85 86 private Context mContext; 87 private int mWifiState; 88 89 private AlarmManager mAlarmManager; 90 private PendingIntent mIdleIntent; 91 private static final int IDLE_REQUEST = 0; 92 private boolean mScreenOff; 93 private boolean mDeviceIdle; 94 private int mPluggedType; 95 96 // true if the user enabled Wifi while in airplane mode 97 private boolean mAirplaneModeOverwridden; 98 99 private final LockList mLocks = new LockList(); 100 // some wifi lock statistics 101 private int mFullLocksAcquired; 102 private int mFullLocksReleased; 103 private int mScanLocksAcquired; 104 private int mScanLocksReleased; 105 106 private final List<Multicaster> mMulticasters = 107 new ArrayList<Multicaster>(); 108 private int mMulticastEnabled; 109 private int mMulticastDisabled; 110 111 private final IBatteryStats mBatteryStats; 112 113 /** 114 * See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a 115 * Settings.Gservices value is not present. This timeout value is chosen as 116 * the approximate point at which the battery drain caused by Wi-Fi 117 * being enabled but not active exceeds the battery drain caused by 118 * re-establishing a connection to the mobile data network. 119 */ 120 private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */ 121 122 private static final String WAKELOCK_TAG = "WifiService"; 123 124 /** 125 * The maximum amount of time to hold the wake lock after a disconnect 126 * caused by stopping the driver. Establishing an EDGE connection has been 127 * observed to take about 5 seconds under normal circumstances. This 128 * provides a bit of extra margin. 129 * <p> 130 * See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}. 131 * This is the default value if a Settings.Secure value is not present. 132 */ 133 private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000; 134 135 // Wake lock used by driver-stop operation 136 private static PowerManager.WakeLock sDriverStopWakeLock; 137 // Wake lock used by other operations 138 private static PowerManager.WakeLock sWakeLock; 139 140 private static final int MESSAGE_ENABLE_WIFI = 0; 141 private static final int MESSAGE_DISABLE_WIFI = 1; 142 private static final int MESSAGE_STOP_WIFI = 2; 143 private static final int MESSAGE_START_WIFI = 3; 144 private static final int MESSAGE_RELEASE_WAKELOCK = 4; 145 146 private final WifiHandler mWifiHandler; 147 148 /* 149 * Cache of scan results objects (size is somewhat arbitrary) 150 */ 151 private static final int SCAN_RESULT_CACHE_SIZE = 80; 152 private final LinkedHashMap<String, ScanResult> mScanResultCache; 153 154 /* 155 * Character buffer used to parse scan results (optimization) 156 */ 157 private static final int SCAN_RESULT_BUFFER_SIZE = 512; 158 private boolean mNeedReconfig; 159 160 /* 161 * Last UID that asked to enable WIFI. 162 */ 163 private int mLastEnableUid = Process.myUid(); 164 165 /** 166 * Number of allowed radio frequency channels in various regulatory domains. 167 * This list is sufficient for 802.11b/g networks (2.4GHz range). 168 */ 169 private static int[] sValidRegulatoryChannelCounts = new int[] {11, 13, 14}; 170 171 private static final String ACTION_DEVICE_IDLE = 172 "com.android.server.WifiManager.action.DEVICE_IDLE"; 173 WifiService(Context context, WifiStateTracker tracker)174 WifiService(Context context, WifiStateTracker tracker) { 175 mContext = context; 176 mWifiStateTracker = tracker; 177 mWifiStateTracker.enableRssiPolling(true); 178 mBatteryStats = BatteryStatsService.getService(); 179 180 mScanResultCache = new LinkedHashMap<String, ScanResult>( 181 SCAN_RESULT_CACHE_SIZE, 0.75f, true) { 182 /* 183 * Limit the cache size by SCAN_RESULT_CACHE_SIZE 184 * elements 185 */ 186 public boolean removeEldestEntry(Map.Entry eldest) { 187 return SCAN_RESULT_CACHE_SIZE < this.size(); 188 } 189 }; 190 191 HandlerThread wifiThread = new HandlerThread("WifiService"); 192 wifiThread.start(); 193 mWifiHandler = new WifiHandler(wifiThread.getLooper()); 194 195 mWifiState = WIFI_STATE_DISABLED; 196 boolean wifiEnabled = getPersistedWifiEnabled(); 197 198 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 199 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); 200 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); 201 202 PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 203 sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); 204 sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); 205 mWifiStateTracker.setReleaseWakeLockCallback( 206 new Runnable() { 207 public void run() { 208 mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK); 209 synchronized (sDriverStopWakeLock) { 210 if (sDriverStopWakeLock.isHeld()) { 211 sDriverStopWakeLock.release(); 212 } 213 } 214 } 215 } 216 ); 217 218 Log.i(TAG, "WifiService starting up with Wi-Fi " + 219 (wifiEnabled ? "enabled" : "disabled")); 220 221 mContext.registerReceiver( 222 new BroadcastReceiver() { 223 @Override 224 public void onReceive(Context context, Intent intent) { 225 // clear our flag indicating the user has overwridden airplane mode 226 mAirplaneModeOverwridden = false; 227 updateWifiState(); 228 } 229 }, 230 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 231 232 setWifiEnabledBlocking(wifiEnabled, false, Process.myUid()); 233 } 234 getPersistedWifiEnabled()235 private boolean getPersistedWifiEnabled() { 236 final ContentResolver cr = mContext.getContentResolver(); 237 try { 238 return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1; 239 } catch (Settings.SettingNotFoundException e) { 240 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0); 241 return false; 242 } 243 } 244 persistWifiEnabled(boolean enabled)245 private void persistWifiEnabled(boolean enabled) { 246 final ContentResolver cr = mContext.getContentResolver(); 247 Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0); 248 } 249 getNetworkStateTracker()250 NetworkStateTracker getNetworkStateTracker() { 251 return mWifiStateTracker; 252 } 253 254 /** 255 * see {@link android.net.wifi.WifiManager#pingSupplicant()} 256 * @return {@code true} if the operation succeeds 257 */ pingSupplicant()258 public boolean pingSupplicant() { 259 enforceChangePermission(); 260 synchronized (mWifiStateTracker) { 261 return WifiNative.pingCommand(); 262 } 263 } 264 265 /** 266 * see {@link android.net.wifi.WifiManager#startScan()} 267 * @return {@code true} if the operation succeeds 268 */ startScan(boolean forceActive)269 public boolean startScan(boolean forceActive) { 270 enforceChangePermission(); 271 synchronized (mWifiStateTracker) { 272 switch (mWifiStateTracker.getSupplicantState()) { 273 case DISCONNECTED: 274 case INACTIVE: 275 case SCANNING: 276 case DORMANT: 277 break; 278 default: 279 WifiNative.setScanResultHandlingCommand( 280 WifiStateTracker.SUPPL_SCAN_HANDLING_LIST_ONLY); 281 break; 282 } 283 return WifiNative.scanCommand(forceActive); 284 } 285 } 286 287 /** 288 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 289 * @param enable {@code true} to enable, {@code false} to disable. 290 * @return {@code true} if the enable/disable operation was 291 * started or is already in the queue. 292 */ setWifiEnabled(boolean enable)293 public boolean setWifiEnabled(boolean enable) { 294 enforceChangePermission(); 295 if (mWifiHandler == null) return false; 296 297 synchronized (mWifiHandler) { 298 // caller may not have WAKE_LOCK permission - it's not required here 299 long ident = Binder.clearCallingIdentity(); 300 sWakeLock.acquire(); 301 Binder.restoreCallingIdentity(ident); 302 303 mLastEnableUid = Binder.getCallingUid(); 304 // set a flag if the user is enabling Wifi while in airplane mode 305 mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable()); 306 sendEnableMessage(enable, true, Binder.getCallingUid()); 307 } 308 309 return true; 310 } 311 312 /** 313 * Enables/disables Wi-Fi synchronously. 314 * @param enable {@code true} to turn Wi-Fi on, {@code false} to turn it off. 315 * @param persist {@code true} if the setting should be persisted. 316 * @param uid The UID of the process making the request. 317 * @return {@code true} if the operation succeeds (or if the existing state 318 * is the same as the requested state) 319 */ setWifiEnabledBlocking(boolean enable, boolean persist, int uid)320 private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) { 321 final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED; 322 323 if (mWifiState == eventualWifiState) { 324 return true; 325 } 326 if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) { 327 return false; 328 } 329 330 setWifiEnabledState(enable ? WIFI_STATE_ENABLING : WIFI_STATE_DISABLING, uid); 331 332 if (enable) { 333 if (!WifiNative.loadDriver()) { 334 Log.e(TAG, "Failed to load Wi-Fi driver."); 335 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid); 336 return false; 337 } 338 if (!WifiNative.startSupplicant()) { 339 WifiNative.unloadDriver(); 340 Log.e(TAG, "Failed to start supplicant daemon."); 341 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid); 342 return false; 343 } 344 registerForBroadcasts(); 345 mWifiStateTracker.startEventLoop(); 346 } else { 347 348 mContext.unregisterReceiver(mReceiver); 349 // Remove notification (it will no-op if it isn't visible) 350 mWifiStateTracker.setNotificationVisible(false, 0, false, 0); 351 352 boolean failedToStopSupplicantOrUnloadDriver = false; 353 if (!WifiNative.stopSupplicant()) { 354 Log.e(TAG, "Failed to stop supplicant daemon."); 355 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid); 356 failedToStopSupplicantOrUnloadDriver = true; 357 } 358 359 // We must reset the interface before we unload the driver 360 mWifiStateTracker.resetInterface(false); 361 362 if (!WifiNative.unloadDriver()) { 363 Log.e(TAG, "Failed to unload Wi-Fi driver."); 364 if (!failedToStopSupplicantOrUnloadDriver) { 365 setWifiEnabledState(WIFI_STATE_UNKNOWN, uid); 366 failedToStopSupplicantOrUnloadDriver = true; 367 } 368 } 369 if (failedToStopSupplicantOrUnloadDriver) { 370 return false; 371 } 372 } 373 374 // Success! 375 376 if (persist) { 377 persistWifiEnabled(enable); 378 } 379 setWifiEnabledState(eventualWifiState, uid); 380 381 return true; 382 } 383 setWifiEnabledState(int wifiState, int uid)384 private void setWifiEnabledState(int wifiState, int uid) { 385 final int previousWifiState = mWifiState; 386 387 long ident = Binder.clearCallingIdentity(); 388 try { 389 if (wifiState == WIFI_STATE_ENABLED) { 390 mBatteryStats.noteWifiOn(uid); 391 } else if (wifiState == WIFI_STATE_DISABLED) { 392 mBatteryStats.noteWifiOff(uid); 393 } 394 } catch (RemoteException e) { 395 } finally { 396 Binder.restoreCallingIdentity(ident); 397 } 398 399 // Update state 400 mWifiState = wifiState; 401 402 // Broadcast 403 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 404 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 405 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, wifiState); 406 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, previousWifiState); 407 mContext.sendStickyBroadcast(intent); 408 } 409 enforceAccessPermission()410 private void enforceAccessPermission() { 411 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 412 "WifiService"); 413 } 414 enforceChangePermission()415 private void enforceChangePermission() { 416 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 417 "WifiService"); 418 419 } 420 enforceMulticastChangePermission()421 private void enforceMulticastChangePermission() { 422 mContext.enforceCallingOrSelfPermission( 423 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 424 "WifiService"); 425 } 426 427 /** 428 * see {@link WifiManager#getWifiState()} 429 * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, 430 * {@link WifiManager#WIFI_STATE_DISABLING}, 431 * {@link WifiManager#WIFI_STATE_ENABLED}, 432 * {@link WifiManager#WIFI_STATE_ENABLING}, 433 * {@link WifiManager#WIFI_STATE_UNKNOWN} 434 */ getWifiEnabledState()435 public int getWifiEnabledState() { 436 enforceAccessPermission(); 437 return mWifiState; 438 } 439 440 /** 441 * see {@link android.net.wifi.WifiManager#disconnect()} 442 * @return {@code true} if the operation succeeds 443 */ disconnect()444 public boolean disconnect() { 445 enforceChangePermission(); 446 synchronized (mWifiStateTracker) { 447 return WifiNative.disconnectCommand(); 448 } 449 } 450 451 /** 452 * see {@link android.net.wifi.WifiManager#reconnect()} 453 * @return {@code true} if the operation succeeds 454 */ reconnect()455 public boolean reconnect() { 456 enforceChangePermission(); 457 synchronized (mWifiStateTracker) { 458 return WifiNative.reconnectCommand(); 459 } 460 } 461 462 /** 463 * see {@link android.net.wifi.WifiManager#reassociate()} 464 * @return {@code true} if the operation succeeds 465 */ reassociate()466 public boolean reassociate() { 467 enforceChangePermission(); 468 synchronized (mWifiStateTracker) { 469 return WifiNative.reassociateCommand(); 470 } 471 } 472 473 /** 474 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 475 * @return the list of configured networks 476 */ getConfiguredNetworks()477 public List<WifiConfiguration> getConfiguredNetworks() { 478 enforceAccessPermission(); 479 String listStr; 480 /* 481 * We don't cache the list, because we want to allow 482 * for the possibility that the configuration file 483 * has been modified through some external means, 484 * such as the wpa_cli command line program. 485 */ 486 synchronized (mWifiStateTracker) { 487 listStr = WifiNative.listNetworksCommand(); 488 } 489 List<WifiConfiguration> networks = 490 new ArrayList<WifiConfiguration>(); 491 if (listStr == null) 492 return networks; 493 494 String[] lines = listStr.split("\n"); 495 // Skip the first line, which is a header 496 for (int i = 1; i < lines.length; i++) { 497 String[] result = lines[i].split("\t"); 498 // network-id | ssid | bssid | flags 499 WifiConfiguration config = new WifiConfiguration(); 500 try { 501 config.networkId = Integer.parseInt(result[0]); 502 } catch(NumberFormatException e) { 503 continue; 504 } 505 if (result.length > 3) { 506 if (result[3].indexOf("[CURRENT]") != -1) 507 config.status = WifiConfiguration.Status.CURRENT; 508 else if (result[3].indexOf("[DISABLED]") != -1) 509 config.status = WifiConfiguration.Status.DISABLED; 510 else 511 config.status = WifiConfiguration.Status.ENABLED; 512 } else 513 config.status = WifiConfiguration.Status.ENABLED; 514 synchronized (mWifiStateTracker) { 515 readNetworkVariables(config); 516 } 517 networks.add(config); 518 } 519 520 return networks; 521 } 522 523 /** 524 * Read the variables from the supplicant daemon that are needed to 525 * fill in the WifiConfiguration object. 526 * <p/> 527 * The caller must hold the synchronization monitor. 528 * @param config the {@link WifiConfiguration} object to be filled in. 529 */ readNetworkVariables(WifiConfiguration config)530 private static void readNetworkVariables(WifiConfiguration config) { 531 532 int netId = config.networkId; 533 if (netId < 0) 534 return; 535 536 /* 537 * TODO: maybe should have a native method that takes an array of 538 * variable names and returns an array of values. But we'd still 539 * be doing a round trip to the supplicant daemon for each variable. 540 */ 541 String value; 542 543 value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.ssidVarName); 544 if (!TextUtils.isEmpty(value)) { 545 config.SSID = value; 546 } else { 547 config.SSID = null; 548 } 549 550 value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.bssidVarName); 551 if (!TextUtils.isEmpty(value)) { 552 config.BSSID = value; 553 } else { 554 config.BSSID = null; 555 } 556 557 value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName); 558 config.priority = -1; 559 if (!TextUtils.isEmpty(value)) { 560 try { 561 config.priority = Integer.parseInt(value); 562 } catch (NumberFormatException ignore) { 563 } 564 } 565 566 value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.hiddenSSIDVarName); 567 config.hiddenSSID = false; 568 if (!TextUtils.isEmpty(value)) { 569 try { 570 config.hiddenSSID = Integer.parseInt(value) != 0; 571 } catch (NumberFormatException ignore) { 572 } 573 } 574 575 value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepTxKeyIdxVarName); 576 config.wepTxKeyIndex = -1; 577 if (!TextUtils.isEmpty(value)) { 578 try { 579 config.wepTxKeyIndex = Integer.parseInt(value); 580 } catch (NumberFormatException ignore) { 581 } 582 } 583 584 /* 585 * Get up to 4 WEP keys. Note that the actual keys are not passed back, 586 * just a "*" if the key is set, or the null string otherwise. 587 */ 588 for (int i = 0; i < 4; i++) { 589 value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.wepKeyVarNames[i]); 590 if (!TextUtils.isEmpty(value)) { 591 config.wepKeys[i] = value; 592 } else { 593 config.wepKeys[i] = null; 594 } 595 } 596 597 /* 598 * Get the private shared key. Note that the actual keys are not passed back, 599 * just a "*" if the key is set, or the null string otherwise. 600 */ 601 value = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.pskVarName); 602 if (!TextUtils.isEmpty(value)) { 603 config.preSharedKey = value; 604 } else { 605 config.preSharedKey = null; 606 } 607 608 value = WifiNative.getNetworkVariableCommand(config.networkId, 609 WifiConfiguration.Protocol.varName); 610 if (!TextUtils.isEmpty(value)) { 611 String vals[] = value.split(" "); 612 for (String val : vals) { 613 int index = 614 lookupString(val, WifiConfiguration.Protocol.strings); 615 if (0 <= index) { 616 config.allowedProtocols.set(index); 617 } 618 } 619 } 620 621 value = WifiNative.getNetworkVariableCommand(config.networkId, 622 WifiConfiguration.KeyMgmt.varName); 623 if (!TextUtils.isEmpty(value)) { 624 String vals[] = value.split(" "); 625 for (String val : vals) { 626 int index = 627 lookupString(val, WifiConfiguration.KeyMgmt.strings); 628 if (0 <= index) { 629 config.allowedKeyManagement.set(index); 630 } 631 } 632 } 633 634 value = WifiNative.getNetworkVariableCommand(config.networkId, 635 WifiConfiguration.AuthAlgorithm.varName); 636 if (!TextUtils.isEmpty(value)) { 637 String vals[] = value.split(" "); 638 for (String val : vals) { 639 int index = 640 lookupString(val, WifiConfiguration.AuthAlgorithm.strings); 641 if (0 <= index) { 642 config.allowedAuthAlgorithms.set(index); 643 } 644 } 645 } 646 647 value = WifiNative.getNetworkVariableCommand(config.networkId, 648 WifiConfiguration.PairwiseCipher.varName); 649 if (!TextUtils.isEmpty(value)) { 650 String vals[] = value.split(" "); 651 for (String val : vals) { 652 int index = 653 lookupString(val, WifiConfiguration.PairwiseCipher.strings); 654 if (0 <= index) { 655 config.allowedPairwiseCiphers.set(index); 656 } 657 } 658 } 659 660 value = WifiNative.getNetworkVariableCommand(config.networkId, 661 WifiConfiguration.GroupCipher.varName); 662 if (!TextUtils.isEmpty(value)) { 663 String vals[] = value.split(" "); 664 for (String val : vals) { 665 int index = 666 lookupString(val, WifiConfiguration.GroupCipher.strings); 667 if (0 <= index) { 668 config.allowedGroupCiphers.set(index); 669 } 670 } 671 } 672 673 for (WifiConfiguration.EnterpriseField field : 674 config.enterpriseFields) { 675 value = WifiNative.getNetworkVariableCommand(netId, 676 field.varName()); 677 if (!TextUtils.isEmpty(value)) { 678 field.setValue(value); 679 } 680 } 681 } 682 683 /** 684 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 685 * @return the supplicant-assigned identifier for the new or updated 686 * network if the operation succeeds, or {@code -1} if it fails 687 */ addOrUpdateNetwork(WifiConfiguration config)688 public synchronized int addOrUpdateNetwork(WifiConfiguration config) { 689 enforceChangePermission(); 690 /* 691 * If the supplied networkId is -1, we create a new empty 692 * network configuration. Otherwise, the networkId should 693 * refer to an existing configuration. 694 */ 695 int netId = config.networkId; 696 boolean newNetwork = netId == -1; 697 boolean doReconfig; 698 int currentPriority; 699 // networkId of -1 means we want to create a new network 700 if (newNetwork) { 701 netId = WifiNative.addNetworkCommand(); 702 if (netId < 0) { 703 if (DBG) { 704 Log.d(TAG, "Failed to add a network!"); 705 } 706 return -1; 707 } 708 doReconfig = true; 709 } else { 710 String priorityVal = WifiNative.getNetworkVariableCommand(netId, WifiConfiguration.priorityVarName); 711 currentPriority = -1; 712 if (!TextUtils.isEmpty(priorityVal)) { 713 try { 714 currentPriority = Integer.parseInt(priorityVal); 715 } catch (NumberFormatException ignore) { 716 } 717 } 718 doReconfig = currentPriority != config.priority; 719 } 720 mNeedReconfig = mNeedReconfig || doReconfig; 721 722 setVariables: { 723 /* 724 * Note that if a networkId for a non-existent network 725 * was supplied, then the first setNetworkVariableCommand() 726 * will fail, so we don't bother to make a separate check 727 * for the validity of the ID up front. 728 */ 729 730 if (config.SSID != null && 731 !WifiNative.setNetworkVariableCommand( 732 netId, 733 WifiConfiguration.ssidVarName, 734 config.SSID)) { 735 if (DBG) { 736 Log.d(TAG, "failed to set SSID: "+config.SSID); 737 } 738 break setVariables; 739 } 740 741 if (config.BSSID != null && 742 !WifiNative.setNetworkVariableCommand( 743 netId, 744 WifiConfiguration.bssidVarName, 745 config.BSSID)) { 746 if (DBG) { 747 Log.d(TAG, "failed to set BSSID: "+config.BSSID); 748 } 749 break setVariables; 750 } 751 752 String allowedKeyManagementString = 753 makeString(config.allowedKeyManagement, WifiConfiguration.KeyMgmt.strings); 754 if (config.allowedKeyManagement.cardinality() != 0 && 755 !WifiNative.setNetworkVariableCommand( 756 netId, 757 WifiConfiguration.KeyMgmt.varName, 758 allowedKeyManagementString)) { 759 if (DBG) { 760 Log.d(TAG, "failed to set key_mgmt: "+ 761 allowedKeyManagementString); 762 } 763 break setVariables; 764 } 765 766 String allowedProtocolsString = 767 makeString(config.allowedProtocols, WifiConfiguration.Protocol.strings); 768 if (config.allowedProtocols.cardinality() != 0 && 769 !WifiNative.setNetworkVariableCommand( 770 netId, 771 WifiConfiguration.Protocol.varName, 772 allowedProtocolsString)) { 773 if (DBG) { 774 Log.d(TAG, "failed to set proto: "+ 775 allowedProtocolsString); 776 } 777 break setVariables; 778 } 779 780 String allowedAuthAlgorithmsString = 781 makeString(config.allowedAuthAlgorithms, WifiConfiguration.AuthAlgorithm.strings); 782 if (config.allowedAuthAlgorithms.cardinality() != 0 && 783 !WifiNative.setNetworkVariableCommand( 784 netId, 785 WifiConfiguration.AuthAlgorithm.varName, 786 allowedAuthAlgorithmsString)) { 787 if (DBG) { 788 Log.d(TAG, "failed to set auth_alg: "+ 789 allowedAuthAlgorithmsString); 790 } 791 break setVariables; 792 } 793 794 String allowedPairwiseCiphersString = 795 makeString(config.allowedPairwiseCiphers, WifiConfiguration.PairwiseCipher.strings); 796 if (config.allowedPairwiseCiphers.cardinality() != 0 && 797 !WifiNative.setNetworkVariableCommand( 798 netId, 799 WifiConfiguration.PairwiseCipher.varName, 800 allowedPairwiseCiphersString)) { 801 if (DBG) { 802 Log.d(TAG, "failed to set pairwise: "+ 803 allowedPairwiseCiphersString); 804 } 805 break setVariables; 806 } 807 808 String allowedGroupCiphersString = 809 makeString(config.allowedGroupCiphers, WifiConfiguration.GroupCipher.strings); 810 if (config.allowedGroupCiphers.cardinality() != 0 && 811 !WifiNative.setNetworkVariableCommand( 812 netId, 813 WifiConfiguration.GroupCipher.varName, 814 allowedGroupCiphersString)) { 815 if (DBG) { 816 Log.d(TAG, "failed to set group: "+ 817 allowedGroupCiphersString); 818 } 819 break setVariables; 820 } 821 822 // Prevent client screw-up by passing in a WifiConfiguration we gave it 823 // by preventing "*" as a key. 824 if (config.preSharedKey != null && !config.preSharedKey.equals("*") && 825 !WifiNative.setNetworkVariableCommand( 826 netId, 827 WifiConfiguration.pskVarName, 828 config.preSharedKey)) { 829 if (DBG) { 830 Log.d(TAG, "failed to set psk: "+config.preSharedKey); 831 } 832 break setVariables; 833 } 834 835 boolean hasSetKey = false; 836 if (config.wepKeys != null) { 837 for (int i = 0; i < config.wepKeys.length; i++) { 838 // Prevent client screw-up by passing in a WifiConfiguration we gave it 839 // by preventing "*" as a key. 840 if (config.wepKeys[i] != null && !config.wepKeys[i].equals("*")) { 841 if (!WifiNative.setNetworkVariableCommand( 842 netId, 843 WifiConfiguration.wepKeyVarNames[i], 844 config.wepKeys[i])) { 845 if (DBG) { 846 Log.d(TAG, 847 "failed to set wep_key"+i+": " + 848 config.wepKeys[i]); 849 } 850 break setVariables; 851 } 852 hasSetKey = true; 853 } 854 } 855 } 856 857 if (hasSetKey) { 858 if (!WifiNative.setNetworkVariableCommand( 859 netId, 860 WifiConfiguration.wepTxKeyIdxVarName, 861 Integer.toString(config.wepTxKeyIndex))) { 862 if (DBG) { 863 Log.d(TAG, 864 "failed to set wep_tx_keyidx: "+ 865 config.wepTxKeyIndex); 866 } 867 break setVariables; 868 } 869 } 870 871 if (!WifiNative.setNetworkVariableCommand( 872 netId, 873 WifiConfiguration.priorityVarName, 874 Integer.toString(config.priority))) { 875 if (DBG) { 876 Log.d(TAG, config.SSID + ": failed to set priority: " 877 +config.priority); 878 } 879 break setVariables; 880 } 881 882 if (config.hiddenSSID && !WifiNative.setNetworkVariableCommand( 883 netId, 884 WifiConfiguration.hiddenSSIDVarName, 885 Integer.toString(config.hiddenSSID ? 1 : 0))) { 886 if (DBG) { 887 Log.d(TAG, config.SSID + ": failed to set hiddenSSID: "+ 888 config.hiddenSSID); 889 } 890 break setVariables; 891 } 892 893 for (WifiConfiguration.EnterpriseField field 894 : config.enterpriseFields) { 895 String varName = field.varName(); 896 String value = field.value(); 897 if ((value != null) && !WifiNative.setNetworkVariableCommand( 898 netId, 899 varName, 900 value)) { 901 if (DBG) { 902 Log.d(TAG, config.SSID + ": failed to set " + varName + 903 ": " + value); 904 } 905 break setVariables; 906 } 907 } 908 909 return netId; 910 } 911 912 /* 913 * For an update, if one of the setNetworkVariable operations fails, 914 * we might want to roll back all the changes already made. But the 915 * chances are that if anything is going to go wrong, it'll happen 916 * the first time we try to set one of the variables. 917 */ 918 if (newNetwork) { 919 removeNetwork(netId); 920 if (DBG) { 921 Log.d(TAG, 922 "Failed to set a network variable, removed network: " 923 + netId); 924 } 925 } 926 return -1; 927 } 928 makeString(BitSet set, String[] strings)929 private static String makeString(BitSet set, String[] strings) { 930 StringBuffer buf = new StringBuffer(); 931 int nextSetBit = -1; 932 933 /* Make sure all set bits are in [0, strings.length) to avoid 934 * going out of bounds on strings. (Shouldn't happen, but...) */ 935 set = set.get(0, strings.length); 936 937 while ((nextSetBit = set.nextSetBit(nextSetBit + 1)) != -1) { 938 buf.append(strings[nextSetBit].replace('_', '-')).append(' '); 939 } 940 941 // remove trailing space 942 if (set.cardinality() > 0) { 943 buf.setLength(buf.length() - 1); 944 } 945 946 return buf.toString(); 947 } 948 lookupString(String string, String[] strings)949 private static int lookupString(String string, String[] strings) { 950 int size = strings.length; 951 952 string = string.replace('-', '_'); 953 954 for (int i = 0; i < size; i++) 955 if (string.equals(strings[i])) 956 return i; 957 958 if (DBG) { 959 // if we ever get here, we should probably add the 960 // value to WifiConfiguration to reflect that it's 961 // supported by the WPA supplicant 962 Log.w(TAG, "Failed to look-up a string: " + string); 963 } 964 965 return -1; 966 } 967 968 /** 969 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 970 * @param netId the integer that identifies the network configuration 971 * to the supplicant 972 * @return {@code true} if the operation succeeded 973 */ removeNetwork(int netId)974 public boolean removeNetwork(int netId) { 975 enforceChangePermission(); 976 977 return mWifiStateTracker.removeNetwork(netId); 978 } 979 980 /** 981 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 982 * @param netId the integer that identifies the network configuration 983 * to the supplicant 984 * @param disableOthers if true, disable all other networks. 985 * @return {@code true} if the operation succeeded 986 */ enableNetwork(int netId, boolean disableOthers)987 public boolean enableNetwork(int netId, boolean disableOthers) { 988 enforceChangePermission(); 989 990 synchronized (mWifiStateTracker) { 991 String ifname = mWifiStateTracker.getInterfaceName(); 992 NetworkUtils.enableInterface(ifname); 993 boolean result = WifiNative.enableNetworkCommand(netId, disableOthers); 994 if (!result) { 995 NetworkUtils.disableInterface(ifname); 996 } 997 return result; 998 } 999 } 1000 1001 /** 1002 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 1003 * @param netId the integer that identifies the network configuration 1004 * to the supplicant 1005 * @return {@code true} if the operation succeeded 1006 */ disableNetwork(int netId)1007 public boolean disableNetwork(int netId) { 1008 enforceChangePermission(); 1009 1010 synchronized (mWifiStateTracker) { 1011 return WifiNative.disableNetworkCommand(netId); 1012 } 1013 } 1014 1015 /** 1016 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 1017 * @return the Wi-Fi information, contained in {@link WifiInfo}. 1018 */ getConnectionInfo()1019 public WifiInfo getConnectionInfo() { 1020 enforceAccessPermission(); 1021 /* 1022 * Make sure we have the latest information, by sending 1023 * a status request to the supplicant. 1024 */ 1025 return mWifiStateTracker.requestConnectionInfo(); 1026 } 1027 1028 /** 1029 * Return the results of the most recent access point scan, in the form of 1030 * a list of {@link ScanResult} objects. 1031 * @return the list of results 1032 */ getScanResults()1033 public List<ScanResult> getScanResults() { 1034 enforceAccessPermission(); 1035 String reply; 1036 synchronized (mWifiStateTracker) { 1037 reply = WifiNative.scanResultsCommand(); 1038 } 1039 if (reply == null) { 1040 return null; 1041 } 1042 1043 List<ScanResult> scanList = new ArrayList<ScanResult>(); 1044 1045 int lineCount = 0; 1046 1047 int replyLen = reply.length(); 1048 // Parse the result string, keeping in mind that the last line does 1049 // not end with a newline. 1050 for (int lineBeg = 0, lineEnd = 0; lineEnd <= replyLen; ++lineEnd) { 1051 if (lineEnd == replyLen || reply.charAt(lineEnd) == '\n') { 1052 ++lineCount; 1053 /* 1054 * Skip the first line, which is a header 1055 */ 1056 if (lineCount == 1) { 1057 lineBeg = lineEnd + 1; 1058 continue; 1059 } 1060 if (lineEnd > lineBeg) { 1061 String line = reply.substring(lineBeg, lineEnd); 1062 ScanResult scanResult = parseScanResult(line); 1063 if (scanResult != null) { 1064 scanList.add(scanResult); 1065 } else if (DBG) { 1066 Log.w(TAG, "misformatted scan result for: " + line); 1067 } 1068 } 1069 lineBeg = lineEnd + 1; 1070 } 1071 } 1072 mWifiStateTracker.setScanResultsList(scanList); 1073 return scanList; 1074 } 1075 1076 /** 1077 * Parse the scan result line passed to us by wpa_supplicant (helper). 1078 * @param line the line to parse 1079 * @return the {@link ScanResult} object 1080 */ parseScanResult(String line)1081 private ScanResult parseScanResult(String line) { 1082 ScanResult scanResult = null; 1083 if (line != null) { 1084 /* 1085 * Cache implementation (LinkedHashMap) is not synchronized, thus, 1086 * must synchronized here! 1087 */ 1088 synchronized (mScanResultCache) { 1089 String[] result = scanResultPattern.split(line); 1090 if (3 <= result.length && result.length <= 5) { 1091 String bssid = result[0]; 1092 // bssid | frequency | level | flags | ssid 1093 int frequency; 1094 int level; 1095 try { 1096 frequency = Integer.parseInt(result[1]); 1097 level = Integer.parseInt(result[2]); 1098 /* some implementations avoid negative values by adding 256 1099 * so we need to adjust for that here. 1100 */ 1101 if (level > 0) level -= 256; 1102 } catch (NumberFormatException e) { 1103 frequency = 0; 1104 level = 0; 1105 } 1106 1107 /* 1108 * The formatting of the results returned by 1109 * wpa_supplicant is intended to make the fields 1110 * line up nicely when printed, 1111 * not to make them easy to parse. So we have to 1112 * apply some heuristics to figure out which field 1113 * is the SSID and which field is the flags. 1114 */ 1115 String ssid; 1116 String flags; 1117 if (result.length == 4) { 1118 if (result[3].charAt(0) == '[') { 1119 flags = result[3]; 1120 ssid = ""; 1121 } else { 1122 flags = ""; 1123 ssid = result[3]; 1124 } 1125 } else if (result.length == 5) { 1126 flags = result[3]; 1127 ssid = result[4]; 1128 } else { 1129 // Here, we must have 3 fields: no flags and ssid 1130 // set 1131 flags = ""; 1132 ssid = ""; 1133 } 1134 1135 // bssid + ssid is the hash key 1136 String key = bssid + ssid; 1137 scanResult = mScanResultCache.get(key); 1138 if (scanResult != null) { 1139 scanResult.level = level; 1140 scanResult.SSID = ssid; 1141 scanResult.capabilities = flags; 1142 scanResult.frequency = frequency; 1143 } else { 1144 // Do not add scan results that have no SSID set 1145 if (0 < ssid.trim().length()) { 1146 scanResult = 1147 new ScanResult( 1148 ssid, bssid, flags, level, frequency); 1149 mScanResultCache.put(key, scanResult); 1150 } 1151 } 1152 } else { 1153 Log.w(TAG, "Misformatted scan result text with " + 1154 result.length + " fields: " + line); 1155 } 1156 } 1157 } 1158 1159 return scanResult; 1160 } 1161 1162 /** 1163 * Parse the "flags" field passed back in a scan result by wpa_supplicant, 1164 * and construct a {@code WifiConfiguration} that describes the encryption, 1165 * key management, and authenticaion capabilities of the access point. 1166 * @param flags the string returned by wpa_supplicant 1167 * @return the {@link WifiConfiguration} object, filled in 1168 */ parseScanFlags(String flags)1169 WifiConfiguration parseScanFlags(String flags) { 1170 WifiConfiguration config = new WifiConfiguration(); 1171 1172 if (flags.length() == 0) { 1173 config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); 1174 } 1175 // ... to be implemented 1176 return config; 1177 } 1178 1179 /** 1180 * Tell the supplicant to persist the current list of configured networks. 1181 * @return {@code true} if the operation succeeded 1182 */ saveConfiguration()1183 public boolean saveConfiguration() { 1184 boolean result; 1185 enforceChangePermission(); 1186 synchronized (mWifiStateTracker) { 1187 result = WifiNative.saveConfigCommand(); 1188 if (result && mNeedReconfig) { 1189 mNeedReconfig = false; 1190 result = WifiNative.reloadConfigCommand(); 1191 1192 if (result) { 1193 Intent intent = new Intent(WifiManager.NETWORK_IDS_CHANGED_ACTION); 1194 mContext.sendBroadcast(intent); 1195 } 1196 } 1197 } 1198 // Inform the backup manager about a data change 1199 IBackupManager ibm = IBackupManager.Stub.asInterface( 1200 ServiceManager.getService(Context.BACKUP_SERVICE)); 1201 if (ibm != null) { 1202 try { 1203 ibm.dataChanged("com.android.providers.settings"); 1204 } catch (Exception e) { 1205 // Try again later 1206 } 1207 } 1208 return result; 1209 } 1210 1211 /** 1212 * Set the number of radio frequency channels that are allowed to be used 1213 * in the current regulatory domain. This method should be used only 1214 * if the correct number of channels cannot be determined automatically 1215 * for some reason. If the operation is successful, the new value may be 1216 * persisted as a Secure setting. 1217 * @param numChannels the number of allowed channels. Must be greater than 0 1218 * and less than or equal to 16. 1219 * @param persist {@code true} if the setting should be remembered. 1220 * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g., 1221 * {@code numChannels} is outside the valid range. 1222 */ setNumAllowedChannels(int numChannels, boolean persist)1223 public boolean setNumAllowedChannels(int numChannels, boolean persist) { 1224 Log.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+ 1225 " with persist set to "+persist); 1226 enforceChangePermission(); 1227 /* 1228 * Validate the argument. We'd like to let the Wi-Fi driver do this, 1229 * but if Wi-Fi isn't currently enabled, that's not possible, and 1230 * we want to persist the setting anyway,so that it will take 1231 * effect when Wi-Fi does become enabled. 1232 */ 1233 boolean found = false; 1234 for (int validChan : sValidRegulatoryChannelCounts) { 1235 if (validChan == numChannels) { 1236 found = true; 1237 break; 1238 } 1239 } 1240 if (!found) { 1241 return false; 1242 } 1243 1244 if (persist) { 1245 Settings.Secure.putInt(mContext.getContentResolver(), 1246 Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, 1247 numChannels); 1248 } 1249 mWifiStateTracker.setNumAllowedChannels(numChannels); 1250 return true; 1251 } 1252 1253 /** 1254 * Return the number of frequency channels that are allowed 1255 * to be used in the current regulatory domain. 1256 * @return the number of allowed channels, or {@code -1} if an error occurs 1257 */ getNumAllowedChannels()1258 public int getNumAllowedChannels() { 1259 int numChannels; 1260 1261 enforceAccessPermission(); 1262 synchronized (mWifiStateTracker) { 1263 /* 1264 * If we can't get the value from the driver (e.g., because 1265 * Wi-Fi is not currently enabled), get the value from 1266 * Settings. 1267 */ 1268 numChannels = WifiNative.getNumAllowedChannelsCommand(); 1269 if (numChannels < 0) { 1270 numChannels = Settings.Secure.getInt(mContext.getContentResolver(), 1271 Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, 1272 -1); 1273 } 1274 } 1275 return numChannels; 1276 } 1277 1278 /** 1279 * Return the list of valid values for the number of allowed radio channels 1280 * for various regulatory domains. 1281 * @return the list of channel counts 1282 */ getValidChannelCounts()1283 public int[] getValidChannelCounts() { 1284 enforceAccessPermission(); 1285 return sValidRegulatoryChannelCounts; 1286 } 1287 1288 /** 1289 * Return the DHCP-assigned addresses from the last successful DHCP request, 1290 * if any. 1291 * @return the DHCP information 1292 */ getDhcpInfo()1293 public DhcpInfo getDhcpInfo() { 1294 enforceAccessPermission(); 1295 return mWifiStateTracker.getDhcpInfo(); 1296 } 1297 1298 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 1299 @Override 1300 public void onReceive(Context context, Intent intent) { 1301 String action = intent.getAction(); 1302 1303 long idleMillis = Settings.Gservices.getLong(mContext.getContentResolver(), 1304 Settings.Gservices.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS); 1305 int stayAwakeConditions = 1306 Settings.System.getInt(mContext.getContentResolver(), 1307 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0); 1308 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1309 Log.d(TAG, "ACTION_SCREEN_ON"); 1310 mAlarmManager.cancel(mIdleIntent); 1311 mDeviceIdle = false; 1312 mScreenOff = false; 1313 mWifiStateTracker.enableRssiPolling(true); 1314 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1315 Log.d(TAG, "ACTION_SCREEN_OFF"); 1316 mScreenOff = true; 1317 mWifiStateTracker.enableRssiPolling(false); 1318 /* 1319 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 1320 * AND the "stay on while plugged in" setting doesn't match the 1321 * current power conditions (i.e, not plugged in, plugged in to USB, 1322 * or plugged in to AC). 1323 */ 1324 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) { 1325 WifiInfo info = mWifiStateTracker.requestConnectionInfo(); 1326 if (info.getSupplicantState() != SupplicantState.COMPLETED) { 1327 // we used to go to sleep immediately, but this caused some race conditions 1328 // we don't have time to track down for this release. Delay instead, but not 1329 // as long as we would if connected (below) 1330 // TODO - fix the race conditions and switch back to the immediate turn-off 1331 long triggerTime = System.currentTimeMillis() + (2*60*1000); // 2 min 1332 Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for 120,000 ms"); 1333 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); 1334 // // do not keep Wifi awake when screen is off if Wifi is not associated 1335 // mDeviceIdle = true; 1336 // updateWifiState(); 1337 } else { 1338 long triggerTime = System.currentTimeMillis() + idleMillis; 1339 Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms"); 1340 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); 1341 } 1342 } 1343 /* we can return now -- there's nothing to do until we get the idle intent back */ 1344 return; 1345 } else if (action.equals(ACTION_DEVICE_IDLE)) { 1346 Log.d(TAG, "got ACTION_DEVICE_IDLE"); 1347 mDeviceIdle = true; 1348 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 1349 /* 1350 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 1351 * AND we are transitioning from a state in which the device was supposed 1352 * to stay awake to a state in which it is not supposed to stay awake. 1353 * If "stay awake" state is not changing, we do nothing, to avoid resetting 1354 * the already-set timer. 1355 */ 1356 int pluggedType = intent.getIntExtra("plugged", 0); 1357 Log.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType); 1358 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) && 1359 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) { 1360 long triggerTime = System.currentTimeMillis() + idleMillis; 1361 Log.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms"); 1362 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); 1363 mPluggedType = pluggedType; 1364 return; 1365 } 1366 mPluggedType = pluggedType; 1367 } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) { 1368 boolean isBluetoothPlaying = 1369 intent.getIntExtra( 1370 BluetoothA2dp.EXTRA_SINK_STATE, 1371 BluetoothA2dp.STATE_DISCONNECTED) == BluetoothA2dp.STATE_PLAYING; 1372 mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying); 1373 } else { 1374 return; 1375 } 1376 1377 updateWifiState(); 1378 } 1379 1380 /** 1381 * Determines whether the Wi-Fi chipset should stay awake or be put to 1382 * sleep. Looks at the setting for the sleep policy and the current 1383 * conditions. 1384 * 1385 * @see #shouldDeviceStayAwake(int, int) 1386 */ 1387 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) { 1388 int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(), 1389 Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT); 1390 1391 if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) { 1392 // Never sleep 1393 return true; 1394 } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && 1395 (pluggedType != 0)) { 1396 // Never sleep while plugged, and we're plugged 1397 return true; 1398 } else { 1399 // Default 1400 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType); 1401 } 1402 } 1403 1404 /** 1405 * Determine whether the bit value corresponding to {@code pluggedType} is set in 1406 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value 1407 * of {@code 0} isn't really a plugged type, but rather an indication that the 1408 * device isn't plugged in at all, there is no bit value corresponding to a 1409 * {@code pluggedType} value of {@code 0}. That is why we shift by 1410 * {@code pluggedType — 1} instead of by {@code pluggedType}. 1411 * @param stayAwakeConditions a bit string specifying which "plugged types" should 1412 * keep the device (and hence Wi-Fi) awake. 1413 * @param pluggedType the type of plug (USB, AC, or none) for which the check is 1414 * being made 1415 * @return {@code true} if {@code pluggedType} indicates that the device is 1416 * supposed to stay awake, {@code false} otherwise. 1417 */ 1418 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) { 1419 return (stayAwakeConditions & pluggedType) != 0; 1420 } 1421 }; 1422 sendEnableMessage(boolean enable, boolean persist, int uid)1423 private void sendEnableMessage(boolean enable, boolean persist, int uid) { 1424 Message msg = Message.obtain(mWifiHandler, 1425 (enable ? MESSAGE_ENABLE_WIFI : MESSAGE_DISABLE_WIFI), 1426 (persist ? 1 : 0), uid); 1427 msg.sendToTarget(); 1428 } 1429 sendStartMessage(boolean scanOnlyMode)1430 private void sendStartMessage(boolean scanOnlyMode) { 1431 Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget(); 1432 } 1433 updateWifiState()1434 private void updateWifiState() { 1435 boolean wifiEnabled = getPersistedWifiEnabled(); 1436 boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden; 1437 boolean lockHeld = mLocks.hasLocks(); 1438 int strongestLockMode; 1439 boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode; 1440 boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld; 1441 if (mDeviceIdle && lockHeld) { 1442 strongestLockMode = mLocks.getStrongestLockMode(); 1443 } else { 1444 strongestLockMode = WifiManager.WIFI_MODE_FULL; 1445 } 1446 1447 synchronized (mWifiHandler) { 1448 if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) { 1449 return; 1450 } 1451 if (wifiShouldBeEnabled) { 1452 if (wifiShouldBeStarted) { 1453 sWakeLock.acquire(); 1454 sendEnableMessage(true, false, mLastEnableUid); 1455 sWakeLock.acquire(); 1456 sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY); 1457 } else { 1458 int wakeLockTimeout = 1459 Settings.Secure.getInt( 1460 mContext.getContentResolver(), 1461 Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS, 1462 DEFAULT_WAKELOCK_TIMEOUT); 1463 /* 1464 * The following wakelock is held in order to ensure 1465 * that the connectivity manager has time to fail over 1466 * to the mobile data network. The connectivity manager 1467 * releases it once mobile data connectivity has been 1468 * established. If connectivity cannot be established, 1469 * the wakelock is released after wakeLockTimeout 1470 * milliseconds have elapsed. 1471 */ 1472 sDriverStopWakeLock.acquire(); 1473 mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI); 1474 mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout); 1475 } 1476 } else { 1477 sWakeLock.acquire(); 1478 sendEnableMessage(false, false, mLastEnableUid); 1479 } 1480 } 1481 } 1482 registerForBroadcasts()1483 private void registerForBroadcasts() { 1484 IntentFilter intentFilter = new IntentFilter(); 1485 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 1486 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 1487 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 1488 intentFilter.addAction(ACTION_DEVICE_IDLE); 1489 intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED); 1490 mContext.registerReceiver(mReceiver, intentFilter); 1491 } 1492 isAirplaneSensitive()1493 private boolean isAirplaneSensitive() { 1494 String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(), 1495 Settings.System.AIRPLANE_MODE_RADIOS); 1496 return airplaneModeRadios == null 1497 || airplaneModeRadios.contains(Settings.System.RADIO_WIFI); 1498 } 1499 isAirplaneToggleable()1500 private boolean isAirplaneToggleable() { 1501 String toggleableRadios = Settings.System.getString(mContext.getContentResolver(), 1502 Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 1503 return toggleableRadios != null 1504 && toggleableRadios.contains(Settings.System.RADIO_WIFI); 1505 } 1506 1507 /** 1508 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is 1509 * currently on. 1510 * @return {@code true} if airplane mode is on. 1511 */ isAirplaneModeOn()1512 private boolean isAirplaneModeOn() { 1513 return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(), 1514 Settings.System.AIRPLANE_MODE_ON, 0) == 1; 1515 } 1516 1517 /** 1518 * Handler that allows posting to the WifiThread. 1519 */ 1520 private class WifiHandler extends Handler { WifiHandler(Looper looper)1521 public WifiHandler(Looper looper) { 1522 super(looper); 1523 } 1524 1525 @Override handleMessage(Message msg)1526 public void handleMessage(Message msg) { 1527 switch (msg.what) { 1528 1529 case MESSAGE_ENABLE_WIFI: 1530 setWifiEnabledBlocking(true, msg.arg1 == 1, msg.arg2); 1531 sWakeLock.release(); 1532 break; 1533 1534 case MESSAGE_START_WIFI: 1535 mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0); 1536 mWifiStateTracker.restart(); 1537 sWakeLock.release(); 1538 break; 1539 1540 case MESSAGE_DISABLE_WIFI: 1541 // a non-zero msg.arg1 value means the "enabled" setting 1542 // should be persisted 1543 setWifiEnabledBlocking(false, msg.arg1 == 1, msg.arg2); 1544 sWakeLock.release(); 1545 break; 1546 1547 case MESSAGE_STOP_WIFI: 1548 mWifiStateTracker.disconnectAndStop(); 1549 // don't release wakelock 1550 break; 1551 1552 case MESSAGE_RELEASE_WAKELOCK: 1553 synchronized (sDriverStopWakeLock) { 1554 if (sDriverStopWakeLock.isHeld()) { 1555 sDriverStopWakeLock.release(); 1556 } 1557 } 1558 break; 1559 } 1560 } 1561 } 1562 1563 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1564 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1565 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1566 != PackageManager.PERMISSION_GRANTED) { 1567 pw.println("Permission Denial: can't dump WifiService from from pid=" 1568 + Binder.getCallingPid() 1569 + ", uid=" + Binder.getCallingUid()); 1570 return; 1571 } 1572 pw.println("Wi-Fi is " + stateName(mWifiState)); 1573 pw.println("Stay-awake conditions: " + 1574 Settings.System.getInt(mContext.getContentResolver(), 1575 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0)); 1576 pw.println(); 1577 1578 pw.println("Internal state:"); 1579 pw.println(mWifiStateTracker); 1580 pw.println(); 1581 pw.println("Latest scan results:"); 1582 List<ScanResult> scanResults = mWifiStateTracker.getScanResultsList(); 1583 if (scanResults != null && scanResults.size() != 0) { 1584 pw.println(" BSSID Frequency RSSI Flags SSID"); 1585 for (ScanResult r : scanResults) { 1586 pw.printf(" %17s %9d %5d %-16s %s%n", 1587 r.BSSID, 1588 r.frequency, 1589 r.level, 1590 r.capabilities, 1591 r.SSID == null ? "" : r.SSID); 1592 } 1593 } 1594 pw.println(); 1595 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " + 1596 mScanLocksAcquired + " scan"); 1597 pw.println("Locks released: " + mFullLocksReleased + " full, " + 1598 mScanLocksReleased + " scan"); 1599 pw.println(); 1600 pw.println("Locks held:"); 1601 mLocks.dump(pw); 1602 } 1603 stateName(int wifiState)1604 private static String stateName(int wifiState) { 1605 switch (wifiState) { 1606 case WIFI_STATE_DISABLING: 1607 return "disabling"; 1608 case WIFI_STATE_DISABLED: 1609 return "disabled"; 1610 case WIFI_STATE_ENABLING: 1611 return "enabling"; 1612 case WIFI_STATE_ENABLED: 1613 return "enabled"; 1614 case WIFI_STATE_UNKNOWN: 1615 return "unknown state"; 1616 default: 1617 return "[invalid state]"; 1618 } 1619 } 1620 1621 private class WifiLock extends DeathRecipient { WifiLock(int lockMode, String tag, IBinder binder)1622 WifiLock(int lockMode, String tag, IBinder binder) { 1623 super(lockMode, tag, binder); 1624 } 1625 binderDied()1626 public void binderDied() { 1627 synchronized (mLocks) { 1628 releaseWifiLockLocked(mBinder); 1629 } 1630 } 1631 toString()1632 public String toString() { 1633 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}"; 1634 } 1635 } 1636 1637 private class LockList { 1638 private List<WifiLock> mList; 1639 LockList()1640 private LockList() { 1641 mList = new ArrayList<WifiLock>(); 1642 } 1643 hasLocks()1644 private synchronized boolean hasLocks() { 1645 return !mList.isEmpty(); 1646 } 1647 getStrongestLockMode()1648 private synchronized int getStrongestLockMode() { 1649 if (mList.isEmpty()) { 1650 return WifiManager.WIFI_MODE_FULL; 1651 } 1652 for (WifiLock l : mList) { 1653 if (l.mMode == WifiManager.WIFI_MODE_FULL) { 1654 return WifiManager.WIFI_MODE_FULL; 1655 } 1656 } 1657 return WifiManager.WIFI_MODE_SCAN_ONLY; 1658 } 1659 addLock(WifiLock lock)1660 private void addLock(WifiLock lock) { 1661 if (findLockByBinder(lock.mBinder) < 0) { 1662 mList.add(lock); 1663 } 1664 } 1665 removeLock(IBinder binder)1666 private WifiLock removeLock(IBinder binder) { 1667 int index = findLockByBinder(binder); 1668 if (index >= 0) { 1669 WifiLock ret = mList.remove(index); 1670 ret.unlinkDeathRecipient(); 1671 return ret; 1672 } else { 1673 return null; 1674 } 1675 } 1676 findLockByBinder(IBinder binder)1677 private int findLockByBinder(IBinder binder) { 1678 int size = mList.size(); 1679 for (int i = size - 1; i >= 0; i--) 1680 if (mList.get(i).mBinder == binder) 1681 return i; 1682 return -1; 1683 } 1684 dump(PrintWriter pw)1685 private void dump(PrintWriter pw) { 1686 for (WifiLock l : mList) { 1687 pw.print(" "); 1688 pw.println(l); 1689 } 1690 } 1691 } 1692 acquireWifiLock(IBinder binder, int lockMode, String tag)1693 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) { 1694 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1695 if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) { 1696 return false; 1697 } 1698 WifiLock wifiLock = new WifiLock(lockMode, tag, binder); 1699 synchronized (mLocks) { 1700 return acquireWifiLockLocked(wifiLock); 1701 } 1702 } 1703 acquireWifiLockLocked(WifiLock wifiLock)1704 private boolean acquireWifiLockLocked(WifiLock wifiLock) { 1705 Log.d(TAG, "acquireWifiLockLocked: " + wifiLock); 1706 1707 mLocks.addLock(wifiLock); 1708 1709 int uid = Binder.getCallingUid(); 1710 long ident = Binder.clearCallingIdentity(); 1711 try { 1712 switch(wifiLock.mMode) { 1713 case WifiManager.WIFI_MODE_FULL: 1714 ++mFullLocksAcquired; 1715 mBatteryStats.noteFullWifiLockAcquired(uid); 1716 break; 1717 case WifiManager.WIFI_MODE_SCAN_ONLY: 1718 ++mScanLocksAcquired; 1719 mBatteryStats.noteScanWifiLockAcquired(uid); 1720 break; 1721 } 1722 } catch (RemoteException e) { 1723 } finally { 1724 Binder.restoreCallingIdentity(ident); 1725 } 1726 1727 updateWifiState(); 1728 return true; 1729 } 1730 releaseWifiLock(IBinder lock)1731 public boolean releaseWifiLock(IBinder lock) { 1732 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1733 synchronized (mLocks) { 1734 return releaseWifiLockLocked(lock); 1735 } 1736 } 1737 releaseWifiLockLocked(IBinder lock)1738 private boolean releaseWifiLockLocked(IBinder lock) { 1739 boolean hadLock; 1740 1741 WifiLock wifiLock = mLocks.removeLock(lock); 1742 1743 Log.d(TAG, "releaseWifiLockLocked: " + wifiLock); 1744 1745 hadLock = (wifiLock != null); 1746 1747 if (hadLock) { 1748 int uid = Binder.getCallingUid(); 1749 long ident = Binder.clearCallingIdentity(); 1750 try { 1751 switch(wifiLock.mMode) { 1752 case WifiManager.WIFI_MODE_FULL: 1753 ++mFullLocksReleased; 1754 mBatteryStats.noteFullWifiLockReleased(uid); 1755 break; 1756 case WifiManager.WIFI_MODE_SCAN_ONLY: 1757 ++mScanLocksReleased; 1758 mBatteryStats.noteScanWifiLockReleased(uid); 1759 break; 1760 } 1761 } catch (RemoteException e) { 1762 } finally { 1763 Binder.restoreCallingIdentity(ident); 1764 } 1765 } 1766 // TODO - should this only happen if you hadLock? 1767 updateWifiState(); 1768 return hadLock; 1769 } 1770 1771 private abstract class DeathRecipient 1772 implements IBinder.DeathRecipient { 1773 String mTag; 1774 int mMode; 1775 IBinder mBinder; 1776 DeathRecipient(int mode, String tag, IBinder binder)1777 DeathRecipient(int mode, String tag, IBinder binder) { 1778 super(); 1779 mTag = tag; 1780 mMode = mode; 1781 mBinder = binder; 1782 try { 1783 mBinder.linkToDeath(this, 0); 1784 } catch (RemoteException e) { 1785 binderDied(); 1786 } 1787 } 1788 unlinkDeathRecipient()1789 void unlinkDeathRecipient() { 1790 mBinder.unlinkToDeath(this, 0); 1791 } 1792 } 1793 1794 private class Multicaster extends DeathRecipient { Multicaster(String tag, IBinder binder)1795 Multicaster(String tag, IBinder binder) { 1796 super(Binder.getCallingUid(), tag, binder); 1797 } 1798 binderDied()1799 public void binderDied() { 1800 Log.e(TAG, "Multicaster binderDied"); 1801 synchronized (mMulticasters) { 1802 int i = mMulticasters.indexOf(this); 1803 if (i != -1) { 1804 removeMulticasterLocked(i, mMode); 1805 } 1806 } 1807 } 1808 toString()1809 public String toString() { 1810 return "Multicaster{" + mTag + " binder=" + mBinder + "}"; 1811 } 1812 getUid()1813 public int getUid() { 1814 return mMode; 1815 } 1816 } 1817 acquireMulticastLock(IBinder binder, String tag)1818 public void acquireMulticastLock(IBinder binder, String tag) { 1819 enforceMulticastChangePermission(); 1820 1821 synchronized (mMulticasters) { 1822 mMulticastEnabled++; 1823 mMulticasters.add(new Multicaster(tag, binder)); 1824 // Note that we could call stopPacketFiltering only when 1825 // our new size == 1 (first call), but this function won't 1826 // be called often and by making the stopPacket call each 1827 // time we're less fragile and self-healing. 1828 synchronized (mWifiStateTracker) { 1829 WifiNative.stopPacketFiltering(); 1830 } 1831 } 1832 1833 int uid = Binder.getCallingUid(); 1834 Long ident = Binder.clearCallingIdentity(); 1835 try { 1836 mBatteryStats.noteWifiMulticastEnabled(uid); 1837 } catch (RemoteException e) { 1838 } finally { 1839 Binder.restoreCallingIdentity(ident); 1840 } 1841 } 1842 releaseMulticastLock()1843 public void releaseMulticastLock() { 1844 enforceMulticastChangePermission(); 1845 1846 int uid = Binder.getCallingUid(); 1847 synchronized (mMulticasters) { 1848 mMulticastDisabled++; 1849 int size = mMulticasters.size(); 1850 for (int i = size - 1; i >= 0; i--) { 1851 Multicaster m = mMulticasters.get(i); 1852 if ((m != null) && (m.getUid() == uid)) { 1853 removeMulticasterLocked(i, uid); 1854 } 1855 } 1856 } 1857 } 1858 removeMulticasterLocked(int i, int uid)1859 private void removeMulticasterLocked(int i, int uid) 1860 { 1861 Multicaster removed = mMulticasters.remove(i); 1862 if (removed != null) { 1863 removed.unlinkDeathRecipient(); 1864 } 1865 if (mMulticasters.size() == 0) { 1866 synchronized (mWifiStateTracker) { 1867 WifiNative.startPacketFiltering(); 1868 } 1869 } 1870 1871 Long ident = Binder.clearCallingIdentity(); 1872 try { 1873 mBatteryStats.noteWifiMulticastDisabled(uid); 1874 } catch (RemoteException e) { 1875 } finally { 1876 Binder.restoreCallingIdentity(ident); 1877 } 1878 } 1879 isMulticastEnabled()1880 public boolean isMulticastEnabled() { 1881 enforceAccessPermission(); 1882 1883 synchronized (mMulticasters) { 1884 return (mMulticasters.size() > 0); 1885 } 1886 } 1887 } 1888