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