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.wifi; 18 19 import android.app.ActivityManager; 20 import android.app.AppOpsManager; 21 import android.bluetooth.BluetoothAdapter; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.PackageManager; 27 import android.database.ContentObserver; 28 import android.net.wifi.IWifiManager; 29 import android.net.wifi.ScanResult; 30 import android.net.wifi.WifiInfo; 31 import android.net.wifi.WifiManager; 32 import android.net.wifi.WifiStateMachine; 33 import android.net.wifi.WifiConfiguration; 34 import android.net.wifi.WifiWatchdogStateMachine; 35 import android.net.DhcpInfo; 36 import android.net.DhcpResults; 37 import android.net.LinkAddress; 38 import android.net.NetworkUtils; 39 import android.net.RouteInfo; 40 import android.os.Binder; 41 import android.os.Handler; 42 import android.os.Messenger; 43 import android.os.HandlerThread; 44 import android.os.IBinder; 45 import android.os.INetworkManagementService; 46 import android.os.Message; 47 import android.os.RemoteException; 48 import android.os.SystemProperties; 49 import android.os.UserHandle; 50 import android.os.WorkSource; 51 import android.provider.Settings; 52 import android.util.Log; 53 import android.util.Slog; 54 55 import java.io.FileDescriptor; 56 import java.io.PrintWriter; 57 import java.net.InetAddress; 58 import java.net.Inet4Address; 59 import java.util.ArrayList; 60 import java.util.List; 61 import java.util.concurrent.atomic.AtomicBoolean; 62 63 import com.android.internal.R; 64 import com.android.internal.app.IBatteryStats; 65 import com.android.internal.telephony.TelephonyIntents; 66 import com.android.internal.util.AsyncChannel; 67 import com.android.server.am.BatteryStatsService; 68 import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED; 69 import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED; 70 import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED; 71 import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED; 72 import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED; 73 import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; 74 import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; 75 import static com.android.server.wifi.WifiController.CMD_SET_AP; 76 import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; 77 /** 78 * WifiService handles remote WiFi operation requests by implementing 79 * the IWifiManager interface. 80 * 81 * @hide 82 */ 83 public final class WifiService extends IWifiManager.Stub { 84 private static final String TAG = "WifiService"; 85 private static final boolean DBG = false; 86 87 final WifiStateMachine mWifiStateMachine; 88 89 private final Context mContext; 90 91 final LockList mLocks = new LockList(); 92 // some wifi lock statistics 93 private int mFullHighPerfLocksAcquired; 94 private int mFullHighPerfLocksReleased; 95 private int mFullLocksAcquired; 96 private int mFullLocksReleased; 97 private int mScanLocksAcquired; 98 private int mScanLocksReleased; 99 100 private final List<Multicaster> mMulticasters = 101 new ArrayList<Multicaster>(); 102 private int mMulticastEnabled; 103 private int mMulticastDisabled; 104 105 private final IBatteryStats mBatteryStats; 106 private final AppOpsManager mAppOps; 107 108 private String mInterfaceName; 109 110 /* Tracks the open wi-fi network notification */ 111 private WifiNotificationController mNotificationController; 112 /* Polls traffic stats and notifies clients */ 113 private WifiTrafficPoller mTrafficPoller; 114 /* Tracks the persisted states for wi-fi & airplane mode */ 115 final WifiSettingsStore mSettingsStore; 116 117 /** 118 * Asynchronous channel to WifiStateMachine 119 */ 120 private AsyncChannel mWifiStateMachineChannel; 121 122 /** 123 * Handles client connections 124 */ 125 private class ClientHandler extends Handler { 126 127 ClientHandler(android.os.Looper looper) { 128 super(looper); 129 } 130 131 @Override 132 public void handleMessage(Message msg) { 133 switch (msg.what) { 134 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 135 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 136 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); 137 // We track the clients by the Messenger 138 // since it is expected to be always available 139 mTrafficPoller.addClient(msg.replyTo); 140 } else { 141 Slog.e(TAG, "Client connection failure, error=" + msg.arg1); 142 } 143 break; 144 } 145 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 146 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 147 if (DBG) Slog.d(TAG, "Send failed, client connection lost"); 148 } else { 149 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); 150 } 151 mTrafficPoller.removeClient(msg.replyTo); 152 break; 153 } 154 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 155 AsyncChannel ac = new AsyncChannel(); 156 ac.connect(mContext, this, msg.replyTo); 157 break; 158 } 159 /* Client commands are forwarded to state machine */ 160 case WifiManager.CONNECT_NETWORK: 161 case WifiManager.SAVE_NETWORK: 162 case WifiManager.FORGET_NETWORK: 163 case WifiManager.START_WPS: 164 case WifiManager.CANCEL_WPS: 165 case WifiManager.DISABLE_NETWORK: 166 case WifiManager.RSSI_PKTCNT_FETCH: { 167 mWifiStateMachine.sendMessage(Message.obtain(msg)); 168 break; 169 } 170 default: { 171 Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg); 172 break; 173 } 174 } 175 } 176 } 177 private ClientHandler mClientHandler; 178 179 /** 180 * Handles interaction with WifiStateMachine 181 */ 182 private class WifiStateMachineHandler extends Handler { 183 private AsyncChannel mWsmChannel; 184 185 WifiStateMachineHandler(android.os.Looper looper) { 186 super(looper); 187 mWsmChannel = new AsyncChannel(); 188 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 189 } 190 191 @Override 192 public void handleMessage(Message msg) { 193 switch (msg.what) { 194 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 195 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 196 mWifiStateMachineChannel = mWsmChannel; 197 } else { 198 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1); 199 mWifiStateMachineChannel = null; 200 } 201 break; 202 } 203 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 204 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1); 205 mWifiStateMachineChannel = null; 206 //Re-establish connection to state machine 207 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 208 break; 209 } 210 default: { 211 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg); 212 break; 213 } 214 } 215 } 216 } 217 WifiStateMachineHandler mWifiStateMachineHandler; 218 219 private WifiWatchdogStateMachine mWifiWatchdogStateMachine; 220 221 public WifiService(Context context) { 222 mContext = context; 223 224 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0"); 225 226 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName); 227 mWifiStateMachine.enableRssiPolling(true); 228 mBatteryStats = BatteryStatsService.getService(); 229 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 230 231 mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine); 232 mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName); 233 mSettingsStore = new WifiSettingsStore(mContext); 234 235 HandlerThread wifiThread = new HandlerThread("WifiService"); 236 wifiThread.start(); 237 mClientHandler = new ClientHandler(wifiThread.getLooper()); 238 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); 239 mWifiController = new WifiController(mContext, this, wifiThread.getLooper()); 240 mWifiController.start(); 241 242 registerForScanModeChange(); 243 mContext.registerReceiver( 244 new BroadcastReceiver() { 245 @Override 246 public void onReceive(Context context, Intent intent) { 247 if (mSettingsStore.handleAirplaneModeToggled()) { 248 mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED); 249 } 250 } 251 }, 252 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 253 254 // Adding optimizations of only receiving broadcasts when wifi is enabled 255 // can result in race conditions when apps toggle wifi in the background 256 // without active user involvement. Always receive broadcasts. 257 registerForBroadcasts(); 258 } 259 260 private WifiController mWifiController; 261 262 /** 263 * Check if Wi-Fi needs to be enabled and start 264 * if needed 265 * 266 * This function is used only at boot time 267 */ 268 public void checkAndStartWifi() { 269 /* Check if wi-fi needs to be enabled */ 270 boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); 271 Slog.i(TAG, "WifiService starting up with Wi-Fi " + 272 (wifiEnabled ? "enabled" : "disabled")); 273 274 // If we are already disabled (could be due to airplane mode), avoid changing persist 275 // state here 276 if (wifiEnabled) setWifiEnabled(wifiEnabled); 277 278 mWifiWatchdogStateMachine = WifiWatchdogStateMachine. 279 makeWifiWatchdogStateMachine(mContext); 280 281 } 282 283 /** 284 * see {@link android.net.wifi.WifiManager#pingSupplicant()} 285 * @return {@code true} if the operation succeeds, {@code false} otherwise 286 */ 287 public boolean pingSupplicant() { 288 enforceAccessPermission(); 289 if (mWifiStateMachineChannel != null) { 290 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel); 291 } else { 292 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 293 return false; 294 } 295 } 296 297 /** 298 * see {@link android.net.wifi.WifiManager#startScan()} 299 */ 300 public void startScan() { 301 enforceChangePermission(); 302 mWifiStateMachine.startScan(Binder.getCallingUid()); 303 } 304 305 private void enforceAccessPermission() { 306 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 307 "WifiService"); 308 } 309 310 private void enforceChangePermission() { 311 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 312 "WifiService"); 313 314 } 315 316 private void enforceMulticastChangePermission() { 317 mContext.enforceCallingOrSelfPermission( 318 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 319 "WifiService"); 320 } 321 322 private void enforceConnectivityInternalPermission() { 323 mContext.enforceCallingOrSelfPermission( 324 android.Manifest.permission.CONNECTIVITY_INTERNAL, 325 "ConnectivityService"); 326 } 327 328 /** 329 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 330 * @param enable {@code true} to enable, {@code false} to disable. 331 * @return {@code true} if the enable/disable operation was 332 * started or is already in the queue. 333 */ 334 public synchronized boolean setWifiEnabled(boolean enable) { 335 enforceChangePermission(); 336 Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() 337 + ", uid=" + Binder.getCallingUid()); 338 if (DBG) { 339 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n"); 340 } 341 342 /* 343 * Caller might not have WRITE_SECURE_SETTINGS, 344 * only CHANGE_WIFI_STATE is enforced 345 */ 346 347 long ident = Binder.clearCallingIdentity(); 348 try { 349 if (! mSettingsStore.handleWifiToggled(enable)) { 350 // Nothing to do if wifi cannot be toggled 351 return true; 352 } 353 } finally { 354 Binder.restoreCallingIdentity(ident); 355 } 356 357 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 358 return true; 359 } 360 361 /** 362 * see {@link WifiManager#getWifiState()} 363 * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, 364 * {@link WifiManager#WIFI_STATE_DISABLING}, 365 * {@link WifiManager#WIFI_STATE_ENABLED}, 366 * {@link WifiManager#WIFI_STATE_ENABLING}, 367 * {@link WifiManager#WIFI_STATE_UNKNOWN} 368 */ 369 public int getWifiEnabledState() { 370 enforceAccessPermission(); 371 return mWifiStateMachine.syncGetWifiState(); 372 } 373 374 /** 375 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)} 376 * @param wifiConfig SSID, security and channel details as 377 * part of WifiConfiguration 378 * @param enabled true to enable and false to disable 379 */ 380 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 381 enforceChangePermission(); 382 mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget(); 383 } 384 385 /** 386 * see {@link WifiManager#getWifiApState()} 387 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 388 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 389 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 390 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 391 * {@link WifiManager#WIFI_AP_STATE_FAILED} 392 */ 393 public int getWifiApEnabledState() { 394 enforceAccessPermission(); 395 return mWifiStateMachine.syncGetWifiApState(); 396 } 397 398 /** 399 * see {@link WifiManager#getWifiApConfiguration()} 400 * @return soft access point configuration 401 */ 402 public WifiConfiguration getWifiApConfiguration() { 403 enforceAccessPermission(); 404 return mWifiStateMachine.syncGetWifiApConfiguration(); 405 } 406 407 /** 408 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)} 409 * @param wifiConfig WifiConfiguration details for soft access point 410 */ 411 public void setWifiApConfiguration(WifiConfiguration wifiConfig) { 412 enforceChangePermission(); 413 if (wifiConfig == null) 414 return; 415 mWifiStateMachine.setWifiApConfiguration(wifiConfig); 416 } 417 418 /** 419 * @param enable {@code true} to enable, {@code false} to disable. 420 * @return {@code true} if the enable/disable operation was 421 * started or is already in the queue. 422 */ 423 public boolean isScanAlwaysAvailable() { 424 enforceAccessPermission(); 425 return mSettingsStore.isScanAlwaysAvailable(); 426 } 427 428 /** 429 * see {@link android.net.wifi.WifiManager#disconnect()} 430 */ 431 public void disconnect() { 432 enforceChangePermission(); 433 mWifiStateMachine.disconnectCommand(); 434 } 435 436 /** 437 * see {@link android.net.wifi.WifiManager#reconnect()} 438 */ 439 public void reconnect() { 440 enforceChangePermission(); 441 mWifiStateMachine.reconnectCommand(); 442 } 443 444 /** 445 * see {@link android.net.wifi.WifiManager#reassociate()} 446 */ 447 public void reassociate() { 448 enforceChangePermission(); 449 mWifiStateMachine.reassociateCommand(); 450 } 451 452 /** 453 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 454 * @return the list of configured networks 455 */ 456 public List<WifiConfiguration> getConfiguredNetworks() { 457 enforceAccessPermission(); 458 if (mWifiStateMachineChannel != null) { 459 return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel); 460 } else { 461 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 462 return null; 463 } 464 } 465 466 /** 467 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 468 * @return the supplicant-assigned identifier for the new or updated 469 * network if the operation succeeds, or {@code -1} if it fails 470 */ 471 public int addOrUpdateNetwork(WifiConfiguration config) { 472 enforceChangePermission(); 473 if (mWifiStateMachineChannel != null) { 474 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config); 475 } else { 476 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 477 return -1; 478 } 479 } 480 481 /** 482 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 483 * @param netId the integer that identifies the network configuration 484 * to the supplicant 485 * @return {@code true} if the operation succeeded 486 */ 487 public boolean removeNetwork(int netId) { 488 enforceChangePermission(); 489 if (mWifiStateMachineChannel != null) { 490 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId); 491 } else { 492 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 493 return false; 494 } 495 } 496 497 /** 498 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 499 * @param netId the integer that identifies the network configuration 500 * to the supplicant 501 * @param disableOthers if true, disable all other networks. 502 * @return {@code true} if the operation succeeded 503 */ 504 public boolean enableNetwork(int netId, boolean disableOthers) { 505 enforceChangePermission(); 506 if (mWifiStateMachineChannel != null) { 507 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId, 508 disableOthers); 509 } else { 510 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 511 return false; 512 } 513 } 514 515 /** 516 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 517 * @param netId the integer that identifies the network configuration 518 * to the supplicant 519 * @return {@code true} if the operation succeeded 520 */ 521 public boolean disableNetwork(int netId) { 522 enforceChangePermission(); 523 if (mWifiStateMachineChannel != null) { 524 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId); 525 } else { 526 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 527 return false; 528 } 529 } 530 531 /** 532 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 533 * @return the Wi-Fi information, contained in {@link WifiInfo}. 534 */ 535 public WifiInfo getConnectionInfo() { 536 enforceAccessPermission(); 537 /* 538 * Make sure we have the latest information, by sending 539 * a status request to the supplicant. 540 */ 541 return mWifiStateMachine.syncRequestConnectionInfo(); 542 } 543 544 /** 545 * Return the results of the most recent access point scan, in the form of 546 * a list of {@link ScanResult} objects. 547 * @return the list of results 548 */ 549 public List<ScanResult> getScanResults(String callingPackage) { 550 enforceAccessPermission(); 551 int userId = UserHandle.getCallingUserId(); 552 int uid = Binder.getCallingUid(); 553 long ident = Binder.clearCallingIdentity(); 554 if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) 555 != AppOpsManager.MODE_ALLOWED) { 556 return new ArrayList<ScanResult>(); 557 } 558 try { 559 int currentUser = ActivityManager.getCurrentUser(); 560 if (userId != currentUser) { 561 return new ArrayList<ScanResult>(); 562 } else { 563 return mWifiStateMachine.syncGetScanResultsList(); 564 } 565 } finally { 566 Binder.restoreCallingIdentity(ident); 567 } 568 } 569 570 /** 571 * Tell the supplicant to persist the current list of configured networks. 572 * @return {@code true} if the operation succeeded 573 * 574 * TODO: deprecate this 575 */ 576 public boolean saveConfiguration() { 577 boolean result = true; 578 enforceChangePermission(); 579 if (mWifiStateMachineChannel != null) { 580 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel); 581 } else { 582 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 583 return false; 584 } 585 } 586 587 /** 588 * Set the country code 589 * @param countryCode ISO 3166 country code. 590 * @param persist {@code true} if the setting should be remembered. 591 * 592 * The persist behavior exists so that wifi can fall back to the last 593 * persisted country code on a restart, when the locale information is 594 * not available from telephony. 595 */ 596 public void setCountryCode(String countryCode, boolean persist) { 597 Slog.i(TAG, "WifiService trying to set country code to " + countryCode + 598 " with persist set to " + persist); 599 enforceChangePermission(); 600 final long token = Binder.clearCallingIdentity(); 601 try { 602 mWifiStateMachine.setCountryCode(countryCode, persist); 603 } finally { 604 Binder.restoreCallingIdentity(token); 605 } 606 } 607 608 /** 609 * Set the operational frequency band 610 * @param band One of 611 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO}, 612 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ}, 613 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ}, 614 * @param persist {@code true} if the setting should be remembered. 615 * 616 */ 617 public void setFrequencyBand(int band, boolean persist) { 618 enforceChangePermission(); 619 if (!isDualBandSupported()) return; 620 Slog.i(TAG, "WifiService trying to set frequency band to " + band + 621 " with persist set to " + persist); 622 final long token = Binder.clearCallingIdentity(); 623 try { 624 mWifiStateMachine.setFrequencyBand(band, persist); 625 } finally { 626 Binder.restoreCallingIdentity(token); 627 } 628 } 629 630 631 /** 632 * Get the operational frequency band 633 */ 634 public int getFrequencyBand() { 635 enforceAccessPermission(); 636 return mWifiStateMachine.getFrequencyBand(); 637 } 638 639 public boolean isDualBandSupported() { 640 //TODO: Should move towards adding a driver API that checks at runtime 641 return mContext.getResources().getBoolean( 642 com.android.internal.R.bool.config_wifi_dual_band_support); 643 } 644 645 /** 646 * Return the DHCP-assigned addresses from the last successful DHCP request, 647 * if any. 648 * @return the DHCP information 649 * @deprecated 650 */ 651 public DhcpInfo getDhcpInfo() { 652 enforceAccessPermission(); 653 DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults(); 654 if (dhcpResults.linkProperties == null) return null; 655 656 DhcpInfo info = new DhcpInfo(); 657 for (LinkAddress la : dhcpResults.linkProperties.getLinkAddresses()) { 658 InetAddress addr = la.getAddress(); 659 if (addr instanceof Inet4Address) { 660 info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr); 661 break; 662 } 663 } 664 for (RouteInfo r : dhcpResults.linkProperties.getRoutes()) { 665 if (r.isDefaultRoute()) { 666 InetAddress gateway = r.getGateway(); 667 if (gateway instanceof Inet4Address) { 668 info.gateway = NetworkUtils.inetAddressToInt((Inet4Address)gateway); 669 } 670 } else if (r.hasGateway() == false) { 671 LinkAddress dest = r.getDestination(); 672 if (dest.getAddress() instanceof Inet4Address) { 673 info.netmask = NetworkUtils.prefixLengthToNetmaskInt( 674 dest.getNetworkPrefixLength()); 675 } 676 } 677 } 678 int dnsFound = 0; 679 for (InetAddress dns : dhcpResults.linkProperties.getDnses()) { 680 if (dns instanceof Inet4Address) { 681 if (dnsFound == 0) { 682 info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 683 } else { 684 info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 685 } 686 if (++dnsFound > 1) break; 687 } 688 } 689 InetAddress serverAddress = dhcpResults.serverAddress; 690 if (serverAddress instanceof Inet4Address) { 691 info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress); 692 } 693 info.leaseDuration = dhcpResults.leaseDuration; 694 695 return info; 696 } 697 698 /** 699 * see {@link android.net.wifi.WifiManager#startWifi} 700 * 701 */ 702 public void startWifi() { 703 enforceConnectivityInternalPermission(); 704 /* TODO: may be add permissions for access only to connectivity service 705 * TODO: if a start issued, keep wifi alive until a stop issued irrespective 706 * of WifiLock & device idle status unless wifi enabled status is toggled 707 */ 708 709 mWifiStateMachine.setDriverStart(true); 710 mWifiStateMachine.reconnectCommand(); 711 } 712 713 public void captivePortalCheckComplete() { 714 enforceConnectivityInternalPermission(); 715 mWifiStateMachine.captivePortalCheckComplete(); 716 } 717 718 /** 719 * see {@link android.net.wifi.WifiManager#stopWifi} 720 * 721 */ 722 public void stopWifi() { 723 enforceConnectivityInternalPermission(); 724 /* 725 * TODO: if a stop is issued, wifi is brought up only by startWifi 726 * unless wifi enabled status is toggled 727 */ 728 mWifiStateMachine.setDriverStart(false); 729 } 730 731 /** 732 * see {@link android.net.wifi.WifiManager#addToBlacklist} 733 * 734 */ 735 public void addToBlacklist(String bssid) { 736 enforceChangePermission(); 737 738 mWifiStateMachine.addToBlacklist(bssid); 739 } 740 741 /** 742 * see {@link android.net.wifi.WifiManager#clearBlacklist} 743 * 744 */ 745 public void clearBlacklist() { 746 enforceChangePermission(); 747 748 mWifiStateMachine.clearBlacklist(); 749 } 750 751 /** 752 * Get a reference to handler. This is used by a client to establish 753 * an AsyncChannel communication with WifiService 754 */ 755 public Messenger getWifiServiceMessenger() { 756 enforceAccessPermission(); 757 enforceChangePermission(); 758 return new Messenger(mClientHandler); 759 } 760 761 /** Get a reference to WifiStateMachine handler for AsyncChannel communication */ 762 public Messenger getWifiStateMachineMessenger() { 763 enforceAccessPermission(); 764 enforceChangePermission(); 765 return mWifiStateMachine.getMessenger(); 766 } 767 768 /** 769 * Get the IP and proxy configuration file 770 */ 771 public String getConfigFile() { 772 enforceAccessPermission(); 773 return mWifiStateMachine.getConfigFile(); 774 } 775 776 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 777 @Override 778 public void onReceive(Context context, Intent intent) { 779 String action = intent.getAction(); 780 if (action.equals(Intent.ACTION_SCREEN_ON)) { 781 mWifiController.sendMessage(CMD_SCREEN_ON); 782 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 783 mWifiController.sendMessage(CMD_SCREEN_OFF); 784 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 785 int pluggedType = intent.getIntExtra("plugged", 0); 786 mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null); 787 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { 788 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 789 BluetoothAdapter.STATE_DISCONNECTED); 790 mWifiStateMachine.sendBluetoothAdapterStateChange(state); 791 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 792 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false); 793 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0); 794 } 795 } 796 }; 797 798 /** 799 * Observes settings changes to scan always mode. 800 */ 801 private void registerForScanModeChange() { 802 ContentObserver contentObserver = new ContentObserver(null) { 803 @Override 804 public void onChange(boolean selfChange) { 805 mSettingsStore.handleWifiScanAlwaysAvailableToggled(); 806 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED); 807 } 808 }; 809 810 mContext.getContentResolver().registerContentObserver( 811 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE), 812 false, contentObserver); 813 } 814 815 private void registerForBroadcasts() { 816 IntentFilter intentFilter = new IntentFilter(); 817 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 818 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 819 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 820 intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 821 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 822 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 823 mContext.registerReceiver(mReceiver, intentFilter); 824 } 825 826 @Override 827 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 828 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 829 != PackageManager.PERMISSION_GRANTED) { 830 pw.println("Permission Denial: can't dump WifiService from from pid=" 831 + Binder.getCallingPid() 832 + ", uid=" + Binder.getCallingUid()); 833 return; 834 } 835 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName()); 836 pw.println("Stay-awake conditions: " + 837 Settings.Global.getInt(mContext.getContentResolver(), 838 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); 839 pw.println("mMulticastEnabled " + mMulticastEnabled); 840 pw.println("mMulticastDisabled " + mMulticastDisabled); 841 mWifiController.dump(fd, pw, args); 842 mSettingsStore.dump(fd, pw, args); 843 mNotificationController.dump(fd, pw, args); 844 mTrafficPoller.dump(fd, pw, args); 845 846 pw.println("Latest scan results:"); 847 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList(); 848 if (scanResults != null && scanResults.size() != 0) { 849 pw.println(" BSSID Frequency RSSI Flags SSID"); 850 for (ScanResult r : scanResults) { 851 pw.printf(" %17s %9d %5d %-16s %s%n", 852 r.BSSID, 853 r.frequency, 854 r.level, 855 r.capabilities, 856 r.SSID == null ? "" : r.SSID); 857 } 858 } 859 pw.println(); 860 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " + 861 mFullHighPerfLocksAcquired + " full high perf, " + 862 mScanLocksAcquired + " scan"); 863 pw.println("Locks released: " + mFullLocksReleased + " full, " + 864 mFullHighPerfLocksReleased + " full high perf, " + 865 mScanLocksReleased + " scan"); 866 pw.println(); 867 pw.println("Locks held:"); 868 mLocks.dump(pw); 869 870 mWifiWatchdogStateMachine.dump(fd, pw, args); 871 pw.println(); 872 mWifiStateMachine.dump(fd, pw, args); 873 pw.println(); 874 } 875 876 private class WifiLock extends DeathRecipient { 877 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) { 878 super(lockMode, tag, binder, ws); 879 } 880 881 public void binderDied() { 882 synchronized (mLocks) { 883 releaseWifiLockLocked(mBinder); 884 } 885 } 886 887 public String toString() { 888 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}"; 889 } 890 } 891 892 class LockList { 893 private List<WifiLock> mList; 894 895 private LockList() { 896 mList = new ArrayList<WifiLock>(); 897 } 898 899 synchronized boolean hasLocks() { 900 return !mList.isEmpty(); 901 } 902 903 synchronized int getStrongestLockMode() { 904 if (mList.isEmpty()) { 905 return WifiManager.WIFI_MODE_FULL; 906 } 907 908 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) { 909 return WifiManager.WIFI_MODE_FULL_HIGH_PERF; 910 } 911 912 if (mFullLocksAcquired > mFullLocksReleased) { 913 return WifiManager.WIFI_MODE_FULL; 914 } 915 916 return WifiManager.WIFI_MODE_SCAN_ONLY; 917 } 918 919 synchronized void updateWorkSource(WorkSource ws) { 920 for (int i = 0; i < mLocks.mList.size(); i++) { 921 ws.add(mLocks.mList.get(i).mWorkSource); 922 } 923 } 924 925 private void addLock(WifiLock lock) { 926 if (findLockByBinder(lock.mBinder) < 0) { 927 mList.add(lock); 928 } 929 } 930 931 private WifiLock removeLock(IBinder binder) { 932 int index = findLockByBinder(binder); 933 if (index >= 0) { 934 WifiLock ret = mList.remove(index); 935 ret.unlinkDeathRecipient(); 936 return ret; 937 } else { 938 return null; 939 } 940 } 941 942 private int findLockByBinder(IBinder binder) { 943 int size = mList.size(); 944 for (int i = size - 1; i >= 0; i--) { 945 if (mList.get(i).mBinder == binder) 946 return i; 947 } 948 return -1; 949 } 950 951 private void dump(PrintWriter pw) { 952 for (WifiLock l : mList) { 953 pw.print(" "); 954 pw.println(l); 955 } 956 } 957 } 958 959 void enforceWakeSourcePermission(int uid, int pid) { 960 if (uid == android.os.Process.myUid()) { 961 return; 962 } 963 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 964 pid, uid, null); 965 } 966 967 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { 968 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 969 if (lockMode != WifiManager.WIFI_MODE_FULL && 970 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY && 971 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) { 972 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode); 973 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode); 974 return false; 975 } 976 if (ws != null && ws.size() == 0) { 977 ws = null; 978 } 979 if (ws != null) { 980 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid()); 981 } 982 if (ws == null) { 983 ws = new WorkSource(Binder.getCallingUid()); 984 } 985 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws); 986 synchronized (mLocks) { 987 return acquireWifiLockLocked(wifiLock); 988 } 989 } 990 991 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException { 992 switch(wifiLock.mMode) { 993 case WifiManager.WIFI_MODE_FULL: 994 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 995 case WifiManager.WIFI_MODE_SCAN_ONLY: 996 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource); 997 break; 998 } 999 } 1000 1001 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException { 1002 switch(wifiLock.mMode) { 1003 case WifiManager.WIFI_MODE_FULL: 1004 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1005 case WifiManager.WIFI_MODE_SCAN_ONLY: 1006 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource); 1007 break; 1008 } 1009 } 1010 1011 private boolean acquireWifiLockLocked(WifiLock wifiLock) { 1012 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock); 1013 1014 mLocks.addLock(wifiLock); 1015 1016 long ident = Binder.clearCallingIdentity(); 1017 try { 1018 noteAcquireWifiLock(wifiLock); 1019 switch(wifiLock.mMode) { 1020 case WifiManager.WIFI_MODE_FULL: 1021 ++mFullLocksAcquired; 1022 break; 1023 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1024 ++mFullHighPerfLocksAcquired; 1025 break; 1026 1027 case WifiManager.WIFI_MODE_SCAN_ONLY: 1028 ++mScanLocksAcquired; 1029 break; 1030 } 1031 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1032 return true; 1033 } catch (RemoteException e) { 1034 return false; 1035 } finally { 1036 Binder.restoreCallingIdentity(ident); 1037 } 1038 } 1039 1040 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) { 1041 int uid = Binder.getCallingUid(); 1042 int pid = Binder.getCallingPid(); 1043 if (ws != null && ws.size() == 0) { 1044 ws = null; 1045 } 1046 if (ws != null) { 1047 enforceWakeSourcePermission(uid, pid); 1048 } 1049 long ident = Binder.clearCallingIdentity(); 1050 try { 1051 synchronized (mLocks) { 1052 int index = mLocks.findLockByBinder(lock); 1053 if (index < 0) { 1054 throw new IllegalArgumentException("Wifi lock not active"); 1055 } 1056 WifiLock wl = mLocks.mList.get(index); 1057 noteReleaseWifiLock(wl); 1058 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid); 1059 noteAcquireWifiLock(wl); 1060 } 1061 } catch (RemoteException e) { 1062 } finally { 1063 Binder.restoreCallingIdentity(ident); 1064 } 1065 } 1066 1067 public boolean releaseWifiLock(IBinder lock) { 1068 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1069 synchronized (mLocks) { 1070 return releaseWifiLockLocked(lock); 1071 } 1072 } 1073 1074 private boolean releaseWifiLockLocked(IBinder lock) { 1075 boolean hadLock; 1076 1077 WifiLock wifiLock = mLocks.removeLock(lock); 1078 1079 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock); 1080 1081 hadLock = (wifiLock != null); 1082 1083 long ident = Binder.clearCallingIdentity(); 1084 try { 1085 if (hadLock) { 1086 noteReleaseWifiLock(wifiLock); 1087 switch(wifiLock.mMode) { 1088 case WifiManager.WIFI_MODE_FULL: 1089 ++mFullLocksReleased; 1090 break; 1091 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1092 ++mFullHighPerfLocksReleased; 1093 break; 1094 case WifiManager.WIFI_MODE_SCAN_ONLY: 1095 ++mScanLocksReleased; 1096 break; 1097 } 1098 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1099 } 1100 } catch (RemoteException e) { 1101 } finally { 1102 Binder.restoreCallingIdentity(ident); 1103 } 1104 1105 return hadLock; 1106 } 1107 1108 private abstract class DeathRecipient 1109 implements IBinder.DeathRecipient { 1110 String mTag; 1111 int mMode; 1112 IBinder mBinder; 1113 WorkSource mWorkSource; 1114 1115 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) { 1116 super(); 1117 mTag = tag; 1118 mMode = mode; 1119 mBinder = binder; 1120 mWorkSource = ws; 1121 try { 1122 mBinder.linkToDeath(this, 0); 1123 } catch (RemoteException e) { 1124 binderDied(); 1125 } 1126 } 1127 1128 void unlinkDeathRecipient() { 1129 mBinder.unlinkToDeath(this, 0); 1130 } 1131 } 1132 1133 private class Multicaster extends DeathRecipient { 1134 Multicaster(String tag, IBinder binder) { 1135 super(Binder.getCallingUid(), tag, binder, null); 1136 } 1137 1138 public void binderDied() { 1139 Slog.e(TAG, "Multicaster binderDied"); 1140 synchronized (mMulticasters) { 1141 int i = mMulticasters.indexOf(this); 1142 if (i != -1) { 1143 removeMulticasterLocked(i, mMode); 1144 } 1145 } 1146 } 1147 1148 public String toString() { 1149 return "Multicaster{" + mTag + " binder=" + mBinder + "}"; 1150 } 1151 1152 public int getUid() { 1153 return mMode; 1154 } 1155 } 1156 1157 public void initializeMulticastFiltering() { 1158 enforceMulticastChangePermission(); 1159 1160 synchronized (mMulticasters) { 1161 // if anybody had requested filters be off, leave off 1162 if (mMulticasters.size() != 0) { 1163 return; 1164 } else { 1165 mWifiStateMachine.startFilteringMulticastV4Packets(); 1166 } 1167 } 1168 } 1169 1170 public void acquireMulticastLock(IBinder binder, String tag) { 1171 enforceMulticastChangePermission(); 1172 1173 synchronized (mMulticasters) { 1174 mMulticastEnabled++; 1175 mMulticasters.add(new Multicaster(tag, binder)); 1176 // Note that we could call stopFilteringMulticastV4Packets only when 1177 // our new size == 1 (first call), but this function won't 1178 // be called often and by making the stopPacket call each 1179 // time we're less fragile and self-healing. 1180 mWifiStateMachine.stopFilteringMulticastV4Packets(); 1181 } 1182 1183 int uid = Binder.getCallingUid(); 1184 final long ident = Binder.clearCallingIdentity(); 1185 try { 1186 mBatteryStats.noteWifiMulticastEnabled(uid); 1187 } catch (RemoteException e) { 1188 } finally { 1189 Binder.restoreCallingIdentity(ident); 1190 } 1191 } 1192 1193 public void releaseMulticastLock() { 1194 enforceMulticastChangePermission(); 1195 1196 int uid = Binder.getCallingUid(); 1197 synchronized (mMulticasters) { 1198 mMulticastDisabled++; 1199 int size = mMulticasters.size(); 1200 for (int i = size - 1; i >= 0; i--) { 1201 Multicaster m = mMulticasters.get(i); 1202 if ((m != null) && (m.getUid() == uid)) { 1203 removeMulticasterLocked(i, uid); 1204 } 1205 } 1206 } 1207 } 1208 1209 private void removeMulticasterLocked(int i, int uid) 1210 { 1211 Multicaster removed = mMulticasters.remove(i); 1212 1213 if (removed != null) { 1214 removed.unlinkDeathRecipient(); 1215 } 1216 if (mMulticasters.size() == 0) { 1217 mWifiStateMachine.startFilteringMulticastV4Packets(); 1218 } 1219 1220 final long ident = Binder.clearCallingIdentity(); 1221 try { 1222 mBatteryStats.noteWifiMulticastDisabled(uid); 1223 } catch (RemoteException e) { 1224 } finally { 1225 Binder.restoreCallingIdentity(ident); 1226 } 1227 } 1228 1229 public boolean isMulticastEnabled() { 1230 enforceAccessPermission(); 1231 1232 synchronized (mMulticasters) { 1233 return (mMulticasters.size() > 0); 1234 } 1235 } 1236 } 1237