WifiServiceImpl.java revision 511a412adce5a46c41e61f90c0df6de5fb4e491c
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 // null wifiConfig is a meaningful input for CMD_SET_AP 683 if (wifiConfig == null || wifiConfig.isValid()) { 684 mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget(); 685 } else { 686 Slog.e(TAG, "Invalid WifiConfiguration"); 687 } 688 } 689 690 /** 691 * see {@link WifiManager#getWifiApState()} 692 * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED}, 693 * {@link WifiManager#WIFI_AP_STATE_DISABLING}, 694 * {@link WifiManager#WIFI_AP_STATE_ENABLED}, 695 * {@link WifiManager#WIFI_AP_STATE_ENABLING}, 696 * {@link WifiManager#WIFI_AP_STATE_FAILED} 697 */ 698 public int getWifiApEnabledState() { 699 enforceAccessPermission(); 700 return mWifiStateMachine.syncGetWifiApState(); 701 } 702 703 /** 704 * see {@link WifiManager#getWifiApConfiguration()} 705 * @return soft access point configuration 706 */ 707 public WifiConfiguration getWifiApConfiguration() { 708 enforceAccessPermission(); 709 return mWifiStateMachine.syncGetWifiApConfiguration(); 710 } 711 712 /** 713 * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)} 714 * @param wifiConfig WifiConfiguration details for soft access point 715 */ 716 public void setWifiApConfiguration(WifiConfiguration wifiConfig) { 717 enforceChangePermission(); 718 if (wifiConfig == null) 719 return; 720 if (wifiConfig.isValid()) { 721 mWifiStateMachine.setWifiApConfiguration(wifiConfig); 722 } else { 723 Slog.e(TAG, "Invalid WifiConfiguration"); 724 } 725 } 726 727 /** 728 * @param enable {@code true} to enable, {@code false} to disable. 729 * @return {@code true} if the enable/disable operation was 730 * started or is already in the queue. 731 */ 732 public boolean isScanAlwaysAvailable() { 733 enforceAccessPermission(); 734 return mSettingsStore.isScanAlwaysAvailable(); 735 } 736 737 /** 738 * see {@link android.net.wifi.WifiManager#disconnect()} 739 */ 740 public void disconnect() { 741 enforceChangePermission(); 742 mWifiStateMachine.disconnectCommand(); 743 } 744 745 /** 746 * see {@link android.net.wifi.WifiManager#reconnect()} 747 */ 748 public void reconnect() { 749 enforceChangePermission(); 750 mWifiStateMachine.reconnectCommand(); 751 } 752 753 /** 754 * see {@link android.net.wifi.WifiManager#reassociate()} 755 */ 756 public void reassociate() { 757 enforceChangePermission(); 758 mWifiStateMachine.reassociateCommand(); 759 } 760 761 /** 762 * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()} 763 * @return the list of configured networks 764 */ 765 public List<WifiConfiguration> getConfiguredNetworks() { 766 enforceAccessPermission(); 767 if (mWifiStateMachineChannel != null) { 768 return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel); 769 } else { 770 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 771 return null; 772 } 773 } 774 775 /** 776 * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)} 777 * @return the supplicant-assigned identifier for the new or updated 778 * network if the operation succeeds, or {@code -1} if it fails 779 */ 780 public int addOrUpdateNetwork(WifiConfiguration config) { 781 enforceChangePermission(); 782 if (config.isValid()) { 783 //TODO: pass the Uid the WifiStateMachine as a message parameter 784 Slog.e("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid()) 785 + " SSID " + config.SSID 786 + " nid=" + Integer.toString(config.networkId)); 787 if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) { 788 config.creatorUid = Binder.getCallingUid(); 789 } else { 790 config.lastUpdateUid = Binder.getCallingUid(); 791 } 792 if (mWifiStateMachineChannel != null) { 793 return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config); 794 } else { 795 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 796 return -1; 797 } 798 } else { 799 Slog.e(TAG, "bad network configuration"); 800 return -1; 801 } 802 } 803 804 /** 805 * See {@link android.net.wifi.WifiManager#removeNetwork(int)} 806 * @param netId the integer that identifies the network configuration 807 * to the supplicant 808 * @return {@code true} if the operation succeeded 809 */ 810 public boolean removeNetwork(int netId) { 811 enforceChangePermission(); 812 if (mWifiStateMachineChannel != null) { 813 return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId); 814 } else { 815 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 816 return false; 817 } 818 } 819 820 /** 821 * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)} 822 * @param netId the integer that identifies the network configuration 823 * to the supplicant 824 * @param disableOthers if true, disable all other networks. 825 * @return {@code true} if the operation succeeded 826 */ 827 public boolean enableNetwork(int netId, boolean disableOthers) { 828 enforceChangePermission(); 829 if (mWifiStateMachineChannel != null) { 830 return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId, 831 disableOthers); 832 } else { 833 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 834 return false; 835 } 836 } 837 838 /** 839 * See {@link android.net.wifi.WifiManager#disableNetwork(int)} 840 * @param netId the integer that identifies the network configuration 841 * to the supplicant 842 * @return {@code true} if the operation succeeded 843 */ 844 public boolean disableNetwork(int netId) { 845 enforceChangePermission(); 846 if (mWifiStateMachineChannel != null) { 847 return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId); 848 } else { 849 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 850 return false; 851 } 852 } 853 854 /** 855 * See {@link android.net.wifi.WifiManager#getConnectionInfo()} 856 * @return the Wi-Fi information, contained in {@link WifiInfo}. 857 */ 858 public WifiInfo getConnectionInfo() { 859 enforceAccessPermission(); 860 /* 861 * Make sure we have the latest information, by sending 862 * a status request to the supplicant. 863 */ 864 return mWifiStateMachine.syncRequestConnectionInfo(); 865 } 866 867 /** 868 * Return the results of the most recent access point scan, in the form of 869 * a list of {@link ScanResult} objects. 870 * @return the list of results 871 */ 872 public List<ScanResult> getScanResults(String callingPackage) { 873 enforceAccessPermission(); 874 int userId = UserHandle.getCallingUserId(); 875 int uid = Binder.getCallingUid(); 876 long ident = Binder.clearCallingIdentity(); 877 try { 878 if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage) 879 != AppOpsManager.MODE_ALLOWED) { 880 return new ArrayList<ScanResult>(); 881 } 882 if (!isCurrentProfile()) { 883 return new ArrayList<ScanResult>(); 884 } 885 return mWifiStateMachine.syncGetScanResultsList(); 886 } finally { 887 Binder.restoreCallingIdentity(ident); 888 } 889 } 890 891 /** 892 * Returns true if the calling user is the current one or a profile of the 893 * current user.. 894 */ 895 private boolean isCurrentProfile() { 896 int userId = UserHandle.getCallingUserId(); 897 int currentUser = ActivityManager.getCurrentUser(); 898 if (userId == currentUser) { 899 return true; 900 } 901 List<UserInfo> profiles = UserManager.get(mContext).getProfiles(currentUser); 902 for (UserInfo user : profiles) { 903 if (userId == user.id) { 904 return true; 905 } 906 } 907 return false; 908 } 909 910 /** 911 * Tell the supplicant to persist the current list of configured networks. 912 * @return {@code true} if the operation succeeded 913 * 914 * TODO: deprecate this 915 */ 916 public boolean saveConfiguration() { 917 boolean result = true; 918 enforceChangePermission(); 919 if (mWifiStateMachineChannel != null) { 920 return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel); 921 } else { 922 Slog.e(TAG, "mWifiStateMachineChannel is not initialized"); 923 return false; 924 } 925 } 926 927 /** 928 * Set the country code 929 * @param countryCode ISO 3166 country code. 930 * @param persist {@code true} if the setting should be remembered. 931 * 932 * The persist behavior exists so that wifi can fall back to the last 933 * persisted country code on a restart, when the locale information is 934 * not available from telephony. 935 */ 936 public void setCountryCode(String countryCode, boolean persist) { 937 Slog.i(TAG, "WifiService trying to set country code to " + countryCode + 938 " with persist set to " + persist); 939 enforceConnectivityInternalPermission(); 940 final long token = Binder.clearCallingIdentity(); 941 try { 942 mWifiStateMachine.setCountryCode(countryCode, persist); 943 } finally { 944 Binder.restoreCallingIdentity(token); 945 } 946 } 947 948 /** 949 * Set the operational frequency band 950 * @param band One of 951 * {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO}, 952 * {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ}, 953 * {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ}, 954 * @param persist {@code true} if the setting should be remembered. 955 * 956 */ 957 public void setFrequencyBand(int band, boolean persist) { 958 enforceChangePermission(); 959 if (!isDualBandSupported()) return; 960 Slog.i(TAG, "WifiService trying to set frequency band to " + band + 961 " with persist set to " + persist); 962 final long token = Binder.clearCallingIdentity(); 963 try { 964 mWifiStateMachine.setFrequencyBand(band, persist); 965 } finally { 966 Binder.restoreCallingIdentity(token); 967 } 968 } 969 970 971 /** 972 * Get the operational frequency band 973 */ 974 public int getFrequencyBand() { 975 enforceAccessPermission(); 976 return mWifiStateMachine.getFrequencyBand(); 977 } 978 979 public boolean isDualBandSupported() { 980 //TODO: Should move towards adding a driver API that checks at runtime 981 return mContext.getResources().getBoolean( 982 com.android.internal.R.bool.config_wifi_dual_band_support); 983 } 984 985 /** 986 * Return the DHCP-assigned addresses from the last successful DHCP request, 987 * if any. 988 * @return the DHCP information 989 * @deprecated 990 */ 991 public DhcpInfo getDhcpInfo() { 992 enforceAccessPermission(); 993 DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults(); 994 if (dhcpResults.linkProperties == null) return null; 995 996 DhcpInfo info = new DhcpInfo(); 997 for (LinkAddress la : dhcpResults.linkProperties.getLinkAddresses()) { 998 InetAddress addr = la.getAddress(); 999 if (addr instanceof Inet4Address) { 1000 info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address)addr); 1001 break; 1002 } 1003 } 1004 for (RouteInfo r : dhcpResults.linkProperties.getRoutes()) { 1005 if (r.isDefaultRoute()) { 1006 InetAddress gateway = r.getGateway(); 1007 if (gateway instanceof Inet4Address) { 1008 info.gateway = NetworkUtils.inetAddressToInt((Inet4Address)gateway); 1009 } 1010 } else if (r.hasGateway() == false) { 1011 LinkAddress dest = r.getDestination(); 1012 if (dest.getAddress() instanceof Inet4Address) { 1013 info.netmask = NetworkUtils.prefixLengthToNetmaskInt( 1014 dest.getNetworkPrefixLength()); 1015 } 1016 } 1017 } 1018 int dnsFound = 0; 1019 for (InetAddress dns : dhcpResults.linkProperties.getDnses()) { 1020 if (dns instanceof Inet4Address) { 1021 if (dnsFound == 0) { 1022 info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 1023 } else { 1024 info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns); 1025 } 1026 if (++dnsFound > 1) break; 1027 } 1028 } 1029 InetAddress serverAddress = dhcpResults.serverAddress; 1030 if (serverAddress instanceof Inet4Address) { 1031 info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress); 1032 } 1033 info.leaseDuration = dhcpResults.leaseDuration; 1034 1035 return info; 1036 } 1037 1038 /** 1039 * see {@link android.net.wifi.WifiManager#startWifi} 1040 * 1041 */ 1042 public void startWifi() { 1043 enforceConnectivityInternalPermission(); 1044 /* TODO: may be add permissions for access only to connectivity service 1045 * TODO: if a start issued, keep wifi alive until a stop issued irrespective 1046 * of WifiLock & device idle status unless wifi enabled status is toggled 1047 */ 1048 1049 mWifiStateMachine.setDriverStart(true); 1050 mWifiStateMachine.reconnectCommand(); 1051 } 1052 1053 /** 1054 * see {@link android.net.wifi.WifiManager#stopWifi} 1055 * 1056 */ 1057 public void stopWifi() { 1058 enforceConnectivityInternalPermission(); 1059 /* 1060 * TODO: if a stop is issued, wifi is brought up only by startWifi 1061 * unless wifi enabled status is toggled 1062 */ 1063 mWifiStateMachine.setDriverStart(false); 1064 } 1065 1066 /** 1067 * see {@link android.net.wifi.WifiManager#addToBlacklist} 1068 * 1069 */ 1070 public void addToBlacklist(String bssid) { 1071 enforceChangePermission(); 1072 1073 mWifiStateMachine.addToBlacklist(bssid); 1074 } 1075 1076 /** 1077 * see {@link android.net.wifi.WifiManager#clearBlacklist} 1078 * 1079 */ 1080 public void clearBlacklist() { 1081 enforceChangePermission(); 1082 1083 mWifiStateMachine.clearBlacklist(); 1084 } 1085 1086 /** 1087 * enable TDLS for the local NIC to remote NIC 1088 * The APPs don't know the remote MAC address to identify NIC though, 1089 * so we need to do additional work to find it from remote IP address 1090 */ 1091 1092 class TdlsTaskParams { 1093 public String remoteIpAddress; 1094 public boolean enable; 1095 } 1096 1097 class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> { 1098 @Override 1099 protected Integer doInBackground(TdlsTaskParams... params) { 1100 1101 // Retrieve parameters for the call 1102 TdlsTaskParams param = params[0]; 1103 String remoteIpAddress = param.remoteIpAddress.trim(); 1104 boolean enable = param.enable; 1105 1106 // Get MAC address of Remote IP 1107 String macAddress = null; 1108 1109 BufferedReader reader = null; 1110 1111 try { 1112 reader = new BufferedReader(new FileReader("/proc/net/arp")); 1113 1114 // Skip over the line bearing colum titles 1115 String line = reader.readLine(); 1116 1117 while ((line = reader.readLine()) != null) { 1118 String[] tokens = line.split("[ ]+"); 1119 if (tokens.length < 6) { 1120 continue; 1121 } 1122 1123 // ARP column format is 1124 // Address HWType HWAddress Flags Mask IFace 1125 String ip = tokens[0]; 1126 String mac = tokens[3]; 1127 1128 if (remoteIpAddress.equals(ip)) { 1129 macAddress = mac; 1130 break; 1131 } 1132 } 1133 1134 if (macAddress == null) { 1135 Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " + 1136 "/proc/net/arp"); 1137 } else { 1138 enableTdlsWithMacAddress(macAddress, enable); 1139 } 1140 1141 } catch (FileNotFoundException e) { 1142 Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address"); 1143 } catch (IOException e) { 1144 Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address"); 1145 } finally { 1146 try { 1147 if (reader != null) { 1148 reader.close(); 1149 } 1150 } 1151 catch (IOException e) { 1152 // Do nothing 1153 } 1154 } 1155 1156 return 0; 1157 } 1158 } 1159 1160 public void enableTdls(String remoteAddress, boolean enable) { 1161 TdlsTaskParams params = new TdlsTaskParams(); 1162 params.remoteIpAddress = remoteAddress; 1163 params.enable = enable; 1164 new TdlsTask().execute(params); 1165 } 1166 1167 1168 public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) { 1169 mWifiStateMachine.enableTdls(remoteMacAddress, enable); 1170 } 1171 1172 /** 1173 * Get a reference to handler. This is used by a client to establish 1174 * an AsyncChannel communication with WifiService 1175 */ 1176 public Messenger getWifiServiceMessenger() { 1177 enforceAccessPermission(); 1178 enforceChangePermission(); 1179 return new Messenger(mClientHandler); 1180 } 1181 1182 1183 /** 1184 * Get the IP and proxy configuration file 1185 */ 1186 public String getConfigFile() { 1187 enforceAccessPermission(); 1188 return mWifiStateMachine.getConfigFile(); 1189 } 1190 1191 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 1192 @Override 1193 public void onReceive(Context context, Intent intent) { 1194 String action = intent.getAction(); 1195 if (action.equals(Intent.ACTION_SCREEN_ON)) { 1196 mWifiController.sendMessage(CMD_SCREEN_ON); 1197 } else if (action.equals(Intent.ACTION_USER_PRESENT)) { 1198 mWifiController.sendMessage(CMD_USER_PRESENT); 1199 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 1200 mWifiController.sendMessage(CMD_SCREEN_OFF); 1201 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { 1202 int pluggedType = intent.getIntExtra("plugged", 0); 1203 mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null); 1204 } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) { 1205 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 1206 BluetoothAdapter.STATE_DISCONNECTED); 1207 mWifiStateMachine.sendBluetoothAdapterStateChange(state); 1208 } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { 1209 boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false); 1210 mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0); 1211 } 1212 } 1213 }; 1214 1215 /** 1216 * Observes settings changes to scan always mode. 1217 */ 1218 private void registerForScanModeChange() { 1219 ContentObserver contentObserver = new ContentObserver(null) { 1220 @Override 1221 public void onChange(boolean selfChange) { 1222 mSettingsStore.handleWifiScanAlwaysAvailableToggled(); 1223 mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED); 1224 } 1225 }; 1226 1227 mContext.getContentResolver().registerContentObserver( 1228 Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE), 1229 false, contentObserver); 1230 } 1231 1232 private void registerForBroadcasts() { 1233 IntentFilter intentFilter = new IntentFilter(); 1234 intentFilter.addAction(Intent.ACTION_SCREEN_ON); 1235 intentFilter.addAction(Intent.ACTION_USER_PRESENT); 1236 intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 1237 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 1238 intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); 1239 intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); 1240 intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); 1241 mContext.registerReceiver(mReceiver, intentFilter); 1242 } 1243 1244 @Override 1245 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1246 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 1247 != PackageManager.PERMISSION_GRANTED) { 1248 pw.println("Permission Denial: can't dump WifiService from from pid=" 1249 + Binder.getCallingPid() 1250 + ", uid=" + Binder.getCallingUid()); 1251 return; 1252 } 1253 pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName()); 1254 pw.println("Stay-awake conditions: " + 1255 Settings.Global.getInt(mContext.getContentResolver(), 1256 Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0)); 1257 pw.println("mMulticastEnabled " + mMulticastEnabled); 1258 pw.println("mMulticastDisabled " + mMulticastDisabled); 1259 mWifiController.dump(fd, pw, args); 1260 mSettingsStore.dump(fd, pw, args); 1261 mNotificationController.dump(fd, pw, args); 1262 mTrafficPoller.dump(fd, pw, args); 1263 1264 pw.println("Latest scan results:"); 1265 List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList(); 1266 if (scanResults != null && scanResults.size() != 0) { 1267 pw.println(" BSSID Frequency RSSI Flags SSID"); 1268 for (ScanResult r : scanResults) { 1269 pw.printf(" %17s %9d %5d %-16s %s%n", 1270 r.BSSID, 1271 r.frequency, 1272 r.level, 1273 r.capabilities, 1274 r.SSID == null ? "" : r.SSID); 1275 } 1276 } 1277 pw.println(); 1278 pw.println("Locks acquired: " + mFullLocksAcquired + " full, " + 1279 mFullHighPerfLocksAcquired + " full high perf, " + 1280 mScanLocksAcquired + " scan"); 1281 pw.println("Locks released: " + mFullLocksReleased + " full, " + 1282 mFullHighPerfLocksReleased + " full high perf, " + 1283 mScanLocksReleased + " scan"); 1284 pw.println(); 1285 pw.println("Locks held:"); 1286 mLocks.dump(pw); 1287 1288 mWifiWatchdogStateMachine.dump(fd, pw, args); 1289 pw.println(); 1290 mWifiStateMachine.dump(fd, pw, args); 1291 pw.println(); 1292 } 1293 1294 private class WifiLock extends DeathRecipient { 1295 WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) { 1296 super(lockMode, tag, binder, ws); 1297 } 1298 1299 public void binderDied() { 1300 synchronized (mLocks) { 1301 releaseWifiLockLocked(mBinder); 1302 } 1303 } 1304 1305 public String toString() { 1306 return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}"; 1307 } 1308 } 1309 1310 class LockList { 1311 private List<WifiLock> mList; 1312 1313 private LockList() { 1314 mList = new ArrayList<WifiLock>(); 1315 } 1316 1317 synchronized boolean hasLocks() { 1318 return !mList.isEmpty(); 1319 } 1320 1321 synchronized int getStrongestLockMode() { 1322 if (mList.isEmpty()) { 1323 return WifiManager.WIFI_MODE_FULL; 1324 } 1325 1326 if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) { 1327 return WifiManager.WIFI_MODE_FULL_HIGH_PERF; 1328 } 1329 1330 if (mFullLocksAcquired > mFullLocksReleased) { 1331 return WifiManager.WIFI_MODE_FULL; 1332 } 1333 1334 return WifiManager.WIFI_MODE_SCAN_ONLY; 1335 } 1336 1337 synchronized void updateWorkSource(WorkSource ws) { 1338 for (int i = 0; i < mLocks.mList.size(); i++) { 1339 ws.add(mLocks.mList.get(i).mWorkSource); 1340 } 1341 } 1342 1343 private void addLock(WifiLock lock) { 1344 if (findLockByBinder(lock.mBinder) < 0) { 1345 mList.add(lock); 1346 } 1347 } 1348 1349 private WifiLock removeLock(IBinder binder) { 1350 int index = findLockByBinder(binder); 1351 if (index >= 0) { 1352 WifiLock ret = mList.remove(index); 1353 ret.unlinkDeathRecipient(); 1354 return ret; 1355 } else { 1356 return null; 1357 } 1358 } 1359 1360 private int findLockByBinder(IBinder binder) { 1361 int size = mList.size(); 1362 for (int i = size - 1; i >= 0; i--) { 1363 if (mList.get(i).mBinder == binder) 1364 return i; 1365 } 1366 return -1; 1367 } 1368 1369 private void dump(PrintWriter pw) { 1370 for (WifiLock l : mList) { 1371 pw.print(" "); 1372 pw.println(l); 1373 } 1374 } 1375 } 1376 1377 void enforceWakeSourcePermission(int uid, int pid) { 1378 if (uid == android.os.Process.myUid()) { 1379 return; 1380 } 1381 mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, 1382 pid, uid, null); 1383 } 1384 1385 public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { 1386 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1387 if (lockMode != WifiManager.WIFI_MODE_FULL && 1388 lockMode != WifiManager.WIFI_MODE_SCAN_ONLY && 1389 lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) { 1390 Slog.e(TAG, "Illegal argument, lockMode= " + lockMode); 1391 if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode); 1392 return false; 1393 } 1394 if (ws != null && ws.size() == 0) { 1395 ws = null; 1396 } 1397 if (ws != null) { 1398 enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid()); 1399 } 1400 if (ws == null) { 1401 ws = new WorkSource(Binder.getCallingUid()); 1402 } 1403 WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws); 1404 synchronized (mLocks) { 1405 return acquireWifiLockLocked(wifiLock); 1406 } 1407 } 1408 1409 private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException { 1410 switch(wifiLock.mMode) { 1411 case WifiManager.WIFI_MODE_FULL: 1412 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1413 case WifiManager.WIFI_MODE_SCAN_ONLY: 1414 mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource); 1415 break; 1416 } 1417 } 1418 1419 private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException { 1420 switch(wifiLock.mMode) { 1421 case WifiManager.WIFI_MODE_FULL: 1422 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1423 case WifiManager.WIFI_MODE_SCAN_ONLY: 1424 mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource); 1425 break; 1426 } 1427 } 1428 1429 private boolean acquireWifiLockLocked(WifiLock wifiLock) { 1430 if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock); 1431 1432 mLocks.addLock(wifiLock); 1433 1434 long ident = Binder.clearCallingIdentity(); 1435 try { 1436 noteAcquireWifiLock(wifiLock); 1437 switch(wifiLock.mMode) { 1438 case WifiManager.WIFI_MODE_FULL: 1439 ++mFullLocksAcquired; 1440 break; 1441 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1442 ++mFullHighPerfLocksAcquired; 1443 break; 1444 1445 case WifiManager.WIFI_MODE_SCAN_ONLY: 1446 ++mScanLocksAcquired; 1447 break; 1448 } 1449 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1450 return true; 1451 } catch (RemoteException e) { 1452 return false; 1453 } finally { 1454 Binder.restoreCallingIdentity(ident); 1455 } 1456 } 1457 1458 public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) { 1459 int uid = Binder.getCallingUid(); 1460 int pid = Binder.getCallingPid(); 1461 if (ws != null && ws.size() == 0) { 1462 ws = null; 1463 } 1464 if (ws != null) { 1465 enforceWakeSourcePermission(uid, pid); 1466 } 1467 long ident = Binder.clearCallingIdentity(); 1468 try { 1469 synchronized (mLocks) { 1470 int index = mLocks.findLockByBinder(lock); 1471 if (index < 0) { 1472 throw new IllegalArgumentException("Wifi lock not active"); 1473 } 1474 WifiLock wl = mLocks.mList.get(index); 1475 noteReleaseWifiLock(wl); 1476 wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid); 1477 noteAcquireWifiLock(wl); 1478 } 1479 } catch (RemoteException e) { 1480 } finally { 1481 Binder.restoreCallingIdentity(ident); 1482 } 1483 } 1484 1485 public boolean releaseWifiLock(IBinder lock) { 1486 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); 1487 synchronized (mLocks) { 1488 return releaseWifiLockLocked(lock); 1489 } 1490 } 1491 1492 private boolean releaseWifiLockLocked(IBinder lock) { 1493 boolean hadLock; 1494 1495 WifiLock wifiLock = mLocks.removeLock(lock); 1496 1497 if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock); 1498 1499 hadLock = (wifiLock != null); 1500 1501 long ident = Binder.clearCallingIdentity(); 1502 try { 1503 if (hadLock) { 1504 noteReleaseWifiLock(wifiLock); 1505 switch(wifiLock.mMode) { 1506 case WifiManager.WIFI_MODE_FULL: 1507 ++mFullLocksReleased; 1508 break; 1509 case WifiManager.WIFI_MODE_FULL_HIGH_PERF: 1510 ++mFullHighPerfLocksReleased; 1511 break; 1512 case WifiManager.WIFI_MODE_SCAN_ONLY: 1513 ++mScanLocksReleased; 1514 break; 1515 } 1516 mWifiController.sendMessage(CMD_LOCKS_CHANGED); 1517 } 1518 } catch (RemoteException e) { 1519 } finally { 1520 Binder.restoreCallingIdentity(ident); 1521 } 1522 1523 return hadLock; 1524 } 1525 1526 private abstract class DeathRecipient 1527 implements IBinder.DeathRecipient { 1528 String mTag; 1529 int mMode; 1530 IBinder mBinder; 1531 WorkSource mWorkSource; 1532 1533 DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) { 1534 super(); 1535 mTag = tag; 1536 mMode = mode; 1537 mBinder = binder; 1538 mWorkSource = ws; 1539 try { 1540 mBinder.linkToDeath(this, 0); 1541 } catch (RemoteException e) { 1542 binderDied(); 1543 } 1544 } 1545 1546 void unlinkDeathRecipient() { 1547 mBinder.unlinkToDeath(this, 0); 1548 } 1549 } 1550 1551 private class Multicaster extends DeathRecipient { 1552 Multicaster(String tag, IBinder binder) { 1553 super(Binder.getCallingUid(), tag, binder, null); 1554 } 1555 1556 public void binderDied() { 1557 Slog.e(TAG, "Multicaster binderDied"); 1558 synchronized (mMulticasters) { 1559 int i = mMulticasters.indexOf(this); 1560 if (i != -1) { 1561 removeMulticasterLocked(i, mMode); 1562 } 1563 } 1564 } 1565 1566 public String toString() { 1567 return "Multicaster{" + mTag + " binder=" + mBinder + "}"; 1568 } 1569 1570 public int getUid() { 1571 return mMode; 1572 } 1573 } 1574 1575 public void initializeMulticastFiltering() { 1576 enforceMulticastChangePermission(); 1577 1578 synchronized (mMulticasters) { 1579 // if anybody had requested filters be off, leave off 1580 if (mMulticasters.size() != 0) { 1581 return; 1582 } else { 1583 mWifiStateMachine.startFilteringMulticastV4Packets(); 1584 } 1585 } 1586 } 1587 1588 public void acquireMulticastLock(IBinder binder, String tag) { 1589 enforceMulticastChangePermission(); 1590 1591 synchronized (mMulticasters) { 1592 mMulticastEnabled++; 1593 mMulticasters.add(new Multicaster(tag, binder)); 1594 // Note that we could call stopFilteringMulticastV4Packets only when 1595 // our new size == 1 (first call), but this function won't 1596 // be called often and by making the stopPacket call each 1597 // time we're less fragile and self-healing. 1598 mWifiStateMachine.stopFilteringMulticastV4Packets(); 1599 } 1600 1601 int uid = Binder.getCallingUid(); 1602 final long ident = Binder.clearCallingIdentity(); 1603 try { 1604 mBatteryStats.noteWifiMulticastEnabled(uid); 1605 } catch (RemoteException e) { 1606 } finally { 1607 Binder.restoreCallingIdentity(ident); 1608 } 1609 } 1610 1611 public void releaseMulticastLock() { 1612 enforceMulticastChangePermission(); 1613 1614 int uid = Binder.getCallingUid(); 1615 synchronized (mMulticasters) { 1616 mMulticastDisabled++; 1617 int size = mMulticasters.size(); 1618 for (int i = size - 1; i >= 0; i--) { 1619 Multicaster m = mMulticasters.get(i); 1620 if ((m != null) && (m.getUid() == uid)) { 1621 removeMulticasterLocked(i, uid); 1622 } 1623 } 1624 } 1625 } 1626 1627 private void removeMulticasterLocked(int i, int uid) 1628 { 1629 Multicaster removed = mMulticasters.remove(i); 1630 1631 if (removed != null) { 1632 removed.unlinkDeathRecipient(); 1633 } 1634 if (mMulticasters.size() == 0) { 1635 mWifiStateMachine.startFilteringMulticastV4Packets(); 1636 } 1637 1638 final long ident = Binder.clearCallingIdentity(); 1639 try { 1640 mBatteryStats.noteWifiMulticastDisabled(uid); 1641 } catch (RemoteException e) { 1642 } finally { 1643 Binder.restoreCallingIdentity(ident); 1644 } 1645 } 1646 1647 public boolean isMulticastEnabled() { 1648 enforceAccessPermission(); 1649 1650 synchronized (mMulticasters) { 1651 return (mMulticasters.size() > 0); 1652 } 1653 } 1654 1655 public WifiMonitor getWifiMonitor() { 1656 return mWifiStateMachine.getWifiMonitor(); 1657 } 1658 1659 1660 public void enableVerboseLogging(int verbose) { 1661 enforceAccessPermission(); 1662 mWifiStateMachine.enableVerboseLogging(verbose); 1663 } 1664 1665 public int getVerboseLoggingLevel() { 1666 enforceAccessPermission(); 1667 return mWifiStateMachine.getVerboseLoggingLevel(); 1668 } 1669} 1670