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