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