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 android.Manifest; 20 import android.app.AlarmManager; 21 import android.app.PendingIntent; 22 import android.content.BroadcastReceiver; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.pm.PackageManager; 27 import android.net.wifi.IWifiScanner; 28 import android.net.wifi.ScanResult; 29 import android.net.wifi.WifiManager; 30 import android.net.wifi.WifiScanner; 31 import android.net.wifi.WifiScanner.BssidInfo; 32 import android.net.wifi.WifiScanner.ChannelSpec; 33 import android.net.wifi.WifiScanner.PnoSettings; 34 import android.net.wifi.WifiScanner.ScanData; 35 import android.net.wifi.WifiScanner.ScanSettings; 36 import android.os.Binder; 37 import android.os.Bundle; 38 import android.os.Handler; 39 import android.os.Looper; 40 import android.os.Message; 41 import android.os.Messenger; 42 import android.os.RemoteException; 43 import android.os.WorkSource; 44 import android.util.ArrayMap; 45 import android.util.LocalLog; 46 import android.util.Log; 47 import android.util.Pair; 48 49 import com.android.internal.app.IBatteryStats; 50 import com.android.internal.util.AsyncChannel; 51 import com.android.internal.util.Protocol; 52 import com.android.internal.util.State; 53 import com.android.internal.util.StateMachine; 54 import com.android.server.wifi.Clock; 55 import com.android.server.wifi.WifiInjector; 56 import com.android.server.wifi.WifiMetrics; 57 import com.android.server.wifi.WifiMetricsProto; 58 import com.android.server.wifi.WifiNative; 59 import com.android.server.wifi.WifiStateMachine; 60 import com.android.server.wifi.scanner.ChannelHelper.ChannelCollection; 61 62 import java.io.FileDescriptor; 63 import java.io.PrintWriter; 64 import java.util.ArrayList; 65 import java.util.Collection; 66 import java.util.HashMap; 67 import java.util.HashSet; 68 import java.util.Iterator; 69 import java.util.Set; 70 71 public class WifiScanningServiceImpl extends IWifiScanner.Stub { 72 73 private static final String TAG = WifiScanningService.TAG; 74 private static final boolean DBG = false; 75 76 private static final int MIN_PERIOD_PER_CHANNEL_MS = 200; // DFS needs 120 ms 77 private static final int UNKNOWN_PID = -1; 78 79 private final LocalLog mLocalLog = new LocalLog(512); 80 localLog(String message)81 private void localLog(String message) { 82 mLocalLog.log(message); 83 } 84 logw(String message)85 private void logw(String message) { 86 Log.w(TAG, message); 87 mLocalLog.log(message); 88 } 89 loge(String message)90 private void loge(String message) { 91 Log.e(TAG, message); 92 mLocalLog.log(message); 93 } 94 95 private WifiScannerImpl mScannerImpl; 96 97 @Override getMessenger()98 public Messenger getMessenger() { 99 if (mClientHandler != null) { 100 return new Messenger(mClientHandler); 101 } else { 102 loge("WifiScanningServiceImpl trying to get messenger w/o initialization"); 103 return null; 104 } 105 } 106 107 @Override getAvailableChannels(int band)108 public Bundle getAvailableChannels(int band) { 109 mChannelHelper.updateChannels(); 110 ChannelSpec[] channelSpecs = mChannelHelper.getAvailableScanChannels(band); 111 ArrayList<Integer> list = new ArrayList<Integer>(channelSpecs.length); 112 for (ChannelSpec channelSpec : channelSpecs) { 113 list.add(channelSpec.frequency); 114 } 115 Bundle b = new Bundle(); 116 b.putIntegerArrayList(WifiScanner.GET_AVAILABLE_CHANNELS_EXTRA, list); 117 return b; 118 } 119 enforceLocationHardwarePermission(int uid)120 private void enforceLocationHardwarePermission(int uid) { 121 mContext.enforcePermission( 122 Manifest.permission.LOCATION_HARDWARE, 123 UNKNOWN_PID, uid, 124 "LocationHardware"); 125 } 126 127 private class ClientHandler extends Handler { 128 ClientHandler(Looper looper)129 ClientHandler(Looper looper) { 130 super(looper); 131 } 132 133 @Override handleMessage(Message msg)134 public void handleMessage(Message msg) { 135 switch (msg.what) { 136 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 137 ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo); 138 if (client != null) { 139 logw("duplicate client connection: " + msg.sendingUid + ", messenger=" 140 + msg.replyTo); 141 client.mChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 142 AsyncChannel.STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED); 143 return; 144 } 145 146 AsyncChannel ac = new AsyncChannel(); 147 ac.connected(mContext, this, msg.replyTo); 148 149 client = new ExternalClientInfo(msg.sendingUid, msg.replyTo, ac); 150 client.register(); 151 152 ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 153 AsyncChannel.STATUS_SUCCESSFUL); 154 155 localLog("client connected: " + client); 156 return; 157 } 158 case AsyncChannel.CMD_CHANNEL_DISCONNECT: { 159 ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo); 160 if (client != null) { 161 client.mChannel.disconnect(); 162 } 163 return; 164 } 165 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 166 ExternalClientInfo client = (ExternalClientInfo) mClients.get(msg.replyTo); 167 if (client != null) { 168 localLog("client disconnected: " + client + ", reason: " + msg.arg1); 169 client.cleanup(); 170 } 171 return; 172 } 173 } 174 175 try { 176 enforceLocationHardwarePermission(msg.sendingUid); 177 } catch (SecurityException e) { 178 localLog("failed to authorize app: " + e); 179 replyFailed(msg, WifiScanner.REASON_NOT_AUTHORIZED, "Not authorized"); 180 return; 181 } 182 183 // Since this message is sent from WifiScanner using |sendMessageSynchronously| which 184 // doesn't set the correct |msg.replyTo| field. 185 if (msg.what == WifiScanner.CMD_GET_SCAN_RESULTS) { 186 mBackgroundScanStateMachine.sendMessage(Message.obtain(msg)); 187 return; 188 } 189 190 ClientInfo ci = mClients.get(msg.replyTo); 191 if (ci == null) { 192 loge("Could not find client info for message " + msg.replyTo); 193 replyFailed(msg, WifiScanner.REASON_INVALID_LISTENER, "Could not find listener"); 194 return; 195 } 196 197 switch (msg.what) { 198 case WifiScanner.CMD_START_BACKGROUND_SCAN: 199 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 200 case WifiScanner.CMD_SET_HOTLIST: 201 case WifiScanner.CMD_RESET_HOTLIST: 202 mBackgroundScanStateMachine.sendMessage(Message.obtain(msg)); 203 break; 204 case WifiScanner.CMD_START_PNO_SCAN: 205 case WifiScanner.CMD_STOP_PNO_SCAN: 206 mPnoScanStateMachine.sendMessage(Message.obtain(msg)); 207 break; 208 case WifiScanner.CMD_START_SINGLE_SCAN: 209 case WifiScanner.CMD_STOP_SINGLE_SCAN: 210 mSingleScanStateMachine.sendMessage(Message.obtain(msg)); 211 break; 212 case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE: 213 case WifiScanner.CMD_START_TRACKING_CHANGE: 214 case WifiScanner.CMD_STOP_TRACKING_CHANGE: 215 mWifiChangeStateMachine.sendMessage(Message.obtain(msg)); 216 break; 217 case WifiScanner.CMD_REGISTER_SCAN_LISTENER: 218 logScanRequest("registerScanListener", ci, msg.arg2, null, null, null); 219 mSingleScanListeners.addRequest(ci, msg.arg2, null, null); 220 replySucceeded(msg); 221 break; 222 case WifiScanner.CMD_DEREGISTER_SCAN_LISTENER: 223 logScanRequest("deregisterScanListener", ci, msg.arg2, null, null, null); 224 mSingleScanListeners.removeRequest(ci, msg.arg2); 225 break; 226 default: 227 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "Invalid request"); 228 break; 229 } 230 } 231 } 232 233 private static final int BASE = Protocol.BASE_WIFI_SCANNER_SERVICE; 234 235 private static final int CMD_SCAN_RESULTS_AVAILABLE = BASE + 0; 236 private static final int CMD_FULL_SCAN_RESULTS = BASE + 1; 237 private static final int CMD_HOTLIST_AP_FOUND = BASE + 2; 238 private static final int CMD_HOTLIST_AP_LOST = BASE + 3; 239 private static final int CMD_WIFI_CHANGE_DETECTED = BASE + 4; 240 private static final int CMD_WIFI_CHANGE_TIMEOUT = BASE + 5; 241 private static final int CMD_DRIVER_LOADED = BASE + 6; 242 private static final int CMD_DRIVER_UNLOADED = BASE + 7; 243 private static final int CMD_SCAN_PAUSED = BASE + 8; 244 private static final int CMD_SCAN_RESTARTED = BASE + 9; 245 private static final int CMD_SCAN_FAILED = BASE + 10; 246 private static final int CMD_PNO_NETWORK_FOUND = BASE + 11; 247 private static final int CMD_PNO_SCAN_FAILED = BASE + 12; 248 249 private final Context mContext; 250 private final Looper mLooper; 251 private final WifiScannerImpl.WifiScannerImplFactory mScannerImplFactory; 252 private final ArrayMap<Messenger, ClientInfo> mClients; 253 254 private final RequestList<Void> mSingleScanListeners = new RequestList<>(); 255 256 private ChannelHelper mChannelHelper; 257 private BackgroundScanScheduler mBackgroundScheduler; 258 private WifiNative.ScanSettings mPreviousSchedule; 259 260 private WifiBackgroundScanStateMachine mBackgroundScanStateMachine; 261 private WifiSingleScanStateMachine mSingleScanStateMachine; 262 private WifiChangeStateMachine mWifiChangeStateMachine; 263 private WifiPnoScanStateMachine mPnoScanStateMachine; 264 private ClientHandler mClientHandler; 265 private final IBatteryStats mBatteryStats; 266 private final AlarmManager mAlarmManager; 267 private final WifiMetrics mWifiMetrics; 268 private final Clock mClock; 269 WifiScanningServiceImpl(Context context, Looper looper, WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, IBatteryStats batteryStats, WifiInjector wifiInjector)270 WifiScanningServiceImpl(Context context, Looper looper, 271 WifiScannerImpl.WifiScannerImplFactory scannerImplFactory, IBatteryStats batteryStats, 272 WifiInjector wifiInjector) { 273 mContext = context; 274 mLooper = looper; 275 mScannerImplFactory = scannerImplFactory; 276 mBatteryStats = batteryStats; 277 mClients = new ArrayMap<>(); 278 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 279 mWifiMetrics = wifiInjector.getWifiMetrics(); 280 mClock = wifiInjector.getClock(); 281 282 mPreviousSchedule = null; 283 } 284 startService()285 public void startService() { 286 mClientHandler = new ClientHandler(mLooper); 287 mBackgroundScanStateMachine = new WifiBackgroundScanStateMachine(mLooper); 288 mWifiChangeStateMachine = new WifiChangeStateMachine(mLooper); 289 mSingleScanStateMachine = new WifiSingleScanStateMachine(mLooper); 290 mPnoScanStateMachine = new WifiPnoScanStateMachine(mLooper); 291 292 mContext.registerReceiver( 293 new BroadcastReceiver() { 294 @Override 295 public void onReceive(Context context, Intent intent) { 296 int state = intent.getIntExtra( 297 WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED); 298 if (DBG) localLog("SCAN_AVAILABLE : " + state); 299 if (state == WifiManager.WIFI_STATE_ENABLED) { 300 mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_LOADED); 301 mSingleScanStateMachine.sendMessage(CMD_DRIVER_LOADED); 302 mPnoScanStateMachine.sendMessage(CMD_DRIVER_LOADED); 303 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 304 mBackgroundScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 305 mSingleScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 306 mPnoScanStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 307 } 308 } 309 }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE)); 310 311 mBackgroundScanStateMachine.start(); 312 mWifiChangeStateMachine.start(); 313 mSingleScanStateMachine.start(); 314 mPnoScanStateMachine.start(); 315 } 316 isWorkSourceValid(WorkSource workSource)317 private static boolean isWorkSourceValid(WorkSource workSource) { 318 return workSource != null && workSource.size() > 0 && workSource.get(0) >= 0; 319 } 320 computeWorkSource(ClientInfo ci, WorkSource requestedWorkSource)321 private WorkSource computeWorkSource(ClientInfo ci, WorkSource requestedWorkSource) { 322 if (requestedWorkSource != null) { 323 if (isWorkSourceValid(requestedWorkSource)) { 324 // Wifi currently doesn't use names, so need to clear names out of the 325 // supplied WorkSource to allow future WorkSource combining. 326 requestedWorkSource.clearNames(); 327 return requestedWorkSource; 328 } else { 329 loge("Got invalid work source request: " + requestedWorkSource.toString() + 330 " from " + ci); 331 } 332 } 333 WorkSource callingWorkSource = new WorkSource(ci.getUid()); 334 if (isWorkSourceValid(callingWorkSource)) { 335 return callingWorkSource; 336 } else { 337 loge("Client has invalid work source: " + callingWorkSource); 338 return new WorkSource(); 339 } 340 } 341 342 private class RequestInfo<T> { 343 final ClientInfo clientInfo; 344 final int handlerId; 345 final WorkSource workSource; 346 final T settings; 347 RequestInfo(ClientInfo clientInfo, int handlerId, WorkSource requestedWorkSource, T settings)348 RequestInfo(ClientInfo clientInfo, int handlerId, WorkSource requestedWorkSource, 349 T settings) { 350 this.clientInfo = clientInfo; 351 this.handlerId = handlerId; 352 this.settings = settings; 353 this.workSource = computeWorkSource(clientInfo, requestedWorkSource); 354 } 355 reportEvent(int what, int arg1, Object obj)356 void reportEvent(int what, int arg1, Object obj) { 357 clientInfo.reportEvent(what, arg1, handlerId, obj); 358 } 359 } 360 361 private class RequestList<T> extends ArrayList<RequestInfo<T>> { addRequest(ClientInfo ci, int handler, WorkSource reqworkSource, T settings)362 void addRequest(ClientInfo ci, int handler, WorkSource reqworkSource, T settings) { 363 add(new RequestInfo<T>(ci, handler, reqworkSource, settings)); 364 } 365 removeRequest(ClientInfo ci, int handlerId)366 T removeRequest(ClientInfo ci, int handlerId) { 367 T removed = null; 368 Iterator<RequestInfo<T>> iter = iterator(); 369 while (iter.hasNext()) { 370 RequestInfo<T> entry = iter.next(); 371 if (entry.clientInfo == ci && entry.handlerId == handlerId) { 372 removed = entry.settings; 373 iter.remove(); 374 } 375 } 376 return removed; 377 } 378 getAllSettings()379 Collection<T> getAllSettings() { 380 ArrayList<T> settingsList = new ArrayList<>(); 381 Iterator<RequestInfo<T>> iter = iterator(); 382 while (iter.hasNext()) { 383 RequestInfo<T> entry = iter.next(); 384 settingsList.add(entry.settings); 385 } 386 return settingsList; 387 } 388 getAllSettingsForClient(ClientInfo ci)389 Collection<T> getAllSettingsForClient(ClientInfo ci) { 390 ArrayList<T> settingsList = new ArrayList<>(); 391 Iterator<RequestInfo<T>> iter = iterator(); 392 while (iter.hasNext()) { 393 RequestInfo<T> entry = iter.next(); 394 if (entry.clientInfo == ci) { 395 settingsList.add(entry.settings); 396 } 397 } 398 return settingsList; 399 } 400 removeAllForClient(ClientInfo ci)401 void removeAllForClient(ClientInfo ci) { 402 Iterator<RequestInfo<T>> iter = iterator(); 403 while (iter.hasNext()) { 404 RequestInfo<T> entry = iter.next(); 405 if (entry.clientInfo == ci) { 406 iter.remove(); 407 } 408 } 409 } 410 createMergedWorkSource()411 WorkSource createMergedWorkSource() { 412 WorkSource mergedSource = new WorkSource(); 413 for (RequestInfo<T> entry : this) { 414 mergedSource.add(entry.workSource); 415 } 416 return mergedSource; 417 } 418 } 419 420 /** 421 * State machine that holds the state of single scans. Scans should only be active in the 422 * ScanningState. The pending scans and active scans maps are swaped when entering 423 * ScanningState. Any requests queued while scanning will be placed in the pending queue and 424 * executed after transitioning back to IdleState. 425 */ 426 class WifiSingleScanStateMachine extends StateMachine implements WifiNative.ScanEventHandler { 427 private final DefaultState mDefaultState = new DefaultState(); 428 private final DriverStartedState mDriverStartedState = new DriverStartedState(); 429 private final IdleState mIdleState = new IdleState(); 430 private final ScanningState mScanningState = new ScanningState(); 431 432 private WifiNative.ScanSettings mActiveScanSettings = null; 433 private RequestList<ScanSettings> mActiveScans = new RequestList<>(); 434 private RequestList<ScanSettings> mPendingScans = new RequestList<>(); 435 WifiSingleScanStateMachine(Looper looper)436 WifiSingleScanStateMachine(Looper looper) { 437 super("WifiSingleScanStateMachine", looper); 438 439 setLogRecSize(128); 440 setLogOnlyTransitions(false); 441 442 // CHECKSTYLE:OFF IndentationCheck 443 addState(mDefaultState); 444 addState(mDriverStartedState, mDefaultState); 445 addState(mIdleState, mDriverStartedState); 446 addState(mScanningState, mDriverStartedState); 447 // CHECKSTYLE:ON IndentationCheck 448 449 setInitialState(mDefaultState); 450 } 451 452 /** 453 * Called to indicate a change in state for the current scan. 454 * Will dispatch a coresponding event to the state machine 455 */ 456 @Override onScanStatus(int event)457 public void onScanStatus(int event) { 458 if (DBG) localLog("onScanStatus event received, event=" + event); 459 switch(event) { 460 case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE: 461 case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS: 462 case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT: 463 sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 464 break; 465 case WifiNative.WIFI_SCAN_FAILED: 466 sendMessage(CMD_SCAN_FAILED); 467 break; 468 default: 469 Log.e(TAG, "Unknown scan status event: " + event); 470 break; 471 } 472 } 473 474 /** 475 * Called for each full scan result if requested 476 */ 477 @Override onFullScanResult(ScanResult fullScanResult, int bucketsScanned)478 public void onFullScanResult(ScanResult fullScanResult, int bucketsScanned) { 479 if (DBG) localLog("onFullScanResult received"); 480 sendMessage(CMD_FULL_SCAN_RESULTS, 0, bucketsScanned, fullScanResult); 481 } 482 483 @Override onScanPaused(ScanData[] scanData)484 public void onScanPaused(ScanData[] scanData) { 485 // should not happen for single scan 486 Log.e(TAG, "Got scan paused for single scan"); 487 } 488 489 @Override onScanRestarted()490 public void onScanRestarted() { 491 // should not happen for single scan 492 Log.e(TAG, "Got scan restarted for single scan"); 493 } 494 495 class DefaultState extends State { 496 @Override enter()497 public void enter() { 498 mActiveScans.clear(); 499 mPendingScans.clear(); 500 } 501 @Override processMessage(Message msg)502 public boolean processMessage(Message msg) { 503 switch (msg.what) { 504 case CMD_DRIVER_LOADED: 505 transitionTo(mIdleState); 506 return HANDLED; 507 case CMD_DRIVER_UNLOADED: 508 transitionTo(mDefaultState); 509 return HANDLED; 510 case WifiScanner.CMD_START_SINGLE_SCAN: 511 case WifiScanner.CMD_STOP_SINGLE_SCAN: 512 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available"); 513 return HANDLED; 514 case CMD_SCAN_RESULTS_AVAILABLE: 515 if (DBG) localLog("ignored scan results available event"); 516 return HANDLED; 517 case CMD_FULL_SCAN_RESULTS: 518 if (DBG) localLog("ignored full scan result event"); 519 return HANDLED; 520 default: 521 return NOT_HANDLED; 522 } 523 524 } 525 } 526 527 /** 528 * State representing when the driver is running. This state is not meant to be transitioned 529 * directly, but is instead indented as a parent state of ScanningState and IdleState 530 * to hold common functionality and handle cleaning up scans when the driver is shut down. 531 */ 532 class DriverStartedState extends State { 533 @Override exit()534 public void exit() { 535 mWifiMetrics.incrementScanReturnEntry( 536 WifiMetricsProto.WifiLog.SCAN_FAILURE_INTERRUPTED, 537 mPendingScans.size()); 538 sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED, 539 "Scan was interrupted"); 540 } 541 542 @Override processMessage(Message msg)543 public boolean processMessage(Message msg) { 544 ClientInfo ci = mClients.get(msg.replyTo); 545 546 switch (msg.what) { 547 case WifiScanner.CMD_START_SINGLE_SCAN: 548 mWifiMetrics.incrementOneshotScanCount(); 549 int handler = msg.arg2; 550 Bundle scanParams = (Bundle) msg.obj; 551 if (scanParams == null) { 552 logCallback("singleScanInvalidRequest", ci, handler, "null params"); 553 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 554 return HANDLED; 555 } 556 scanParams.setDefusable(true); 557 ScanSettings scanSettings = 558 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY); 559 WorkSource workSource = 560 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY); 561 if (validateScanRequest(ci, handler, scanSettings, workSource)) { 562 logScanRequest("addSingleScanRequest", ci, handler, workSource, 563 scanSettings, null); 564 replySucceeded(msg); 565 566 // If there is an active scan that will fulfill the scan request then 567 // mark this request as an active scan, otherwise mark it pending. 568 // If were not currently scanning then try to start a scan. Otherwise 569 // this scan will be scheduled when transitioning back to IdleState 570 // after finishing the current scan. 571 if (getCurrentState() == mScanningState) { 572 if (activeScanSatisfies(scanSettings)) { 573 mActiveScans.addRequest(ci, handler, workSource, scanSettings); 574 } else { 575 mPendingScans.addRequest(ci, handler, workSource, scanSettings); 576 } 577 } else { 578 mPendingScans.addRequest(ci, handler, workSource, scanSettings); 579 tryToStartNewScan(); 580 } 581 } else { 582 logCallback("singleScanInvalidRequest", ci, handler, "bad request"); 583 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 584 mWifiMetrics.incrementScanReturnEntry( 585 WifiMetricsProto.WifiLog.SCAN_FAILURE_INVALID_CONFIGURATION, 1); 586 } 587 return HANDLED; 588 case WifiScanner.CMD_STOP_SINGLE_SCAN: 589 removeSingleScanRequest(ci, msg.arg2); 590 return HANDLED; 591 default: 592 return NOT_HANDLED; 593 } 594 } 595 } 596 597 class IdleState extends State { 598 @Override enter()599 public void enter() { 600 tryToStartNewScan(); 601 } 602 603 @Override processMessage(Message msg)604 public boolean processMessage(Message msg) { 605 return NOT_HANDLED; 606 } 607 } 608 609 class ScanningState extends State { 610 private WorkSource mScanWorkSource; 611 612 @Override enter()613 public void enter() { 614 mScanWorkSource = mActiveScans.createMergedWorkSource(); 615 try { 616 mBatteryStats.noteWifiScanStartedFromSource(mScanWorkSource); 617 } catch (RemoteException e) { 618 loge(e.toString()); 619 } 620 } 621 622 @Override exit()623 public void exit() { 624 mActiveScanSettings = null; 625 try { 626 mBatteryStats.noteWifiScanStoppedFromSource(mScanWorkSource); 627 } catch (RemoteException e) { 628 loge(e.toString()); 629 } 630 631 // if any scans are still active (never got results available then indicate failure) 632 mWifiMetrics.incrementScanReturnEntry( 633 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, 634 mActiveScans.size()); 635 sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED, 636 "Scan was interrupted"); 637 } 638 639 @Override processMessage(Message msg)640 public boolean processMessage(Message msg) { 641 switch (msg.what) { 642 case CMD_SCAN_RESULTS_AVAILABLE: 643 mWifiMetrics.incrementScanReturnEntry( 644 WifiMetricsProto.WifiLog.SCAN_SUCCESS, 645 mActiveScans.size()); 646 reportScanResults(mScannerImpl.getLatestSingleScanResults()); 647 mActiveScans.clear(); 648 transitionTo(mIdleState); 649 return HANDLED; 650 case CMD_FULL_SCAN_RESULTS: 651 reportFullScanResult((ScanResult) msg.obj, /* bucketsScanned */ msg.arg2); 652 return HANDLED; 653 case CMD_SCAN_FAILED: 654 mWifiMetrics.incrementScanReturnEntry( 655 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mActiveScans.size()); 656 sendOpFailedToAllAndClear(mActiveScans, WifiScanner.REASON_UNSPECIFIED, 657 "Scan failed"); 658 transitionTo(mIdleState); 659 return HANDLED; 660 default: 661 return NOT_HANDLED; 662 } 663 } 664 } 665 validateScanRequest(ClientInfo ci, int handler, ScanSettings settings, WorkSource workSource)666 boolean validateScanRequest(ClientInfo ci, int handler, ScanSettings settings, 667 WorkSource workSource) { 668 if (ci == null) { 669 Log.d(TAG, "Failing single scan request ClientInfo not found " + handler); 670 return false; 671 } 672 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED) { 673 if (settings.channels == null || settings.channels.length == 0) { 674 Log.d(TAG, "Failing single scan because channel list was empty"); 675 return false; 676 } 677 } 678 return true; 679 } 680 activeScanSatisfies(ScanSettings settings)681 boolean activeScanSatisfies(ScanSettings settings) { 682 if (mActiveScanSettings == null) { 683 return false; 684 } 685 686 // there is always one bucket for a single scan 687 WifiNative.BucketSettings activeBucket = mActiveScanSettings.buckets[0]; 688 689 // validate that all requested channels are being scanned 690 ChannelCollection activeChannels = mChannelHelper.createChannelCollection(); 691 activeChannels.addChannels(activeBucket); 692 if (!activeChannels.containsSettings(settings)) { 693 return false; 694 } 695 696 // if the request is for a full scan, but there is no ongoing full scan 697 if ((settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) != 0 698 && (activeBucket.report_events & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) 699 == 0) { 700 return false; 701 } 702 703 if (settings.hiddenNetworkIds != null) { 704 if (mActiveScanSettings.hiddenNetworkIds == null) { 705 return false; 706 } 707 Set<Integer> activeHiddenNetworkIds = new HashSet<>(); 708 for (int id : mActiveScanSettings.hiddenNetworkIds) { 709 activeHiddenNetworkIds.add(id); 710 } 711 for (int id : settings.hiddenNetworkIds) { 712 if (!activeHiddenNetworkIds.contains(id)) { 713 return false; 714 } 715 } 716 } 717 718 return true; 719 } 720 removeSingleScanRequest(ClientInfo ci, int handler)721 void removeSingleScanRequest(ClientInfo ci, int handler) { 722 if (ci != null) { 723 logScanRequest("removeSingleScanRequest", ci, handler, null, null, null); 724 mPendingScans.removeRequest(ci, handler); 725 mActiveScans.removeRequest(ci, handler); 726 } 727 } 728 removeSingleScanRequests(ClientInfo ci)729 void removeSingleScanRequests(ClientInfo ci) { 730 if (ci != null) { 731 logScanRequest("removeSingleScanRequests", ci, -1, null, null, null); 732 mPendingScans.removeAllForClient(ci); 733 mActiveScans.removeAllForClient(ci); 734 } 735 } 736 tryToStartNewScan()737 void tryToStartNewScan() { 738 if (mPendingScans.size() == 0) { // no pending requests 739 return; 740 } 741 mChannelHelper.updateChannels(); 742 // TODO move merging logic to a scheduler 743 WifiNative.ScanSettings settings = new WifiNative.ScanSettings(); 744 settings.num_buckets = 1; 745 WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); 746 bucketSettings.bucket = 0; 747 bucketSettings.period_ms = 0; 748 bucketSettings.report_events = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 749 750 ChannelCollection channels = mChannelHelper.createChannelCollection(); 751 HashSet<Integer> hiddenNetworkIdSet = new HashSet<>(); 752 for (RequestInfo<ScanSettings> entry : mPendingScans) { 753 channels.addChannels(entry.settings); 754 if (entry.settings.hiddenNetworkIds != null) { 755 for (int i = 0; i < entry.settings.hiddenNetworkIds.length; i++) { 756 hiddenNetworkIdSet.add(entry.settings.hiddenNetworkIds[i]); 757 } 758 } 759 if ((entry.settings.reportEvents & WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT) 760 != 0) { 761 bucketSettings.report_events |= WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT; 762 } 763 } 764 if (hiddenNetworkIdSet.size() > 0) { 765 settings.hiddenNetworkIds = new int[hiddenNetworkIdSet.size()]; 766 int numHiddenNetworks = 0; 767 for (Integer hiddenNetworkId : hiddenNetworkIdSet) { 768 settings.hiddenNetworkIds[numHiddenNetworks++] = hiddenNetworkId; 769 } 770 } 771 772 channels.fillBucketSettings(bucketSettings, Integer.MAX_VALUE); 773 774 settings.buckets = new WifiNative.BucketSettings[] {bucketSettings}; 775 if (mScannerImpl.startSingleScan(settings, this)) { 776 // store the active scan settings 777 mActiveScanSettings = settings; 778 // swap pending and active scan requests 779 RequestList<ScanSettings> tmp = mActiveScans; 780 mActiveScans = mPendingScans; 781 mPendingScans = tmp; 782 // make sure that the pending list is clear 783 mPendingScans.clear(); 784 transitionTo(mScanningState); 785 } else { 786 mWifiMetrics.incrementScanReturnEntry( 787 WifiMetricsProto.WifiLog.SCAN_UNKNOWN, mPendingScans.size()); 788 // notify and cancel failed scans 789 sendOpFailedToAllAndClear(mPendingScans, WifiScanner.REASON_UNSPECIFIED, 790 "Failed to start single scan"); 791 } 792 } 793 sendOpFailedToAllAndClear(RequestList<?> clientHandlers, int reason, String description)794 void sendOpFailedToAllAndClear(RequestList<?> clientHandlers, int reason, 795 String description) { 796 for (RequestInfo<?> entry : clientHandlers) { 797 logCallback("singleScanFailed", entry.clientInfo, entry.handlerId, 798 "reason=" + reason + ", " + description); 799 entry.reportEvent(WifiScanner.CMD_OP_FAILED, 0, 800 new WifiScanner.OperationResult(reason, description)); 801 } 802 clientHandlers.clear(); 803 } 804 reportFullScanResult(ScanResult result, int bucketsScanned)805 void reportFullScanResult(ScanResult result, int bucketsScanned) { 806 for (RequestInfo<ScanSettings> entry : mActiveScans) { 807 if (ScanScheduleUtil.shouldReportFullScanResultForSettings(mChannelHelper, 808 result, bucketsScanned, entry.settings, -1)) { 809 entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result); 810 } 811 } 812 813 for (RequestInfo<Void> entry : mSingleScanListeners) { 814 entry.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, result); 815 } 816 } 817 reportScanResults(ScanData results)818 void reportScanResults(ScanData results) { 819 if (results != null && results.getResults() != null) { 820 if (results.getResults().length > 0) { 821 mWifiMetrics.incrementNonEmptyScanResultCount(); 822 } else { 823 mWifiMetrics.incrementEmptyScanResultCount(); 824 } 825 } 826 ScanData[] allResults = new ScanData[] {results}; 827 for (RequestInfo<ScanSettings> entry : mActiveScans) { 828 ScanData[] resultsToDeliver = ScanScheduleUtil.filterResultsForSettings( 829 mChannelHelper, allResults, entry.settings, -1); 830 WifiScanner.ParcelableScanData parcelableResultsToDeliver = 831 new WifiScanner.ParcelableScanData(resultsToDeliver); 832 logCallback("singleScanResults", entry.clientInfo, entry.handlerId, 833 describeForLog(resultsToDeliver)); 834 entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableResultsToDeliver); 835 // make sure the handler is removed 836 entry.reportEvent(WifiScanner.CMD_SINGLE_SCAN_COMPLETED, 0, null); 837 } 838 839 WifiScanner.ParcelableScanData parcelableAllResults = 840 new WifiScanner.ParcelableScanData(allResults); 841 for (RequestInfo<Void> entry : mSingleScanListeners) { 842 logCallback("singleScanResults", entry.clientInfo, entry.handlerId, 843 describeForLog(allResults)); 844 entry.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, parcelableAllResults); 845 } 846 } 847 } 848 849 class WifiBackgroundScanStateMachine extends StateMachine 850 implements WifiNative.ScanEventHandler, WifiNative.HotlistEventHandler { 851 852 private final DefaultState mDefaultState = new DefaultState(); 853 private final StartedState mStartedState = new StartedState(); 854 private final PausedState mPausedState = new PausedState(); 855 856 private final RequestList<ScanSettings> mActiveBackgroundScans = new RequestList<>(); 857 private final RequestList<WifiScanner.HotlistSettings> mActiveHotlistSettings = 858 new RequestList<>(); 859 WifiBackgroundScanStateMachine(Looper looper)860 WifiBackgroundScanStateMachine(Looper looper) { 861 super("WifiBackgroundScanStateMachine", looper); 862 863 setLogRecSize(512); 864 setLogOnlyTransitions(false); 865 866 // CHECKSTYLE:OFF IndentationCheck 867 addState(mDefaultState); 868 addState(mStartedState, mDefaultState); 869 addState(mPausedState, mDefaultState); 870 // CHECKSTYLE:ON IndentationCheck 871 872 setInitialState(mDefaultState); 873 } 874 getBackgroundScanSettings(ClientInfo ci)875 public Collection<ScanSettings> getBackgroundScanSettings(ClientInfo ci) { 876 return mActiveBackgroundScans.getAllSettingsForClient(ci); 877 } 878 removeBackgroundScanSettings(ClientInfo ci)879 public void removeBackgroundScanSettings(ClientInfo ci) { 880 mActiveBackgroundScans.removeAllForClient(ci); 881 updateSchedule(); 882 } 883 removeHotlistSettings(ClientInfo ci)884 public void removeHotlistSettings(ClientInfo ci) { 885 mActiveHotlistSettings.removeAllForClient(ci); 886 resetHotlist(); 887 } 888 889 @Override onScanStatus(int event)890 public void onScanStatus(int event) { 891 if (DBG) localLog("onScanStatus event received, event=" + event); 892 switch(event) { 893 case WifiNative.WIFI_SCAN_RESULTS_AVAILABLE: 894 case WifiNative.WIFI_SCAN_THRESHOLD_NUM_SCANS: 895 case WifiNative.WIFI_SCAN_THRESHOLD_PERCENT: 896 sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 897 break; 898 case WifiNative.WIFI_SCAN_FAILED: 899 sendMessage(CMD_SCAN_FAILED); 900 break; 901 default: 902 Log.e(TAG, "Unknown scan status event: " + event); 903 break; 904 } 905 } 906 907 @Override onFullScanResult(ScanResult fullScanResult, int bucketsScanned)908 public void onFullScanResult(ScanResult fullScanResult, int bucketsScanned) { 909 if (DBG) localLog("onFullScanResult received"); 910 sendMessage(CMD_FULL_SCAN_RESULTS, 0, bucketsScanned, fullScanResult); 911 } 912 913 @Override onScanPaused(ScanData scanData[])914 public void onScanPaused(ScanData scanData[]) { 915 if (DBG) localLog("onScanPaused received"); 916 sendMessage(CMD_SCAN_PAUSED, scanData); 917 } 918 919 @Override onScanRestarted()920 public void onScanRestarted() { 921 if (DBG) localLog("onScanRestarted received"); 922 sendMessage(CMD_SCAN_RESTARTED); 923 } 924 925 @Override onHotlistApFound(ScanResult[] results)926 public void onHotlistApFound(ScanResult[] results) { 927 if (DBG) localLog("onHotlistApFound event received"); 928 sendMessage(CMD_HOTLIST_AP_FOUND, 0, 0, results); 929 } 930 931 @Override onHotlistApLost(ScanResult[] results)932 public void onHotlistApLost(ScanResult[] results) { 933 if (DBG) localLog("onHotlistApLost event received"); 934 sendMessage(CMD_HOTLIST_AP_LOST, 0, 0, results); 935 } 936 937 class DefaultState extends State { 938 @Override enter()939 public void enter() { 940 if (DBG) localLog("DefaultState"); 941 mActiveBackgroundScans.clear(); 942 mActiveHotlistSettings.clear(); 943 } 944 945 @Override processMessage(Message msg)946 public boolean processMessage(Message msg) { 947 switch (msg.what) { 948 case CMD_DRIVER_LOADED: 949 // TODO this should be moved to a common location since it is used outside 950 // of this state machine. It is ok right now because the driver loaded event 951 // is sent to this state machine first. 952 if (mScannerImpl == null) { 953 mScannerImpl = mScannerImplFactory.create(mContext, mLooper, mClock); 954 mChannelHelper = mScannerImpl.getChannelHelper(); 955 } 956 957 mBackgroundScheduler = new BackgroundScanScheduler(mChannelHelper); 958 959 WifiNative.ScanCapabilities capabilities = 960 new WifiNative.ScanCapabilities(); 961 if (!mScannerImpl.getScanCapabilities(capabilities)) { 962 loge("could not get scan capabilities"); 963 return HANDLED; 964 } 965 mBackgroundScheduler.setMaxBuckets(capabilities.max_scan_buckets); 966 mBackgroundScheduler.setMaxApPerScan(capabilities.max_ap_cache_per_scan); 967 968 Log.i(TAG, "wifi driver loaded with scan capabilities: " 969 + "max buckets=" + capabilities.max_scan_buckets); 970 971 transitionTo(mStartedState); 972 return HANDLED; 973 case CMD_DRIVER_UNLOADED: 974 Log.i(TAG, "wifi driver unloaded"); 975 transitionTo(mDefaultState); 976 break; 977 case WifiScanner.CMD_START_BACKGROUND_SCAN: 978 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 979 case WifiScanner.CMD_START_SINGLE_SCAN: 980 case WifiScanner.CMD_STOP_SINGLE_SCAN: 981 case WifiScanner.CMD_SET_HOTLIST: 982 case WifiScanner.CMD_RESET_HOTLIST: 983 case WifiScanner.CMD_GET_SCAN_RESULTS: 984 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available"); 985 break; 986 987 case CMD_SCAN_RESULTS_AVAILABLE: 988 if (DBG) localLog("ignored scan results available event"); 989 break; 990 991 case CMD_FULL_SCAN_RESULTS: 992 if (DBG) localLog("ignored full scan result event"); 993 break; 994 995 default: 996 break; 997 } 998 999 return HANDLED; 1000 } 1001 } 1002 1003 class StartedState extends State { 1004 1005 @Override enter()1006 public void enter() { 1007 if (DBG) localLog("StartedState"); 1008 } 1009 1010 @Override exit()1011 public void exit() { 1012 sendBackgroundScanFailedToAllAndClear( 1013 WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted"); 1014 sendHotlistFailedToAllAndClear( 1015 WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted"); 1016 mScannerImpl.cleanup(); 1017 } 1018 1019 @Override processMessage(Message msg)1020 public boolean processMessage(Message msg) { 1021 ClientInfo ci = mClients.get(msg.replyTo); 1022 1023 switch (msg.what) { 1024 case CMD_DRIVER_LOADED: 1025 return NOT_HANDLED; 1026 case CMD_DRIVER_UNLOADED: 1027 return NOT_HANDLED; 1028 case WifiScanner.CMD_START_BACKGROUND_SCAN: { 1029 mWifiMetrics.incrementBackgroundScanCount(); 1030 Bundle scanParams = (Bundle) msg.obj; 1031 if (scanParams == null) { 1032 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1033 return HANDLED; 1034 } 1035 scanParams.setDefusable(true); 1036 ScanSettings scanSettings = 1037 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY); 1038 WorkSource workSource = 1039 scanParams.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY); 1040 if (addBackgroundScanRequest(ci, msg.arg2, scanSettings, workSource)) { 1041 replySucceeded(msg); 1042 } else { 1043 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1044 } 1045 break; 1046 } 1047 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 1048 removeBackgroundScanRequest(ci, msg.arg2); 1049 break; 1050 case WifiScanner.CMD_GET_SCAN_RESULTS: 1051 reportScanResults(mScannerImpl.getLatestBatchedScanResults(true)); 1052 replySucceeded(msg); 1053 break; 1054 case WifiScanner.CMD_SET_HOTLIST: 1055 if (addHotlist(ci, msg.arg2, (WifiScanner.HotlistSettings) msg.obj)) { 1056 replySucceeded(msg); 1057 } else { 1058 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1059 } 1060 break; 1061 case WifiScanner.CMD_RESET_HOTLIST: 1062 removeHotlist(ci, msg.arg2); 1063 break; 1064 case CMD_SCAN_RESULTS_AVAILABLE: 1065 reportScanResults(mScannerImpl.getLatestBatchedScanResults(true)); 1066 break; 1067 case CMD_FULL_SCAN_RESULTS: 1068 reportFullScanResult((ScanResult) msg.obj, /* bucketsScanned */ msg.arg2); 1069 break; 1070 case CMD_HOTLIST_AP_FOUND: 1071 reportHotlistResults(WifiScanner.CMD_AP_FOUND, (ScanResult[]) msg.obj); 1072 break; 1073 case CMD_HOTLIST_AP_LOST: 1074 reportHotlistResults(WifiScanner.CMD_AP_LOST, (ScanResult[]) msg.obj); 1075 break; 1076 case CMD_SCAN_PAUSED: 1077 reportScanResults((ScanData[]) msg.obj); 1078 transitionTo(mPausedState); 1079 break; 1080 case CMD_SCAN_FAILED: 1081 Log.e(TAG, "WifiScanner background scan gave CMD_SCAN_FAILED"); 1082 sendBackgroundScanFailedToAllAndClear( 1083 WifiScanner.REASON_UNSPECIFIED, "Background Scan failed"); 1084 break; 1085 default: 1086 return NOT_HANDLED; 1087 } 1088 1089 return HANDLED; 1090 } 1091 } 1092 1093 class PausedState extends State { 1094 @Override enter()1095 public void enter() { 1096 if (DBG) localLog("PausedState"); 1097 } 1098 1099 @Override processMessage(Message msg)1100 public boolean processMessage(Message msg) { 1101 switch (msg.what) { 1102 case CMD_SCAN_RESTARTED: 1103 transitionTo(mStartedState); 1104 break; 1105 default: 1106 deferMessage(msg); 1107 break; 1108 } 1109 return HANDLED; 1110 } 1111 } 1112 addBackgroundScanRequest(ClientInfo ci, int handler, ScanSettings settings, WorkSource workSource)1113 private boolean addBackgroundScanRequest(ClientInfo ci, int handler, 1114 ScanSettings settings, WorkSource workSource) { 1115 // sanity check the input 1116 if (ci == null) { 1117 Log.d(TAG, "Failing scan request ClientInfo not found " + handler); 1118 return false; 1119 } 1120 if (settings.periodInMs < WifiScanner.MIN_SCAN_PERIOD_MS) { 1121 loge("Failing scan request because periodInMs is " + settings.periodInMs 1122 + ", min scan period is: " + WifiScanner.MIN_SCAN_PERIOD_MS); 1123 return false; 1124 } 1125 1126 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED && settings.channels == null) { 1127 loge("Channels was null with unspecified band"); 1128 return false; 1129 } 1130 1131 if (settings.band == WifiScanner.WIFI_BAND_UNSPECIFIED 1132 && settings.channels.length == 0) { 1133 loge("No channels specified"); 1134 return false; 1135 } 1136 1137 int minSupportedPeriodMs = mChannelHelper.estimateScanDuration(settings); 1138 if (settings.periodInMs < minSupportedPeriodMs) { 1139 loge("Failing scan request because minSupportedPeriodMs is " 1140 + minSupportedPeriodMs + " but the request wants " + settings.periodInMs); 1141 return false; 1142 } 1143 1144 // check truncated binary exponential back off scan settings 1145 if (settings.maxPeriodInMs != 0 && settings.maxPeriodInMs != settings.periodInMs) { 1146 if (settings.maxPeriodInMs < settings.periodInMs) { 1147 loge("Failing scan request because maxPeriodInMs is " + settings.maxPeriodInMs 1148 + " but less than periodInMs " + settings.periodInMs); 1149 return false; 1150 } 1151 if (settings.maxPeriodInMs > WifiScanner.MAX_SCAN_PERIOD_MS) { 1152 loge("Failing scan request because maxSupportedPeriodMs is " 1153 + WifiScanner.MAX_SCAN_PERIOD_MS + " but the request wants " 1154 + settings.maxPeriodInMs); 1155 return false; 1156 } 1157 if (settings.stepCount < 1) { 1158 loge("Failing scan request because stepCount is " + settings.stepCount 1159 + " which is less than 1"); 1160 return false; 1161 } 1162 } 1163 1164 logScanRequest("addBackgroundScanRequest", ci, handler, null, settings, null); 1165 mActiveBackgroundScans.addRequest(ci, handler, workSource, settings); 1166 1167 if (updateSchedule()) { 1168 return true; 1169 } else { 1170 mActiveBackgroundScans.removeRequest(ci, handler); 1171 localLog("Failing scan request because failed to reset scan"); 1172 return false; 1173 } 1174 } 1175 updateSchedule()1176 private boolean updateSchedule() { 1177 if (mChannelHelper == null || mBackgroundScheduler == null || mScannerImpl == null) { 1178 loge("Failed to update schedule because WifiScanningService is not initialized"); 1179 return false; 1180 } 1181 mChannelHelper.updateChannels(); 1182 Collection<ScanSettings> settings = mActiveBackgroundScans.getAllSettings(); 1183 1184 mBackgroundScheduler.updateSchedule(settings); 1185 WifiNative.ScanSettings schedule = mBackgroundScheduler.getSchedule(); 1186 1187 if (ScanScheduleUtil.scheduleEquals(mPreviousSchedule, schedule)) { 1188 if (DBG) Log.d(TAG, "schedule updated with no change"); 1189 return true; 1190 } 1191 1192 mPreviousSchedule = schedule; 1193 1194 if (schedule.num_buckets == 0) { 1195 mScannerImpl.stopBatchedScan(); 1196 if (DBG) Log.d(TAG, "scan stopped"); 1197 return true; 1198 } else { 1199 localLog("starting scan: " 1200 + "base period=" + schedule.base_period_ms 1201 + ", max ap per scan=" + schedule.max_ap_per_scan 1202 + ", batched scans=" + schedule.report_threshold_num_scans); 1203 for (int b = 0; b < schedule.num_buckets; b++) { 1204 WifiNative.BucketSettings bucket = schedule.buckets[b]; 1205 localLog("bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)" 1206 + "[" + bucket.report_events + "]: " 1207 + ChannelHelper.toString(bucket)); 1208 } 1209 1210 if (mScannerImpl.startBatchedScan(schedule, this)) { 1211 if (DBG) { 1212 Log.d(TAG, "scan restarted with " + schedule.num_buckets 1213 + " bucket(s) and base period: " + schedule.base_period_ms); 1214 } 1215 return true; 1216 } else { 1217 mPreviousSchedule = null; 1218 loge("error starting scan: " 1219 + "base period=" + schedule.base_period_ms 1220 + ", max ap per scan=" + schedule.max_ap_per_scan 1221 + ", batched scans=" + schedule.report_threshold_num_scans); 1222 for (int b = 0; b < schedule.num_buckets; b++) { 1223 WifiNative.BucketSettings bucket = schedule.buckets[b]; 1224 loge("bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)" 1225 + "[" + bucket.report_events + "]: " 1226 + ChannelHelper.toString(bucket)); 1227 } 1228 return false; 1229 } 1230 } 1231 } 1232 removeBackgroundScanRequest(ClientInfo ci, int handler)1233 private void removeBackgroundScanRequest(ClientInfo ci, int handler) { 1234 if (ci != null) { 1235 ScanSettings settings = mActiveBackgroundScans.removeRequest(ci, handler); 1236 logScanRequest("removeBackgroundScanRequest", ci, handler, null, settings, null); 1237 updateSchedule(); 1238 } 1239 } 1240 reportFullScanResult(ScanResult result, int bucketsScanned)1241 private void reportFullScanResult(ScanResult result, int bucketsScanned) { 1242 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 1243 ClientInfo ci = entry.clientInfo; 1244 int handler = entry.handlerId; 1245 ScanSettings settings = entry.settings; 1246 if (mBackgroundScheduler.shouldReportFullScanResultForSettings( 1247 result, bucketsScanned, settings)) { 1248 ScanResult newResult = new ScanResult(result); 1249 if (result.informationElements != null) { 1250 newResult.informationElements = result.informationElements.clone(); 1251 } 1252 else { 1253 newResult.informationElements = null; 1254 } 1255 ci.reportEvent(WifiScanner.CMD_FULL_SCAN_RESULT, 0, handler, newResult); 1256 } 1257 } 1258 } 1259 reportScanResults(ScanData[] results)1260 private void reportScanResults(ScanData[] results) { 1261 for (ScanData result : results) { 1262 if (result != null && result.getResults() != null) { 1263 if (result.getResults().length > 0) { 1264 mWifiMetrics.incrementNonEmptyScanResultCount(); 1265 } else { 1266 mWifiMetrics.incrementEmptyScanResultCount(); 1267 } 1268 } 1269 } 1270 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 1271 ClientInfo ci = entry.clientInfo; 1272 int handler = entry.handlerId; 1273 ScanSettings settings = entry.settings; 1274 ScanData[] resultsToDeliver = 1275 mBackgroundScheduler.filterResultsForSettings(results, settings); 1276 if (resultsToDeliver != null) { 1277 logCallback("backgroundScanResults", ci, handler, 1278 describeForLog(resultsToDeliver)); 1279 WifiScanner.ParcelableScanData parcelableScanData = 1280 new WifiScanner.ParcelableScanData(resultsToDeliver); 1281 ci.reportEvent(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanData); 1282 } 1283 } 1284 } 1285 sendBackgroundScanFailedToAllAndClear(int reason, String description)1286 private void sendBackgroundScanFailedToAllAndClear(int reason, String description) { 1287 for (RequestInfo<ScanSettings> entry : mActiveBackgroundScans) { 1288 ClientInfo ci = entry.clientInfo; 1289 int handler = entry.handlerId; 1290 ci.reportEvent(WifiScanner.CMD_OP_FAILED, 0, handler, 1291 new WifiScanner.OperationResult(reason, description)); 1292 } 1293 mActiveBackgroundScans.clear(); 1294 } 1295 addHotlist(ClientInfo ci, int handler, WifiScanner.HotlistSettings settings)1296 private boolean addHotlist(ClientInfo ci, int handler, 1297 WifiScanner.HotlistSettings settings) { 1298 if (ci == null) { 1299 Log.d(TAG, "Failing hotlist request ClientInfo not found " + handler); 1300 return false; 1301 } 1302 mActiveHotlistSettings.addRequest(ci, handler, null, settings); 1303 resetHotlist(); 1304 return true; 1305 } 1306 removeHotlist(ClientInfo ci, int handler)1307 private void removeHotlist(ClientInfo ci, int handler) { 1308 if (ci != null) { 1309 mActiveHotlistSettings.removeRequest(ci, handler); 1310 resetHotlist(); 1311 } 1312 } 1313 resetHotlist()1314 private void resetHotlist() { 1315 if (mScannerImpl == null) { 1316 loge("Failed to update hotlist because WifiScanningService is not initialized"); 1317 return; 1318 } 1319 1320 Collection<WifiScanner.HotlistSettings> settings = 1321 mActiveHotlistSettings.getAllSettings(); 1322 int num_hotlist_ap = 0; 1323 1324 for (WifiScanner.HotlistSettings s : settings) { 1325 num_hotlist_ap += s.bssidInfos.length; 1326 } 1327 1328 if (num_hotlist_ap == 0) { 1329 mScannerImpl.resetHotlist(); 1330 } else { 1331 BssidInfo[] bssidInfos = new BssidInfo[num_hotlist_ap]; 1332 int apLostThreshold = Integer.MAX_VALUE; 1333 int index = 0; 1334 for (WifiScanner.HotlistSettings s : settings) { 1335 for (int i = 0; i < s.bssidInfos.length; i++, index++) { 1336 bssidInfos[index] = s.bssidInfos[i]; 1337 } 1338 if (s.apLostThreshold < apLostThreshold) { 1339 apLostThreshold = s.apLostThreshold; 1340 } 1341 } 1342 1343 WifiScanner.HotlistSettings mergedSettings = new WifiScanner.HotlistSettings(); 1344 mergedSettings.bssidInfos = bssidInfos; 1345 mergedSettings.apLostThreshold = apLostThreshold; 1346 mScannerImpl.setHotlist(mergedSettings, this); 1347 } 1348 } 1349 reportHotlistResults(int what, ScanResult[] results)1350 private void reportHotlistResults(int what, ScanResult[] results) { 1351 if (DBG) localLog("reportHotlistResults " + what + " results " + results.length); 1352 for (RequestInfo<WifiScanner.HotlistSettings> entry : mActiveHotlistSettings) { 1353 ClientInfo ci = entry.clientInfo; 1354 int handler = entry.handlerId; 1355 WifiScanner.HotlistSettings settings = entry.settings; 1356 int num_results = 0; 1357 for (ScanResult result : results) { 1358 for (BssidInfo BssidInfo : settings.bssidInfos) { 1359 if (result.BSSID.equalsIgnoreCase(BssidInfo.bssid)) { 1360 num_results++; 1361 break; 1362 } 1363 } 1364 } 1365 if (num_results == 0) { 1366 // nothing to report 1367 return; 1368 } 1369 ScanResult[] results2 = new ScanResult[num_results]; 1370 int index = 0; 1371 for (ScanResult result : results) { 1372 for (BssidInfo BssidInfo : settings.bssidInfos) { 1373 if (result.BSSID.equalsIgnoreCase(BssidInfo.bssid)) { 1374 results2[index] = result; 1375 index++; 1376 } 1377 } 1378 } 1379 WifiScanner.ParcelableScanResults parcelableScanResults = 1380 new WifiScanner.ParcelableScanResults(results2); 1381 1382 ci.reportEvent(what, 0, handler, parcelableScanResults); 1383 } 1384 } 1385 sendHotlistFailedToAllAndClear(int reason, String description)1386 private void sendHotlistFailedToAllAndClear(int reason, String description) { 1387 for (RequestInfo<WifiScanner.HotlistSettings> entry : mActiveHotlistSettings) { 1388 ClientInfo ci = entry.clientInfo; 1389 int handler = entry.handlerId; 1390 ci.reportEvent(WifiScanner.CMD_OP_FAILED, 0, handler, 1391 new WifiScanner.OperationResult(reason, description)); 1392 } 1393 mActiveHotlistSettings.clear(); 1394 } 1395 } 1396 1397 /** 1398 * PNO scan state machine has 5 states: 1399 * -Default State 1400 * -Started State 1401 * -Hw Pno Scan state 1402 * -Single Scan state 1403 * -Sw Pno Scan state 1404 * 1405 * These are the main state transitions: 1406 * 1. Start at |Default State| 1407 * 2. Move to |Started State| when we get the |WIFI_SCAN_AVAILABLE| broadcast from WifiManager. 1408 * 3. When a new PNO scan request comes in: 1409 * a.1. Switch to |Hw Pno Scan state| when the device supports HW PNO 1410 * (This could either be HAL based ePNO or supplicant based PNO). 1411 * a.2. In |Hw Pno Scan state| when PNO scan results are received, check if the result 1412 * contains IE (information elements). If yes, send the results to the client, else 1413 * switch to |Single Scan state| and send the result to the client when the scan result 1414 * is obtained. 1415 * b.1. Switch to |Sw Pno Scan state| when the device does not supports HW PNO 1416 * (This is for older devices which do not support HW PNO and for connected PNO on 1417 * devices which support supplicant based PNO) 1418 * b.2. In |Sw Pno Scan state| send the result to the client when the background scan result 1419 * is obtained 1420 * 1421 * Note: PNO scans only work for a single client today. We don't have support in HW to support 1422 * multiple requests at the same time, so will need non-trivial changes to support (if at all 1423 * possible) in WifiScanningService. 1424 */ 1425 class WifiPnoScanStateMachine extends StateMachine implements WifiNative.PnoEventHandler { 1426 1427 private final DefaultState mDefaultState = new DefaultState(); 1428 private final StartedState mStartedState = new StartedState(); 1429 private final HwPnoScanState mHwPnoScanState = new HwPnoScanState(); 1430 private final SwPnoScanState mSwPnoScanState = new SwPnoScanState(); 1431 private final SingleScanState mSingleScanState = new SingleScanState(); 1432 private InternalClientInfo mInternalClientInfo; 1433 1434 private final RequestList<Pair<PnoSettings, ScanSettings>> mActivePnoScans = 1435 new RequestList<>(); 1436 WifiPnoScanStateMachine(Looper looper)1437 WifiPnoScanStateMachine(Looper looper) { 1438 super("WifiPnoScanStateMachine", looper); 1439 1440 setLogRecSize(512); 1441 setLogOnlyTransitions(false); 1442 1443 // CHECKSTYLE:OFF IndentationCheck 1444 addState(mDefaultState); 1445 addState(mStartedState, mDefaultState); 1446 addState(mHwPnoScanState, mStartedState); 1447 addState(mSingleScanState, mHwPnoScanState); 1448 addState(mSwPnoScanState, mStartedState); 1449 // CHECKSTYLE:ON IndentationCheck 1450 1451 setInitialState(mDefaultState); 1452 } 1453 removePnoSettings(ClientInfo ci)1454 public void removePnoSettings(ClientInfo ci) { 1455 mActivePnoScans.removeAllForClient(ci); 1456 transitionTo(mStartedState); 1457 } 1458 1459 @Override onPnoNetworkFound(ScanResult[] results)1460 public void onPnoNetworkFound(ScanResult[] results) { 1461 if (DBG) localLog("onWifiPnoNetworkFound event received"); 1462 sendMessage(CMD_PNO_NETWORK_FOUND, 0, 0, results); 1463 } 1464 1465 @Override onPnoScanFailed()1466 public void onPnoScanFailed() { 1467 if (DBG) localLog("onWifiPnoScanFailed event received"); 1468 sendMessage(CMD_PNO_SCAN_FAILED, 0, 0, null); 1469 } 1470 1471 class DefaultState extends State { 1472 @Override enter()1473 public void enter() { 1474 if (DBG) localLog("DefaultState"); 1475 } 1476 1477 @Override processMessage(Message msg)1478 public boolean processMessage(Message msg) { 1479 switch (msg.what) { 1480 case CMD_DRIVER_LOADED: 1481 transitionTo(mStartedState); 1482 break; 1483 case CMD_DRIVER_UNLOADED: 1484 transitionTo(mDefaultState); 1485 break; 1486 case WifiScanner.CMD_START_PNO_SCAN: 1487 case WifiScanner.CMD_STOP_PNO_SCAN: 1488 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "not available"); 1489 break; 1490 case CMD_PNO_NETWORK_FOUND: 1491 case CMD_PNO_SCAN_FAILED: 1492 case WifiScanner.CMD_SCAN_RESULT: 1493 case WifiScanner.CMD_OP_FAILED: 1494 loge("Unexpected message " + msg.what); 1495 break; 1496 default: 1497 return NOT_HANDLED; 1498 } 1499 return HANDLED; 1500 } 1501 } 1502 1503 class StartedState extends State { 1504 @Override enter()1505 public void enter() { 1506 if (DBG) localLog("StartedState"); 1507 } 1508 1509 @Override exit()1510 public void exit() { 1511 sendPnoScanFailedToAllAndClear( 1512 WifiScanner.REASON_UNSPECIFIED, "Scan was interrupted"); 1513 } 1514 1515 @Override processMessage(Message msg)1516 public boolean processMessage(Message msg) { 1517 ClientInfo ci = mClients.get(msg.replyTo); 1518 switch (msg.what) { 1519 case WifiScanner.CMD_START_PNO_SCAN: 1520 Bundle pnoParams = (Bundle) msg.obj; 1521 if (pnoParams == null) { 1522 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1523 return HANDLED; 1524 } 1525 pnoParams.setDefusable(true); 1526 PnoSettings pnoSettings = 1527 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY); 1528 // This message is handled after the transition to SwPnoScan/HwPnoScan state 1529 deferMessage(msg); 1530 if (mScannerImpl.isHwPnoSupported(pnoSettings.isConnected)) { 1531 transitionTo(mHwPnoScanState); 1532 } else { 1533 transitionTo(mSwPnoScanState); 1534 } 1535 break; 1536 case WifiScanner.CMD_STOP_PNO_SCAN: 1537 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, "no scan running"); 1538 break; 1539 default: 1540 return NOT_HANDLED; 1541 } 1542 return HANDLED; 1543 } 1544 } 1545 1546 class HwPnoScanState extends State { 1547 @Override enter()1548 public void enter() { 1549 if (DBG) localLog("HwPnoScanState"); 1550 } 1551 1552 @Override exit()1553 public void exit() { 1554 // Reset PNO scan in ScannerImpl before we exit. 1555 mScannerImpl.resetHwPnoList(); 1556 removeInternalClient(); 1557 } 1558 1559 @Override processMessage(Message msg)1560 public boolean processMessage(Message msg) { 1561 ClientInfo ci = mClients.get(msg.replyTo); 1562 switch (msg.what) { 1563 case WifiScanner.CMD_START_PNO_SCAN: 1564 Bundle pnoParams = (Bundle) msg.obj; 1565 if (pnoParams == null) { 1566 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1567 return HANDLED; 1568 } 1569 pnoParams.setDefusable(true); 1570 PnoSettings pnoSettings = 1571 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY); 1572 ScanSettings scanSettings = 1573 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY); 1574 if (addHwPnoScanRequest(ci, msg.arg2, scanSettings, pnoSettings)) { 1575 replySucceeded(msg); 1576 } else { 1577 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1578 transitionTo(mStartedState); 1579 } 1580 break; 1581 case WifiScanner.CMD_STOP_PNO_SCAN: 1582 removeHwPnoScanRequest(ci, msg.arg2); 1583 transitionTo(mStartedState); 1584 break; 1585 case CMD_PNO_NETWORK_FOUND: 1586 ScanResult[] scanResults = ((ScanResult[]) msg.obj); 1587 if (isSingleScanNeeded(scanResults)) { 1588 ScanSettings activeScanSettings = getScanSettings(); 1589 if (activeScanSettings == null) { 1590 sendPnoScanFailedToAllAndClear( 1591 WifiScanner.REASON_UNSPECIFIED, 1592 "couldn't retrieve setting"); 1593 transitionTo(mStartedState); 1594 } else { 1595 addSingleScanRequest(activeScanSettings); 1596 transitionTo(mSingleScanState); 1597 } 1598 } else { 1599 reportPnoNetworkFound((ScanResult[]) msg.obj); 1600 } 1601 break; 1602 case CMD_PNO_SCAN_FAILED: 1603 sendPnoScanFailedToAllAndClear( 1604 WifiScanner.REASON_UNSPECIFIED, "pno scan failed"); 1605 transitionTo(mStartedState); 1606 break; 1607 default: 1608 return NOT_HANDLED; 1609 } 1610 return HANDLED; 1611 } 1612 } 1613 1614 class SingleScanState extends State { 1615 @Override enter()1616 public void enter() { 1617 if (DBG) localLog("SingleScanState"); 1618 } 1619 1620 @Override processMessage(Message msg)1621 public boolean processMessage(Message msg) { 1622 ClientInfo ci = mClients.get(msg.replyTo); 1623 switch (msg.what) { 1624 case WifiScanner.CMD_SCAN_RESULT: 1625 WifiScanner.ParcelableScanData parcelableScanData = 1626 (WifiScanner.ParcelableScanData) msg.obj; 1627 ScanData[] scanDatas = parcelableScanData.getResults(); 1628 ScanData lastScanData = scanDatas[scanDatas.length - 1]; 1629 reportPnoNetworkFound(lastScanData.getResults()); 1630 transitionTo(mHwPnoScanState); 1631 break; 1632 case WifiScanner.CMD_OP_FAILED: 1633 sendPnoScanFailedToAllAndClear( 1634 WifiScanner.REASON_UNSPECIFIED, "single scan failed"); 1635 transitionTo(mStartedState); 1636 break; 1637 default: 1638 return NOT_HANDLED; 1639 } 1640 return HANDLED; 1641 } 1642 } 1643 1644 class SwPnoScanState extends State { 1645 private final ArrayList<ScanResult> mSwPnoFullScanResults = new ArrayList<>(); 1646 1647 @Override enter()1648 public void enter() { 1649 if (DBG) localLog("SwPnoScanState"); 1650 mSwPnoFullScanResults.clear(); 1651 } 1652 1653 @Override exit()1654 public void exit() { 1655 removeInternalClient(); 1656 } 1657 1658 @Override processMessage(Message msg)1659 public boolean processMessage(Message msg) { 1660 ClientInfo ci = mClients.get(msg.replyTo); 1661 switch (msg.what) { 1662 case WifiScanner.CMD_START_PNO_SCAN: 1663 Bundle pnoParams = (Bundle) msg.obj; 1664 if (pnoParams == null) { 1665 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "params null"); 1666 return HANDLED; 1667 } 1668 pnoParams.setDefusable(true); 1669 PnoSettings pnoSettings = 1670 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_PNO_SETTINGS_KEY); 1671 ScanSettings scanSettings = 1672 pnoParams.getParcelable(WifiScanner.PNO_PARAMS_SCAN_SETTINGS_KEY); 1673 if (addSwPnoScanRequest(ci, msg.arg2, scanSettings, pnoSettings)) { 1674 replySucceeded(msg); 1675 } else { 1676 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 1677 transitionTo(mStartedState); 1678 } 1679 break; 1680 case WifiScanner.CMD_STOP_PNO_SCAN: 1681 removeSwPnoScanRequest(ci, msg.arg2); 1682 transitionTo(mStartedState); 1683 break; 1684 case WifiScanner.CMD_FULL_SCAN_RESULT: 1685 // Aggregate full scan results until we get the |CMD_SCAN_RESULT| message 1686 mSwPnoFullScanResults.add((ScanResult) msg.obj); 1687 break; 1688 case WifiScanner.CMD_SCAN_RESULT: 1689 ScanResult[] scanResults = mSwPnoFullScanResults.toArray( 1690 new ScanResult[mSwPnoFullScanResults.size()]); 1691 reportPnoNetworkFound(scanResults); 1692 mSwPnoFullScanResults.clear(); 1693 break; 1694 case WifiScanner.CMD_OP_FAILED: 1695 sendPnoScanFailedToAllAndClear( 1696 WifiScanner.REASON_UNSPECIFIED, "background scan failed"); 1697 transitionTo(mStartedState); 1698 break; 1699 default: 1700 return NOT_HANDLED; 1701 } 1702 return HANDLED; 1703 } 1704 } 1705 convertPnoSettingsToNative(PnoSettings pnoSettings)1706 private WifiNative.PnoSettings convertPnoSettingsToNative(PnoSettings pnoSettings) { 1707 WifiNative.PnoSettings nativePnoSetting = new WifiNative.PnoSettings(); 1708 nativePnoSetting.min5GHzRssi = pnoSettings.min5GHzRssi; 1709 nativePnoSetting.min24GHzRssi = pnoSettings.min24GHzRssi; 1710 nativePnoSetting.initialScoreMax = pnoSettings.initialScoreMax; 1711 nativePnoSetting.currentConnectionBonus = pnoSettings.currentConnectionBonus; 1712 nativePnoSetting.sameNetworkBonus = pnoSettings.sameNetworkBonus; 1713 nativePnoSetting.secureBonus = pnoSettings.secureBonus; 1714 nativePnoSetting.band5GHzBonus = pnoSettings.band5GHzBonus; 1715 nativePnoSetting.isConnected = pnoSettings.isConnected; 1716 nativePnoSetting.networkList = 1717 new WifiNative.PnoNetwork[pnoSettings.networkList.length]; 1718 for (int i = 0; i < pnoSettings.networkList.length; i++) { 1719 nativePnoSetting.networkList[i] = new WifiNative.PnoNetwork(); 1720 nativePnoSetting.networkList[i].ssid = pnoSettings.networkList[i].ssid; 1721 nativePnoSetting.networkList[i].networkId = pnoSettings.networkList[i].networkId; 1722 nativePnoSetting.networkList[i].priority = pnoSettings.networkList[i].priority; 1723 nativePnoSetting.networkList[i].flags = pnoSettings.networkList[i].flags; 1724 nativePnoSetting.networkList[i].auth_bit_field = 1725 pnoSettings.networkList[i].authBitField; 1726 } 1727 return nativePnoSetting; 1728 } 1729 1730 // Retrieve the only active scan settings. getScanSettings()1731 private ScanSettings getScanSettings() { 1732 for (Pair<PnoSettings, ScanSettings> settingsPair : mActivePnoScans.getAllSettings()) { 1733 return settingsPair.second; 1734 } 1735 return null; 1736 } 1737 removeInternalClient()1738 private void removeInternalClient() { 1739 if (mInternalClientInfo != null) { 1740 mInternalClientInfo.cleanup(); 1741 mInternalClientInfo = null; 1742 } else { 1743 Log.w(TAG, "No Internal client for PNO"); 1744 } 1745 } 1746 addInternalClient(ClientInfo ci)1747 private void addInternalClient(ClientInfo ci) { 1748 if (mInternalClientInfo == null) { 1749 mInternalClientInfo = 1750 new InternalClientInfo(ci.getUid(), new Messenger(this.getHandler())); 1751 mInternalClientInfo.register(); 1752 } else { 1753 Log.w(TAG, "Internal client for PNO already exists"); 1754 } 1755 } 1756 addPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, PnoSettings pnoSettings)1757 private void addPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, 1758 PnoSettings pnoSettings) { 1759 mActivePnoScans.addRequest(ci, handler, WifiStateMachine.WIFI_WORK_SOURCE, 1760 Pair.create(pnoSettings, scanSettings)); 1761 addInternalClient(ci); 1762 } 1763 removePnoScanRequest(ClientInfo ci, int handler)1764 private Pair<PnoSettings, ScanSettings> removePnoScanRequest(ClientInfo ci, int handler) { 1765 Pair<PnoSettings, ScanSettings> settings = mActivePnoScans.removeRequest(ci, handler); 1766 return settings; 1767 } 1768 addHwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, PnoSettings pnoSettings)1769 private boolean addHwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, 1770 PnoSettings pnoSettings) { 1771 if (ci == null) { 1772 Log.d(TAG, "Failing scan request ClientInfo not found " + handler); 1773 return false; 1774 } 1775 if (!mActivePnoScans.isEmpty()) { 1776 loge("Failing scan request because there is already an active scan"); 1777 return false; 1778 } 1779 WifiNative.PnoSettings nativePnoSettings = convertPnoSettingsToNative(pnoSettings); 1780 if (!mScannerImpl.setHwPnoList(nativePnoSettings, mPnoScanStateMachine)) { 1781 return false; 1782 } 1783 logScanRequest("addHwPnoScanRequest", ci, handler, null, scanSettings, pnoSettings); 1784 addPnoScanRequest(ci, handler, scanSettings, pnoSettings); 1785 // HW PNO is supported, check if we need a background scan running for this. 1786 if (mScannerImpl.shouldScheduleBackgroundScanForHwPno()) { 1787 addBackgroundScanRequest(scanSettings); 1788 } 1789 return true; 1790 } 1791 removeHwPnoScanRequest(ClientInfo ci, int handler)1792 private void removeHwPnoScanRequest(ClientInfo ci, int handler) { 1793 if (ci != null) { 1794 Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci, handler); 1795 logScanRequest("removeHwPnoScanRequest", ci, handler, null, 1796 settings.second, settings.first); 1797 } 1798 } 1799 addSwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, PnoSettings pnoSettings)1800 private boolean addSwPnoScanRequest(ClientInfo ci, int handler, ScanSettings scanSettings, 1801 PnoSettings pnoSettings) { 1802 if (ci == null) { 1803 Log.d(TAG, "Failing scan request ClientInfo not found " + handler); 1804 return false; 1805 } 1806 if (!mActivePnoScans.isEmpty()) { 1807 loge("Failing scan request because there is already an active scan"); 1808 return false; 1809 } 1810 logScanRequest("addSwPnoScanRequest", ci, handler, null, scanSettings, pnoSettings); 1811 addPnoScanRequest(ci, handler, scanSettings, pnoSettings); 1812 // HW PNO is not supported, we need to revert to normal background scans and 1813 // report events after each scan and we need full scan results to get the IE information 1814 scanSettings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN 1815 | WifiScanner.REPORT_EVENT_FULL_SCAN_RESULT; 1816 addBackgroundScanRequest(scanSettings); 1817 return true; 1818 } 1819 removeSwPnoScanRequest(ClientInfo ci, int handler)1820 private void removeSwPnoScanRequest(ClientInfo ci, int handler) { 1821 if (ci != null) { 1822 Pair<PnoSettings, ScanSettings> settings = removePnoScanRequest(ci, handler); 1823 logScanRequest("removeSwPnoScanRequest", ci, handler, null, 1824 settings.second, settings.first); 1825 } 1826 } 1827 reportPnoNetworkFound(ScanResult[] results)1828 private void reportPnoNetworkFound(ScanResult[] results) { 1829 WifiScanner.ParcelableScanResults parcelableScanResults = 1830 new WifiScanner.ParcelableScanResults(results); 1831 for (RequestInfo<Pair<PnoSettings, ScanSettings>> entry : mActivePnoScans) { 1832 ClientInfo ci = entry.clientInfo; 1833 int handler = entry.handlerId; 1834 logCallback("pnoNetworkFound", ci, handler, describeForLog(results)); 1835 ci.reportEvent( 1836 WifiScanner.CMD_PNO_NETWORK_FOUND, 0, handler, parcelableScanResults); 1837 } 1838 } 1839 sendPnoScanFailedToAllAndClear(int reason, String description)1840 private void sendPnoScanFailedToAllAndClear(int reason, String description) { 1841 for (RequestInfo<Pair<PnoSettings, ScanSettings>> entry : mActivePnoScans) { 1842 ClientInfo ci = entry.clientInfo; 1843 int handler = entry.handlerId; 1844 ci.reportEvent(WifiScanner.CMD_OP_FAILED, 0, handler, 1845 new WifiScanner.OperationResult(reason, description)); 1846 } 1847 mActivePnoScans.clear(); 1848 } 1849 addBackgroundScanRequest(ScanSettings settings)1850 private void addBackgroundScanRequest(ScanSettings settings) { 1851 if (DBG) localLog("Starting background scan"); 1852 if (mInternalClientInfo != null) { 1853 mInternalClientInfo.sendRequestToClientHandler( 1854 WifiScanner.CMD_START_BACKGROUND_SCAN, settings, 1855 WifiStateMachine.WIFI_WORK_SOURCE); 1856 } 1857 } 1858 addSingleScanRequest(ScanSettings settings)1859 private void addSingleScanRequest(ScanSettings settings) { 1860 if (DBG) localLog("Starting single scan"); 1861 if (mInternalClientInfo != null) { 1862 mInternalClientInfo.sendRequestToClientHandler( 1863 WifiScanner.CMD_START_SINGLE_SCAN, settings, 1864 WifiStateMachine.WIFI_WORK_SOURCE); 1865 } 1866 } 1867 1868 /** 1869 * Checks if IE are present in scan data, if no single scan is needed to report event to 1870 * client 1871 */ isSingleScanNeeded(ScanResult[] scanResults)1872 private boolean isSingleScanNeeded(ScanResult[] scanResults) { 1873 for (ScanResult scanResult : scanResults) { 1874 if (scanResult.informationElements != null 1875 && scanResult.informationElements.length > 0) { 1876 return false; 1877 } 1878 } 1879 return true; 1880 } 1881 } 1882 1883 private abstract class ClientInfo { 1884 private final int mUid; 1885 private final WorkSource mWorkSource; 1886 private boolean mScanWorkReported = false; 1887 protected final Messenger mMessenger; 1888 ClientInfo(int uid, Messenger messenger)1889 ClientInfo(int uid, Messenger messenger) { 1890 mUid = uid; 1891 mMessenger = messenger; 1892 mWorkSource = new WorkSource(uid); 1893 } 1894 1895 /** 1896 * Register this client to main client map. 1897 */ register()1898 public void register() { 1899 mClients.put(mMessenger, this); 1900 } 1901 1902 /** 1903 * Unregister this client from main client map. 1904 */ unregister()1905 private void unregister() { 1906 mClients.remove(mMessenger); 1907 } 1908 cleanup()1909 public void cleanup() { 1910 mSingleScanListeners.removeAllForClient(this); 1911 mSingleScanStateMachine.removeSingleScanRequests(this); 1912 mBackgroundScanStateMachine.removeBackgroundScanSettings(this); 1913 mBackgroundScanStateMachine.removeHotlistSettings(this); 1914 unregister(); 1915 localLog("Successfully stopped all requests for client " + this); 1916 } 1917 getUid()1918 public int getUid() { 1919 return mUid; 1920 } 1921 reportEvent(int what, int arg1, int arg2)1922 public void reportEvent(int what, int arg1, int arg2) { 1923 reportEvent(what, arg1, arg2, null); 1924 } 1925 1926 // This has to be implemented by subclasses to report events back to clients. reportEvent(int what, int arg1, int arg2, Object obj)1927 public abstract void reportEvent(int what, int arg1, int arg2, Object obj); 1928 1929 // TODO(b/27903217): Blame scan on provided work source reportBatchedScanStart()1930 private void reportBatchedScanStart() { 1931 if (mUid == 0) 1932 return; 1933 1934 int csph = getCsph(); 1935 1936 try { 1937 mBatteryStats.noteWifiBatchedScanStartedFromSource(mWorkSource, csph); 1938 } catch (RemoteException e) { 1939 logw("failed to report scan work: " + e.toString()); 1940 } 1941 } 1942 reportBatchedScanStop()1943 private void reportBatchedScanStop() { 1944 if (mUid == 0) 1945 return; 1946 1947 try { 1948 mBatteryStats.noteWifiBatchedScanStoppedFromSource(mWorkSource); 1949 } catch (RemoteException e) { 1950 logw("failed to cleanup scan work: " + e.toString()); 1951 } 1952 } 1953 1954 // TODO migrate batterystats to accept scan duration per hour instead of csph getCsph()1955 private int getCsph() { 1956 int totalScanDurationPerHour = 0; 1957 Collection<ScanSettings> settingsList = 1958 mBackgroundScanStateMachine.getBackgroundScanSettings(this); 1959 for (ScanSettings settings : settingsList) { 1960 int scanDurationMs = mChannelHelper.estimateScanDuration(settings); 1961 int scans_per_Hour = settings.periodInMs == 0 ? 1 : (3600 * 1000) / 1962 settings.periodInMs; 1963 totalScanDurationPerHour += scanDurationMs * scans_per_Hour; 1964 } 1965 1966 return totalScanDurationPerHour / ChannelHelper.SCAN_PERIOD_PER_CHANNEL_MS; 1967 } 1968 reportScanWorkUpdate()1969 public void reportScanWorkUpdate() { 1970 if (mScanWorkReported) { 1971 reportBatchedScanStop(); 1972 mScanWorkReported = false; 1973 } 1974 if (mBackgroundScanStateMachine.getBackgroundScanSettings(this).isEmpty()) { 1975 reportBatchedScanStart(); 1976 mScanWorkReported = true; 1977 } 1978 } 1979 1980 @Override toString()1981 public String toString() { 1982 return "ClientInfo[uid=" + mUid + "," + mMessenger + "]"; 1983 } 1984 } 1985 1986 /** 1987 * This class is used to represent external clients to the WifiScanning Service. 1988 */ 1989 private class ExternalClientInfo extends ClientInfo { 1990 private final AsyncChannel mChannel; 1991 /** 1992 * Indicates if the client is still connected 1993 * If the client is no longer connected then messages to it will be silently dropped 1994 */ 1995 private boolean mDisconnected = false; 1996 ExternalClientInfo(int uid, Messenger messenger, AsyncChannel c)1997 ExternalClientInfo(int uid, Messenger messenger, AsyncChannel c) { 1998 super(uid, messenger); 1999 mChannel = c; 2000 if (DBG) localLog("New client, channel: " + c); 2001 } 2002 2003 @Override reportEvent(int what, int arg1, int arg2, Object obj)2004 public void reportEvent(int what, int arg1, int arg2, Object obj) { 2005 if (!mDisconnected) { 2006 mChannel.sendMessage(what, arg1, arg2, obj); 2007 } 2008 } 2009 2010 @Override cleanup()2011 public void cleanup() { 2012 mDisconnected = true; 2013 // Internal clients should not have any wifi change requests. So, keeping this cleanup 2014 // only for external client because this will otherwise cause an infinite recursion 2015 // when the internal client in WifiChangeStateMachine is cleaned up. 2016 mWifiChangeStateMachine.removeWifiChangeHandler(this); 2017 mPnoScanStateMachine.removePnoSettings(this); 2018 super.cleanup(); 2019 } 2020 } 2021 2022 /** 2023 * This class is used to represent internal clients to the WifiScanning Service. This is needed 2024 * for communicating between State Machines. 2025 * This leaves the onReportEvent method unimplemented, so that the clients have the freedom 2026 * to handle the events as they need. 2027 */ 2028 private class InternalClientInfo extends ClientInfo { 2029 private static final int INTERNAL_CLIENT_HANDLER = 0; 2030 2031 /** 2032 * The UID here is used to proxy the original external requester UID. 2033 */ InternalClientInfo(int requesterUid, Messenger messenger)2034 InternalClientInfo(int requesterUid, Messenger messenger) { 2035 super(requesterUid, messenger); 2036 } 2037 2038 @Override reportEvent(int what, int arg1, int arg2, Object obj)2039 public void reportEvent(int what, int arg1, int arg2, Object obj) { 2040 Message message = Message.obtain(); 2041 message.what = what; 2042 message.arg1 = arg1; 2043 message.arg2 = arg2; 2044 message.obj = obj; 2045 try { 2046 mMessenger.send(message); 2047 } catch (RemoteException e) { 2048 loge("Failed to send message: " + what); 2049 } 2050 } 2051 2052 /** 2053 * Send a message to the client handler which should reroute the message to the appropriate 2054 * state machine. 2055 */ sendRequestToClientHandler(int what, ScanSettings settings, WorkSource workSource)2056 public void sendRequestToClientHandler(int what, ScanSettings settings, 2057 WorkSource workSource) { 2058 Message msg = Message.obtain(); 2059 msg.what = what; 2060 msg.arg2 = INTERNAL_CLIENT_HANDLER; 2061 if (settings != null) { 2062 Bundle bundle = new Bundle(); 2063 bundle.putParcelable(WifiScanner.SCAN_PARAMS_SCAN_SETTINGS_KEY, settings); 2064 bundle.putParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY, workSource); 2065 msg.obj = bundle; 2066 } 2067 msg.replyTo = mMessenger; 2068 msg.sendingUid = getUid(); 2069 mClientHandler.sendMessage(msg); 2070 } 2071 2072 /** 2073 * Send a message to the client handler which should reroute the message to the appropriate 2074 * state machine. 2075 */ sendRequestToClientHandler(int what)2076 public void sendRequestToClientHandler(int what) { 2077 sendRequestToClientHandler(what, null, null); 2078 } 2079 2080 @Override toString()2081 public String toString() { 2082 return "InternalClientInfo[]"; 2083 } 2084 } 2085 replySucceeded(Message msg)2086 void replySucceeded(Message msg) { 2087 if (msg.replyTo != null) { 2088 Message reply = Message.obtain(); 2089 reply.what = WifiScanner.CMD_OP_SUCCEEDED; 2090 reply.arg2 = msg.arg2; 2091 try { 2092 msg.replyTo.send(reply); 2093 } catch (RemoteException e) { 2094 // There's not much we can do if reply can't be sent! 2095 } 2096 } else { 2097 // locally generated message; doesn't need a reply! 2098 } 2099 } 2100 replyFailed(Message msg, int reason, String description)2101 void replyFailed(Message msg, int reason, String description) { 2102 if (msg.replyTo != null) { 2103 Message reply = Message.obtain(); 2104 reply.what = WifiScanner.CMD_OP_FAILED; 2105 reply.arg2 = msg.arg2; 2106 reply.obj = new WifiScanner.OperationResult(reason, description); 2107 try { 2108 msg.replyTo.send(reply); 2109 } catch (RemoteException e) { 2110 // There's not much we can do if reply can't be sent! 2111 } 2112 } else { 2113 // locally generated message; doesn't need a reply! 2114 } 2115 } 2116 2117 /** 2118 * Wifi Change state machine is used to handle any wifi change tracking requests. 2119 * TODO: This state machine doesn't handle driver loading/unloading yet. 2120 */ 2121 class WifiChangeStateMachine extends StateMachine 2122 implements WifiNative.SignificantWifiChangeEventHandler { 2123 2124 private static final int MAX_APS_TO_TRACK = 3; 2125 private static final int MOVING_SCAN_PERIOD_MS = 10000; 2126 private static final int STATIONARY_SCAN_PERIOD_MS = 5000; 2127 private static final int MOVING_STATE_TIMEOUT_MS = 30000; 2128 2129 State mDefaultState = new DefaultState(); 2130 State mStationaryState = new StationaryState(); 2131 State mMovingState = new MovingState(); 2132 2133 private static final String ACTION_TIMEOUT = 2134 "com.android.server.WifiScanningServiceImpl.action.TIMEOUT"; 2135 private PendingIntent mTimeoutIntent; 2136 private ScanResult[] mCurrentBssids; 2137 private InternalClientInfo mInternalClientInfo; 2138 2139 private final Set<Pair<ClientInfo, Integer>> mActiveWifiChangeHandlers = new HashSet<>(); 2140 WifiChangeStateMachine(Looper looper)2141 WifiChangeStateMachine(Looper looper) { 2142 super("SignificantChangeStateMachine", looper); 2143 2144 // CHECKSTYLE:OFF IndentationCheck 2145 addState(mDefaultState); 2146 addState(mStationaryState, mDefaultState); 2147 addState(mMovingState, mDefaultState); 2148 // CHECKSTYLE:ON IndentationCheck 2149 2150 setInitialState(mDefaultState); 2151 } 2152 removeWifiChangeHandler(ClientInfo ci)2153 public void removeWifiChangeHandler(ClientInfo ci) { 2154 Iterator<Pair<ClientInfo, Integer>> iter = mActiveWifiChangeHandlers.iterator(); 2155 while (iter.hasNext()) { 2156 Pair<ClientInfo, Integer> entry = iter.next(); 2157 if (entry.first == ci) { 2158 iter.remove(); 2159 } 2160 } 2161 untrackSignificantWifiChangeOnEmpty(); 2162 } 2163 2164 class DefaultState extends State { 2165 @Override enter()2166 public void enter() { 2167 if (DBG) localLog("Entering IdleState"); 2168 } 2169 2170 @Override processMessage(Message msg)2171 public boolean processMessage(Message msg) { 2172 if (DBG) localLog("DefaultState state got " + msg); 2173 ClientInfo ci = mClients.get(msg.replyTo); 2174 switch (msg.what) { 2175 case WifiScanner.CMD_START_TRACKING_CHANGE: 2176 if (addWifiChangeHandler(ci, msg.arg2)) { 2177 replySucceeded(msg); 2178 transitionTo(mMovingState); 2179 } else { 2180 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 2181 } 2182 break; 2183 case WifiScanner.CMD_STOP_TRACKING_CHANGE: 2184 // nothing to do 2185 break; 2186 case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE: 2187 /* save configuration till we transition to moving state */ 2188 deferMessage(msg); 2189 break; 2190 case WifiScanner.CMD_SCAN_RESULT: 2191 // nothing to do 2192 break; 2193 default: 2194 return NOT_HANDLED; 2195 } 2196 return HANDLED; 2197 } 2198 } 2199 2200 class StationaryState extends State { 2201 @Override enter()2202 public void enter() { 2203 if (DBG) localLog("Entering StationaryState"); 2204 reportWifiStabilized(mCurrentBssids); 2205 } 2206 2207 @Override processMessage(Message msg)2208 public boolean processMessage(Message msg) { 2209 if (DBG) localLog("Stationary state got " + msg); 2210 ClientInfo ci = mClients.get(msg.replyTo); 2211 switch (msg.what) { 2212 case WifiScanner.CMD_START_TRACKING_CHANGE: 2213 if (addWifiChangeHandler(ci, msg.arg2)) { 2214 replySucceeded(msg); 2215 } else { 2216 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 2217 } 2218 break; 2219 case WifiScanner.CMD_STOP_TRACKING_CHANGE: 2220 removeWifiChangeHandler(ci, msg.arg2); 2221 break; 2222 case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE: 2223 /* save configuration till we transition to moving state */ 2224 deferMessage(msg); 2225 break; 2226 case CMD_WIFI_CHANGE_DETECTED: 2227 if (DBG) localLog("Got wifi change detected"); 2228 reportWifiChanged((ScanResult[]) msg.obj); 2229 transitionTo(mMovingState); 2230 break; 2231 case WifiScanner.CMD_SCAN_RESULT: 2232 // nothing to do 2233 break; 2234 default: 2235 return NOT_HANDLED; 2236 } 2237 return HANDLED; 2238 } 2239 } 2240 2241 class MovingState extends State { 2242 boolean mWifiChangeDetected = false; 2243 boolean mScanResultsPending = false; 2244 2245 @Override enter()2246 public void enter() { 2247 if (DBG) localLog("Entering MovingState"); 2248 if (mTimeoutIntent == null) { 2249 Intent intent = new Intent(ACTION_TIMEOUT, null); 2250 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 2251 2252 mContext.registerReceiver( 2253 new BroadcastReceiver() { 2254 @Override 2255 public void onReceive(Context context, Intent intent) { 2256 sendMessage(CMD_WIFI_CHANGE_TIMEOUT); 2257 } 2258 }, new IntentFilter(ACTION_TIMEOUT)); 2259 } 2260 issueFullScan(); 2261 } 2262 2263 @Override processMessage(Message msg)2264 public boolean processMessage(Message msg) { 2265 if (DBG) localLog("MovingState state got " + msg); 2266 ClientInfo ci = mClients.get(msg.replyTo); 2267 switch (msg.what) { 2268 case WifiScanner.CMD_START_TRACKING_CHANGE: 2269 if (addWifiChangeHandler(ci, msg.arg2)) { 2270 replySucceeded(msg); 2271 } else { 2272 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, "bad request"); 2273 } 2274 break; 2275 case WifiScanner.CMD_STOP_TRACKING_CHANGE: 2276 removeWifiChangeHandler(ci, msg.arg2); 2277 break; 2278 case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE: 2279 if (DBG) localLog("Got configuration from app"); 2280 WifiScanner.WifiChangeSettings settings = 2281 (WifiScanner.WifiChangeSettings) msg.obj; 2282 reconfigureScan(settings); 2283 mWifiChangeDetected = false; 2284 long unchangedDelay = settings.unchangedSampleSize * settings.periodInMs; 2285 mAlarmManager.cancel(mTimeoutIntent); 2286 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 2287 mClock.elapsedRealtime() + unchangedDelay, 2288 mTimeoutIntent); 2289 break; 2290 case WifiScanner.CMD_SCAN_RESULT: 2291 if (DBG) localLog("Got scan results"); 2292 if (mScanResultsPending) { 2293 if (DBG) localLog("reconfiguring scan"); 2294 reconfigureScan((ScanData[])msg.obj, 2295 STATIONARY_SCAN_PERIOD_MS); 2296 mWifiChangeDetected = false; 2297 mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, 2298 mClock.elapsedRealtime() + MOVING_STATE_TIMEOUT_MS, 2299 mTimeoutIntent); 2300 mScanResultsPending = false; 2301 } 2302 break; 2303 case CMD_WIFI_CHANGE_DETECTED: 2304 if (DBG) localLog("Change detected"); 2305 mAlarmManager.cancel(mTimeoutIntent); 2306 reportWifiChanged((ScanResult[])msg.obj); 2307 mWifiChangeDetected = true; 2308 issueFullScan(); 2309 break; 2310 case CMD_WIFI_CHANGE_TIMEOUT: 2311 if (DBG) localLog("Got timeout event"); 2312 if (mWifiChangeDetected == false) { 2313 transitionTo(mStationaryState); 2314 } 2315 break; 2316 default: 2317 return NOT_HANDLED; 2318 } 2319 return HANDLED; 2320 } 2321 2322 @Override exit()2323 public void exit() { 2324 mAlarmManager.cancel(mTimeoutIntent); 2325 } 2326 issueFullScan()2327 void issueFullScan() { 2328 if (DBG) localLog("Issuing full scan"); 2329 ScanSettings settings = new ScanSettings(); 2330 settings.band = WifiScanner.WIFI_BAND_BOTH; 2331 settings.periodInMs = MOVING_SCAN_PERIOD_MS; 2332 settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 2333 addScanRequest(settings); 2334 mScanResultsPending = true; 2335 } 2336 2337 } 2338 reconfigureScan(ScanData[] results, int period)2339 private void reconfigureScan(ScanData[] results, int period) { 2340 // find brightest APs and set them as sentinels 2341 if (results.length < MAX_APS_TO_TRACK) { 2342 localLog("too few APs (" + results.length + ") available to track wifi change"); 2343 return; 2344 } 2345 2346 removeScanRequest(); 2347 2348 // remove duplicate BSSIDs 2349 HashMap<String, ScanResult> bssidToScanResult = new HashMap<String, ScanResult>(); 2350 for (ScanResult result : results[0].getResults()) { 2351 ScanResult saved = bssidToScanResult.get(result.BSSID); 2352 if (saved == null) { 2353 bssidToScanResult.put(result.BSSID, result); 2354 } else if (saved.level > result.level) { 2355 bssidToScanResult.put(result.BSSID, result); 2356 } 2357 } 2358 2359 // find brightest BSSIDs 2360 ScanResult brightest[] = new ScanResult[MAX_APS_TO_TRACK]; 2361 Collection<ScanResult> results2 = bssidToScanResult.values(); 2362 for (ScanResult result : results2) { 2363 for (int j = 0; j < brightest.length; j++) { 2364 if (brightest[j] == null 2365 || (brightest[j].level < result.level)) { 2366 for (int k = brightest.length; k > (j + 1); k--) { 2367 brightest[k - 1] = brightest[k - 2]; 2368 } 2369 brightest[j] = result; 2370 break; 2371 } 2372 } 2373 } 2374 2375 // Get channels to scan for 2376 ArrayList<Integer> channels = new ArrayList<Integer>(); 2377 for (int i = 0; i < brightest.length; i++) { 2378 boolean found = false; 2379 for (int j = i + 1; j < brightest.length; j++) { 2380 if (brightest[j].frequency == brightest[i].frequency) { 2381 found = true; 2382 } 2383 } 2384 if (!found) { 2385 channels.add(brightest[i].frequency); 2386 } 2387 } 2388 2389 if (DBG) localLog("Found " + channels.size() + " channels"); 2390 2391 // set scanning schedule 2392 ScanSettings settings = new ScanSettings(); 2393 settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED; 2394 settings.channels = new ChannelSpec[channels.size()]; 2395 for (int i = 0; i < channels.size(); i++) { 2396 settings.channels[i] = new ChannelSpec(channels.get(i)); 2397 } 2398 2399 settings.periodInMs = period; 2400 addScanRequest(settings); 2401 2402 WifiScanner.WifiChangeSettings settings2 = new WifiScanner.WifiChangeSettings(); 2403 settings2.rssiSampleSize = 3; 2404 settings2.lostApSampleSize = 3; 2405 settings2.unchangedSampleSize = 3; 2406 settings2.minApsBreachingThreshold = 2; 2407 settings2.bssidInfos = new BssidInfo[brightest.length]; 2408 2409 for (int i = 0; i < brightest.length; i++) { 2410 BssidInfo BssidInfo = new BssidInfo(); 2411 BssidInfo.bssid = brightest[i].BSSID; 2412 int threshold = (100 + brightest[i].level) / 32 + 2; 2413 BssidInfo.low = brightest[i].level - threshold; 2414 BssidInfo.high = brightest[i].level + threshold; 2415 settings2.bssidInfos[i] = BssidInfo; 2416 2417 if (DBG) localLog("Setting bssid=" + BssidInfo.bssid + ", " + 2418 "low=" + BssidInfo.low + ", high=" + BssidInfo.high); 2419 } 2420 2421 trackSignificantWifiChange(settings2); 2422 mCurrentBssids = brightest; 2423 } 2424 reconfigureScan(WifiScanner.WifiChangeSettings settings)2425 private void reconfigureScan(WifiScanner.WifiChangeSettings settings) { 2426 2427 if (settings.bssidInfos.length < MAX_APS_TO_TRACK) { 2428 localLog("too few APs (" + settings.bssidInfos.length 2429 + ") available to track wifi change"); 2430 return; 2431 } 2432 2433 if (DBG) localLog("Setting configuration specified by app"); 2434 2435 mCurrentBssids = new ScanResult[settings.bssidInfos.length]; 2436 HashSet<Integer> channels = new HashSet<Integer>(); 2437 2438 for (int i = 0; i < settings.bssidInfos.length; i++) { 2439 ScanResult result = new ScanResult(); 2440 result.BSSID = settings.bssidInfos[i].bssid; 2441 mCurrentBssids[i] = result; 2442 channels.add(settings.bssidInfos[i].frequencyHint); 2443 } 2444 2445 // cancel previous scan 2446 removeScanRequest(); 2447 2448 // set new scanning schedule 2449 ScanSettings settings2 = new ScanSettings(); 2450 settings2.band = WifiScanner.WIFI_BAND_UNSPECIFIED; 2451 settings2.channels = new ChannelSpec[channels.size()]; 2452 int i = 0; 2453 for (Integer channel : channels) { 2454 settings2.channels[i++] = new ChannelSpec(channel); 2455 } 2456 2457 settings2.periodInMs = settings.periodInMs; 2458 addScanRequest(settings2); 2459 2460 // start tracking new APs 2461 trackSignificantWifiChange(settings); 2462 } 2463 2464 2465 @Override onChangesFound(ScanResult results[])2466 public void onChangesFound(ScanResult results[]) { 2467 sendMessage(CMD_WIFI_CHANGE_DETECTED, 0, 0, results); 2468 } 2469 addScanRequest(ScanSettings settings)2470 private void addScanRequest(ScanSettings settings) { 2471 if (DBG) localLog("Starting scans"); 2472 if (mInternalClientInfo != null) { 2473 mInternalClientInfo.sendRequestToClientHandler( 2474 WifiScanner.CMD_START_BACKGROUND_SCAN, settings, null); 2475 } 2476 } 2477 removeScanRequest()2478 private void removeScanRequest() { 2479 if (DBG) localLog("Stopping scans"); 2480 if (mInternalClientInfo != null) { 2481 mInternalClientInfo.sendRequestToClientHandler( 2482 WifiScanner.CMD_STOP_BACKGROUND_SCAN); 2483 } 2484 } 2485 trackSignificantWifiChange(WifiScanner.WifiChangeSettings settings)2486 private void trackSignificantWifiChange(WifiScanner.WifiChangeSettings settings) { 2487 if (mScannerImpl != null) { 2488 mScannerImpl.untrackSignificantWifiChange(); 2489 mScannerImpl.trackSignificantWifiChange(settings, this); 2490 } 2491 } 2492 untrackSignificantWifiChange()2493 private void untrackSignificantWifiChange() { 2494 if (mScannerImpl != null) { 2495 mScannerImpl.untrackSignificantWifiChange(); 2496 } 2497 } 2498 addWifiChangeHandler(ClientInfo ci, int handler)2499 private boolean addWifiChangeHandler(ClientInfo ci, int handler) { 2500 if (ci == null) { 2501 Log.d(TAG, "Failing wifi change request ClientInfo not found " + handler); 2502 return false; 2503 } 2504 mActiveWifiChangeHandlers.add(Pair.create(ci, handler)); 2505 // Add an internal client to make background scan requests. 2506 if (mInternalClientInfo == null) { 2507 mInternalClientInfo = 2508 new InternalClientInfo(ci.getUid(), new Messenger(this.getHandler())); 2509 mInternalClientInfo.register(); 2510 } 2511 return true; 2512 } 2513 removeWifiChangeHandler(ClientInfo ci, int handler)2514 private void removeWifiChangeHandler(ClientInfo ci, int handler) { 2515 if (ci != null) { 2516 mActiveWifiChangeHandlers.remove(Pair.create(ci, handler)); 2517 untrackSignificantWifiChangeOnEmpty(); 2518 } 2519 } 2520 untrackSignificantWifiChangeOnEmpty()2521 private void untrackSignificantWifiChangeOnEmpty() { 2522 if (mActiveWifiChangeHandlers.isEmpty()) { 2523 if (DBG) localLog("Got Disable Wifi Change"); 2524 mCurrentBssids = null; 2525 untrackSignificantWifiChange(); 2526 // Remove the internal client when there are no more external clients. 2527 if (mInternalClientInfo != null) { 2528 mInternalClientInfo.cleanup(); 2529 mInternalClientInfo = null; 2530 } 2531 transitionTo(mDefaultState); 2532 } 2533 } 2534 reportWifiChanged(ScanResult[] results)2535 private void reportWifiChanged(ScanResult[] results) { 2536 WifiScanner.ParcelableScanResults parcelableScanResults = 2537 new WifiScanner.ParcelableScanResults(results); 2538 Iterator<Pair<ClientInfo, Integer>> it = mActiveWifiChangeHandlers.iterator(); 2539 while (it.hasNext()) { 2540 Pair<ClientInfo, Integer> entry = it.next(); 2541 ClientInfo ci = entry.first; 2542 int handler = entry.second; 2543 ci.reportEvent(WifiScanner.CMD_WIFI_CHANGE_DETECTED, 0, handler, 2544 parcelableScanResults); 2545 } 2546 } 2547 reportWifiStabilized(ScanResult[] results)2548 private void reportWifiStabilized(ScanResult[] results) { 2549 WifiScanner.ParcelableScanResults parcelableScanResults = 2550 new WifiScanner.ParcelableScanResults(results); 2551 Iterator<Pair<ClientInfo, Integer>> it = mActiveWifiChangeHandlers.iterator(); 2552 while (it.hasNext()) { 2553 Pair<ClientInfo, Integer> entry = it.next(); 2554 ClientInfo ci = entry.first; 2555 int handler = entry.second; 2556 ci.reportEvent(WifiScanner.CMD_WIFI_CHANGES_STABILIZED, 0, handler, 2557 parcelableScanResults); 2558 } 2559 } 2560 } 2561 toString(int uid, ScanSettings settings)2562 private static String toString(int uid, ScanSettings settings) { 2563 StringBuilder sb = new StringBuilder(); 2564 sb.append("ScanSettings[uid=").append(uid); 2565 sb.append(", period=").append(settings.periodInMs); 2566 sb.append(", report=").append(settings.reportEvents); 2567 if (settings.reportEvents == WifiScanner.REPORT_EVENT_AFTER_BUFFER_FULL 2568 && settings.numBssidsPerScan > 0 2569 && settings.maxScansToCache > 1) { 2570 sb.append(", batch=").append(settings.maxScansToCache); 2571 sb.append(", numAP=").append(settings.numBssidsPerScan); 2572 } 2573 sb.append(", ").append(ChannelHelper.toString(settings)); 2574 sb.append("]"); 2575 2576 return sb.toString(); 2577 } 2578 2579 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)2580 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2581 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 2582 != PackageManager.PERMISSION_GRANTED) { 2583 pw.println("Permission Denial: can't dump WifiScanner from from pid=" 2584 + Binder.getCallingPid() 2585 + ", uid=" + Binder.getCallingUid() 2586 + " without permission " 2587 + android.Manifest.permission.DUMP); 2588 return; 2589 } 2590 pw.println("WifiScanningService - Log Begin ----"); 2591 mLocalLog.dump(fd, pw, args); 2592 pw.println("WifiScanningService - Log End ----"); 2593 pw.println(); 2594 pw.println("clients:"); 2595 for (ClientInfo client : mClients.values()) { 2596 pw.println(" " + client); 2597 } 2598 pw.println("listeners:"); 2599 for (ClientInfo client : mClients.values()) { 2600 Collection<ScanSettings> settingsList = 2601 mBackgroundScanStateMachine.getBackgroundScanSettings(client); 2602 for (ScanSettings settings : settingsList) { 2603 pw.println(" " + toString(client.mUid, settings)); 2604 } 2605 } 2606 if (mBackgroundScheduler != null) { 2607 WifiNative.ScanSettings schedule = mBackgroundScheduler.getSchedule(); 2608 if (schedule != null) { 2609 pw.println("schedule:"); 2610 pw.println(" base period: " + schedule.base_period_ms); 2611 pw.println(" max ap per scan: " + schedule.max_ap_per_scan); 2612 pw.println(" batched scans: " + schedule.report_threshold_num_scans); 2613 pw.println(" buckets:"); 2614 for (int b = 0; b < schedule.num_buckets; b++) { 2615 WifiNative.BucketSettings bucket = schedule.buckets[b]; 2616 pw.println(" bucket " + bucket.bucket + " (" + bucket.period_ms + "ms)[" 2617 + bucket.report_events + "]: " 2618 + ChannelHelper.toString(bucket)); 2619 } 2620 } 2621 } 2622 if (mPnoScanStateMachine != null) { 2623 mPnoScanStateMachine.dump(fd, pw, args); 2624 } 2625 } 2626 logScanRequest(String request, ClientInfo ci, int id, WorkSource workSource, ScanSettings settings, PnoSettings pnoSettings)2627 void logScanRequest(String request, ClientInfo ci, int id, WorkSource workSource, 2628 ScanSettings settings, PnoSettings pnoSettings) { 2629 StringBuilder sb = new StringBuilder(); 2630 sb.append(request) 2631 .append(": ") 2632 .append((ci == null) ? "ClientInfo[unknown]" : ci.toString()) 2633 .append(",Id=") 2634 .append(id); 2635 if (workSource != null) { 2636 sb.append(",").append(workSource); 2637 } 2638 if (settings != null) { 2639 sb.append(", "); 2640 describeTo(sb, settings); 2641 } 2642 if (pnoSettings != null) { 2643 sb.append(", "); 2644 describeTo(sb, pnoSettings); 2645 } 2646 localLog(sb.toString()); 2647 } 2648 logCallback(String callback, ClientInfo ci, int id, String extra)2649 void logCallback(String callback, ClientInfo ci, int id, String extra) { 2650 StringBuilder sb = new StringBuilder(); 2651 sb.append(callback) 2652 .append(": ") 2653 .append((ci == null) ? "ClientInfo[unknown]" : ci.toString()) 2654 .append(",Id=") 2655 .append(id); 2656 if (extra != null) { 2657 sb.append(",").append(extra); 2658 } 2659 localLog(sb.toString()); 2660 } 2661 describeForLog(ScanData[] results)2662 static String describeForLog(ScanData[] results) { 2663 StringBuilder sb = new StringBuilder(); 2664 sb.append("results="); 2665 for (int i = 0; i < results.length; ++i) { 2666 if (i > 0) sb.append(";"); 2667 sb.append(results[i].getResults().length); 2668 } 2669 return sb.toString(); 2670 } 2671 describeForLog(ScanResult[] results)2672 static String describeForLog(ScanResult[] results) { 2673 return "results=" + results.length; 2674 } 2675 describeTo(StringBuilder sb, ScanSettings scanSettings)2676 static String describeTo(StringBuilder sb, ScanSettings scanSettings) { 2677 sb.append("ScanSettings { ") 2678 .append(" band:").append(scanSettings.band) 2679 .append(" period:").append(scanSettings.periodInMs) 2680 .append(" reportEvents:").append(scanSettings.reportEvents) 2681 .append(" numBssidsPerScan:").append(scanSettings.numBssidsPerScan) 2682 .append(" maxScansToCache:").append(scanSettings.maxScansToCache) 2683 .append(" channels:[ "); 2684 if (scanSettings.channels != null) { 2685 for (int i = 0; i < scanSettings.channels.length; i++) { 2686 sb.append(scanSettings.channels[i].frequency) 2687 .append(" "); 2688 } 2689 } 2690 sb.append(" ] ") 2691 .append(" } "); 2692 return sb.toString(); 2693 } 2694 describeTo(StringBuilder sb, PnoSettings pnoSettings)2695 static String describeTo(StringBuilder sb, PnoSettings pnoSettings) { 2696 sb.append("PnoSettings { ") 2697 .append(" min5GhzRssi:").append(pnoSettings.min5GHzRssi) 2698 .append(" min24GhzRssi:").append(pnoSettings.min24GHzRssi) 2699 .append(" initialScoreMax:").append(pnoSettings.initialScoreMax) 2700 .append(" currentConnectionBonus:").append(pnoSettings.currentConnectionBonus) 2701 .append(" sameNetworkBonus:").append(pnoSettings.sameNetworkBonus) 2702 .append(" secureBonus:").append(pnoSettings.secureBonus) 2703 .append(" band5GhzBonus:").append(pnoSettings.band5GHzBonus) 2704 .append(" isConnected:").append(pnoSettings.isConnected) 2705 .append(" networks:[ "); 2706 if (pnoSettings.networkList != null) { 2707 for (int i = 0; i < pnoSettings.networkList.length; i++) { 2708 sb.append(pnoSettings.networkList[i].ssid) 2709 .append(",") 2710 .append(pnoSettings.networkList[i].networkId) 2711 .append(" "); 2712 } 2713 } 2714 sb.append(" ] ") 2715 .append(" } "); 2716 return sb.toString(); 2717 } 2718 } 2719