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