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