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