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