1 /* 2 * Copyright (C) 2018 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.internal.util.Preconditions.checkNotNull; 20 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_LOCAL_ONLY; 21 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY; 22 import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes; 23 24 import static java.lang.Math.toIntExact; 25 26 import android.annotation.NonNull; 27 import android.annotation.Nullable; 28 import android.app.ActivityManager; 29 import android.app.AlarmManager; 30 import android.app.AppOpsManager; 31 import android.companion.CompanionDeviceManager; 32 import android.content.BroadcastReceiver; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.pm.ApplicationInfo; 37 import android.content.pm.PackageManager; 38 import android.net.MacAddress; 39 import android.net.NetworkCapabilities; 40 import android.net.NetworkFactory; 41 import android.net.NetworkRequest; 42 import android.net.NetworkSpecifier; 43 import android.net.wifi.IActionListener; 44 import android.net.wifi.INetworkRequestMatchCallback; 45 import android.net.wifi.INetworkRequestUserSelectionCallback; 46 import android.net.wifi.ScanResult; 47 import android.net.wifi.SecurityParams; 48 import android.net.wifi.WifiConfiguration; 49 import android.net.wifi.WifiConfiguration.SecurityType; 50 import android.net.wifi.WifiNetworkSpecifier; 51 import android.net.wifi.WifiScanner; 52 import android.os.Handler; 53 import android.os.HandlerExecutor; 54 import android.os.Looper; 55 import android.os.PatternMatcher; 56 import android.os.PowerManager; 57 import android.os.Process; 58 import android.os.RemoteCallbackList; 59 import android.os.RemoteException; 60 import android.os.UserHandle; 61 import android.os.WorkSource; 62 import android.text.TextUtils; 63 import android.util.Log; 64 import android.util.Pair; 65 66 import com.android.internal.annotations.VisibleForTesting; 67 import com.android.server.wifi.proto.nano.WifiMetricsProto; 68 import com.android.server.wifi.util.ActionListenerWrapper; 69 import com.android.server.wifi.util.ScanResultUtil; 70 import com.android.server.wifi.util.WifiPermissionsUtil; 71 import com.android.wifi.resources.R; 72 73 import java.io.FileDescriptor; 74 import java.io.PrintWriter; 75 import java.util.ArrayList; 76 import java.util.Collection; 77 import java.util.Comparator; 78 import java.util.HashMap; 79 import java.util.HashSet; 80 import java.util.Iterator; 81 import java.util.LinkedHashSet; 82 import java.util.List; 83 import java.util.Map; 84 import java.util.Objects; 85 import java.util.Set; 86 import java.util.concurrent.TimeUnit; 87 import java.util.stream.Collectors; 88 89 /** 90 * Network factory to handle trusted wifi network requests. 91 */ 92 public class WifiNetworkFactory extends NetworkFactory { 93 private static final String TAG = "WifiNetworkFactory"; 94 @VisibleForTesting 95 private static final int SCORE_FILTER = 60; 96 @VisibleForTesting 97 public static final int CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS = 30 * 1000; 98 @VisibleForTesting 99 public static final int PERIODIC_SCAN_INTERVAL_MS = 10 * 1000; // 10 seconds 100 @VisibleForTesting 101 public static final int NETWORK_CONNECTION_TIMEOUT_MS = 30 * 1000; // 30 seconds 102 @VisibleForTesting 103 public static final int USER_SELECTED_NETWORK_CONNECT_RETRY_MAX = 3; // max of 3 retries. 104 @VisibleForTesting 105 public static final String UI_START_INTENT_ACTION = 106 "com.android.settings.wifi.action.NETWORK_REQUEST"; 107 @VisibleForTesting 108 public static final String UI_START_INTENT_CATEGORY = "android.intent.category.DEFAULT"; 109 @VisibleForTesting 110 public static final String UI_START_INTENT_EXTRA_APP_NAME = 111 "com.android.settings.wifi.extra.APP_NAME"; 112 @VisibleForTesting 113 public static final String UI_START_INTENT_EXTRA_REQUEST_IS_FOR_SINGLE_NETWORK = 114 "com.android.settings.wifi.extra.REQUEST_IS_FOR_SINGLE_NETWORK"; 115 // Capacity limit of approved Access Point per App 116 @VisibleForTesting 117 public static final int NUM_OF_ACCESS_POINT_LIMIT_PER_APP = 50; 118 119 private final Context mContext; 120 private final ActivityManager mActivityManager; 121 private final AlarmManager mAlarmManager; 122 private final AppOpsManager mAppOpsManager; 123 private final Clock mClock; 124 private final Handler mHandler; 125 private final WifiInjector mWifiInjector; 126 private final WifiConnectivityManager mWifiConnectivityManager; 127 private final WifiConfigManager mWifiConfigManager; 128 private final WifiConfigStore mWifiConfigStore; 129 private final WifiPermissionsUtil mWifiPermissionsUtil; 130 private final WifiMetrics mWifiMetrics; 131 private final ActiveModeWarden mActiveModeWarden; 132 private final WifiScanner.ScanSettings mScanSettings; 133 private final NetworkFactoryScanListener mScanListener; 134 private final PeriodicScanAlarmListener mPeriodicScanTimerListener; 135 private final ConnectionTimeoutAlarmListener mConnectionTimeoutAlarmListener; 136 private final ConnectHelper mConnectHelper; 137 private final ClientModeImplMonitor mClientModeImplMonitor; 138 private RemoteCallbackList<INetworkRequestMatchCallback> mRegisteredCallbacks; 139 // Store all user approved access points for apps. 140 @VisibleForTesting 141 public final Map<String, LinkedHashSet<AccessPoint>> mUserApprovedAccessPointMap; 142 private WifiScanner mWifiScanner; 143 @Nullable private ClientModeManager mClientModeManager; 144 @Nullable private ActiveModeManager.ClientRole mClientModeManagerRole; 145 private CompanionDeviceManager mCompanionDeviceManager; 146 // Temporary approval set by shell commands. 147 @Nullable private String mApprovedApp = null; 148 149 private int mGenericConnectionReqCount = 0; 150 // Request that is being actively processed. All new requests start out as an "active" request 151 // because we're processing it & handling all the user interactions associated with it. Once we 152 // successfully connect to the network, we transition that request to "connected". 153 @Nullable private NetworkRequest mActiveSpecificNetworkRequest; 154 @Nullable private WifiNetworkSpecifier mActiveSpecificNetworkRequestSpecifier; 155 // Request corresponding to the the network that the device is currently connected to. 156 @Nullable private NetworkRequest mConnectedSpecificNetworkRequest; 157 @Nullable private WifiNetworkSpecifier mConnectedSpecificNetworkRequestSpecifier; 158 @Nullable private WifiConfiguration mUserSelectedNetwork; 159 private int mUserSelectedNetworkConnectRetryCount; 160 // Map of bssid to latest scan results for all scan results matching a request. Will be 161 // - null, if there are no active requests. 162 // - empty, if there are no matching scan results received for the active request. 163 @Nullable private Map<String, ScanResult> mActiveMatchedScanResults; 164 /** Connection start time to keep track of connection duration */ 165 private long mConnectionStartTimeMillis = -1L; 166 /** 167 * CMI listener used for concurrent connection metrics collection. 168 * Not used when the connection is on primary STA (i.e not STA + STA). 169 */ 170 @Nullable private CmiListener mCmiListener; 171 // Verbose logging flag. 172 private boolean mVerboseLoggingEnabled = false; 173 private boolean mPeriodicScanTimerSet = false; 174 private boolean mConnectionTimeoutSet = false; 175 private boolean mIsPeriodicScanEnabled = false; 176 private boolean mIsPeriodicScanPaused = false; 177 // We sent a new connection request and are waiting for connection success. 178 private boolean mPendingConnectionSuccess = false; 179 /** 180 * Indicates that we have new data to serialize. 181 */ 182 private boolean mHasNewDataToSerialize = false; 183 184 /** 185 * Helper class to store an access point that the user previously approved for a specific app. 186 * TODO(b/123014687): Move to a common util class. 187 */ 188 public static class AccessPoint { 189 public final String ssid; 190 public final MacAddress bssid; 191 public final @SecurityType int networkType; 192 AccessPoint(@onNull String ssid, @NonNull MacAddress bssid, @SecurityType int networkType)193 AccessPoint(@NonNull String ssid, @NonNull MacAddress bssid, 194 @SecurityType int networkType) { 195 this.ssid = ssid; 196 this.bssid = bssid; 197 this.networkType = networkType; 198 } 199 200 @Override hashCode()201 public int hashCode() { 202 return Objects.hash(ssid, bssid, networkType); 203 } 204 205 @Override equals(Object obj)206 public boolean equals(Object obj) { 207 if (this == obj) { 208 return true; 209 } 210 if (!(obj instanceof AccessPoint)) { 211 return false; 212 } 213 AccessPoint other = (AccessPoint) obj; 214 return TextUtils.equals(this.ssid, other.ssid) 215 && Objects.equals(this.bssid, other.bssid) 216 && this.networkType == other.networkType; 217 } 218 219 @Override toString()220 public String toString() { 221 StringBuilder sb = new StringBuilder("AccessPoint: "); 222 return sb.append(ssid) 223 .append(", ") 224 .append(bssid) 225 .append(", ") 226 .append(networkType) 227 .toString(); 228 } 229 } 230 231 // Scan listener for scan requests. 232 private class NetworkFactoryScanListener implements WifiScanner.ScanListener { 233 @Override onSuccess()234 public void onSuccess() { 235 // Scan request succeeded, wait for results to report to external clients. 236 if (mVerboseLoggingEnabled) { 237 Log.d(TAG, "Scan request succeeded"); 238 } 239 } 240 241 @Override onFailure(int reason, String description)242 public void onFailure(int reason, String description) { 243 Log.e(TAG, "Scan failure received. reason: " + reason 244 + ", description: " + description); 245 // TODO(b/113878056): Retry scan to workaround any transient scan failures. 246 scheduleNextPeriodicScan(); 247 } 248 249 @Override onResults(WifiScanner.ScanData[] scanDatas)250 public void onResults(WifiScanner.ScanData[] scanDatas) { 251 if (mVerboseLoggingEnabled) { 252 Log.d(TAG, "Scan results received"); 253 } 254 // For single scans, the array size should always be 1. 255 if (scanDatas.length != 1) { 256 Log.wtf(TAG, "Found more than 1 batch of scan results, Ignoring..."); 257 return; 258 } 259 WifiScanner.ScanData scanData = scanDatas[0]; 260 ScanResult[] scanResults = scanData.getResults(); 261 if (mVerboseLoggingEnabled) { 262 Log.v(TAG, "Received " + scanResults.length + " scan results"); 263 } 264 handleScanResults(scanResults); 265 if (mActiveMatchedScanResults != null) { 266 sendNetworkRequestMatchCallbacksForActiveRequest( 267 mActiveMatchedScanResults.values()); 268 } 269 scheduleNextPeriodicScan(); 270 } 271 272 @Override onFullResult(ScanResult fullScanResult)273 public void onFullResult(ScanResult fullScanResult) { 274 // Ignore for single scans. 275 } 276 277 @Override onPeriodChanged(int periodInMs)278 public void onPeriodChanged(int periodInMs) { 279 // Ignore for single scans. 280 } 281 }; 282 283 private class PeriodicScanAlarmListener implements AlarmManager.OnAlarmListener { 284 @Override onAlarm()285 public void onAlarm() { 286 // Trigger the next scan. 287 startScan(); 288 mPeriodicScanTimerSet = false; 289 } 290 } 291 292 private class ConnectionTimeoutAlarmListener implements AlarmManager.OnAlarmListener { 293 @Override onAlarm()294 public void onAlarm() { 295 Log.e(TAG, "Timed-out connecting to network"); 296 handleNetworkConnectionFailure(mUserSelectedNetwork, mUserSelectedNetwork.BSSID); 297 mConnectionTimeoutSet = false; 298 } 299 } 300 301 // Callback result from settings UI. 302 private class NetworkFactoryUserSelectionCallback extends 303 INetworkRequestUserSelectionCallback.Stub { 304 private final NetworkRequest mNetworkRequest; 305 NetworkFactoryUserSelectionCallback(NetworkRequest networkRequest)306 NetworkFactoryUserSelectionCallback(NetworkRequest networkRequest) { 307 mNetworkRequest = networkRequest; 308 } 309 310 @Override select(WifiConfiguration wifiConfiguration)311 public void select(WifiConfiguration wifiConfiguration) { 312 mHandler.post(() -> { 313 if (mActiveSpecificNetworkRequest != mNetworkRequest) { 314 Log.e(TAG, "Stale callback select received"); 315 return; 316 } 317 handleConnectToNetworkUserSelection(wifiConfiguration); 318 }); 319 } 320 321 @Override reject()322 public void reject() { 323 mHandler.post(() -> { 324 if (mActiveSpecificNetworkRequest != mNetworkRequest) { 325 Log.e(TAG, "Stale callback reject received"); 326 return; 327 } 328 handleRejectUserSelection(); 329 }); 330 } 331 } 332 333 private final class ConnectActionListener extends IActionListener.Stub { 334 @Override onSuccess()335 public void onSuccess() { 336 if (mVerboseLoggingEnabled) { 337 Log.v(TAG, "Triggered network connection"); 338 } 339 } 340 341 @Override onFailure(int reason)342 public void onFailure(int reason) { 343 Log.e(TAG, "Failed to trigger network connection"); 344 handleNetworkConnectionFailure(mUserSelectedNetwork, mUserSelectedNetwork.BSSID); 345 } 346 } 347 348 private final class ClientModeManagerRequestListener implements 349 ActiveModeWarden.ExternalClientModeManagerRequestListener { 350 @Override onAnswer(@ullable ClientModeManager modeManager)351 public void onAnswer(@Nullable ClientModeManager modeManager) { 352 if (modeManager != null) { 353 // Remove the mode manager if the associated request is no longer active. 354 if (mActiveSpecificNetworkRequest == null 355 && mConnectedSpecificNetworkRequest == null) { 356 Log.w(TAG, "Client mode manager request answer received with no active" 357 + " requests"); 358 mActiveModeWarden.removeClientModeManager(modeManager); 359 return; 360 } 361 mClientModeManager = modeManager; 362 mClientModeManagerRole = modeManager.getRole(); 363 handleClientModeManagerRetrieval(); 364 } else { 365 handleClientModeManagerRemovalOrFailure(); 366 } 367 } 368 } 369 370 private class ModeChangeCallback implements ActiveModeWarden.ModeChangeCallback { 371 @Override onActiveModeManagerAdded(@onNull ActiveModeManager activeModeManager)372 public void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager) { 373 // ignored. 374 // Will get a dedicated ClientModeManager instance for our request via 375 // ClientModeManagerRequestListener. 376 } 377 378 @Override onActiveModeManagerRemoved(@onNull ActiveModeManager activeModeManager)379 public void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager) { 380 if (!(activeModeManager instanceof ClientModeManager)) return; 381 if (mVerboseLoggingEnabled) { 382 Log.v(TAG, "ModeManager removed " + activeModeManager.getInterfaceName()); 383 } 384 // Mode manager removed. Cleanup any ongoing requests. 385 if (activeModeManager == mClientModeManager 386 || !mActiveModeWarden.hasPrimaryClientModeManager()) { 387 handleClientModeManagerRemovalOrFailure(); 388 } 389 } 390 391 @Override onActiveModeManagerRoleChanged(@onNull ActiveModeManager activeModeManager)392 public void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager) { 393 if (!(activeModeManager instanceof ClientModeManager)) return; 394 if (mVerboseLoggingEnabled) { 395 Log.v(TAG, "ModeManager role changed " + activeModeManager.getInterfaceName()); 396 } 397 // Mode manager role changed. Cleanup any ongoing requests. 398 if (activeModeManager == mClientModeManager 399 || !mActiveModeWarden.hasPrimaryClientModeManager()) { 400 handleClientModeManagerRemovalOrFailure(); 401 } 402 } 403 } 404 405 /** 406 * Module to interact with the wifi config store. 407 */ 408 private class NetworkRequestDataSource implements NetworkRequestStoreData.DataSource { 409 @Override toSerialize()410 public Map<String, Set<AccessPoint>> toSerialize() { 411 // Clear the flag after writing to disk. 412 mHasNewDataToSerialize = false; 413 return new HashMap<>(mUserApprovedAccessPointMap); 414 } 415 416 @Override fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPointMap)417 public void fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPointMap) { 418 approvedAccessPointMap.forEach((key, value) -> 419 mUserApprovedAccessPointMap.put(key, new LinkedHashSet<>(value))); 420 } 421 422 @Override reset()423 public void reset() { 424 mUserApprovedAccessPointMap.clear(); 425 } 426 427 @Override hasNewDataToSerialize()428 public boolean hasNewDataToSerialize() { 429 return mHasNewDataToSerialize; 430 } 431 } 432 433 /** 434 * To keep track of concurrent connections using this API surface (for metrics collection only). 435 * 436 * Only used if the connection is initiated on secondary STA. 437 */ 438 private class CmiListener implements ClientModeImplListener { 439 /** Concurrent connection start time to keep track of connection duration */ 440 private long mConcurrentConnectionStartTimeMillis = -1L; 441 /** Whether we have already indicated the presence of concurrent connection */ 442 private boolean mHasAlreadyIncrementedConcurrentConnectionCount = false; 443 isLocalOnlyOrPrimary(@onNull ClientModeManager cmm)444 private boolean isLocalOnlyOrPrimary(@NonNull ClientModeManager cmm) { 445 return cmm.getRole() == ROLE_CLIENT_PRIMARY 446 || cmm.getRole() == ROLE_CLIENT_LOCAL_ONLY; 447 } 448 checkForConcurrencyStartAndIncrementMetrics()449 private void checkForConcurrencyStartAndIncrementMetrics() { 450 int numLocalOnlyOrPrimaryConnectedCmms = 0; 451 for (ClientModeManager cmm : mActiveModeWarden.getClientModeManagers()) { 452 if (isLocalOnlyOrPrimary(cmm) && cmm.isConnected()) { 453 numLocalOnlyOrPrimaryConnectedCmms++; 454 } 455 } 456 if (numLocalOnlyOrPrimaryConnectedCmms > 1) { 457 mConcurrentConnectionStartTimeMillis = mClock.getElapsedSinceBootMillis(); 458 // Note: We could have multiple connect/disconnect of the primary connection 459 // while remaining connected to the local only connection. We want to keep track 460 // of the connection durations accurately across those disconnects. However, we do 461 // not want to increment the connection count metric since that should be a 1:1 462 // mapping with the number of requests processed (i.e don't indicate 2 concurrent 463 // connection count if the primary disconnected & connected back while processing 464 // the same local only request). 465 if (!mHasAlreadyIncrementedConcurrentConnectionCount) { 466 mWifiMetrics.incrementNetworkRequestApiNumConcurrentConnection(); 467 mHasAlreadyIncrementedConcurrentConnectionCount = true; 468 } 469 } 470 } 471 checkForConcurrencyEndAndIncrementMetrics()472 public void checkForConcurrencyEndAndIncrementMetrics() { 473 if (mConcurrentConnectionStartTimeMillis != -1L) { 474 mWifiMetrics.incrementNetworkRequestApiConcurrentConnectionDurationSecHistogram( 475 toIntExact(TimeUnit.MILLISECONDS.toSeconds( 476 mClock.getElapsedSinceBootMillis() 477 - mConcurrentConnectionStartTimeMillis))); 478 mConcurrentConnectionStartTimeMillis = -1L; 479 } 480 } 481 CmiListener()482 CmiListener() { 483 checkForConcurrencyStartAndIncrementMetrics(); 484 } 485 486 @Override onL3Connected(@onNull ConcreteClientModeManager clientModeManager)487 public void onL3Connected(@NonNull ConcreteClientModeManager clientModeManager) { 488 if (isLocalOnlyOrPrimary(clientModeManager)) { 489 checkForConcurrencyStartAndIncrementMetrics(); 490 } 491 } 492 493 @Override onConnectionEnd(@onNull ConcreteClientModeManager clientModeManager)494 public void onConnectionEnd(@NonNull ConcreteClientModeManager clientModeManager) { 495 if (isLocalOnlyOrPrimary(clientModeManager)) { 496 checkForConcurrencyEndAndIncrementMetrics(); 497 } 498 } 499 } 500 WifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, ActivityManager activityManager, AlarmManager alarmManager, AppOpsManager appOpsManager, Clock clock, WifiInjector wifiInjector, WifiConnectivityManager connectivityManager, WifiConfigManager configManager, WifiConfigStore configStore, WifiPermissionsUtil wifiPermissionsUtil, WifiMetrics wifiMetrics, ActiveModeWarden activeModeWarden, ConnectHelper connectHelper, ClientModeImplMonitor clientModeImplMonitor)501 public WifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, 502 ActivityManager activityManager, AlarmManager alarmManager, 503 AppOpsManager appOpsManager, 504 Clock clock, WifiInjector wifiInjector, 505 WifiConnectivityManager connectivityManager, 506 WifiConfigManager configManager, 507 WifiConfigStore configStore, 508 WifiPermissionsUtil wifiPermissionsUtil, 509 WifiMetrics wifiMetrics, 510 ActiveModeWarden activeModeWarden, 511 ConnectHelper connectHelper, 512 ClientModeImplMonitor clientModeImplMonitor) { 513 super(looper, context, TAG, nc); 514 mContext = context; 515 mActivityManager = activityManager; 516 mAlarmManager = alarmManager; 517 mAppOpsManager = appOpsManager; 518 mClock = clock; 519 mHandler = new Handler(looper); 520 mWifiInjector = wifiInjector; 521 mWifiConnectivityManager = connectivityManager; 522 mWifiConfigManager = configManager; 523 mWifiConfigStore = configStore; 524 mWifiPermissionsUtil = wifiPermissionsUtil; 525 mWifiMetrics = wifiMetrics; 526 mActiveModeWarden = activeModeWarden; 527 mConnectHelper = connectHelper; 528 mClientModeImplMonitor = clientModeImplMonitor; 529 // Create the scan settings. 530 mScanSettings = new WifiScanner.ScanSettings(); 531 mScanSettings.type = WifiScanner.SCAN_TYPE_HIGH_ACCURACY; 532 mScanSettings.band = WifiScanner.WIFI_BAND_ALL; 533 mScanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 534 mScanListener = new NetworkFactoryScanListener(); 535 mPeriodicScanTimerListener = new PeriodicScanAlarmListener(); 536 mConnectionTimeoutAlarmListener = new ConnectionTimeoutAlarmListener(); 537 mUserApprovedAccessPointMap = new HashMap<>(); 538 539 IntentFilter filter = new IntentFilter(); 540 filter.addAction(Intent.ACTION_SCREEN_ON); 541 filter.addAction(Intent.ACTION_SCREEN_OFF); 542 context.registerReceiver( 543 new BroadcastReceiver() { 544 @Override 545 public void onReceive(Context context, Intent intent) { 546 String action = intent.getAction(); 547 if (action.equals(Intent.ACTION_SCREEN_ON)) { 548 handleScreenStateChanged(true); 549 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 550 handleScreenStateChanged(false); 551 } 552 } 553 }, filter, null, mHandler); 554 handleScreenStateChanged(context.getSystemService(PowerManager.class).isInteractive()); 555 556 // register the data store for serializing/deserializing data. 557 configStore.registerStoreData( 558 wifiInjector.makeNetworkRequestStoreData(new NetworkRequestDataSource())); 559 560 activeModeWarden.registerModeChangeCallback(new ModeChangeCallback()); 561 562 setScoreFilter(SCORE_FILTER); 563 } 564 saveToStore()565 private void saveToStore() { 566 // Set the flag to let WifiConfigStore that we have new data to write. 567 mHasNewDataToSerialize = true; 568 if (!mWifiConfigManager.saveToStore(true)) { 569 Log.w(TAG, "Failed to save to store"); 570 } 571 } 572 573 /** 574 * Enable verbose logging. 575 */ enableVerboseLogging(boolean verbose)576 public void enableVerboseLogging(boolean verbose) { 577 mVerboseLoggingEnabled = verbose; 578 } 579 580 /** 581 * Add a new callback for network request match handling. 582 */ addCallback(INetworkRequestMatchCallback callback)583 public void addCallback(INetworkRequestMatchCallback callback) { 584 if (mActiveSpecificNetworkRequest == null) { 585 Log.wtf(TAG, "No valid network request. Ignoring callback registration"); 586 try { 587 callback.onAbort(); 588 } catch (RemoteException e) { 589 Log.e(TAG, "Unable to invoke network request abort callback " + callback, e); 590 } 591 return; 592 } 593 if (mRegisteredCallbacks == null) { 594 mRegisteredCallbacks = new RemoteCallbackList<>(); 595 } 596 if (!mRegisteredCallbacks.register(callback)) { 597 Log.e(TAG, "Failed to add callback"); 598 return; 599 } 600 if (mVerboseLoggingEnabled) { 601 Log.v(TAG, "Adding callback. Num callbacks: " 602 + mRegisteredCallbacks.getRegisteredCallbackCount()); 603 } 604 // Register our user selection callback. 605 try { 606 callback.onUserSelectionCallbackRegistration( 607 new NetworkFactoryUserSelectionCallback(mActiveSpecificNetworkRequest)); 608 } catch (RemoteException e) { 609 Log.e(TAG, "Unable to invoke user selection registration callback " + callback, e); 610 return; 611 } 612 613 // If we are already in the midst of processing a request, send matching callbacks 614 // immediately on registering the callback. 615 if (mActiveMatchedScanResults != null) { 616 sendNetworkRequestMatchCallbacksForActiveRequest( 617 mActiveMatchedScanResults.values()); 618 } 619 } 620 621 /** 622 * Remove an existing callback for network request match handling. 623 */ removeCallback(INetworkRequestMatchCallback callback)624 public void removeCallback(INetworkRequestMatchCallback callback) { 625 if (mRegisteredCallbacks == null) return; 626 mRegisteredCallbacks.unregister(callback); 627 if (mVerboseLoggingEnabled) { 628 Log.v(TAG, "Removing callback. Num callbacks: " 629 + mRegisteredCallbacks.getRegisteredCallbackCount()); 630 } 631 } 632 canNewRequestOverrideExistingRequest( NetworkRequest newRequest, NetworkRequest existingRequest)633 private boolean canNewRequestOverrideExistingRequest( 634 NetworkRequest newRequest, NetworkRequest existingRequest) { 635 if (existingRequest == null) return true; 636 // Request from app with NETWORK_SETTINGS can override any existing requests. 637 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(newRequest.getRequestorUid())) { 638 return true; 639 } 640 // Request from fg app can override any existing requests. 641 if (isRequestFromForegroundApp(newRequest.getRequestorPackageName())) return true; 642 // Request from fg service can override only if the existing request is not from a fg app. 643 if (!isRequestFromForegroundApp(existingRequest.getRequestorPackageName())) return true; 644 Log.e(TAG, "Already processing request from a foreground app " 645 + existingRequest.getRequestorPackageName() + ". Rejecting request from " 646 + newRequest.getRequestorPackageName()); 647 return false; 648 } 649 isRequestWithWifiNetworkSpecifierValid(NetworkRequest networkRequest)650 boolean isRequestWithWifiNetworkSpecifierValid(NetworkRequest networkRequest) { 651 // Request cannot have internet capability since such a request can never be fulfilled. 652 // (NetworkAgent for connection with WifiNetworkSpecifier will not have internet capability) 653 if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { 654 Log.e(TAG, "Request with wifi network specifier cannot contain " 655 + "NET_CAPABILITY_INTERNET. Rejecting"); 656 return false; 657 } 658 if (networkRequest.getRequestorUid() == Process.INVALID_UID) { 659 Log.e(TAG, "Request with wifi network specifier should contain valid uid. Rejecting"); 660 return false; 661 } 662 if (TextUtils.isEmpty(networkRequest.getRequestorPackageName())) { 663 Log.e(TAG, "Request with wifi network specifier should contain valid package name." 664 + "Rejecting"); 665 return false; 666 } 667 try { 668 mAppOpsManager.checkPackage( 669 networkRequest.getRequestorUid(), networkRequest.getRequestorPackageName()); 670 } catch (SecurityException e) { 671 Log.e(TAG, "Invalid uid/package name " + networkRequest.getRequestorUid() + ", " 672 + networkRequest.getRequestorPackageName() + ". Rejecting", e); 673 return false; 674 } 675 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) networkRequest.getNetworkSpecifier(); 676 if (wns.getBand() != ScanResult.UNSPECIFIED) { 677 Log.e(TAG, "Requesting specific frequency bands is not yet supported. Rejecting"); 678 return false; 679 } 680 if (!WifiConfigurationUtil.validateNetworkSpecifier(wns)) { 681 Log.e(TAG, "Invalid wifi network specifier: " + wns + ". Rejecting "); 682 return false; 683 } 684 return true; 685 } 686 687 /** 688 * Check whether to accept the new network connection request. 689 * 690 * All the validation of the incoming request is done in this method. 691 */ 692 @Override acceptRequest(NetworkRequest networkRequest)693 public boolean acceptRequest(NetworkRequest networkRequest) { 694 NetworkSpecifier ns = networkRequest.getNetworkSpecifier(); 695 if (ns == null) { 696 // Generic wifi request. Always accept. 697 } else { 698 // Unsupported network specifier. 699 if (!(ns instanceof WifiNetworkSpecifier)) { 700 Log.e(TAG, "Unsupported network specifier: " + ns + ". Rejecting"); 701 return false; 702 } 703 // Invalid request with wifi network specifier. 704 if (!isRequestWithWifiNetworkSpecifierValid(networkRequest)) { 705 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 706 return false; 707 } 708 if (Objects.equals(mActiveSpecificNetworkRequest, networkRequest) 709 || Objects.equals(mConnectedSpecificNetworkRequest, networkRequest)) { 710 Log.e(TAG, "acceptRequest: Already processing the request " + networkRequest); 711 return true; 712 } 713 // Only allow specific wifi network request from foreground app/service. 714 if (!mWifiPermissionsUtil.checkNetworkSettingsPermission( 715 networkRequest.getRequestorUid()) 716 && !isRequestFromForegroundAppOrService( 717 networkRequest.getRequestorPackageName())) { 718 Log.e(TAG, "Request not from foreground app or service." 719 + " Rejecting request from " + networkRequest.getRequestorPackageName()); 720 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 721 return false; 722 } 723 // If there is an active request, only proceed if the new request is from a foreground 724 // app. 725 if (!canNewRequestOverrideExistingRequest( 726 networkRequest, mActiveSpecificNetworkRequest)) { 727 Log.e(TAG, "Request cannot override active request." 728 + " Rejecting request from " + networkRequest.getRequestorPackageName()); 729 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 730 return false; 731 } 732 // If there is a connected request, only proceed if the new request is from a foreground 733 // app. 734 if (!canNewRequestOverrideExistingRequest( 735 networkRequest, mConnectedSpecificNetworkRequest)) { 736 Log.e(TAG, "Request cannot override connected request." 737 + " Rejecting request from " + networkRequest.getRequestorPackageName()); 738 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 739 return false; 740 } 741 if (mVerboseLoggingEnabled) { 742 Log.v(TAG, "Accepted network request with specifier from fg " 743 + (isRequestFromForegroundApp(networkRequest.getRequestorPackageName()) 744 ? "app" : "service")); 745 } 746 } 747 if (mVerboseLoggingEnabled) { 748 Log.v(TAG, "Accepted network request " + networkRequest); 749 } 750 return true; 751 } 752 753 /** 754 * Handle new network connection requests. 755 * 756 * The assumption here is that {@link #acceptRequest(NetworkRequest)} has already sanitized 757 * the incoming request. 758 */ 759 @Override needNetworkFor(NetworkRequest networkRequest)760 protected void needNetworkFor(NetworkRequest networkRequest) { 761 NetworkSpecifier ns = networkRequest.getNetworkSpecifier(); 762 if (ns == null) { 763 // Generic wifi request. Turn on auto-join if necessary. 764 if (++mGenericConnectionReqCount == 1) { 765 mWifiConnectivityManager.setTrustedConnectionAllowed(true); 766 } 767 } else { 768 // Unsupported network specifier. 769 if (!(ns instanceof WifiNetworkSpecifier)) { 770 Log.e(TAG, "Unsupported network specifier: " + ns + ". Ignoring"); 771 return; 772 } 773 // Invalid request with wifi network specifier. 774 if (!isRequestWithWifiNetworkSpecifierValid(networkRequest)) { 775 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 776 return; 777 } 778 // Wifi-off abort early. 779 if (!mActiveModeWarden.hasPrimaryClientModeManager()) { 780 Log.e(TAG, "Request with wifi network specifier when wifi is off." 781 + "Rejecting"); 782 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 783 return; 784 } 785 if (Objects.equals(mActiveSpecificNetworkRequest, networkRequest) 786 || Objects.equals(mConnectedSpecificNetworkRequest, networkRequest)) { 787 Log.e(TAG, "needNetworkFor: Already processing the request " + networkRequest); 788 return; 789 } 790 791 retrieveWifiScanner(); 792 // Reset state from any previous request. 793 setupForActiveRequest(); 794 // Store the active network request. 795 mActiveSpecificNetworkRequest = networkRequest; 796 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) ns; 797 mActiveSpecificNetworkRequestSpecifier = new WifiNetworkSpecifier( 798 wns.ssidPatternMatcher, wns.bssidPatternMatcher, ScanResult.UNSPECIFIED, 799 wns.wifiConfiguration); 800 mWifiMetrics.incrementNetworkRequestApiNumRequest(); 801 802 if (!triggerConnectIfUserApprovedMatchFound()) { 803 // Start UI to let the user grant/disallow this request from the app. 804 startUi(); 805 // Didn't find an approved match, send the matching results to UI and trigger 806 // periodic scans for finding a network in the request. 807 // Fetch the latest cached scan results to speed up network matching. 808 ScanResult[] cachedScanResults = getFilteredCachedScanResults(); 809 if (mVerboseLoggingEnabled) { 810 Log.v(TAG, "Using cached " + cachedScanResults.length + " scan results"); 811 } 812 handleScanResults(cachedScanResults); 813 if (mActiveMatchedScanResults != null) { 814 sendNetworkRequestMatchCallbacksForActiveRequest( 815 mActiveMatchedScanResults.values()); 816 } 817 startPeriodicScans(); 818 } 819 } 820 } 821 822 @Override releaseNetworkFor(NetworkRequest networkRequest)823 protected void releaseNetworkFor(NetworkRequest networkRequest) { 824 NetworkSpecifier ns = networkRequest.getNetworkSpecifier(); 825 if (ns == null) { 826 // Generic wifi request. Turn off auto-join if necessary. 827 if (mGenericConnectionReqCount == 0) { 828 Log.e(TAG, "No valid network request to release"); 829 return; 830 } 831 if (--mGenericConnectionReqCount == 0) { 832 mWifiConnectivityManager.setTrustedConnectionAllowed(false); 833 } 834 } else { 835 // Unsupported network specifier. 836 if (!(ns instanceof WifiNetworkSpecifier)) { 837 Log.e(TAG, "Unsupported network specifier mentioned. Ignoring"); 838 return; 839 } 840 if (mActiveSpecificNetworkRequest == null && mConnectedSpecificNetworkRequest == null) { 841 Log.e(TAG, "Network release received with no active/connected request." 842 + " Ignoring"); 843 return; 844 } 845 if (Objects.equals(mActiveSpecificNetworkRequest, networkRequest)) { 846 Log.i(TAG, "App released active request, cancelling " 847 + mActiveSpecificNetworkRequest); 848 teardownForActiveRequest(); 849 } else if (Objects.equals(mConnectedSpecificNetworkRequest, networkRequest)) { 850 Log.i(TAG, "App released connected request, cancelling " 851 + mConnectedSpecificNetworkRequest); 852 teardownForConnectedNetwork(); 853 } else { 854 Log.e(TAG, "Network specifier does not match the active/connected request." 855 + " Ignoring"); 856 } 857 } 858 } 859 860 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)861 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 862 super.dump(fd, pw, args); 863 pw.println(TAG + ": mGenericConnectionReqCount " + mGenericConnectionReqCount); 864 pw.println(TAG + ": mActiveSpecificNetworkRequest " + mActiveSpecificNetworkRequest); 865 pw.println(TAG + ": mUserApprovedAccessPointMap " + mUserApprovedAccessPointMap); 866 } 867 868 /** 869 * Check if there is at least one connection request. 870 */ hasConnectionRequests()871 public boolean hasConnectionRequests() { 872 return mGenericConnectionReqCount > 0 || mActiveSpecificNetworkRequest != null 873 || mConnectedSpecificNetworkRequest != null; 874 } 875 876 /** 877 * Return the uid of the specific network request being processed if connected to the requested 878 * network. 879 * 880 * @param connectedNetwork WifiConfiguration corresponding to the connected network. 881 * @return Pair of uid & package name of the specific request (if any), else <-1, "">. 882 */ getSpecificNetworkRequestUidAndPackageName( @onNull WifiConfiguration connectedNetwork, @NonNull String connectedBssid)883 public Pair<Integer, String> getSpecificNetworkRequestUidAndPackageName( 884 @NonNull WifiConfiguration connectedNetwork, @NonNull String connectedBssid) { 885 if (mUserSelectedNetwork == null || connectedNetwork == null) { 886 return Pair.create(Process.INVALID_UID, ""); 887 } 888 if (!isUserSelectedNetwork(connectedNetwork, connectedBssid)) { 889 Log.w(TAG, "Connected to unknown network " + connectedNetwork + ":" + connectedBssid 890 + ". Ignoring..."); 891 return Pair.create(Process.INVALID_UID, ""); 892 } 893 if (mConnectedSpecificNetworkRequestSpecifier != null) { 894 return Pair.create(mConnectedSpecificNetworkRequest.getRequestorUid(), 895 mConnectedSpecificNetworkRequest.getRequestorPackageName()); 896 } 897 if (mActiveSpecificNetworkRequestSpecifier != null) { 898 return Pair.create(mActiveSpecificNetworkRequest.getRequestorUid(), 899 mActiveSpecificNetworkRequest.getRequestorPackageName()); 900 } 901 return Pair.create(Process.INVALID_UID, ""); 902 } 903 904 // Helper method to add the provided network configuration to WifiConfigManager, if it does not 905 // already exist & return the allocated network ID. This ID will be used in the CONNECT_NETWORK 906 // request to ClientModeImpl. 907 // If the network already exists, just return the network ID of the existing network. addNetworkToWifiConfigManager(@onNull WifiConfiguration network)908 private int addNetworkToWifiConfigManager(@NonNull WifiConfiguration network) { 909 WifiConfiguration existingSavedNetwork = 910 mWifiConfigManager.getConfiguredNetwork(network.getProfileKey()); 911 if (existingSavedNetwork != null) { 912 if (WifiConfigurationUtil.hasCredentialChanged(existingSavedNetwork, network)) { 913 // TODO (b/142035508): What if the user has a saved network with different 914 // credentials? 915 Log.w(TAG, "Network config already present in config manager, reusing"); 916 } 917 return existingSavedNetwork.networkId; 918 } 919 NetworkUpdateResult networkUpdateResult = 920 mWifiConfigManager.addOrUpdateNetwork( 921 network, mActiveSpecificNetworkRequest.getRequestorUid(), 922 mActiveSpecificNetworkRequest.getRequestorPackageName()); 923 if (mVerboseLoggingEnabled) { 924 Log.v(TAG, "Added network to config manager " + networkUpdateResult.getNetworkId()); 925 } 926 return networkUpdateResult.getNetworkId(); 927 } 928 929 // Helper method to remove the provided network configuration from WifiConfigManager, if it was 930 // added by an app's specifier request. disconnectAndRemoveNetworkFromWifiConfigManager( @ullable WifiConfiguration network)931 private void disconnectAndRemoveNetworkFromWifiConfigManager( 932 @Nullable WifiConfiguration network) { 933 // Trigger a disconnect first. 934 if (mClientModeManager != null) mClientModeManager.disconnect(); 935 936 if (network == null) return; 937 WifiConfiguration wcmNetwork = 938 mWifiConfigManager.getConfiguredNetwork(network.getProfileKey()); 939 if (wcmNetwork == null) { 940 Log.e(TAG, "Network not present in config manager"); 941 return; 942 } 943 // Remove the network if it was added previously by an app's specifier request. 944 if (wcmNetwork.ephemeral && wcmNetwork.fromWifiNetworkSpecifier) { 945 boolean success = 946 mWifiConfigManager.removeNetwork( 947 wcmNetwork.networkId, wcmNetwork.creatorUid, wcmNetwork.creatorName); 948 if (!success) { 949 Log.e(TAG, "Failed to remove network from config manager"); 950 } else if (mVerboseLoggingEnabled) { 951 Log.v(TAG, "Removed network from config manager " + wcmNetwork.networkId); 952 } 953 } 954 } 955 956 // Helper method to trigger a connection request & schedule a timeout alarm to track the 957 // connection request. connectToNetwork(@onNull WifiConfiguration network)958 private void connectToNetwork(@NonNull WifiConfiguration network) { 959 // Cancel connection timeout alarm for any previous connection attempts. 960 cancelConnectionTimeout(); 961 962 // First add the network to WifiConfigManager and then use the obtained networkId 963 // in the CONNECT_NETWORK request. 964 // Note: We don't do any error checks on the networkId because ClientModeImpl will do the 965 // necessary checks when processing CONNECT_NETWORK. 966 int networkId = addNetworkToWifiConfigManager(network); 967 968 mWifiMetrics.setNominatorForNetwork(networkId, 969 WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER); 970 if (mClientModeManagerRole == ROLE_CLIENT_PRIMARY) { 971 mWifiMetrics.incrementNetworkRequestApiNumConnectOnPrimaryIface(); 972 } else { 973 mWifiMetrics.incrementNetworkRequestApiNumConnectOnSecondaryIface(); 974 } 975 976 // Send the connect request to ClientModeImpl. 977 // TODO(b/117601161): Refactor this. 978 ConnectActionListener listener = new ConnectActionListener(); 979 mConnectHelper.connectToNetwork( 980 mClientModeManager, 981 new NetworkUpdateResult(networkId), 982 new ActionListenerWrapper(listener), 983 mActiveSpecificNetworkRequest.getRequestorUid()); 984 985 // Post an alarm to handle connection timeout. 986 scheduleConnectionTimeout(); 987 } 988 handleConnectToNetworkUserSelectionInternal(WifiConfiguration network)989 private void handleConnectToNetworkUserSelectionInternal(WifiConfiguration network) { 990 // Copy over the credentials from the app's request and then copy the ssid from user 991 // selection. 992 WifiConfiguration networkToConnect = 993 new WifiConfiguration(mActiveSpecificNetworkRequestSpecifier.wifiConfiguration); 994 networkToConnect.SSID = network.SSID; 995 // Set the WifiConfiguration.BSSID field to prevent roaming. 996 if (network.BSSID != null) { 997 // If pre-approved, use the bssid from the request. 998 networkToConnect.BSSID = network.BSSID; 999 } else { 1000 // If not pre-approved, find the best bssid matching the request. 1001 networkToConnect.BSSID = 1002 findBestBssidFromActiveMatchedScanResultsForNetwork( 1003 ScanResultMatchInfo.fromWifiConfiguration(networkToConnect)); 1004 } 1005 networkToConnect.ephemeral = true; 1006 // Mark it user private to avoid conflicting with any saved networks the user might have. 1007 // TODO (b/142035508): Use a more generic mechanism to fix this. 1008 networkToConnect.shared = false; 1009 networkToConnect.fromWifiNetworkSpecifier = true; 1010 1011 // TODO(b/188021807): Implement the band request from the specifier on the network to 1012 // connect. 1013 1014 // Store the user selected network. 1015 mUserSelectedNetwork = networkToConnect; 1016 1017 // Request a new CMM for the connection processing. 1018 if (mVerboseLoggingEnabled) Log.v(TAG, "Requesting new ClientModeManager instance"); 1019 mActiveModeWarden.requestLocalOnlyClientModeManager( 1020 new ClientModeManagerRequestListener(), 1021 new WorkSource(mActiveSpecificNetworkRequest.getRequestorUid(), 1022 mActiveSpecificNetworkRequest.getRequestorPackageName()), 1023 networkToConnect.SSID, networkToConnect.BSSID); 1024 } 1025 handleConnectToNetworkUserSelection(WifiConfiguration network)1026 private void handleConnectToNetworkUserSelection(WifiConfiguration network) { 1027 Log.d(TAG, "User initiated connect to network: " + network.SSID); 1028 1029 // Cancel the ongoing scans after user selection. 1030 cancelPeriodicScans(); 1031 mIsPeriodicScanEnabled = false; 1032 1033 // Trigger connection attempts. 1034 handleConnectToNetworkUserSelectionInternal(network); 1035 1036 // Add the network to the approved access point map for the app. 1037 addNetworkToUserApprovedAccessPointMap(mUserSelectedNetwork); 1038 } 1039 handleRejectUserSelection()1040 private void handleRejectUserSelection() { 1041 Log.w(TAG, "User dismissed notification, cancelling " + mActiveSpecificNetworkRequest); 1042 teardownForActiveRequest(); 1043 mWifiMetrics.incrementNetworkRequestApiNumUserReject(); 1044 } 1045 isUserSelectedNetwork(WifiConfiguration config, String bssid)1046 private boolean isUserSelectedNetwork(WifiConfiguration config, String bssid) { 1047 if (!TextUtils.equals(mUserSelectedNetwork.SSID, config.SSID)) { 1048 return false; 1049 } 1050 if (!Objects.equals( 1051 mUserSelectedNetwork.allowedKeyManagement, config.allowedKeyManagement)) { 1052 return false; 1053 } 1054 if (!TextUtils.equals(mUserSelectedNetwork.BSSID, bssid)) { 1055 return false; 1056 } 1057 return true; 1058 } 1059 1060 /** 1061 * Invoked by {@link ClientModeImpl} on end of connection attempt to a network. 1062 */ handleConnectionAttemptEnded( int failureCode, @NonNull WifiConfiguration network, @NonNull String bssid)1063 public void handleConnectionAttemptEnded( 1064 int failureCode, @NonNull WifiConfiguration network, @NonNull String bssid) { 1065 if (failureCode == WifiMetrics.ConnectionEvent.FAILURE_NONE) { 1066 handleNetworkConnectionSuccess(network, bssid); 1067 } else { 1068 handleNetworkConnectionFailure(network, bssid); 1069 } 1070 } 1071 1072 /** 1073 * Invoked by {@link ClientModeImpl} on successful connection to a network. 1074 */ handleNetworkConnectionSuccess(@onNull WifiConfiguration connectedNetwork, @NonNull String connectedBssid)1075 private void handleNetworkConnectionSuccess(@NonNull WifiConfiguration connectedNetwork, 1076 @NonNull String connectedBssid) { 1077 if (mUserSelectedNetwork == null || connectedNetwork == null 1078 || !mPendingConnectionSuccess) { 1079 return; 1080 } 1081 if (!isUserSelectedNetwork(connectedNetwork, connectedBssid)) { 1082 Log.w(TAG, "Connected to unknown network " + connectedNetwork + ":" + connectedBssid 1083 + ". Ignoring..."); 1084 return; 1085 } 1086 Log.d(TAG, "Connected to network " + mUserSelectedNetwork); 1087 if (mRegisteredCallbacks != null) { 1088 int itemCount = mRegisteredCallbacks.beginBroadcast(); 1089 for (int i = 0; i < itemCount; i++) { 1090 try { 1091 mRegisteredCallbacks.getBroadcastItem(i).onUserSelectionConnectSuccess( 1092 mUserSelectedNetwork); 1093 } catch (RemoteException e) { 1094 Log.e(TAG, "Unable to invoke network request connect failure callback ", e); 1095 } 1096 } 1097 mRegisteredCallbacks.finishBroadcast(); 1098 } 1099 // transition the request from "active" to "connected". 1100 setupForConnectedRequest(); 1101 } 1102 1103 /** 1104 * Invoked by {@link ClientModeImpl} on failure to connect to a network. 1105 */ handleNetworkConnectionFailure(@onNull WifiConfiguration failedNetwork, @NonNull String failedBssid)1106 private void handleNetworkConnectionFailure(@NonNull WifiConfiguration failedNetwork, 1107 @NonNull String failedBssid) { 1108 if (mUserSelectedNetwork == null || failedNetwork == null || !mPendingConnectionSuccess) { 1109 return; 1110 } 1111 if (!isUserSelectedNetwork(failedNetwork, failedBssid)) { 1112 Log.w(TAG, "Connection failed to unknown network " + failedNetwork + ":" + failedBssid 1113 + ". Ignoring..."); 1114 return; 1115 } 1116 Log.w(TAG, "Failed to connect to network " + mUserSelectedNetwork); 1117 if (mUserSelectedNetworkConnectRetryCount++ < USER_SELECTED_NETWORK_CONNECT_RETRY_MAX) { 1118 Log.i(TAG, "Retrying connection attempt, attempt# " 1119 + mUserSelectedNetworkConnectRetryCount); 1120 connectToNetwork(mUserSelectedNetwork); 1121 return; 1122 } 1123 Log.e(TAG, "Connection failures, cancelling " + mUserSelectedNetwork); 1124 if (mRegisteredCallbacks != null) { 1125 int itemCount = mRegisteredCallbacks.beginBroadcast(); 1126 for (int i = 0; i < itemCount; i++) { 1127 try { 1128 mRegisteredCallbacks.getBroadcastItem(i).onUserSelectionConnectFailure( 1129 mUserSelectedNetwork); 1130 } catch (RemoteException e) { 1131 Log.e(TAG, "Unable to invoke network request connect failure callback ", e); 1132 } 1133 } 1134 mRegisteredCallbacks.finishBroadcast(); 1135 } 1136 teardownForActiveRequest(); 1137 } 1138 1139 /** 1140 * Invoked by {@link ClientModeImpl} to indicate screen state changes. 1141 */ handleScreenStateChanged(boolean screenOn)1142 private void handleScreenStateChanged(boolean screenOn) { 1143 // If there is no active request or if the user has already selected a network, 1144 // ignore screen state changes. 1145 if (mActiveSpecificNetworkRequest == null || !mIsPeriodicScanEnabled) return; 1146 1147 // Pause periodic scans when the screen is off & resume when the screen is on. 1148 if (screenOn) { 1149 if (mVerboseLoggingEnabled) Log.v(TAG, "Resuming scans on screen on"); 1150 mIsPeriodicScanPaused = false; 1151 startScan(); 1152 } else { 1153 if (mVerboseLoggingEnabled) Log.v(TAG, "Pausing scans on screen off"); 1154 cancelPeriodicScans(); 1155 mIsPeriodicScanPaused = true; 1156 } 1157 } 1158 1159 // Common helper method for start/end of active request processing. cleanupActiveRequest()1160 private void cleanupActiveRequest() { 1161 // Send the abort to the UI for the current active request. 1162 if (mRegisteredCallbacks != null) { 1163 int itemCount = mRegisteredCallbacks.beginBroadcast(); 1164 for (int i = 0; i < itemCount; i++) { 1165 try { 1166 mRegisteredCallbacks.getBroadcastItem(i).onAbort(); 1167 } catch (RemoteException e) { 1168 Log.e(TAG, "Unable to invoke network request abort callback ", e); 1169 } 1170 } 1171 mRegisteredCallbacks.finishBroadcast(); 1172 } 1173 // Force-release the network request to let the app know early that the attempt failed. 1174 if (mActiveSpecificNetworkRequest != null) { 1175 releaseRequestAsUnfulfillableByAnyFactory(mActiveSpecificNetworkRequest); 1176 } 1177 // Reset the active network request. 1178 mActiveSpecificNetworkRequest = null; 1179 mActiveSpecificNetworkRequestSpecifier = null; 1180 mUserSelectedNetwork = null; 1181 mUserSelectedNetworkConnectRetryCount = 0; 1182 mIsPeriodicScanEnabled = false; 1183 mIsPeriodicScanPaused = false; 1184 mActiveMatchedScanResults = null; 1185 mPendingConnectionSuccess = false; 1186 // Cancel periodic scan, connection timeout alarm. 1187 cancelPeriodicScans(); 1188 cancelConnectionTimeout(); 1189 // Remove any callbacks registered for the request. 1190 if (mRegisteredCallbacks != null) mRegisteredCallbacks.kill(); 1191 mRegisteredCallbacks = null; 1192 } 1193 1194 // Invoked at the start of new active request processing. setupForActiveRequest()1195 private void setupForActiveRequest() { 1196 if (mActiveSpecificNetworkRequest != null) { 1197 cleanupActiveRequest(); 1198 } 1199 } 1200 removeClientModeManagerIfNecessary()1201 private void removeClientModeManagerIfNecessary() { 1202 if (mClientModeManager != null) { 1203 if (mClientModeManagerRole == ROLE_CLIENT_PRIMARY) { 1204 mWifiConnectivityManager.setSpecificNetworkRequestInProgress(false); 1205 } 1206 if (mContext.getResources().getBoolean(R.bool.config_wifiUseHalApiToDisableFwRoaming)) { 1207 mClientModeManager.enableRoaming(true); // Re-enable roaming. 1208 } 1209 mActiveModeWarden.removeClientModeManager(mClientModeManager); 1210 // For every connection attempt, get the appropriate client mode impl to use. 1211 mClientModeManager = null; 1212 mClientModeManagerRole = null; 1213 } 1214 } 1215 1216 // Invoked at the termination of current active request processing. teardownForActiveRequest()1217 private void teardownForActiveRequest() { 1218 if (mPendingConnectionSuccess) { 1219 Log.i(TAG, "Disconnecting from network on reset"); 1220 disconnectAndRemoveNetworkFromWifiConfigManager(mUserSelectedNetwork); 1221 } 1222 cleanupActiveRequest(); 1223 // ensure there is no connected request in progress. 1224 if (mConnectedSpecificNetworkRequest == null) { 1225 removeClientModeManagerIfNecessary(); 1226 } 1227 } 1228 1229 // Invoked at the start of new connected request processing. setupForConnectedRequest()1230 private void setupForConnectedRequest() { 1231 mConnectedSpecificNetworkRequest = mActiveSpecificNetworkRequest; 1232 mConnectedSpecificNetworkRequestSpecifier = mActiveSpecificNetworkRequestSpecifier; 1233 mActiveSpecificNetworkRequest = null; 1234 mActiveSpecificNetworkRequestSpecifier = null; 1235 mActiveMatchedScanResults = null; 1236 mPendingConnectionSuccess = false; 1237 // Cancel connection timeout alarm. 1238 cancelConnectionTimeout(); 1239 1240 mConnectionStartTimeMillis = mClock.getElapsedSinceBootMillis(); 1241 if (mClientModeManagerRole == ROLE_CLIENT_PRIMARY) { 1242 mWifiMetrics.incrementNetworkRequestApiNumConnectSuccessOnPrimaryIface(); 1243 } else { 1244 mWifiMetrics.incrementNetworkRequestApiNumConnectSuccessOnSecondaryIface(); 1245 // secondary STA being used, register CMI listener for concurrent connection metrics 1246 // collection. 1247 mCmiListener = new CmiListener(); 1248 mClientModeImplMonitor.registerListener(mCmiListener); 1249 } 1250 // Disable roaming. 1251 if (mContext.getResources().getBoolean(R.bool.config_wifiUseHalApiToDisableFwRoaming)) { 1252 // Note: This is an old HAL API, but since it wasn't being exercised before, we are 1253 // being extra cautious and only using it on devices running >= S. 1254 if (!mClientModeManager.enableRoaming(false)) { 1255 Log.w(TAG, "Failed to disable roaming"); 1256 } 1257 } 1258 } 1259 1260 // Invoked at the termination of current connected request processing. teardownForConnectedNetwork()1261 private void teardownForConnectedNetwork() { 1262 Log.i(TAG, "Disconnecting from network on reset"); 1263 disconnectAndRemoveNetworkFromWifiConfigManager(mUserSelectedNetwork); 1264 mConnectedSpecificNetworkRequest = null; 1265 mConnectedSpecificNetworkRequestSpecifier = null; 1266 1267 if (mConnectionStartTimeMillis != -1) { 1268 int connectionDurationSec = toIntExact(TimeUnit.MILLISECONDS.toSeconds( 1269 mClock.getElapsedSinceBootMillis() - mConnectionStartTimeMillis)); 1270 if (mClientModeManagerRole == ROLE_CLIENT_PRIMARY) { 1271 mWifiMetrics.incrementNetworkRequestApiConnectionDurationSecOnPrimaryIfaceHistogram( 1272 connectionDurationSec); 1273 1274 } else { 1275 mWifiMetrics 1276 .incrementNetworkRequestApiConnectionDurationSecOnSecondaryIfaceHistogram( 1277 connectionDurationSec); 1278 } 1279 mConnectionStartTimeMillis = -1L; 1280 } 1281 if (mCmiListener != null) { 1282 mCmiListener.checkForConcurrencyEndAndIncrementMetrics(); 1283 mClientModeImplMonitor.unregisterListener(mCmiListener); 1284 mCmiListener = null; 1285 } 1286 // ensure there is no active request in progress. 1287 if (mActiveSpecificNetworkRequest == null) { 1288 removeClientModeManagerIfNecessary(); 1289 } 1290 } 1291 1292 /** 1293 * Check if the request comes from foreground app/service. 1294 */ isRequestFromForegroundAppOrService(@onNull String requestorPackageName)1295 private boolean isRequestFromForegroundAppOrService(@NonNull String requestorPackageName) { 1296 try { 1297 return mActivityManager.getPackageImportance(requestorPackageName) 1298 <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; 1299 } catch (SecurityException e) { 1300 Log.e(TAG, "Failed to check the app state", e); 1301 return false; 1302 } 1303 } 1304 1305 /** 1306 * Check if the request comes from foreground app. 1307 */ isRequestFromForegroundApp(@onNull String requestorPackageName)1308 private boolean isRequestFromForegroundApp(@NonNull String requestorPackageName) { 1309 try { 1310 return mActivityManager.getPackageImportance(requestorPackageName) 1311 <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 1312 } catch (SecurityException e) { 1313 Log.e(TAG, "Failed to check the app state", e); 1314 return false; 1315 } 1316 } 1317 1318 /** 1319 * Helper method to populate WifiScanner handle. This is done lazily because 1320 * WifiScanningService is started after WifiService. 1321 */ retrieveWifiScanner()1322 private void retrieveWifiScanner() { 1323 if (mWifiScanner != null) return; 1324 mWifiScanner = mWifiInjector.getWifiScanner(); 1325 checkNotNull(mWifiScanner); 1326 } 1327 handleClientModeManagerRetrieval()1328 private void handleClientModeManagerRetrieval() { 1329 if (mVerboseLoggingEnabled) { 1330 Log.v(TAG, "ClientModeManager retrieved: " + mClientModeManager); 1331 } 1332 if (mUserSelectedNetwork == null) { 1333 Log.e(TAG, "No user selected network to connect to. Ignoring ClientModeManager" 1334 + "retrieval.."); 1335 return; 1336 } 1337 1338 // If using primary STA, disable Auto-join so that NetworkFactory can take control of the 1339 // network connection. 1340 if (mClientModeManagerRole == ROLE_CLIENT_PRIMARY) { 1341 mWifiConnectivityManager.setSpecificNetworkRequestInProgress(true); 1342 } 1343 1344 // Disconnect from the current network before issuing a new connect request. 1345 disconnectAndRemoveNetworkFromWifiConfigManager(mUserSelectedNetwork); 1346 1347 // Trigger connection to the network. 1348 connectToNetwork(mUserSelectedNetwork); 1349 // Triggered connection to network, now wait for the connection status. 1350 mPendingConnectionSuccess = true; 1351 } 1352 handleClientModeManagerRemovalOrFailure()1353 private void handleClientModeManagerRemovalOrFailure() { 1354 if (mActiveSpecificNetworkRequest != null) { 1355 Log.w(TAG, "ClientModeManager retrieval failed or removed, cancelling " 1356 + mActiveSpecificNetworkRequest); 1357 teardownForActiveRequest(); 1358 } 1359 if (mConnectedSpecificNetworkRequest != null) { 1360 Log.w(TAG, "ClientModeManager retrieval failed or removed, cancelling " 1361 + mConnectedSpecificNetworkRequest); 1362 teardownForConnectedNetwork(); 1363 } 1364 } 1365 startPeriodicScans()1366 private void startPeriodicScans() { 1367 if (mActiveSpecificNetworkRequestSpecifier == null) { 1368 Log.e(TAG, "Periodic scan triggered when there is no active network request. " 1369 + "Ignoring..."); 1370 return; 1371 } 1372 WifiNetworkSpecifier wns = mActiveSpecificNetworkRequestSpecifier; 1373 WifiConfiguration wifiConfiguration = wns.wifiConfiguration; 1374 if (wifiConfiguration.hiddenSSID) { 1375 // Can't search for SSID pattern in hidden networks. 1376 mScanSettings.hiddenNetworks.clear(); 1377 mScanSettings.hiddenNetworks.add(new WifiScanner.ScanSettings.HiddenNetwork( 1378 addEnclosingQuotes(wns.ssidPatternMatcher.getPath()))); 1379 } 1380 mIsPeriodicScanEnabled = true; 1381 startScan(); 1382 } 1383 cancelPeriodicScans()1384 private void cancelPeriodicScans() { 1385 if (mPeriodicScanTimerSet) { 1386 mAlarmManager.cancel(mPeriodicScanTimerListener); 1387 mPeriodicScanTimerSet = false; 1388 } 1389 // Clear the hidden networks field after each request. 1390 mScanSettings.hiddenNetworks.clear(); 1391 } 1392 scheduleNextPeriodicScan()1393 private void scheduleNextPeriodicScan() { 1394 if (mIsPeriodicScanPaused) { 1395 Log.e(TAG, "Scan triggered when periodic scanning paused. Ignoring..."); 1396 return; 1397 } 1398 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1399 mClock.getElapsedSinceBootMillis() + PERIODIC_SCAN_INTERVAL_MS, 1400 TAG, mPeriodicScanTimerListener, mHandler); 1401 mPeriodicScanTimerSet = true; 1402 } 1403 startScan()1404 private void startScan() { 1405 if (mActiveSpecificNetworkRequestSpecifier == null) { 1406 Log.e(TAG, "Scan triggered when there is no active network request. Ignoring..."); 1407 return; 1408 } 1409 if (!mIsPeriodicScanEnabled) { 1410 Log.e(TAG, "Scan triggered after user selected network. Ignoring..."); 1411 return; 1412 } 1413 if (mVerboseLoggingEnabled) { 1414 Log.v(TAG, "Starting the next scan for " + mActiveSpecificNetworkRequestSpecifier); 1415 } 1416 // Create a worksource using the caller's UID. 1417 WorkSource workSource = new WorkSource(mActiveSpecificNetworkRequest.getRequestorUid()); 1418 mWifiScanner.startScan( 1419 mScanSettings, new HandlerExecutor(mHandler), mScanListener, workSource); 1420 } 1421 doesScanResultMatchWifiNetworkSpecifier( WifiNetworkSpecifier wns, ScanResult scanResult)1422 private boolean doesScanResultMatchWifiNetworkSpecifier( 1423 WifiNetworkSpecifier wns, ScanResult scanResult) { 1424 if (!wns.ssidPatternMatcher.match(scanResult.SSID)) { 1425 return false; 1426 } 1427 MacAddress bssid = MacAddress.fromString(scanResult.BSSID); 1428 MacAddress matchBaseAddress = wns.bssidPatternMatcher.first; 1429 MacAddress matchMask = wns.bssidPatternMatcher.second; 1430 if (!bssid.matches(matchBaseAddress, matchMask)) { 1431 return false; 1432 } 1433 ScanResultMatchInfo fromScanResult = ScanResultMatchInfo.fromScanResult(scanResult); 1434 ScanResultMatchInfo fromWifiConfiguration = 1435 ScanResultMatchInfo.fromWifiConfiguration(wns.wifiConfiguration); 1436 return fromScanResult.networkTypeEquals(fromWifiConfiguration); 1437 } 1438 1439 // Loops through the scan results and finds scan results matching the active network 1440 // request. getNetworksMatchingActiveNetworkRequest( ScanResult[] scanResults)1441 private List<ScanResult> getNetworksMatchingActiveNetworkRequest( 1442 ScanResult[] scanResults) { 1443 if (mActiveSpecificNetworkRequestSpecifier == null) { 1444 Log.e(TAG, "Scan results received with no active network request. Ignoring..."); 1445 return new ArrayList<>(); 1446 } 1447 List<ScanResult> matchedScanResults = new ArrayList<>(); 1448 WifiNetworkSpecifier wns = mActiveSpecificNetworkRequestSpecifier; 1449 1450 for (ScanResult scanResult : scanResults) { 1451 if (doesScanResultMatchWifiNetworkSpecifier(wns, scanResult)) { 1452 matchedScanResults.add(scanResult); 1453 } 1454 } 1455 if (mVerboseLoggingEnabled) { 1456 Log.v(TAG, "List of scan results matching the active request " 1457 + matchedScanResults); 1458 } 1459 return matchedScanResults; 1460 } 1461 sendNetworkRequestMatchCallbacksForActiveRequest( @onNull Collection<ScanResult> matchedScanResults)1462 private void sendNetworkRequestMatchCallbacksForActiveRequest( 1463 @NonNull Collection<ScanResult> matchedScanResults) { 1464 if (matchedScanResults.isEmpty()) return; 1465 if (mRegisteredCallbacks == null 1466 || mRegisteredCallbacks.getRegisteredCallbackCount() == 0) { 1467 Log.e(TAG, "No callback registered for sending network request matches. " 1468 + "Ignoring..."); 1469 return; 1470 } 1471 int itemCount = mRegisteredCallbacks.beginBroadcast(); 1472 for (int i = 0; i < itemCount; i++) { 1473 try { 1474 mRegisteredCallbacks.getBroadcastItem(i).onMatch( 1475 new ArrayList<>(matchedScanResults)); 1476 } catch (RemoteException e) { 1477 Log.e(TAG, "Unable to invoke network request match callback ", e); 1478 } 1479 } 1480 mRegisteredCallbacks.finishBroadcast(); 1481 } 1482 cancelConnectionTimeout()1483 private void cancelConnectionTimeout() { 1484 if (mConnectionTimeoutSet) { 1485 mAlarmManager.cancel(mConnectionTimeoutAlarmListener); 1486 mConnectionTimeoutSet = false; 1487 } 1488 } 1489 scheduleConnectionTimeout()1490 private void scheduleConnectionTimeout() { 1491 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1492 mClock.getElapsedSinceBootMillis() + NETWORK_CONNECTION_TIMEOUT_MS, 1493 TAG, mConnectionTimeoutAlarmListener, mHandler); 1494 mConnectionTimeoutSet = true; 1495 } 1496 getAppName(@onNull String packageName, int uid)1497 private @NonNull CharSequence getAppName(@NonNull String packageName, int uid) { 1498 ApplicationInfo applicationInfo = null; 1499 try { 1500 applicationInfo = mContext.getPackageManager().getApplicationInfoAsUser( 1501 packageName, 0, UserHandle.getUserHandleForUid(uid)); 1502 } catch (PackageManager.NameNotFoundException e) { 1503 Log.e(TAG, "Failed to find app name for " + packageName); 1504 return ""; 1505 } 1506 CharSequence appName = mContext.getPackageManager().getApplicationLabel(applicationInfo); 1507 return (appName != null) ? appName : ""; 1508 } 1509 startUi()1510 private void startUi() { 1511 Intent intent = new Intent(); 1512 intent.setAction(UI_START_INTENT_ACTION); 1513 intent.addCategory(UI_START_INTENT_CATEGORY); 1514 intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); 1515 intent.putExtra(UI_START_INTENT_EXTRA_APP_NAME, 1516 getAppName(mActiveSpecificNetworkRequest.getRequestorPackageName(), 1517 mActiveSpecificNetworkRequest.getRequestorUid())); 1518 intent.putExtra(UI_START_INTENT_EXTRA_REQUEST_IS_FOR_SINGLE_NETWORK, 1519 isActiveRequestForSingleNetwork()); 1520 mContext.startActivityAsUser(intent, UserHandle.getUserHandleForUid( 1521 mActiveSpecificNetworkRequest.getRequestorUid())); 1522 } 1523 1524 // Helper method to determine if the specifier does not contain any patterns and matches 1525 // a single access point. isActiveRequestForSingleAccessPoint()1526 private boolean isActiveRequestForSingleAccessPoint() { 1527 if (mActiveSpecificNetworkRequestSpecifier == null) return false; 1528 1529 if (mActiveSpecificNetworkRequestSpecifier.ssidPatternMatcher.getType() 1530 != PatternMatcher.PATTERN_LITERAL) { 1531 return false; 1532 } 1533 if (!Objects.equals( 1534 mActiveSpecificNetworkRequestSpecifier.bssidPatternMatcher.second, 1535 MacAddress.BROADCAST_ADDRESS)) { 1536 return false; 1537 } 1538 return true; 1539 } 1540 1541 // Helper method to determine if the specifier does not contain any patterns and matches 1542 // a single network. isActiveRequestForSingleNetwork()1543 private boolean isActiveRequestForSingleNetwork() { 1544 if (mActiveSpecificNetworkRequestSpecifier == null) return false; 1545 1546 if (mActiveSpecificNetworkRequestSpecifier.ssidPatternMatcher.getType() 1547 == PatternMatcher.PATTERN_LITERAL) { 1548 return true; 1549 } 1550 if (Objects.equals( 1551 mActiveSpecificNetworkRequestSpecifier.bssidPatternMatcher.second, 1552 MacAddress.BROADCAST_ADDRESS)) { 1553 return true; 1554 } 1555 return false; 1556 } 1557 1558 // Will return the best bssid to use for the current request's connection. 1559 // 1560 // Note: This will never return null, unless there is some internal error. 1561 // For ex: 1562 // i) The latest scan results were empty. 1563 // ii) The latest scan result did not contain any BSSID for the SSID user chose. findBestBssidFromActiveMatchedScanResultsForNetwork( @onNull ScanResultMatchInfo scanResultMatchInfo)1564 private @Nullable String findBestBssidFromActiveMatchedScanResultsForNetwork( 1565 @NonNull ScanResultMatchInfo scanResultMatchInfo) { 1566 if (mActiveSpecificNetworkRequestSpecifier == null 1567 || mActiveMatchedScanResults == null) return null; 1568 ScanResult selectedScanResult = mActiveMatchedScanResults 1569 .values() 1570 .stream() 1571 .filter(scanResult -> Objects.equals( 1572 ScanResultMatchInfo.fromScanResult(scanResult), 1573 scanResultMatchInfo)) 1574 .max(Comparator.comparing(scanResult -> scanResult.level)) 1575 .orElse(null); 1576 if (selectedScanResult == null) { // Should never happen. 1577 Log.wtf(TAG, "Expected to find at least one matching scan result"); 1578 return null; 1579 } 1580 if (mVerboseLoggingEnabled) { 1581 Log.v(TAG, "Best bssid selected for the request " + selectedScanResult); 1582 } 1583 return selectedScanResult.BSSID; 1584 } 1585 isAccessPointApprovedInInternalApprovalList( @onNull String ssid, @NonNull MacAddress bssid, @SecurityType int networkType, @NonNull String requestorPackageName)1586 private boolean isAccessPointApprovedInInternalApprovalList( 1587 @NonNull String ssid, @NonNull MacAddress bssid, @SecurityType int networkType, 1588 @NonNull String requestorPackageName) { 1589 Set<AccessPoint> approvedAccessPoints = 1590 mUserApprovedAccessPointMap.get(requestorPackageName); 1591 if (approvedAccessPoints == null) return false; 1592 AccessPoint accessPoint = 1593 new AccessPoint(ssid, bssid, networkType); 1594 if (!approvedAccessPoints.contains(accessPoint)) return false; 1595 // keep the most recently used AP in the end 1596 approvedAccessPoints.remove(accessPoint); 1597 approvedAccessPoints.add(accessPoint); 1598 if (mVerboseLoggingEnabled) { 1599 Log.v(TAG, "Found " + bssid 1600 + " in internal user approved access point for " + requestorPackageName); 1601 } 1602 return true; 1603 } 1604 isAccessPointApprovedInCompanionDeviceManager( @onNull MacAddress bssid, @NonNull UserHandle requestorUserHandle, @NonNull String requestorPackageName)1605 private boolean isAccessPointApprovedInCompanionDeviceManager( 1606 @NonNull MacAddress bssid, 1607 @NonNull UserHandle requestorUserHandle, 1608 @NonNull String requestorPackageName) { 1609 if (mCompanionDeviceManager == null) { 1610 mCompanionDeviceManager = mContext.getSystemService(CompanionDeviceManager.class); 1611 } 1612 boolean approved = mCompanionDeviceManager.isDeviceAssociatedForWifiConnection( 1613 requestorPackageName, bssid, requestorUserHandle); 1614 if (!approved) return false; 1615 if (mVerboseLoggingEnabled) { 1616 Log.v(TAG, "Found " + bssid 1617 + " in CompanionDeviceManager approved access point for " 1618 + requestorPackageName); 1619 } 1620 return true; 1621 } 1622 isAccessPointApprovedForActiveRequest(@onNull String ssid, @NonNull MacAddress bssid, @SecurityType int networkType)1623 private boolean isAccessPointApprovedForActiveRequest(@NonNull String ssid, 1624 @NonNull MacAddress bssid, @SecurityType int networkType) { 1625 String requestorPackageName = mActiveSpecificNetworkRequest.getRequestorPackageName(); 1626 UserHandle requestorUserHandle = 1627 UserHandle.getUserHandleForUid(mActiveSpecificNetworkRequest.getRequestorUid()); 1628 // Check if access point is approved via CompanionDeviceManager first. 1629 if (isAccessPointApprovedInCompanionDeviceManager( 1630 bssid, requestorUserHandle, requestorPackageName)) { 1631 return true; 1632 } 1633 // Check if access point is approved in internal approval list next. 1634 if (isAccessPointApprovedInInternalApprovalList( 1635 ssid, bssid, networkType, requestorPackageName)) { 1636 return true; 1637 } 1638 // Shell approved app 1639 if (TextUtils.equals(mApprovedApp, requestorPackageName)) { 1640 return true; 1641 } 1642 // no bypass approvals, show UI. 1643 return false; 1644 } 1645 1646 1647 // Helper method to store the all the BSSIDs matching the network from the matched scan results addNetworkToUserApprovedAccessPointMap(@onNull WifiConfiguration network)1648 private void addNetworkToUserApprovedAccessPointMap(@NonNull WifiConfiguration network) { 1649 if (mActiveSpecificNetworkRequestSpecifier == null 1650 || mActiveMatchedScanResults == null) return; 1651 // Note: This hopefully is a list of size 1, because we want to store a 1:1 mapping 1652 // from user selection and the AP that was approved. But, since we get a WifiConfiguration 1653 // object representing an entire network from UI, we need to ensure that all the visible 1654 // BSSIDs matching the original request and the selected network are stored. 1655 Set<AccessPoint> newUserApprovedAccessPoints = new HashSet<>(); 1656 1657 ScanResultMatchInfo fromWifiConfiguration = 1658 ScanResultMatchInfo.fromWifiConfiguration(network); 1659 for (ScanResult scanResult : mActiveMatchedScanResults.values()) { 1660 ScanResultMatchInfo fromScanResult = ScanResultMatchInfo.fromScanResult(scanResult); 1661 SecurityParams params = fromScanResult.matchForNetworkSelection(fromWifiConfiguration); 1662 if (null != params) { 1663 AccessPoint approvedAccessPoint = 1664 new AccessPoint(scanResult.SSID, MacAddress.fromString(scanResult.BSSID), 1665 params.getSecurityType()); 1666 newUserApprovedAccessPoints.add(approvedAccessPoint); 1667 } 1668 } 1669 if (newUserApprovedAccessPoints.isEmpty()) return; 1670 1671 String requestorPackageName = mActiveSpecificNetworkRequest.getRequestorPackageName(); 1672 LinkedHashSet<AccessPoint> approvedAccessPoints = 1673 mUserApprovedAccessPointMap.get(requestorPackageName); 1674 if (approvedAccessPoints == null) { 1675 approvedAccessPoints = new LinkedHashSet<>(); 1676 mUserApprovedAccessPointMap.put(requestorPackageName, approvedAccessPoints); 1677 // Note the new app in metrics. 1678 mWifiMetrics.incrementNetworkRequestApiNumApps(); 1679 } 1680 if (mVerboseLoggingEnabled) { 1681 Log.v(TAG, "Adding " + newUserApprovedAccessPoints 1682 + " to user approved access point for " + requestorPackageName); 1683 } 1684 // keep the most recently added APs in the end 1685 approvedAccessPoints.removeAll(newUserApprovedAccessPoints); 1686 approvedAccessPoints.addAll(newUserApprovedAccessPoints); 1687 cleanUpLRUAccessPoints(approvedAccessPoints); 1688 saveToStore(); 1689 } 1690 1691 /** 1692 * 1) If the request is for a single bssid, check if the matching ScanResult was pre-approved 1693 * by the user. 1694 * 2) If yes to (b), trigger a connect immediately and returns true. Else, returns false. 1695 * 1696 * @return true if a pre-approved network was found for connection, false otherwise. 1697 */ triggerConnectIfUserApprovedMatchFound()1698 private boolean triggerConnectIfUserApprovedMatchFound() { 1699 if (mActiveSpecificNetworkRequestSpecifier == null) return false; 1700 if (!isActiveRequestForSingleAccessPoint()) return false; 1701 String ssid = mActiveSpecificNetworkRequestSpecifier.ssidPatternMatcher.getPath(); 1702 MacAddress bssid = mActiveSpecificNetworkRequestSpecifier.bssidPatternMatcher.first; 1703 SecurityParams params = 1704 ScanResultMatchInfo.fromWifiConfiguration( 1705 mActiveSpecificNetworkRequestSpecifier.wifiConfiguration) 1706 .getFirstAvailableSecurityParams(); 1707 if (null == params) return false; 1708 int networkType = params.getSecurityType(); 1709 if (!isAccessPointApprovedForActiveRequest(ssid, bssid, networkType) 1710 || mWifiConfigManager.isNetworkTemporarilyDisabledByUser( 1711 ScanResultUtil.createQuotedSSID(ssid))) { 1712 if (mVerboseLoggingEnabled) { 1713 Log.v(TAG, "No approved access point found"); 1714 } 1715 return false; 1716 } 1717 Log.v(TAG, "Approved access point found in matching scan results. " 1718 + "Triggering connect " + ssid + "/" + bssid); 1719 WifiConfiguration config = mActiveSpecificNetworkRequestSpecifier.wifiConfiguration; 1720 config.SSID = "\"" + ssid + "\""; 1721 config.BSSID = bssid.toString(); 1722 handleConnectToNetworkUserSelectionInternal(config); 1723 mWifiMetrics.incrementNetworkRequestApiNumUserApprovalBypass(); 1724 return true; 1725 } 1726 1727 /** 1728 * Handle scan results 1729 * 1730 * @param scanResults Array of {@link ScanResult} to be processed. 1731 */ handleScanResults(ScanResult[] scanResults)1732 private void handleScanResults(ScanResult[] scanResults) { 1733 List<ScanResult> matchedScanResults = 1734 getNetworksMatchingActiveNetworkRequest(scanResults); 1735 if ((mActiveMatchedScanResults == null || mActiveMatchedScanResults.isEmpty()) 1736 && !matchedScanResults.isEmpty()) { 1737 // only note the first match size in metrics (chances of this changing in further 1738 // scans is pretty low) 1739 mWifiMetrics.incrementNetworkRequestApiMatchSizeHistogram( 1740 matchedScanResults.size()); 1741 } 1742 // First set of scan results for this request. 1743 if (mActiveMatchedScanResults == null) mActiveMatchedScanResults = new HashMap<>(); 1744 // Coalesce the new set of scan results with previous scan results received for request. 1745 mActiveMatchedScanResults.putAll(matchedScanResults 1746 .stream() 1747 .collect(Collectors.toMap( 1748 scanResult -> scanResult.BSSID, scanResult -> scanResult, (a, b) -> a))); 1749 // Weed out any stale cached scan results. 1750 long currentTimeInMillis = mClock.getElapsedSinceBootMillis(); 1751 mActiveMatchedScanResults.entrySet().removeIf( 1752 e -> ((currentTimeInMillis - (e.getValue().timestamp / 1000)) 1753 >= CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS)); 1754 } 1755 1756 /** 1757 * Retrieve the latest cached scan results from wifi scanner and filter out any 1758 * {@link ScanResult} older than {@link #CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}. 1759 */ getFilteredCachedScanResults()1760 private @NonNull ScanResult[] getFilteredCachedScanResults() { 1761 List<ScanResult> cachedScanResults = mWifiScanner.getSingleScanResults(); 1762 if (cachedScanResults == null || cachedScanResults.isEmpty()) return new ScanResult[0]; 1763 long currentTimeInMillis = mClock.getElapsedSinceBootMillis(); 1764 return cachedScanResults.stream() 1765 .filter(scanResult 1766 -> ((currentTimeInMillis - (scanResult.timestamp / 1000)) 1767 < CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS)) 1768 .toArray(ScanResult[]::new); 1769 } 1770 1771 /** 1772 * Clean up least recently used Access Points if specified app reach the limit. 1773 */ cleanUpLRUAccessPoints(Set<AccessPoint> approvedAccessPoints)1774 private static void cleanUpLRUAccessPoints(Set<AccessPoint> approvedAccessPoints) { 1775 if (approvedAccessPoints.size() <= NUM_OF_ACCESS_POINT_LIMIT_PER_APP) { 1776 return; 1777 } 1778 Iterator iter = approvedAccessPoints.iterator(); 1779 while (iter.hasNext() && approvedAccessPoints.size() > NUM_OF_ACCESS_POINT_LIMIT_PER_APP) { 1780 iter.next(); 1781 iter.remove(); 1782 } 1783 } 1784 1785 /** 1786 * Sets all access points approved for the specified app. 1787 * Used by shell commands. 1788 */ setUserApprovedApp(@onNull String packageName, boolean approved)1789 public void setUserApprovedApp(@NonNull String packageName, boolean approved) { 1790 if (approved) { 1791 mApprovedApp = packageName; 1792 } else if (TextUtils.equals(packageName, mApprovedApp)) { 1793 mApprovedApp = null; 1794 } 1795 } 1796 1797 /** 1798 * Whether all access points are approved for the specified app. 1799 * Used by shell commands. 1800 */ hasUserApprovedApp(@onNull String packageName)1801 public boolean hasUserApprovedApp(@NonNull String packageName) { 1802 return TextUtils.equals(packageName, mApprovedApp); 1803 } 1804 1805 /** 1806 * Remove all user approved access points for the specified app. 1807 */ removeUserApprovedAccessPointsForApp(@onNull String packageName)1808 public void removeUserApprovedAccessPointsForApp(@NonNull String packageName) { 1809 if (mUserApprovedAccessPointMap.remove(packageName) != null) { 1810 Log.i(TAG, "Removing all approved access points for " + packageName); 1811 } 1812 saveToStore(); 1813 } 1814 1815 /** 1816 * Clear all internal state (for network settings reset). 1817 */ clear()1818 public void clear() { 1819 mUserApprovedAccessPointMap.clear(); 1820 mApprovedApp = null; 1821 Log.i(TAG, "Cleared all internal state"); 1822 saveToStore(); 1823 } 1824 } 1825