1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import static com.android.internal.util.Preconditions.checkNotNull; 20 import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.app.ActivityManager; 25 import android.app.AlarmManager; 26 import android.app.AppOpsManager; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.pm.ApplicationInfo; 30 import android.content.pm.PackageManager; 31 import android.net.MacAddress; 32 import android.net.NetworkCapabilities; 33 import android.net.NetworkFactory; 34 import android.net.NetworkRequest; 35 import android.net.NetworkSpecifier; 36 import android.net.wifi.INetworkRequestMatchCallback; 37 import android.net.wifi.INetworkRequestUserSelectionCallback; 38 import android.net.wifi.ScanResult; 39 import android.net.wifi.WifiConfiguration; 40 import android.net.wifi.WifiConfiguration.SecurityType; 41 import android.net.wifi.WifiManager; 42 import android.net.wifi.WifiNetworkSpecifier; 43 import android.net.wifi.WifiScanner; 44 import android.os.Handler; 45 import android.os.IBinder; 46 import android.os.Looper; 47 import android.os.Message; 48 import android.os.Messenger; 49 import android.os.PatternMatcher; 50 import android.os.Process; 51 import android.os.RemoteException; 52 import android.os.UserHandle; 53 import android.os.WorkSource; 54 import android.text.TextUtils; 55 import android.util.Log; 56 import android.util.Pair; 57 58 import com.android.internal.annotations.VisibleForTesting; 59 import com.android.server.wifi.nano.WifiMetricsProto; 60 import com.android.server.wifi.util.ExternalCallbackTracker; 61 import com.android.server.wifi.util.ScanResultUtil; 62 import com.android.server.wifi.util.WifiPermissionsUtil; 63 64 import java.io.FileDescriptor; 65 import java.io.PrintWriter; 66 import java.util.ArrayList; 67 import java.util.Comparator; 68 import java.util.HashMap; 69 import java.util.HashSet; 70 import java.util.Iterator; 71 import java.util.List; 72 import java.util.Map; 73 import java.util.Objects; 74 import java.util.Set; 75 76 /** 77 * Network factory to handle trusted wifi network requests. 78 */ 79 public class WifiNetworkFactory extends NetworkFactory { 80 private static final String TAG = "WifiNetworkFactory"; 81 @VisibleForTesting 82 private static final int SCORE_FILTER = 60; 83 @VisibleForTesting 84 public static final int PERIODIC_SCAN_INTERVAL_MS = 10 * 1000; // 10 seconds 85 @VisibleForTesting 86 public static final int NETWORK_CONNECTION_TIMEOUT_MS = 30 * 1000; // 30 seconds 87 @VisibleForTesting 88 public static final int USER_SELECTED_NETWORK_CONNECT_RETRY_MAX = 3; // max of 3 retries. 89 @VisibleForTesting 90 public static final String UI_START_INTENT_ACTION = 91 "com.android.settings.wifi.action.NETWORK_REQUEST"; 92 @VisibleForTesting 93 public static final String UI_START_INTENT_CATEGORY = "android.intent.category.DEFAULT"; 94 @VisibleForTesting 95 public static final String UI_START_INTENT_EXTRA_APP_NAME = 96 "com.android.settings.wifi.extra.APP_NAME"; 97 @VisibleForTesting 98 public static final String UI_START_INTENT_EXTRA_REQUEST_IS_FOR_SINGLE_NETWORK = 99 "com.android.settings.wifi.extra.REQUEST_IS_FOR_SINGLE_NETWORK"; 100 101 private final Context mContext; 102 private final ActivityManager mActivityManager; 103 private final AlarmManager mAlarmManager; 104 private final AppOpsManager mAppOpsManager; 105 private final Clock mClock; 106 private final Handler mHandler; 107 private final WifiInjector mWifiInjector; 108 private final WifiConnectivityManager mWifiConnectivityManager; 109 private final WifiConfigManager mWifiConfigManager; 110 private final WifiConfigStore mWifiConfigStore; 111 private final WifiPermissionsUtil mWifiPermissionsUtil; 112 private final WifiMetrics mWifiMetrics; 113 private final WifiScanner.ScanSettings mScanSettings; 114 private final NetworkFactoryScanListener mScanListener; 115 private final PeriodicScanAlarmListener mPeriodicScanTimerListener; 116 private final ConnectionTimeoutAlarmListener mConnectionTimeoutAlarmListener; 117 private final ExternalCallbackTracker<INetworkRequestMatchCallback> mRegisteredCallbacks; 118 private final Messenger mSrcMessenger; 119 // Store all user approved access points for apps. 120 // TODO(b/122658039): Persist this. 121 private final Map<String, Set<AccessPoint>> mUserApprovedAccessPointMap = new HashMap<>(); 122 private WifiScanner mWifiScanner; 123 124 private int mGenericConnectionReqCount = 0; 125 // Request that is being actively processed. All new requests start out as an "active" request 126 // because we're processing it & handling all the user interactions associated with it. Once we 127 // successfully connect to the network, we transition that request to "connected". 128 private NetworkRequest mActiveSpecificNetworkRequest; 129 private WifiNetworkSpecifier mActiveSpecificNetworkRequestSpecifier; 130 // Request corresponding to the the network that the device is currently connected to. 131 private NetworkRequest mConnectedSpecificNetworkRequest; 132 private WifiNetworkSpecifier mConnectedSpecificNetworkRequestSpecifier; 133 private WifiConfiguration mUserSelectedNetwork; 134 private int mUserSelectedNetworkConnectRetryCount; 135 private List<ScanResult> mActiveMatchedScanResults; 136 // Verbose logging flag. 137 private boolean mVerboseLoggingEnabled = false; 138 private boolean mPeriodicScanTimerSet = false; 139 private boolean mConnectionTimeoutSet = false; 140 private boolean mIsPeriodicScanPaused = false; 141 // We sent a new connection request and are waiting for connection success. 142 private boolean mPendingConnectionSuccess = false; 143 private boolean mWifiEnabled = false; 144 /** 145 * Indicates that we have new data to serialize. 146 */ 147 private boolean mHasNewDataToSerialize = false; 148 149 /** 150 * Helper class to store an access point that the user previously approved for a specific app. 151 * TODO(b/123014687): Move to a common util class. 152 */ 153 public static class AccessPoint { 154 public final String ssid; 155 public final MacAddress bssid; 156 public final @SecurityType int networkType; 157 AccessPoint(@onNull String ssid, @NonNull MacAddress bssid, @SecurityType int networkType)158 AccessPoint(@NonNull String ssid, @NonNull MacAddress bssid, 159 @SecurityType int networkType) { 160 this.ssid = ssid; 161 this.bssid = bssid; 162 this.networkType = networkType; 163 } 164 165 @Override hashCode()166 public int hashCode() { 167 return Objects.hash(ssid, bssid, networkType); 168 } 169 170 @Override equals(Object obj)171 public boolean equals(Object obj) { 172 if (this == obj) { 173 return true; 174 } 175 if (!(obj instanceof AccessPoint)) { 176 return false; 177 } 178 AccessPoint other = (AccessPoint) obj; 179 return TextUtils.equals(this.ssid, other.ssid) 180 && Objects.equals(this.bssid, other.bssid) 181 && this.networkType == other.networkType; 182 } 183 184 @Override toString()185 public String toString() { 186 StringBuilder sb = new StringBuilder("AccessPoint: "); 187 return sb.append(ssid) 188 .append(", ") 189 .append(bssid) 190 .append(", ") 191 .append(networkType) 192 .toString(); 193 } 194 } 195 196 // Scan listener for scan requests. 197 private class NetworkFactoryScanListener implements WifiScanner.ScanListener { 198 @Override onSuccess()199 public void onSuccess() { 200 // Scan request succeeded, wait for results to report to external clients. 201 if (mVerboseLoggingEnabled) { 202 Log.d(TAG, "Scan request succeeded"); 203 } 204 } 205 206 @Override onFailure(int reason, String description)207 public void onFailure(int reason, String description) { 208 Log.e(TAG, "Scan failure received. reason: " + reason 209 + ", description: " + description); 210 // TODO(b/113878056): Retry scan to workaround any transient scan failures. 211 scheduleNextPeriodicScan(); 212 } 213 214 @Override onResults(WifiScanner.ScanData[] scanDatas)215 public void onResults(WifiScanner.ScanData[] scanDatas) { 216 if (mVerboseLoggingEnabled) { 217 Log.d(TAG, "Scan results received"); 218 } 219 // For single scans, the array size should always be 1. 220 if (scanDatas.length != 1) { 221 Log.wtf(TAG, "Found more than 1 batch of scan results, Ignoring..."); 222 return; 223 } 224 WifiScanner.ScanData scanData = scanDatas[0]; 225 ScanResult[] scanResults = scanData.getResults(); 226 if (mVerboseLoggingEnabled) { 227 Log.v(TAG, "Received " + scanResults.length + " scan results"); 228 } 229 List<ScanResult> matchedScanResults = 230 getNetworksMatchingActiveNetworkRequest(scanResults); 231 if (mActiveMatchedScanResults == null) { 232 // only note the first match size in metrics (chances of this changing in further 233 // scans is pretty low) 234 mWifiMetrics.incrementNetworkRequestApiMatchSizeHistogram( 235 matchedScanResults.size()); 236 } 237 mActiveMatchedScanResults = matchedScanResults; 238 239 ScanResult approvedScanResult = null; 240 if (isActiveRequestForSingleAccessPoint()) { 241 approvedScanResult = 242 findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults(); 243 } 244 if (approvedScanResult != null 245 && !mWifiConfigManager.wasEphemeralNetworkDeleted( 246 ScanResultUtil.createQuotedSSID(approvedScanResult.SSID))) { 247 Log.v(TAG, "Approved access point found in matching scan results. " 248 + "Triggering connect " + approvedScanResult); 249 handleConnectToNetworkUserSelectionInternal( 250 ScanResultUtil.createNetworkFromScanResult(approvedScanResult)); 251 mWifiMetrics.incrementNetworkRequestApiNumUserApprovalBypass(); 252 // TODO (b/122658039): Post notification. 253 } else { 254 if (mVerboseLoggingEnabled) { 255 Log.v(TAG, "No approved access points found in matching scan results. " 256 + "Sending match callback"); 257 } 258 sendNetworkRequestMatchCallbacksForActiveRequest(matchedScanResults); 259 // Didn't find an approved match, schedule the next scan. 260 scheduleNextPeriodicScan(); 261 } 262 } 263 264 @Override onFullResult(ScanResult fullScanResult)265 public void onFullResult(ScanResult fullScanResult) { 266 // Ignore for single scans. 267 } 268 269 @Override onPeriodChanged(int periodInMs)270 public void onPeriodChanged(int periodInMs) { 271 // Ignore for single scans. 272 } 273 }; 274 275 private class PeriodicScanAlarmListener implements AlarmManager.OnAlarmListener { 276 @Override onAlarm()277 public void onAlarm() { 278 // Trigger the next scan. 279 startScan(); 280 } 281 } 282 283 private class ConnectionTimeoutAlarmListener implements AlarmManager.OnAlarmListener { 284 @Override onAlarm()285 public void onAlarm() { 286 Log.e(TAG, "Timed-out connecting to network"); 287 handleNetworkConnectionFailure(mUserSelectedNetwork); 288 } 289 } 290 291 // Callback result from settings UI. 292 private class NetworkFactoryUserSelectionCallback extends 293 INetworkRequestUserSelectionCallback.Stub { 294 private final NetworkRequest mNetworkRequest; 295 NetworkFactoryUserSelectionCallback(NetworkRequest networkRequest)296 NetworkFactoryUserSelectionCallback(NetworkRequest networkRequest) { 297 mNetworkRequest = networkRequest; 298 } 299 300 @Override select(WifiConfiguration wifiConfiguration)301 public void select(WifiConfiguration wifiConfiguration) { 302 mHandler.post(() -> { 303 if (mActiveSpecificNetworkRequest != mNetworkRequest) { 304 Log.e(TAG, "Stale callback select received"); 305 return; 306 } 307 handleConnectToNetworkUserSelection(wifiConfiguration); 308 }); 309 } 310 311 @Override reject()312 public void reject() { 313 mHandler.post(() -> { 314 if (mActiveSpecificNetworkRequest != mNetworkRequest) { 315 Log.e(TAG, "Stale callback reject received"); 316 return; 317 } 318 handleRejectUserSelection(); 319 }); 320 } 321 } 322 323 private final Handler.Callback mNetworkConnectionTriggerCallback = (Message msg) -> { 324 switch (msg.what) { 325 // Success here means that an attempt to connect to the network has been initiated. 326 case WifiManager.CONNECT_NETWORK_SUCCEEDED: 327 if (mVerboseLoggingEnabled) { 328 Log.v(TAG, "Triggered network connection"); 329 } 330 break; 331 case WifiManager.CONNECT_NETWORK_FAILED: 332 Log.e(TAG, "Failed to trigger network connection"); 333 handleNetworkConnectionFailure(mUserSelectedNetwork); 334 break; 335 default: 336 Log.e(TAG, "Unknown message " + msg.what); 337 } 338 return true; 339 }; 340 341 /** 342 * Module to interact with the wifi config store. 343 */ 344 private class NetworkRequestDataSource implements NetworkRequestStoreData.DataSource { 345 @Override toSerialize()346 public Map<String, Set<AccessPoint>> toSerialize() { 347 // Clear the flag after writing to disk. 348 mHasNewDataToSerialize = false; 349 return mUserApprovedAccessPointMap; 350 } 351 352 @Override fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPointMap)353 public void fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPointMap) { 354 mUserApprovedAccessPointMap.putAll(approvedAccessPointMap); 355 } 356 357 @Override reset()358 public void reset() { 359 mUserApprovedAccessPointMap.clear(); 360 } 361 362 @Override hasNewDataToSerialize()363 public boolean hasNewDataToSerialize() { 364 return mHasNewDataToSerialize; 365 } 366 } 367 WifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, ActivityManager activityManager, AlarmManager alarmManager, AppOpsManager appOpsManager, Clock clock, WifiInjector wifiInjector, WifiConnectivityManager connectivityManager, WifiConfigManager configManager, WifiConfigStore configStore, WifiPermissionsUtil wifiPermissionsUtil, WifiMetrics wifiMetrics)368 public WifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, 369 ActivityManager activityManager, AlarmManager alarmManager, 370 AppOpsManager appOpsManager, 371 Clock clock, WifiInjector wifiInjector, 372 WifiConnectivityManager connectivityManager, 373 WifiConfigManager configManager, 374 WifiConfigStore configStore, 375 WifiPermissionsUtil wifiPermissionsUtil, 376 WifiMetrics wifiMetrics) { 377 super(looper, context, TAG, nc); 378 mContext = context; 379 mActivityManager = activityManager; 380 mAlarmManager = alarmManager; 381 mAppOpsManager = appOpsManager; 382 mClock = clock; 383 mHandler = new Handler(looper); 384 mWifiInjector = wifiInjector; 385 mWifiConnectivityManager = connectivityManager; 386 mWifiConfigManager = configManager; 387 mWifiConfigStore = configStore; 388 mWifiPermissionsUtil = wifiPermissionsUtil; 389 mWifiMetrics = wifiMetrics; 390 // Create the scan settings. 391 mScanSettings = new WifiScanner.ScanSettings(); 392 mScanSettings.type = WifiScanner.TYPE_HIGH_ACCURACY; 393 mScanSettings.band = WifiScanner.WIFI_BAND_BOTH_WITH_DFS; 394 mScanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 395 mScanListener = new NetworkFactoryScanListener(); 396 mPeriodicScanTimerListener = new PeriodicScanAlarmListener(); 397 mConnectionTimeoutAlarmListener = new ConnectionTimeoutAlarmListener(); 398 mRegisteredCallbacks = new ExternalCallbackTracker<INetworkRequestMatchCallback>(mHandler); 399 mSrcMessenger = new Messenger(new Handler(looper, mNetworkConnectionTriggerCallback)); 400 401 // register the data store for serializing/deserializing data. 402 configStore.registerStoreData( 403 wifiInjector.makeNetworkRequestStoreData(new NetworkRequestDataSource())); 404 405 setScoreFilter(SCORE_FILTER); 406 } 407 saveToStore()408 private void saveToStore() { 409 // Set the flag to let WifiConfigStore that we have new data to write. 410 mHasNewDataToSerialize = true; 411 if (!mWifiConfigManager.saveToStore(true)) { 412 Log.w(TAG, "Failed to save to store"); 413 } 414 } 415 416 /** 417 * Enable verbose logging. 418 */ enableVerboseLogging(int verbose)419 public void enableVerboseLogging(int verbose) { 420 mVerboseLoggingEnabled = (verbose > 0); 421 } 422 423 /** 424 * Add a new callback for network request match handling. 425 */ addCallback(IBinder binder, INetworkRequestMatchCallback callback, int callbackIdentifier)426 public void addCallback(IBinder binder, INetworkRequestMatchCallback callback, 427 int callbackIdentifier) { 428 if (mActiveSpecificNetworkRequest == null) { 429 Log.wtf(TAG, "No valid network request. Ignoring callback registration"); 430 try { 431 callback.onAbort(); 432 } catch (RemoteException e) { 433 Log.e(TAG, "Unable to invoke network request abort callback " + callback, e); 434 } 435 return; 436 } 437 if (!mRegisteredCallbacks.add(binder, callback, callbackIdentifier)) { 438 Log.e(TAG, "Failed to add callback"); 439 return; 440 } 441 if (mVerboseLoggingEnabled) { 442 Log.v(TAG, "Adding callback. Num callbacks: " + mRegisteredCallbacks.getNumCallbacks()); 443 } 444 // Register our user selection callback. 445 try { 446 callback.onUserSelectionCallbackRegistration( 447 new NetworkFactoryUserSelectionCallback(mActiveSpecificNetworkRequest)); 448 } catch (RemoteException e) { 449 Log.e(TAG, "Unable to invoke user selection registration callback " + callback, e); 450 } 451 } 452 453 /** 454 * Remove an existing callback for network request match handling. 455 */ removeCallback(int callbackIdentifier)456 public void removeCallback(int callbackIdentifier) { 457 mRegisteredCallbacks.remove(callbackIdentifier); 458 if (mVerboseLoggingEnabled) { 459 Log.v(TAG, "Removing callback. Num callbacks: " 460 + mRegisteredCallbacks.getNumCallbacks()); 461 } 462 } 463 canNewRequestOverrideExistingRequest( WifiNetworkSpecifier newRequest, WifiNetworkSpecifier existingRequest)464 private boolean canNewRequestOverrideExistingRequest( 465 WifiNetworkSpecifier newRequest, WifiNetworkSpecifier existingRequest) { 466 if (existingRequest == null) return true; 467 // Request from app with NETWORK_SETTINGS can override any existing requests. 468 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(newRequest.requestorUid)) { 469 return true; 470 } 471 // Request from fg app can override any existing requests. 472 if (isRequestFromForegroundApp(newRequest.requestorPackageName)) return true; 473 // Request from fg service can override only if the existing request is not from a fg app. 474 if (!isRequestFromForegroundApp(existingRequest.requestorPackageName)) return true; 475 Log.e(TAG, "Already processing request from a foreground app " 476 + existingRequest.requestorPackageName + ". Rejecting request from " 477 + newRequest.requestorPackageName); 478 return false; 479 } 480 isRequestWithNetworkSpecifierValid(NetworkRequest networkRequest)481 boolean isRequestWithNetworkSpecifierValid(NetworkRequest networkRequest) { 482 NetworkSpecifier ns = networkRequest.networkCapabilities.getNetworkSpecifier(); 483 // Invalid network specifier. 484 if (!(ns instanceof WifiNetworkSpecifier)) { 485 Log.e(TAG, "Invalid network specifier mentioned. Rejecting"); 486 return false; 487 } 488 // Request cannot have internet capability since such a request can never be fulfilled. 489 // (NetworkAgent for connection with WifiNetworkSpecifier will not have internet capability) 490 if (networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { 491 Log.e(TAG, "Request with wifi network specifier cannot contain " 492 + "NET_CAPABILITY_INTERNET. Rejecting"); 493 return false; 494 } 495 return true; 496 } 497 498 /** 499 * Check whether to accept the new network connection request. 500 * 501 * All the validation of the incoming request is done in this method. 502 */ 503 @Override acceptRequest(NetworkRequest networkRequest, int score)504 public boolean acceptRequest(NetworkRequest networkRequest, int score) { 505 NetworkSpecifier ns = networkRequest.networkCapabilities.getNetworkSpecifier(); 506 if (ns == null) { 507 // Generic wifi request. Always accept. 508 } else { 509 // Invalid request with network specifier. 510 if (!isRequestWithNetworkSpecifierValid(networkRequest)) { 511 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 512 return false; 513 } 514 if (!mWifiEnabled) { 515 // Will re-evaluate when wifi is turned on. 516 Log.e(TAG, "Wifi off. Rejecting"); 517 return false; 518 } 519 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) ns; 520 if (!WifiConfigurationUtil.validateNetworkSpecifier(wns)) { 521 Log.e(TAG, "Invalid network specifier." 522 + " Rejecting request from " + wns.requestorPackageName); 523 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 524 return false; 525 } 526 try { 527 mAppOpsManager.checkPackage(wns.requestorUid, wns.requestorPackageName); 528 } catch (SecurityException e) { 529 Log.e(TAG, "Invalid uid/package name " + wns.requestorPackageName + ", " 530 + wns.requestorPackageName, e); 531 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 532 return false; 533 } 534 // Only allow specific wifi network request from foreground app/service. 535 if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(wns.requestorUid) 536 && !isRequestFromForegroundAppOrService(wns.requestorPackageName)) { 537 Log.e(TAG, "Request not from foreground app or service." 538 + " Rejecting request from " + wns.requestorPackageName); 539 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 540 return false; 541 } 542 // If there is an active request, only proceed if the new request is from a foreground 543 // app. 544 if (!canNewRequestOverrideExistingRequest( 545 wns, mActiveSpecificNetworkRequestSpecifier)) { 546 Log.e(TAG, "Request cannot override active request." 547 + " Rejecting request from " + wns.requestorPackageName); 548 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 549 return false; 550 } 551 // If there is a connected request, only proceed if the new request is from a foreground 552 // app. 553 if (!canNewRequestOverrideExistingRequest( 554 wns, mConnectedSpecificNetworkRequestSpecifier)) { 555 Log.e(TAG, "Request cannot override connected request." 556 + " Rejecting request from " + wns.requestorPackageName); 557 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 558 return false; 559 } 560 if (mVerboseLoggingEnabled) { 561 Log.v(TAG, "Accepted network request with specifier from fg " 562 + (isRequestFromForegroundApp(wns.requestorPackageName) 563 ? "app" : "service")); 564 } 565 } 566 if (mVerboseLoggingEnabled) { 567 Log.v(TAG, "Accepted network request " + networkRequest); 568 } 569 return true; 570 } 571 572 /** 573 * Handle new network connection requests. 574 * 575 * The assumption here is that {@link #acceptRequest(NetworkRequest, int)} has already sanitized 576 * the incoming request. 577 */ 578 @Override needNetworkFor(NetworkRequest networkRequest, int score)579 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 580 NetworkSpecifier ns = networkRequest.networkCapabilities.getNetworkSpecifier(); 581 if (ns == null) { 582 // Generic wifi request. Turn on auto-join if necessary. 583 if (++mGenericConnectionReqCount == 1) { 584 mWifiConnectivityManager.setTrustedConnectionAllowed(true); 585 } 586 } else { 587 // Invalid request with network specifier. 588 if (!isRequestWithNetworkSpecifierValid(networkRequest)) { 589 releaseRequestAsUnfulfillableByAnyFactory(networkRequest); 590 return; 591 } 592 if (!mWifiEnabled) { 593 // Will re-evaluate when wifi is turned on. 594 Log.e(TAG, "Wifi off. Rejecting"); 595 return; 596 } 597 retrieveWifiScanner(); 598 // Reset state from any previous request. 599 setupForActiveRequest(); 600 601 // Store the active network request. 602 mActiveSpecificNetworkRequest = new NetworkRequest(networkRequest); 603 WifiNetworkSpecifier wns = (WifiNetworkSpecifier) ns; 604 mActiveSpecificNetworkRequestSpecifier = new WifiNetworkSpecifier( 605 wns.ssidPatternMatcher, wns.bssidPatternMatcher, wns.wifiConfiguration, 606 wns.requestorUid, wns.requestorPackageName); 607 mWifiMetrics.incrementNetworkRequestApiNumRequest(); 608 609 // Start UI to let the user grant/disallow this request from the app. 610 startUi(); 611 // Trigger periodic scans for finding a network in the request. 612 startPeriodicScans(); 613 } 614 } 615 616 @Override releaseNetworkFor(NetworkRequest networkRequest)617 protected void releaseNetworkFor(NetworkRequest networkRequest) { 618 NetworkSpecifier ns = networkRequest.networkCapabilities.getNetworkSpecifier(); 619 if (ns == null) { 620 // Generic wifi request. Turn off auto-join if necessary. 621 if (mGenericConnectionReqCount == 0) { 622 Log.e(TAG, "No valid network request to release"); 623 return; 624 } 625 if (--mGenericConnectionReqCount == 0) { 626 mWifiConnectivityManager.setTrustedConnectionAllowed(false); 627 } 628 } else { 629 // Invalid network specifier. 630 if (!(ns instanceof WifiNetworkSpecifier)) { 631 Log.e(TAG, "Invalid network specifier mentioned. Ignoring"); 632 return; 633 } 634 if (!mWifiEnabled) { 635 Log.e(TAG, "Wifi off. Ignoring"); 636 return; 637 } 638 if (mActiveSpecificNetworkRequest == null && mConnectedSpecificNetworkRequest == null) { 639 Log.e(TAG, "Network release received with no active/connected request." 640 + " Ignoring"); 641 return; 642 } 643 if (Objects.equals(mActiveSpecificNetworkRequest, networkRequest)) { 644 Log.i(TAG, "App released request, cancelling " 645 + mActiveSpecificNetworkRequest); 646 teardownForActiveRequest(); 647 } else if (Objects.equals(mConnectedSpecificNetworkRequest, networkRequest)) { 648 Log.i(TAG, "App released request, cancelling " 649 + mConnectedSpecificNetworkRequest); 650 teardownForConnectedNetwork(); 651 } else { 652 Log.e(TAG, "Network specifier does not match the active/connected request." 653 + " Ignoring"); 654 } 655 } 656 } 657 658 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)659 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 660 super.dump(fd, pw, args); 661 pw.println(TAG + ": mGenericConnectionReqCount " + mGenericConnectionReqCount); 662 pw.println(TAG + ": mActiveSpecificNetworkRequest " + mActiveSpecificNetworkRequest); 663 pw.println(TAG + ": mUserApprovedAccessPointMap " + mUserApprovedAccessPointMap); 664 } 665 666 /** 667 * Check if there is at least one connection request. 668 */ hasConnectionRequests()669 public boolean hasConnectionRequests() { 670 return mGenericConnectionReqCount > 0 || mActiveSpecificNetworkRequest != null 671 || mConnectedSpecificNetworkRequest != null; 672 } 673 674 /** 675 * Return the uid of the specific network request being processed if connected to the requested 676 * network. 677 * 678 * @param connectedNetwork WifiConfiguration corresponding to the connected network. 679 * @return Pair of uid & package name of the specific request (if any), else <-1, "">. 680 */ getSpecificNetworkRequestUidAndPackageName( @onNull WifiConfiguration connectedNetwork)681 public Pair<Integer, String> getSpecificNetworkRequestUidAndPackageName( 682 @NonNull WifiConfiguration connectedNetwork) { 683 if (mUserSelectedNetwork == null || connectedNetwork == null) { 684 return Pair.create(Process.INVALID_UID, ""); 685 } 686 if (!isUserSelectedNetwork(connectedNetwork)) { 687 Log.w(TAG, "Connected to unknown network " + connectedNetwork + ". Ignoring..."); 688 return Pair.create(Process.INVALID_UID, ""); 689 } 690 if (mConnectedSpecificNetworkRequestSpecifier != null) { 691 return Pair.create(mConnectedSpecificNetworkRequestSpecifier.requestorUid, 692 mConnectedSpecificNetworkRequestSpecifier.requestorPackageName); 693 } 694 if (mActiveSpecificNetworkRequestSpecifier != null) { 695 return Pair.create(mActiveSpecificNetworkRequestSpecifier.requestorUid, 696 mActiveSpecificNetworkRequestSpecifier.requestorPackageName); 697 } 698 return Pair.create(Process.INVALID_UID, ""); 699 } 700 701 // Helper method to add the provided network configuration to WifiConfigManager, if it does not 702 // already exist & return the allocated network ID. This ID will be used in the CONNECT_NETWORK 703 // request to ClientModeImpl. 704 // If the network already exists, just return the network ID of the existing network. addNetworkToWifiConfigManager(@onNull WifiConfiguration network)705 private int addNetworkToWifiConfigManager(@NonNull WifiConfiguration network) { 706 WifiConfiguration existingSavedNetwork = 707 mWifiConfigManager.getConfiguredNetwork(network.configKey()); 708 if (existingSavedNetwork != null) { 709 return existingSavedNetwork.networkId; 710 } 711 NetworkUpdateResult networkUpdateResult = 712 mWifiConfigManager.addOrUpdateNetwork( 713 network, mActiveSpecificNetworkRequestSpecifier.requestorUid, 714 mActiveSpecificNetworkRequestSpecifier.requestorPackageName); 715 if (mVerboseLoggingEnabled) { 716 Log.v(TAG, "Added network to config manager " + networkUpdateResult.netId); 717 } 718 return networkUpdateResult.netId; 719 } 720 721 // Helper method to trigger a connection request & schedule a timeout alarm to track the 722 // connection request. connectToNetwork(@onNull WifiConfiguration network)723 private void connectToNetwork(@NonNull WifiConfiguration network) { 724 // Cancel connection timeout alarm for any previous connection attempts. 725 cancelConnectionTimeout(); 726 727 // First add the network to WifiConfigManager and then use the obtained networkId 728 // in the CONNECT_NETWORK request. 729 // Note: We don't do any error checks on the networkId because ClientModeImpl will do the 730 // necessary checks when processing CONNECT_NETWORK. 731 int networkId = addNetworkToWifiConfigManager(network); 732 733 mWifiMetrics.setNominatorForNetwork(networkId, 734 WifiMetricsProto.ConnectionEvent.NOMINATOR_SPECIFIER); 735 736 // Send the connect request to ClientModeImpl. 737 // TODO(b/117601161): Refactor this. 738 Message msg = Message.obtain(); 739 msg.what = WifiManager.CONNECT_NETWORK; 740 msg.arg1 = networkId; 741 msg.replyTo = mSrcMessenger; 742 mWifiInjector.getClientModeImpl().sendMessage(msg); 743 744 // Post an alarm to handle connection timeout. 745 scheduleConnectionTimeout(); 746 } 747 handleConnectToNetworkUserSelectionInternal(WifiConfiguration network)748 private void handleConnectToNetworkUserSelectionInternal(WifiConfiguration network) { 749 // Disable Auto-join so that NetworkFactory can take control of the network connection. 750 mWifiConnectivityManager.setSpecificNetworkRequestInProgress(true); 751 752 // Copy over the credentials from the app's request and then copy the ssid from user 753 // selection. 754 WifiConfiguration networkToConnect = 755 new WifiConfiguration(mActiveSpecificNetworkRequestSpecifier.wifiConfiguration); 756 networkToConnect.SSID = network.SSID; 757 // Set the WifiConfiguration.BSSID field to prevent roaming. 758 networkToConnect.BSSID = findBestBssidFromActiveMatchedScanResultsForNetwork(network); 759 // Mark the network ephemeral so that it's automatically removed at the end of connection. 760 networkToConnect.ephemeral = true; 761 networkToConnect.fromWifiNetworkSpecifier = true; 762 763 // Store the user selected network. 764 mUserSelectedNetwork = networkToConnect; 765 766 // Disconnect from the current network before issuing a new connect request. 767 mWifiInjector.getClientModeImpl().disconnectCommand(); 768 // Trigger connection to the network. 769 connectToNetwork(networkToConnect); 770 // Triggered connection to network, now wait for the connection status. 771 mPendingConnectionSuccess = true; 772 } 773 handleConnectToNetworkUserSelection(WifiConfiguration network)774 private void handleConnectToNetworkUserSelection(WifiConfiguration network) { 775 Log.d(TAG, "User initiated connect to network: " + network.SSID); 776 777 // Cancel the ongoing scans after user selection. 778 cancelPeriodicScans(); 779 780 // Trigger connection attempts. 781 handleConnectToNetworkUserSelectionInternal(network); 782 783 // Add the network to the approved access point map for the app. 784 addNetworkToUserApprovedAccessPointMap(mUserSelectedNetwork); 785 } 786 handleRejectUserSelection()787 private void handleRejectUserSelection() { 788 Log.w(TAG, "User dismissed notification, cancelling " + mActiveSpecificNetworkRequest); 789 teardownForActiveRequest(); 790 mWifiMetrics.incrementNetworkRequestApiNumUserReject(); 791 } 792 isUserSelectedNetwork(WifiConfiguration config)793 private boolean isUserSelectedNetwork(WifiConfiguration config) { 794 if (!TextUtils.equals(mUserSelectedNetwork.SSID, config.SSID)) { 795 return false; 796 } 797 if (!Objects.equals( 798 mUserSelectedNetwork.allowedKeyManagement, config.allowedKeyManagement)) { 799 return false; 800 } 801 return true; 802 } 803 804 /** 805 * Invoked by {@link ClientModeImpl} on end of connection attempt to a network. 806 */ handleConnectionAttemptEnded( int failureCode, @NonNull WifiConfiguration network)807 public void handleConnectionAttemptEnded( 808 int failureCode, @NonNull WifiConfiguration network) { 809 if (failureCode == WifiMetrics.ConnectionEvent.FAILURE_NONE) { 810 handleNetworkConnectionSuccess(network); 811 } else { 812 handleNetworkConnectionFailure(network); 813 } 814 } 815 816 /** 817 * Invoked by {@link ClientModeImpl} on successful connection to a network. 818 */ handleNetworkConnectionSuccess(@onNull WifiConfiguration connectedNetwork)819 private void handleNetworkConnectionSuccess(@NonNull WifiConfiguration connectedNetwork) { 820 if (mUserSelectedNetwork == null || connectedNetwork == null 821 || !mPendingConnectionSuccess) { 822 return; 823 } 824 if (!isUserSelectedNetwork(connectedNetwork)) { 825 Log.w(TAG, "Connected to unknown network " + connectedNetwork + ". Ignoring..."); 826 return; 827 } 828 Log.d(TAG, "Connected to network " + mUserSelectedNetwork); 829 for (INetworkRequestMatchCallback callback : mRegisteredCallbacks.getCallbacks()) { 830 try { 831 callback.onUserSelectionConnectSuccess(mUserSelectedNetwork); 832 } catch (RemoteException e) { 833 Log.e(TAG, "Unable to invoke network request connect failure callback " 834 + callback, e); 835 } 836 } 837 // transition the request from "active" to "connected". 838 setupForConnectedRequest(); 839 mWifiMetrics.incrementNetworkRequestApiNumConnectSuccess(); 840 } 841 842 /** 843 * Invoked by {@link ClientModeImpl} on failure to connect to a network. 844 */ handleNetworkConnectionFailure(@onNull WifiConfiguration failedNetwork)845 private void handleNetworkConnectionFailure(@NonNull WifiConfiguration failedNetwork) { 846 if (mUserSelectedNetwork == null || failedNetwork == null || !mPendingConnectionSuccess) { 847 return; 848 } 849 if (!isUserSelectedNetwork(failedNetwork)) { 850 Log.w(TAG, "Connection failed to unknown network " + failedNetwork + ". Ignoring..."); 851 return; 852 } 853 Log.w(TAG, "Failed to connect to network " + mUserSelectedNetwork); 854 if (mUserSelectedNetworkConnectRetryCount++ < USER_SELECTED_NETWORK_CONNECT_RETRY_MAX) { 855 Log.i(TAG, "Retrying connection attempt, attempt# " 856 + mUserSelectedNetworkConnectRetryCount); 857 connectToNetwork(mUserSelectedNetwork); 858 return; 859 } 860 Log.e(TAG, "Connection failures, cancelling " + mUserSelectedNetwork); 861 for (INetworkRequestMatchCallback callback : mRegisteredCallbacks.getCallbacks()) { 862 try { 863 callback.onUserSelectionConnectFailure(mUserSelectedNetwork); 864 } catch (RemoteException e) { 865 Log.e(TAG, "Unable to invoke network request connect failure callback " 866 + callback, e); 867 } 868 } 869 teardownForActiveRequest(); 870 } 871 872 /** 873 * Invoked by {@link ClientModeImpl} to indicate screen state changes. 874 */ handleScreenStateChanged(boolean screenOn)875 public void handleScreenStateChanged(boolean screenOn) { 876 // If there is no active request or if the user has already selected a network, 877 // ignore screen state changes. 878 if (mActiveSpecificNetworkRequest == null || mUserSelectedNetwork != null) return; 879 880 // Pause periodic scans when the screen is off & resume when the screen is on. 881 if (screenOn) { 882 if (mVerboseLoggingEnabled) Log.v(TAG, "Resuming scans on screen on"); 883 startScan(); 884 mIsPeriodicScanPaused = false; 885 } else { 886 if (mVerboseLoggingEnabled) Log.v(TAG, "Pausing scans on screen off"); 887 cancelPeriodicScans(); 888 mIsPeriodicScanPaused = true; 889 } 890 } 891 892 /** 893 * Invoked by {@link ClientModeImpl} to indicate wifi state toggle. 894 */ setWifiState(boolean enabled)895 public void setWifiState(boolean enabled) { 896 if (mVerboseLoggingEnabled) Log.v(TAG, "setWifiState " + enabled); 897 if (enabled) { 898 reevaluateAllRequests(); // Re-evaluate any pending requests. 899 } else { 900 if (mActiveSpecificNetworkRequest != null) { 901 Log.w(TAG, "Wifi off, cancelling " + mActiveSpecificNetworkRequest); 902 teardownForActiveRequest(); 903 } 904 if (mConnectedSpecificNetworkRequest != null) { 905 Log.w(TAG, "Wifi off, cancelling " + mConnectedSpecificNetworkRequest); 906 teardownForConnectedNetwork(); 907 } 908 } 909 mWifiEnabled = enabled; 910 } 911 912 // Common helper method for start/end of active request processing. cleanupActiveRequest()913 private void cleanupActiveRequest() { 914 // Send the abort to the UI for the current active request. 915 for (INetworkRequestMatchCallback callback : mRegisteredCallbacks.getCallbacks()) { 916 try { 917 callback.onAbort(); 918 } catch (RemoteException e) { 919 Log.e(TAG, "Unable to invoke network request abort callback " + callback, e); 920 } 921 } 922 // Force-release the network request to let the app know early that the attempt failed. 923 if (mActiveSpecificNetworkRequest != null) { 924 releaseRequestAsUnfulfillableByAnyFactory(mActiveSpecificNetworkRequest); 925 } 926 // Reset the active network request. 927 mActiveSpecificNetworkRequest = null; 928 mActiveSpecificNetworkRequestSpecifier = null; 929 mUserSelectedNetwork = null; 930 mUserSelectedNetworkConnectRetryCount = 0; 931 mIsPeriodicScanPaused = false; 932 mActiveMatchedScanResults = null; 933 mPendingConnectionSuccess = false; 934 // Cancel periodic scan, connection timeout alarm. 935 cancelPeriodicScans(); 936 cancelConnectionTimeout(); 937 // Remove any callbacks registered for the request. 938 mRegisteredCallbacks.clear(); 939 } 940 941 // Invoked at the start of new active request processing. setupForActiveRequest()942 private void setupForActiveRequest() { 943 if (mActiveSpecificNetworkRequest != null) { 944 cleanupActiveRequest(); 945 } 946 } 947 948 // Invoked at the termination of current active request processing. teardownForActiveRequest()949 private void teardownForActiveRequest() { 950 cleanupActiveRequest(); 951 // ensure there is no connected request in progress. 952 if (mConnectedSpecificNetworkRequest == null) { 953 mWifiConnectivityManager.setSpecificNetworkRequestInProgress(false); 954 } 955 } 956 957 // Invoked at the start of new connected request processing. setupForConnectedRequest()958 private void setupForConnectedRequest() { 959 mConnectedSpecificNetworkRequest = mActiveSpecificNetworkRequest; 960 mConnectedSpecificNetworkRequestSpecifier = mActiveSpecificNetworkRequestSpecifier; 961 mActiveSpecificNetworkRequest = null; 962 mActiveSpecificNetworkRequestSpecifier = null; 963 mPendingConnectionSuccess = false; 964 // Cancel connection timeout alarm. 965 cancelConnectionTimeout(); 966 } 967 968 // Invoked at the termination of current connected request processing. teardownForConnectedNetwork()969 private void teardownForConnectedNetwork() { 970 Log.i(TAG, "Disconnecting from network on reset"); 971 mWifiInjector.getClientModeImpl().disconnectCommand(); 972 mConnectedSpecificNetworkRequest = null; 973 mConnectedSpecificNetworkRequestSpecifier = null; 974 // ensure there is no active request in progress. 975 if (mActiveSpecificNetworkRequest == null) { 976 mWifiConnectivityManager.setSpecificNetworkRequestInProgress(false); 977 } 978 } 979 980 /** 981 * Check if the request comes from foreground app/service. 982 */ isRequestFromForegroundAppOrService(@onNull String requestorPackageName)983 private boolean isRequestFromForegroundAppOrService(@NonNull String requestorPackageName) { 984 try { 985 return mActivityManager.getPackageImportance(requestorPackageName) 986 <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE; 987 } catch (SecurityException e) { 988 Log.e(TAG, "Failed to check the app state", e); 989 return false; 990 } 991 } 992 993 /** 994 * Check if the request comes from foreground app. 995 */ isRequestFromForegroundApp(@onNull String requestorPackageName)996 private boolean isRequestFromForegroundApp(@NonNull String requestorPackageName) { 997 try { 998 return mActivityManager.getPackageImportance(requestorPackageName) 999 <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 1000 } catch (SecurityException e) { 1001 Log.e(TAG, "Failed to check the app state", e); 1002 return false; 1003 } 1004 } 1005 1006 /** 1007 * Helper method to populate WifiScanner handle. This is done lazily because 1008 * WifiScanningService is started after WifiService. 1009 */ retrieveWifiScanner()1010 private void retrieveWifiScanner() { 1011 if (mWifiScanner != null) return; 1012 mWifiScanner = mWifiInjector.getWifiScanner(); 1013 checkNotNull(mWifiScanner); 1014 } 1015 startPeriodicScans()1016 private void startPeriodicScans() { 1017 if (mActiveSpecificNetworkRequestSpecifier == null) { 1018 Log.e(TAG, "Periodic scan triggered when there is no active network request. " 1019 + "Ignoring..."); 1020 return; 1021 } 1022 WifiNetworkSpecifier wns = mActiveSpecificNetworkRequestSpecifier; 1023 WifiConfiguration wifiConfiguration = wns.wifiConfiguration; 1024 if (wifiConfiguration.hiddenSSID) { 1025 mScanSettings.hiddenNetworks = new WifiScanner.ScanSettings.HiddenNetwork[1]; 1026 // Can't search for SSID pattern in hidden networks. 1027 mScanSettings.hiddenNetworks[0] = 1028 new WifiScanner.ScanSettings.HiddenNetwork( 1029 addEnclosingQuotes(wns.ssidPatternMatcher.getPath())); 1030 } 1031 startScan(); 1032 } 1033 cancelPeriodicScans()1034 private void cancelPeriodicScans() { 1035 if (mPeriodicScanTimerSet) { 1036 mAlarmManager.cancel(mPeriodicScanTimerListener); 1037 mPeriodicScanTimerSet = false; 1038 } 1039 // Clear the hidden networks field after each request. 1040 mScanSettings.hiddenNetworks = null; 1041 } 1042 scheduleNextPeriodicScan()1043 private void scheduleNextPeriodicScan() { 1044 if (mIsPeriodicScanPaused) { 1045 Log.e(TAG, "Scan triggered when periodic scanning paused. Ignoring..."); 1046 return; 1047 } 1048 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1049 mClock.getElapsedSinceBootMillis() + PERIODIC_SCAN_INTERVAL_MS, 1050 TAG, mPeriodicScanTimerListener, mHandler); 1051 mPeriodicScanTimerSet = true; 1052 } 1053 startScan()1054 private void startScan() { 1055 if (mActiveSpecificNetworkRequestSpecifier == null) { 1056 Log.e(TAG, "Scan triggered when there is no active network request. Ignoring..."); 1057 return; 1058 } 1059 if (mVerboseLoggingEnabled) { 1060 Log.v(TAG, "Starting the next scan for " + mActiveSpecificNetworkRequestSpecifier); 1061 } 1062 // Create a worksource using the caller's UID. 1063 WorkSource workSource = new WorkSource(mActiveSpecificNetworkRequestSpecifier.requestorUid); 1064 mWifiScanner.startScan(mScanSettings, mScanListener, workSource); 1065 } 1066 doesScanResultMatchWifiNetworkSpecifier( WifiNetworkSpecifier wns, ScanResult scanResult)1067 private boolean doesScanResultMatchWifiNetworkSpecifier( 1068 WifiNetworkSpecifier wns, ScanResult scanResult) { 1069 if (!wns.ssidPatternMatcher.match(scanResult.SSID)) { 1070 return false; 1071 } 1072 MacAddress bssid = MacAddress.fromString(scanResult.BSSID); 1073 MacAddress matchBaseAddress = wns.bssidPatternMatcher.first; 1074 MacAddress matchMask = wns.bssidPatternMatcher.second; 1075 if (!bssid.matches(matchBaseAddress, matchMask)) { 1076 return false; 1077 } 1078 if (ScanResultMatchInfo.getNetworkType(wns.wifiConfiguration) 1079 != ScanResultMatchInfo.getNetworkType(scanResult)) { 1080 return false; 1081 } 1082 return true; 1083 } 1084 1085 // Loops through the scan results and finds scan results matching the active network 1086 // request. getNetworksMatchingActiveNetworkRequest( ScanResult[] scanResults)1087 private List<ScanResult> getNetworksMatchingActiveNetworkRequest( 1088 ScanResult[] scanResults) { 1089 if (mActiveSpecificNetworkRequestSpecifier == null) { 1090 Log.e(TAG, "Scan results received with no active network request. Ignoring..."); 1091 return new ArrayList<>(); 1092 } 1093 List<ScanResult> matchedScanResults = new ArrayList<>(); 1094 WifiNetworkSpecifier wns = mActiveSpecificNetworkRequestSpecifier; 1095 1096 for (ScanResult scanResult : scanResults) { 1097 if (doesScanResultMatchWifiNetworkSpecifier(wns, scanResult)) { 1098 matchedScanResults.add(scanResult); 1099 } 1100 } 1101 if (mVerboseLoggingEnabled) { 1102 Log.v(TAG, "List of scan results matching the active request " 1103 + matchedScanResults); 1104 } 1105 return matchedScanResults; 1106 } 1107 sendNetworkRequestMatchCallbacksForActiveRequest( List<ScanResult> matchedScanResults)1108 private void sendNetworkRequestMatchCallbacksForActiveRequest( 1109 List<ScanResult> matchedScanResults) { 1110 if (mRegisteredCallbacks.getNumCallbacks() == 0) { 1111 Log.e(TAG, "No callback registered for sending network request matches. " 1112 + "Ignoring..."); 1113 return; 1114 } 1115 for (INetworkRequestMatchCallback callback : mRegisteredCallbacks.getCallbacks()) { 1116 try { 1117 callback.onMatch(matchedScanResults); 1118 } catch (RemoteException e) { 1119 Log.e(TAG, "Unable to invoke network request match callback " + callback, e); 1120 } 1121 } 1122 } 1123 cancelConnectionTimeout()1124 private void cancelConnectionTimeout() { 1125 if (mConnectionTimeoutSet) { 1126 mAlarmManager.cancel(mConnectionTimeoutAlarmListener); 1127 mConnectionTimeoutSet = false; 1128 } 1129 } 1130 scheduleConnectionTimeout()1131 private void scheduleConnectionTimeout() { 1132 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1133 mClock.getElapsedSinceBootMillis() + NETWORK_CONNECTION_TIMEOUT_MS, 1134 TAG, mConnectionTimeoutAlarmListener, mHandler); 1135 mConnectionTimeoutSet = true; 1136 } 1137 getAppName(@onNull String packageName)1138 private @NonNull CharSequence getAppName(@NonNull String packageName) { 1139 ApplicationInfo applicationInfo = null; 1140 try { 1141 applicationInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0); 1142 } catch (PackageManager.NameNotFoundException e) { 1143 Log.e(TAG, "Failed to find app name for " + packageName); 1144 return ""; 1145 } 1146 CharSequence appName = mContext.getPackageManager().getApplicationLabel(applicationInfo); 1147 return (appName != null) ? appName : ""; 1148 } 1149 startUi()1150 private void startUi() { 1151 Intent intent = new Intent(); 1152 intent.setAction(UI_START_INTENT_ACTION); 1153 intent.addCategory(UI_START_INTENT_CATEGORY); 1154 intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); 1155 intent.putExtra(UI_START_INTENT_EXTRA_APP_NAME, 1156 getAppName(mActiveSpecificNetworkRequestSpecifier.requestorPackageName)); 1157 intent.putExtra(UI_START_INTENT_EXTRA_REQUEST_IS_FOR_SINGLE_NETWORK, 1158 isActiveRequestForSingleNetwork()); 1159 mContext.startActivityAsUser(intent, UserHandle.getUserHandleForUid( 1160 mActiveSpecificNetworkRequestSpecifier.requestorUid)); 1161 } 1162 1163 // Helper method to determine if the specifier does not contain any patterns and matches 1164 // a single access point. isActiveRequestForSingleAccessPoint()1165 private boolean isActiveRequestForSingleAccessPoint() { 1166 if (mActiveSpecificNetworkRequestSpecifier == null) return false; 1167 1168 if (mActiveSpecificNetworkRequestSpecifier.ssidPatternMatcher.getType() 1169 != PatternMatcher.PATTERN_LITERAL) { 1170 return false; 1171 } 1172 if (!Objects.equals( 1173 mActiveSpecificNetworkRequestSpecifier.bssidPatternMatcher.second, 1174 MacAddress.BROADCAST_ADDRESS)) { 1175 return false; 1176 } 1177 return true; 1178 } 1179 1180 // Helper method to determine if the specifier does not contain any patterns and matches 1181 // a single network. isActiveRequestForSingleNetwork()1182 private boolean isActiveRequestForSingleNetwork() { 1183 if (mActiveSpecificNetworkRequestSpecifier == null) return false; 1184 1185 if (mActiveSpecificNetworkRequestSpecifier.ssidPatternMatcher.getType() 1186 == PatternMatcher.PATTERN_LITERAL) { 1187 return true; 1188 } 1189 if (Objects.equals( 1190 mActiveSpecificNetworkRequestSpecifier.bssidPatternMatcher.second, 1191 MacAddress.BROADCAST_ADDRESS)) { 1192 return true; 1193 } 1194 return false; 1195 } 1196 1197 // Will return the best bssid to use for the current request's connection. 1198 // 1199 // Note: This will never return null, unless there is some internal error. 1200 // For ex: 1201 // i) The latest scan results were empty. 1202 // ii) The latest scan result did not contain any BSSID for the SSID user chose. findBestBssidFromActiveMatchedScanResultsForNetwork( @onNull WifiConfiguration network)1203 private @Nullable String findBestBssidFromActiveMatchedScanResultsForNetwork( 1204 @NonNull WifiConfiguration network) { 1205 if (mActiveSpecificNetworkRequestSpecifier == null 1206 || mActiveMatchedScanResults == null) return null; 1207 ScanResult selectedScanResult = mActiveMatchedScanResults 1208 .stream() 1209 .filter(scanResult -> Objects.equals( 1210 ScanResultMatchInfo.fromScanResult(scanResult), 1211 ScanResultMatchInfo.fromWifiConfiguration(network))) 1212 .max(Comparator.comparing(scanResult -> scanResult.level)) 1213 .orElse(null); 1214 if (selectedScanResult == null) { // Should never happen. 1215 Log.wtf(TAG, "Expected to find at least one matching scan result"); 1216 return null; 1217 } 1218 if (mVerboseLoggingEnabled) { 1219 Log.v(TAG, "Best bssid selected for the request " + selectedScanResult); 1220 } 1221 return selectedScanResult.BSSID; 1222 } 1223 1224 private @Nullable ScanResult findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults()1225 findUserApprovedAccessPointForActiveRequestFromActiveMatchedScanResults() { 1226 if (mActiveSpecificNetworkRequestSpecifier == null 1227 || mActiveMatchedScanResults == null) return null; 1228 String requestorPackageName = mActiveSpecificNetworkRequestSpecifier.requestorPackageName; 1229 Set<AccessPoint> approvedAccessPoints = 1230 mUserApprovedAccessPointMap.get(requestorPackageName); 1231 if (approvedAccessPoints == null) return null; 1232 for (ScanResult scanResult : mActiveMatchedScanResults) { 1233 ScanResultMatchInfo fromScanResult = ScanResultMatchInfo.fromScanResult(scanResult); 1234 AccessPoint accessPoint = 1235 new AccessPoint(scanResult.SSID, 1236 MacAddress.fromString(scanResult.BSSID), fromScanResult.networkType); 1237 if (approvedAccessPoints.contains(accessPoint)) { 1238 if (mVerboseLoggingEnabled) { 1239 Log.v(TAG, "Found " + accessPoint 1240 + " in user approved access point for " + requestorPackageName); 1241 } 1242 return scanResult; 1243 } 1244 } 1245 return null; 1246 } 1247 1248 // Helper method to store the all the BSSIDs matching the network from the matched scan results addNetworkToUserApprovedAccessPointMap(@onNull WifiConfiguration network)1249 private void addNetworkToUserApprovedAccessPointMap(@NonNull WifiConfiguration network) { 1250 if (mActiveSpecificNetworkRequestSpecifier == null 1251 || mActiveMatchedScanResults == null) return; 1252 // Note: This hopefully is a list of size 1, because we want to store a 1:1 mapping 1253 // from user selection and the AP that was approved. But, since we get a WifiConfiguration 1254 // object representing an entire network from UI, we need to ensure that all the visible 1255 // BSSIDs matching the original request and the selected network are stored. 1256 Set<AccessPoint> newUserApprovedAccessPoints = new HashSet<>(); 1257 for (ScanResult scanResult : mActiveMatchedScanResults) { 1258 ScanResultMatchInfo fromScanResult = ScanResultMatchInfo.fromScanResult(scanResult); 1259 ScanResultMatchInfo fromWifiConfiguration = 1260 ScanResultMatchInfo.fromWifiConfiguration(network); 1261 if (fromScanResult.equals(fromWifiConfiguration)) { 1262 AccessPoint approvedAccessPoint = 1263 new AccessPoint(scanResult.SSID, MacAddress.fromString(scanResult.BSSID), 1264 fromScanResult.networkType); 1265 newUserApprovedAccessPoints.add(approvedAccessPoint); 1266 } 1267 } 1268 if (newUserApprovedAccessPoints.isEmpty()) return; 1269 1270 String requestorPackageName = mActiveSpecificNetworkRequestSpecifier.requestorPackageName; 1271 Set<AccessPoint> approvedAccessPoints = 1272 mUserApprovedAccessPointMap.get(requestorPackageName); 1273 if (approvedAccessPoints == null) { 1274 approvedAccessPoints = new HashSet<>(); 1275 mUserApprovedAccessPointMap.put(requestorPackageName, approvedAccessPoints); 1276 // Note the new app in metrics. 1277 mWifiMetrics.incrementNetworkRequestApiNumApps(); 1278 } 1279 if (mVerboseLoggingEnabled) { 1280 Log.v(TAG, "Adding " + newUserApprovedAccessPoints 1281 + " to user approved access point for " + requestorPackageName); 1282 } 1283 approvedAccessPoints.addAll(newUserApprovedAccessPoints); 1284 saveToStore(); 1285 } 1286 1287 /** 1288 * Remove all user approved access points for the specified app. 1289 */ removeUserApprovedAccessPointsForApp(@onNull String packageName)1290 public void removeUserApprovedAccessPointsForApp(@NonNull String packageName) { 1291 Iterator<Map.Entry<String, Set<AccessPoint>>> iter = 1292 mUserApprovedAccessPointMap.entrySet().iterator(); 1293 while (iter.hasNext()) { 1294 Map.Entry<String, Set<AccessPoint>> entry = iter.next(); 1295 if (packageName.equals(entry.getKey())) { 1296 Log.i(TAG, "Removing all approved access points for " + packageName); 1297 iter.remove(); 1298 } 1299 } 1300 saveToStore(); 1301 } 1302 1303 /** 1304 * Clear all internal state (for network settings reset). 1305 */ clear()1306 public void clear() { 1307 mUserApprovedAccessPointMap.clear(); 1308 Log.i(TAG, "Cleared all internal state"); 1309 saveToStore(); 1310 } 1311 } 1312 1313