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