1 /* 2 * Copyright (C) 2008 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.scanner; 18 19 import static android.content.pm.PackageManager.PERMISSION_DENIED; 20 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 21 22 import android.Manifest; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.AlarmManager; 26 import android.app.PendingIntent; 27 import android.content.BroadcastReceiver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.IntentFilter; 31 import android.net.wifi.IScanDataListener; 32 import android.net.wifi.IWifiScanner; 33 import android.net.wifi.IWifiScannerListener; 34 import android.net.wifi.ScanResult; 35 import android.net.wifi.WifiAnnotations; 36 import android.net.wifi.WifiManager; 37 import android.net.wifi.WifiScanner; 38 import android.net.wifi.WifiScanner.ChannelSpec; 39 import android.net.wifi.WifiScanner.PnoSettings; 40 import android.net.wifi.WifiScanner.ScanData; 41 import android.net.wifi.WifiScanner.ScanSettings; 42 import android.net.wifi.WifiScanner.WifiBand; 43 import android.net.wifi.util.ScanResultUtil; 44 import android.os.BatteryStatsManager; 45 import android.os.Binder; 46 import android.os.Build; 47 import android.os.Bundle; 48 import android.os.Handler; 49 import android.os.Looper; 50 import android.os.Message; 51 import android.os.Process; 52 import android.os.RemoteException; 53 import android.os.WorkSource; 54 import android.util.ArrayMap; 55 import android.util.ArraySet; 56 import android.util.LocalLog; 57 import android.util.Log; 58 import android.util.Pair; 59 60 import com.android.internal.annotations.VisibleForTesting; 61 import com.android.internal.util.Protocol; 62 import com.android.internal.util.State; 63 import com.android.internal.util.StateMachine; 64 import com.android.modules.utils.ParceledListSlice; 65 import com.android.modules.utils.build.SdkLevel; 66 import com.android.server.wifi.ClientModeImpl; 67 import com.android.server.wifi.Clock; 68 import com.android.server.wifi.DeviceConfigFacade; 69 import com.android.server.wifi.WifiGlobals; 70 import com.android.server.wifi.WifiInjector; 71 import com.android.server.wifi.WifiLocalServices; 72 import com.android.server.wifi.WifiLog; 73 import com.android.server.wifi.WifiMetrics; 74 import com.android.server.wifi.WifiNative; 75 import com.android.server.wifi.WifiThreadRunner; 76 import com.android.server.wifi.proto.WifiStatsLog; 77 import com.android.server.wifi.proto.nano.WifiMetricsProto; 78 import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection; 79 import com.android.server.wifi.util.ArrayUtils; 80 import com.android.server.wifi.util.LastCallerInfoManager; 81 import com.android.server.wifi.util.WifiPermissionsUtil; 82 import com.android.server.wifi.util.WorkSourceUtil; 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.Arrays; 89 import java.util.Collection; 90 import java.util.Iterator; 91 import java.util.List; 92 import java.util.Map; 93 import java.util.Objects; 94 import java.util.Set; 95 import java.util.concurrent.atomic.AtomicBoolean; 96 import java.util.stream.Collectors; 97 98 public class WifiScanningServiceImpl extends IWifiScanner.Stub { 99 100 private static final String TAG = WifiScanningService.TAG; 101 private static final boolean DBG = false; 102 103 private static final int UNKNOWN_PID = -1; 104 105 private final LocalLog mLocalLog = new LocalLog(512); 106 107 private WifiLog mLog; 108 localLog(String message)109 private void localLog(String message) { 110 mLocalLog.log(message); 111 if (isVerboseLoggingEnabled()) { 112 Log.i(TAG, message, null); 113 } 114 } 115 logw(String message)116 private void logw(String message) { 117 Log.w(TAG, message, null); 118 mLocalLog.log(message); 119 } 120 loge(String message)121 private void loge(String message) { 122 Log.e(TAG, message, null); 123 mLocalLog.log(message); 124 } 125 notifyFailure(IWifiScannerListener listener, int reasonCode, String reason)126 private void notifyFailure(IWifiScannerListener listener, int reasonCode, String reason) { 127 try { 128 listener.onFailure(reasonCode, reason); 129 } catch (RemoteException e) { 130 loge(e + "failed to notify listener for failure"); 131 } 132 } 133 isPlatformOrTargetSdkLessThanU(String packageName, int uid)134 private boolean isPlatformOrTargetSdkLessThanU(String packageName, int uid) { 135 if (!SdkLevel.isAtLeastU()) { 136 return true; 137 } 138 return mWifiPermissionsUtil.isTargetSdkLessThan(packageName, 139 Build.VERSION_CODES.UPSIDE_DOWN_CAKE, uid); 140 } 141 142 @Override getAvailableChannels(@ifiBand int band, String packageName, @Nullable String attributionTag, Bundle extras)143 public Bundle getAvailableChannels(@WifiBand int band, String packageName, 144 @Nullable String attributionTag, Bundle extras) { 145 int uid = Binder.getCallingUid(); 146 if (isPlatformOrTargetSdkLessThanU(packageName, uid)) { 147 long ident = Binder.clearCallingIdentity(); 148 try { 149 enforcePermission(uid, packageName, attributionTag, false, false, false); 150 } finally { 151 Binder.restoreCallingIdentity(ident); 152 } 153 } else { 154 mWifiPermissionsUtil.enforceNearbyDevicesPermission( 155 extras.getParcelable(WifiManager.EXTRA_PARAM_KEY_ATTRIBUTION_SOURCE), 156 true, TAG + " getAvailableChannels"); 157 } 158 ChannelSpec[][] channelSpecs = mWifiThreadRunner.call(() -> { 159 if (mChannelHelper == null) return new ChannelSpec[0][0]; 160 mChannelHelper.updateChannels(); 161 return mChannelHelper.getAvailableScanChannels(band); 162 }, new ChannelSpec[0][0], TAG + "#getAvailableChannels"); 163 if (channelSpecs == null) { 164 channelSpecs = new ChannelSpec[0][0]; 165 } 166 167 ArrayList<Integer> list = new ArrayList<>(); 168 for (int i = 0; i < channelSpecs.length; i++) { 169 for (ChannelSpec channelSpec : channelSpecs[i]) { 170 list.add(channelSpec.frequency); 171 } 172 } 173 Bundle b = new Bundle(); 174 b.putIntegerArrayList(WifiScanner.GET_AVAILABLE_CHANNELS_EXTRA, list); 175 mLog.trace("getAvailableChannels uid=%").c(Binder.getCallingUid()).flush(); 176 return b; 177 } 178 179 /** 180 * See {@link WifiScanner#isScanning()} 181 * 182 * @return true if in ScanningState. 183 */ 184 @Override isScanning()185 public boolean isScanning() { 186 int uid = Binder.getCallingUid(); 187 if (!mWifiPermissionsUtil.checkCallersHardwareLocationPermission(uid)) { 188 throw new SecurityException("UID " + uid 189 + " does not have hardware Location permission"); 190 } 191 return mIsScanning; 192 } 193 194 @Override setScanningEnabled(boolean enable, int tid, String packageName)195 public boolean setScanningEnabled(boolean enable, int tid, String packageName) { 196 int uid = Binder.getCallingUid(); 197 int msgWhat = enable ? WifiScanner.CMD_ENABLE : WifiScanner.CMD_DISABLE; 198 try { 199 enforcePermission(uid, packageName, null, isPrivilegedMessage(msgWhat), 200 false, false); 201 } catch (SecurityException e) { 202 localLog("setScanningEnabled: failed to authorize app: " + packageName + " uid " 203 + uid); 204 return false; 205 } 206 localLog("enable scan: package " + packageName + " tid " + tid + " enable " + enable); 207 mWifiThreadRunner.post(() -> { 208 if (enable) { 209 Log.i(TAG, 210 "Received a request to enable scanning, UID = " + Binder.getCallingUid()); 211 setupScannerImpls(); 212 } else { 213 Log.i(TAG, "Received a request to disable scanning, UID = " + uid); 214 teardownScannerImpls(); 215 } 216 Message msg = Message.obtain(); 217 msg.what = msgWhat; 218 mBackgroundScanStateMachine.sendMessage(Message.obtain(msg)); 219 mSingleScanStateMachine.sendMessage(Message.obtain(msg)); 220 mPnoScanStateMachine.sendMessage(Message.obtain(msg)); 221 mLastCallerInfoManager.put(WifiManager.API_SCANNING_ENABLED, tid, 222 Binder.getCallingUid(), Binder.getCallingPid(), packageName, enable); 223 }, TAG + "#setScanningEnabled"); 224 return true; 225 } 226 227 @Override registerScanListener(IWifiScannerListener listener, String packageName, String featureId)228 public void registerScanListener(IWifiScannerListener listener, String packageName, 229 String featureId) { 230 final int uid = Binder.getCallingUid(); 231 try { 232 enforcePermission(uid, packageName, featureId, 233 isPrivilegedMessage(WifiScanner.CMD_REGISTER_SCAN_LISTENER), 234 false, false); 235 } catch (SecurityException e) { 236 localLog("registerScanListener: failed to authorize app: " + packageName + " uid " 237 + uid + " AttributionTag " + featureId); 238 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 239 return; 240 } 241 mWifiThreadRunner.post(() -> { 242 if (mClients.get(listener) != null) { 243 logw("duplicate client connection: " + uid + ", listener=" + listener 244 + " AttributionTag " + featureId); 245 return; 246 } 247 final ExternalClientInfo client = new ExternalClientInfo(uid, packageName, 248 listener, featureId); 249 client.register(); 250 localLog("register scan listener: " + client + " AttributionTag " + featureId); 251 logScanRequest("registerScanListener", client, null, null, null); 252 mSingleScanListeners.addRequest(client, null, null); 253 client.replySucceeded(); 254 }, TAG + "#registerScanListener"); 255 } 256 257 @Override unregisterScanListener(IWifiScannerListener listener, String packageName, String featureId)258 public void unregisterScanListener(IWifiScannerListener listener, String packageName, 259 String featureId) { 260 int uid = Binder.getCallingUid(); 261 try { 262 enforcePermission(uid, packageName, featureId, 263 isPrivilegedMessage(WifiScanner.CMD_DEREGISTER_SCAN_LISTENER), 264 true, false); 265 } catch (SecurityException e) { 266 localLog("unregisterScanListener: failed to authorize app: " + packageName + " uid " 267 + uid + " AttributionTag " + featureId); 268 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 269 return; 270 } 271 mWifiThreadRunner.post(() -> { 272 ExternalClientInfo client = (ExternalClientInfo) mClients.get(listener); 273 if (client == null) { 274 logw("no client registered: " + uid + ", listener=" + listener 275 + " AttributionTag " + featureId); 276 return; 277 } 278 logScanRequest("deregisterScanListener", client, null, null, null); 279 mSingleScanListeners.removeRequest(client); 280 client.cleanup(); 281 }, TAG + "#unregisterScanListener"); 282 } 283 284 @Override startBackgroundScan(IWifiScannerListener listener, WifiScanner.ScanSettings settings, WorkSource workSource, String packageName, String featureId)285 public void startBackgroundScan(IWifiScannerListener listener, 286 WifiScanner.ScanSettings settings, 287 WorkSource workSource, String packageName, String featureId) { 288 final int uid = Binder.getCallingUid(); 289 try { 290 enforcePermission(uid, packageName, featureId, 291 isPrivilegedMessage(WifiScanner.CMD_START_BACKGROUND_SCAN), 292 false, false); 293 } catch (SecurityException e) { 294 localLog("startBackgroundScan: failed to authorize app: " + packageName + " uid " 295 + uid); 296 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 297 return; 298 } 299 mWifiThreadRunner.post(() -> { 300 ExternalClientInfo client = (ExternalClientInfo) mClients.get(listener); 301 if (client == null) { 302 client = new ExternalClientInfo(uid, packageName, listener, featureId); 303 client.register(); 304 } 305 localLog("start background scan: " + client + " package " + packageName); 306 Message msg = Message.obtain(); 307 msg.what = WifiScanner.CMD_START_BACKGROUND_SCAN; 308 msg.obj = new ScanParams(listener, settings, workSource, featureId); 309 msg.sendingUid = uid; 310 mBackgroundScanStateMachine.sendMessage(msg); 311 }, TAG + "#startBackgroundScan"); 312 } 313 314 @Override stopBackgroundScan(IWifiScannerListener listener, String packageName, String featureId)315 public void stopBackgroundScan(IWifiScannerListener listener, String packageName, 316 String featureId) { 317 final int uid = Binder.getCallingUid(); 318 try { 319 enforcePermission(uid, packageName, featureId, 320 isPrivilegedMessage(WifiScanner.CMD_STOP_BACKGROUND_SCAN), 321 true, false); 322 } catch (SecurityException e) { 323 localLog("stopBackgroundScan: failed to authorize app: " + packageName + " uid " 324 + uid); 325 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 326 return; 327 } 328 ExternalClientInfo client = (ExternalClientInfo) mClients.get(listener); 329 if (client == null) { 330 Log.e(TAG, "listener not found " + listener); 331 return; 332 } 333 localLog("stop background scan: " + client); 334 Message msg = Message.obtain(); 335 msg.what = WifiScanner.CMD_STOP_BACKGROUND_SCAN; 336 msg.obj = new ScanParams(listener, null, null, featureId); 337 msg.sendingUid = uid; 338 mBackgroundScanStateMachine.sendMessage(msg); 339 } 340 341 @Override getScanResults(String packageName, String featureId)342 public boolean getScanResults(String packageName, String featureId) { 343 final int uid = Binder.getCallingUid(); 344 try { 345 enforcePermission(uid, packageName, featureId, 346 isPrivilegedMessage(WifiScanner.CMD_GET_SCAN_RESULTS), 347 false, false); 348 } catch (SecurityException e) { 349 localLog("getScanResults: failed to authorize app: " + packageName + " uid " 350 + uid + " AttributionTag " + featureId); 351 return false; 352 } 353 localLog("get scan result: " + packageName + " AttributionTag " + featureId); 354 mBackgroundScanStateMachine.sendMessage(WifiScanner.CMD_GET_SCAN_RESULTS); 355 return true; 356 } 357 358 private static class ScanParams { 359 public IWifiScannerListener listener; 360 public WifiScanner.ScanSettings settings; 361 public WifiScanner.PnoSettings pnoSettings; 362 public WorkSource workSource; 363 public String packageName; 364 public String featureId; 365 ScanParams(IWifiScannerListener listener, WifiScanner.ScanSettings settings, WorkSource workSource, String featureId)366 ScanParams(IWifiScannerListener listener, WifiScanner.ScanSettings settings, 367 WorkSource workSource, String featureId) { 368 this(listener, settings, null, workSource, null, featureId); 369 } 370 ScanParams(IWifiScannerListener listener, WifiScanner.ScanSettings settings, WifiScanner.PnoSettings pnoSettings, WorkSource workSource, String packageName, String featureId)371 ScanParams(IWifiScannerListener listener, WifiScanner.ScanSettings settings, 372 WifiScanner.PnoSettings pnoSettings, WorkSource workSource, String packageName, 373 String featureId) { 374 this.listener = listener; 375 this.settings = settings; 376 this.pnoSettings = pnoSettings; 377 this.workSource = workSource; 378 this.packageName = packageName; 379 this.featureId = featureId; 380 } 381 } 382 383 @Override startScan(IWifiScannerListener listener, WifiScanner.ScanSettings settings, WorkSource workSource, String packageName, String featureId)384 public void startScan(IWifiScannerListener listener, WifiScanner.ScanSettings settings, 385 WorkSource workSource, String packageName, String featureId) { 386 final int uid = Binder.getCallingUid(); 387 try { 388 enforcePermission(uid, packageName, featureId, 389 isPrivilegedMessage(WifiScanner.CMD_START_SINGLE_SCAN), 390 shouldIgnoreLocationSettingsForSingleScan(settings), 391 shouldHideFromAppsForSingleScan(settings)); 392 } catch (SecurityException e) { 393 localLog("startScan: failed to authorize app: " + packageName + " uid " 394 + uid + " AttributionTag " + featureId); 395 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 396 return; 397 } 398 mLastCallerInfoManager.put(WifiManager.API_WIFI_SCANNER_START_SCAN, Process.myTid(), 399 uid, Binder.getCallingPid(), packageName, true); 400 mWifiThreadRunner.post(() -> { 401 ExternalClientInfo client = (ExternalClientInfo) mClients.get(listener); 402 if (client == null) { 403 client = new ExternalClientInfo(uid, packageName, listener, featureId); 404 client.register(); 405 } 406 localLog("start scan: " + client + " package " + packageName + " AttributionTag " 407 + featureId); 408 Message msg = Message.obtain(); 409 msg.what = WifiScanner.CMD_START_SINGLE_SCAN; 410 msg.obj = new ScanParams(listener, settings, workSource, featureId); 411 msg.sendingUid = uid; 412 mSingleScanStateMachine.sendMessage(msg); 413 }, TAG + "#startScan"); 414 } 415 416 @Override stopScan(IWifiScannerListener listener, String packageName, String featureId)417 public void stopScan(IWifiScannerListener listener, String packageName, String featureId) { 418 int uid = Binder.getCallingUid(); 419 try { 420 enforcePermission(uid, packageName, featureId, 421 isPrivilegedMessage(WifiScanner.CMD_STOP_SINGLE_SCAN), 422 true, false); 423 } catch (SecurityException e) { 424 localLog("stopScan: failed to authorize app: " + packageName + " uid " 425 + uid + " AttributionTag " + featureId); 426 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 427 return; 428 } 429 mWifiThreadRunner.post(() -> { 430 ExternalClientInfo client = (ExternalClientInfo) mClients.get(listener); 431 if (client == null) { 432 Log.e(TAG, "listener not found " + listener); 433 return; 434 } 435 localLog("stop scan: " + client + " AttributionTag " + featureId); 436 Message msg = Message.obtain(); 437 msg.what = WifiScanner.CMD_STOP_SINGLE_SCAN; 438 msg.obj = new ScanParams(listener, null, null, featureId); 439 msg.sendingUid = uid; 440 mSingleScanStateMachine.sendMessage(msg); 441 }, TAG + "#stopScan"); 442 } 443 444 @Override getSingleScanResults(String packageName, String featureId)445 public List<ScanResult> getSingleScanResults(String packageName, String featureId) { 446 localLog("get single scan result: package " + packageName 447 + " AttributionTag " + featureId); 448 final int uid = Binder.getCallingUid(); 449 try { 450 enforcePermission(uid, packageName, featureId, 451 isPrivilegedMessage(WifiScanner.CMD_GET_SCAN_RESULTS), 452 false, false); 453 } catch (SecurityException e) { 454 localLog("getSingleScanResults: failed to authorize app: " + packageName + " uid " 455 + uid + " AttributionTag " + featureId); 456 return new ArrayList<>(); 457 } 458 return mWifiThreadRunner.call(() -> mSingleScanStateMachine.filterCachedScanResultsByAge(), 459 new ArrayList<ScanResult>(), TAG + "#getSingleScanResults"); 460 } 461 462 463 /** 464 * See {@link WifiScanner#getCachedScanData(Executor, Consumer)}. 465 */ 466 @Override getCachedScanData(String packageName, String featureId, IScanDataListener listener)467 public void getCachedScanData(String packageName, String featureId, 468 IScanDataListener listener) { 469 localLog("get single scan result: package " + packageName 470 + " AttributionTag " + featureId); 471 final int uid = Binder.getCallingUid(); 472 Objects.requireNonNull(listener, "listener cannot be null"); 473 enforcePermission(uid, packageName, featureId, false, false, false); 474 475 mWifiThreadRunner.post(() -> { 476 try { 477 listener.onResult(mWifiNative.getCachedScanResultsFromAllClientIfaces()); 478 } catch (RemoteException e) { 479 Log.e(TAG, e.getMessage(), e); 480 } 481 }, TAG + "#getCachedScanData"); 482 } 483 484 @Override startPnoScan(IWifiScannerListener listener, WifiScanner.ScanSettings scanSettings, WifiScanner.PnoSettings pnoSettings, String packageName, String featureId)485 public void startPnoScan(IWifiScannerListener listener, WifiScanner.ScanSettings scanSettings, 486 WifiScanner.PnoSettings pnoSettings, String packageName, String featureId) { 487 final int uid = Binder.getCallingUid(); 488 if (listener == null) { 489 Log.e(TAG, "listener is null"); 490 return; 491 } 492 try { 493 enforcePermission(uid, packageName, featureId, 494 isPrivilegedMessage(WifiScanner.CMD_START_PNO_SCAN), 495 false, false); 496 } catch (SecurityException e) { 497 localLog("startPnoScan: failed to authorize app: " + packageName + " uid " 498 + uid + " AttributionTag " + featureId); 499 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 500 return; 501 } 502 mWifiThreadRunner.post(() -> { 503 String clientInfoLog = "ClientInfo[uid=" + uid + ", package=" + packageName + ", " 504 + listener + "]"; 505 localLog("start pno scan: " + clientInfoLog + " AttributionTag " + featureId); 506 Message msg = Message.obtain(); 507 msg.what = WifiScanner.CMD_START_PNO_SCAN; 508 msg.obj = new ScanParams(listener, scanSettings, pnoSettings, null, packageName, 509 featureId); 510 msg.sendingUid = uid; 511 mPnoScanStateMachine.sendMessage(msg); 512 }, TAG + "#startPnoScan"); 513 } 514 515 @Override stopPnoScan(IWifiScannerListener listener, String packageName, String featureId)516 public void stopPnoScan(IWifiScannerListener listener, String packageName, String featureId) { 517 final int uid = Binder.getCallingUid(); 518 if (listener == null) { 519 Log.e(TAG, "listener is null"); 520 return; 521 } 522 try { 523 enforcePermission(uid, packageName, featureId, 524 isPrivilegedMessage(WifiScanner.CMD_STOP_PNO_SCAN), 525 true, false); 526 } catch (SecurityException e) { 527 localLog("stopPnoScan: failed to authorize app: " + packageName + " uid " 528 + uid + " AttributionTag " + featureId); 529 notifyFailure(listener, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 530 return; 531 } 532 mWifiThreadRunner.post(() -> { 533 localLog("stop pno scan: " + packageName + " AttributionTag " + featureId); 534 Message msg = Message.obtain(); 535 msg.what = WifiScanner.CMD_STOP_PNO_SCAN; 536 msg.obj = new ScanParams(listener, null, null, featureId); 537 msg.sendingUid = uid; 538 mPnoScanStateMachine.sendMessage(msg); 539 }, TAG + "#stopPnoScan"); 540 } 541 542 @Override enableVerboseLogging(boolean enabled)543 public void enableVerboseLogging(boolean enabled) { 544 if (!mWifiPermissionsUtil.checkNetworkSettingsPermission(Binder.getCallingUid())) { 545 return; 546 } 547 mVerboseLoggingEnabled.set(enabled); 548 localLog("enableVerboseLogging: uid=" + Binder.getCallingUid() + " enabled=" + enabled); 549 } 550 isVerboseLoggingEnabled()551 private boolean isVerboseLoggingEnabled() { 552 return mVerboseLoggingEnabled.get(); 553 } 554 enforceNetworkStack(int uid)555 private void enforceNetworkStack(int uid) { 556 mContext.enforcePermission( 557 Manifest.permission.NETWORK_STACK, 558 UNKNOWN_PID, uid, 559 "NetworkStack"); 560 } 561 562 // Helper method to check if the incoming message is for a privileged request. isPrivilegedMessage(int msgWhat)563 private boolean isPrivilegedMessage(int msgWhat) { 564 boolean isPrivileged = (msgWhat == WifiScanner.CMD_ENABLE 565 || msgWhat == WifiScanner.CMD_DISABLE 566 || msgWhat == WifiScanner.CMD_START_PNO_SCAN 567 || msgWhat == WifiScanner.CMD_STOP_PNO_SCAN); 568 if (!SdkLevel.isAtLeastT()) { 569 isPrivileged = isPrivileged || msgWhat == WifiScanner.CMD_REGISTER_SCAN_LISTENER; 570 } 571 return isPrivileged; 572 } 573 574 // Check if we should ignore location settings if this is a single scan request. shouldIgnoreLocationSettingsForSingleScan(ScanSettings scanSettings)575 private boolean shouldIgnoreLocationSettingsForSingleScan(ScanSettings scanSettings) { 576 if (scanSettings == null) return false; 577 return scanSettings.ignoreLocationSettings; 578 } 579 580 // Check if we should hide this request from app-ops if this is a single scan request. shouldHideFromAppsForSingleScan(ScanSettings scanSettings)581 private boolean shouldHideFromAppsForSingleScan(ScanSettings scanSettings) { 582 if (scanSettings == null) return false; 583 return scanSettings.hideFromAppOps; 584 } 585 586 /** 587 * Get merged vendor IE byte array from List 588 */ getVendorIesBytesFromVendorIesList( List<ScanResult.InformationElement> vendorIesList)589 public static byte[] getVendorIesBytesFromVendorIesList( 590 List<ScanResult.InformationElement> vendorIesList) { 591 if (vendorIesList.size() == 0) return null; 592 593 int len = 0; 594 for (ScanResult.InformationElement ie : vendorIesList) { 595 if ((len + WifiScanner.WIFI_IE_HEAD_LEN + ie.bytes.length) 596 > WifiScanner.WIFI_SCANNER_SETTINGS_VENDOR_ELEMENTS_MAX_LEN) { 597 Log.w(TAG, "Total vendor IE len is larger than max len. Current len:" + len); 598 break; 599 } 600 len += WifiScanner.WIFI_IE_HEAD_LEN + ie.bytes.length; 601 } 602 603 byte[] vendorIes = new byte[len]; 604 int index = 0; 605 for (ScanResult.InformationElement ie : vendorIesList) { 606 if ((index + WifiScanner.WIFI_IE_HEAD_LEN + ie.bytes.length) 607 > WifiScanner.WIFI_SCANNER_SETTINGS_VENDOR_ELEMENTS_MAX_LEN) { 608 break; 609 } 610 vendorIes[index] = (byte) ie.id; 611 vendorIes[index + 1] = (byte) ie.bytes.length; 612 System.arraycopy(ie.bytes, 0, vendorIes, index + WifiScanner.WIFI_IE_HEAD_LEN, 613 ie.bytes.length); 614 index += WifiScanner.WIFI_IE_HEAD_LEN + ie.bytes.length; 615 } 616 return vendorIes; 617 } 618 619 /** 620 * Enforce the necessary client permissions for WifiScanner. 621 * If the client has NETWORK_STACK permission, then it can "always" send "any" request. 622 * If the client has only LOCATION_HARDWARE permission, then it can 623 * a) Only make scan related requests when location is turned on. 624 * b) Can never make one of the privileged requests. 625 * 626 * @param uid uid of the client 627 * @param packageName package name of the client 628 * @param attributionTag The feature in the package of the client 629 * @param isPrivilegedRequest whether we are checking for a privileged request 630 * @param shouldIgnoreLocationSettings override to ignore location settings 631 * @param shouldHideFromApps override to hide request from AppOps 632 */ enforcePermission(int uid, String packageName, @Nullable String attributionTag, boolean isPrivilegedRequest, boolean shouldIgnoreLocationSettings, boolean shouldHideFromApps)633 private void enforcePermission(int uid, String packageName, @Nullable String attributionTag, 634 boolean isPrivilegedRequest, boolean shouldIgnoreLocationSettings, 635 boolean shouldHideFromApps) { 636 try { 637 /** Wifi stack issued requests.*/ 638 enforceNetworkStack(uid); 639 } catch (SecurityException e) { 640 // System-app issued requests 641 if (isPrivilegedRequest) { 642 // Privileged message, only requests from clients with NETWORK_STACK allowed! 643 throw e; 644 } 645 mWifiPermissionsUtil.enforceCanAccessScanResultsForWifiScanner(packageName, 646 attributionTag, uid, shouldIgnoreLocationSettings, shouldHideFromApps); 647 } 648 } 649 650 private static final int BASE = Protocol.BASE_WIFI_SCANNER_SERVICE; 651 652 private static final int CMD_SCAN_RESULTS_AVAILABLE = BASE + 0; 653 private static final int CMD_FULL_SCAN_SINGLE_RESULT = BASE + 1; 654 private static final int CMD_FULL_SCAN_ALL_RESULTS = BASE + 2; 655 private static final int CMD_SCAN_PAUSED = BASE + 8; 656 private static final int CMD_SCAN_RESTARTED = BASE + 9; 657 private static final int CMD_SCAN_FAILED = BASE + 10; 658 private static final int CMD_PNO_NETWORK_FOUND = BASE + 11; 659 private static final int CMD_PNO_SCAN_FAILED = BASE + 12; 660 private static final int CMD_SW_PNO_SCAN = BASE + 14; 661 662 663 private final Context mContext; 664 private final Looper mLooper; 665 private final WifiThreadRunner mWifiThreadRunner; 666 private final WifiScannerImpl.WifiScannerImplFactory mScannerImplFactory; 667 private final ArrayMap<IWifiScannerListener, ClientInfo> mClients; 668 private final Map<String, WifiScannerImpl> mScannerImpls; 669 670 671 private final RequestList<Void> mSingleScanListeners = new RequestList<>(); 672 673 private ChannelHelper mChannelHelper; 674 private BackgroundScanScheduler mBackgroundScheduler; 675 private WifiNative.ScanSettings mPreviousSchedule; 676 private boolean mIsScanning = false; 677 678 private WifiBackgroundScanStateMachine mBackgroundScanStateMachine; 679 private WifiSingleScanStateMachine mSingleScanStateMachine; 680 private WifiPnoScanStateMachine mPnoScanStateMachine; 681 private final BatteryStatsManager mBatteryStats; 682 private final AlarmManager mAlarmManager; 683 private final WifiMetrics mWifiMetrics; 684 private final Clock mClock; 685 private final WifiPermissionsUtil mWifiPermissionsUtil; 686 private final WifiNative mWifiNative; 687 private final WifiManager mWifiManager; 688 private final LastCallerInfoManager mLastCallerInfoManager; 689 private final DeviceConfigFacade mDeviceConfigFacade; 690 private final WifiGlobals mWifiGlobals; 691 692 private AtomicBoolean mVerboseLoggingEnabled = new AtomicBoolean(false); 693 WifiScanningServiceImpl(Context context, Looper looper, WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, BatteryStatsManager batteryStats, WifiInjector wifiInjector)694 WifiScanningServiceImpl(Context context, Looper looper, 695 WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, 696 BatteryStatsManager batteryStats, WifiInjector wifiInjector) { 697 mContext = context; 698 mLooper = looper; 699 mWifiThreadRunner = new WifiThreadRunner(new Handler(looper)); 700 mScannerImplFactory = scannerImplFactory; 701 mBatteryStats = batteryStats; 702 mClients = new ArrayMap<>(); 703 mScannerImpls = new ArrayMap<>(); 704 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 705 mWifiMetrics = wifiInjector.getWifiMetrics(); 706 mClock = wifiInjector.getClock(); 707 mLog = wifiInjector.makeLog(TAG); 708 mWifiPermissionsUtil = wifiInjector.getWifiPermissionsUtil(); 709 mWifiNative = wifiInjector.getWifiNative(); 710 mDeviceConfigFacade = wifiInjector.getDeviceConfigFacade(); 711 mWifiGlobals = wifiInjector.getWifiGlobals(); 712 // Wifi service is always started before other wifi services. So, there is no problem 713 // obtaining WifiManager in the constructor here. 714 mWifiManager = mContext.getSystemService(WifiManager.class); 715 mPreviousSchedule = null; 716 mLastCallerInfoManager = wifiInjector.getLastCallerInfoManager(); 717 } 718 startService()719 public void startService() { 720 mWifiThreadRunner.post(() -> { 721 WifiLocalServices.addService(WifiScannerInternal.class, new LocalService()); 722 mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper); 723 mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper); 724 mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper); 725 726 mBackgroundScanStateMachine.start(); 727 mSingleScanStateMachine.start(); 728 mPnoScanStateMachine.start(); 729 }, TAG + "#startService"); 730 } 731 732 /** 733 * Checks if all the channels provided by the new impl is already satisfied by an existing impl. 734 * 735 * Note: This only handles the cases where the 2 ifaces are on different chips with 736 * distinctly different bands supported on both. If there are cases where 737 * the 2 ifaces support overlapping bands, then we probably need to rework this. 738 * For example: wlan0 supports 2.4G only, wlan1 supports 2.4G + 5G + DFS. 739 * In the above example, we should teardown wlan0 impl when wlan1 impl is created 740 * because wlan1 impl can already handle all the supported bands. 741 * Ignoring this for now since we don't foresee this requirement in the near future. 742 */ doesAnyExistingImplSatisfy(WifiScannerImpl newImpl)743 private boolean doesAnyExistingImplSatisfy(WifiScannerImpl newImpl) { 744 for (WifiScannerImpl existingImpl : mScannerImpls.values()) { 745 if (existingImpl.getChannelHelper().satisfies(newImpl.getChannelHelper())) { 746 return true; 747 } 748 } 749 return false; 750 } 751 setupScannerImpls()752 private void setupScannerImpls() { 753 Set<String> ifaceNames = mWifiNative.getClientInterfaceNames(); 754 if (ArrayUtils.isEmpty(ifaceNames)) { 755 loge("Failed to retrieve client interface names"); 756 return; 757 } 758 Set<String> ifaceNamesOfImplsAlreadySetup = mScannerImpls.keySet(); 759 if (ifaceNames.equals(ifaceNamesOfImplsAlreadySetup)) { 760 // Scanner Impls already exist for all ifaces (back to back CMD_ENABLE sent?). 761 Log.i(TAG, "scanner impls already exists"); 762 return; 763 } 764 // set of impls to teardown. 765 Set<String> ifaceNamesOfImplsToTeardown = new ArraySet<>(ifaceNamesOfImplsAlreadySetup); 766 ifaceNamesOfImplsToTeardown.removeAll(ifaceNames); 767 // set of impls to be considered for setup. 768 Set<String> ifaceNamesOfImplsToSetup = new ArraySet<>(ifaceNames); 769 ifaceNamesOfImplsToSetup.removeAll(ifaceNamesOfImplsAlreadySetup); 770 771 for (String ifaceName : ifaceNamesOfImplsToTeardown) { 772 WifiScannerImpl impl = mScannerImpls.remove(ifaceName); 773 if (impl == null) continue; // should never happen 774 impl.cleanup(); 775 Log.i(TAG, "Removed an impl for " + ifaceName); 776 } 777 for (String ifaceName : ifaceNamesOfImplsToSetup) { 778 WifiScannerImpl impl = mScannerImplFactory.create(mContext, mLooper, mClock, ifaceName); 779 if (impl == null) { 780 loge("Failed to create scanner impl for " + ifaceName); 781 continue; 782 } 783 // If this new scanner impl does not offer any new bands to scan, then we should 784 // ignore it. 785 if (!doesAnyExistingImplSatisfy(impl)) { 786 mScannerImpls.put(ifaceName, impl); 787 Log.i(TAG, "Created a new impl for " + ifaceName); 788 } else { 789 Log.i(TAG, "All the channels on the new impl for iface " + ifaceName 790 + " are already satisfied by an existing impl. Skipping.."); 791 impl.cleanup(); // cleanup the impl before discarding. 792 } 793 } 794 } 795 teardownScannerImpls()796 private void teardownScannerImpls() { 797 for (Map.Entry<String, WifiScannerImpl> entry : mScannerImpls.entrySet()) { 798 WifiScannerImpl impl = entry.getValue(); 799 String ifaceName = entry.getKey(); 800 if (impl == null) continue; // should never happen 801 impl.cleanup(); 802 Log.i(TAG, "Removed an impl for " + ifaceName); 803 } 804 mScannerImpls.clear(); 805 } 806 computeWorkSource(ClientInfo ci, WorkSource requestedWorkSource)807 private WorkSource computeWorkSource(ClientInfo ci, WorkSource requestedWorkSource) { 808 if (requestedWorkSource != null && !requestedWorkSource.isEmpty()) { 809 return requestedWorkSource.withoutNames(); 810 } 811 812 if (ci.getUid() > 0) { 813 return new WorkSource(ci.getUid()); 814 } 815 816 // We can't construct a sensible WorkSource because the one supplied to us was empty and 817 // we don't have a valid UID for the given client. 818 loge("Unable to compute workSource for client: " + ci + ", requested: " 819 + requestedWorkSource); 820 return new WorkSource(); 821 } 822 823 private class RequestInfo<T> { 824 final ClientInfo clientInfo; 825 final WorkSource workSource; 826 final T settings; 827 RequestInfo(ClientInfo clientInfo, WorkSource requestedWorkSource, T settings)828 RequestInfo(ClientInfo clientInfo, WorkSource requestedWorkSource, T settings) { 829 this.clientInfo = clientInfo; 830 this.settings = settings; 831 this.workSource = computeWorkSource(clientInfo, requestedWorkSource); 832 } 833 } 834 835 private class RequestList<T> extends ArrayList<RequestInfo<T>> { addRequest(ClientInfo ci, WorkSource reqworkSource, T settings)836 void addRequest(ClientInfo ci, WorkSource reqworkSource, T settings) { 837 add(new RequestInfo<T>(ci, reqworkSource, settings)); 838 } 839 removeRequest(ClientInfo ci)840 T removeRequest(ClientInfo ci) { 841 T removed = null; 842 Iterator<RequestInfo<T>> iter = iterator(); 843 while (iter.hasNext()) { 844 RequestInfo<T> entry = iter.next(); 845 if (entry.clientInfo == ci) { 846 removed = entry.settings; 847 iter.remove(); 848 } 849 } 850 return removed; 851 } 852 getAllSettings()853 Collection<T> getAllSettings() { 854 ArrayList<T> settingsList = new ArrayList<>(); 855 Iterator<RequestInfo<T>> iter = iterator(); 856 while (iter.hasNext()) { 857 RequestInfo<T> entry = iter.next(); 858 settingsList.add(entry.settings); 859 } 860 return settingsList; 861 } 862 getAllSettingsForClient(ClientInfo ci)863 Collection<T> getAllSettingsForClient(ClientInfo ci) { 864 ArrayList<T> settingsList = new ArrayList<>(); 865 Iterator<RequestInfo<T>> iter = iterator(); 866 while (iter.hasNext()) { 867 RequestInfo<T> entry = iter.next(); 868 if (entry.clientInfo == ci) { 869 settingsList.add(entry.settings); 870 } 871 } 872 return settingsList; 873 } 874 removeAllForClient(ClientInfo ci)875 void removeAllForClient(ClientInfo ci) { 876 Iterator<RequestInfo<T>> iter = iterator(); 877 while (iter.hasNext()) { 878 RequestInfo<T> entry = iter.next(); 879 if (entry.clientInfo == ci) { 880 iter.remove(); 881 } 882 } 883 } 884 createMergedWorkSource()885 WorkSource createMergedWorkSource() { 886 WorkSource mergedSource = new WorkSource(); 887 for (RequestInfo<T> entry : this) { 888 mergedSource.add(entry.workSource); 889 } 890 return mergedSource; 891 } 892 } 893 getWhatToStringInternal(int what)894 private String getWhatToStringInternal(int what) { 895 switch (what) { 896 case WifiScanner.CMD_START_BACKGROUND_SCAN: 897 return "WifiScanner.CMD_START_BACKGROUND_SCAN"; 898 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 899 return "WifiScanner.CMD_STOP_BACKGROUND_SCAN"; 900 case WifiScanner.CMD_GET_SCAN_RESULTS: 901 return "WifiScanner.CMD_GET_SCAN_RESULTS"; 902 case WifiScanner.CMD_SCAN_RESULT: 903 return "WifiScanner.CMD_SCAN_RESULT"; 904 case WifiScanner.CMD_CACHED_SCAN_DATA: 905 return "WifiScanner.CMD_CACHED_SCAN_DATA"; 906 case WifiScanner.CMD_OP_SUCCEEDED: 907 return "WifiScanner.CMD_OP_SUCCEEDED"; 908 case WifiScanner.CMD_OP_FAILED: 909 return "WifiScanner.CMD_OP_FAILED"; 910 case WifiScanner.CMD_FULL_SCAN_RESULT: 911 return "WifiScanner.CMD_FULL_SCAN_RESULT"; 912 case WifiScanner.CMD_START_SINGLE_SCAN: 913 return "WifiScanner.CMD_START_SINGLE_SCAN"; 914 case WifiScanner.CMD_STOP_SINGLE_SCAN: 915 return "WifiScanner.CMD_STOP_SINGLE_SCAN"; 916 case WifiScanner.CMD_SINGLE_SCAN_COMPLETED: 917 return "WifiScanner.CMD_SINGLE_SCAN_COMPLETED"; 918 case WifiScanner.CMD_START_PNO_SCAN: 919 return "WifiScanner.CMD_START_PNO_SCAN"; 920 case WifiScanner.CMD_STOP_PNO_SCAN: 921 return "WifiScanner.CMD_STOP_PNO_SCAN"; 922 case WifiScanner.CMD_PNO_NETWORK_FOUND: 923 return "WifiScanner.CMD_PNO_NETWORK_FOUND"; 924 case WifiScanner.CMD_REGISTER_SCAN_LISTENER: 925 return "WifiScanner.CMD_REGISTER_SCAN_LISTENER"; 926 case WifiScanner.CMD_DEREGISTER_SCAN_LISTENER: 927 return "WifiScanner.CMD_DEREGISTER_SCAN_LISTENER"; 928 case WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS: 929 return "WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS"; 930 case WifiScanner.CMD_ENABLE: 931 return "WifiScanner.CMD_ENABLE"; 932 case WifiScanner.CMD_DISABLE: 933 return "WifiScanner.CMD_DISABLE"; 934 case CMD_SCAN_RESULTS_AVAILABLE: 935 return "CMD_SCAN_RESULTS_AVAILABLE"; 936 case CMD_FULL_SCAN_SINGLE_RESULT: 937 return "CMD_FULL_SCAN_SINGLE_RESULT"; 938 case CMD_FULL_SCAN_ALL_RESULTS: 939 return "CMD_FULL_SCAN_ALL_RESULTS"; 940 case CMD_SCAN_PAUSED: 941 return "CMD_SCAN_PAUSED"; 942 case CMD_SCAN_RESTARTED: 943 return "CMD_SCAN_RESTARTED"; 944 case CMD_SCAN_FAILED: 945 return "CMD_SCAN_FAILED"; 946 case CMD_PNO_NETWORK_FOUND: 947 return "CMD_PNO_NETWORK_FOUND"; 948 case CMD_PNO_SCAN_FAILED: 949 return "CMD_PNO_SCAN_FAILED"; 950 case CMD_SW_PNO_SCAN: 951 return "CMD_SW_PNO_SCAN"; 952 default: 953 return "what:" + what; 954 } 955 } 956 957 958 /** 959 * State machine that holds the state of single scans. Scans should only be active in the 960 * ScanningState. The pending scans and active scans maps are swapped when entering 961 * ScanningState. Any requests queued while scanning will be placed in the pending queue and 962 * executed after transitioning back to IdleState. 963 */ 964 class WifiSingleScanStateMachine extends StateMachine { 965 /** 966 * Maximum age of results that we return from our cache via 967 * {@link WifiScanner#getScanResults()}. 968 * This is currently set to 3 minutes to restore parity with the wpa_supplicant's scan 969 * result cache expiration policy. (See b/62253332 for details) 970 */ 971 @VisibleForTesting 972 public static final int CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS = 180 * 1000; 973 /** 974 * Alarm Tag to use for the delayed indication of emergency scan end. 975 */ 976 @VisibleForTesting 977 public static final String EMERGENCY_SCAN_END_INDICATION_ALARM_TAG = 978 TAG + "EmergencyScanEnd"; 979 /** 980 * Alarm timeout to use for the delayed indication of emergency scan end. 981 */ 982 private static final int EMERGENCY_SCAN_END_INDICATION_DELAY_MILLIS = 15_000; 983 /** 984 * Alarm listener to use for the delayed indication of emergency scan end. 985 */ 986 private final AlarmManager.OnAlarmListener mEmergencyScanEndIndicationListener = 987 () -> mWifiManager.setEmergencyScanRequestInProgress(false); 988 989 private final DefaultState mDefaultState = new DefaultState(); 990 private final DriverStartedState mDriverStartedState = new DriverStartedState(); 991 private final IdleState mIdleState = new IdleState(); 992 private final ScanningState mScanningState = new ScanningState(); 993 994 private WifiNative.ScanSettings mActiveScanSettings = null; 995 private RequestList<ScanSettings> mActiveScans = new RequestList<>(); 996 private RequestList<ScanSettings> mPendingScans = new RequestList<>(); 997 998 // Scan results cached from the last full single scan request. 999 private final List<ScanResult> mCachedScanResults = new ArrayList<>(); 1000 1001 // Tracks scan requests across multiple scanner impls. 1002 private final ScannerImplsTracker mScannerImplsTracker; 1003 WifiSingleScanStateMachine(Looper looper)1004 WifiSingleScanStateMachine(Looper looper) { 1005 super("WifiSingleScanStateMachine", looper); 1006 1007 mScannerImplsTracker = new ScannerImplsTracker(); 1008 1009 setLogRecSize(128); 1010 setLogOnlyTransitions(false); 1011 1012 // CHECKSTYLE:OFF IndentationCheck 1013 addState(mDefaultState); 1014 addState(mDriverStartedState, mDefaultState); 1015 addState(mIdleState, mDriverStartedState); 1016 addState(mScanningState, mDriverStartedState); 1017 // CHECKSTYLE:ON IndentationCheck 1018 1019 setInitialState(mDefaultState); 1020 } 1021 1022 /** 1023 * @return the string for msg.what 1024 */ 1025 @Override getWhatToString(int what)1026 protected String getWhatToString(int what) { 1027 return getWhatToStringInternal(what); 1028 } 1029 1030 /** 1031 * Return the additional string to be logged by LogRec, default 1032 * 1033 * @param msg that was processed 1034 * @return information to be logged as a String 1035 */ 1036 @Override getLogRecString(Message msg)1037 protected String getLogRecString(Message msg) { 1038 StringBuilder sb = new StringBuilder(); 1039 sb.append(" "); 1040 sb.append(Integer.toString(msg.arg1)); 1041 sb.append(" "); 1042 sb.append(Integer.toString(msg.arg2)); 1043 return sb.toString(); 1044 } 1045 1046 /** 1047 * Tracks a single scan request across all the available scanner impls. 1048 * 1049 * a) Initiates the scan using the same ScanSettings across all the available impls. 1050 * b) Waits for all the impls to report the status of the scan request (success or failure). 1051 * c) Calculates a consolidated scan status and sends the results if successful. 1052 * Note: If there are failures on some of the scanner impls, we ignore them since we will 1053 * get some scan results from the other successful impls. We don't declare total scan 1054 * failures, unless all the scanner impls fail. 1055 */ 1056 private final class ScannerImplsTracker { 1057 private final class ScanEventHandler implements WifiNative.ScanEventHandler { 1058 private final String mImplIfaceName; ScanEventHandler(@onNull String implIfaceName)1059 ScanEventHandler(@NonNull String implIfaceName) { 1060 mImplIfaceName = implIfaceName; 1061 } 1062 1063 /** 1064 * Called to indicate a change in state for the current scan. 1065 * Will dispatch a corresponding event to the state machine 1066 */ 1067 @Override onScanStatus(int event)1068 public void onScanStatus(int event) { 1069 if (DBG) { 1070 localLog("onScanStatus event received, event=" + event 1071 + ", iface=" + mImplIfaceName); 1072 } 1073 switch (event) { 1074 case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE: 1075 case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS: 1076 case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT: 1077 reportScanStatusForImpl(mImplIfaceName, STATUS_SUCCEEDED, 1078 WifiScanner.REASON_SUCCEEDED); 1079 break; 1080 case WifiNative.WIFI_SCAN_FAILED: 1081 reportScanStatusForImpl(mImplIfaceName, STATUS_FAILED, 1082 WifiScanner.REASON_UNSPECIFIED); 1083 break; 1084 default: 1085 Log.e(TAG, "Unknown scan status event: " + event); 1086 break; 1087 } 1088 } 1089 1090 /** 1091 * Called for each full scan result if requested 1092 */ 1093 @Override onFullScanResult(ScanResult fullScanResult, int bucketsScanned)1094 public void onFullScanResult(ScanResult fullScanResult, int bucketsScanned) { 1095 if (DBG) localLog("onFullScanResult received on iface " + mImplIfaceName); 1096 reportFullScanResultForImpl(mImplIfaceName, fullScanResult, bucketsScanned); 1097 } 1098 1099 @Override onScanPaused(ScanData[] scanData)1100 public void onScanPaused(ScanData[] scanData) { 1101 // should not happen for single scan 1102 Log.e(TAG, "Got scan paused for single scan"); 1103 } 1104 1105 @Override onScanRestarted()1106 public void onScanRestarted() { 1107 // should not happen for single scan 1108 Log.e(TAG, "Got scan restarted for single scan"); 1109 } 1110 1111 /** 1112 * Called to indicate a scan failure 1113 */ 1114 @Override onScanRequestFailed(int errorCode)1115 public void onScanRequestFailed(int errorCode) { 1116 reportScanStatusForImpl(mImplIfaceName, STATUS_FAILED, errorCode); 1117 } 1118 1119 @Override onFullScanResults(List<ScanResult> fullScanResults, int bucketsScanned)1120 public void onFullScanResults(List<ScanResult> fullScanResults, 1121 int bucketsScanned) { 1122 if (DBG) localLog("onFullScanResults received on iface " + mImplIfaceName); 1123 if (fullScanResults == null || fullScanResults.isEmpty()) { 1124 return; 1125 } 1126 reportFullScanResultsForImpl(mImplIfaceName, fullScanResults, bucketsScanned); 1127 } 1128 } 1129 1130 private static final int STATUS_PENDING = 0; 1131 private static final int STATUS_SUCCEEDED = 1; 1132 private static final int STATUS_FAILED = 2; 1133 1134 // Tracks scan status per impl. 1135 Map<String, Integer> mStatusPerImpl = new ArrayMap<>(); 1136 1137 /** 1138 * Triggers a new scan on all the available scanner impls. 1139 * @return true if the scan succeeded on any of the impl, false otherwise. 1140 */ startSingleScan(WifiNative.ScanSettings scanSettings)1141 public boolean startSingleScan(WifiNative.ScanSettings scanSettings) { 1142 mStatusPerImpl.clear(); 1143 boolean anySuccess = false; 1144 for (Map.Entry<String, WifiScannerImpl> entry : mScannerImpls.entrySet()) { 1145 String ifaceName = entry.getKey(); 1146 WifiScannerImpl impl = entry.getValue(); 1147 boolean success = impl.startSingleScan( 1148 scanSettings, new ScanEventHandler(ifaceName)); 1149 if (!success) { 1150 Log.e(TAG, "Failed to start single scan on " + ifaceName); 1151 mStatusPerImpl.put(ifaceName, STATUS_FAILED); 1152 continue; 1153 } 1154 mStatusPerImpl.put(ifaceName, STATUS_PENDING); 1155 anySuccess = true; 1156 } 1157 return anySuccess; 1158 } 1159 1160 /** 1161 * Returns the latest scan results from all the available scanner impls. 1162 * @return Consolidated list of scan results from all the impl. 1163 */ getLatestSingleScanResults()1164 public @Nullable ScanData getLatestSingleScanResults() { 1165 ScanData consolidatedScanData = null; 1166 for (WifiScannerImpl impl : mScannerImpls.values()) { 1167 Integer ifaceStatus = mStatusPerImpl.get(impl.getIfaceName()); 1168 if (ifaceStatus == null || ifaceStatus != STATUS_SUCCEEDED) { 1169 continue; 1170 } 1171 ScanData scanData = impl.getLatestSingleScanResults(); 1172 if (consolidatedScanData == null) { 1173 consolidatedScanData = new ScanData(scanData); 1174 } else { 1175 consolidatedScanData.addResults(scanData.getResults()); 1176 } 1177 } 1178 return consolidatedScanData; 1179 } 1180 reportFullScanResultForImpl(@onNull String implIfaceName, ScanResult fullScanResult, int bucketsScanned)1181 private void reportFullScanResultForImpl(@NonNull String implIfaceName, 1182 ScanResult fullScanResult, int bucketsScanned) { 1183 Integer status = mStatusPerImpl.get(implIfaceName); 1184 if (status != null && status == STATUS_PENDING) { 1185 sendMessage(CMD_FULL_SCAN_SINGLE_RESULT, 0, bucketsScanned, fullScanResult); 1186 } 1187 } 1188 reportFullScanResultsForImpl(@onNull String implIfaceName, List<ScanResult> fullScanResults, int bucketsScanned)1189 private void reportFullScanResultsForImpl(@NonNull String implIfaceName, 1190 List<ScanResult> fullScanResults, int bucketsScanned) { 1191 Integer status = mStatusPerImpl.get(implIfaceName); 1192 if (status != null && status == STATUS_PENDING) { 1193 sendMessage(CMD_FULL_SCAN_ALL_RESULTS, 0, bucketsScanned, fullScanResults); 1194 } 1195 } 1196 getConsolidatedStatus()1197 private int getConsolidatedStatus() { 1198 boolean anyPending = mStatusPerImpl.values().stream() 1199 .anyMatch(status -> status == STATUS_PENDING); 1200 // at-least one impl status is still pending. 1201 if (anyPending) return STATUS_PENDING; 1202 1203 boolean anySuccess = mStatusPerImpl.values().stream() 1204 .anyMatch(status -> status == STATUS_SUCCEEDED); 1205 // one success is good enough to declare consolidated success. 1206 if (anySuccess) { 1207 return STATUS_SUCCEEDED; 1208 } else { 1209 // all failed. 1210 return STATUS_FAILED; 1211 } 1212 } 1213 reportScanStatusForImpl(@onNull String implIfaceName, int newStatus, int statusCode)1214 private void reportScanStatusForImpl(@NonNull String implIfaceName, int newStatus, 1215 int statusCode) { 1216 Integer currentStatus = mStatusPerImpl.get(implIfaceName); 1217 if (currentStatus != null && currentStatus == STATUS_PENDING) { 1218 mStatusPerImpl.put(implIfaceName, newStatus); 1219 } 1220 // Now check if all the scanner impls scan status is available. 1221 int consolidatedStatus = getConsolidatedStatus(); 1222 if (consolidatedStatus == STATUS_SUCCEEDED) { 1223 sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 1224 } else if (consolidatedStatus == STATUS_FAILED) { 1225 sendMessage(CMD_SCAN_FAILED, statusCode); 1226 } 1227 } 1228 } 1229 1230 /** 1231 * Helper method to handle the scan start message. 1232 */ handleScanStartMessage(ClientInfo ci, ScanParams scanParams)1233 private void handleScanStartMessage(ClientInfo ci, ScanParams scanParams) { 1234 if (ci == null) { 1235 logCallback("singleScanInvalidRequest", ci, "null params"); 1236 return; 1237 } 1238 ScanSettings scanSettings = scanParams.settings; 1239 WorkSource workSource = scanParams.workSource; 1240 if (validateScanRequest(ci, scanSettings)) { 1241 if (getCurrentState() == mDefaultState && !scanSettings.ignoreLocationSettings) { 1242 // Reject regular scan requests if scanning is disabled. 1243 ci.replyFailed(WifiScanner.REASON_UNSPECIFIED, "not available"); 1244 ci.cleanup(); 1245 return; 1246 } 1247 mWifiMetrics.incrementOneshotScanCount(); 1248 if ((scanSettings.band & WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY) != 0) { 1249 mWifiMetrics.incrementOneshotScanWithDfsCount(); 1250 } 1251 logScanRequest("addSingleScanRequest", ci, workSource, 1252 scanSettings, null); 1253 ci.replySucceeded(); 1254 1255 if (scanSettings.ignoreLocationSettings) { 1256 // Inform wifi manager that an emergency scan is in progress (regardless of 1257 // whether scanning is currently enabled or not). This ensures that 1258 // the wifi chip remains on for the duration of this scan. 1259 mWifiManager.setEmergencyScanRequestInProgress(true); 1260 } 1261 1262 if (getCurrentState() == mScanningState) { 1263 // If there is an active scan that will fulfill the scan request then 1264 // mark this request as an active scan, otherwise mark it pending. 1265 if (activeScanSatisfies(scanSettings)) { 1266 mActiveScans.addRequest(ci, workSource, scanSettings); 1267 } else { 1268 mPendingScans.addRequest(ci, workSource, scanSettings); 1269 } 1270 } else if (getCurrentState() == mIdleState) { 1271 // If were not currently scanning then try to start a scan. Otherwise 1272 // this scan will be scheduled when transitioning back to IdleState 1273 // after finishing the current scan. 1274 mPendingScans.addRequest(ci, workSource, scanSettings); 1275 tryToStartNewScan(); 1276 } else if (getCurrentState() == mDefaultState) { 1277 // If scanning is disabled and the request is for emergency purposes 1278 // (checked above), add to pending list. this scan will be scheduled when 1279 // transitioning to IdleState when wifi manager enables scanning as a part of 1280 // processing WifiManager.setEmergencyScanRequestInProgress(true) 1281 mPendingScans.addRequest(ci, workSource, scanSettings); 1282 } 1283 } else { 1284 logCallback("singleScanInvalidRequest", ci, "bad request"); 1285 ci.replyFailed(WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1286 ci.cleanup(); 1287 mWifiMetrics.incrementScanReturnEntry( 1288 WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1); 1289 } 1290 } 1291 1292 class DefaultState extends State { 1293 @Override enter()1294 public void enter() { 1295 mActiveScans.clear(); 1296 mPendingScans.clear(); 1297 } 1298 1299 @Override processMessage(Message msg)1300 public boolean processMessage(Message msg) { 1301 switch (msg.what) { 1302 case WifiScanner.CMD_ENABLE: 1303 if (mScannerImpls.isEmpty()) { 1304 loge("Failed to start single scan state machine because scanner impl" 1305 + " is null"); 1306 return HANDLED; 1307 } 1308 transitionTo(mIdleState); 1309 return HANDLED; 1310 case WifiScanner.CMD_DISABLE: 1311 transitionTo(mDefaultState); 1312 return HANDLED; 1313 case WifiScanner.CMD_START_SINGLE_SCAN: 1314 ScanParams scanParams = (ScanParams) msg.obj; 1315 if (scanParams != null) { 1316 ClientInfo ci = mClients.get(scanParams.listener); 1317 handleScanStartMessage(ci, scanParams); 1318 } 1319 return HANDLED; 1320 case WifiScanner.CMD_STOP_SINGLE_SCAN: 1321 scanParams = (ScanParams) msg.obj; 1322 if (scanParams != null) { 1323 ClientInfo ci = mClients.get(scanParams.listener); 1324 removeSingleScanRequests(ci); 1325 } 1326 return HANDLED; 1327 case CMD_SCAN_RESULTS_AVAILABLE: 1328 if (DBG) localLog("ignored scan results available event"); 1329 return HANDLED; 1330 case CMD_FULL_SCAN_SINGLE_RESULT: 1331 case CMD_FULL_SCAN_ALL_RESULTS: 1332 if (DBG) localLog("ignored full scan result event"); 1333 return HANDLED; 1334 case WifiScanner.CMD_GET_SINGLE_SCAN_RESULTS: 1335 // Should not handled here. 1336 return HANDLED; 1337 default: 1338 return NOT_HANDLED; 1339 } 1340 } 1341 } 1342 1343 /** 1344 * State representing when the driver is running. This state is not meant to be transitioned 1345 * directly, but is instead intended as a parent state of ScanningState and IdleState 1346 * to hold common functionality and handle cleaning up scans when the driver is shut down. 1347 */ 1348 class DriverStartedState extends State { 1349 @Override exit()1350 public void exit() { 1351 // clear scan results when scan mode is not active 1352 mCachedScanResults.clear(); 1353 1354 mWifiMetrics.incrementScanReturnEntry( 1355 WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED, 1356 mPendingScans.size()); 1357 sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED, 1358 "Scan was interrupted"); 1359 } 1360 1361 @Override processMessage(Message msg)1362 public boolean processMessage(Message msg) { 1363 switch (msg.what) { 1364 case WifiScanner.CMD_ENABLE: 1365 // Ignore if we're already in driver loaded state. 1366 return HANDLED; 1367 default: 1368 return NOT_HANDLED; 1369 } 1370 } 1371 } 1372 1373 class IdleState extends State { 1374 @Override enter()1375 public void enter() { 1376 tryToStartNewScan(); 1377 } 1378 1379 @Override processMessage(Message msg)1380 public boolean processMessage(Message msg) { 1381 return NOT_HANDLED; 1382 } 1383 } 1384 1385 class ScanningState extends State { 1386 private WorkSource mScanWorkSource; 1387 1388 @Override enter()1389 public void enter() { 1390 mScanWorkSource = mActiveScans.createMergedWorkSource(); 1391 mBatteryStats.reportWifiScanStartedFromSource(mScanWorkSource); 1392 Pair<int[], String[]> uidsAndTags = 1393 WorkSourceUtil.getUidsAndTagsForWs(mScanWorkSource); 1394 WifiStatsLog.write(WifiStatsLog.WIFI_SCAN_STATE_CHANGED, 1395 uidsAndTags.first, uidsAndTags.second, 1396 WifiStatsLog.WIFI_SCAN_STATE_CHANGED__STATE__ON); 1397 mIsScanning = true; 1398 } 1399 1400 @Override exit()1401 public void exit() { 1402 mActiveScanSettings = null; 1403 mBatteryStats.reportWifiScanStoppedFromSource(mScanWorkSource); 1404 Pair<int[], String[]> uidsAndTags = 1405 WorkSourceUtil.getUidsAndTagsForWs(mScanWorkSource); 1406 WifiStatsLog.write(WifiStatsLog.WIFI_SCAN_STATE_CHANGED, 1407 uidsAndTags.first, uidsAndTags.second, 1408 WifiStatsLog.WIFI_SCAN_STATE_CHANGED__STATE__OFF); 1409 mIsScanning = false; 1410 1411 // if any scans are still active (never got results available then indicate failure) 1412 mWifiMetrics.incrementScanReturnEntry( 1413 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, 1414 mActiveScans.size()); 1415 sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED, 1416 "Scan was interrupted"); 1417 } 1418 1419 @Override processMessage(Message msg)1420 public boolean processMessage(Message msg) { 1421 switch (msg.what) { 1422 case CMD_SCAN_RESULTS_AVAILABLE: 1423 ScanData latestScanResults = 1424 mScannerImplsTracker.getLatestSingleScanResults(); 1425 if (latestScanResults != null) { 1426 handleScanResults(latestScanResults); 1427 } else { 1428 Log.e(TAG, "latest scan results null unexpectedly"); 1429 } 1430 transitionTo(mIdleState); 1431 return HANDLED; 1432 case CMD_FULL_SCAN_SINGLE_RESULT: 1433 reportFullScanSingleResult((ScanResult) msg.obj, 1434 /* bucketsScanned */ msg.arg2); 1435 return HANDLED; 1436 case CMD_FULL_SCAN_ALL_RESULTS: 1437 reportFullScanAllResults((List<ScanResult>) msg.obj, 1438 /* bucketsScanned */ msg.arg2); 1439 return HANDLED; 1440 case CMD_SCAN_FAILED: 1441 mWifiMetrics.incrementScanReturnEntry( 1442 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mActiveScans.size()); 1443 mWifiMetrics.getScanMetrics().logScanFailed( 1444 WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE); 1445 sendOpFailedToAllAndClear(mActiveScans, msg.arg1, 1446 scanErrorCodeToDescriptionString(msg.arg1)); 1447 transitionTo(mIdleState); 1448 return HANDLED; 1449 default: 1450 return NOT_HANDLED; 1451 } 1452 } 1453 } 1454 validateScanType(@ifiAnnotations.ScanType int type)1455 boolean validateScanType(@WifiAnnotations.ScanType int type) { 1456 return (type == WifiScanner.SCAN_TYPE_LOW_LATENCY 1457 || type == WifiScanner.SCAN_TYPE_LOW_POWER 1458 || type == WifiScanner.SCAN_TYPE_HIGH_ACCURACY); 1459 } 1460 validateScanRequest(ClientInfo ci, ScanSettings settings)1461 boolean validateScanRequest(ClientInfo ci, ScanSettings settings) { 1462 if (ci == null) { 1463 Log.d(TAG, "Failing single scan request ClientInfo not found " + ci); 1464 return false; 1465 } 1466 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 1467 if (settings.channels == null || settings.channels.length == 0) { 1468 Log.d(TAG, "Failing single scan because channel list was empty"); 1469 return false; 1470 } 1471 } 1472 if (!validateScanType(settings.type)) { 1473 Log.e(TAG, "Invalid scan type " + settings.type); 1474 return false; 1475 } 1476 if (mContext.checkPermission( 1477 Manifest.permission.NETWORK_STACK, UNKNOWN_PID, ci.getUid()) 1478 == PERMISSION_DENIED) { 1479 if (!ArrayUtils.isEmpty(settings.hiddenNetworks)) { 1480 Log.e(TAG, "Failing single scan because app " + ci.getUid() 1481 + " does not have permission to set hidden networks"); 1482 return false; 1483 } 1484 if (settings.type != WifiScanner.SCAN_TYPE_LOW_LATENCY) { 1485 Log.e(TAG, "Failing single scan because app " + ci.getUid() 1486 + " does not have permission to set type"); 1487 return false; 1488 } 1489 } 1490 return true; 1491 } 1492 1493 // We can coalesce a LOW_POWER/LOW_LATENCY scan request into an ongoing HIGH_ACCURACY 1494 // scan request. But, we can't coalesce a HIGH_ACCURACY scan request into an ongoing 1495 // LOW_POWER/LOW_LATENCY scan request. activeScanTypeSatisfies(int requestScanType)1496 boolean activeScanTypeSatisfies(int requestScanType) { 1497 switch(mActiveScanSettings.scanType) { 1498 case WifiScanner.SCAN_TYPE_LOW_LATENCY: 1499 case WifiScanner.SCAN_TYPE_LOW_POWER: 1500 return requestScanType != WifiScanner.SCAN_TYPE_HIGH_ACCURACY; 1501 case WifiScanner.SCAN_TYPE_HIGH_ACCURACY: 1502 return true; 1503 default: 1504 // This should never happen because we've validated the incoming type in 1505 // |validateScanType|. 1506 throw new IllegalArgumentException("Invalid scan type " 1507 + mActiveScanSettings.scanType); 1508 } 1509 } 1510 1511 // If there is a HIGH_ACCURACY scan request among the requests being merged, the merged 1512 // scan type should be HIGH_ACCURACY. mergeScanTypes(int existingScanType, int newScanType)1513 int mergeScanTypes(int existingScanType, int newScanType) { 1514 switch(existingScanType) { 1515 case WifiScanner.SCAN_TYPE_LOW_LATENCY: 1516 case WifiScanner.SCAN_TYPE_LOW_POWER: 1517 return newScanType; 1518 case WifiScanner.SCAN_TYPE_HIGH_ACCURACY: 1519 return existingScanType; 1520 default: 1521 // This should never happen because we've validated the incoming type in 1522 // |validateScanType|. 1523 throw new IllegalArgumentException("Invalid scan type " + existingScanType); 1524 } 1525 } 1526 mergeRnrSetting(boolean enable6GhzRnr, ScanSettings scanSettings)1527 private boolean mergeRnrSetting(boolean enable6GhzRnr, ScanSettings scanSettings) { 1528 if (!SdkLevel.isAtLeastS()) { 1529 return false; 1530 } 1531 if (enable6GhzRnr) { 1532 return true; 1533 } 1534 int rnrSetting = scanSettings.getRnrSetting(); 1535 if (rnrSetting == WifiScanner.WIFI_RNR_ENABLED) { 1536 return true; 1537 } 1538 if (rnrSetting == WifiScanner.WIFI_RNR_ENABLED_IF_WIFI_BAND_6_GHZ_SCANNED) { 1539 return ChannelHelper.is6GhzBandIncluded(scanSettings.band); 1540 } 1541 return false; 1542 } 1543 mergeVendorIes(List<ScanResult.InformationElement> existingVendorIes, ScanSettings scanSettings)1544 private void mergeVendorIes(List<ScanResult.InformationElement> existingVendorIes, 1545 ScanSettings scanSettings) { 1546 if (!SdkLevel.isAtLeastU()) { 1547 return; 1548 } 1549 for (ScanResult.InformationElement ie : scanSettings.getVendorIes()) { 1550 if (!existingVendorIes.contains(ie)) { 1551 existingVendorIes.add(ie); 1552 } 1553 } 1554 } 1555 activeScanSatisfies(ScanSettings settings)1556 boolean activeScanSatisfies(ScanSettings settings) { 1557 if (mActiveScanSettings == null) { 1558 return false; 1559 } 1560 1561 if (!activeScanTypeSatisfies(settings.type)) { 1562 return false; 1563 } 1564 1565 // there is always one bucket for a single scan 1566 WifiNative.BucketSettings activeBucket = mActiveScanSettings.buckets[0]; 1567 1568 // validate that all requested channels are being scanned 1569 ChannelCollection activeChannels = mChannelHelper.createChannelCollection(); 1570 activeChannels.addChannels(activeBucket); 1571 if (!activeChannels.containsSettings(settings)) { 1572 return false; 1573 } 1574 1575 // if the request is for a full scan, but there is no ongoing full scan 1576 if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0 1577 && (activeBucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) 1578 == 0) { 1579 return false; 1580 } 1581 1582 if (!ArrayUtils.isEmpty(settings.hiddenNetworks)) { 1583 if (ArrayUtils.isEmpty(mActiveScanSettings.hiddenNetworks)) { 1584 return false; 1585 } 1586 List<WifiNative.HiddenNetwork> activeHiddenNetworks = new ArrayList<>(); 1587 for (WifiNative.HiddenNetwork hiddenNetwork : mActiveScanSettings.hiddenNetworks) { 1588 activeHiddenNetworks.add(hiddenNetwork); 1589 } 1590 for (ScanSettings.HiddenNetwork hiddenNetwork : settings.hiddenNetworks) { 1591 WifiNative.HiddenNetwork nativeHiddenNetwork = new WifiNative.HiddenNetwork(); 1592 nativeHiddenNetwork.ssid = hiddenNetwork.ssid; 1593 if (!activeHiddenNetworks.contains(nativeHiddenNetwork)) { 1594 return false; 1595 } 1596 } 1597 } 1598 1599 return true; 1600 } 1601 removeSingleScanRequests(ClientInfo ci)1602 void removeSingleScanRequests(ClientInfo ci) { 1603 if (ci != null) { 1604 logScanRequest("removeSingleScanRequests", ci, null, null, null); 1605 mPendingScans.removeAllForClient(ci); 1606 mActiveScans.removeAllForClient(ci); 1607 } 1608 } 1609 tryToStartNewScan()1610 void tryToStartNewScan() { 1611 if (mPendingScans.size() == 0) { // no pending requests 1612 return; 1613 } 1614 mChannelHelper.updateChannels(); 1615 // TODO move merging logic to a scheduler 1616 WifiNative.ScanSettings settings = new WifiNative.ScanSettings(); 1617 settings.num_buckets = 1; 1618 WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); 1619 bucketSettings.bucket = 0; 1620 bucketSettings.period_ms = 0; 1621 bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 1622 1623 ChannelCollection channels = mChannelHelper.createChannelCollection(); 1624 WifiScanner.ChannelSpec[][] available6GhzChannels = 1625 mChannelHelper.getAvailableScanChannels(WifiScanner.WIFI_BAND_6_GHZ); 1626 boolean are6GhzChannelsAvailable = available6GhzChannels.length > 0 1627 && available6GhzChannels[0].length > 0; 1628 List<WifiNative.HiddenNetwork> hiddenNetworkList = new ArrayList<>(); 1629 List<ScanResult.InformationElement> vendorIesList = new ArrayList<>(); 1630 for (RequestInfo<ScanSettings> entry : mPendingScans) { 1631 settings.scanType = mergeScanTypes(settings.scanType, entry.settings.type); 1632 if (are6GhzChannelsAvailable) { 1633 settings.enable6GhzRnr = mergeRnrSetting( 1634 settings.enable6GhzRnr, entry.settings); 1635 } else { 1636 settings.enable6GhzRnr = false; 1637 } 1638 channels.addChannels(entry.settings); 1639 for (ScanSettings.HiddenNetwork srcNetwork : entry.settings.hiddenNetworks) { 1640 WifiNative.HiddenNetwork hiddenNetwork = new WifiNative.HiddenNetwork(); 1641 hiddenNetwork.ssid = srcNetwork.ssid; 1642 hiddenNetworkList.add(hiddenNetwork); 1643 } 1644 mergeVendorIes(vendorIesList, entry.settings); 1645 if ((entry.settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) 1646 != 0) { 1647 bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT; 1648 } 1649 1650 if (entry.clientInfo != null) { 1651 mWifiMetrics.getScanMetrics().setClientUid(entry.clientInfo.mUid); 1652 } 1653 mWifiMetrics.getScanMetrics().setWorkSource(entry.workSource); 1654 } 1655 1656 if (hiddenNetworkList.size() > 0) { 1657 settings.hiddenNetworks = new WifiNative.HiddenNetwork[hiddenNetworkList.size()]; 1658 int numHiddenNetworks = 0; 1659 for (WifiNative.HiddenNetwork hiddenNetwork : hiddenNetworkList) { 1660 settings.hiddenNetworks[numHiddenNetworks++] = hiddenNetwork; 1661 } 1662 } 1663 settings.vendorIes = getVendorIesBytesFromVendorIesList(vendorIesList); 1664 1665 channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE); 1666 settings.buckets = new WifiNative.BucketSettings[] {bucketSettings}; 1667 1668 if (mScannerImplsTracker.startSingleScan(settings)) { 1669 mWifiMetrics.getScanMetrics().logScanStarted( 1670 WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE); 1671 1672 // store the active scan settings 1673 mActiveScanSettings = settings; 1674 // swap pending and active scan requests 1675 RequestList<ScanSettings> tmp = mActiveScans; 1676 mActiveScans = mPendingScans; 1677 mPendingScans = tmp; 1678 // make sure that the pending list is clear 1679 mPendingScans.clear(); 1680 transitionTo(mScanningState); 1681 } else { 1682 mWifiMetrics.incrementScanReturnEntry( 1683 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size()); 1684 mWifiMetrics.getScanMetrics().logScanFailedToStart( 1685 WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE); 1686 1687 // notify and cancel failed scans 1688 sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED, 1689 "Failed to start single scan"); 1690 } 1691 } 1692 sendOpFailedToAllAndClear(RequestList<?> clientHandlers, int reason, String description)1693 void sendOpFailedToAllAndClear(RequestList<?> clientHandlers, int reason, 1694 String description) { 1695 for (RequestInfo<?> entry : clientHandlers) { 1696 logCallback("singleScanFailed", entry.clientInfo, 1697 "reason=" + reason + ", " + description); 1698 try { 1699 entry.clientInfo.mListener.onFailure(reason, description); 1700 } catch (Exception e) { 1701 loge("Failed to call onFailure: " + entry.clientInfo); 1702 } 1703 entry.clientInfo.unregister(); 1704 } 1705 clientHandlers.clear(); 1706 } 1707 reportFullScanSingleResult(@onNull ScanResult result, int bucketsScanned)1708 void reportFullScanSingleResult(@NonNull ScanResult result, int bucketsScanned) { 1709 for (RequestInfo<ScanSettings> entry : mActiveScans) { 1710 if (ScanScheduleUtil.shouldReportFullScanResultForSettings(mChannelHelper, 1711 result, bucketsScanned, entry.settings, -1)) { 1712 entry.clientInfo.reportEvent((listener) -> { 1713 try { 1714 listener.onFullResult(result); 1715 } catch (RemoteException e) { 1716 loge("Failed to call onFullResult: " + entry.clientInfo); 1717 } 1718 }); 1719 } 1720 } 1721 1722 for (RequestInfo<Void> entry : mSingleScanListeners) { 1723 entry.clientInfo.reportEvent((listener) -> { 1724 try { 1725 listener.onFullResult(result); 1726 } catch (RemoteException e) { 1727 loge("Failed to call onFullResult: " + entry.clientInfo); 1728 } 1729 }); 1730 } 1731 } 1732 reportFullScanAllResults(@onNull List<ScanResult> results, int bucketsScanned)1733 void reportFullScanAllResults(@NonNull List<ScanResult> results, int bucketsScanned) { 1734 List<ScanResult> matchedScanResults = new ArrayList<>(results.size()); 1735 for (RequestInfo<ScanSettings> entry : mActiveScans) { 1736 for (ScanResult result : results) { 1737 if (ScanScheduleUtil.shouldReportFullScanResultForSettings(mChannelHelper, 1738 result, bucketsScanned, entry.settings, -1)) { 1739 matchedScanResults.add(result); 1740 } 1741 } 1742 entry.clientInfo.reportEvent((listener) -> { 1743 try { 1744 listener.onFullResults( 1745 new ParceledListSlice<>(new ArrayList<>(matchedScanResults))); 1746 } catch (RemoteException e) { 1747 loge("Failed to call onFullResults: " + entry.clientInfo); 1748 } 1749 }); 1750 matchedScanResults.clear(); 1751 } 1752 1753 for (RequestInfo<Void> entry : mSingleScanListeners) { 1754 entry.clientInfo.reportEvent((listener) -> { 1755 try { 1756 listener.onFullResults(new ParceledListSlice<>(results)); 1757 } catch (RemoteException e) { 1758 loge("Failed to call onFullResults: " + entry.clientInfo); 1759 } 1760 }); 1761 } 1762 } 1763 reportScanResults(@onNull ScanData results)1764 void reportScanResults(@NonNull ScanData results) { 1765 if (results != null && results.getResults() != null) { 1766 if (results.getResults().length > 0) { 1767 mWifiMetrics.incrementNonEmptyScanResultCount(); 1768 } else { 1769 mWifiMetrics.incrementEmptyScanResultCount(); 1770 } 1771 } 1772 ScanData[] allResults = new ScanData[] {results}; 1773 for (RequestInfo<ScanSettings> entry : mActiveScans) { 1774 ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings( 1775 mChannelHelper, allResults, entry.settings, -1); 1776 logCallback("singleScanResults", entry.clientInfo, 1777 describeForLog(resultsToDeliver)); 1778 entry.clientInfo.reportEvent((listener) -> { 1779 try { 1780 listener.onResults(resultsToDeliver); 1781 // make sure the handler is removed 1782 listener.onSingleScanCompleted(); 1783 } catch (RemoteException e) { 1784 loge("Failed to call onResults: " + entry.clientInfo); 1785 } 1786 }); 1787 } 1788 1789 for (RequestInfo<Void> entry : mSingleScanListeners) { 1790 logCallback("singleScanResults listener", entry.clientInfo, 1791 describeForLog(allResults)); 1792 entry.clientInfo.reportEvent((listener) -> { 1793 try { 1794 listener.onResults(allResults); 1795 } catch (RemoteException e) { 1796 loge("Failed to call onResults: " + entry.clientInfo); 1797 } 1798 }); 1799 } 1800 } 1801 handleScanResults(@onNull ScanData results)1802 void handleScanResults(@NonNull ScanData results) { 1803 mWifiMetrics.getScanMetrics().logScanSucceeded( 1804 WifiMetrics.ScanMetrics.SCAN_TYPE_SINGLE, results.getResults().length); 1805 mWifiMetrics.incrementScanReturnEntry( 1806 WifiMetricsProto.WifiLog.SCAN_SUCCESS, mActiveScans.size()); 1807 reportScanResults(results); 1808 // Cache full band (with DFS or not) scan results. 1809 if (WifiScanner.isFullBandScan(results.getScannedBandsInternal(), true)) { 1810 mCachedScanResults.clear(); 1811 mCachedScanResults.addAll(Arrays.asList(results.getResults())); 1812 } 1813 if (mActiveScans.stream().anyMatch(rI -> rI.settings.ignoreLocationSettings)) { 1814 // We were processing an emergency scan, post an alarm to inform WifiManager the 1815 // end of that scan processing. If another scan is processed before the alarm fires, 1816 // this timer is restarted (AlarmManager.set() using the same listener resets the 1817 // timer). This delayed indication of emergency scan end prevents 1818 // quick wifi toggle on/off if there is a burst of emergency scans when wifi is off. 1819 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 1820 mClock.getElapsedSinceBootMillis() 1821 + EMERGENCY_SCAN_END_INDICATION_DELAY_MILLIS, 1822 EMERGENCY_SCAN_END_INDICATION_ALARM_TAG, 1823 mEmergencyScanEndIndicationListener, getHandler()); 1824 } 1825 for (RequestInfo<ScanSettings> entry : mActiveScans) { 1826 entry.clientInfo.unregister(); 1827 } 1828 mActiveScans.clear(); 1829 } 1830 getCachedScanResultsAsList()1831 List<ScanResult> getCachedScanResultsAsList() { 1832 return mCachedScanResults; 1833 } 1834 1835 /** 1836 * Filter out any scan results that are older than 1837 * {@link #CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS}. 1838 * 1839 * @return Filtered list of scan results. 1840 */ filterCachedScanResultsByAge()1841 public List<ScanResult> filterCachedScanResultsByAge() { 1842 // Using ScanResult.timestamp here to ensure that we use the same fields as 1843 // WificondScannerImpl for filtering stale results. 1844 long currentTimeInMillis = mClock.getElapsedSinceBootMillis(); 1845 return mCachedScanResults.stream() 1846 .filter(scanResult 1847 -> ((currentTimeInMillis - (scanResult.timestamp / 1000)) 1848 < CACHED_SCAN_RESULTS_MAX_AGE_IN_MILLIS)).collect(Collectors.toList()); 1849 } 1850 } 1851 1852 // TODO(b/71855918): Remove this bg scan state machine and its dependencies. 1853 // Note: bgscan will not support multiple scanner impls (will pick any). 1854 class WifiBackgroundScanStateMachine extends StateMachine { 1855 1856 private final DefaultState mDefaultState = new DefaultState(); 1857 private final StartedState mStartedState = new StartedState(); 1858 private final PausedState mPausedState = new PausedState(); 1859 1860 private final RequestList<ScanSettings> mActiveBackgroundScans = new RequestList<>(); 1861 1862 private WifiScannerImpl mScannerImpl; 1863 WifiBackgroundScanStateMachine(Looper looper)1864 WifiBackgroundScanStateMachine(Looper looper) { 1865 super("WifiBackgroundScanStateMachine", looper); 1866 1867 setLogRecSize(512); 1868 setLogOnlyTransitions(false); 1869 1870 // CHECKSTYLE:OFF IndentationCheck 1871 addState(mDefaultState); 1872 addState(mStartedState, mDefaultState); 1873 addState(mPausedState, mDefaultState); 1874 // CHECKSTYLE:ON IndentationCheck 1875 1876 setInitialState(mDefaultState); 1877 } 1878 getBackgroundScanSettings(ClientInfo ci)1879 public Collection<ScanSettings> getBackgroundScanSettings(ClientInfo ci) { 1880 return mActiveBackgroundScans.getAllSettingsForClient(ci); 1881 } 1882 removeBackgroundScanSettings(ClientInfo ci)1883 public void removeBackgroundScanSettings(ClientInfo ci) { 1884 mActiveBackgroundScans.removeAllForClient(ci); 1885 updateSchedule(); 1886 } 1887 1888 private final class ScanEventHandler implements WifiNative.ScanEventHandler { 1889 private final String mImplIfaceName; 1890 ScanEventHandler(@onNull String implIfaceName)1891 ScanEventHandler(@NonNull String implIfaceName) { 1892 mImplIfaceName = implIfaceName; 1893 } 1894 1895 @Override onScanStatus(int event)1896 public void onScanStatus(int event) { 1897 if (DBG) localLog("onScanStatus event received, event=" + event); 1898 switch (event) { 1899 case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE: 1900 case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS: 1901 case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT: 1902 sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 1903 break; 1904 case WifiNative.WIFI_SCAN_FAILED: 1905 sendMessage(CMD_SCAN_FAILED, WifiScanner.REASON_UNSPECIFIED); 1906 break; 1907 default: 1908 Log.e(TAG, "Unknown scan status event: " + event); 1909 break; 1910 } 1911 } 1912 1913 @Override onFullScanResult(ScanResult fullScanResult, int bucketsScanned)1914 public void onFullScanResult(ScanResult fullScanResult, int bucketsScanned) { 1915 if (DBG) localLog("onFullScanResult received"); 1916 sendMessage(CMD_FULL_SCAN_SINGLE_RESULT, 0, bucketsScanned, fullScanResult); 1917 } 1918 1919 @Override onScanPaused(ScanData[] scanData)1920 public void onScanPaused(ScanData[] scanData) { 1921 if (DBG) localLog("onScanPaused received"); 1922 sendMessage(CMD_SCAN_PAUSED, scanData); 1923 } 1924 1925 @Override onScanRestarted()1926 public void onScanRestarted() { 1927 if (DBG) localLog("onScanRestarted received"); 1928 sendMessage(CMD_SCAN_RESTARTED); 1929 } 1930 1931 /** 1932 * Called to indicate a scan failure 1933 */ 1934 @Override onScanRequestFailed(int errorCode)1935 public void onScanRequestFailed(int errorCode) { 1936 sendMessage(CMD_SCAN_FAILED, errorCode); 1937 } 1938 1939 @Override onFullScanResults(List<ScanResult> fullScanResults, int bucketsScanned)1940 public void onFullScanResults(List<ScanResult> fullScanResults, int bucketsScanned) { 1941 if (DBG) localLog("onFullScanResult received"); 1942 if (fullScanResults == null || fullScanResults.isEmpty()) { 1943 return; 1944 } 1945 sendMessage(CMD_FULL_SCAN_ALL_RESULTS, 0, bucketsScanned, fullScanResults); 1946 1947 } 1948 } 1949 1950 class DefaultState extends State { 1951 @Override enter()1952 public void enter() { 1953 if (DBG) localLog("DefaultState"); 1954 mActiveBackgroundScans.clear(); 1955 } 1956 1957 @Override processMessage(Message msg)1958 public boolean processMessage(Message msg) { 1959 switch (msg.what) { 1960 case WifiScanner.CMD_ENABLE: 1961 if (mScannerImpls.isEmpty()) { 1962 loge("Failed to start bgscan scan state machine because scanner impl" 1963 + " is null"); 1964 return HANDLED; 1965 } 1966 // Pick any impl available and stick to it until disable. 1967 mScannerImpl = mScannerImpls.entrySet().iterator().next().getValue(); 1968 mChannelHelper = mScannerImpl.getChannelHelper(); 1969 1970 mBackgroundScheduler = new BackgroundScanScheduler(mChannelHelper); 1971 1972 WifiNative.ScanCapabilities capabilities = 1973 new WifiNative.ScanCapabilities(); 1974 if (!mScannerImpl.getScanCapabilities(capabilities)) { 1975 loge("could not get scan capabilities"); 1976 return HANDLED; 1977 } 1978 if (capabilities.max_scan_buckets <= 0) { 1979 loge("invalid max buckets in scan capabilities " 1980 + capabilities.max_scan_buckets); 1981 return HANDLED; 1982 } 1983 mBackgroundScheduler.setMaxBuckets(capabilities.max_scan_buckets); 1984 mBackgroundScheduler.setMaxApPerScan(capabilities.max_ap_cache_per_scan); 1985 1986 Log.i(TAG, "wifi driver loaded with scan capabilities: " 1987 + "max buckets=" + capabilities.max_scan_buckets); 1988 1989 transitionTo(mStartedState); 1990 return HANDLED; 1991 case WifiScanner.CMD_DISABLE: 1992 Log.i(TAG, "wifi driver unloaded"); 1993 transitionTo(mDefaultState); 1994 break; 1995 case WifiScanner.CMD_START_BACKGROUND_SCAN: 1996 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 1997 case WifiScanner.CMD_START_SINGLE_SCAN: 1998 case WifiScanner.CMD_STOP_SINGLE_SCAN: 1999 case WifiScanner.CMD_GET_SCAN_RESULTS: 2000 ScanParams scanParams = (ScanParams) msg.obj; 2001 ClientInfo ci = mClients.get(scanParams.listener); 2002 if (ci == null) { 2003 loge("ClientInfo is null"); 2004 break; 2005 } 2006 ci.replyFailed(WifiScanner.REASON_UNSPECIFIED, "not available"); 2007 break; 2008 2009 case CMD_SCAN_RESULTS_AVAILABLE: 2010 if (DBG) localLog("ignored scan results available event"); 2011 break; 2012 case CMD_FULL_SCAN_SINGLE_RESULT: 2013 case CMD_FULL_SCAN_ALL_RESULTS: 2014 if (DBG) localLog("ignored full scan result event"); 2015 break; 2016 2017 default: 2018 break; 2019 } 2020 2021 return HANDLED; 2022 } 2023 } 2024 2025 class StartedState extends State { 2026 2027 @Override enter()2028 public void enter() { 2029 if (DBG) localLog("StartedState"); 2030 if (mScannerImpl == null) { 2031 // should never happen 2032 Log.wtf(TAG, "Scanner impl unexpectedly null"); 2033 transitionTo(mDefaultState); 2034 } 2035 } 2036 2037 @Override exit()2038 public void exit() { 2039 sendBackgroundScanFailedToAllAndClear( 2040 WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted"); 2041 mScannerImpl = null; // reset impl 2042 } 2043 2044 @Override processMessage(Message msg)2045 public boolean processMessage(Message msg) { 2046 switch (msg.what) { 2047 case WifiScanner.CMD_ENABLE: 2048 Log.e(TAG, "wifi driver loaded received while already loaded"); 2049 // Ignore if we're already in driver loaded state. 2050 return HANDLED; 2051 case WifiScanner.CMD_DISABLE: 2052 return NOT_HANDLED; 2053 case WifiScanner.CMD_START_BACKGROUND_SCAN: { 2054 ScanParams scanParams = (ScanParams) msg.obj; 2055 mWifiMetrics.incrementBackgroundScanCount(); 2056 ClientInfo ci = mClients.get(scanParams.listener); 2057 if (ci == null) { 2058 loge("ClientInfo is null"); 2059 return HANDLED; 2060 } 2061 if (scanParams.settings == null) { 2062 loge("params null"); 2063 return HANDLED; 2064 } 2065 if (addBackgroundScanRequest(ci, msg.arg2, scanParams.settings, 2066 scanParams.workSource)) { 2067 ci.replySucceeded(); 2068 } else { 2069 ci.replyFailed(WifiScanner.REASON_INVALID_REQUEST, "bad request"); 2070 } 2071 break; 2072 } 2073 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 2074 ScanParams scanParams = (ScanParams) msg.obj; 2075 ClientInfo ci = mClients.get(scanParams.listener); 2076 removeBackgroundScanRequest(ci); 2077 break; 2078 case WifiScanner.CMD_GET_SCAN_RESULTS: 2079 reportScanResults(mScannerImpl.getLatestBatchedScanResults(true)); 2080 break; 2081 case CMD_SCAN_RESULTS_AVAILABLE: 2082 WifiScanner.ScanData[] results = mScannerImpl.getLatestBatchedScanResults( 2083 true); 2084 mWifiMetrics.getScanMetrics().logScanSucceeded( 2085 WifiMetrics.ScanMetrics.SCAN_TYPE_BACKGROUND, 2086 results != null ? results.length : 0); 2087 reportScanResults(results); 2088 break; 2089 case CMD_FULL_SCAN_SINGLE_RESULT: 2090 reportFullScanSingleResult((ScanResult) msg.obj, 2091 /* bucketsScanned */ msg.arg2); 2092 break; 2093 case CMD_FULL_SCAN_ALL_RESULTS: 2094 reportFullScanAllResults((List<ScanResult>) msg.obj, 2095 /* bucketsScanned */ msg.arg2); 2096 break; 2097 case CMD_SCAN_PAUSED: 2098 reportScanResults((ScanData[]) msg.obj); 2099 transitionTo(mPausedState); 2100 break; 2101 case CMD_SCAN_FAILED: 2102 mWifiMetrics.getScanMetrics().logScanFailed( 2103 WifiMetrics.ScanMetrics.SCAN_TYPE_BACKGROUND); 2104 Log.e(TAG, "WifiScanner background scan gave CMD_SCAN_FAILED"); 2105 sendBackgroundScanFailedToAllAndClear( 2106 WifiScanner.REASON_UNSPECIFIED, "Background Scan failed"); 2107 break; 2108 default: 2109 return NOT_HANDLED; 2110 } 2111 2112 return HANDLED; 2113 } 2114 } 2115 2116 class PausedState extends State { 2117 @Override enter()2118 public void enter() { 2119 if (DBG) localLog("PausedState"); 2120 } 2121 2122 @Override processMessage(Message msg)2123 public boolean processMessage(Message msg) { 2124 switch (msg.what) { 2125 case CMD_SCAN_RESTARTED: 2126 transitionTo(mStartedState); 2127 break; 2128 default: 2129 deferMessage(msg); 2130 break; 2131 } 2132 return HANDLED; 2133 } 2134 } 2135 addBackgroundScanRequest(ClientInfo ci, int handler, ScanSettings settings, WorkSource workSource)2136 private boolean addBackgroundScanRequest(ClientInfo ci, int handler, 2137 ScanSettings settings, WorkSource workSource) { 2138 if (ci == null) { 2139 Log.d(TAG, "Failing scan request ClientInfo not found " + handler); 2140 return false; 2141 } 2142 2143 if (settings.periodInMs < WifiScanner.MIN_SCAN_PERIOD_MS) { 2144 loge("Failing scan request because periodInMs is " + settings.periodInMs 2145 + ", min scan period is: " + WifiScanner.MIN_SCAN_PERIOD_MS); 2146 return false; 2147 } 2148 2149 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED && settings.channels == null) { 2150 loge("Channels was null with unspecified band"); 2151 return false; 2152 } 2153 2154 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED 2155 && settings.channels.length == 0) { 2156 loge("No channels specified"); 2157 return false; 2158 } 2159 2160 int minSupportedPeriodMs = mChannelHelper.estimateScanDuration(settings); 2161 if (settings.periodInMs < minSupportedPeriodMs) { 2162 loge("Failing scan request because minSupportedPeriodMs is " 2163 + minSupportedPeriodMs + " but the request wants " + settings.periodInMs); 2164 return false; 2165 } 2166 2167 // check truncated binary exponential back off scan settings 2168 if (settings.maxPeriodInMs != 0 && settings.maxPeriodInMs != settings.periodInMs) { 2169 if (settings.maxPeriodInMs < settings.periodInMs) { 2170 loge("Failing scan request because maxPeriodInMs is " + settings.maxPeriodInMs 2171 + " but less than periodInMs " + settings.periodInMs); 2172 return false; 2173 } 2174 if (settings.maxPeriodInMs > WifiScanner.MAX_SCAN_PERIOD_MS) { 2175 loge("Failing scan request because maxSupportedPeriodMs is " 2176 + WifiScanner.MAX_SCAN_PERIOD_MS + " but the request wants " 2177 + settings.maxPeriodInMs); 2178 return false; 2179 } 2180 if (settings.stepCount < 1) { 2181 loge("Failing scan request because stepCount is " + settings.stepCount 2182 + " which is less than 1"); 2183 return false; 2184 } 2185 } 2186 2187 logScanRequest("addBackgroundScanRequest", ci, null, settings, null); 2188 mWifiMetrics.getScanMetrics().setClientUid(ci.mUid); 2189 mWifiMetrics.getScanMetrics().setWorkSource(workSource); 2190 mActiveBackgroundScans.addRequest(ci, workSource, settings); 2191 2192 if (updateSchedule()) { 2193 return true; 2194 } else { 2195 mActiveBackgroundScans.removeRequest(ci); 2196 localLog("Failing scan request because failed to reset scan"); 2197 return false; 2198 } 2199 } 2200 updateSchedule()2201 private boolean updateSchedule() { 2202 if (mChannelHelper == null || mBackgroundScheduler == null || mScannerImpl == null) { 2203 loge("Failed to update schedule because WifiScanningService is not initialized"); 2204 return false; 2205 } 2206 mChannelHelper.updateChannels(); 2207 Collection<ScanSettings> settings = mActiveBackgroundScans.getAllSettings(); 2208 2209 mBackgroundScheduler.updateSchedule(settings); 2210 WifiNative.ScanSettings schedule = mBackgroundScheduler.getSchedule(); 2211 2212 if (ScanScheduleUtil.scheduleEquals(mPreviousSchedule, schedule)) { 2213 if (DBG) Log.d(TAG, "schedule updated with no change"); 2214 return true; 2215 } 2216 2217 mPreviousSchedule = schedule; 2218 2219 if (schedule.num_buckets == 0) { 2220 mScannerImpl.stopBatchedScan(); 2221 if (DBG) Log.d(TAG, "scan stopped"); 2222 return true; 2223 } else { 2224 localLog("starting scan: " 2225 + "base period=" + schedule.base_period_ms 2226 + ", max ap per scan=" + schedule.max_ap_per_scan 2227 + ", batched scans=" + schedule.report_threshold_num_scans); 2228 for (int b = 0; b < schedule.num_buckets; b++) { 2229 WifiNative.BucketSettings bucket = schedule.buckets[b]; 2230 localLog("bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)" 2231 + "[" + bucket.report_events + "]: " 2232 + ChannelHelper.toString(bucket)); 2233 } 2234 2235 if (mScannerImpl.startBatchedScan(schedule, 2236 new ScanEventHandler(mScannerImpl.getIfaceName()))) { 2237 if (DBG) { 2238 Log.d(TAG, "scan restarted with " + schedule.num_buckets 2239 + " bucket(s) and base period: " + schedule.base_period_ms); 2240 } 2241 mWifiMetrics.getScanMetrics().logScanStarted( 2242 WifiMetrics.ScanMetrics.SCAN_TYPE_BACKGROUND); 2243 return true; 2244 } else { 2245 mPreviousSchedule = null; 2246 loge("error starting scan: " 2247 + "base period=" + schedule.base_period_ms 2248 + ", max ap per scan=" + schedule.max_ap_per_scan 2249 + ", batched scans=" + schedule.report_threshold_num_scans); 2250 for (int b = 0; b < schedule.num_buckets; b++) { 2251 WifiNative.BucketSettings bucket = schedule.buckets[b]; 2252 loge("bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)" 2253 + "[" + bucket.report_events + "]: " 2254 + ChannelHelper.toString(bucket)); 2255 } 2256 mWifiMetrics.getScanMetrics().logScanFailedToStart( 2257 WifiMetrics.ScanMetrics.SCAN_TYPE_BACKGROUND); 2258 return false; 2259 } 2260 } 2261 } 2262 removeBackgroundScanRequest(ClientInfo ci)2263 private void removeBackgroundScanRequest(ClientInfo ci) { 2264 if (ci != null) { 2265 ScanSettings settings = mActiveBackgroundScans.removeRequest(ci); 2266 logScanRequest("removeBackgroundScanRequest", ci, null, settings, null); 2267 updateSchedule(); 2268 } 2269 } 2270 reportFullScanSingleResult(ScanResult result, int bucketsScanned)2271 private void reportFullScanSingleResult(ScanResult result, int bucketsScanned) { 2272 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 2273 ClientInfo ci = entry.clientInfo; 2274 ScanSettings settings = entry.settings; 2275 if (mBackgroundScheduler.shouldReportFullScanResultForSettings( 2276 result, bucketsScanned, settings)) { 2277 ScanResult newResult = new ScanResult(result); 2278 if (result.informationElements != null) { 2279 newResult.informationElements = result.informationElements.clone(); 2280 } 2281 else { 2282 newResult.informationElements = null; 2283 } 2284 entry.clientInfo.reportEvent((listener) -> { 2285 try { 2286 listener.onFullResult(newResult); 2287 } catch (RemoteException e) { 2288 loge("Failed to call onFullResult: " + ci); 2289 } 2290 }); 2291 } 2292 } 2293 } 2294 reportFullScanAllResults(List<ScanResult> results, int bucketsScanned)2295 private void reportFullScanAllResults(List<ScanResult> results, int bucketsScanned) { 2296 List<ScanResult> copyResults = new ArrayList<>(results.size()); 2297 for (ScanResult result : results) { 2298 ScanResult newResult = new ScanResult(result); 2299 if (result.informationElements != null) { 2300 newResult.informationElements = result.informationElements.clone(); 2301 } else { 2302 newResult.informationElements = null; 2303 } 2304 copyResults.add(newResult); 2305 } 2306 List<ScanResult> matchedResults = new ArrayList<>(copyResults.size()); 2307 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 2308 ClientInfo ci = entry.clientInfo; 2309 ScanSettings settings = entry.settings; 2310 2311 for (ScanResult result : results) { 2312 if (mBackgroundScheduler.shouldReportFullScanResultForSettings( 2313 result, bucketsScanned, settings)) { 2314 2315 matchedResults.add(result); 2316 } 2317 entry.clientInfo.reportEvent((listener) -> { 2318 try { 2319 listener.onFullResults( 2320 new ParceledListSlice<>(new ArrayList<>(matchedResults))); 2321 } catch (RemoteException e) { 2322 loge("Failed to call onFullResults: " + ci); 2323 } 2324 }); 2325 } 2326 matchedResults.clear(); 2327 } 2328 } 2329 reportScanResults(ScanData[] results)2330 private void reportScanResults(ScanData[] results) { 2331 if (results == null) { 2332 Log.d(TAG,"The results is null, nothing to report."); 2333 return; 2334 } 2335 for (ScanData result : results) { 2336 if (result != null && result.getResults() != null) { 2337 if (result.getResults().length > 0) { 2338 mWifiMetrics.incrementNonEmptyScanResultCount(); 2339 } else { 2340 mWifiMetrics.incrementEmptyScanResultCount(); 2341 } 2342 } 2343 } 2344 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 2345 ClientInfo ci = entry.clientInfo; 2346 ScanSettings settings = entry.settings; 2347 ScanData[] resultsToDeliver = 2348 mBackgroundScheduler.filterResultsForSettings(results, settings); 2349 if (resultsToDeliver != null) { 2350 logCallback("backgroundScanResults", ci, 2351 describeForLog(resultsToDeliver)); 2352 entry.clientInfo.reportEvent((listener) -> { 2353 try { 2354 listener.onResults(resultsToDeliver); 2355 } catch (RemoteException e) { 2356 loge("Failed to call onResults: " + ci); 2357 } 2358 }); 2359 } 2360 } 2361 } 2362 sendBackgroundScanFailedToAllAndClear(int reason, String description)2363 private void sendBackgroundScanFailedToAllAndClear(int reason, String description) { 2364 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 2365 ClientInfo ci = entry.clientInfo; 2366 entry.clientInfo.reportEvent((listener) -> { 2367 try { 2368 listener.onFailure(reason, description); 2369 } catch (RemoteException e) { 2370 loge("Failed to call onFailure: " + ci); 2371 } 2372 }); 2373 } 2374 mActiveBackgroundScans.clear(); 2375 } 2376 } 2377 2378 /** 2379 * PNO scan state machine has 5 states: 2380 * -Default State 2381 * -Started State 2382 * -Hw Pno Scan state 2383 * -Single Scan state 2384 * 2385 * These are the main state transitions: 2386 * 1. Start at |Default State| 2387 * 2. Move to |Started State| when we get the |WIFI_SCAN_AVAILABLE| broadcast from WifiManager. 2388 * 3. When a new PNO scan request comes in: 2389 * a.1. Switch to |Hw Pno Scan state| when the device supports HW PNO 2390 * (This could either be HAL based ePNO or wificond based PNO). 2391 * a.2. In |Hw Pno Scan state| when PNO scan results are received, check if the result 2392 * contains IE (information elements). If yes, send the results to the client, else 2393 * switch to |Single Scan state| and send the result to the client when the scan result 2394 * is obtained. 2395 * 2396 * Note: PNO scans only work for a single client today. We don't have support in HW to support 2397 * multiple requests at the same time, so will need non-trivial changes to support (if at all 2398 * possible) in WifiScanningService. 2399 */ 2400 class WifiPnoScanStateMachine extends StateMachine { 2401 2402 private final DefaultState mDefaultState = new DefaultState(); 2403 private final StartedState mStartedState = new StartedState(); 2404 private final HwPnoScanState mHwPnoScanState = new HwPnoScanState(); 2405 private final SwPnoScanState mSwPnoScanState = new SwPnoScanState(); 2406 private final SingleScanState mSingleScanState = new SingleScanState(); 2407 private InternalClientInfo mInternalClientInfo; 2408 2409 private final RequestList<Pair<PnoSettings, ScanSettings>> mActivePnoScans = 2410 new RequestList<>(); 2411 // Tracks scan requests across multiple scanner impls. 2412 private final ScannerImplsTracker mScannerImplsTracker; 2413 WifiPnoScanStateMachine(Looper looper)2414 WifiPnoScanStateMachine(Looper looper) { 2415 super("WifiPnoScanStateMachine", looper); 2416 2417 mScannerImplsTracker = new ScannerImplsTracker(); 2418 2419 setLogRecSize(256); 2420 setLogOnlyTransitions(false); 2421 2422 // CHECKSTYLE:OFF IndentationCheck 2423 addState(mDefaultState); 2424 addState(mStartedState, mDefaultState); 2425 addState(mHwPnoScanState, mStartedState); 2426 addState(mSingleScanState, mHwPnoScanState); 2427 addState(mSwPnoScanState, mStartedState); 2428 // CHECKSTYLE:ON IndentationCheck 2429 2430 setInitialState(mDefaultState); 2431 } 2432 2433 /** 2434 * @return the string for msg.what 2435 */ 2436 @Override getWhatToString(int what)2437 protected String getWhatToString(int what) { 2438 return getWhatToStringInternal(what); 2439 } 2440 2441 /** 2442 * Return the additional string to be logged by LogRec, default 2443 * 2444 * @param msg that was processed 2445 * @return information to be logged as a String 2446 */ 2447 @Override getLogRecString(Message msg)2448 protected String getLogRecString(Message msg) { 2449 StringBuilder sb = new StringBuilder(); 2450 sb.append(" "); 2451 sb.append(Integer.toString(msg.arg1)); 2452 sb.append(" "); 2453 sb.append(Integer.toString(msg.arg2)); 2454 return sb.toString(); 2455 } 2456 removePnoSettings(ClientInfo ci)2457 public void removePnoSettings(ClientInfo ci) { 2458 mActivePnoScans.removeAllForClient(ci); 2459 } 2460 2461 /** 2462 * Tracks a PNO scan request across all the available scanner impls. 2463 * 2464 * Note: If there are failures on some of the scanner impls, we ignore them since we can 2465 * get a PNO match from the other successful impls. We don't declare total scan 2466 * failures, unless all the scanner impls fail. 2467 */ 2468 private final class ScannerImplsTracker { 2469 private final class PnoEventHandler implements WifiNative.PnoEventHandler { 2470 private final String mImplIfaceName; 2471 PnoEventHandler(@onNull String implIfaceName)2472 PnoEventHandler(@NonNull String implIfaceName) { 2473 mImplIfaceName = implIfaceName; 2474 } 2475 2476 @Override onPnoNetworkFound(ScanResult[] results)2477 public void onPnoNetworkFound(ScanResult[] results) { 2478 if (DBG) localLog("onWifiPnoNetworkFound event received"); 2479 reportPnoNetworkFoundForImpl(mImplIfaceName, results); 2480 } 2481 2482 @Override onPnoScanFailed()2483 public void onPnoScanFailed() { 2484 if (DBG) localLog("onWifiPnoScanFailed event received"); 2485 reportPnoScanFailedForImpl(mImplIfaceName); 2486 } 2487 } 2488 2489 private static final int STATUS_PENDING = 0; 2490 private static final int STATUS_FAILED = 2; 2491 2492 // Tracks scan status per impl. 2493 Map<String, Integer> mStatusPerImpl = new ArrayMap<>(); 2494 2495 /** 2496 * Triggers a new PNO with the specified settings on all the available scanner impls. 2497 * @return true if the PNO succeeded on any of the impl, false otherwise. 2498 */ setHwPnoList(WifiNative.PnoSettings pnoSettings)2499 public boolean setHwPnoList(WifiNative.PnoSettings pnoSettings) { 2500 mStatusPerImpl.clear(); 2501 boolean anySuccess = false; 2502 for (Map.Entry<String, WifiScannerImpl> entry : mScannerImpls.entrySet()) { 2503 String ifaceName = entry.getKey(); 2504 WifiScannerImpl impl = entry.getValue(); 2505 boolean success = impl.setHwPnoList( 2506 pnoSettings, new PnoEventHandler(ifaceName)); 2507 if (!success) { 2508 Log.e(TAG, "Failed to start pno on " + ifaceName); 2509 continue; 2510 } 2511 mStatusPerImpl.put(ifaceName, STATUS_PENDING); 2512 anySuccess = true; 2513 } 2514 return anySuccess; 2515 } 2516 2517 /** 2518 * Resets any ongoing PNO on all the available scanner impls. 2519 * @return true if the PNO stop succeeded on all of the impl, false otherwise. 2520 */ resetHwPnoList()2521 public boolean resetHwPnoList() { 2522 boolean allSuccess = true; 2523 for (String ifaceName : mStatusPerImpl.keySet()) { 2524 WifiScannerImpl impl = mScannerImpls.get(ifaceName); 2525 if (impl == null) continue; 2526 boolean success = impl.resetHwPnoList(); 2527 if (!success) { 2528 Log.e(TAG, "Failed to stop pno on " + ifaceName); 2529 allSuccess = false; 2530 } 2531 } 2532 mStatusPerImpl.clear(); 2533 return allSuccess; 2534 } 2535 2536 /** 2537 * @return true if HW PNO is supported on all the available scanner impls, 2538 * false otherwise. 2539 */ isHwPnoSupported(boolean isConnected)2540 public boolean isHwPnoSupported(boolean isConnected) { 2541 for (WifiScannerImpl impl : mScannerImpls.values()) { 2542 if (!impl.isHwPnoSupported(isConnected)) { 2543 return false; 2544 } 2545 } 2546 return true; 2547 } 2548 reportPnoNetworkFoundForImpl(@onNull String implIfaceName, ScanResult[] results)2549 private void reportPnoNetworkFoundForImpl(@NonNull String implIfaceName, 2550 ScanResult[] results) { 2551 Integer status = mStatusPerImpl.get(implIfaceName); 2552 if (status != null && status == STATUS_PENDING) { 2553 sendMessage(CMD_PNO_NETWORK_FOUND, 0, 0, results); 2554 } 2555 } 2556 getConsolidatedStatus()2557 private int getConsolidatedStatus() { 2558 boolean anyPending = mStatusPerImpl.values().stream() 2559 .anyMatch(status -> status == STATUS_PENDING); 2560 // at-least one impl status is still pending. 2561 if (anyPending) { 2562 return STATUS_PENDING; 2563 } else { 2564 // all failed. 2565 return STATUS_FAILED; 2566 } 2567 } 2568 reportPnoScanFailedForImpl(@onNull String implIfaceName)2569 private void reportPnoScanFailedForImpl(@NonNull String implIfaceName) { 2570 Integer currentStatus = mStatusPerImpl.get(implIfaceName); 2571 if (currentStatus != null && currentStatus == STATUS_PENDING) { 2572 mStatusPerImpl.put(implIfaceName, STATUS_FAILED); 2573 } 2574 // Now check if all the scanner impls scan status is available. 2575 int consolidatedStatus = getConsolidatedStatus(); 2576 if (consolidatedStatus == STATUS_FAILED) { 2577 sendMessage(CMD_PNO_SCAN_FAILED); 2578 } 2579 } 2580 } 2581 2582 class DefaultState extends State { 2583 @Override enter()2584 public void enter() { 2585 if (DBG) localLog("DefaultState"); 2586 } 2587 2588 @Override processMessage(Message msg)2589 public boolean processMessage(Message msg) { 2590 switch (msg.what) { 2591 case WifiScanner.CMD_ENABLE: 2592 if (mScannerImpls.isEmpty()) { 2593 loge("Failed to start pno scan state machine because scanner impl" 2594 + " is null"); 2595 return HANDLED; 2596 } 2597 transitionTo(mStartedState); 2598 break; 2599 case WifiScanner.CMD_DISABLE: 2600 transitionTo(mDefaultState); 2601 break; 2602 case WifiScanner.CMD_START_PNO_SCAN: { 2603 ScanParams scanParams = (ScanParams) msg.obj; 2604 try { 2605 scanParams.listener.onFailure(WifiScanner.REASON_UNSPECIFIED, 2606 "not available"); 2607 } catch (RemoteException e) { 2608 // not much we can do if message can't be sent. 2609 } 2610 break; 2611 } 2612 case WifiScanner.CMD_STOP_PNO_SCAN: { 2613 ScanParams scanParams = (ScanParams) msg.obj; 2614 ClientInfo ci = mClients.get(scanParams.listener); 2615 if (ci == null) { 2616 localLog("Pno ClientInfo is null in DefaultState"); 2617 break; 2618 } 2619 ci.replyFailed(WifiScanner.REASON_UNSPECIFIED, "not available"); 2620 break; 2621 } 2622 case CMD_PNO_NETWORK_FOUND: 2623 case CMD_PNO_SCAN_FAILED: 2624 case WifiScanner.CMD_SCAN_RESULT: 2625 case WifiScanner.CMD_OP_FAILED: 2626 loge("Unexpected message " + msg.what); 2627 break; 2628 default: 2629 return NOT_HANDLED; 2630 } 2631 return HANDLED; 2632 } 2633 } 2634 2635 class StartedState extends State { 2636 @Override enter()2637 public void enter() { 2638 if (DBG) localLog("StartedState"); 2639 } 2640 2641 @Override exit()2642 public void exit() { 2643 sendPnoScanFailedToAllAndClear( 2644 WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted"); 2645 } 2646 2647 @Override processMessage(Message msg)2648 public boolean processMessage(Message msg) { 2649 switch (msg.what) { 2650 case WifiScanner.CMD_ENABLE: 2651 // Ignore if we're already in driver loaded state. 2652 return HANDLED; 2653 case WifiScanner.CMD_START_PNO_SCAN: 2654 ScanParams scanParams = (ScanParams) msg.obj; 2655 if (scanParams == null) { 2656 loge("scan params null"); 2657 return HANDLED; 2658 } 2659 ClientInfo ci = mClients.get(scanParams.listener); 2660 if (ci == null) { 2661 ci = new ExternalClientInfo(msg.sendingUid, scanParams.packageName, 2662 scanParams.listener, scanParams.featureId); 2663 ci.register(); 2664 } 2665 if (scanParams.pnoSettings == null || scanParams.settings == null) { 2666 Log.e(TAG, "Failed to get parcelable params"); 2667 ci.replyFailed(WifiScanner.REASON_INVALID_REQUEST, "bad parcel params"); 2668 return HANDLED; 2669 } 2670 if (mScannerImplsTracker.isHwPnoSupported( 2671 scanParams.pnoSettings.isConnected)) { 2672 deferMessage(msg); 2673 transitionTo(mHwPnoScanState); 2674 } else if (mWifiGlobals.isSwPnoEnabled() 2675 && mDeviceConfigFacade.isSoftwarePnoEnabled()) { 2676 deferMessage(msg); 2677 transitionTo(mSwPnoScanState); 2678 } else { 2679 Log.w(TAG, "PNO is not available"); 2680 ci.replyFailed(WifiScanner.REASON_INVALID_REQUEST, "not supported"); 2681 } 2682 break; 2683 case WifiScanner.CMD_STOP_PNO_SCAN: 2684 scanParams = (ScanParams) msg.obj; 2685 ci = mClients.get(scanParams.listener); 2686 if (ci != null) { 2687 ci.cleanup(); 2688 } 2689 break; 2690 default: 2691 return NOT_HANDLED; 2692 } 2693 return HANDLED; 2694 } 2695 } 2696 2697 class HwPnoScanState extends State { 2698 @Override enter()2699 public void enter() { 2700 if (DBG) localLog("HwPnoScanState"); 2701 } 2702 2703 @Override exit()2704 public void exit() { 2705 // Reset PNO scan in ScannerImpl before we exit. 2706 mScannerImplsTracker.resetHwPnoList(); 2707 removeInternalClient(); 2708 } 2709 2710 @Override processMessage(Message msg)2711 public boolean processMessage(Message msg) { 2712 switch (msg.what) { 2713 case WifiScanner.CMD_START_PNO_SCAN: 2714 ScanParams scanParams = (ScanParams) msg.obj; 2715 if (scanParams == null) { 2716 loge("params null"); 2717 return HANDLED; 2718 } 2719 ClientInfo ci = mClients.get(scanParams.listener); 2720 if (ci == null) { 2721 ci = new ExternalClientInfo(msg.sendingUid, scanParams.packageName, 2722 scanParams.listener, scanParams.featureId); 2723 ci.register(); 2724 } 2725 if (scanParams.pnoSettings == null || scanParams.settings == null) { 2726 Log.e(TAG, "Failed to get parcelable params"); 2727 ci.replyFailed(WifiScanner.REASON_INVALID_REQUEST, "bad parcel params"); 2728 return HANDLED; 2729 } 2730 2731 if (addHwPnoScanRequest(ci, scanParams.settings, 2732 scanParams.pnoSettings)) { 2733 mWifiMetrics.getScanMetrics().logPnoScanEvent( 2734 WifiMetrics.ScanMetrics.PNO_SCAN_STATE_STARTED); 2735 ci.replySucceeded(); 2736 } else { 2737 mWifiMetrics.getScanMetrics().logPnoScanEvent( 2738 WifiMetrics.ScanMetrics.PNO_SCAN_STATE_FAILED_TO_START); 2739 ci.replyFailed(WifiScanner.REASON_INVALID_REQUEST, "bad request"); 2740 ci.cleanup(); 2741 transitionTo(mStartedState); 2742 } 2743 break; 2744 case WifiScanner.CMD_STOP_PNO_SCAN: 2745 scanParams = (ScanParams) msg.obj; 2746 ci = mClients.get(scanParams.listener); 2747 removeHwPnoScanRequest(ci); 2748 transitionTo(mStartedState); 2749 break; 2750 case CMD_PNO_NETWORK_FOUND: 2751 ScanResult[] scanResults = ((ScanResult[]) msg.obj); 2752 mWifiMetrics.getScanMetrics().logPnoScanEvent( 2753 WifiMetrics.ScanMetrics.PNO_SCAN_STATE_COMPLETED_NETWORK_FOUND); 2754 2755 if (isSingleScanNeeded(scanResults)) { 2756 ScanSettings activeScanSettings = getScanSettings(); 2757 if (activeScanSettings == null) { 2758 sendPnoScanFailedToAllAndClear( 2759 WifiScanner.REASON_UNSPECIFIED, 2760 "couldn't retrieve setting"); 2761 transitionTo(mStartedState); 2762 } else { 2763 addSingleScanRequest(activeScanSettings); 2764 transitionTo(mSingleScanState); 2765 } 2766 } else { 2767 reportPnoNetworkFound((ScanResult[]) msg.obj); 2768 } 2769 break; 2770 case CMD_PNO_SCAN_FAILED: 2771 mWifiMetrics.getScanMetrics().logPnoScanEvent( 2772 WifiMetrics.ScanMetrics.PNO_SCAN_STATE_FAILED); 2773 sendPnoScanFailedToAllAndClear( 2774 WifiScanner.REASON_UNSPECIFIED, "pno scan failed"); 2775 transitionTo(mStartedState); 2776 break; 2777 default: 2778 return NOT_HANDLED; 2779 } 2780 return HANDLED; 2781 } 2782 } 2783 2784 class SwPnoScanState extends State { 2785 private final AlarmManager mSwPnoAlarmManager; 2786 private final SwPnoAlarmReceiver mSwPnoAlarmReceiver = new SwPnoAlarmReceiver(); 2787 @VisibleForTesting 2788 public static final String SW_PNO_ALARM_INTENT_ACTION = 2789 "com.android.server.wifi.scanner.WifiPnoScanStateMachine.SwPnoScanState" 2790 + ".SW_PNO_ALARM"; 2791 PendingIntent mPendingIntentSwPno; 2792 private final int mSwPnoTimerMarginMs; 2793 @VisibleForTesting 2794 public static final String SW_PNO_UPPER_BOUND_ALARM_INTENT_ACTION = 2795 "com.android.server.wifi.scanner.WifiPnoScanStateMachine.SwPnoScanState" 2796 + ".SW_PNO_UPPERBOUND_ALARM"; 2797 PendingIntent mPendingIntentSwPnoUpperBound; 2798 private SwPnoScheduler mSwPnoScheduler = null; 2799 private ScanParams mScanParams = null; 2800 private ClientInfo mClientInfo = null; 2801 2802 2803 private final class SwPnoScheduler { 2804 2805 private final class SwPnoScheduleInfo { 2806 /** 2807 * The timer is initially scheduled with an interval equal to mTimerBaseMs. 2808 * If mBackoff is true, at each iteration the interval will increase 2809 * proportionally to the elapsed iterations. 2810 * The schedule is repeated up to mMaxIterations iterations. 2811 */ 2812 private final int mMaxIterations; 2813 private final int mTimerBaseMs; 2814 private final boolean mBackoff; 2815 /** 2816 * Whether the alarm should be exact or not. 2817 * Inexact alarms are delivered when the system thinks it is most efficient. 2818 */ 2819 private final boolean mExact; 2820 2821 SwPnoScheduleInfo(int maxIterations, boolean exact, int timerBaseMs, boolean backoff)2822 SwPnoScheduleInfo(int maxIterations, boolean exact, int timerBaseMs, 2823 boolean backoff) { 2824 if (maxIterations < 1 || timerBaseMs < 1) { 2825 Log.wtf(TAG, "Invalid Sw PNO Schedule Info."); 2826 throw new IllegalArgumentException("Invalid Sw PNO Schedule Info"); 2827 } 2828 this.mMaxIterations = maxIterations; 2829 this.mExact = exact; 2830 this.mTimerBaseMs = timerBaseMs; 2831 this.mBackoff = backoff; 2832 } 2833 } 2834 private List<SwPnoScheduleInfo> mSwPnoScheduleInfos = new ArrayList<>(); 2835 SwPnoScheduleInfo mCurrentSchedule; 2836 Iterator<SwPnoScheduleInfo> mScheduleIterator; 2837 int mIteration = 0; 2838 2839 /** 2840 * Append a new schedule info at the end of the schedule queue. 2841 * @param maxIterations Number of times the current schedule must be repeated 2842 * @param exact Whether the alarms are scheduled exactly or not 2843 * @param timerBaseMs Initial alarm interval 2844 * @param backoff Whether the interval should increase at each iteration or not 2845 */ addSchedule(int maxIterations, boolean exact, int timerBaseMs, boolean backoff)2846 void addSchedule(int maxIterations, boolean exact, int timerBaseMs, 2847 boolean backoff) { 2848 mSwPnoScheduleInfos.add(new SwPnoScheduleInfo(maxIterations, exact, timerBaseMs, 2849 backoff)); 2850 } 2851 start()2852 boolean start() { 2853 if (mSwPnoScheduleInfos.isEmpty()) { 2854 Log.wtf(TAG, "No SwPno Schedule Found"); 2855 return false; 2856 } 2857 mScheduleIterator = mSwPnoScheduleInfos.iterator(); 2858 mCurrentSchedule = mScheduleIterator.next(); 2859 return true; 2860 } 2861 next()2862 boolean next() { 2863 if (mCurrentSchedule.mMaxIterations > mIteration) { 2864 mIteration++; 2865 return true; 2866 } else if (mScheduleIterator.hasNext()) { 2867 mCurrentSchedule = mScheduleIterator.next(); 2868 mIteration = 1; 2869 return true; 2870 } 2871 return false; 2872 } 2873 getInterval()2874 int getInterval() { 2875 int multiplier = mCurrentSchedule.mBackoff ? mIteration : 1; 2876 return mCurrentSchedule.mTimerBaseMs * multiplier; 2877 } 2878 isExact()2879 boolean isExact() { 2880 return mCurrentSchedule.mExact; 2881 } 2882 } 2883 2884 private class SwPnoAlarmReceiver extends BroadcastReceiver { 2885 2886 @Override onReceive(Context context, Intent intent)2887 public void onReceive(Context context, Intent intent) { 2888 if (intent.getAction().equals(SW_PNO_UPPER_BOUND_ALARM_INTENT_ACTION)) { 2889 mSwPnoAlarmManager.cancel(mPendingIntentSwPno); 2890 } else { 2891 mSwPnoAlarmManager.cancel(mPendingIntentSwPnoUpperBound); 2892 } 2893 Message msg = obtainMessage(); 2894 msg.what = CMD_SW_PNO_SCAN; 2895 sendMessage(msg); 2896 } 2897 } 2898 SwPnoScanState()2899 SwPnoScanState() { 2900 Intent alarmIntent = new Intent(SW_PNO_ALARM_INTENT_ACTION).setPackage( 2901 mContext.getPackageName()); 2902 Intent alarmIntentUpperBound = new Intent( 2903 SW_PNO_UPPER_BOUND_ALARM_INTENT_ACTION).setPackage( 2904 mContext.getPackageName()); 2905 mSwPnoAlarmManager = mContext.getSystemService(AlarmManager.class); 2906 mPendingIntentSwPno = PendingIntent.getBroadcast(mContext, /* requestCode */ 0, 2907 alarmIntent, PendingIntent.FLAG_IMMUTABLE); 2908 mPendingIntentSwPnoUpperBound = PendingIntent.getBroadcast(mContext, 2909 /* requestCode */ 1, alarmIntentUpperBound, PendingIntent.FLAG_IMMUTABLE); 2910 mSwPnoTimerMarginMs = mContext.getResources().getInteger( 2911 R.integer.config_wifiSwPnoSlowTimerMargin); 2912 } 2913 2914 @Override enter()2915 public void enter() { 2916 if (DBG) localLog("SwPnoScanState"); 2917 IntentFilter filter = new IntentFilter(SW_PNO_ALARM_INTENT_ACTION); 2918 filter.addAction(SW_PNO_UPPER_BOUND_ALARM_INTENT_ACTION); 2919 mContext.registerReceiver(mSwPnoAlarmReceiver, filter, null, 2920 getHandler()); 2921 } 2922 2923 @Override exit()2924 public void exit() { 2925 removeInternalClient(); 2926 mSwPnoAlarmManager.cancel(mPendingIntentSwPno); 2927 mSwPnoAlarmManager.cancel(mPendingIntentSwPnoUpperBound); 2928 mContext.unregisterReceiver(mSwPnoAlarmReceiver); 2929 mScanParams = null; 2930 mClientInfo = null; 2931 } 2932 initializeSwPnoScheduleInfos(int mobilityIntervalMs)2933 boolean initializeSwPnoScheduleInfos(int mobilityIntervalMs) { 2934 final int swPnoDefaultTimerFastMs = mContext.getResources().getInteger( 2935 R.integer.config_wifiSwPnoFastTimerMs); 2936 final int swPnoDefaultTimerSlowMs = mContext.getResources().getInteger( 2937 R.integer.config_wifiSwPnoSlowTimerMs); 2938 final int swPnoMobilityIterations = mContext.getResources().getInteger( 2939 R.integer.config_wifiSwPnoMobilityStateTimerIterations); 2940 final int swPnoFastIterations = mContext.getResources().getInteger( 2941 R.integer.config_wifiSwPnoFastTimerIterations); 2942 final int swPnoSlowIterations = mContext.getResources().getInteger( 2943 R.integer.config_wifiSwPnoSlowTimerIterations); 2944 2945 mSwPnoScheduler = new SwPnoScheduler(); 2946 try { 2947 mSwPnoScheduler.addSchedule(swPnoMobilityIterations, 2948 /* exact */ true, mobilityIntervalMs, /* backoff */ true); 2949 mSwPnoScheduler.addSchedule(swPnoFastIterations, 2950 /* exact */ true, swPnoDefaultTimerFastMs, /* backoff */ false); 2951 mSwPnoScheduler.addSchedule(swPnoSlowIterations, 2952 /* exact */ false, swPnoDefaultTimerSlowMs, /* backoff */ false); 2953 } catch (IllegalArgumentException e) { 2954 return false; 2955 } 2956 return mSwPnoScheduler.start(); 2957 } 2958 addSwPnoScanRequest(ClientInfo ci, ScanSettings scanSettings, PnoSettings pnoSettings)2959 private void addSwPnoScanRequest(ClientInfo ci, 2960 ScanSettings scanSettings, PnoSettings pnoSettings) { 2961 scanSettings.reportEvents |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT 2962 | WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 2963 addPnoScanRequest(ci, scanSettings, pnoSettings); 2964 } 2965 removeSwPnoScanRequest(ClientInfo ci)2966 private void removeSwPnoScanRequest(ClientInfo ci) { 2967 if (ci != null) { 2968 Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci); 2969 ci.cleanup(); 2970 if (settings != null) { 2971 logScanRequest("removeSwPnoScanRequest", ci, null, 2972 settings.second, settings.first); 2973 } 2974 } 2975 } 2976 schedulePnoTimer(boolean exact, int timeoutMs)2977 private void schedulePnoTimer(boolean exact, int timeoutMs) { 2978 Log.i(TAG, "Next SwPno scan in: " + timeoutMs); 2979 if (exact) { 2980 mSwPnoAlarmManager.setExactAndAllowWhileIdle( 2981 AlarmManager.ELAPSED_REALTIME_WAKEUP, 2982 mClock.getElapsedSinceBootMillis() + timeoutMs, 2983 mPendingIntentSwPno); 2984 } else { 2985 mSwPnoAlarmManager.setWindow(AlarmManager.ELAPSED_REALTIME, 2986 mClock.getElapsedSinceBootMillis() + timeoutMs, 2987 mSwPnoTimerMarginMs, 2988 mPendingIntentSwPno); 2989 2990 mSwPnoAlarmManager.setExactAndAllowWhileIdle( 2991 AlarmManager.ELAPSED_REALTIME_WAKEUP, 2992 mClock.getElapsedSinceBootMillis() + timeoutMs 2993 + mSwPnoTimerMarginMs, mPendingIntentSwPnoUpperBound); 2994 } 2995 } 2996 handleSwPnoScan()2997 private void handleSwPnoScan() { 2998 if (mScanParams != null && mScanParams.settings != null && mClientInfo != null) { 2999 // The Internal ClientInfo is unregistered by 3000 // WifiSingleScanStateMachine#handleScanResults after each scan. We have 3001 // therefore to re-create or at least re-register the client before each scan. 3002 // For the first scan this is redundant. 3003 removeInternalClient(); 3004 addInternalClient(mClientInfo); 3005 addSingleScanRequest(mScanParams.settings); 3006 } 3007 } 3008 handleSwPnoSchedule()3009 private void handleSwPnoSchedule() { 3010 if (mSwPnoScheduler.next()) { 3011 schedulePnoTimer(mSwPnoScheduler.isExact(), 3012 mSwPnoScheduler.getInterval()); 3013 } else { 3014 // Nothing more to schedule, stopping SW PNO 3015 Message msg = obtainMessage(); 3016 msg.what = WifiScanner.CMD_STOP_PNO_SCAN; 3017 sendMessage(msg); 3018 } 3019 } 3020 3021 @Override processMessage(Message msg)3022 public boolean processMessage(Message msg) { 3023 switch (msg.what) { 3024 case WifiScanner.CMD_START_PNO_SCAN: { 3025 Log.i(TAG, "Starting Software PNO"); 3026 ScanParams scanParams = (ScanParams) msg.obj; 3027 if (scanParams == null) { 3028 Log.wtf(TAG, "Received Start PNO request without parameters"); 3029 transitionTo(mStartedState); 3030 return HANDLED; 3031 } 3032 3033 ClientInfo clientInfo = mClients.get(scanParams.listener); 3034 if (clientInfo == null) { 3035 clientInfo = new ExternalClientInfo(msg.sendingUid, 3036 scanParams.packageName, scanParams.listener, 3037 scanParams.featureId); 3038 clientInfo.register(); 3039 } 3040 3041 if (!mActivePnoScans.isEmpty()) { 3042 loge("Dropping scan request because there is already an active scan"); 3043 clientInfo.replyFailed(WifiScanner.REASON_DUPLICATE_REQEUST, 3044 "Failed to add a SW Pno Scan Request"); 3045 return HANDLED; 3046 } 3047 3048 if (scanParams.pnoSettings == null || scanParams.settings == null) { 3049 Log.e(TAG, "SwPno Invalid Scan Parameters"); 3050 clientInfo.replyFailed(WifiScanner.REASON_INVALID_REQUEST, 3051 "invalid settings"); 3052 transitionTo(mStartedState); 3053 return HANDLED; 3054 } 3055 3056 if (!initializeSwPnoScheduleInfos(scanParams.settings.periodInMs)) { 3057 clientInfo.replyFailed(WifiScanner.REASON_INVALID_REQUEST, 3058 "Failed to initialize the Sw PNO Scheduler"); 3059 transitionTo(mStartedState); 3060 return HANDLED; 3061 } 3062 3063 addSwPnoScanRequest(clientInfo, scanParams.settings, 3064 scanParams.pnoSettings); 3065 clientInfo.replySucceeded(); 3066 mClientInfo = clientInfo; 3067 mScanParams = scanParams; 3068 3069 handleSwPnoScan(); 3070 handleSwPnoSchedule(); 3071 break; 3072 } 3073 case CMD_SW_PNO_SCAN: 3074 // The internal client is registered to mClients when the PNO scan is 3075 // started, and is deregistered when the scan is over. By verifying that 3076 // the internal client is not registered in mClients can be sure that no 3077 // other pno scans are in progress 3078 if (mClients.get(mInternalClientInfo.mListener) == null) { 3079 handleSwPnoScan(); 3080 handleSwPnoSchedule(); 3081 } 3082 break; 3083 case WifiScanner.CMD_STOP_PNO_SCAN: { 3084 Log.i(TAG, "Stopping Software PNO"); 3085 if (mClientInfo != null) { 3086 removeSwPnoScanRequest(mClientInfo); 3087 transitionTo(mStartedState); 3088 } 3089 break; 3090 } 3091 case WifiScanner.CMD_OP_FAILED: 3092 sendPnoScanFailedToAllAndClear( 3093 WifiScanner.REASON_UNSPECIFIED, "scan failed"); 3094 transitionTo(mStartedState); 3095 break; 3096 default: 3097 return NOT_HANDLED; 3098 } 3099 return HANDLED; 3100 } 3101 } 3102 3103 class SingleScanState extends State { 3104 @Override enter()3105 public void enter() { 3106 if (DBG) localLog("SingleScanState"); 3107 } 3108 3109 @Override processMessage(Message msg)3110 public boolean processMessage(Message msg) { 3111 switch (msg.what) { 3112 case WifiScanner.CMD_SCAN_RESULT: 3113 WifiScanner.ParcelableScanData parcelableScanData = 3114 (WifiScanner.ParcelableScanData) msg.obj; 3115 ScanData[] scanDatas = parcelableScanData.getResults(); 3116 ScanData lastScanData = scanDatas[scanDatas.length - 1]; 3117 reportPnoNetworkFound(lastScanData.getResults()); 3118 transitionTo(mHwPnoScanState); 3119 break; 3120 case WifiScanner.CMD_OP_FAILED: 3121 sendPnoScanFailedToAllAndClear( 3122 WifiScanner.REASON_UNSPECIFIED, "single scan failed"); 3123 transitionTo(mStartedState); 3124 break; 3125 default: 3126 return NOT_HANDLED; 3127 } 3128 return HANDLED; 3129 } 3130 } 3131 convertToWifiNativePnoSettings(ScanSettings scanSettings, PnoSettings pnoSettings)3132 private WifiNative.PnoSettings convertToWifiNativePnoSettings(ScanSettings scanSettings, 3133 PnoSettings pnoSettings) { 3134 WifiNative.PnoSettings nativePnoSetting = new WifiNative.PnoSettings(); 3135 nativePnoSetting.periodInMs = scanSettings.periodInMs; 3136 nativePnoSetting.min5GHzRssi = pnoSettings.min5GHzRssi; 3137 nativePnoSetting.min24GHzRssi = pnoSettings.min24GHzRssi; 3138 nativePnoSetting.min6GHzRssi = pnoSettings.min6GHzRssi; 3139 nativePnoSetting.scanIterations = pnoSettings.scanIterations; 3140 nativePnoSetting.scanIntervalMultiplier = pnoSettings.scanIntervalMultiplier; 3141 nativePnoSetting.isConnected = pnoSettings.isConnected; 3142 nativePnoSetting.networkList = 3143 new WifiNative.PnoNetwork[pnoSettings.networkList.length]; 3144 for (int i = 0; i < pnoSettings.networkList.length; i++) { 3145 nativePnoSetting.networkList[i] = new WifiNative.PnoNetwork(); 3146 nativePnoSetting.networkList[i].ssid = pnoSettings.networkList[i].ssid; 3147 nativePnoSetting.networkList[i].flags = pnoSettings.networkList[i].flags; 3148 nativePnoSetting.networkList[i].auth_bit_field = 3149 pnoSettings.networkList[i].authBitField; 3150 nativePnoSetting.networkList[i].frequencies = 3151 pnoSettings.networkList[i].frequencies; 3152 } 3153 return nativePnoSetting; 3154 } 3155 3156 // Retrieve the only active scan settings. getScanSettings()3157 private ScanSettings getScanSettings() { 3158 for (Pair<PnoSettings, ScanSettings> settingsPair : mActivePnoScans.getAllSettings()) { 3159 return settingsPair.second; 3160 } 3161 return null; 3162 } 3163 removeInternalClient()3164 private void removeInternalClient() { 3165 if (mInternalClientInfo != null) { 3166 mInternalClientInfo.cleanup(); 3167 mInternalClientInfo = null; 3168 } else { 3169 Log.w(TAG, "No Internal client for PNO"); 3170 } 3171 } 3172 addInternalClient(ClientInfo ci)3173 private void addInternalClient(ClientInfo ci) { 3174 if (mInternalClientInfo == null) { 3175 mInternalClientInfo = new InternalClientInfo(ci.getUid(), "internal", 3176 new InternalListener(), ci.mAttributionTag); 3177 mInternalClientInfo.register(); 3178 } else { 3179 Log.w(TAG, "Internal client for PNO already exists"); 3180 } 3181 } 3182 addPnoScanRequest(ClientInfo ci, ScanSettings scanSettings, PnoSettings pnoSettings)3183 private void addPnoScanRequest(ClientInfo ci, ScanSettings scanSettings, 3184 PnoSettings pnoSettings) { 3185 mActivePnoScans.addRequest(ci, ClientModeImpl.WIFI_WORK_SOURCE, 3186 Pair.create(pnoSettings, scanSettings)); 3187 addInternalClient(ci); 3188 } 3189 removePnoScanRequest(ClientInfo ci)3190 private Pair<PnoSettings, ScanSettings> removePnoScanRequest(ClientInfo ci) { 3191 Pair<PnoSettings, ScanSettings> settings = mActivePnoScans.removeRequest(ci); 3192 return settings; 3193 } 3194 addHwPnoScanRequest(ClientInfo ci, ScanSettings scanSettings, PnoSettings pnoSettings)3195 private boolean addHwPnoScanRequest(ClientInfo ci, ScanSettings scanSettings, 3196 PnoSettings pnoSettings) { 3197 if (ci == null) { 3198 Log.d(TAG, "Failing scan request ClientInfo not found "); 3199 return false; 3200 } 3201 if (!mActivePnoScans.isEmpty()) { 3202 loge("Failing scan request because there is already an active scan"); 3203 return false; 3204 } 3205 WifiNative.PnoSettings nativePnoSettings = 3206 convertToWifiNativePnoSettings(scanSettings, pnoSettings); 3207 if (!mScannerImplsTracker.setHwPnoList(nativePnoSettings)) { 3208 return false; 3209 } 3210 logScanRequest("addHwPnoScanRequest", ci, null, scanSettings, pnoSettings); 3211 addPnoScanRequest(ci, scanSettings, pnoSettings); 3212 3213 return true; 3214 } 3215 removeHwPnoScanRequest(ClientInfo ci)3216 private void removeHwPnoScanRequest(ClientInfo ci) { 3217 if (ci != null) { 3218 Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci); 3219 ci.cleanup(); 3220 if (settings != null) { 3221 logScanRequest("removeHwPnoScanRequest", ci, null, 3222 settings.second, settings.first); 3223 } 3224 } 3225 } 3226 reportPnoNetworkFound(ScanResult[] results)3227 private void reportPnoNetworkFound(ScanResult[] results) { 3228 for (RequestInfo<Pair<PnoSettings, ScanSettings>> entry : mActivePnoScans) { 3229 ClientInfo ci = entry.clientInfo; 3230 logCallback("pnoNetworkFound", ci, describeForLog(results)); 3231 ci.reportEvent((listener) -> { 3232 try { 3233 listener.onPnoNetworkFound(results); 3234 } catch (RemoteException e) { 3235 loge("Failed to call onPnoNetworkFound: " + ci); 3236 } 3237 }); 3238 } 3239 } 3240 sendPnoScanFailedToAllAndClear(int reason, String description)3241 private void sendPnoScanFailedToAllAndClear(int reason, String description) { 3242 for (RequestInfo<Pair<PnoSettings, ScanSettings>> entry : mActivePnoScans) { 3243 ClientInfo ci = entry.clientInfo; 3244 ci.reportEvent((listener) -> { 3245 try { 3246 listener.onFailure(reason, description); 3247 } catch (RemoteException e) { 3248 loge("Failed to call onFailure: " + ci); 3249 } 3250 }); 3251 } 3252 mActivePnoScans.clear(); 3253 } 3254 addSingleScanRequest(ScanSettings settings)3255 private void addSingleScanRequest(ScanSettings settings) { 3256 if (DBG) localLog("Starting single scan"); 3257 if (mInternalClientInfo != null) { 3258 Message msg = Message.obtain(); 3259 msg.what = WifiScanner.CMD_START_SINGLE_SCAN; 3260 msg.obj = new ScanParams(mInternalClientInfo.mListener, settings, 3261 ClientModeImpl.WIFI_WORK_SOURCE, "WIFI_INTERNAL"); 3262 mSingleScanStateMachine.sendMessage(msg); 3263 } 3264 mWifiMetrics.getScanMetrics().setWorkSource(ClientModeImpl.WIFI_WORK_SOURCE); 3265 } 3266 3267 /** 3268 * Checks if IE are present in scan data, if no single scan is needed to report event to 3269 * client 3270 */ isSingleScanNeeded(ScanResult[] scanResults)3271 private boolean isSingleScanNeeded(ScanResult[] scanResults) { 3272 for (ScanResult scanResult : scanResults) { 3273 if (scanResult.informationElements != null 3274 && scanResult.informationElements.length > 0) { 3275 return false; 3276 } 3277 } 3278 return true; 3279 } 3280 } 3281 3282 @FunctionalInterface 3283 private interface ListenerCallback { callListener(IWifiScannerListener listener)3284 void callListener(IWifiScannerListener listener); 3285 } 3286 3287 private abstract class ClientInfo { 3288 private final int mUid; 3289 private final String mPackageName; 3290 private final String mAttributionTag; 3291 private final WorkSource mWorkSource; 3292 private boolean mScanWorkReported = false; 3293 protected final IWifiScannerListener mListener; 3294 protected DeathRecipient mDeathRecipient = new DeathRecipient() { 3295 @Override 3296 public void binderDied() { 3297 mWifiThreadRunner.post(() -> { 3298 if (DBG) localLog("binder died: client listener: " + mListener); 3299 if (isVerboseLoggingEnabled()) { 3300 Log.i(TAG, "binder died: client listener: " + mListener); 3301 } 3302 cleanup(); 3303 }, TAG + "#binderDied"); 3304 } 3305 }; 3306 ClientInfo(int uid, String packageName, IWifiScannerListener listener, String attributionTag)3307 ClientInfo(int uid, String packageName, IWifiScannerListener listener, 3308 String attributionTag) { 3309 mUid = uid; 3310 mPackageName = packageName; 3311 mListener = listener; 3312 mWorkSource = new WorkSource(uid); 3313 mAttributionTag = attributionTag; 3314 } 3315 3316 /** 3317 * Register this client to main client map. 3318 */ register()3319 public void register() { 3320 if (isVerboseLoggingEnabled()) { 3321 Log.i(TAG, "Registering listener= " + mListener + " uid=" + mUid 3322 + " packageName=" + mPackageName + " workSource=" + mWorkSource); 3323 } 3324 mClients.put(mListener, this); 3325 } 3326 3327 /** 3328 * Unregister this client from main client map. 3329 */ unregister()3330 private void unregister() { 3331 if (isVerboseLoggingEnabled()) { 3332 Log.i(TAG, "Unregistering listener= " + mListener + " uid=" + mUid 3333 + " packageName=" + mPackageName + " workSource=" + mWorkSource); 3334 } 3335 try { 3336 mListener.asBinder().unlinkToDeath(mDeathRecipient, 0); 3337 } catch (Exception e) { 3338 Log.e(TAG, "Failed to unregister death recipient! " + mListener); 3339 } 3340 3341 mClients.remove(mListener); 3342 } 3343 cleanup()3344 public void cleanup() { 3345 mSingleScanListeners.removeAllForClient(this); 3346 mSingleScanStateMachine.removeSingleScanRequests(this); 3347 mBackgroundScanStateMachine.removeBackgroundScanSettings(this); 3348 unregister(); 3349 localLog("Successfully stopped all requests for client " + this); 3350 } 3351 getUid()3352 public int getUid() { 3353 return mUid; 3354 } 3355 3356 // This has to be implemented by subclasses to report events back to clients. reportEvent(ListenerCallback cb)3357 public abstract void reportEvent(ListenerCallback cb); 3358 3359 // TODO(b/27903217, 71530998): This is dead code. Should this be wired up ? reportBatchedScanStart()3360 private void reportBatchedScanStart() { 3361 if (mUid == 0) 3362 return; 3363 3364 int csph = getCsph(); 3365 3366 mBatteryStats.reportWifiBatchedScanStartedFromSource(mWorkSource, csph); 3367 } 3368 3369 // TODO(b/27903217, 71530998): This is dead code. Should this be wired up ? reportBatchedScanStop()3370 private void reportBatchedScanStop() { 3371 if (mUid == 0) 3372 return; 3373 3374 mBatteryStats.reportWifiBatchedScanStoppedFromSource(mWorkSource); 3375 } 3376 3377 // TODO migrate batterystats to accept scan duration per hour instead of csph getCsph()3378 private int getCsph() { 3379 int totalScanDurationPerHour = 0; 3380 Collection<ScanSettings> settingsList = 3381 mBackgroundScanStateMachine.getBackgroundScanSettings(this); 3382 for (ScanSettings settings : settingsList) { 3383 int scanDurationMs = mChannelHelper.estimateScanDuration(settings); 3384 int scans_per_Hour = settings.periodInMs == 0 ? 1 : (3600 * 1000) / 3385 settings.periodInMs; 3386 totalScanDurationPerHour += scanDurationMs * scans_per_Hour; 3387 } 3388 3389 return totalScanDurationPerHour / ChannelHelper.SCAN_PERIOD_PER_CHANNEL_MS; 3390 } 3391 3392 // TODO(b/27903217, 71530998): This is dead code. Should this be wired up ? reportScanWorkUpdate()3393 private void reportScanWorkUpdate() { 3394 if (mScanWorkReported) { 3395 reportBatchedScanStop(); 3396 mScanWorkReported = false; 3397 } 3398 if (mBackgroundScanStateMachine.getBackgroundScanSettings(this).isEmpty()) { 3399 reportBatchedScanStart(); 3400 mScanWorkReported = true; 3401 } 3402 } 3403 replySucceeded()3404 void replySucceeded() { 3405 if (mListener != null) { 3406 try { 3407 mListener.onSuccess(); 3408 mLog.trace("onSuccess").flush(); 3409 } catch (Exception e) { 3410 // There's not much we can do if reply can't be sent! 3411 } 3412 } else { 3413 // locally generated message; doesn't need a reply! 3414 } 3415 } 3416 replyFailed(int reason, String description)3417 void replyFailed(int reason, String description) { 3418 if (mListener != null) { 3419 try { 3420 mListener.onFailure(reason, description); 3421 mLog.trace("onFailure reason=% description=%") 3422 .c(reason) 3423 .c(description) 3424 .flush(); 3425 } catch (Exception e) { 3426 // There's not much we can do if reply can't be sent! 3427 } 3428 } else { 3429 // locally generated message; doesn't need a reply! 3430 } 3431 } 3432 3433 @Override toString()3434 public String toString() { 3435 return "ClientInfo[uid=" + mUid + ", package=" + mPackageName + ", attributionTag=" 3436 + mAttributionTag + ", " + mListener + "]"; 3437 } 3438 } 3439 3440 /** 3441 * This class is used to represent external clients to the WifiScanning Service. 3442 */ 3443 private class ExternalClientInfo extends ClientInfo { 3444 /** 3445 * Indicates if the client is still connected 3446 * If the client is no longer connected then messages to it will be silently dropped 3447 */ 3448 private boolean mDisconnected = false; 3449 ExternalClientInfo(int uid, String packageName, IWifiScannerListener listener, String attributionTag)3450 ExternalClientInfo(int uid, String packageName, IWifiScannerListener listener, 3451 String attributionTag) { 3452 super(uid, packageName, listener, attributionTag); 3453 if (DBG) localLog("New client, listener: " + listener); 3454 try { 3455 listener.asBinder().linkToDeath(mDeathRecipient, 0); 3456 } catch (RemoteException e) { 3457 Log.e(TAG, "can't register death recipient! " + listener); 3458 } 3459 } 3460 reportEvent(ListenerCallback cb)3461 public void reportEvent(ListenerCallback cb) { 3462 if (!mDisconnected) { 3463 cb.callListener(mListener); 3464 } 3465 } 3466 3467 @Override cleanup()3468 public void cleanup() { 3469 mDisconnected = true; 3470 mPnoScanStateMachine.removePnoSettings(this); 3471 super.cleanup(); 3472 } 3473 } 3474 3475 /** 3476 * This class is used to represent internal clients to the WifiScanning Service. This is needed 3477 * for communicating between State Machines. 3478 * This leaves the onReportEvent method unimplemented, so that the clients have the freedom 3479 * to handle the events as they need. 3480 */ 3481 private class InternalClientInfo extends ClientInfo { 3482 /** 3483 * The UID here is used to proxy the original external requester UID. 3484 */ InternalClientInfo(int requesterUid, String packageName, IWifiScannerListener listener, String attributionTag)3485 InternalClientInfo(int requesterUid, String packageName, IWifiScannerListener listener, 3486 String attributionTag) { 3487 super(requesterUid, packageName, listener, attributionTag); 3488 } 3489 3490 @Override reportEvent(ListenerCallback cb)3491 public void reportEvent(ListenerCallback cb) { 3492 cb.callListener(mListener); 3493 } 3494 3495 @Override toString()3496 public String toString() { 3497 return "InternalClientInfo[]"; 3498 } 3499 } 3500 3501 private static class InternalListener extends IWifiScannerListener.Default { 3502 } 3503 3504 private class LocalService extends WifiScannerInternal { 3505 @Override setScanningEnabled(boolean enable)3506 public void setScanningEnabled(boolean enable) { 3507 WifiScanningServiceImpl.this.setScanningEnabled(enable, Process.myTid(), 3508 mContext.getOpPackageName()); 3509 } 3510 3511 @Override registerScanListener(@onNull WifiScannerInternal.ScanListener listener)3512 public void registerScanListener(@NonNull WifiScannerInternal.ScanListener listener) { 3513 WifiScanningServiceImpl.this.registerScanListener(listener, 3514 mContext.getOpPackageName(), mContext.getAttributionTag()); 3515 } 3516 3517 @Override startScan(WifiScanner.ScanSettings settings, WifiScannerInternal.ScanListener listener, @Nullable WorkSource workSource)3518 public void startScan(WifiScanner.ScanSettings settings, 3519 WifiScannerInternal.ScanListener listener, 3520 @Nullable WorkSource workSource) { 3521 WifiScanningServiceImpl.this.startScan(listener, settings, workSource, 3522 workSource.getPackageName(0), mContext.getAttributionTag()); 3523 } 3524 3525 @Override stopScan(WifiScannerInternal.ScanListener listener)3526 public void stopScan(WifiScannerInternal.ScanListener listener) { 3527 WifiScanningServiceImpl.this.stopScan(listener, 3528 mContext.getOpPackageName(), mContext.getAttributionTag()); 3529 } 3530 3531 @Override startPnoScan(WifiScanner.ScanSettings scanSettings, WifiScanner.PnoSettings pnoSettings, WifiScannerInternal.ScanListener listener)3532 public void startPnoScan(WifiScanner.ScanSettings scanSettings, 3533 WifiScanner.PnoSettings pnoSettings, 3534 WifiScannerInternal.ScanListener listener) { 3535 WifiScanningServiceImpl.this.startPnoScan(listener, 3536 scanSettings, pnoSettings, mContext.getOpPackageName(), 3537 mContext.getAttributionTag()); 3538 } 3539 3540 @Override stopPnoScan(WifiScannerInternal.ScanListener listener)3541 public void stopPnoScan(WifiScannerInternal.ScanListener listener) { 3542 WifiScanningServiceImpl.this.stopPnoScan(listener, mContext.getOpPackageName(), 3543 mContext.getAttributionTag()); 3544 } 3545 3546 @Override getSingleScanResults()3547 public List<ScanResult> getSingleScanResults() { 3548 return mSingleScanStateMachine.filterCachedScanResultsByAge(); 3549 } 3550 } 3551 toString(int uid, ScanSettings settings)3552 private static String toString(int uid, ScanSettings settings) { 3553 StringBuilder sb = new StringBuilder(); 3554 sb.append("ScanSettings[uid=").append(uid); 3555 sb.append(", period=").append(settings.periodInMs); 3556 sb.append(", report=").append(settings.reportEvents); 3557 if (settings.reportEvents == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL 3558 && settings.numBssidsPerScan > 0 3559 && settings.maxScansToCache > 1) { 3560 sb.append(", batch=").append(settings.maxScansToCache); 3561 sb.append(", numAP=").append(settings.numBssidsPerScan); 3562 } 3563 sb.append(", ").append(ChannelHelper.toString(settings)); 3564 sb.append("]"); 3565 3566 return sb.toString(); 3567 } 3568 3569 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)3570 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 3571 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 3572 != PERMISSION_GRANTED) { 3573 pw.println("Permission Denial: can't dump WifiScanner from from pid=" 3574 + Binder.getCallingPid() 3575 + ", uid=" + Binder.getCallingUid() 3576 + " without permission " 3577 + android.Manifest.permission.DUMP); 3578 return; 3579 } 3580 pw.println("WifiScanningService - Log Begin ----"); 3581 mLocalLog.dump(fd, pw, args); 3582 pw.println("WifiScanningService - Log End ----"); 3583 pw.println(); 3584 pw.println("clients:"); 3585 for (ClientInfo client : mClients.values()) { 3586 pw.println(" " + client); 3587 } 3588 pw.println("listeners:"); 3589 for (ClientInfo client : mClients.values()) { 3590 Collection<ScanSettings> settingsList = 3591 mBackgroundScanStateMachine.getBackgroundScanSettings(client); 3592 for (ScanSettings settings : settingsList) { 3593 pw.println(" " + toString(client.mUid, settings)); 3594 } 3595 } 3596 if (mBackgroundScheduler != null) { 3597 WifiNative.ScanSettings schedule = mBackgroundScheduler.getSchedule(); 3598 if (schedule != null) { 3599 pw.println("schedule:"); 3600 pw.println(" base period: " + schedule.base_period_ms); 3601 pw.println(" max ap per scan: " + schedule.max_ap_per_scan); 3602 pw.println(" batched scans: " + schedule.report_threshold_num_scans); 3603 pw.println(" buckets:"); 3604 for (int b = 0; b < schedule.num_buckets; b++) { 3605 WifiNative.BucketSettings bucket = schedule.buckets[b]; 3606 pw.println(" bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)[" 3607 + bucket.report_events + "]: " 3608 + ChannelHelper.toString(bucket)); 3609 } 3610 } 3611 } 3612 if (mPnoScanStateMachine != null) { 3613 mPnoScanStateMachine.dump(fd, pw, args); 3614 } 3615 pw.println(); 3616 3617 if (mChannelHelper != null) { 3618 mChannelHelper.dump(fd, pw, args); 3619 pw.println(); 3620 } 3621 3622 if (mSingleScanStateMachine != null) { 3623 mSingleScanStateMachine.dump(fd, pw, args); 3624 pw.println(); 3625 List<ScanResult> scanResults = mSingleScanStateMachine.getCachedScanResultsAsList(); 3626 long nowMs = mClock.getElapsedSinceBootMillis(); 3627 Log.d(TAG, "Latest scan results nowMs = " + nowMs); 3628 pw.println("Latest scan results:"); 3629 ScanResultUtil.dumpScanResults(pw, scanResults, nowMs); 3630 pw.println(); 3631 } 3632 for (WifiScannerImpl impl : mScannerImpls.values()) { 3633 impl.dump(fd, pw, args); 3634 } 3635 } 3636 logScanRequest(String request, ClientInfo ci, WorkSource workSource, ScanSettings settings, PnoSettings pnoSettings)3637 void logScanRequest(String request, ClientInfo ci, WorkSource workSource, 3638 ScanSettings settings, PnoSettings pnoSettings) { 3639 StringBuilder sb = new StringBuilder(); 3640 sb.append(request) 3641 .append(": ") 3642 .append((ci == null) ? "ClientInfo[unknown]" : ci.toString()); 3643 if (workSource != null) { 3644 sb.append(",").append(workSource); 3645 } 3646 if (settings != null) { 3647 sb.append(", "); 3648 describeTo(sb, settings); 3649 } 3650 if (pnoSettings != null) { 3651 sb.append(", "); 3652 describeTo(sb, pnoSettings); 3653 } 3654 localLog(sb.toString()); 3655 } 3656 logCallback(String callback, ClientInfo ci, String extra)3657 void logCallback(String callback, ClientInfo ci, String extra) { 3658 StringBuilder sb = new StringBuilder(); 3659 sb.append(callback) 3660 .append(": ") 3661 .append((ci == null) ? "ClientInfo[unknown]" : ci.toString()); 3662 if (extra != null) { 3663 sb.append(",").append(extra); 3664 } 3665 localLog(sb.toString()); 3666 } 3667 describeForLog(ScanData[] results)3668 static String describeForLog(ScanData[] results) { 3669 StringBuilder sb = new StringBuilder(); 3670 sb.append("results="); 3671 for (int i = 0; i < results.length; ++i) { 3672 if (i > 0) sb.append(";"); 3673 sb.append(results[i].getResults().length); 3674 } 3675 return sb.toString(); 3676 } 3677 describeForLog(ScanResult[] results)3678 static String describeForLog(ScanResult[] results) { 3679 return "results=" + results.length; 3680 } 3681 getScanTypeString(int type)3682 static String getScanTypeString(int type) { 3683 switch(type) { 3684 case WifiScanner.SCAN_TYPE_LOW_LATENCY: 3685 return "LOW LATENCY"; 3686 case WifiScanner.SCAN_TYPE_LOW_POWER: 3687 return "LOW POWER"; 3688 case WifiScanner.SCAN_TYPE_HIGH_ACCURACY: 3689 return "HIGH ACCURACY"; 3690 default: 3691 // This should never happen because we've validated the incoming type in 3692 // |validateScanType|. 3693 throw new IllegalArgumentException("Invalid scan type " + type); 3694 } 3695 } 3696 3697 /** 3698 * Convert Wi-Fi standard error to string 3699 */ scanErrorCodeToDescriptionString(int errorCode)3700 private static String scanErrorCodeToDescriptionString(int errorCode) { 3701 switch(errorCode) { 3702 case WifiScanner.REASON_BUSY: 3703 return "Scan failed - Device or resource busy"; 3704 case WifiScanner.REASON_ABORT: 3705 return "Scan aborted"; 3706 case WifiScanner.REASON_NO_DEVICE: 3707 return "Scan failed - No such device"; 3708 case WifiScanner.REASON_INVALID_ARGS: 3709 return "Scan failed - invalid argument"; 3710 case WifiScanner.REASON_TIMEOUT: 3711 return "Scan failed - Timeout"; 3712 case WifiScanner.REASON_UNSPECIFIED: 3713 default: 3714 return "Scan failed - unspecified reason"; 3715 } 3716 } 3717 describeTo(StringBuilder sb, ScanSettings scanSettings)3718 static String describeTo(StringBuilder sb, ScanSettings scanSettings) { 3719 sb.append("ScanSettings { ") 3720 .append(" type:").append(getScanTypeString(scanSettings.type)) 3721 .append(" band:").append(ChannelHelper.bandToString(scanSettings.band)) 3722 .append(" ignoreLocationSettings:").append(scanSettings.ignoreLocationSettings) 3723 .append(" period:").append(scanSettings.periodInMs) 3724 .append(" reportEvents:").append(scanSettings.reportEvents) 3725 .append(" numBssidsPerScan:").append(scanSettings.numBssidsPerScan) 3726 .append(" maxScansToCache:").append(scanSettings.maxScansToCache) 3727 .append(" rnrSetting:").append( 3728 SdkLevel.isAtLeastS() ? scanSettings.getRnrSetting() : "Not supported") 3729 .append(" 6GhzPscOnlyEnabled:").append( 3730 SdkLevel.isAtLeastS() ? scanSettings.is6GhzPscOnlyEnabled() 3731 : "Not supported") 3732 .append(" channels:[ "); 3733 if (scanSettings.channels != null) { 3734 for (int i = 0; i < scanSettings.channels.length; i++) { 3735 sb.append(scanSettings.channels[i].frequency).append(" "); 3736 } 3737 } 3738 sb.append(" ] ").append(" } "); 3739 return sb.toString(); 3740 } 3741 describeTo(StringBuilder sb, PnoSettings pnoSettings)3742 static String describeTo(StringBuilder sb, PnoSettings pnoSettings) { 3743 sb.append("PnoSettings { ") 3744 .append(" min5GhzRssi:").append(pnoSettings.min5GHzRssi) 3745 .append(" min24GhzRssi:").append(pnoSettings.min24GHzRssi) 3746 .append(" min6GhzRssi:").append(pnoSettings.min6GHzRssi) 3747 .append(" scanIterations:").append(pnoSettings.scanIterations) 3748 .append(" scanIntervalMultiplier:").append(pnoSettings.scanIntervalMultiplier) 3749 .append(" isConnected:").append(pnoSettings.isConnected) 3750 .append(" networks:[ "); 3751 if (pnoSettings.networkList != null) { 3752 for (int i = 0; i < pnoSettings.networkList.length; i++) { 3753 sb.append(pnoSettings.networkList[i].ssid).append(","); 3754 } 3755 } 3756 sb.append(" ] ") 3757 .append(" } "); 3758 return sb.toString(); 3759 } 3760 } 3761