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