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