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