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