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