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