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