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