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.content.Intent; 22 import android.net.ConnectivityManager; 23 import android.net.ConnectivityManager.NetworkCallback; 24 import android.net.Network; 25 import android.net.NetworkCapabilities; 26 import android.net.NetworkRequest; 27 import android.net.wifi.WifiManager; 28 import android.os.Handler; 29 import android.os.HandlerExecutor; 30 import android.os.Looper; 31 import android.os.Message; 32 import android.os.PersistableBundle; 33 import android.os.UserHandle; 34 import android.telephony.AccessNetworkConstants; 35 import android.telephony.CarrierConfigManager; 36 import android.telephony.SubscriptionInfo; 37 import android.telephony.SubscriptionManager; 38 import android.telephony.ims.ImsException; 39 import android.telephony.ims.ImsMmTelManager; 40 import android.telephony.ims.ImsReasonInfo; 41 import android.telephony.ims.RegistrationManager; 42 import android.telephony.ims.feature.MmTelFeature; 43 import android.telephony.ims.stub.ImsRegistrationImplBase; 44 import android.text.TextUtils; 45 import android.util.Log; 46 47 import com.android.internal.util.IState; 48 import com.android.internal.util.Preconditions; 49 import com.android.internal.util.State; 50 import com.android.internal.util.StateMachine; 51 import com.android.server.wifi.WifiNative.InterfaceCallback; 52 import com.android.server.wifi.util.WifiHandler; 53 import com.android.wifi.resources.R; 54 55 import java.io.FileDescriptor; 56 import java.io.PrintWriter; 57 import java.util.List; 58 59 /** 60 * Manager WiFi in Client Mode where we connect to configured networks. 61 */ 62 public class ClientModeManager implements ActiveModeManager { 63 private static final String TAG = "WifiClientModeManager"; 64 65 private final ClientModeStateMachine mStateMachine; 66 67 private final Context mContext; 68 private final Clock mClock; 69 private final WifiNative mWifiNative; 70 private final WifiMetrics mWifiMetrics; 71 private final SarManager mSarManager; 72 private final WakeupController mWakeupController; 73 private final Listener mModeListener; 74 private final ClientModeImpl mClientModeImpl; 75 76 private String mClientInterfaceName; 77 private boolean mIfaceIsUp = false; 78 private DeferStopHandler mDeferStopHandler; 79 private @Role int mRole = ROLE_UNSPECIFIED; 80 private @Role int mTargetRole = ROLE_UNSPECIFIED; 81 private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 82 ClientModeManager(Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative, Listener listener, WifiMetrics wifiMetrics, SarManager sarManager, WakeupController wakeupController, ClientModeImpl clientModeImpl)83 ClientModeManager(Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative, 84 Listener listener, WifiMetrics wifiMetrics, SarManager sarManager, 85 WakeupController wakeupController, ClientModeImpl clientModeImpl) { 86 mContext = context; 87 mClock = clock; 88 mWifiNative = wifiNative; 89 mModeListener = listener; 90 mWifiMetrics = wifiMetrics; 91 mSarManager = sarManager; 92 mWakeupController = wakeupController; 93 mClientModeImpl = clientModeImpl; 94 mStateMachine = new ClientModeStateMachine(looper); 95 mDeferStopHandler = new DeferStopHandler(TAG, looper); 96 } 97 98 /** 99 * Start client mode. 100 */ 101 @Override start()102 public void start() { 103 mTargetRole = ROLE_CLIENT_SCAN_ONLY; 104 mStateMachine.sendMessage(ClientModeStateMachine.CMD_START); 105 } 106 107 /** 108 * Disconnect from any currently connected networks and stop client mode. 109 */ 110 @Override stop()111 public void stop() { 112 Log.d(TAG, " currentstate: " + getCurrentStateName()); 113 mTargetRole = ROLE_UNSPECIFIED; 114 if (mIfaceIsUp) { 115 updateConnectModeState(WifiManager.WIFI_STATE_DISABLING, 116 WifiManager.WIFI_STATE_ENABLED); 117 } else { 118 updateConnectModeState(WifiManager.WIFI_STATE_DISABLING, 119 WifiManager.WIFI_STATE_ENABLING); 120 } 121 mDeferStopHandler.start(getWifiOffDeferringTimeMs()); 122 } 123 124 @Override isStopping()125 public boolean isStopping() { 126 return mTargetRole == ROLE_UNSPECIFIED && mRole != ROLE_UNSPECIFIED; 127 } 128 129 private class DeferStopHandler extends WifiHandler { 130 private boolean mIsDeferring = false; 131 private ImsMmTelManager mImsMmTelManager = null; 132 private Looper mLooper = null; 133 private final Runnable mRunnable = () -> continueToStopWifi(); 134 private int mMaximumDeferringTimeMillis = 0; 135 private long mDeferringStartTimeMillis = 0; 136 private NetworkRequest mImsRequest = null; 137 private ConnectivityManager mConnectivityManager = null; 138 139 private RegistrationManager.RegistrationCallback mImsRegistrationCallback = 140 new RegistrationManager.RegistrationCallback() { 141 @Override 142 public void onRegistered(int imsRadioTech) { 143 Log.d(TAG, "on IMS registered on type " + imsRadioTech); 144 if (!mIsDeferring) return; 145 146 if (imsRadioTech != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 147 continueToStopWifi(); 148 } 149 } 150 151 @Override 152 public void onUnregistered(ImsReasonInfo imsReasonInfo) { 153 Log.d(TAG, "on IMS unregistered"); 154 // Wait for onLost in NetworkCallback 155 } 156 }; 157 158 private NetworkCallback mImsNetworkCallback = new NetworkCallback() { 159 private int mRegisteredImsNetworkCount = 0; 160 @Override 161 public void onAvailable(Network network) { 162 synchronized (this) { 163 Log.d(TAG, "IMS network available: " + network); 164 mRegisteredImsNetworkCount++; 165 } 166 } 167 168 @Override 169 public void onLost(Network network) { 170 synchronized (this) { 171 Log.d(TAG, "IMS network lost: " + network 172 + " ,isDeferring: " + mIsDeferring 173 + " ,registered IMS network count: " + mRegisteredImsNetworkCount); 174 mRegisteredImsNetworkCount--; 175 if (mIsDeferring && mRegisteredImsNetworkCount <= 0) { 176 mRegisteredImsNetworkCount = 0; 177 // Add delay for targets where IMS PDN down at modem takes additional delay. 178 int delay = mContext.getResources() 179 .getInteger(R.integer.config_wifiDelayDisconnectOnImsLostMs); 180 if (delay == 0 || !postDelayed(mRunnable, delay)) { 181 continueToStopWifi(); 182 } 183 } 184 } 185 } 186 }; 187 DeferStopHandler(String tag, Looper looper)188 DeferStopHandler(String tag, Looper looper) { 189 super(tag, looper); 190 mLooper = looper; 191 } 192 start(int delayMs)193 public void start(int delayMs) { 194 if (mIsDeferring) return; 195 196 mMaximumDeferringTimeMillis = delayMs; 197 mDeferringStartTimeMillis = mClock.getElapsedSinceBootMillis(); 198 // Most cases don't need delay, check it first to avoid unnecessary work. 199 if (delayMs == 0) { 200 continueToStopWifi(); 201 return; 202 } 203 204 mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(mActiveSubId); 205 if (mImsMmTelManager == null || !postDelayed(mRunnable, delayMs)) { 206 // if no delay or failed to add runnable, stop Wifi immediately. 207 continueToStopWifi(); 208 return; 209 } 210 211 mIsDeferring = true; 212 Log.d(TAG, "Start DeferWifiOff handler with deferring time " 213 + delayMs + " ms for subId: " + mActiveSubId); 214 try { 215 mImsMmTelManager.registerImsRegistrationCallback( 216 new HandlerExecutor(new Handler(mLooper)), 217 mImsRegistrationCallback); 218 } catch (RuntimeException | ImsException e) { 219 Log.e(TAG, "registerImsRegistrationCallback failed", e); 220 continueToStopWifi(); 221 return; 222 } 223 224 mImsRequest = new NetworkRequest.Builder() 225 .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS) 226 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 227 .build(); 228 229 mConnectivityManager = 230 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); 231 232 mConnectivityManager.registerNetworkCallback(mImsRequest, mImsNetworkCallback, 233 new Handler(mLooper)); 234 } 235 continueToStopWifi()236 private void continueToStopWifi() { 237 Log.d(TAG, "The target role " + mTargetRole); 238 239 int deferringDurationMillis = 240 (int) (mClock.getElapsedSinceBootMillis() - mDeferringStartTimeMillis); 241 boolean isTimedOut = mMaximumDeferringTimeMillis > 0 242 && deferringDurationMillis >= mMaximumDeferringTimeMillis; 243 if (mTargetRole == ROLE_UNSPECIFIED) { 244 Log.d(TAG, "Continue to stop wifi"); 245 mStateMachine.quitNow(); 246 mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis); 247 } else if (mTargetRole == ROLE_CLIENT_SCAN_ONLY) { 248 if (!mWifiNative.switchClientInterfaceToScanMode(mClientInterfaceName)) { 249 mModeListener.onStartFailure(); 250 } else { 251 mStateMachine.sendMessage( 252 ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE); 253 mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis); 254 } 255 } else { 256 updateConnectModeState(WifiManager.WIFI_STATE_ENABLED, 257 WifiManager.WIFI_STATE_DISABLING); 258 } 259 260 if (!mIsDeferring) return; 261 262 Log.d(TAG, "Stop DeferWifiOff handler."); 263 removeCallbacks(mRunnable); 264 if (mImsMmTelManager != null) { 265 try { 266 mImsMmTelManager.unregisterImsRegistrationCallback(mImsRegistrationCallback); 267 } catch (RuntimeException e) { 268 Log.e(TAG, "unregisterImsRegistrationCallback failed", e); 269 } 270 } 271 272 if (mConnectivityManager != null) { 273 mConnectivityManager.unregisterNetworkCallback(mImsNetworkCallback); 274 } 275 276 mIsDeferring = false; 277 } 278 } 279 280 /** 281 * Get deferring time before turning off WiFi. 282 */ getWifiOffDeferringTimeMs()283 private int getWifiOffDeferringTimeMs() { 284 SubscriptionManager subscriptionManager = (SubscriptionManager) mContext.getSystemService( 285 Context.TELEPHONY_SUBSCRIPTION_SERVICE); 286 if (subscriptionManager == null) { 287 Log.d(TAG, "SubscriptionManager not found"); 288 return 0; 289 } 290 291 List<SubscriptionInfo> subInfoList = subscriptionManager.getActiveSubscriptionInfoList(); 292 if (subInfoList == null) { 293 Log.d(TAG, "Active SubscriptionInfo list not found"); 294 return 0; 295 } 296 297 // Get the maximum delay for the active subscription latched on IWLAN. 298 int maxDelay = 0; 299 for (SubscriptionInfo subInfo : subInfoList) { 300 int curDelay = getWifiOffDeferringTimeMs(subInfo.getSubscriptionId()); 301 if (curDelay > maxDelay) { 302 maxDelay = curDelay; 303 mActiveSubId = subInfo.getSubscriptionId(); 304 } 305 } 306 return maxDelay; 307 } 308 getWifiOffDeferringTimeMs(int subId)309 private int getWifiOffDeferringTimeMs(int subId) { 310 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 311 Log.d(TAG, "Invalid Subscription ID: " + subId); 312 return 0; 313 } 314 315 ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 316 // If no wifi calling, no delay 317 if (!imsMmTelManager.isAvailable( 318 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 319 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)) { 320 Log.d(TAG, "IMS not registered over IWLAN for subId: " + subId); 321 return 0; 322 } 323 324 CarrierConfigManager configManager = 325 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 326 PersistableBundle config = configManager.getConfigForSubId(subId); 327 return (config != null) 328 ? config.getInt(CarrierConfigManager.Ims.KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT) 329 : 0; 330 } 331 332 @Override getRole()333 public @Role int getRole() { 334 return mRole; 335 } 336 337 @Override setRole(@ole int role)338 public void setRole(@Role int role) { 339 Preconditions.checkState(CLIENT_ROLES.contains(role)); 340 if (role == ROLE_CLIENT_SCAN_ONLY) { 341 mTargetRole = role; 342 // Switch client mode manager to scan only mode. 343 mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE); 344 } else if (CLIENT_CONNECTIVITY_ROLES.contains(role)) { 345 mTargetRole = role; 346 // Switch client mode manager to connect mode. 347 mStateMachine.sendMessage(ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE, role); 348 } 349 } 350 351 /** 352 * Dump info about this ClientMode manager. 353 */ 354 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)355 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 356 pw.println("--Dump of ClientModeManager--"); 357 358 pw.println("current StateMachine mode: " + getCurrentStateName()); 359 pw.println("mRole: " + mRole); 360 pw.println("mTargetRole: " + mTargetRole); 361 pw.println("mClientInterfaceName: " + mClientInterfaceName); 362 pw.println("mIfaceIsUp: " + mIfaceIsUp); 363 mStateMachine.dump(fd, pw, args); 364 } 365 getCurrentStateName()366 private String getCurrentStateName() { 367 IState currentState = mStateMachine.getCurrentState(); 368 369 if (currentState != null) { 370 return currentState.getName(); 371 } 372 373 return "StateMachine not active"; 374 } 375 376 /** 377 * Update Wifi state and send the broadcast. 378 * @param newState new Wifi state 379 * @param currentState current wifi state 380 */ updateConnectModeState(int newState, int currentState)381 private void updateConnectModeState(int newState, int currentState) { 382 if (newState == WifiManager.WIFI_STATE_UNKNOWN) { 383 // do not need to broadcast failure to system 384 return; 385 } 386 if (mRole != ROLE_CLIENT_PRIMARY) { 387 // do not raise public broadcast unless this is the primary client mode manager 388 return; 389 } 390 391 mClientModeImpl.setWifiStateForApiCalls(newState); 392 393 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 394 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 395 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState); 396 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, currentState); 397 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 398 } 399 400 private class ClientModeStateMachine extends StateMachine { 401 // Commands for the state machine. 402 public static final int CMD_START = 0; 403 public static final int CMD_SWITCH_TO_SCAN_ONLY_MODE = 1; 404 public static final int CMD_SWITCH_TO_CONNECT_MODE = 2; 405 public static final int CMD_INTERFACE_STATUS_CHANGED = 3; 406 public static final int CMD_INTERFACE_DESTROYED = 4; 407 public static final int CMD_INTERFACE_DOWN = 5; 408 public static final int CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE = 6; 409 private final State mIdleState = new IdleState(); 410 private final State mStartedState = new StartedState(); 411 private final State mScanOnlyModeState = new ScanOnlyModeState(); 412 private final State mConnectModeState = new ConnectModeState(); 413 414 private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() { 415 @Override 416 public void onDestroyed(String ifaceName) { 417 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 418 Log.d(TAG, "STA iface " + ifaceName + " was destroyed, stopping client mode"); 419 420 // we must immediately clean up state in ClientModeImpl to unregister 421 // all client mode related objects 422 // Note: onDestroyed is only called from the main Wifi thread 423 mClientModeImpl.handleIfaceDestroyed(); 424 425 sendMessage(CMD_INTERFACE_DESTROYED); 426 } 427 } 428 429 @Override 430 public void onUp(String ifaceName) { 431 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 432 sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1); 433 } 434 } 435 436 @Override 437 public void onDown(String ifaceName) { 438 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 439 sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0); 440 } 441 } 442 }; 443 ClientModeStateMachine(Looper looper)444 ClientModeStateMachine(Looper looper) { 445 super(TAG, looper); 446 447 // CHECKSTYLE:OFF IndentationCheck 448 addState(mIdleState); 449 addState(mStartedState); 450 addState(mScanOnlyModeState, mStartedState); 451 addState(mConnectModeState, mStartedState); 452 // CHECKSTYLE:ON IndentationCheck 453 454 setInitialState(mIdleState); 455 start(); 456 } 457 458 private class IdleState extends State { 459 @Override enter()460 public void enter() { 461 Log.d(TAG, "entering IdleState"); 462 mClientInterfaceName = null; 463 mIfaceIsUp = false; 464 } 465 466 @Override processMessage(Message message)467 public boolean processMessage(Message message) { 468 switch (message.what) { 469 case CMD_START: 470 // Always start in scan mode first. 471 mClientInterfaceName = 472 mWifiNative.setupInterfaceForClientInScanMode( 473 mWifiNativeInterfaceCallback); 474 if (TextUtils.isEmpty(mClientInterfaceName)) { 475 Log.e(TAG, "Failed to create ClientInterface. Sit in Idle"); 476 mModeListener.onStartFailure(); 477 break; 478 } 479 transitionTo(mScanOnlyModeState); 480 break; 481 default: 482 Log.d(TAG, "received an invalid message: " + message); 483 return NOT_HANDLED; 484 } 485 return HANDLED; 486 } 487 } 488 489 private class StartedState extends State { 490 onUpChanged(boolean isUp)491 private void onUpChanged(boolean isUp) { 492 if (isUp == mIfaceIsUp) { 493 return; // no change 494 } 495 mIfaceIsUp = isUp; 496 if (!isUp) { 497 // if the interface goes down we should exit and go back to idle state. 498 Log.d(TAG, "interface down!"); 499 mStateMachine.sendMessage(CMD_INTERFACE_DOWN); 500 } 501 } 502 503 @Override enter()504 public void enter() { 505 Log.d(TAG, "entering StartedState"); 506 mIfaceIsUp = false; 507 onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName)); 508 } 509 510 @Override processMessage(Message message)511 public boolean processMessage(Message message) { 512 switch(message.what) { 513 case CMD_START: 514 // Already started, ignore this command. 515 break; 516 case CMD_SWITCH_TO_CONNECT_MODE: 517 mRole = message.arg1; // could be any one of possible connect mode roles. 518 updateConnectModeState(WifiManager.WIFI_STATE_ENABLING, 519 WifiManager.WIFI_STATE_DISABLED); 520 if (!mWifiNative.switchClientInterfaceToConnectivityMode( 521 mClientInterfaceName)) { 522 updateConnectModeState(WifiManager.WIFI_STATE_UNKNOWN, 523 WifiManager.WIFI_STATE_ENABLING); 524 updateConnectModeState(WifiManager.WIFI_STATE_DISABLED, 525 WifiManager.WIFI_STATE_UNKNOWN); 526 mModeListener.onStartFailure(); 527 break; 528 } 529 transitionTo(mConnectModeState); 530 break; 531 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 532 updateConnectModeState(WifiManager.WIFI_STATE_DISABLING, 533 WifiManager.WIFI_STATE_ENABLED); 534 mDeferStopHandler.start(getWifiOffDeferringTimeMs()); 535 break; 536 case CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE: 537 transitionTo(mScanOnlyModeState); 538 break; 539 case CMD_INTERFACE_DOWN: 540 Log.e(TAG, "Detected an interface down, reporting failure to " 541 + "SelfRecovery"); 542 mClientModeImpl.failureDetected(SelfRecovery.REASON_STA_IFACE_DOWN); 543 transitionTo(mIdleState); 544 break; 545 case CMD_INTERFACE_STATUS_CHANGED: 546 boolean isUp = message.arg1 == 1; 547 onUpChanged(isUp); 548 break; 549 case CMD_INTERFACE_DESTROYED: 550 Log.d(TAG, "interface destroyed - client mode stopping"); 551 mClientInterfaceName = null; 552 transitionTo(mIdleState); 553 break; 554 default: 555 return NOT_HANDLED; 556 } 557 return HANDLED; 558 } 559 560 /** 561 * Clean up state, unregister listeners and update wifi state. 562 */ 563 @Override exit()564 public void exit() { 565 mClientModeImpl.setOperationalMode(ClientModeImpl.DISABLED_MODE, null); 566 567 if (mClientInterfaceName != null) { 568 mWifiNative.teardownInterface(mClientInterfaceName); 569 mClientInterfaceName = null; 570 mIfaceIsUp = false; 571 } 572 573 // once we leave started, nothing else to do... stop the state machine 574 mRole = ROLE_UNSPECIFIED; 575 mStateMachine.quitNow(); 576 mModeListener.onStopped(); 577 } 578 } 579 580 private class ScanOnlyModeState extends State { 581 @Override enter()582 public void enter() { 583 Log.d(TAG, "entering ScanOnlyModeState"); 584 mClientModeImpl.setOperationalMode(ClientModeImpl.SCAN_ONLY_MODE, 585 mClientInterfaceName); 586 mRole = ROLE_CLIENT_SCAN_ONLY; 587 mModeListener.onStarted(); 588 589 // Inform sar manager that scan only is being enabled 590 mSarManager.setScanOnlyWifiState(WifiManager.WIFI_STATE_ENABLED); 591 mWakeupController.start(); 592 } 593 594 @Override processMessage(Message message)595 public boolean processMessage(Message message) { 596 switch (message.what) { 597 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 598 // Already in scan only mode, ignore this command. 599 break; 600 default: 601 return NOT_HANDLED; 602 } 603 return HANDLED; 604 } 605 606 @Override exit()607 public void exit() { 608 // Inform sar manager that scan only is being disabled 609 mSarManager.setScanOnlyWifiState(WifiManager.WIFI_STATE_DISABLED); 610 mWakeupController.stop(); 611 } 612 } 613 614 private class ConnectModeState extends State { 615 @Override enter()616 public void enter() { 617 Log.d(TAG, "entering ConnectModeState"); 618 mClientModeImpl.setOperationalMode(ClientModeImpl.CONNECT_MODE, 619 mClientInterfaceName); 620 mModeListener.onStarted(); 621 updateConnectModeState(WifiManager.WIFI_STATE_ENABLED, 622 WifiManager.WIFI_STATE_ENABLING); 623 624 // Inform sar manager that wifi is Enabled 625 mSarManager.setClientWifiState(WifiManager.WIFI_STATE_ENABLED); 626 } 627 628 @Override processMessage(Message message)629 public boolean processMessage(Message message) { 630 switch (message.what) { 631 case CMD_SWITCH_TO_CONNECT_MODE: 632 int newRole = message.arg1; 633 // Already in connect mode, only switching the connectivity roles. 634 if (newRole != mRole) { 635 mRole = newRole; 636 mModeListener.onStarted(); 637 } 638 break; 639 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 640 updateConnectModeState(WifiManager.WIFI_STATE_DISABLING, 641 WifiManager.WIFI_STATE_ENABLED); 642 return NOT_HANDLED; // Handled in StartedState. 643 case CMD_INTERFACE_DOWN: 644 updateConnectModeState(WifiManager.WIFI_STATE_DISABLING, 645 WifiManager.WIFI_STATE_UNKNOWN); 646 return NOT_HANDLED; // Handled in StartedState. 647 case CMD_INTERFACE_STATUS_CHANGED: 648 boolean isUp = message.arg1 == 1; 649 if (isUp == mIfaceIsUp) { 650 break; // no change 651 } 652 if (!isUp) { 653 if (!mClientModeImpl.isConnectedMacRandomizationEnabled()) { 654 // Handle the error case where our underlying interface went down if 655 // we do not have mac randomization enabled (b/72459123). 656 // if the interface goes down we should exit and go back to idle 657 // state. 658 updateConnectModeState(WifiManager.WIFI_STATE_UNKNOWN, 659 WifiManager.WIFI_STATE_ENABLED); 660 } else { 661 return HANDLED; // For MAC randomization, ignore... 662 } 663 } 664 return NOT_HANDLED; // Handled in StartedState. 665 case CMD_INTERFACE_DESTROYED: 666 updateConnectModeState(WifiManager.WIFI_STATE_DISABLING, 667 WifiManager.WIFI_STATE_ENABLED); 668 return NOT_HANDLED; // Handled in StartedState. 669 default: 670 return NOT_HANDLED; 671 } 672 return HANDLED; 673 } 674 675 @Override exit()676 public void exit() { 677 updateConnectModeState(WifiManager.WIFI_STATE_DISABLED, 678 WifiManager.WIFI_STATE_DISABLING); 679 680 // Inform sar manager that wifi is being disabled 681 mSarManager.setClientWifiState(WifiManager.WIFI_STATE_DISABLED); 682 } 683 } 684 } 685 } 686