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