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