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