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