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