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