WifiService.java revision 3d33a633916be943eb294d3309701994095d80f2
1/* 2 * Copyright (C) 2010 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 android.app.ActivityManager; 20import android.app.AlarmManager; 21import android.app.Notification; 22import android.app.NotificationManager; 23import android.app.PendingIntent; 24import android.bluetooth.BluetoothAdapter; 25import android.content.BroadcastReceiver; 26import android.content.ContentResolver; 27import android.content.Context; 28import android.content.Intent; 29import android.content.IntentFilter; 30import android.content.pm.PackageManager; 31import android.database.ContentObserver; 32import android.net.wifi.IWifiManager; 33import android.net.wifi.ScanResult; 34import android.net.wifi.SupplicantState; 35import android.net.wifi.WifiInfo; 36import android.net.wifi.WifiManager; 37import android.net.wifi.WifiStateMachine; 38import android.net.wifi.WifiConfiguration; 39import android.net.wifi.WifiWatchdogStateMachine; 40import android.net.wifi.WifiConfiguration.KeyMgmt; 41import android.net.wifi.WpsInfo; 42import android.net.wifi.WpsResult; 43import android.net.ConnectivityManager; 44import android.net.DhcpInfo; 45import android.net.NetworkInfo; 46import android.net.NetworkInfo.State; 47import android.net.NetworkInfo.DetailedState; 48import android.net.TrafficStats; 49import android.os.Binder; 50import android.os.Handler; 51import android.os.Messenger; 52import android.os.HandlerThread; 53import android.os.IBinder; 54import android.os.INetworkManagementService; 55import android.os.Message; 56import android.os.RemoteException; 57import android.os.ServiceManager; 58import android.os.SystemProperties; 59import android.os.UserHandle; 60import android.os.WorkSource; 61import android.provider.Settings; 62import android.text.TextUtils; 63import android.util.Log; 64import android.util.Slog; 65 66import java.util.ArrayList; 67import java.util.HashMap; 68import java.util.List; 69import java.util.Set; 70import java.util.concurrent.atomic.AtomicInteger; 71import java.util.concurrent.atomic.AtomicBoolean; 72import java.io.FileDescriptor; 73import java.io.PrintWriter; 74 75import com.android.internal.app.IBatteryStats; 76import com.android.internal.telephony.TelephonyIntents; 77import com.android.internal.util.AsyncChannel; 78import com.android.server.am.BatteryStatsService; 79import com.android.internal.R; 80 81/** 82 * WifiService handles remote WiFi operation requests by implementing 83 * the IWifiManager interface. 84 * 85 * @hide 86 */ 87//TODO: Clean up multiple locks and implement WifiService 88// as a SM to track soft AP/client/adhoc bring up based 89// on device idle state, airplane mode and boot. 90 91public class WifiService extends IWifiManager.Stub { 92 private static final String TAG = "WifiService"; 93 private static final boolean DBG = false; 94 95 private final WifiStateMachine mWifiStateMachine; 96 97 private Context mContext; 98 99 private AlarmManager mAlarmManager; 100 private PendingIntent mIdleIntent; 101 private static final int IDLE_REQUEST = 0; 102 private boolean mScreenOff; 103 private boolean mDeviceIdle; 104 private boolean mEmergencyCallbackMode = false; 105 private int mPluggedType; 106 107 private final LockList mLocks = new LockList(); 108 // some wifi lock statistics 109 private int mFullHighPerfLocksAcquired; 110 private int mFullHighPerfLocksReleased; 111 private int mFullLocksAcquired; 112 private int mFullLocksReleased; 113 private int mScanLocksAcquired; 114 private int mScanLocksReleased; 115 116 private final List<Multicaster> mMulticasters = 117 new ArrayList<Multicaster>(); 118 private int mMulticastEnabled; 119 private int mMulticastDisabled; 120 121 private final IBatteryStats mBatteryStats; 122 123 private boolean mEnableTrafficStatsPoll = false; 124 private int mTrafficStatsPollToken = 0; 125 private long mTxPkts; 126 private long mRxPkts; 127 /* Tracks last reported data activity */ 128 private int mDataActivity; 129 private String mInterfaceName; 130 131 /** 132 * Interval in milliseconds between polling for traffic 133 * statistics 134 */ 135 private static final int POLL_TRAFFIC_STATS_INTERVAL_MSECS = 1000; 136 137 /** 138 * See {@link Settings.Global#WIFI_IDLE_MS}. This is the default value if a 139 * Settings.Global value is not present. This timeout value is chosen as 140 * the approximate point at which the battery drain caused by Wi-Fi 141 * being enabled but not active exceeds the battery drain caused by 142 * re-establishing a connection to the mobile data network. 143 */ 144 private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000; /* 15 minutes */ 145 146 private static final String ACTION_DEVICE_IDLE = 147 "com.android.server.WifiManager.action.DEVICE_IDLE"; 148 149 private static final int WIFI_DISABLED = 0; 150 private static final int WIFI_ENABLED = 1; 151 /* Wifi enabled while in airplane mode */ 152 private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2; 153 /* Wifi disabled due to airplane mode on */ 154 private static final int WIFI_DISABLED_AIRPLANE_ON = 3; 155 156 /* Persisted state that tracks the wifi & airplane interaction from settings */ 157 private AtomicInteger mPersistWifiState = new AtomicInteger(WIFI_DISABLED); 158 /* Tracks current airplane mode state */ 159 private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false); 160 /* Tracks whether wifi is enabled from WifiStateMachine's perspective */ 161 private boolean mWifiEnabled; 162 163 /* The work source (UID) that triggered the current WIFI scan, synchronized 164 * on this */ 165 private WorkSource mScanWorkSource; 166 167 private boolean mIsReceiverRegistered = false; 168 169 170 NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); 171 172 // Variables relating to the 'available networks' notification 173 /** 174 * The icon to show in the 'available networks' notification. This will also 175 * be the ID of the Notification given to the NotificationManager. 176 */ 177 private static final int ICON_NETWORKS_AVAILABLE = 178 com.android.internal.R.drawable.stat_notify_wifi_in_range; 179 /** 180 * When a notification is shown, we wait this amount before possibly showing it again. 181 */ 182 private final long NOTIFICATION_REPEAT_DELAY_MS; 183 /** 184 * Whether the user has set the setting to show the 'available networks' notification. 185 */ 186 private boolean mNotificationEnabled; 187 /** 188 * Observes the user setting to keep {@link #mNotificationEnabled} in sync. 189 */ 190 private NotificationEnabledSettingObserver mNotificationEnabledSettingObserver; 191 /** 192 * The {@link System#currentTimeMillis()} must be at least this value for us 193 * to show the notification again. 194 */ 195 private long mNotificationRepeatTime; 196 /** 197 * The Notification object given to the NotificationManager. 198 */ 199 private Notification mNotification; 200 /** 201 * Whether the notification is being shown, as set by us. That is, if the 202 * user cancels the notification, we will not receive the callback so this 203 * will still be true. We only guarantee if this is false, then the 204 * notification is not showing. 205 */ 206 private boolean mNotificationShown; 207 /** 208 * The number of continuous scans that must occur before consider the 209 * supplicant in a scanning state. This allows supplicant to associate with 210 * remembered networks that are in the scan results. 211 */ 212 private static final int NUM_SCANS_BEFORE_ACTUALLY_SCANNING = 3; 213 /** 214 * The number of scans since the last network state change. When this 215 * exceeds {@link #NUM_SCANS_BEFORE_ACTUALLY_SCANNING}, we consider the 216 * supplicant to actually be scanning. When the network state changes to 217 * something other than scanning, we reset this to 0. 218 */ 219 private int mNumScansSinceNetworkStateChange; 220 221 /** 222 * Asynchronous channel to WifiStateMachine 223 */ 224 private AsyncChannel mWifiStateMachineChannel; 225 226 /** 227 * Clients receiving asynchronous messages 228 */ 229 private List<AsyncChannel> mClients = new ArrayList<AsyncChannel>(); 230 231 /** 232 * Handles client connections 233 */ 234 private class AsyncServiceHandler extends Handler { 235 236 AsyncServiceHandler(android.os.Looper looper) { 237 super(looper); 238 } 239 240 @Override 241 public void handleMessage(Message msg) { 242 switch (msg.what) { 243 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 244 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 245 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); 246 mClients.add((AsyncChannel) msg.obj); 247 } else { 248 Slog.e(TAG, "Client connection failure, error=" + msg.arg1); 249 } 250 break; 251 } 252 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 253 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 254 if (DBG) Slog.d(TAG, "Send failed, client connection lost"); 255 } else { 256 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); 257 } 258 mClients.remove((AsyncChannel) msg.obj); 259 break; 260 } 261 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 262 AsyncChannel ac = new AsyncChannel(); 263 ac.connect(mContext, this, msg.replyTo); 264 break; 265 } 266 case WifiManager.ENABLE_TRAFFIC_STATS_POLL: { 267 mEnableTrafficStatsPoll = (msg.arg1 == 1); 268 mTrafficStatsPollToken++; 269 if (mEnableTrafficStatsPoll) { 270 notifyOnDataActivity(); 271 sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL, 272 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 273 } 274 break; 275 } 276 case WifiManager.TRAFFIC_STATS_POLL: { 277 if (msg.arg1 == mTrafficStatsPollToken) { 278 notifyOnDataActivity(); 279 sendMessageDelayed(Message.obtain(this, WifiManager.TRAFFIC_STATS_POLL, 280 mTrafficStatsPollToken, 0), POLL_TRAFFIC_STATS_INTERVAL_MSECS); 281 } 282 break; 283 } 284 case WifiManager.CONNECT_NETWORK: { 285 mWifiStateMachine.sendMessage(Message.obtain(msg)); 286 break; 287 } 288 case WifiManager.SAVE_NETWORK: { 289 mWifiStateMachine.sendMessage(Message.obtain(msg)); 290 break; 291 } 292 case WifiManager.FORGET_NETWORK: { 293 mWifiStateMachine.sendMessage(Message.obtain(msg)); 294 break; 295 } 296 case WifiManager.START_WPS: { 297 mWifiStateMachine.sendMessage(Message.obtain(msg)); 298 break; 299 } 300 case WifiManager.CANCEL_WPS: { 301 mWifiStateMachine.sendMessage(Message.obtain(msg)); 302 break; 303 } 304 case WifiManager.DISABLE_NETWORK: { 305 mWifiStateMachine.sendMessage(Message.obtain(msg)); 306 break; 307 } 308 case WifiManager.RSSI_PKTCNT_FETCH: { 309 mWifiStateMachine.sendMessage(Message.obtain(msg)); 310 break; 311 } 312 default: { 313 Slog.d(TAG, "WifiServicehandler.handleMessage ignoring msg=" + msg); 314 break; 315 } 316 } 317 } 318 } 319 private AsyncServiceHandler mAsyncServiceHandler; 320 321 /** 322 * Handles interaction with WifiStateMachine 323 */ 324 private class WifiStateMachineHandler extends Handler { 325 private AsyncChannel mWsmChannel; 326 327 WifiStateMachineHandler(android.os.Looper looper) { 328 super(looper); 329 mWsmChannel = new AsyncChannel(); 330 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 331 } 332 333 @Override 334 public void handleMessage(Message msg) { 335 switch (msg.what) { 336 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 337 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 338 mWifiStateMachineChannel = mWsmChannel; 339 } else { 340 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1); 341 mWifiStateMachineChannel = null; 342 } 343 break; 344 } 345 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 346 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1); 347 mWifiStateMachineChannel = null; 348 //Re-establish connection to state machine 349 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 350 break; 351 } 352 default: { 353 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg); 354 break; 355 } 356 } 357 } 358 } 359 WifiStateMachineHandler mWifiStateMachineHandler; 360 361 /** 362 * Temporary for computing UIDS that are responsible for starting WIFI. 363 * Protected by mWifiStateTracker lock. 364 */ 365 private final WorkSource mTmpWorkSource = new WorkSource(); 366 private WifiWatchdogStateMachine mWifiWatchdogStateMachine; 367 368 WifiService(Context context) { 369 mContext = context; 370 371 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0"); 372 373 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName); 374 mWifiStateMachine.enableRssiPolling(true); 375 mBatteryStats = BatteryStatsService.getService(); 376 377 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 378 Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); 379 mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0); 380 381 mContext.registerReceiver( 382 new BroadcastReceiver() { 383 @Override 384 public void onReceive(Context context, Intent intent) { 385 mAirplaneModeOn.set(isAirplaneModeOn()); 386 handleAirplaneModeToggled(mAirplaneModeOn.get()); 387 updateWifiState(); 388 } 389 }, 390 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 391 392 IntentFilter filter = new IntentFilter(); 393 filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); 394 filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 395 filter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION); 396 397 mContext.registerReceiver( 398 new BroadcastReceiver() { 399 @Override 400 public void onReceive(Context context, Intent intent) { 401 if (intent.getAction().equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { 402 int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, 403 WifiManager.WIFI_STATE_DISABLED); 404 405 mWifiEnabled = (wifiState == WifiManager.WIFI_STATE_ENABLED); 406 407 // reset & clear notification on any wifi state change 408 resetNotification(); 409 } else if (intent.getAction().equals( 410 WifiManager.NETWORK_STATE_CHANGED_ACTION)) { 411 mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( 412 WifiManager.EXTRA_NETWORK_INFO); 413 // reset & clear notification on a network connect & disconnect 414 switch(mNetworkInfo.getDetailedState()) { 415 case CONNECTED: 416 case DISCONNECTED: 417 case CAPTIVE_PORTAL_CHECK: 418 evaluateTrafficStatsPolling(); 419 resetNotification(); 420 break; 421 } 422 } else if (intent.getAction().equals( 423 WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) { 424 noteScanEnd(); 425 checkAndSetNotification(); 426 } 427 } 428 }, filter); 429 430 HandlerThread wifiThread = new HandlerThread("WifiService"); 431 wifiThread.start(); 432 mAsyncServiceHandler = new AsyncServiceHandler(wifiThread.getLooper()); 433 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); 434 435 // Setting is in seconds 436 NOTIFICATION_REPEAT_DELAY_MS = Settings.Global.getInt(context.getContentResolver(), 437 Settings.Global.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, 900) * 1000l; 438 mNotificationEnabledSettingObserver = new NotificationEnabledSettingObserver(new Handler()); 439 mNotificationEnabledSettingObserver.register(); 440 } 441 442 /** Tell battery stats about a new WIFI scan */ 443 private void noteScanStart() { 444 WorkSource scanWorkSource = null; 445 synchronized (WifiService.this) { 446 if (mScanWorkSource != null) { 447 // Scan already in progress, don't add this one to battery stats 448 return; 449 } 450 scanWorkSource = new WorkSource(Binder.getCallingUid()); 451 mScanWorkSource = scanWorkSource; 452 } 453 454 long id = Binder.clearCallingIdentity(); 455 try { 456 mBatteryStats.noteWifiScanStartedFromSource(scanWorkSource); 457 } catch (RemoteException e) { 458 Log.w(TAG, e); 459 } finally { 460 Binder.restoreCallingIdentity(id); 461 } 462 } 463 464 /** Tell battery stats that the current WIFI scan has completed */ 465 private void noteScanEnd() { 466 WorkSource scanWorkSource = null; 467 synchronized (WifiService.this) { 468 scanWorkSource = mScanWorkSource; 469 mScanWorkSource = null; 470 } 471 if (scanWorkSource != null) { 472 try { 473 mBatteryStats.noteWifiScanStoppedFromSource(scanWorkSource); 474 } catch (RemoteException e) { 475 Log.w(TAG, e); 476 } 477 } 478 } 479 480 /** 481 * Check if Wi-Fi needs to be enabled and start 482 * if needed 483 * 484 * This function is used only at boot time 485 */ 486 public void checkAndStartWifi() { 487 mAirplaneModeOn.set(isAirplaneModeOn()); 488 mPersistWifiState.set(getPersistedWifiState()); 489 /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */ 490 boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState(); 491 Slog.i(TAG, "WifiService starting up with Wi-Fi " + 492 (wifiEnabled ? "enabled" : "disabled")); 493 494 // If we are already disabled (could be due to airplane mode), avoid changing persist 495 // state here 496 if (wifiEnabled) setWifiEnabled(wifiEnabled); 497 498 mWifiWatchdogStateMachine = WifiWatchdogStateMachine. 499 makeWifiWatchdogStateMachine(mContext); 500 501 } 502 503 private boolean testAndClearWifiSavedState() { 504 final ContentResolver cr = mContext.getContentResolver(); 505 int wifiSavedState = 0; 506 try { 507 wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE); 508 if(wifiSavedState == 1) 509 Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0); 510 } catch (Settings.SettingNotFoundException e) { 511 ; 512 } 513 return (wifiSavedState == 1); 514 } 515 516 private int getPersistedWifiState() { 517 final ContentResolver cr = mContext.getContentResolver(); 518 try { 519 return Settings.Global.getInt(cr, Settings.Global.WIFI_ON); 520 } catch (Settings.SettingNotFoundException e) { 521 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, WIFI_DISABLED); 522 return WIFI_DISABLED; 523 } 524 } 525 526 private boolean shouldWifiBeEnabled() { 527 if (mAirplaneModeOn.get()) { 528 return mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE; 529 } else { 530 return mPersistWifiState.get() != WIFI_DISABLED; 531 } 532 } 533 534 private void handleWifiToggled(boolean wifiEnabled) { 535 boolean airplaneEnabled = mAirplaneModeOn.get() && isAirplaneToggleable(); 536 if (wifiEnabled) { 537 if (airplaneEnabled) { 538 persistWifiState(WIFI_ENABLED_AIRPLANE_OVERRIDE); 539 } else { 540 persistWifiState(WIFI_ENABLED); 541 } 542 } else { 543 // When wifi state is disabled, we do not care 544 // if airplane mode is on or not. The scenario of 545 // wifi being disabled due to airplane mode being turned on 546 // is handled handleAirplaneModeToggled() 547 persistWifiState(WIFI_DISABLED); 548 } 549 } 550 551 private void handleAirplaneModeToggled(boolean airplaneEnabled) { 552 if (airplaneEnabled) { 553 // Wifi disabled due to airplane on 554 if (mWifiEnabled) { 555 persistWifiState(WIFI_DISABLED_AIRPLANE_ON); 556 } 557 } else { 558 /* On airplane mode disable, restore wifi state if necessary */ 559 if (testAndClearWifiSavedState() || 560 mPersistWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE) { 561 persistWifiState(WIFI_ENABLED); 562 } 563 } 564 } 565 566 private void persistWifiState(int state) { 567 final ContentResolver cr = mContext.getContentResolver(); 568 mPersistWifiState.set(state); 569 Settings.Global.putInt(cr, Settings.Global.WIFI_ON, state); 570 } 571 572 /** 573 * see {@link android.net.wifi.WifiManager#pingSupplicant()} 574 * @return {@code true} if the operation succeeds, {@code false} otherwise 575 */ 576 public boolean pingSupplicant() { 577 enforceAccessPermission(); 578 if (mWifiStateMachineChannel != null) { 579 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel); 580 } else { 581 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 582 return false; 583 } 584 } 585 586 /** 587 * see {@link android.net.wifi.WifiManager#startScan()} 588 */ 589 public void startScan(boolean forceActive) { 590 enforceChangePermission(); 591 mWifiStateMachine.startScan(forceActive); 592 noteScanStart(); 593 } 594 595 private void enforceAccessPermission() { 596 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 597 "WifiService"); 598 } 599 600 private void enforceChangePermission() { 601 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 602 "WifiService"); 603 604 } 605 606 private void enforceMulticastChangePermission() { 607 mContext.enforceCallingOrSelfPermission( 608 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 609 "WifiService"); 610 } 611 612 private void enforceConnectivityInternalPermission() { 613 mContext.enforceCallingOrSelfPermission( 614 android.Manifest.permission.CONNECTIVITY_INTERNAL, 615 "ConnectivityService"); 616 } 617 618 /** 619 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 620 * @param enable {@code true} to enable, {@code false} to disable. 621 * @return {@code true} if the enable/disable operation was 622 * started or is already in the queue. 623 */ 624 public synchronized boolean setWifiEnabled(boolean enable) { 625 enforceChangePermission(); 626 Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() 627 + ", uid=" + Binder.getCallingUid()); 628 if (DBG) { 629 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n"); 630 } 631 632 if (enable) { 633 reportStartWorkSource(); 634 } 635 mWifiStateMachine.setWifiEnabled(enable); 636 637 /* 638 * Caller might not have WRITE_SECURE_SETTINGS, 639 * only CHANGE_WIFI_STATE is enforced 640 */ 641 642 long ident = Binder.clearCallingIdentity(); 643 try { 644 handleWifiToggled(enable); 645 } finally { 646 Binder.restoreCallingIdentity(ident); 647 } 648 649 if (enable) { 650 if (!mIsReceiverRegistered) { 651 registerForBroadcasts(); 652 mIsReceiverRegistered = true; 653 } 654 } else if (mIsReceiverRegistered) { 655 mContext.unregisterReceiver(mReceiver); 656 mIsReceiverRegistered = false; 657 } 658 659 return true; 660 } 661 662 /** 663 * see {@link WifiManager#getWifiState()} 664 * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, 665 * {@link WifiManager#WIFI_STATE_DISABLING}, 666 * {@link WifiManager#WIFI_STATE_ENABLED}, 667 * {@link WifiManager#WIFI_STATE_ENABLING}, 668 * {@link WifiManager#WIFI_STATE_UNKNOWN} 669 */ 670 public int getWifiEnabledState() { 671 enforceAccessPermission(); 672 return mWifiStateMachine.syncGetWifiState(); 673 } 674 675 /** 676 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)} 677 * @param wifiConfig SSID, security and channel details as 678 * part of WifiConfiguration 679 * @param enabled true to enable and false to disable 680 */ 681 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 682 enforceChangePermission(); 683 mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled); 684 } 685 686 /** 687 * see {@link WifiManager#getWifiApState()} 688 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 689 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 690 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 691 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 692 * {@link WifiManager#WIFI_AP_STATE_FAILED} 693 */ 694 public int getWifiApEnabledState() { 695 enforceAccessPermission(); 696 return mWifiStateMachine.syncGetWifiApState(); 697 } 698 699 /** 700 * see {@link WifiManager#getWifiApConfiguration()} 701 * @return soft access point configuration 702 */ 703 public WifiConfiguration getWifiApConfiguration() { 704 enforceAccessPermission(); 705 return mWifiStateMachine.syncGetWifiApConfiguration(); 706 } 707 708 /** 709 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)} 710 * @param wifiConfig WifiConfiguration details for soft access point 711 */ 712 public void setWifiApConfiguration(WifiConfiguration wifiConfig) { 713 enforceChangePermission(); 714 if (wifiConfig == null) 715 return; 716 mWifiStateMachine.setWifiApConfiguration(wifiConfig); 717 } 718 719 /** 720 * see {@link android.net.wifi.WifiManager#disconnect()} 721 */ 722 public void disconnect() { 723 enforceChangePermission(); 724 mWifiStateMachine.disconnectCommand(); 725 } 726 727 /** 728 * see {@link android.net.wifi.WifiManager#reconnect()} 729 */ 730 public void reconnect() { 731 enforceChangePermission(); 732 mWifiStateMachine.reconnectCommand(); 733 } 734 735 /** 736 * see {@link android.net.wifi.WifiManager#reassociate()} 737 */ 738 public void reassociate() { 739 enforceChangePermission(); 740 mWifiStateMachine.reassociateCommand(); 741 } 742 743 /** 744 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 745 * @return the list of configured networks 746 */ 747 public List<WifiConfiguration> getConfiguredNetworks() { 748 enforceAccessPermission(); 749 if (mWifiStateMachineChannel != null) { 750 return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel); 751 } else { 752 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 753 return null; 754 } 755 } 756 757 /** 758 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 759 * @return the supplicant-assigned identifier for the new or updated 760 * network if the operation succeeds, or {@code -1} if it fails 761 */ 762 public int addOrUpdateNetwork(WifiConfiguration config) { 763 enforceChangePermission(); 764 if (mWifiStateMachineChannel != null) { 765 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config); 766 } else { 767 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 768 return -1; 769 } 770 } 771 772 /** 773 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 774 * @param netId the integer that identifies the network configuration 775 * to the supplicant 776 * @return {@code true} if the operation succeeded 777 */ 778 public boolean removeNetwork(int netId) { 779 enforceChangePermission(); 780 if (mWifiStateMachineChannel != null) { 781 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId); 782 } else { 783 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 784 return false; 785 } 786 } 787 788 /** 789 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 790 * @param netId the integer that identifies the network configuration 791 * to the supplicant 792 * @param disableOthers if true, disable all other networks. 793 * @return {@code true} if the operation succeeded 794 */ 795 public boolean enableNetwork(int netId, boolean disableOthers) { 796 enforceChangePermission(); 797 if (mWifiStateMachineChannel != null) { 798 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId, 799 disableOthers); 800 } else { 801 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 802 return false; 803 } 804 } 805 806 /** 807 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 808 * @param netId the integer that identifies the network configuration 809 * to the supplicant 810 * @return {@code true} if the operation succeeded 811 */ 812 public boolean disableNetwork(int netId) { 813 enforceChangePermission(); 814 if (mWifiStateMachineChannel != null) { 815 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId); 816 } else { 817 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 818 return false; 819 } 820 } 821 822 /** 823 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 824 * @return the Wi-Fi information, contained in {@link WifiInfo}. 825 */ 826 public WifiInfo getConnectionInfo() { 827 enforceAccessPermission(); 828 /* 829 * Make sure we have the latest information, by sending 830 * a status request to the supplicant. 831 */ 832 return mWifiStateMachine.syncRequestConnectionInfo(); 833 } 834 835 /** 836 * Return the results of the most recent access point scan, in the form of 837 * a list of {@link ScanResult} objects. 838 * @return the list of results 839 */ 840 public List<ScanResult> getScanResults() { 841 enforceAccessPermission(); 842 int userId = UserHandle.getCallingUserId(); 843 long ident = Binder.clearCallingIdentity(); 844 try { 845 int currentUser = ActivityManager.getCurrentUser(); 846 if (userId != currentUser) { 847 return new ArrayList<ScanResult>(); 848 } else { 849 return mWifiStateMachine.syncGetScanResultsList(); 850 } 851 } finally { 852 Binder.restoreCallingIdentity(ident); 853 } 854 } 855 856 /** 857 * Tell the supplicant to persist the current list of configured networks. 858 * @return {@code true} if the operation succeeded 859 * 860 * TODO: deprecate this 861 */ 862 public boolean saveConfiguration() { 863 boolean result = true; 864 enforceChangePermission(); 865 if (mWifiStateMachineChannel != null) { 866 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel); 867 } else { 868 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 869 return false; 870 } 871 } 872 873 /** 874 * Set the country code 875 * @param countryCode ISO 3166 country code. 876 * @param persist {@code true} if the setting should be remembered. 877 * 878 * The persist behavior exists so that wifi can fall back to the last 879 * persisted country code on a restart, when the locale information is 880 * not available from telephony. 881 */ 882 public void setCountryCode(String countryCode, boolean persist) { 883 Slog.i(TAG, "WifiService trying to set country code to " + countryCode + 884 " with persist set to " + persist); 885 enforceChangePermission(); 886 mWifiStateMachine.setCountryCode(countryCode, persist); 887 } 888 889 /** 890 * Set the operational frequency band 891 * @param band One of 892 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO}, 893 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ}, 894 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ}, 895 * @param persist {@code true} if the setting should be remembered. 896 * 897 */ 898 public void setFrequencyBand(int band, boolean persist) { 899 enforceChangePermission(); 900 if (!isDualBandSupported()) return; 901 Slog.i(TAG, "WifiService trying to set frequency band to " + band + 902 " with persist set to " + persist); 903 mWifiStateMachine.setFrequencyBand(band, persist); 904 } 905 906 907 /** 908 * Get the operational frequency band 909 */ 910 public int getFrequencyBand() { 911 enforceAccessPermission(); 912 return mWifiStateMachine.getFrequencyBand(); 913 } 914 915 public boolean isDualBandSupported() { 916 //TODO: Should move towards adding a driver API that checks at runtime 917 return mContext.getResources().getBoolean( 918 com.android.internal.R.bool.config_wifi_dual_band_support); 919 } 920 921 /** 922 * Return the DHCP-assigned addresses from the last successful DHCP request, 923 * if any. 924 * @return the DHCP information 925 */ 926 public DhcpInfo getDhcpInfo() { 927 enforceAccessPermission(); 928 return mWifiStateMachine.syncGetDhcpInfo(); 929 } 930 931 /** 932 * see {@link android.net.wifi.WifiManager#startWifi} 933 * 934 */ 935 public void startWifi() { 936 enforceConnectivityInternalPermission(); 937 /* TODO: may be add permissions for access only to connectivity service 938 * TODO: if a start issued, keep wifi alive until a stop issued irrespective 939 * of WifiLock & device idle status unless wifi enabled status is toggled 940 */ 941 942 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode); 943 mWifiStateMachine.reconnectCommand(); 944 } 945 946 public void captivePortalCheckComplete() { 947 enforceConnectivityInternalPermission(); 948 mWifiStateMachine.captivePortalCheckComplete(); 949 } 950 951 /** 952 * see {@link android.net.wifi.WifiManager#stopWifi} 953 * 954 */ 955 public void stopWifi() { 956 enforceConnectivityInternalPermission(); 957 /* 958 * TODO: if a stop is issued, wifi is brought up only by startWifi 959 * unless wifi enabled status is toggled 960 */ 961 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode); 962 } 963 964 /** 965 * see {@link android.net.wifi.WifiManager#addToBlacklist} 966 * 967 */ 968 public void addToBlacklist(String bssid) { 969 enforceChangePermission(); 970 971 mWifiStateMachine.addToBlacklist(bssid); 972 } 973 974 /** 975 * see {@link android.net.wifi.WifiManager#clearBlacklist} 976 * 977 */ 978 public void clearBlacklist() { 979 enforceChangePermission(); 980 981 mWifiStateMachine.clearBlacklist(); 982 } 983 984 /** 985 * Get a reference to handler. This is used by a client to establish 986 * an AsyncChannel communication with WifiService 987 */ 988 public Messenger getWifiServiceMessenger() { 989 enforceAccessPermission(); 990 enforceChangePermission(); 991 return new Messenger(mAsyncServiceHandler); 992 } 993 994 /** Get a reference to WifiStateMachine handler for AsyncChannel communication */ 995 public Messenger getWifiStateMachineMessenger() { 996 enforceAccessPermission(); 997 enforceChangePermission(); 998 return mWifiStateMachine.getMessenger(); 999 } 1000 1001 /** 1002 * Get the IP and proxy configuration file 1003 */ 1004 public String getConfigFile() { 1005 enforceAccessPermission(); 1006 return mWifiStateMachine.getConfigFile(); 1007 } 1008 1009 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 1010 @Override 1011 public void onReceive(Context context, Intent intent) { 1012 String action = intent.getAction(); 1013 1014 long idleMillis = 1015 Settings.Global.getLong(mContext.getContentResolver(), 1016 Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS); 1017 int stayAwakeConditions = 1018 Settings.Global.getInt(mContext.getContentResolver(), 1019 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); 1020 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1021 if (DBG) { 1022 Slog.d(TAG, "ACTION_SCREEN_ON"); 1023 } 1024 mAlarmManager.cancel(mIdleIntent); 1025 mScreenOff = false; 1026 evaluateTrafficStatsPolling(); 1027 setDeviceIdleAndUpdateWifi(false); 1028 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1029 if (DBG) { 1030 Slog.d(TAG, "ACTION_SCREEN_OFF"); 1031 } 1032 mScreenOff = true; 1033 evaluateTrafficStatsPolling(); 1034 /* 1035 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 1036 * AND the "stay on while plugged in" setting doesn't match the 1037 * current power conditions (i.e, not plugged in, plugged in to USB, 1038 * or plugged in to AC). 1039 */ 1040 if (!shouldWifiStayAwake(stayAwakeConditions, mPluggedType)) { 1041 //Delayed shutdown if wifi is connected 1042 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED) { 1043 if (DBG) Slog.d(TAG, "setting ACTION_DEVICE_IDLE: " + idleMillis + " ms"); 1044 mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() 1045 + idleMillis, mIdleIntent); 1046 } else { 1047 setDeviceIdleAndUpdateWifi(true); 1048 } 1049 } 1050 } else if (action.equals(ACTION_DEVICE_IDLE)) { 1051 setDeviceIdleAndUpdateWifi(true); 1052 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 1053 /* 1054 * Set a timer to put Wi-Fi to sleep, but only if the screen is off 1055 * AND we are transitioning from a state in which the device was supposed 1056 * to stay awake to a state in which it is not supposed to stay awake. 1057 * If "stay awake" state is not changing, we do nothing, to avoid resetting 1058 * the already-set timer. 1059 */ 1060 int pluggedType = intent.getIntExtra("plugged", 0); 1061 if (DBG) { 1062 Slog.d(TAG, "ACTION_BATTERY_CHANGED pluggedType: " + pluggedType); 1063 } 1064 if (mScreenOff && shouldWifiStayAwake(stayAwakeConditions, mPluggedType) && 1065 !shouldWifiStayAwake(stayAwakeConditions, pluggedType)) { 1066 long triggerTime = System.currentTimeMillis() + idleMillis; 1067 if (DBG) { 1068 Slog.d(TAG, "setting ACTION_DEVICE_IDLE timer for " + idleMillis + "ms"); 1069 } 1070 mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent); 1071 } 1072 1073 mPluggedType = pluggedType; 1074 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { 1075 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 1076 BluetoothAdapter.STATE_DISCONNECTED); 1077 mWifiStateMachine.sendBluetoothAdapterStateChange(state); 1078 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 1079 mEmergencyCallbackMode = intent.getBooleanExtra("phoneinECMState", false); 1080 updateWifiState(); 1081 } 1082 } 1083 1084 /** 1085 * Determines whether the Wi-Fi chipset should stay awake or be put to 1086 * sleep. Looks at the setting for the sleep policy and the current 1087 * conditions. 1088 * 1089 * @see #shouldDeviceStayAwake(int, int) 1090 */ 1091 private boolean shouldWifiStayAwake(int stayAwakeConditions, int pluggedType) { 1092 //Never sleep as long as the user has not changed the settings 1093 int wifiSleepPolicy = Settings.System.getInt(mContext.getContentResolver(), 1094 Settings.System.WIFI_SLEEP_POLICY, 1095 Settings.System.WIFI_SLEEP_POLICY_NEVER); 1096 1097 if (wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER) { 1098 // Never sleep 1099 return true; 1100 } else if ((wifiSleepPolicy == Settings.System.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && 1101 (pluggedType != 0)) { 1102 // Never sleep while plugged, and we're plugged 1103 return true; 1104 } else { 1105 // Default 1106 return shouldDeviceStayAwake(stayAwakeConditions, pluggedType); 1107 } 1108 } 1109 1110 /** 1111 * Determine whether the bit value corresponding to {@code pluggedType} is set in 1112 * the bit string {@code stayAwakeConditions}. Because a {@code pluggedType} value 1113 * of {@code 0} isn't really a plugged type, but rather an indication that the 1114 * device isn't plugged in at all, there is no bit value corresponding to a 1115 * {@code pluggedType} value of {@code 0}. That is why we shift by 1116 * {@code pluggedType - 1} instead of by {@code pluggedType}. 1117 * @param stayAwakeConditions a bit string specifying which "plugged types" should 1118 * keep the device (and hence Wi-Fi) awake. 1119 * @param pluggedType the type of plug (USB, AC, or none) for which the check is 1120 * being made 1121 * @return {@code true} if {@code pluggedType} indicates that the device is 1122 * supposed to stay awake, {@code false} otherwise. 1123 */ 1124 private boolean shouldDeviceStayAwake(int stayAwakeConditions, int pluggedType) { 1125 return (stayAwakeConditions & pluggedType) != 0; 1126 } 1127 }; 1128 1129 private void setDeviceIdleAndUpdateWifi(boolean deviceIdle) { 1130 mDeviceIdle = deviceIdle; 1131 reportStartWorkSource(); 1132 updateWifiState(); 1133 } 1134 1135 private synchronized void reportStartWorkSource() { 1136 mTmpWorkSource.clear(); 1137 if (mDeviceIdle) { 1138 for (int i=0; i<mLocks.mList.size(); i++) { 1139 mTmpWorkSource.add(mLocks.mList.get(i).mWorkSource); 1140 } 1141 } 1142 mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource); 1143 } 1144 1145 private void updateWifiState() { 1146 boolean lockHeld = mLocks.hasLocks(); 1147 int strongestLockMode = WifiManager.WIFI_MODE_FULL; 1148 boolean wifiShouldBeStarted; 1149 1150 if (mEmergencyCallbackMode) { 1151 wifiShouldBeStarted = false; 1152 } else { 1153 wifiShouldBeStarted = !mDeviceIdle || lockHeld; 1154 } 1155 1156 if (lockHeld) { 1157 strongestLockMode = mLocks.getStrongestLockMode(); 1158 } 1159 /* If device is not idle, lockmode cannot be scan only */ 1160 if (!mDeviceIdle && strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY) { 1161 strongestLockMode = WifiManager.WIFI_MODE_FULL; 1162 } 1163 1164 /* Disable tethering when airplane mode is enabled */ 1165 if (mAirplaneModeOn.get()) { 1166 mWifiStateMachine.setWifiApEnabled(null, false); 1167 } 1168 1169 if (shouldWifiBeEnabled()) { 1170 if (wifiShouldBeStarted) { 1171 reportStartWorkSource(); 1172 mWifiStateMachine.setWifiEnabled(true); 1173 mWifiStateMachine.setScanOnlyMode( 1174 strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY); 1175 mWifiStateMachine.setDriverStart(true, mEmergencyCallbackMode); 1176 mWifiStateMachine.setHighPerfModeEnabled(strongestLockMode 1177 == WifiManager.WIFI_MODE_FULL_HIGH_PERF); 1178 } else { 1179 mWifiStateMachine.setDriverStart(false, mEmergencyCallbackMode); 1180 } 1181 } else { 1182 mWifiStateMachine.setWifiEnabled(false); 1183 } 1184 } 1185 1186 private void registerForBroadcasts() { 1187 IntentFilter intentFilter = new IntentFilter(); 1188 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 1189 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 1190 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 1191 intentFilter.addAction(ACTION_DEVICE_IDLE); 1192 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 1193 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 1194 mContext.registerReceiver(mReceiver, intentFilter); 1195 } 1196 1197 private boolean isAirplaneSensitive() { 1198 String airplaneModeRadios = Settings.Global.getString(mContext.getContentResolver(), 1199 Settings.Global.AIRPLANE_MODE_RADIOS); 1200 return airplaneModeRadios == null 1201 || airplaneModeRadios.contains(Settings.Global.RADIO_WIFI); 1202 } 1203 1204 private boolean isAirplaneToggleable() { 1205 String toggleableRadios = Settings.Global.getString(mContext.getContentResolver(), 1206 Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); 1207 return toggleableRadios != null 1208 && toggleableRadios.contains(Settings.Global.RADIO_WIFI); 1209 } 1210 1211 /** 1212 * Returns true if Wi-Fi is sensitive to airplane mode, and airplane mode is 1213 * currently on. 1214 * @return {@code true} if airplane mode is on. 1215 */ 1216 private boolean isAirplaneModeOn() { 1217 return isAirplaneSensitive() && Settings.Global.getInt(mContext.getContentResolver(), 1218 Settings.Global.AIRPLANE_MODE_ON, 0) == 1; 1219 } 1220 1221 @Override 1222 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1223 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1224 != PackageManager.PERMISSION_GRANTED) { 1225 pw.println("Permission Denial: can't dump WifiService from from pid=" 1226 + Binder.getCallingPid() 1227 + ", uid=" + Binder.getCallingUid()); 1228 return; 1229 } 1230 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName()); 1231 pw.println("Stay-awake conditions: " + 1232 Settings.Global.getInt(mContext.getContentResolver(), 1233 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); 1234 pw.println(); 1235 1236 pw.println("Internal state:"); 1237 pw.println(mWifiStateMachine); 1238 pw.println(); 1239 pw.println("Latest scan results:"); 1240 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList(); 1241 if (scanResults != null && scanResults.size() != 0) { 1242 pw.println(" BSSID Frequency RSSI Flags SSID"); 1243 for (ScanResult r : scanResults) { 1244 pw.printf(" %17s %9d %5d %-16s %s%n", 1245 r.BSSID, 1246 r.frequency, 1247 r.level, 1248 r.capabilities, 1249 r.SSID == null ? "" : r.SSID); 1250 } 1251 } 1252 pw.println(); 1253 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " + 1254 mFullHighPerfLocksAcquired + " full high perf, " + 1255 mScanLocksAcquired + " scan"); 1256 pw.println("Locks released: " + mFullLocksReleased + " full, " + 1257 mFullHighPerfLocksReleased + " full high perf, " + 1258 mScanLocksReleased + " scan"); 1259 pw.println(); 1260 pw.println("Locks held:"); 1261 mLocks.dump(pw); 1262 1263 pw.println(); 1264 pw.println("WifiWatchdogStateMachine dump"); 1265 mWifiWatchdogStateMachine.dump(pw); 1266 pw.println("WifiStateMachine dump"); 1267 mWifiStateMachine.dump(fd, pw, args); 1268 } 1269 1270 private class WifiLock extends DeathRecipient { 1271 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) { 1272 super(lockMode, tag, binder, ws); 1273 } 1274 1275 public void binderDied() { 1276 synchronized (mLocks) { 1277 releaseWifiLockLocked(mBinder); 1278 } 1279 } 1280 1281 public String toString() { 1282 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}"; 1283 } 1284 } 1285 1286 private class LockList { 1287 private List<WifiLock> mList; 1288 1289 private LockList() { 1290 mList = new ArrayList<WifiLock>(); 1291 } 1292 1293 private synchronized boolean hasLocks() { 1294 return !mList.isEmpty(); 1295 } 1296 1297 private synchronized int getStrongestLockMode() { 1298 if (mList.isEmpty()) { 1299 return WifiManager.WIFI_MODE_FULL; 1300 } 1301 1302 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) { 1303 return WifiManager.WIFI_MODE_FULL_HIGH_PERF; 1304 } 1305 1306 if (mFullLocksAcquired > mFullLocksReleased) { 1307 return WifiManager.WIFI_MODE_FULL; 1308 } 1309 1310 return WifiManager.WIFI_MODE_SCAN_ONLY; 1311 } 1312 1313 private void addLock(WifiLock lock) { 1314 if (findLockByBinder(lock.mBinder) < 0) { 1315 mList.add(lock); 1316 } 1317 } 1318 1319 private WifiLock removeLock(IBinder binder) { 1320 int index = findLockByBinder(binder); 1321 if (index >= 0) { 1322 WifiLock ret = mList.remove(index); 1323 ret.unlinkDeathRecipient(); 1324 return ret; 1325 } else { 1326 return null; 1327 } 1328 } 1329 1330 private int findLockByBinder(IBinder binder) { 1331 int size = mList.size(); 1332 for (int i = size - 1; i >= 0; i--) 1333 if (mList.get(i).mBinder == binder) 1334 return i; 1335 return -1; 1336 } 1337 1338 private void dump(PrintWriter pw) { 1339 for (WifiLock l : mList) { 1340 pw.print(" "); 1341 pw.println(l); 1342 } 1343 } 1344 } 1345 1346 void enforceWakeSourcePermission(int uid, int pid) { 1347 if (uid == android.os.Process.myUid()) { 1348 return; 1349 } 1350 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 1351 pid, uid, null); 1352 } 1353 1354 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { 1355 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1356 if (lockMode != WifiManager.WIFI_MODE_FULL && 1357 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY && 1358 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) { 1359 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode); 1360 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode); 1361 return false; 1362 } 1363 if (ws != null && ws.size() == 0) { 1364 ws = null; 1365 } 1366 if (ws != null) { 1367 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid()); 1368 } 1369 if (ws == null) { 1370 ws = new WorkSource(Binder.getCallingUid()); 1371 } 1372 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws); 1373 synchronized (mLocks) { 1374 return acquireWifiLockLocked(wifiLock); 1375 } 1376 } 1377 1378 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException { 1379 switch(wifiLock.mMode) { 1380 case WifiManager.WIFI_MODE_FULL: 1381 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1382 case WifiManager.WIFI_MODE_SCAN_ONLY: 1383 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource); 1384 break; 1385 } 1386 } 1387 1388 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException { 1389 switch(wifiLock.mMode) { 1390 case WifiManager.WIFI_MODE_FULL: 1391 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1392 case WifiManager.WIFI_MODE_SCAN_ONLY: 1393 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource); 1394 break; 1395 } 1396 } 1397 1398 private boolean acquireWifiLockLocked(WifiLock wifiLock) { 1399 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock); 1400 1401 mLocks.addLock(wifiLock); 1402 1403 long ident = Binder.clearCallingIdentity(); 1404 try { 1405 noteAcquireWifiLock(wifiLock); 1406 switch(wifiLock.mMode) { 1407 case WifiManager.WIFI_MODE_FULL: 1408 ++mFullLocksAcquired; 1409 break; 1410 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1411 ++mFullHighPerfLocksAcquired; 1412 break; 1413 1414 case WifiManager.WIFI_MODE_SCAN_ONLY: 1415 ++mScanLocksAcquired; 1416 break; 1417 } 1418 1419 // Be aggressive about adding new locks into the accounted state... 1420 // we want to over-report rather than under-report. 1421 reportStartWorkSource(); 1422 1423 updateWifiState(); 1424 return true; 1425 } catch (RemoteException e) { 1426 return false; 1427 } finally { 1428 Binder.restoreCallingIdentity(ident); 1429 } 1430 } 1431 1432 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) { 1433 int uid = Binder.getCallingUid(); 1434 int pid = Binder.getCallingPid(); 1435 if (ws != null && ws.size() == 0) { 1436 ws = null; 1437 } 1438 if (ws != null) { 1439 enforceWakeSourcePermission(uid, pid); 1440 } 1441 long ident = Binder.clearCallingIdentity(); 1442 try { 1443 synchronized (mLocks) { 1444 int index = mLocks.findLockByBinder(lock); 1445 if (index < 0) { 1446 throw new IllegalArgumentException("Wifi lock not active"); 1447 } 1448 WifiLock wl = mLocks.mList.get(index); 1449 noteReleaseWifiLock(wl); 1450 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid); 1451 noteAcquireWifiLock(wl); 1452 } 1453 } catch (RemoteException e) { 1454 } finally { 1455 Binder.restoreCallingIdentity(ident); 1456 } 1457 } 1458 1459 public boolean releaseWifiLock(IBinder lock) { 1460 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1461 synchronized (mLocks) { 1462 return releaseWifiLockLocked(lock); 1463 } 1464 } 1465 1466 private boolean releaseWifiLockLocked(IBinder lock) { 1467 boolean hadLock; 1468 1469 WifiLock wifiLock = mLocks.removeLock(lock); 1470 1471 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock); 1472 1473 hadLock = (wifiLock != null); 1474 1475 long ident = Binder.clearCallingIdentity(); 1476 try { 1477 if (hadLock) { 1478 noteReleaseWifiLock(wifiLock); 1479 switch(wifiLock.mMode) { 1480 case WifiManager.WIFI_MODE_FULL: 1481 ++mFullLocksReleased; 1482 break; 1483 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1484 ++mFullHighPerfLocksReleased; 1485 break; 1486 case WifiManager.WIFI_MODE_SCAN_ONLY: 1487 ++mScanLocksReleased; 1488 break; 1489 } 1490 } 1491 1492 // TODO - should this only happen if you hadLock? 1493 updateWifiState(); 1494 1495 } catch (RemoteException e) { 1496 } finally { 1497 Binder.restoreCallingIdentity(ident); 1498 } 1499 1500 return hadLock; 1501 } 1502 1503 private abstract class DeathRecipient 1504 implements IBinder.DeathRecipient { 1505 String mTag; 1506 int mMode; 1507 IBinder mBinder; 1508 WorkSource mWorkSource; 1509 1510 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) { 1511 super(); 1512 mTag = tag; 1513 mMode = mode; 1514 mBinder = binder; 1515 mWorkSource = ws; 1516 try { 1517 mBinder.linkToDeath(this, 0); 1518 } catch (RemoteException e) { 1519 binderDied(); 1520 } 1521 } 1522 1523 void unlinkDeathRecipient() { 1524 mBinder.unlinkToDeath(this, 0); 1525 } 1526 } 1527 1528 private class Multicaster extends DeathRecipient { 1529 Multicaster(String tag, IBinder binder) { 1530 super(Binder.getCallingUid(), tag, binder, null); 1531 } 1532 1533 public void binderDied() { 1534 Slog.e(TAG, "Multicaster binderDied"); 1535 synchronized (mMulticasters) { 1536 int i = mMulticasters.indexOf(this); 1537 if (i != -1) { 1538 removeMulticasterLocked(i, mMode); 1539 } 1540 } 1541 } 1542 1543 public String toString() { 1544 return "Multicaster{" + mTag + " binder=" + mBinder + "}"; 1545 } 1546 1547 public int getUid() { 1548 return mMode; 1549 } 1550 } 1551 1552 public void initializeMulticastFiltering() { 1553 enforceMulticastChangePermission(); 1554 1555 synchronized (mMulticasters) { 1556 // if anybody had requested filters be off, leave off 1557 if (mMulticasters.size() != 0) { 1558 return; 1559 } else { 1560 mWifiStateMachine.startFilteringMulticastV4Packets(); 1561 } 1562 } 1563 } 1564 1565 public void acquireMulticastLock(IBinder binder, String tag) { 1566 enforceMulticastChangePermission(); 1567 1568 synchronized (mMulticasters) { 1569 mMulticastEnabled++; 1570 mMulticasters.add(new Multicaster(tag, binder)); 1571 // Note that we could call stopFilteringMulticastV4Packets only when 1572 // our new size == 1 (first call), but this function won't 1573 // be called often and by making the stopPacket call each 1574 // time we're less fragile and self-healing. 1575 mWifiStateMachine.stopFilteringMulticastV4Packets(); 1576 } 1577 1578 int uid = Binder.getCallingUid(); 1579 Long ident = Binder.clearCallingIdentity(); 1580 try { 1581 mBatteryStats.noteWifiMulticastEnabled(uid); 1582 } catch (RemoteException e) { 1583 } finally { 1584 Binder.restoreCallingIdentity(ident); 1585 } 1586 } 1587 1588 public void releaseMulticastLock() { 1589 enforceMulticastChangePermission(); 1590 1591 int uid = Binder.getCallingUid(); 1592 synchronized (mMulticasters) { 1593 mMulticastDisabled++; 1594 int size = mMulticasters.size(); 1595 for (int i = size - 1; i >= 0; i--) { 1596 Multicaster m = mMulticasters.get(i); 1597 if ((m != null) && (m.getUid() == uid)) { 1598 removeMulticasterLocked(i, uid); 1599 } 1600 } 1601 } 1602 } 1603 1604 private void removeMulticasterLocked(int i, int uid) 1605 { 1606 Multicaster removed = mMulticasters.remove(i); 1607 1608 if (removed != null) { 1609 removed.unlinkDeathRecipient(); 1610 } 1611 if (mMulticasters.size() == 0) { 1612 mWifiStateMachine.startFilteringMulticastV4Packets(); 1613 } 1614 1615 Long ident = Binder.clearCallingIdentity(); 1616 try { 1617 mBatteryStats.noteWifiMulticastDisabled(uid); 1618 } catch (RemoteException e) { 1619 } finally { 1620 Binder.restoreCallingIdentity(ident); 1621 } 1622 } 1623 1624 public boolean isMulticastEnabled() { 1625 enforceAccessPermission(); 1626 1627 synchronized (mMulticasters) { 1628 return (mMulticasters.size() > 0); 1629 } 1630 } 1631 1632 /** 1633 * Evaluate if traffic stats polling is needed based on 1634 * connection and screen on status 1635 */ 1636 private void evaluateTrafficStatsPolling() { 1637 Message msg; 1638 if (mNetworkInfo.getDetailedState() == DetailedState.CONNECTED && !mScreenOff) { 1639 msg = Message.obtain(mAsyncServiceHandler, 1640 WifiManager.ENABLE_TRAFFIC_STATS_POLL, 1, 0); 1641 } else { 1642 msg = Message.obtain(mAsyncServiceHandler, 1643 WifiManager.ENABLE_TRAFFIC_STATS_POLL, 0, 0); 1644 } 1645 msg.sendToTarget(); 1646 } 1647 1648 private void notifyOnDataActivity() { 1649 long sent, received; 1650 long preTxPkts = mTxPkts, preRxPkts = mRxPkts; 1651 int dataActivity = WifiManager.DATA_ACTIVITY_NONE; 1652 1653 mTxPkts = TrafficStats.getTxPackets(mInterfaceName); 1654 mRxPkts = TrafficStats.getRxPackets(mInterfaceName); 1655 1656 if (preTxPkts > 0 || preRxPkts > 0) { 1657 sent = mTxPkts - preTxPkts; 1658 received = mRxPkts - preRxPkts; 1659 if (sent > 0) { 1660 dataActivity |= WifiManager.DATA_ACTIVITY_OUT; 1661 } 1662 if (received > 0) { 1663 dataActivity |= WifiManager.DATA_ACTIVITY_IN; 1664 } 1665 1666 if (dataActivity != mDataActivity && !mScreenOff) { 1667 mDataActivity = dataActivity; 1668 for (AsyncChannel client : mClients) { 1669 client.sendMessage(WifiManager.DATA_ACTIVITY_NOTIFICATION, mDataActivity); 1670 } 1671 } 1672 } 1673 } 1674 1675 1676 private void checkAndSetNotification() { 1677 // If we shouldn't place a notification on available networks, then 1678 // don't bother doing any of the following 1679 if (!mNotificationEnabled) return; 1680 1681 State state = mNetworkInfo.getState(); 1682 if ((state == NetworkInfo.State.DISCONNECTED) 1683 || (state == NetworkInfo.State.UNKNOWN)) { 1684 // Look for an open network 1685 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList(); 1686 if (scanResults != null) { 1687 int numOpenNetworks = 0; 1688 for (int i = scanResults.size() - 1; i >= 0; i--) { 1689 ScanResult scanResult = scanResults.get(i); 1690 1691 //A capability of [ESS] represents an open access point 1692 //that is available for an STA to connect 1693 if (scanResult.capabilities != null && 1694 scanResult.capabilities.equals("[ESS]")) { 1695 numOpenNetworks++; 1696 } 1697 } 1698 1699 if (numOpenNetworks > 0) { 1700 if (++mNumScansSinceNetworkStateChange >= NUM_SCANS_BEFORE_ACTUALLY_SCANNING) { 1701 /* 1702 * We've scanned continuously at least 1703 * NUM_SCANS_BEFORE_NOTIFICATION times. The user 1704 * probably does not have a remembered network in range, 1705 * since otherwise supplicant would have tried to 1706 * associate and thus resetting this counter. 1707 */ 1708 setNotificationVisible(true, numOpenNetworks, false, 0); 1709 } 1710 return; 1711 } 1712 } 1713 } 1714 1715 // No open networks in range, remove the notification 1716 setNotificationVisible(false, 0, false, 0); 1717 } 1718 1719 /** 1720 * Clears variables related to tracking whether a notification has been 1721 * shown recently and clears the current notification. 1722 */ 1723 private void resetNotification() { 1724 mNotificationRepeatTime = 0; 1725 mNumScansSinceNetworkStateChange = 0; 1726 setNotificationVisible(false, 0, false, 0); 1727 } 1728 1729 /** 1730 * Display or don't display a notification that there are open Wi-Fi networks. 1731 * @param visible {@code true} if notification should be visible, {@code false} otherwise 1732 * @param numNetworks the number networks seen 1733 * @param force {@code true} to force notification to be shown/not-shown, 1734 * even if it is already shown/not-shown. 1735 * @param delay time in milliseconds after which the notification should be made 1736 * visible or invisible. 1737 */ 1738 private void setNotificationVisible(boolean visible, int numNetworks, boolean force, 1739 int delay) { 1740 1741 // Since we use auto cancel on the notification, when the 1742 // mNetworksAvailableNotificationShown is true, the notification may 1743 // have actually been canceled. However, when it is false we know 1744 // for sure that it is not being shown (it will not be shown any other 1745 // place than here) 1746 1747 // If it should be hidden and it is already hidden, then noop 1748 if (!visible && !mNotificationShown && !force) { 1749 return; 1750 } 1751 1752 NotificationManager notificationManager = (NotificationManager) mContext 1753 .getSystemService(Context.NOTIFICATION_SERVICE); 1754 1755 Message message; 1756 if (visible) { 1757 1758 // Not enough time has passed to show the notification again 1759 if (System.currentTimeMillis() < mNotificationRepeatTime) { 1760 return; 1761 } 1762 1763 if (mNotification == null) { 1764 // Cache the Notification object. 1765 mNotification = new Notification(); 1766 mNotification.when = 0; 1767 mNotification.icon = ICON_NETWORKS_AVAILABLE; 1768 mNotification.flags = Notification.FLAG_AUTO_CANCEL; 1769 mNotification.contentIntent = PendingIntent.getActivity(mContext, 0, 1770 new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK), 0); 1771 } 1772 1773 CharSequence title = mContext.getResources().getQuantityText( 1774 com.android.internal.R.plurals.wifi_available, numNetworks); 1775 CharSequence details = mContext.getResources().getQuantityText( 1776 com.android.internal.R.plurals.wifi_available_detailed, numNetworks); 1777 mNotification.tickerText = title; 1778 mNotification.setLatestEventInfo(mContext, title, details, mNotification.contentIntent); 1779 1780 mNotificationRepeatTime = System.currentTimeMillis() + NOTIFICATION_REPEAT_DELAY_MS; 1781 1782 notificationManager.notify(ICON_NETWORKS_AVAILABLE, mNotification); 1783 } else { 1784 notificationManager.cancel(ICON_NETWORKS_AVAILABLE); 1785 } 1786 1787 mNotificationShown = visible; 1788 } 1789 1790 private class NotificationEnabledSettingObserver extends ContentObserver { 1791 1792 public NotificationEnabledSettingObserver(Handler handler) { 1793 super(handler); 1794 } 1795 1796 public void register() { 1797 ContentResolver cr = mContext.getContentResolver(); 1798 cr.registerContentObserver(Settings.Global.getUriFor( 1799 Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON), true, this); 1800 mNotificationEnabled = getValue(); 1801 } 1802 1803 @Override 1804 public void onChange(boolean selfChange) { 1805 super.onChange(selfChange); 1806 1807 mNotificationEnabled = getValue(); 1808 resetNotification(); 1809 } 1810 1811 private boolean getValue() { 1812 return Settings.Global.getInt(mContext.getContentResolver(), 1813 Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1) == 1; 1814 } 1815 } 1816 1817 1818} 1819