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