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