WifiServiceImpl.java revision 9ae6b45c038fa74a9e7285ef4834551dd93da332
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wifi; 18 19import android.app.ActivityManager; 20import android.app.AppOpsManager; 21import android.bluetooth.BluetoothAdapter; 22import android.content.BroadcastReceiver; 23import android.content.Context; 24import android.content.Intent; 25import android.content.IntentFilter; 26import android.content.pm.PackageManager; 27import android.content.pm.UserInfo; 28import android.database.ContentObserver; 29import android.net.DhcpInfo; 30import android.net.DhcpResults; 31import android.net.LinkAddress; 32import android.net.NetworkUtils; 33import android.net.RouteInfo; 34import android.net.wifi.IWifiManager; 35import android.net.wifi.ScanResult; 36import android.net.wifi.BatchedScanResult; 37import android.net.wifi.BatchedScanSettings; 38import android.net.wifi.ScanSettings; 39import android.net.wifi.WifiChannel; 40import android.net.wifi.WifiConfiguration; 41import android.net.wifi.WifiConfiguration.ProxySettings; 42import android.net.wifi.WifiInfo; 43import android.net.wifi.WifiManager; 44import android.os.Binder; 45import android.os.Handler; 46import android.os.Messenger; 47import android.os.HandlerThread; 48import android.os.IBinder; 49import android.os.Message; 50import android.os.RemoteException; 51import android.os.SystemProperties; 52import android.os.UserHandle; 53import android.os.UserManager; 54import android.os.WorkSource; 55import android.os.AsyncTask; 56import android.provider.Settings; 57import android.util.Slog; 58 59import java.io.FileNotFoundException; 60import java.io.BufferedReader; 61import java.io.FileDescriptor; 62import java.io.FileReader; 63import java.io.IOException; 64import java.io.PrintWriter; 65import java.lang.Override; 66import java.net.InetAddress; 67import java.net.Inet4Address; 68import java.util.ArrayList; 69import java.util.List; 70 71import com.android.internal.R; 72import com.android.internal.app.IBatteryStats; 73import com.android.internal.telephony.TelephonyIntents; 74import com.android.internal.util.AsyncChannel; 75import com.android.server.am.BatteryStatsService; 76 77import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED; 78import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED; 79import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED; 80import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED; 81import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED; 82import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; 83import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; 84import static com.android.server.wifi.WifiController.CMD_SET_AP; 85import static com.android.server.wifi.WifiController.CMD_USER_PRESENT; 86import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; 87/** 88 * WifiService handles remote WiFi operation requests by implementing 89 * the IWifiManager interface. 90 * 91 * @hide 92 */ 93public final class WifiServiceImpl extends IWifiManager.Stub { 94 private static final String TAG = "WifiService"; 95 private static final boolean DBG = true; 96 97 final WifiStateMachine mWifiStateMachine; 98 99 private final Context mContext; 100 101 final LockList mLocks = new LockList(); 102 // some wifi lock statistics 103 private int mFullHighPerfLocksAcquired; 104 private int mFullHighPerfLocksReleased; 105 private int mFullLocksAcquired; 106 private int mFullLocksReleased; 107 private int mScanLocksAcquired; 108 private int mScanLocksReleased; 109 110 private final List<Multicaster> mMulticasters = 111 new ArrayList<Multicaster>(); 112 private int mMulticastEnabled; 113 private int mMulticastDisabled; 114 115 private final IBatteryStats mBatteryStats; 116 private final AppOpsManager mAppOps; 117 118 private String mInterfaceName; 119 120 /* Tracks the open wi-fi network notification */ 121 private WifiNotificationController mNotificationController; 122 /* Polls traffic stats and notifies clients */ 123 private WifiTrafficPoller mTrafficPoller; 124 /* Tracks the persisted states for wi-fi & airplane mode */ 125 final WifiSettingsStore mSettingsStore; 126 127 final boolean mBatchedScanSupported; 128 129 /** 130 * Asynchronous channel to WifiStateMachine 131 */ 132 private AsyncChannel mWifiStateMachineChannel; 133 134 /** 135 * Handles client connections 136 */ 137 private class ClientHandler extends Handler { 138 139 ClientHandler(android.os.Looper looper) { 140 super(looper); 141 } 142 143 @Override 144 public void handleMessage(Message msg) { 145 switch (msg.what) { 146 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 147 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 148 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); 149 // We track the clients by the Messenger 150 // since it is expected to be always available 151 mTrafficPoller.addClient(msg.replyTo); 152 } else { 153 Slog.e(TAG, "Client connection failure, error=" + msg.arg1); 154 } 155 break; 156 } 157 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 158 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 159 if (DBG) Slog.d(TAG, "Send failed, client connection lost"); 160 } else { 161 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); 162 } 163 mTrafficPoller.removeClient(msg.replyTo); 164 break; 165 } 166 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 167 AsyncChannel ac = new AsyncChannel(); 168 ac.connect(mContext, this, msg.replyTo); 169 break; 170 } 171 /* Client commands are forwarded to state machine */ 172 case WifiManager.CONNECT_NETWORK: 173 case WifiManager.SAVE_NETWORK: { 174 WifiConfiguration config = (WifiConfiguration) msg.obj; 175 int networkId = msg.arg1; 176 if (msg.what == WifiManager.SAVE_NETWORK) 177 Slog.e("WiFiServiceImpl " , "SAVE" + " nid=" + Integer.toString(networkId)); 178 if (msg.what == WifiManager.CONNECT_NETWORK) 179 Slog.e("WiFiServiceImpl " , "CONNECT " + " nid=" + Integer.toString(networkId)); 180 if (config != null && config.isValid()) { 181 // This is restricted because there is no UI for the user to 182 // monitor/control PAC. 183 if (config.proxySettings != ProxySettings.PAC) { 184 if (DBG) Slog.d(TAG, "Connect with config" + config); 185 mWifiStateMachine.sendMessage(Message.obtain(msg)); 186 } else { 187 Slog.e(TAG, "ClientHandler.handleMessage cannot process msg with PAC"); 188 if (msg.what == WifiManager.CONNECT_NETWORK) { 189 replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED); 190 } else { 191 replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED); 192 } 193 } 194 } else if (config == null 195 && networkId != WifiConfiguration.INVALID_NETWORK_ID) { 196 if (DBG) Slog.d(TAG, "Connect with networkId" + networkId); 197 mWifiStateMachine.sendMessage(Message.obtain(msg)); 198 } else { 199 Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg); 200 if (msg.what == WifiManager.CONNECT_NETWORK) { 201 replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED); 202 } else { 203 replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED); 204 } 205 } 206 break; 207 } 208 case WifiManager.FORGET_NETWORK: 209 case WifiManager.START_WPS: 210 case WifiManager.CANCEL_WPS: 211 case WifiManager.DISABLE_NETWORK: 212 case WifiManager.RSSI_PKTCNT_FETCH: { 213 mWifiStateMachine.sendMessage(Message.obtain(msg)); 214 break; 215 } 216 default: { 217 Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg); 218 break; 219 } 220 } 221 } 222 223 private void replyFailed(Message msg, int what) { 224 Message reply = msg.obtain(); 225 reply.what = what; 226 reply.arg1 = WifiManager.INVALID_ARGS; 227 try { 228 msg.replyTo.send(reply); 229 } catch (RemoteException e) { 230 // There's not much we can do if reply can't be sent! 231 } 232 } 233 } 234 private ClientHandler mClientHandler; 235 236 /** 237 * Handles interaction with WifiStateMachine 238 */ 239 private class WifiStateMachineHandler extends Handler { 240 private AsyncChannel mWsmChannel; 241 242 WifiStateMachineHandler(android.os.Looper looper) { 243 super(looper); 244 mWsmChannel = new AsyncChannel(); 245 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 246 } 247 248 @Override 249 public void handleMessage(Message msg) { 250 switch (msg.what) { 251 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { 252 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 253 mWifiStateMachineChannel = mWsmChannel; 254 } else { 255 Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1); 256 mWifiStateMachineChannel = null; 257 } 258 break; 259 } 260 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 261 Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1); 262 mWifiStateMachineChannel = null; 263 //Re-establish connection to state machine 264 mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler()); 265 break; 266 } 267 default: { 268 Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg); 269 break; 270 } 271 } 272 } 273 } 274 275 WifiStateMachineHandler mWifiStateMachineHandler; 276 277 private WifiWatchdogStateMachine mWifiWatchdogStateMachine; 278 279 private WifiController mWifiController; 280 281 public WifiServiceImpl(Context context) { 282 mContext = context; 283 284 mInterfaceName = SystemProperties.get("wifi.interface", "wlan0"); 285 286 mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName); 287 mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller); 288 mWifiStateMachine.enableRssiPolling(true); 289 mBatteryStats = BatteryStatsService.getService(); 290 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 291 292 mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine); 293 mSettingsStore = new WifiSettingsStore(mContext); 294 295 HandlerThread wifiThread = new HandlerThread("WifiService"); 296 wifiThread.start(); 297 mClientHandler = new ClientHandler(wifiThread.getLooper()); 298 mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper()); 299 mWifiController = new WifiController(mContext, this, wifiThread.getLooper()); 300 301 mBatchedScanSupported = mContext.getResources().getBoolean( 302 R.bool.config_wifi_batched_scan_supported); 303 } 304 305 306 /** 307 * Check if Wi-Fi needs to be enabled and start 308 * if needed 309 * 310 * This function is used only at boot time 311 */ 312 public void checkAndStartWifi() { 313 /* Check if wi-fi needs to be enabled */ 314 boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled(); 315 Slog.i(TAG, "WifiService starting up with Wi-Fi " + 316 (wifiEnabled ? "enabled" : "disabled")); 317 318 registerForScanModeChange(); 319 mContext.registerReceiver( 320 new BroadcastReceiver() { 321 @Override 322 public void onReceive(Context context, Intent intent) { 323 if (mSettingsStore.handleAirplaneModeToggled()) { 324 mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED); 325 } 326 } 327 }, 328 new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED)); 329 330 // Adding optimizations of only receiving broadcasts when wifi is enabled 331 // can result in race conditions when apps toggle wifi in the background 332 // without active user involvement. Always receive broadcasts. 333 registerForBroadcasts(); 334 335 mWifiController.start(); 336 337 // If we are already disabled (could be due to airplane mode), avoid changing persist 338 // state here 339 if (wifiEnabled) setWifiEnabled(wifiEnabled); 340 341 mWifiWatchdogStateMachine = WifiWatchdogStateMachine. 342 makeWifiWatchdogStateMachine(mContext, mWifiStateMachine.getMessenger()); 343 } 344 345 /** 346 * see {@link android.net.wifi.WifiManager#pingSupplicant()} 347 * @return {@code true} if the operation succeeds, {@code false} otherwise 348 */ 349 public boolean pingSupplicant() { 350 enforceAccessPermission(); 351 if (mWifiStateMachineChannel != null) { 352 return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel); 353 } else { 354 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 355 return false; 356 } 357 } 358 359 /** 360 * see {@link android.net.wifi.WifiManager#getChannelList} 361 */ 362 public List<WifiChannel> getChannelList() { 363 enforceAccessPermission(); 364 if (mWifiStateMachineChannel != null) { 365 return mWifiStateMachine.syncGetChannelList(mWifiStateMachineChannel); 366 } else { 367 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 368 return null; 369 } 370 } 371 372 /** 373 * see {@link android.net.wifi.WifiManager#startScan} 374 * and {@link android.net.wifi.WifiManager#startCustomizedScan} 375 * 376 * @param settings If null, use default parameter, i.e. full scan. 377 * @param workSource If null, all blame is given to the calling uid. 378 */ 379 public void startScan(ScanSettings settings, WorkSource workSource) { 380 enforceChangePermission(); 381 if (settings != null) { 382 // TODO: should be removed once the startCustomizedScan API is opened up 383 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE, 384 "LocationHardware"); 385 settings = new ScanSettings(settings); 386 if (!settings.isValid()) { 387 Slog.e(TAG, "invalid scan setting"); 388 return; 389 } 390 } 391 if (workSource != null) { 392 enforceWorkSourcePermission(); 393 // WifiManager currently doesn't use names, so need to clear names out of the 394 // supplied WorkSource to allow future WorkSource combining. 395 workSource.clearNames(); 396 } 397 mWifiStateMachine.startScan(Binder.getCallingUid(), settings, workSource); 398 } 399 400 private class BatchedScanRequest extends DeathRecipient { 401 final BatchedScanSettings settings; 402 final int uid; 403 final int pid; 404 final WorkSource workSource; 405 406 BatchedScanRequest(BatchedScanSettings settings, IBinder binder, WorkSource ws) { 407 super(0, null, binder, null); 408 this.settings = settings; 409 this.uid = getCallingUid(); 410 this.pid = getCallingPid(); 411 workSource = ws; 412 } 413 public void binderDied() { 414 stopBatchedScan(settings, uid, pid); 415 } 416 public String toString() { 417 return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}"; 418 } 419 420 public boolean isSameApp(int uid, int pid) { 421 return (this.uid == uid && this.pid == pid); 422 } 423 } 424 425 private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>(); 426 427 public boolean isBatchedScanSupported() { 428 return mBatchedScanSupported; 429 } 430 431 public void pollBatchedScan() { 432 enforceChangePermission(); 433 if (mBatchedScanSupported == false) return; 434 mWifiStateMachine.requestBatchedScanPoll(); 435 } 436 437 public String getWpsNfcConfigurationToken(int netId) { 438 enforceChangePermission(); 439 return mWifiStateMachine.syncGetWpsNfcConfigurationToken(netId); 440 } 441 442 /** 443 * see {@link android.net.wifi.WifiManager#requestBatchedScan()} 444 */ 445 public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder, 446 WorkSource workSource) { 447 enforceChangePermission(); 448 if (workSource != null) { 449 enforceWorkSourcePermission(); 450 // WifiManager currently doesn't use names, so need to clear names out of the 451 // supplied WorkSource to allow future WorkSource combining. 452 workSource.clearNames(); 453 } 454 if (mBatchedScanSupported == false) return false; 455 requested = new BatchedScanSettings(requested); 456 if (requested.isInvalid()) return false; 457 BatchedScanRequest r = new BatchedScanRequest(requested, binder, workSource); 458 synchronized(mBatchedScanners) { 459 mBatchedScanners.add(r); 460 resolveBatchedScannersLocked(); 461 } 462 return true; 463 } 464 465 public List<BatchedScanResult> getBatchedScanResults(String callingPackage) { 466 enforceAccessPermission(); 467 if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>(); 468 int uid = Binder.getCallingUid(); 469 long ident = Binder.clearCallingIdentity(); 470 try { 471 if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) 472 != AppOpsManager.MODE_ALLOWED) { 473 return new ArrayList<BatchedScanResult>(); 474 } 475 if (!isCurrentProfile()) { 476 return new ArrayList<BatchedScanResult>(); 477 } 478 return mWifiStateMachine.syncGetBatchedScanResultsList(); 479 } finally { 480 Binder.restoreCallingIdentity(ident); 481 } 482 } 483 484 public void stopBatchedScan(BatchedScanSettings settings) { 485 enforceChangePermission(); 486 if (mBatchedScanSupported == false) return; 487 stopBatchedScan(settings, getCallingUid(), getCallingPid()); 488 } 489 490 private void stopBatchedScan(BatchedScanSettings settings, int uid, int pid) { 491 ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>(); 492 synchronized(mBatchedScanners) { 493 for (BatchedScanRequest r : mBatchedScanners) { 494 if (r.isSameApp(uid, pid) && (settings == null || settings.equals(r.settings))) { 495 found.add(r); 496 if (settings != null) break; 497 } 498 } 499 for (BatchedScanRequest r : found) { 500 mBatchedScanners.remove(r); 501 } 502 if (found.size() != 0) { 503 resolveBatchedScannersLocked(); 504 } 505 } 506 } 507 508 private void resolveBatchedScannersLocked() { 509 BatchedScanSettings setting = new BatchedScanSettings(); 510 WorkSource responsibleWorkSource = null; 511 int responsibleUid = 0; 512 double responsibleCsph = 0; // Channel Scans Per Hour 513 514 if (mBatchedScanners.size() == 0) { 515 mWifiStateMachine.setBatchedScanSettings(null, 0, 0, null); 516 return; 517 } 518 for (BatchedScanRequest r : mBatchedScanners) { 519 BatchedScanSettings s = r.settings; 520 521 // evaluate responsibility 522 int currentChannelCount; 523 int currentScanInterval; 524 double currentCsph; 525 526 if (s.channelSet == null || s.channelSet.isEmpty()) { 527 // all channels - 11 B and 9 A channels roughly. 528 currentChannelCount = 9 + 11; 529 } else { 530 currentChannelCount = s.channelSet.size(); 531 // these are rough est - no real need to correct for reg-domain; 532 if (s.channelSet.contains("A")) currentChannelCount += (9 - 1); 533 if (s.channelSet.contains("B")) currentChannelCount += (11 - 1); 534 535 } 536 if (s.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) { 537 currentScanInterval = BatchedScanSettings.DEFAULT_INTERVAL_SEC; 538 } else { 539 currentScanInterval = s.scanIntervalSec; 540 } 541 currentCsph = 60 * 60 * currentChannelCount / currentScanInterval; 542 543 if (currentCsph > responsibleCsph) { 544 responsibleUid = r.uid; 545 responsibleWorkSource = r.workSource; 546 responsibleCsph = currentCsph; 547 } 548 549 if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED && 550 s.maxScansPerBatch < setting.maxScansPerBatch) { 551 setting.maxScansPerBatch = s.maxScansPerBatch; 552 } 553 if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED && 554 (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED || 555 s.maxApPerScan > setting.maxApPerScan)) { 556 setting.maxApPerScan = s.maxApPerScan; 557 } 558 if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED && 559 s.scanIntervalSec < setting.scanIntervalSec) { 560 setting.scanIntervalSec = s.scanIntervalSec; 561 } 562 if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED && 563 (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED || 564 s.maxApForDistance > setting.maxApForDistance)) { 565 setting.maxApForDistance = s.maxApForDistance; 566 } 567 if (s.channelSet != null && s.channelSet.size() != 0) { 568 if (setting.channelSet == null || setting.channelSet.size() != 0) { 569 if (setting.channelSet == null) setting.channelSet = new ArrayList<String>(); 570 for (String i : s.channelSet) { 571 if (setting.channelSet.contains(i) == false) setting.channelSet.add(i); 572 } 573 } // else, ignore the constraint - we already use all channels 574 } else { 575 if (setting.channelSet == null || setting.channelSet.size() != 0) { 576 setting.channelSet = new ArrayList<String>(); 577 } 578 } 579 } 580 581 setting.constrain(); 582 mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid, (int)responsibleCsph, 583 responsibleWorkSource); 584 } 585 586 private void enforceAccessPermission() { 587 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, 588 "WifiService"); 589 } 590 591 private void enforceChangePermission() { 592 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE, 593 "WifiService"); 594 595 } 596 597 private void enforceWorkSourcePermission() { 598 mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 599 "WifiService"); 600 601 } 602 603 private void enforceMulticastChangePermission() { 604 mContext.enforceCallingOrSelfPermission( 605 android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, 606 "WifiService"); 607 } 608 609 private void enforceConnectivityInternalPermission() { 610 mContext.enforceCallingOrSelfPermission( 611 android.Manifest.permission.CONNECTIVITY_INTERNAL, 612 "ConnectivityService"); 613 } 614 615 /** 616 * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)} 617 * @param enable {@code true} to enable, {@code false} to disable. 618 * @return {@code true} if the enable/disable operation was 619 * started or is already in the queue. 620 */ 621 public synchronized boolean setWifiEnabled(boolean enable) { 622 enforceChangePermission(); 623 Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid() 624 + ", uid=" + Binder.getCallingUid()); 625 if (DBG) { 626 Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n"); 627 } 628 629 /* 630 * Caller might not have WRITE_SECURE_SETTINGS, 631 * only CHANGE_WIFI_STATE is enforced 632 */ 633 634 long ident = Binder.clearCallingIdentity(); 635 try { 636 if (! mSettingsStore.handleWifiToggled(enable)) { 637 // Nothing to do if wifi cannot be toggled 638 return true; 639 } 640 } finally { 641 Binder.restoreCallingIdentity(ident); 642 } 643 644 mWifiController.sendMessage(CMD_WIFI_TOGGLED); 645 return true; 646 } 647 648 /** 649 * see {@link WifiManager#getWifiState()} 650 * @return One of {@link WifiManager#WIFI_STATE_DISABLED}, 651 * {@link WifiManager#WIFI_STATE_DISABLING}, 652 * {@link WifiManager#WIFI_STATE_ENABLED}, 653 * {@link WifiManager#WIFI_STATE_ENABLING}, 654 * {@link WifiManager#WIFI_STATE_UNKNOWN} 655 */ 656 public int getWifiEnabledState() { 657 enforceAccessPermission(); 658 return mWifiStateMachine.syncGetWifiState(); 659 } 660 661 /** 662 * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)} 663 * @param wifiConfig SSID, security and channel details as 664 * part of WifiConfiguration 665 * @param enabled true to enable and false to disable 666 */ 667 public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) { 668 enforceChangePermission(); 669 // null wifiConfig is a meaningful input for CMD_SET_AP 670 if (wifiConfig == null || wifiConfig.isValid()) { 671 mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget(); 672 } else { 673 Slog.e(TAG, "Invalid WifiConfiguration"); 674 } 675 } 676 677 /** 678 * see {@link WifiManager#getWifiApState()} 679 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 680 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 681 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 682 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 683 * {@link WifiManager#WIFI_AP_STATE_FAILED} 684 */ 685 public int getWifiApEnabledState() { 686 enforceAccessPermission(); 687 return mWifiStateMachine.syncGetWifiApState(); 688 } 689 690 /** 691 * see {@link WifiManager#getWifiApConfiguration()} 692 * @return soft access point configuration 693 */ 694 public WifiConfiguration getWifiApConfiguration() { 695 enforceAccessPermission(); 696 return mWifiStateMachine.syncGetWifiApConfiguration(); 697 } 698 699 /** 700 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)} 701 * @param wifiConfig WifiConfiguration details for soft access point 702 */ 703 public void setWifiApConfiguration(WifiConfiguration wifiConfig) { 704 enforceChangePermission(); 705 if (wifiConfig == null) 706 return; 707 if (wifiConfig.isValid()) { 708 mWifiStateMachine.setWifiApConfiguration(wifiConfig); 709 } else { 710 Slog.e(TAG, "Invalid WifiConfiguration"); 711 } 712 } 713 714 /** 715 * @param enable {@code true} to enable, {@code false} to disable. 716 * @return {@code true} if the enable/disable operation was 717 * started or is already in the queue. 718 */ 719 public boolean isScanAlwaysAvailable() { 720 enforceAccessPermission(); 721 return mSettingsStore.isScanAlwaysAvailable(); 722 } 723 724 /** 725 * see {@link android.net.wifi.WifiManager#disconnect()} 726 */ 727 public void disconnect() { 728 enforceChangePermission(); 729 mWifiStateMachine.disconnectCommand(); 730 } 731 732 /** 733 * see {@link android.net.wifi.WifiManager#reconnect()} 734 */ 735 public void reconnect() { 736 enforceChangePermission(); 737 mWifiStateMachine.reconnectCommand(); 738 } 739 740 /** 741 * see {@link android.net.wifi.WifiManager#reassociate()} 742 */ 743 public void reassociate() { 744 enforceChangePermission(); 745 mWifiStateMachine.reassociateCommand(); 746 } 747 748 /** 749 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 750 * @return the list of configured networks 751 */ 752 public List<WifiConfiguration> getConfiguredNetworks() { 753 enforceAccessPermission(); 754 if (mWifiStateMachineChannel != null) { 755 return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel); 756 } else { 757 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 758 return null; 759 } 760 } 761 762 /** 763 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 764 * @return the supplicant-assigned identifier for the new or updated 765 * network if the operation succeeds, or {@code -1} if it fails 766 */ 767 public int addOrUpdateNetwork(WifiConfiguration config) { 768 enforceChangePermission(); 769 if (config.proxySettings == ProxySettings.PAC) { 770 enforceConnectivityInternalPermission(); 771 } 772 if (config.isValid()) { 773 if (mWifiStateMachineChannel != null) { 774 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config); 775 } else { 776 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 777 return -1; 778 } 779 } else { 780 Slog.e(TAG, "bad network configuration"); 781 return -1; 782 } 783 } 784 785 /** 786 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 787 * @param netId the integer that identifies the network configuration 788 * to the supplicant 789 * @return {@code true} if the operation succeeded 790 */ 791 public boolean removeNetwork(int netId) { 792 enforceChangePermission(); 793 if (mWifiStateMachineChannel != null) { 794 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId); 795 } else { 796 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 797 return false; 798 } 799 } 800 801 /** 802 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 803 * @param netId the integer that identifies the network configuration 804 * to the supplicant 805 * @param disableOthers if true, disable all other networks. 806 * @return {@code true} if the operation succeeded 807 */ 808 public boolean enableNetwork(int netId, boolean disableOthers) { 809 enforceChangePermission(); 810 if (mWifiStateMachineChannel != null) { 811 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId, 812 disableOthers); 813 } else { 814 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 815 return false; 816 } 817 } 818 819 /** 820 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 821 * @param netId the integer that identifies the network configuration 822 * to the supplicant 823 * @return {@code true} if the operation succeeded 824 */ 825 public boolean disableNetwork(int netId) { 826 enforceChangePermission(); 827 if (mWifiStateMachineChannel != null) { 828 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId); 829 } else { 830 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 831 return false; 832 } 833 } 834 835 /** 836 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 837 * @return the Wi-Fi information, contained in {@link WifiInfo}. 838 */ 839 public WifiInfo getConnectionInfo() { 840 enforceAccessPermission(); 841 /* 842 * Make sure we have the latest information, by sending 843 * a status request to the supplicant. 844 */ 845 return mWifiStateMachine.syncRequestConnectionInfo(); 846 } 847 848 /** 849 * Return the results of the most recent access point scan, in the form of 850 * a list of {@link ScanResult} objects. 851 * @return the list of results 852 */ 853 public List<ScanResult> getScanResults(String callingPackage) { 854 enforceAccessPermission(); 855 int userId = UserHandle.getCallingUserId(); 856 int uid = Binder.getCallingUid(); 857 long ident = Binder.clearCallingIdentity(); 858 try { 859 if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) 860 != AppOpsManager.MODE_ALLOWED) { 861 return new ArrayList<ScanResult>(); 862 } 863 if (!isCurrentProfile()) { 864 return new ArrayList<ScanResult>(); 865 } 866 return mWifiStateMachine.syncGetScanResultsList(); 867 } finally { 868 Binder.restoreCallingIdentity(ident); 869 } 870 } 871 872 /** 873 * Returns true if the calling user is the current one or a profile of the 874 * current user.. 875 */ 876 private boolean isCurrentProfile() { 877 int userId = UserHandle.getCallingUserId(); 878 int currentUser = ActivityManager.getCurrentUser(); 879 if (userId == currentUser) { 880 return true; 881 } 882 List<UserInfo> profiles = UserManager.get(mContext).getProfiles(currentUser); 883 for (UserInfo user : profiles) { 884 if (userId == user.id) { 885 return true; 886 } 887 } 888 return false; 889 } 890 891 /** 892 * Tell the supplicant to persist the current list of configured networks. 893 * @return {@code true} if the operation succeeded 894 * 895 * TODO: deprecate this 896 */ 897 public boolean saveConfiguration() { 898 boolean result = true; 899 enforceChangePermission(); 900 if (mWifiStateMachineChannel != null) { 901 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel); 902 } else { 903 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 904 return false; 905 } 906 } 907 908 /** 909 * Set the country code 910 * @param countryCode ISO 3166 country code. 911 * @param persist {@code true} if the setting should be remembered. 912 * 913 * The persist behavior exists so that wifi can fall back to the last 914 * persisted country code on a restart, when the locale information is 915 * not available from telephony. 916 */ 917 public void setCountryCode(String countryCode, boolean persist) { 918 Slog.i(TAG, "WifiService trying to set country code to " + countryCode + 919 " with persist set to " + persist); 920 enforceConnectivityInternalPermission(); 921 final long token = Binder.clearCallingIdentity(); 922 try { 923 mWifiStateMachine.setCountryCode(countryCode, persist); 924 } finally { 925 Binder.restoreCallingIdentity(token); 926 } 927 } 928 929 /** 930 * Set the operational frequency band 931 * @param band One of 932 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO}, 933 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ}, 934 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ}, 935 * @param persist {@code true} if the setting should be remembered. 936 * 937 */ 938 public void setFrequencyBand(int band, boolean persist) { 939 enforceChangePermission(); 940 if (!isDualBandSupported()) return; 941 Slog.i(TAG, "WifiService trying to set frequency band to " + band + 942 " with persist set to " + persist); 943 final long token = Binder.clearCallingIdentity(); 944 try { 945 mWifiStateMachine.setFrequencyBand(band, persist); 946 } finally { 947 Binder.restoreCallingIdentity(token); 948 } 949 } 950 951 952 /** 953 * Get the operational frequency band 954 */ 955 public int getFrequencyBand() { 956 enforceAccessPermission(); 957 return mWifiStateMachine.getFrequencyBand(); 958 } 959 960 public boolean isDualBandSupported() { 961 //TODO: Should move towards adding a driver API that checks at runtime 962 return mContext.getResources().getBoolean( 963 com.android.internal.R.bool.config_wifi_dual_band_support); 964 } 965 966 /** 967 * Return the DHCP-assigned addresses from the last successful DHCP request, 968 * if any. 969 * @return the DHCP information 970 * @deprecated 971 */ 972 public DhcpInfo getDhcpInfo() { 973 enforceAccessPermission(); 974 DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults(); 975 if (dhcpResults.linkProperties == null) return null; 976 977 DhcpInfo info = new DhcpInfo(); 978 for (LinkAddress la : dhcpResults.linkProperties.getLinkAddresses()) { 979 InetAddress addr = la.getAddress(); 980 if (addr instanceof Inet4Address) { 981 info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr); 982 break; 983 } 984 } 985 for (RouteInfo r : dhcpResults.linkProperties.getRoutes()) { 986 if (r.isDefaultRoute()) { 987 InetAddress gateway = r.getGateway(); 988 if (gateway instanceof Inet4Address) { 989 info.gateway = NetworkUtils.inetAddressToInt((Inet4Address)gateway); 990 } 991 } else if (r.hasGateway() == false) { 992 LinkAddress dest = r.getDestination(); 993 if (dest.getAddress() instanceof Inet4Address) { 994 info.netmask = NetworkUtils.prefixLengthToNetmaskInt( 995 dest.getNetworkPrefixLength()); 996 } 997 } 998 } 999 int dnsFound = 0; 1000 for (InetAddress dns : dhcpResults.linkProperties.getDnses()) { 1001 if (dns instanceof Inet4Address) { 1002 if (dnsFound == 0) { 1003 info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 1004 } else { 1005 info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 1006 } 1007 if (++dnsFound > 1) break; 1008 } 1009 } 1010 InetAddress serverAddress = dhcpResults.serverAddress; 1011 if (serverAddress instanceof Inet4Address) { 1012 info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress); 1013 } 1014 info.leaseDuration = dhcpResults.leaseDuration; 1015 1016 return info; 1017 } 1018 1019 /** 1020 * see {@link android.net.wifi.WifiManager#startWifi} 1021 * 1022 */ 1023 public void startWifi() { 1024 enforceConnectivityInternalPermission(); 1025 /* TODO: may be add permissions for access only to connectivity service 1026 * TODO: if a start issued, keep wifi alive until a stop issued irrespective 1027 * of WifiLock & device idle status unless wifi enabled status is toggled 1028 */ 1029 1030 mWifiStateMachine.setDriverStart(true); 1031 mWifiStateMachine.reconnectCommand(); 1032 } 1033 1034 /** 1035 * see {@link android.net.wifi.WifiManager#stopWifi} 1036 * 1037 */ 1038 public void stopWifi() { 1039 enforceConnectivityInternalPermission(); 1040 /* 1041 * TODO: if a stop is issued, wifi is brought up only by startWifi 1042 * unless wifi enabled status is toggled 1043 */ 1044 mWifiStateMachine.setDriverStart(false); 1045 } 1046 1047 /** 1048 * see {@link android.net.wifi.WifiManager#addToBlacklist} 1049 * 1050 */ 1051 public void addToBlacklist(String bssid) { 1052 enforceChangePermission(); 1053 1054 mWifiStateMachine.addToBlacklist(bssid); 1055 } 1056 1057 /** 1058 * see {@link android.net.wifi.WifiManager#clearBlacklist} 1059 * 1060 */ 1061 public void clearBlacklist() { 1062 enforceChangePermission(); 1063 1064 mWifiStateMachine.clearBlacklist(); 1065 } 1066 1067 /** 1068 * enable TDLS for the local NIC to remote NIC 1069 * The APPs don't know the remote MAC address to identify NIC though, 1070 * so we need to do additional work to find it from remote IP address 1071 */ 1072 1073 class TdlsTaskParams { 1074 public String remoteIpAddress; 1075 public boolean enable; 1076 } 1077 1078 class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> { 1079 @Override 1080 protected Integer doInBackground(TdlsTaskParams... params) { 1081 1082 // Retrieve parameters for the call 1083 TdlsTaskParams param = params[0]; 1084 String remoteIpAddress = param.remoteIpAddress.trim(); 1085 boolean enable = param.enable; 1086 1087 // Get MAC address of Remote IP 1088 String macAddress = null; 1089 1090 BufferedReader reader = null; 1091 1092 try { 1093 reader = new BufferedReader(new FileReader("/proc/net/arp")); 1094 1095 // Skip over the line bearing colum titles 1096 String line = reader.readLine(); 1097 1098 while ((line = reader.readLine()) != null) { 1099 String[] tokens = line.split("[ ]+"); 1100 if (tokens.length < 6) { 1101 continue; 1102 } 1103 1104 // ARP column format is 1105 // Address HWType HWAddress Flags Mask IFace 1106 String ip = tokens[0]; 1107 String mac = tokens[3]; 1108 1109 if (remoteIpAddress.equals(ip)) { 1110 macAddress = mac; 1111 break; 1112 } 1113 } 1114 1115 if (macAddress == null) { 1116 Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " + 1117 "/proc/net/arp"); 1118 } else { 1119 enableTdlsWithMacAddress(macAddress, enable); 1120 } 1121 1122 } catch (FileNotFoundException e) { 1123 Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address"); 1124 } catch (IOException e) { 1125 Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address"); 1126 } finally { 1127 try { 1128 if (reader != null) { 1129 reader.close(); 1130 } 1131 } 1132 catch (IOException e) { 1133 // Do nothing 1134 } 1135 } 1136 1137 return 0; 1138 } 1139 } 1140 1141 public void enableTdls(String remoteAddress, boolean enable) { 1142 TdlsTaskParams params = new TdlsTaskParams(); 1143 params.remoteIpAddress = remoteAddress; 1144 params.enable = enable; 1145 new TdlsTask().execute(params); 1146 } 1147 1148 1149 public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) { 1150 mWifiStateMachine.enableTdls(remoteMacAddress, enable); 1151 } 1152 1153 /** 1154 * Get a reference to handler. This is used by a client to establish 1155 * an AsyncChannel communication with WifiService 1156 */ 1157 public Messenger getWifiServiceMessenger() { 1158 enforceAccessPermission(); 1159 enforceChangePermission(); 1160 return new Messenger(mClientHandler); 1161 } 1162 1163 1164 /** 1165 * Get the IP and proxy configuration file 1166 */ 1167 public String getConfigFile() { 1168 enforceAccessPermission(); 1169 return mWifiStateMachine.getConfigFile(); 1170 } 1171 1172 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 1173 @Override 1174 public void onReceive(Context context, Intent intent) { 1175 String action = intent.getAction(); 1176 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1177 mWifiController.sendMessage(CMD_SCREEN_ON); 1178 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 1179 mWifiController.sendMessage(CMD_USER_PRESENT); 1180 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1181 mWifiController.sendMessage(CMD_SCREEN_OFF); 1182 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 1183 int pluggedType = intent.getIntExtra("plugged", 0); 1184 mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null); 1185 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { 1186 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 1187 BluetoothAdapter.STATE_DISCONNECTED); 1188 mWifiStateMachine.sendBluetoothAdapterStateChange(state); 1189 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 1190 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false); 1191 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0); 1192 } 1193 } 1194 }; 1195 1196 /** 1197 * Observes settings changes to scan always mode. 1198 */ 1199 private void registerForScanModeChange() { 1200 ContentObserver contentObserver = new ContentObserver(null) { 1201 @Override 1202 public void onChange(boolean selfChange) { 1203 mSettingsStore.handleWifiScanAlwaysAvailableToggled(); 1204 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED); 1205 } 1206 }; 1207 1208 mContext.getContentResolver().registerContentObserver( 1209 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE), 1210 false, contentObserver); 1211 } 1212 1213 private void registerForBroadcasts() { 1214 IntentFilter intentFilter = new IntentFilter(); 1215 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 1216 intentFilter.addAction(Intent.ACTION_USER_PRESENT); 1217 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 1218 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 1219 intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1220 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 1221 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 1222 mContext.registerReceiver(mReceiver, intentFilter); 1223 } 1224 1225 @Override 1226 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1227 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1228 != PackageManager.PERMISSION_GRANTED) { 1229 pw.println("Permission Denial: can't dump WifiService from from pid=" 1230 + Binder.getCallingPid() 1231 + ", uid=" + Binder.getCallingUid()); 1232 return; 1233 } 1234 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName()); 1235 pw.println("Stay-awake conditions: " + 1236 Settings.Global.getInt(mContext.getContentResolver(), 1237 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); 1238 pw.println("mMulticastEnabled " + mMulticastEnabled); 1239 pw.println("mMulticastDisabled " + mMulticastDisabled); 1240 mWifiController.dump(fd, pw, args); 1241 mSettingsStore.dump(fd, pw, args); 1242 mNotificationController.dump(fd, pw, args); 1243 mTrafficPoller.dump(fd, pw, args); 1244 1245 pw.println("Latest scan results:"); 1246 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList(); 1247 if (scanResults != null && scanResults.size() != 0) { 1248 pw.println(" BSSID Frequency RSSI Flags SSID"); 1249 for (ScanResult r : scanResults) { 1250 pw.printf(" %17s %9d %5d %-16s %s%n", 1251 r.BSSID, 1252 r.frequency, 1253 r.level, 1254 r.capabilities, 1255 r.SSID == null ? "" : r.SSID); 1256 } 1257 } 1258 pw.println(); 1259 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " + 1260 mFullHighPerfLocksAcquired + " full high perf, " + 1261 mScanLocksAcquired + " scan"); 1262 pw.println("Locks released: " + mFullLocksReleased + " full, " + 1263 mFullHighPerfLocksReleased + " full high perf, " + 1264 mScanLocksReleased + " scan"); 1265 pw.println(); 1266 pw.println("Locks held:"); 1267 mLocks.dump(pw); 1268 1269 mWifiWatchdogStateMachine.dump(fd, pw, args); 1270 pw.println(); 1271 mWifiStateMachine.dump(fd, pw, args); 1272 pw.println(); 1273 } 1274 1275 private class WifiLock extends DeathRecipient { 1276 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) { 1277 super(lockMode, tag, binder, ws); 1278 } 1279 1280 public void binderDied() { 1281 synchronized (mLocks) { 1282 releaseWifiLockLocked(mBinder); 1283 } 1284 } 1285 1286 public String toString() { 1287 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}"; 1288 } 1289 } 1290 1291 class LockList { 1292 private List<WifiLock> mList; 1293 1294 private LockList() { 1295 mList = new ArrayList<WifiLock>(); 1296 } 1297 1298 synchronized boolean hasLocks() { 1299 return !mList.isEmpty(); 1300 } 1301 1302 synchronized int getStrongestLockMode() { 1303 if (mList.isEmpty()) { 1304 return WifiManager.WIFI_MODE_FULL; 1305 } 1306 1307 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) { 1308 return WifiManager.WIFI_MODE_FULL_HIGH_PERF; 1309 } 1310 1311 if (mFullLocksAcquired > mFullLocksReleased) { 1312 return WifiManager.WIFI_MODE_FULL; 1313 } 1314 1315 return WifiManager.WIFI_MODE_SCAN_ONLY; 1316 } 1317 1318 synchronized void updateWorkSource(WorkSource ws) { 1319 for (int i = 0; i < mLocks.mList.size(); i++) { 1320 ws.add(mLocks.mList.get(i).mWorkSource); 1321 } 1322 } 1323 1324 private void addLock(WifiLock lock) { 1325 if (findLockByBinder(lock.mBinder) < 0) { 1326 mList.add(lock); 1327 } 1328 } 1329 1330 private WifiLock removeLock(IBinder binder) { 1331 int index = findLockByBinder(binder); 1332 if (index >= 0) { 1333 WifiLock ret = mList.remove(index); 1334 ret.unlinkDeathRecipient(); 1335 return ret; 1336 } else { 1337 return null; 1338 } 1339 } 1340 1341 private int findLockByBinder(IBinder binder) { 1342 int size = mList.size(); 1343 for (int i = size - 1; i >= 0; i--) { 1344 if (mList.get(i).mBinder == binder) 1345 return i; 1346 } 1347 return -1; 1348 } 1349 1350 private void dump(PrintWriter pw) { 1351 for (WifiLock l : mList) { 1352 pw.print(" "); 1353 pw.println(l); 1354 } 1355 } 1356 } 1357 1358 void enforceWakeSourcePermission(int uid, int pid) { 1359 if (uid == android.os.Process.myUid()) { 1360 return; 1361 } 1362 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 1363 pid, uid, null); 1364 } 1365 1366 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { 1367 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1368 if (lockMode != WifiManager.WIFI_MODE_FULL && 1369 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY && 1370 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) { 1371 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode); 1372 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode); 1373 return false; 1374 } 1375 if (ws != null && ws.size() == 0) { 1376 ws = null; 1377 } 1378 if (ws != null) { 1379 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid()); 1380 } 1381 if (ws == null) { 1382 ws = new WorkSource(Binder.getCallingUid()); 1383 } 1384 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws); 1385 synchronized (mLocks) { 1386 return acquireWifiLockLocked(wifiLock); 1387 } 1388 } 1389 1390 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException { 1391 switch(wifiLock.mMode) { 1392 case WifiManager.WIFI_MODE_FULL: 1393 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1394 case WifiManager.WIFI_MODE_SCAN_ONLY: 1395 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource); 1396 break; 1397 } 1398 } 1399 1400 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException { 1401 switch(wifiLock.mMode) { 1402 case WifiManager.WIFI_MODE_FULL: 1403 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1404 case WifiManager.WIFI_MODE_SCAN_ONLY: 1405 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource); 1406 break; 1407 } 1408 } 1409 1410 private boolean acquireWifiLockLocked(WifiLock wifiLock) { 1411 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock); 1412 1413 mLocks.addLock(wifiLock); 1414 1415 long ident = Binder.clearCallingIdentity(); 1416 try { 1417 noteAcquireWifiLock(wifiLock); 1418 switch(wifiLock.mMode) { 1419 case WifiManager.WIFI_MODE_FULL: 1420 ++mFullLocksAcquired; 1421 break; 1422 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1423 ++mFullHighPerfLocksAcquired; 1424 break; 1425 1426 case WifiManager.WIFI_MODE_SCAN_ONLY: 1427 ++mScanLocksAcquired; 1428 break; 1429 } 1430 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1431 return true; 1432 } catch (RemoteException e) { 1433 return false; 1434 } finally { 1435 Binder.restoreCallingIdentity(ident); 1436 } 1437 } 1438 1439 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) { 1440 int uid = Binder.getCallingUid(); 1441 int pid = Binder.getCallingPid(); 1442 if (ws != null && ws.size() == 0) { 1443 ws = null; 1444 } 1445 if (ws != null) { 1446 enforceWakeSourcePermission(uid, pid); 1447 } 1448 long ident = Binder.clearCallingIdentity(); 1449 try { 1450 synchronized (mLocks) { 1451 int index = mLocks.findLockByBinder(lock); 1452 if (index < 0) { 1453 throw new IllegalArgumentException("Wifi lock not active"); 1454 } 1455 WifiLock wl = mLocks.mList.get(index); 1456 noteReleaseWifiLock(wl); 1457 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid); 1458 noteAcquireWifiLock(wl); 1459 } 1460 } catch (RemoteException e) { 1461 } finally { 1462 Binder.restoreCallingIdentity(ident); 1463 } 1464 } 1465 1466 public boolean releaseWifiLock(IBinder lock) { 1467 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1468 synchronized (mLocks) { 1469 return releaseWifiLockLocked(lock); 1470 } 1471 } 1472 1473 private boolean releaseWifiLockLocked(IBinder lock) { 1474 boolean hadLock; 1475 1476 WifiLock wifiLock = mLocks.removeLock(lock); 1477 1478 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock); 1479 1480 hadLock = (wifiLock != null); 1481 1482 long ident = Binder.clearCallingIdentity(); 1483 try { 1484 if (hadLock) { 1485 noteReleaseWifiLock(wifiLock); 1486 switch(wifiLock.mMode) { 1487 case WifiManager.WIFI_MODE_FULL: 1488 ++mFullLocksReleased; 1489 break; 1490 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1491 ++mFullHighPerfLocksReleased; 1492 break; 1493 case WifiManager.WIFI_MODE_SCAN_ONLY: 1494 ++mScanLocksReleased; 1495 break; 1496 } 1497 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1498 } 1499 } catch (RemoteException e) { 1500 } finally { 1501 Binder.restoreCallingIdentity(ident); 1502 } 1503 1504 return hadLock; 1505 } 1506 1507 private abstract class DeathRecipient 1508 implements IBinder.DeathRecipient { 1509 String mTag; 1510 int mMode; 1511 IBinder mBinder; 1512 WorkSource mWorkSource; 1513 1514 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) { 1515 super(); 1516 mTag = tag; 1517 mMode = mode; 1518 mBinder = binder; 1519 mWorkSource = ws; 1520 try { 1521 mBinder.linkToDeath(this, 0); 1522 } catch (RemoteException e) { 1523 binderDied(); 1524 } 1525 } 1526 1527 void unlinkDeathRecipient() { 1528 mBinder.unlinkToDeath(this, 0); 1529 } 1530 } 1531 1532 private class Multicaster extends DeathRecipient { 1533 Multicaster(String tag, IBinder binder) { 1534 super(Binder.getCallingUid(), tag, binder, null); 1535 } 1536 1537 public void binderDied() { 1538 Slog.e(TAG, "Multicaster binderDied"); 1539 synchronized (mMulticasters) { 1540 int i = mMulticasters.indexOf(this); 1541 if (i != -1) { 1542 removeMulticasterLocked(i, mMode); 1543 } 1544 } 1545 } 1546 1547 public String toString() { 1548 return "Multicaster{" + mTag + " binder=" + mBinder + "}"; 1549 } 1550 1551 public int getUid() { 1552 return mMode; 1553 } 1554 } 1555 1556 public void initializeMulticastFiltering() { 1557 enforceMulticastChangePermission(); 1558 1559 synchronized (mMulticasters) { 1560 // if anybody had requested filters be off, leave off 1561 if (mMulticasters.size() != 0) { 1562 return; 1563 } else { 1564 mWifiStateMachine.startFilteringMulticastV4Packets(); 1565 } 1566 } 1567 } 1568 1569 public void acquireMulticastLock(IBinder binder, String tag) { 1570 enforceMulticastChangePermission(); 1571 1572 synchronized (mMulticasters) { 1573 mMulticastEnabled++; 1574 mMulticasters.add(new Multicaster(tag, binder)); 1575 // Note that we could call stopFilteringMulticastV4Packets only when 1576 // our new size == 1 (first call), but this function won't 1577 // be called often and by making the stopPacket call each 1578 // time we're less fragile and self-healing. 1579 mWifiStateMachine.stopFilteringMulticastV4Packets(); 1580 } 1581 1582 int uid = Binder.getCallingUid(); 1583 final long ident = Binder.clearCallingIdentity(); 1584 try { 1585 mBatteryStats.noteWifiMulticastEnabled(uid); 1586 } catch (RemoteException e) { 1587 } finally { 1588 Binder.restoreCallingIdentity(ident); 1589 } 1590 } 1591 1592 public void releaseMulticastLock() { 1593 enforceMulticastChangePermission(); 1594 1595 int uid = Binder.getCallingUid(); 1596 synchronized (mMulticasters) { 1597 mMulticastDisabled++; 1598 int size = mMulticasters.size(); 1599 for (int i = size - 1; i >= 0; i--) { 1600 Multicaster m = mMulticasters.get(i); 1601 if ((m != null) && (m.getUid() == uid)) { 1602 removeMulticasterLocked(i, uid); 1603 } 1604 } 1605 } 1606 } 1607 1608 private void removeMulticasterLocked(int i, int uid) 1609 { 1610 Multicaster removed = mMulticasters.remove(i); 1611 1612 if (removed != null) { 1613 removed.unlinkDeathRecipient(); 1614 } 1615 if (mMulticasters.size() == 0) { 1616 mWifiStateMachine.startFilteringMulticastV4Packets(); 1617 } 1618 1619 final long ident = Binder.clearCallingIdentity(); 1620 try { 1621 mBatteryStats.noteWifiMulticastDisabled(uid); 1622 } catch (RemoteException e) { 1623 } finally { 1624 Binder.restoreCallingIdentity(ident); 1625 } 1626 } 1627 1628 public boolean isMulticastEnabled() { 1629 enforceAccessPermission(); 1630 1631 synchronized (mMulticasters) { 1632 return (mMulticasters.size() > 0); 1633 } 1634 } 1635 1636 // STOPSHIP: temp solution before supplicant manager 1637 public WifiMonitor getMonitor() { 1638 return mWifiStateMachine.getMonitor(); 1639 } 1640} 1641