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