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