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