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