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