1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wifi; 18 19 import android.annotation.NonNull; 20 import android.content.Context; 21 import android.net.wifi.WifiConfiguration; 22 import android.net.wifi.WifiManager; 23 import android.os.BatteryStats; 24 import android.os.Handler; 25 import android.os.Looper; 26 import android.os.Message; 27 import android.os.RemoteException; 28 import android.util.ArraySet; 29 import android.util.Log; 30 31 import com.android.internal.app.IBatteryStats; 32 import com.android.internal.util.Protocol; 33 import com.android.internal.util.State; 34 import com.android.internal.util.StateMachine; 35 import com.android.server.wifi.WifiNative.StatusListener; 36 37 import java.io.FileDescriptor; 38 import java.io.PrintWriter; 39 40 /** 41 * This class provides the implementation for different WiFi operating modes. 42 */ 43 public class ActiveModeWarden { 44 private static final String TAG = "WifiActiveModeWarden"; 45 46 private ModeStateMachine mModeStateMachine; 47 48 // Holder for active mode managers 49 private final ArraySet<ActiveModeManager> mActiveModeManagers; 50 // DefaultModeManager used to service API calls when there are not active mode managers. 51 private DefaultModeManager mDefaultModeManager; 52 53 private final WifiInjector mWifiInjector; 54 private final Context mContext; 55 private final Looper mLooper; 56 private final Handler mHandler; 57 private final WifiNative mWifiNative; 58 private final IBatteryStats mBatteryStats; 59 private final SelfRecovery mSelfRecovery; 60 private BaseWifiDiagnostics mWifiDiagnostics; 61 private final ScanRequestProxy mScanRequestProxy; 62 63 // The base for wifi message types 64 static final int BASE = Protocol.BASE_WIFI; 65 66 // The message identifiers below are mapped to those in ClientModeImpl when applicable. 67 // Start the soft access point 68 static final int CMD_START_AP = BASE + 21; 69 // Indicates soft ap start failed 70 static final int CMD_START_AP_FAILURE = BASE + 22; 71 // Stop the soft access point 72 static final int CMD_STOP_AP = BASE + 23; 73 // Soft access point teardown is completed 74 static final int CMD_AP_STOPPED = BASE + 24; 75 76 // Start Scan Only mode 77 static final int CMD_START_SCAN_ONLY_MODE = BASE + 200; 78 // Indicates that start Scan only mode failed 79 static final int CMD_START_SCAN_ONLY_MODE_FAILURE = BASE + 201; 80 // Indicates that scan only mode stopped 81 static final int CMD_STOP_SCAN_ONLY_MODE = BASE + 202; 82 // ScanOnly mode teardown is complete 83 static final int CMD_SCAN_ONLY_MODE_STOPPED = BASE + 203; 84 // ScanOnly mode failed 85 static final int CMD_SCAN_ONLY_MODE_FAILED = BASE + 204; 86 87 // Start Client mode 88 static final int CMD_START_CLIENT_MODE = BASE + 300; 89 // Indicates that start client mode failed 90 static final int CMD_START_CLIENT_MODE_FAILURE = BASE + 301; 91 // Indicates that client mode stopped 92 static final int CMD_STOP_CLIENT_MODE = BASE + 302; 93 // Client mode teardown is complete 94 static final int CMD_CLIENT_MODE_STOPPED = BASE + 303; 95 // Client mode failed 96 static final int CMD_CLIENT_MODE_FAILED = BASE + 304; 97 98 private StatusListener mWifiNativeStatusListener; 99 100 private WifiManager.SoftApCallback mSoftApCallback; 101 private ScanOnlyModeManager.Listener mScanOnlyCallback; 102 private ClientModeManager.Listener mClientModeCallback; 103 104 /** 105 * Called from WifiServiceImpl to register a callback for notifications from SoftApManager 106 */ registerSoftApCallback(@onNull WifiManager.SoftApCallback callback)107 public void registerSoftApCallback(@NonNull WifiManager.SoftApCallback callback) { 108 mSoftApCallback = callback; 109 } 110 111 /** 112 * Called from WifiController to register a callback for notifications from ScanOnlyModeManager 113 */ registerScanOnlyCallback(@onNull ScanOnlyModeManager.Listener callback)114 public void registerScanOnlyCallback(@NonNull ScanOnlyModeManager.Listener callback) { 115 mScanOnlyCallback = callback; 116 } 117 118 /** 119 * Called from WifiController to register a callback for notifications from ClientModeManager 120 */ registerClientModeCallback(@onNull ClientModeManager.Listener callback)121 public void registerClientModeCallback(@NonNull ClientModeManager.Listener callback) { 122 mClientModeCallback = callback; 123 } 124 ActiveModeWarden(WifiInjector wifiInjector, Context context, Looper looper, WifiNative wifiNative, DefaultModeManager defaultModeManager, IBatteryStats batteryStats)125 ActiveModeWarden(WifiInjector wifiInjector, 126 Context context, 127 Looper looper, 128 WifiNative wifiNative, 129 DefaultModeManager defaultModeManager, 130 IBatteryStats batteryStats) { 131 mWifiInjector = wifiInjector; 132 mContext = context; 133 mLooper = looper; 134 mHandler = new Handler(looper); 135 mWifiNative = wifiNative; 136 mActiveModeManagers = new ArraySet(); 137 mDefaultModeManager = defaultModeManager; 138 mBatteryStats = batteryStats; 139 mSelfRecovery = mWifiInjector.getSelfRecovery(); 140 mWifiDiagnostics = mWifiInjector.getWifiDiagnostics(); 141 mScanRequestProxy = mWifiInjector.getScanRequestProxy(); 142 mModeStateMachine = new ModeStateMachine(); 143 mWifiNativeStatusListener = new WifiNativeStatusListener(); 144 mWifiNative.registerStatusListener(mWifiNativeStatusListener); 145 } 146 147 /** 148 * Method to switch wifi into client mode where connections to configured networks will be 149 * attempted. 150 */ enterClientMode()151 public void enterClientMode() { 152 changeMode(ModeStateMachine.CMD_START_CLIENT_MODE); 153 } 154 155 /** 156 * Method to switch wifi into scan only mode where network connection attempts will not be made. 157 * 158 * This mode is utilized by location scans. If wifi is disabled by a user, but they have 159 * previously configured their device to perform location scans, this mode allows wifi to 160 * fulfill the location scan requests but will not be used for connectivity. 161 */ enterScanOnlyMode()162 public void enterScanOnlyMode() { 163 changeMode(ModeStateMachine.CMD_START_SCAN_ONLY_MODE); 164 } 165 166 /** 167 * Method to enable soft ap for wifi hotspot. 168 * 169 * The supplied SoftApModeConfiguration includes the target softap WifiConfiguration (or null if 170 * the persisted config is to be used) and the target operating mode (ex, 171 * {@link WifiManager.IFACE_IP_MODE_TETHERED} {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}). 172 * 173 * @param wifiConfig SoftApModeConfiguration for the hostapd softap 174 */ enterSoftAPMode(@onNull SoftApModeConfiguration wifiConfig)175 public void enterSoftAPMode(@NonNull SoftApModeConfiguration wifiConfig) { 176 mHandler.post(() -> { 177 startSoftAp(wifiConfig); 178 }); 179 } 180 181 /** 182 * Method to stop soft ap for wifi hotspot. 183 * 184 * This method will stop any active softAp mode managers. 185 * 186 * @param mode the operating mode of APs to bring down (ex, 187 * {@link WifiManager.IFACE_IP_MODE_TETHERED} or 188 * {@link WifiManager.IFACE_IP_MODE_LOCAL_ONLY}). 189 * Use {@link WifiManager.IFACE_IP_MODE_UNSPECIFIED} to stop all APs. 190 */ stopSoftAPMode(int mode)191 public void stopSoftAPMode(int mode) { 192 mHandler.post(() -> { 193 for (ActiveModeManager manager : mActiveModeManagers) { 194 if (!(manager instanceof SoftApManager)) continue; 195 SoftApManager softApManager = (SoftApManager) manager; 196 197 if (mode != WifiManager.IFACE_IP_MODE_UNSPECIFIED 198 && mode != softApManager.getIpMode()) { 199 continue; 200 } 201 softApManager.stop(); 202 } 203 updateBatteryStatsWifiState(false); 204 }); 205 } 206 207 /** 208 * Method to disable wifi in sta/client mode scenarios. 209 * 210 * This mode will stop any client/scan modes and will not perform any network scans. 211 */ disableWifi()212 public void disableWifi() { 213 changeMode(ModeStateMachine.CMD_DISABLE_WIFI); 214 } 215 216 /** 217 * Method to stop all active modes, for example, when toggling airplane mode. 218 */ shutdownWifi()219 public void shutdownWifi() { 220 mHandler.post(() -> { 221 for (ActiveModeManager manager : mActiveModeManagers) { 222 manager.stop(); 223 } 224 updateBatteryStatsWifiState(false); 225 }); 226 } 227 228 /** 229 * Dump current state for active mode managers. 230 * 231 * Must be called from ClientModeImpl thread. 232 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)233 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 234 pw.println("Dump of " + TAG); 235 236 pw.println("Current wifi mode: " + getCurrentMode()); 237 pw.println("NumActiveModeManagers: " + mActiveModeManagers.size()); 238 for (ActiveModeManager manager : mActiveModeManagers) { 239 manager.dump(fd, pw, args); 240 } 241 } 242 getCurrentMode()243 protected String getCurrentMode() { 244 return mModeStateMachine.getCurrentMode(); 245 } 246 changeMode(int newMode)247 private void changeMode(int newMode) { 248 mModeStateMachine.sendMessage(newMode); 249 } 250 251 /** 252 * Helper class to wrap the ActiveModeManager callback objects. 253 */ 254 private class ModeCallback { 255 ActiveModeManager mActiveManager; 256 setActiveModeManager(ActiveModeManager manager)257 void setActiveModeManager(ActiveModeManager manager) { 258 mActiveManager = manager; 259 } 260 getActiveModeManager()261 ActiveModeManager getActiveModeManager() { 262 return mActiveManager; 263 } 264 } 265 266 private class ModeStateMachine extends StateMachine { 267 // Commands for the state machine - these will be removed, 268 // along with the StateMachine itself 269 public static final int CMD_START_CLIENT_MODE = 0; 270 public static final int CMD_START_SCAN_ONLY_MODE = 1; 271 public static final int CMD_DISABLE_WIFI = 3; 272 273 private final State mWifiDisabledState = new WifiDisabledState(); 274 private final State mClientModeActiveState = new ClientModeActiveState(); 275 private final State mScanOnlyModeActiveState = new ScanOnlyModeActiveState(); 276 ModeStateMachine()277 ModeStateMachine() { 278 super(TAG, mLooper); 279 280 addState(mClientModeActiveState); 281 addState(mScanOnlyModeActiveState); 282 addState(mWifiDisabledState); 283 284 Log.d(TAG, "Starting Wifi in WifiDisabledState"); 285 setInitialState(mWifiDisabledState); 286 start(); 287 } 288 getCurrentMode()289 private String getCurrentMode() { 290 return getCurrentState().getName(); 291 } 292 checkForAndHandleModeChange(Message message)293 private boolean checkForAndHandleModeChange(Message message) { 294 switch(message.what) { 295 case ModeStateMachine.CMD_START_CLIENT_MODE: 296 Log.d(TAG, "Switching from " + getCurrentMode() + " to ClientMode"); 297 mModeStateMachine.transitionTo(mClientModeActiveState); 298 break; 299 case ModeStateMachine.CMD_START_SCAN_ONLY_MODE: 300 Log.d(TAG, "Switching from " + getCurrentMode() + " to ScanOnlyMode"); 301 mModeStateMachine.transitionTo(mScanOnlyModeActiveState); 302 break; 303 case ModeStateMachine.CMD_DISABLE_WIFI: 304 Log.d(TAG, "Switching from " + getCurrentMode() + " to WifiDisabled"); 305 mModeStateMachine.transitionTo(mWifiDisabledState); 306 break; 307 default: 308 return NOT_HANDLED; 309 } 310 return HANDLED; 311 } 312 313 class ModeActiveState extends State { 314 ActiveModeManager mManager; 315 @Override processMessage(Message message)316 public boolean processMessage(Message message) { 317 // handle messages for changing modes here 318 return NOT_HANDLED; 319 } 320 321 @Override exit()322 public void exit() { 323 // Active states must have a mode manager, so this should not be null, but it isn't 324 // obvious from the structure - add a null check here, just in case this is missed 325 // in the future 326 if (mManager != null) { 327 mManager.stop(); 328 mActiveModeManagers.remove(mManager); 329 updateScanMode(); 330 } 331 updateBatteryStatsWifiState(false); 332 } 333 334 // Hook to be used by sub-classes of ModeActiveState to indicate the completion of 335 // bringup of the corresponding mode. onModeActivationComplete()336 public void onModeActivationComplete() { 337 updateScanMode(); 338 } 339 340 // Update the scan state based on all active mode managers. 341 // Note: This is an overkill currently because there is only 1 of scan-only or client 342 // mode present today. updateScanMode()343 private void updateScanMode() { 344 boolean scanEnabled = false; 345 boolean scanningForHiddenNetworksEnabled = false; 346 for (ActiveModeManager modeManager : mActiveModeManagers) { 347 @ActiveModeManager.ScanMode int scanState = modeManager.getScanMode(); 348 switch (scanState) { 349 case ActiveModeManager.SCAN_NONE: 350 break; 351 case ActiveModeManager.SCAN_WITHOUT_HIDDEN_NETWORKS: 352 scanEnabled = true; 353 break; 354 case ActiveModeManager.SCAN_WITH_HIDDEN_NETWORKS: 355 scanEnabled = true; 356 scanningForHiddenNetworksEnabled = true; 357 break; 358 } 359 } 360 mScanRequestProxy.enableScanning(scanEnabled, scanningForHiddenNetworksEnabled); 361 } 362 } 363 364 class WifiDisabledState extends ModeActiveState { 365 @Override enter()366 public void enter() { 367 Log.d(TAG, "Entering WifiDisabledState"); 368 } 369 370 @Override processMessage(Message message)371 public boolean processMessage(Message message) { 372 Log.d(TAG, "received a message in WifiDisabledState: " + message); 373 if (checkForAndHandleModeChange(message)) { 374 return HANDLED; 375 } 376 return NOT_HANDLED; 377 } 378 379 @Override exit()380 public void exit() { 381 // do not have an active mode manager... nothing to clean up 382 } 383 384 } 385 386 class ClientModeActiveState extends ModeActiveState { 387 ClientListener mListener; 388 private class ClientListener implements ClientModeManager.Listener { 389 @Override onStateChanged(int state)390 public void onStateChanged(int state) { 391 // make sure this listener is still active 392 if (this != mListener) { 393 Log.d(TAG, "Client mode state change from previous manager"); 394 return; 395 } 396 397 Log.d(TAG, "State changed from client mode. state = " + state); 398 399 if (state == WifiManager.WIFI_STATE_UNKNOWN) { 400 // error while setting up client mode or an unexpected failure. 401 mModeStateMachine.sendMessage(CMD_CLIENT_MODE_FAILED, this); 402 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 403 // client mode stopped 404 mModeStateMachine.sendMessage(CMD_CLIENT_MODE_STOPPED, this); 405 } else if (state == WifiManager.WIFI_STATE_ENABLED) { 406 // client mode is ready to go 407 Log.d(TAG, "client mode active"); 408 onModeActivationComplete(); 409 } else { 410 // only care if client mode stopped or started, dropping 411 } 412 } 413 } 414 415 @Override enter()416 public void enter() { 417 Log.d(TAG, "Entering ClientModeActiveState"); 418 419 mListener = new ClientListener(); 420 mManager = mWifiInjector.makeClientModeManager(mListener); 421 mManager.start(); 422 mActiveModeManagers.add(mManager); 423 424 updateBatteryStatsWifiState(true); 425 } 426 427 @Override exit()428 public void exit() { 429 super.exit(); 430 mListener = null; 431 } 432 433 @Override processMessage(Message message)434 public boolean processMessage(Message message) { 435 if (checkForAndHandleModeChange(message)) { 436 return HANDLED; 437 } 438 439 switch(message.what) { 440 case CMD_START_CLIENT_MODE: 441 Log.d(TAG, "Received CMD_START_CLIENT_MODE when active - drop"); 442 break; 443 case CMD_CLIENT_MODE_FAILED: 444 if (mListener != message.obj) { 445 Log.d(TAG, "Client mode state change from previous manager"); 446 return HANDLED; 447 } 448 Log.d(TAG, "ClientMode failed, return to WifiDisabledState."); 449 // notify WifiController that ClientMode failed 450 mClientModeCallback.onStateChanged(WifiManager.WIFI_STATE_UNKNOWN); 451 mModeStateMachine.transitionTo(mWifiDisabledState); 452 break; 453 case CMD_CLIENT_MODE_STOPPED: 454 if (mListener != message.obj) { 455 Log.d(TAG, "Client mode state change from previous manager"); 456 return HANDLED; 457 } 458 459 Log.d(TAG, "ClientMode stopped, return to WifiDisabledState."); 460 // notify WifiController that ClientMode stopped 461 mClientModeCallback.onStateChanged(WifiManager.WIFI_STATE_DISABLED); 462 mModeStateMachine.transitionTo(mWifiDisabledState); 463 break; 464 default: 465 return NOT_HANDLED; 466 } 467 return NOT_HANDLED; 468 } 469 } 470 471 class ScanOnlyModeActiveState extends ModeActiveState { 472 ScanOnlyListener mListener; 473 private class ScanOnlyListener implements ScanOnlyModeManager.Listener { 474 @Override onStateChanged(int state)475 public void onStateChanged(int state) { 476 if (this != mListener) { 477 Log.d(TAG, "ScanOnly mode state change from previous manager"); 478 return; 479 } 480 481 if (state == WifiManager.WIFI_STATE_UNKNOWN) { 482 Log.d(TAG, "ScanOnlyMode mode failed"); 483 // error while setting up scan mode or an unexpected failure. 484 mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_FAILED, this); 485 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 486 Log.d(TAG, "ScanOnlyMode stopped"); 487 //scan only mode stopped 488 mModeStateMachine.sendMessage(CMD_SCAN_ONLY_MODE_STOPPED, this); 489 } else if (state == WifiManager.WIFI_STATE_ENABLED) { 490 // scan mode is ready to go 491 Log.d(TAG, "scan mode active"); 492 onModeActivationComplete(); 493 } else { 494 Log.d(TAG, "unexpected state update: " + state); 495 } 496 } 497 } 498 499 @Override enter()500 public void enter() { 501 Log.d(TAG, "Entering ScanOnlyModeActiveState"); 502 503 mListener = new ScanOnlyListener(); 504 mManager = mWifiInjector.makeScanOnlyModeManager(mListener); 505 mManager.start(); 506 mActiveModeManagers.add(mManager); 507 508 updateBatteryStatsWifiState(true); 509 updateBatteryStatsScanModeActive(); 510 } 511 512 @Override exit()513 public void exit() { 514 super.exit(); 515 mListener = null; 516 } 517 518 @Override processMessage(Message message)519 public boolean processMessage(Message message) { 520 if (checkForAndHandleModeChange(message)) { 521 return HANDLED; 522 } 523 524 switch(message.what) { 525 case CMD_START_SCAN_ONLY_MODE: 526 Log.d(TAG, "Received CMD_START_SCAN_ONLY_MODE when active - drop"); 527 break; 528 case CMD_SCAN_ONLY_MODE_FAILED: 529 if (mListener != message.obj) { 530 Log.d(TAG, "ScanOnly mode state change from previous manager"); 531 return HANDLED; 532 } 533 534 Log.d(TAG, "ScanOnlyMode failed, return to WifiDisabledState."); 535 // notify WifiController that ScanOnlyMode failed 536 mScanOnlyCallback.onStateChanged(WifiManager.WIFI_STATE_UNKNOWN); 537 mModeStateMachine.transitionTo(mWifiDisabledState); 538 break; 539 case CMD_SCAN_ONLY_MODE_STOPPED: 540 if (mListener != message.obj) { 541 Log.d(TAG, "ScanOnly mode state change from previous manager"); 542 return HANDLED; 543 } 544 545 Log.d(TAG, "ScanOnlyMode stopped, return to WifiDisabledState."); 546 // notify WifiController that ScanOnlyMode stopped 547 mScanOnlyCallback.onStateChanged(WifiManager.WIFI_STATE_DISABLED); 548 mModeStateMachine.transitionTo(mWifiDisabledState); 549 break; 550 default: 551 return NOT_HANDLED; 552 } 553 return HANDLED; 554 } 555 } 556 } // class ModeStateMachine 557 558 private class SoftApCallbackImpl extends ModeCallback implements WifiManager.SoftApCallback { 559 private int mMode; 560 SoftApCallbackImpl(int mode)561 private SoftApCallbackImpl(int mode) { 562 mMode = mode; 563 } 564 565 @Override onStateChanged(int state, int reason)566 public void onStateChanged(int state, int reason) { 567 if (state == WifiManager.WIFI_AP_STATE_DISABLED) { 568 mActiveModeManagers.remove(getActiveModeManager()); 569 updateBatteryStatsWifiState(false); 570 } else if (state == WifiManager.WIFI_AP_STATE_FAILED) { 571 mActiveModeManagers.remove(getActiveModeManager()); 572 updateBatteryStatsWifiState(false); 573 } 574 575 if (mSoftApCallback != null && mMode == WifiManager.IFACE_IP_MODE_TETHERED) { 576 mSoftApCallback.onStateChanged(state, reason); 577 } 578 } 579 580 @Override onNumClientsChanged(int numClients)581 public void onNumClientsChanged(int numClients) { 582 if (mSoftApCallback == null) { 583 Log.d(TAG, "SoftApCallback is null. Dropping NumClientsChanged event."); 584 } else if (mMode == WifiManager.IFACE_IP_MODE_TETHERED) { 585 mSoftApCallback.onNumClientsChanged(numClients); 586 } 587 } 588 } 589 startSoftAp(SoftApModeConfiguration softapConfig)590 private void startSoftAp(SoftApModeConfiguration softapConfig) { 591 Log.d(TAG, "Starting SoftApModeManager"); 592 593 WifiConfiguration config = softapConfig.getWifiConfiguration(); 594 if (config != null && config.SSID != null) { 595 Log.d(TAG, "Passing config to SoftApManager! " + config); 596 } else { 597 config = null; 598 } 599 600 SoftApCallbackImpl callback = new SoftApCallbackImpl(softapConfig.getTargetMode()); 601 ActiveModeManager manager = mWifiInjector.makeSoftApManager(callback, softapConfig); 602 callback.setActiveModeManager(manager); 603 manager.start(); 604 mActiveModeManagers.add(manager); 605 updateBatteryStatsWifiState(true); 606 } 607 608 /** 609 * Helper method to report wifi state as on/off (doesn't matter which mode). 610 * 611 * @param enabled boolean indicating that some mode has been turned on or off 612 */ updateBatteryStatsWifiState(boolean enabled)613 private void updateBatteryStatsWifiState(boolean enabled) { 614 try { 615 if (enabled) { 616 if (mActiveModeManagers.size() == 1) { 617 // only report wifi on if we haven't already 618 mBatteryStats.noteWifiOn(); 619 } 620 } else { 621 if (mActiveModeManagers.size() == 0) { 622 // only report if we don't have any active modes 623 mBatteryStats.noteWifiOff(); 624 } 625 } 626 } catch (RemoteException e) { 627 Log.e(TAG, "Failed to note battery stats in wifi"); 628 } 629 } 630 updateBatteryStatsScanModeActive()631 private void updateBatteryStatsScanModeActive() { 632 try { 633 mBatteryStats.noteWifiState(BatteryStats.WIFI_STATE_OFF_SCANNING, null); 634 } catch (RemoteException e) { 635 Log.e(TAG, "Failed to note battery stats in wifi"); 636 } 637 } 638 639 // callback used to receive callbacks about underlying native failures 640 private final class WifiNativeStatusListener implements StatusListener { 641 642 @Override onStatusChanged(boolean isReady)643 public void onStatusChanged(boolean isReady) { 644 if (!isReady) { 645 mHandler.post(() -> { 646 Log.e(TAG, "One of the native daemons died. Triggering recovery"); 647 mWifiDiagnostics.captureBugReportData( 648 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE); 649 650 // immediately trigger SelfRecovery if we receive a notice about an 651 // underlying daemon failure 652 mWifiInjector.getSelfRecovery().trigger(SelfRecovery.REASON_WIFINATIVE_FAILURE); 653 }); 654 } 655 } 656 }; 657 } 658