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 static android.net.wifi.WifiManager.WIFI_STATE_DISABLING; 20 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED; 21 import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING; 22 23 import static com.android.server.wifi.util.GeneralUtil.bitsetToLong; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.net.ConnectivityManager; 30 import android.net.ConnectivityManager.NetworkCallback; 31 import android.net.DhcpResultsParcelable; 32 import android.net.MacAddress; 33 import android.net.Network; 34 import android.net.NetworkCapabilities; 35 import android.net.NetworkRequest; 36 import android.net.wifi.BlockingOption; 37 import android.net.wifi.IWifiConnectedNetworkScorer; 38 import android.net.wifi.WifiAnnotations; 39 import android.net.wifi.WifiConfiguration; 40 import android.net.wifi.WifiInfo; 41 import android.net.wifi.WifiManager; 42 import android.net.wifi.WifiManager.DeviceMobilityState; 43 import android.net.wifi.hotspot2.IProvisioningCallback; 44 import android.net.wifi.hotspot2.OsuProvider; 45 import android.net.wifi.nl80211.DeviceWiphyCapabilities; 46 import android.os.Handler; 47 import android.os.IBinder; 48 import android.os.Looper; 49 import android.os.Message; 50 import android.os.PersistableBundle; 51 import android.os.UserHandle; 52 import android.os.WorkSource; 53 import android.telephony.AccessNetworkConstants; 54 import android.telephony.CarrierConfigManager; 55 import android.telephony.SubscriptionInfo; 56 import android.telephony.SubscriptionManager; 57 import android.telephony.ims.ImsException; 58 import android.telephony.ims.ImsMmTelManager; 59 import android.telephony.ims.ImsReasonInfo; 60 import android.telephony.ims.RegistrationManager; 61 import android.telephony.ims.feature.MmTelFeature; 62 import android.telephony.ims.stub.ImsRegistrationImplBase; 63 import android.text.TextUtils; 64 import android.util.Log; 65 66 import androidx.annotation.Keep; 67 68 import com.android.internal.util.IState; 69 import com.android.internal.util.State; 70 import com.android.internal.util.StateMachine; 71 import com.android.modules.utils.HandlerExecutor; 72 import com.android.server.wifi.WifiNative.InterfaceCallback; 73 import com.android.server.wifi.WifiNative.InterfaceEventCallback; 74 import com.android.server.wifi.WifiNative.RxFateReport; 75 import com.android.server.wifi.WifiNative.TxFateReport; 76 import com.android.server.wifi.util.ActionListenerWrapper; 77 import com.android.server.wifi.util.StateMachineObituary; 78 import com.android.wifi.resources.R; 79 80 import java.io.FileDescriptor; 81 import java.io.PrintWriter; 82 import java.util.ArrayDeque; 83 import java.util.ArrayList; 84 import java.util.BitSet; 85 import java.util.List; 86 import java.util.Set; 87 88 /** 89 * Manage WiFi in Client Mode where we connect to configured networks and in Scan Only Mode where 90 * we do not connect to configured networks but do perform scanning. 91 * 92 * An instance of this class is active to manage each client interface. This is in contrast to 93 * {@link DefaultClientModeManager} which handles calls when no client interfaces are active. 94 * 95 * This class will dynamically instantiate {@link ClientModeImpl} when it enters client mode, and 96 * tear it down when it exits client mode. No instance of ClientModeImpl will be active in 97 * scan-only mode, instead {@link ScanOnlyModeImpl} will be used to respond to calls. 98 * 99 * <pre> 100 * ActiveModeWarden 101 * / \ 102 * / \ 103 * ConcreteClientModeManager DefaultClientModeManager 104 * (Client Mode + Scan Only Mode) (Wifi off) 105 * / \ 106 * / \ 107 * ClientModeImpl ScanOnlyModeImpl 108 * </pre> 109 */ 110 public class ConcreteClientModeManager implements ClientModeManager { 111 private static final String TAG = "WifiClientModeManager"; 112 113 private final ClientModeStateMachine mStateMachine; 114 115 private final Context mContext; 116 private final Clock mClock; 117 private final WifiNative mWifiNative; 118 private final WifiMetrics mWifiMetrics; 119 private final WakeupController mWakeupController; 120 private final WifiInjector mWifiInjector; 121 private final SelfRecovery mSelfRecovery; 122 private final WifiGlobals mWifiGlobals; 123 private final DefaultClientModeManager mDefaultClientModeManager; 124 private final ClientModeManagerBroadcastQueue mBroadcastQueue; 125 private final long mId; 126 private final Graveyard mGraveyard = new Graveyard(); 127 128 private String mClientInterfaceName; 129 private boolean mIfaceIsUp = false; 130 private boolean mShouldReduceNetworkScore = false; 131 private final DeferStopHandler mDeferStopHandler; 132 @Nullable 133 private ClientRole mRole = null; 134 @Nullable 135 private ClientRole mPreviousRole = null; 136 private long mLastRoleChangeSinceBootMs = 0; 137 @Nullable 138 private WorkSource mRequestorWs = null; 139 @NonNull 140 private Listener<ConcreteClientModeManager> mModeListener; 141 /** Caches the latest role change request. This is needed for the IMS dereg delay */ 142 @Nullable 143 private RoleChangeInfo mTargetRoleChangeInfo; 144 private boolean mVerboseLoggingEnabled = false; 145 private int mActiveSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 146 private boolean mWifiStateChangeBroadcastEnabled = true; 147 private boolean mSecondaryInternet = false; 148 private boolean mIsDbs = false; 149 /** 150 * mClientModeImpl is only non-null when in {@link ClientModeStateMachine.ConnectModeState} - 151 * it will be null in all other states 152 */ 153 @Nullable 154 private ClientModeImpl mClientModeImpl = null; 155 156 @Nullable 157 private ScanOnlyModeImpl mScanOnlyModeImpl = null; 158 159 private boolean mIsStopped = true; 160 ConcreteClientModeManager( Context context, @NonNull Looper looper, Clock clock, WifiNative wifiNative, @NonNull Listener<ConcreteClientModeManager> listener, WifiMetrics wifiMetrics, WakeupController wakeupController, WifiInjector wifiInjector, SelfRecovery selfRecovery, WifiGlobals wifiGlobals, DefaultClientModeManager defaultClientModeManager, long id, @NonNull WorkSource requestorWs, @NonNull ClientRole role, @NonNull ClientModeManagerBroadcastQueue broadcastQueue, boolean verboseLoggingEnabled)161 ConcreteClientModeManager( 162 Context context, @NonNull Looper looper, Clock clock, 163 WifiNative wifiNative, @NonNull Listener<ConcreteClientModeManager> listener, 164 WifiMetrics wifiMetrics, 165 WakeupController wakeupController, WifiInjector wifiInjector, 166 SelfRecovery selfRecovery, WifiGlobals wifiGlobals, 167 DefaultClientModeManager defaultClientModeManager, long id, 168 @NonNull WorkSource requestorWs, @NonNull ClientRole role, 169 @NonNull ClientModeManagerBroadcastQueue broadcastQueue, 170 boolean verboseLoggingEnabled) { 171 mContext = context; 172 mClock = clock; 173 mWifiNative = wifiNative; 174 mModeListener = listener; 175 mWifiMetrics = wifiMetrics; 176 mWakeupController = wakeupController; 177 mWifiInjector = wifiInjector; 178 mStateMachine = new ClientModeStateMachine(looper); 179 mDeferStopHandler = new DeferStopHandler(looper); 180 mSelfRecovery = selfRecovery; 181 mWifiGlobals = wifiGlobals; 182 mDefaultClientModeManager = defaultClientModeManager; 183 mId = id; 184 mTargetRoleChangeInfo = new RoleChangeInfo(role, requestorWs, listener); 185 mBroadcastQueue = broadcastQueue; 186 enableVerboseLogging(verboseLoggingEnabled); 187 mStateMachine.sendMessage(ClientModeStateMachine.CMD_START, mTargetRoleChangeInfo); 188 } 189 getTag()190 private String getTag() { 191 return TAG + "[" + mId + ":" + (mClientInterfaceName == null ? "unknown" 192 : mClientInterfaceName) + "]"; 193 } 194 195 /** 196 * Sets whether to send WIFI_STATE_CHANGED broadcast for this ClientModeManager. 197 * @param enabled 198 */ setWifiStateChangeBroadcastEnabled(boolean enabled)199 public void setWifiStateChangeBroadcastEnabled(boolean enabled) { 200 mWifiStateChangeBroadcastEnabled = enabled; 201 } 202 203 /** 204 * Sets whether this ClientModeManager is for secondary STA with internet. 205 * @param secondaryInternet whether the ClientModeManager is for secondary internet. 206 */ 207 @Keep setSecondaryInternet(boolean secondaryInternet)208 public void setSecondaryInternet(boolean secondaryInternet) { 209 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 210 if (mRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) { 211 mSecondaryInternet = secondaryInternet; 212 } 213 } 214 215 /** 216 * Sets whether this ClientModeManager is for DBS AP multi internet. 217 * @param isDbs whether the ClientModeManager is connecting to to the same SSID as primary. 218 */ 219 @Keep setSecondaryInternetDbsAp(boolean isDbs)220 public void setSecondaryInternetDbsAp(boolean isDbs) { 221 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 222 if (mRole == ROLE_CLIENT_SECONDARY_LONG_LIVED) { 223 mIsDbs = isDbs; 224 } 225 } 226 227 /** 228 * Returns whether this ClientModeManager is for secondary STA with internet. 229 * @return true if it is for secondary STA with internet. 230 */ isSecondaryInternet()231 public boolean isSecondaryInternet() { 232 return mSecondaryInternet; 233 } 234 235 /** 236 * Returns whether this ClientModeManager is for DBS AP multi internet. 237 * @return true if the ClientModeManager is connecting to to the same SSID as primary. 238 */ isSecondaryInternetDbsAp()239 public boolean isSecondaryInternetDbsAp() { 240 if (!isSecondaryInternet()) { 241 Log.wtf(TAG, "isSecondaryInternetDbsAp called while not secondary internet!?"); 242 (new Throwable()).printStackTrace(); 243 } 244 return mIsDbs; 245 } 246 247 /** 248 * Disconnect from any currently connected networks and stop client mode. 249 */ 250 @Override stop()251 public void stop() { 252 Log.d(getTag(), " currentstate: " + getCurrentStateName()); 253 mTargetRoleChangeInfo = null; 254 if (mIfaceIsUp) { 255 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 256 WifiManager.WIFI_STATE_ENABLED); 257 } else { 258 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 259 WifiManager.WIFI_STATE_ENABLING); 260 } 261 mDeferStopHandler.start(getWifiOffDeferringTimeMs()); 262 } 263 264 private class DeferStopHandler extends Handler { 265 private boolean mIsDeferring = false; 266 private ImsMmTelManager mImsMmTelManager = null; 267 private Looper mLooper = null; 268 private final Runnable mRunnable = () -> continueToStopWifi(); 269 private int mMaximumDeferringTimeMillis = 0; 270 private long mDeferringStartTimeMillis = 0; 271 private ConnectivityManager mConnectivityManager = null; 272 private List<ImsNetworkCallback> mImsNetworks = new ArrayList<>(); 273 private boolean mIsImsNetworkUnregistered = false; 274 275 private final RegistrationManager.RegistrationCallback mImsRegistrationCallback = 276 new RegistrationManager.RegistrationCallback() { 277 @Override 278 public void onRegistered(int imsRadioTech) { 279 Log.d(getTag(), "on IMS registered on type " + imsRadioTech); 280 if (!mIsDeferring) return; 281 282 if (imsRadioTech != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 283 continueToStopWifi(); 284 } 285 } 286 287 @Override 288 public void onUnregistered(ImsReasonInfo imsReasonInfo) { 289 Log.d(getTag(), "on IMS unregistered"); 290 mIsImsNetworkUnregistered = true; 291 checkAndContinueToStopWifi(); 292 } 293 }; 294 295 private final class ImsNetworkCallback extends NetworkCallback { 296 private final int mNetworkType; 297 private int mRegisteredImsNetworkCount = 0; 298 299 /** 300 * Constructor for ImsNetworkCallback. 301 * 302 * @param type One of android.net.NetworkCapabilities.NetCapability. 303 */ ImsNetworkCallback(int type)304 ImsNetworkCallback(int type) { 305 mNetworkType = type; 306 } 307 308 @Override onAvailable(Network network)309 public void onAvailable(Network network) { 310 synchronized (this) { 311 Log.d(getTag(), "IMS network available: " + network 312 + ", type: " + mNetworkType); 313 mRegisteredImsNetworkCount++; 314 } 315 } 316 317 @Override onLost(Network network)318 public void onLost(Network network) { 319 synchronized (this) { 320 Log.d(getTag(), "IMS network lost: " + network 321 + " ,isDeferring: " + mIsDeferring 322 + " ,registered IMS network count: " + mRegisteredImsNetworkCount 323 + ", type: " + mNetworkType); 324 mRegisteredImsNetworkCount--; 325 if (mIsDeferring && mRegisteredImsNetworkCount <= 0) { 326 mRegisteredImsNetworkCount = 0; 327 checkAndContinueToStopWifi(); 328 } 329 } 330 } 331 isNetworkLost()332 public boolean isNetworkLost() { 333 return 0 == mRegisteredImsNetworkCount; 334 } 335 } 336 DeferStopHandler(Looper looper)337 DeferStopHandler(Looper looper) { 338 super(looper); 339 mLooper = looper; 340 mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); 341 } 342 start(int delayMs)343 public void start(int delayMs) { 344 if (mIsDeferring) return; 345 346 mMaximumDeferringTimeMillis = delayMs; 347 mDeferringStartTimeMillis = mClock.getElapsedSinceBootMillis(); 348 // Most cases don't need delay, check it first to avoid unnecessary work. 349 if (delayMs == 0) { 350 continueToStopWifi(); 351 return; 352 } 353 354 mImsMmTelManager = ImsMmTelManager.createForSubscriptionId(mActiveSubId); 355 if (mImsMmTelManager == null || !postDelayed(mRunnable, delayMs)) { 356 // if no delay or failed to add runnable, stop Wifi immediately. 357 continueToStopWifi(); 358 return; 359 } 360 361 mIsDeferring = true; 362 Log.d(getTag(), "Start DeferWifiOff handler with deferring time " 363 + delayMs + " ms for subId: " + mActiveSubId); 364 try { 365 mImsMmTelManager.registerImsRegistrationCallback( 366 new HandlerExecutor(new Handler(mLooper)), 367 mImsRegistrationCallback); 368 } catch (RuntimeException | ImsException e) { 369 Log.e(getTag(), "registerImsRegistrationCallback failed", e); 370 continueToStopWifi(); 371 return; 372 } 373 374 registerImsNetworkCallback(NetworkCapabilities.NET_CAPABILITY_IMS); 375 registerImsNetworkCallback(NetworkCapabilities.NET_CAPABILITY_EIMS); 376 } 377 registerImsNetworkCallback(int imsType)378 private void registerImsNetworkCallback(int imsType) { 379 NetworkRequest imsRequest = new NetworkRequest.Builder() 380 .addCapability(imsType) 381 .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) 382 .build(); 383 ImsNetworkCallback imsCallback = new ImsNetworkCallback(imsType); 384 mConnectivityManager.registerNetworkCallback(imsRequest, imsCallback, 385 new Handler(mLooper)); 386 mImsNetworks.add(imsCallback); 387 } 388 checkAndContinueToStopWifi()389 private void checkAndContinueToStopWifi() { 390 if (!mIsImsNetworkUnregistered) return; 391 392 for (ImsNetworkCallback c: mImsNetworks) { 393 if (!c.isNetworkLost()) return; 394 } 395 396 // Add delay for targets where IMS PDN down at modem takes additional delay. 397 int delay = mContext.getResources() 398 .getInteger(R.integer.config_wifiDelayDisconnectOnImsLostMs); 399 if (delay == 0 || !postDelayed(mRunnable, delay)) { 400 continueToStopWifi(); 401 } 402 } 403 continueToStopWifi()404 private void continueToStopWifi() { 405 Log.d(getTag(), "The target role change info " + mTargetRoleChangeInfo); 406 407 int deferringDurationMillis = 408 (int) (mClock.getElapsedSinceBootMillis() - mDeferringStartTimeMillis); 409 boolean isTimedOut = mMaximumDeferringTimeMillis > 0 410 && deferringDurationMillis >= mMaximumDeferringTimeMillis; 411 if (mTargetRoleChangeInfo == null) { 412 Log.d(getTag(), "Continue to stop wifi"); 413 mStateMachine.captureObituaryAndQuitNow(); 414 mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis); 415 } else if (mTargetRoleChangeInfo.role == ROLE_CLIENT_SCAN_ONLY) { 416 if (!mWifiNative.switchClientInterfaceToScanMode( 417 mClientInterfaceName, mTargetRoleChangeInfo.requestorWs)) { 418 mModeListener.onStartFailure(ConcreteClientModeManager.this); 419 updateConnectModeState(mRole, WifiManager.WIFI_STATE_UNKNOWN, 420 WifiManager.WIFI_STATE_DISABLING); 421 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLED, 422 WifiManager.WIFI_STATE_UNKNOWN); 423 takeBugReportInterfaceFailureIfNeeded( 424 "Wi-Fi BugReport (STA interface failure):", 425 "Fail to switch to scan-only mode in started state"); 426 } else { 427 mStateMachine.sendMessage( 428 ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE, 429 mTargetRoleChangeInfo); 430 mWifiMetrics.noteWifiOff(mIsDeferring, isTimedOut, deferringDurationMillis); 431 } 432 } else { 433 updateConnectModeState(mRole, WifiManager.WIFI_STATE_ENABLED, 434 WifiManager.WIFI_STATE_DISABLING); 435 } 436 437 if (!mIsDeferring) return; 438 439 Log.d(getTag(), "Stop DeferWifiOff handler."); 440 removeCallbacks(mRunnable); 441 if (mImsMmTelManager != null) { 442 try { 443 mImsMmTelManager.unregisterImsRegistrationCallback(mImsRegistrationCallback); 444 } catch (RuntimeException e) { 445 Log.e(getTag(), "unregisterImsRegistrationCallback failed", e); 446 } 447 } 448 449 if (mConnectivityManager != null && mImsNetworks.size() > 0) { 450 for (ImsNetworkCallback c: mImsNetworks) { 451 mConnectivityManager.unregisterNetworkCallback(c); 452 } 453 mImsNetworks.clear(); 454 } 455 456 mIsDeferring = false; 457 mIsImsNetworkUnregistered = false; 458 } 459 } 460 isAnyImsServiceOverWlanAvailable(int subId)461 private boolean isAnyImsServiceOverWlanAvailable(int subId) { 462 ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId); 463 try { 464 int[] possibleServiceOverWlan = new int[] { 465 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 466 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, 467 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, 468 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS, 469 MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_CALL_COMPOSER, 470 }; 471 for (int i: possibleServiceOverWlan) { 472 if (imsMmTelManager.isAvailable(i, 473 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN)) { 474 return true; 475 } 476 } 477 } catch (UnsupportedOperationException ex) { 478 Log.d(TAG, "IMS Manager is not supported."); 479 } catch (RuntimeException ex) { 480 Log.e(TAG, "IMS Manager is not available.", ex); 481 } 482 return false; 483 } 484 485 /** 486 * Get deferring time before turning off WiFi. 487 */ getWifiOffDeferringTimeMs()488 private int getWifiOffDeferringTimeMs() { 489 if (mRole != ROLE_CLIENT_PRIMARY && !isSecondaryInternet()) { 490 Log.d(getTag(), "Do not defer stop for non-internet providing CMMs"); 491 return 0; 492 } 493 SubscriptionManager subscriptionManager = 494 mContext.getSystemService(SubscriptionManager.class); 495 if (subscriptionManager == null) { 496 Log.d(getTag(), "SubscriptionManager not found"); 497 return 0; 498 } 499 500 List<SubscriptionInfo> subInfoList = subscriptionManager 501 .getCompleteActiveSubscriptionInfoList(); 502 if (subInfoList == null) { 503 Log.d(getTag(), "Active SubscriptionInfo list not found"); 504 return 0; 505 } 506 507 // Get the maximum delay for the active subscription latched on IWLAN. 508 int maxDelay = 0; 509 for (SubscriptionInfo subInfo : subInfoList) { 510 int curDelay = getWifiOffDeferringTimeMs(subInfo.getSubscriptionId()); 511 if (curDelay > maxDelay) { 512 maxDelay = curDelay; 513 mActiveSubId = subInfo.getSubscriptionId(); 514 } 515 } 516 return maxDelay; 517 } 518 getWifiOffDeferringTimeMs(int subId)519 private int getWifiOffDeferringTimeMs(int subId) { 520 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 521 Log.d(getTag(), "Invalid Subscription ID: " + subId); 522 return 0; 523 } 524 525 // If no IMS service over WLAN, no delay 526 if (!isAnyImsServiceOverWlanAvailable(subId)) { 527 Log.d(getTag(), "IMS not registered over IWLAN for subId: " + subId); 528 return 0; 529 } 530 531 CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class); 532 PersistableBundle config = configManager.getConfigForSubId(subId); 533 return (config != null) 534 ? config.getInt(CarrierConfigManager.Ims.KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT) 535 : 0; 536 } 537 538 @Override getRole()539 @Nullable public ClientRole getRole() { 540 return mRole; 541 } 542 543 /** 544 * Get the role this ClientModeManager is expected to become. 545 */ getTargetRole()546 @Nullable public ClientRole getTargetRole() { 547 return mTargetRoleChangeInfo == null ? null : mTargetRoleChangeInfo.role; 548 } 549 550 @Override getPreviousRole()551 @Nullable public ClientRole getPreviousRole() { 552 return mPreviousRole; 553 } 554 555 @Override getLastRoleChangeSinceBootMs()556 public long getLastRoleChangeSinceBootMs() { 557 return mLastRoleChangeSinceBootMs; 558 } 559 560 /** 561 * Class to hold info needed for role change. 562 */ 563 private static class RoleChangeInfo { 564 @Nullable public final ClientRole role; 565 @Nullable public final WorkSource requestorWs; 566 @Nullable public final Listener<ConcreteClientModeManager> modeListener; 567 RoleChangeInfo(@ullable ClientRole role)568 RoleChangeInfo(@Nullable ClientRole role) { 569 this(role, null, null); 570 } 571 RoleChangeInfo(@ullable ClientRole role, @Nullable WorkSource requestorWs, @Nullable Listener<ConcreteClientModeManager> modeListener)572 RoleChangeInfo(@Nullable ClientRole role, @Nullable WorkSource requestorWs, 573 @Nullable Listener<ConcreteClientModeManager> modeListener) { 574 this.role = role; 575 this.requestorWs = requestorWs; 576 this.modeListener = modeListener; 577 } 578 579 @Override toString()580 public String toString() { 581 return "Role: " + role + ", RequestorWs: " + requestorWs 582 + ", ModeListener: " + modeListener; 583 } 584 } 585 586 /** Set the role of this ClientModeManager */ setRole(@onNull ClientRole role, @NonNull WorkSource requestorWs)587 public void setRole(@NonNull ClientRole role, @NonNull WorkSource requestorWs) { 588 setRole(role, requestorWs, null); 589 } 590 591 /** Set the role of this ClientModeManager */ setRole(@onNull ClientRole role, @NonNull WorkSource requestorWs, @Nullable Listener<ConcreteClientModeManager> modeListener)592 public void setRole(@NonNull ClientRole role, @NonNull WorkSource requestorWs, 593 @Nullable Listener<ConcreteClientModeManager> modeListener) { 594 mTargetRoleChangeInfo = new RoleChangeInfo(role, requestorWs, modeListener); 595 if (role == ROLE_CLIENT_SCAN_ONLY) { 596 // Switch client mode manager to scan only mode. 597 if (mRole == ROLE_CLIENT_PRIMARY) { 598 mWifiInjector.getActiveModeWarden().setWifiStateForApiCalls(WIFI_STATE_DISABLING); 599 } 600 mStateMachine.sendMessage( 601 ClientModeStateMachine.CMD_SWITCH_TO_SCAN_ONLY_MODE); 602 } else { 603 // Switch client mode manager to connect mode. 604 mStateMachine.sendMessage( 605 ClientModeStateMachine.CMD_SWITCH_TO_CONNECT_MODE, 606 mTargetRoleChangeInfo); 607 } 608 } 609 610 @Override getInterfaceName()611 public String getInterfaceName() { 612 return mClientInterfaceName; 613 } 614 615 @Override getRequestorWs()616 public WorkSource getRequestorWs() { 617 return mRequestorWs; 618 } 619 620 /** 621 * Keep stopped {@link ClientModeImpl} instances so that they can be dumped to aid debugging. 622 * 623 * TODO(b/160283853): Find a smarter way to evict old ClientModeImpls 624 */ 625 private static class Graveyard { 626 private static final int INSTANCES_TO_KEEP = 3; 627 628 private final ArrayDeque<ClientModeImpl> mClientModeImpls = new ArrayDeque<>(); 629 630 /** 631 * Add this stopped {@link ClientModeImpl} to the graveyard, and evict the oldest 632 * ClientModeImpl if the graveyard is full. 633 */ inter(ClientModeImpl clientModeImpl)634 void inter(ClientModeImpl clientModeImpl) { 635 if (mClientModeImpls.size() == INSTANCES_TO_KEEP) { 636 mClientModeImpls.removeFirst(); 637 } 638 mClientModeImpls.addLast(clientModeImpl); 639 } 640 641 /** Dump the contents of the graveyard. */ dump(FileDescriptor fd, PrintWriter pw, String[] args)642 void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 643 pw.println("Dump of ConcreteClientModeManager.Graveyard"); 644 pw.println("Stopped ClientModeImpls: " + mClientModeImpls.size() + " total"); 645 for (ClientModeImpl clientModeImpl : mClientModeImpls) { 646 clientModeImpl.dump(fd, pw, args); 647 } 648 pw.println(); 649 } 650 hasAllClientModeImplsQuit()651 boolean hasAllClientModeImplsQuit() { 652 for (ClientModeImpl cmi : mClientModeImpls) { 653 if (!cmi.hasQuit()) return false; 654 } 655 return true; 656 } 657 } 658 659 /** 660 * Dump info about this ClientMode manager. 661 */ 662 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)663 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 664 pw.println("Dump of ClientModeManager id=" + mId); 665 pw.println("current StateMachine mode: " + getCurrentStateName()); 666 pw.println("mRole: " + mRole); 667 pw.println("mPreviousRole: " + mPreviousRole); 668 pw.println("mTargetRoleChangeInfo: " + mTargetRoleChangeInfo); 669 pw.println("mClientInterfaceName: " + mClientInterfaceName); 670 pw.println("mIfaceIsUp: " + mIfaceIsUp); 671 pw.println("mSecondaryInternet: " + mSecondaryInternet); 672 pw.println("mIsDbs: " + mIsDbs); 673 mStateMachine.dump(fd, pw, args); 674 pw.println(); 675 if (mClientModeImpl == null) { 676 pw.println("No active ClientModeImpl instance"); 677 } else { 678 mClientModeImpl.dump(fd, pw, args); 679 } 680 mGraveyard.dump(fd, pw, args); 681 pw.println(); 682 } 683 getCurrentStateName()684 private String getCurrentStateName() { 685 IState currentState = mStateMachine.getCurrentState(); 686 687 if (currentState != null) { 688 return currentState.getName(); 689 } 690 691 return "StateMachine not active"; 692 } 693 694 /** 695 * Update Wifi state and send the broadcast. 696 * 697 * @param role Target/Set role for this client mode manager instance. 698 * @param newState new Wifi state 699 * @param currentState current wifi state 700 */ updateConnectModeState(ClientRole role, int newState, int currentState)701 private void updateConnectModeState(ClientRole role, int newState, int currentState) { 702 if (role != ROLE_CLIENT_PRIMARY || !mWifiStateChangeBroadcastEnabled) { 703 // do not raise public broadcast unless this is the primary client mode manager 704 return; 705 } 706 // TODO(b/186881160): May need to restore per STA state for Battery state reported. 707 mWifiInjector.getActiveModeWarden().setWifiStateForApiCalls(newState); 708 if (newState == WifiManager.WIFI_STATE_UNKNOWN) { 709 // do not need to broadcast failure to system 710 return; 711 } 712 713 // TODO(b/175839153): this broadcast should only be sent out when wifi is toggled on/off, 714 // not per CMM 715 final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION); 716 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 717 intent.putExtra(WifiManager.EXTRA_WIFI_STATE, newState); 718 intent.putExtra(WifiManager.EXTRA_PREVIOUS_WIFI_STATE, currentState); 719 String summary = "broadcast=WIFI_STATE_CHANGED_ACTION" 720 + " EXTRA_WIFI_STATE=" + newState 721 + " EXTRA_PREVIOUS_WIFI_STATE=" + currentState; 722 if (mVerboseLoggingEnabled) Log.d(getTag(), "Queuing " + summary); 723 ClientModeManagerBroadcastQueue.QueuedBroadcast broadcast = 724 () -> { 725 if (mVerboseLoggingEnabled) Log.d(getTag(), "Sending " + summary); 726 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 727 }; 728 if (mRole == null && role == ROLE_CLIENT_PRIMARY) { 729 // This CMM is intended to be the primary, but has not completed the mode transition 730 // yet. Need to force broadcast to be sent. 731 broadcast.send(); 732 } else { 733 mBroadcastQueue.queueOrSendBroadcast(this, broadcast); 734 } 735 } 736 737 private class ClientModeStateMachine extends StateMachine { 738 // Commands for the state machine. 739 public static final int CMD_START = 0; 740 public static final int CMD_SWITCH_TO_SCAN_ONLY_MODE = 1; 741 public static final int CMD_SWITCH_TO_CONNECT_MODE = 2; 742 public static final int CMD_INTERFACE_STATUS_CHANGED = 3; 743 public static final int CMD_INTERFACE_DESTROYED = 4; 744 public static final int CMD_INTERFACE_DOWN = 5; 745 public static final int CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE = 6; 746 public static final int CMD_INTERFACE_ADDED = 7; 747 private final State mIdleState; 748 private final State mStartedState; 749 private final State mScanOnlyModeState; 750 private final State mConnectModeState; 751 // Workaround since we cannot use transitionTo(mScanOnlyModeState, RoleChangeInfo) 752 private RoleChangeInfo mScanRoleChangeInfoToSetOnTransition = null; 753 // Workaround since we cannot use transitionTo(mConnectModeState, RoleChangeInfo) 754 private RoleChangeInfo mConnectRoleChangeInfoToSetOnTransition = null; 755 756 @Nullable 757 private StateMachineObituary mObituary = null; 758 759 private final InterfaceEventCallback mWifiNativeInterfaceEventCallback = 760 new InterfaceEventCallback() { 761 762 boolean mEnabling = false; 763 764 @Override 765 public void onInterfaceLinkStateChanged(String ifaceName, boolean isLinkUp) { 766 Log.d("InterfaceEventCallback", 767 "onInterfaceLinkStateChanged, ifaceName=" + ifaceName + " up=" 768 + isLinkUp + " CurrentState=" + getCurrentStateName()); 769 if (isLinkUp) { 770 mEnabling = false; 771 } 772 } 773 774 @Override 775 public void onInterfaceAdded(String ifaceName) { 776 Log.d("InterfaceEventCallback", 777 "onInterfaceAdded, ifaceName=" + ifaceName 778 + " CurrentState=" + getCurrentStateName()); 779 if (mStateMachine.getCurrentState() == null) { 780 Log.d(TAG, "StateMachine not active, trigger ifaceAddedDetected"); 781 mSelfRecovery.trigger(SelfRecovery.REASON_IFACE_ADDED); 782 } else if (!mEnabling) { 783 Log.d("InterfaceEventCallback", "send CMD_INTERFACE_ADDED"); 784 mStateMachine.sendMessage(CMD_INTERFACE_ADDED); 785 mEnabling = true; 786 } else { 787 Log.d("InterfaceEventCallback", "wifi already in the start"); 788 } 789 } 790 }; 791 792 private final InterfaceCallback mWifiNativeInterfaceCallback = new InterfaceCallback() { 793 @Override 794 public void onDestroyed(String ifaceName) { 795 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 796 Log.d(getTag(), "STA iface " + ifaceName + " was destroyed, " 797 + "stopping client mode"); 798 799 // we must immediately clean up state in ClientModeImpl to unregister 800 // all client mode related objects 801 // Note: onDestroyed is only called from the main Wifi thread 802 if (mClientModeImpl == null) { 803 Log.w(getTag(), "Received mWifiNativeInterfaceCallback.onDestroyed " 804 + "callback when no ClientModeImpl instance is active."); 805 } else { 806 mClientModeImpl.handleIfaceDestroyed(); 807 } 808 809 // set it to null since the interface had been destroyed 810 mClientInterfaceName = null; 811 sendMessage(CMD_INTERFACE_DESTROYED); 812 } 813 } 814 815 @Override 816 public void onUp(String ifaceName) { 817 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 818 sendMessage(CMD_INTERFACE_STATUS_CHANGED, 1); 819 } 820 } 821 822 @Override 823 public void onDown(String ifaceName) { 824 if (mClientInterfaceName != null && mClientInterfaceName.equals(ifaceName)) { 825 sendMessage(CMD_INTERFACE_STATUS_CHANGED, 0); 826 } 827 } 828 }; 829 ClientModeStateMachine(Looper looper)830 ClientModeStateMachine(Looper looper) { 831 super(TAG, looper); 832 final int threshold = mContext.getResources().getInteger( 833 R.integer.config_wifiConfigurationWifiRunnerThresholdInMs); 834 mIdleState = new IdleState(threshold); 835 mStartedState = new StartedState(threshold); 836 mScanOnlyModeState = new ScanOnlyModeState(threshold); 837 mConnectModeState = new ConnectModeState(threshold); 838 // CHECKSTYLE:OFF IndentationCheck 839 addState(mIdleState); 840 addState(mStartedState, mIdleState); 841 addState(mScanOnlyModeState, mStartedState); 842 addState(mConnectModeState, mStartedState); 843 // CHECKSTYLE:ON IndentationCheck 844 845 setInitialState(mIdleState); 846 start(); 847 } 848 captureObituaryAndQuitNow()849 void captureObituaryAndQuitNow() { 850 // capture StateMachine LogRecs since we will lose them after we call quitNow() 851 // This is used for debugging. 852 mObituary = new StateMachineObituary(this); 853 854 quitNow(); 855 } 856 857 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)858 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 859 if (mObituary == null) { 860 // StateMachine hasn't quit yet, dump `this` via StateMachineObituary's dump() 861 // method for consistency with `else` branch. 862 new StateMachineObituary(this).dump(fd, pw, args); 863 } else { 864 // StateMachine has quit and cleared all LogRecs. 865 // Get them from the obituary instead. 866 mObituary.dump(fd, pw, args); 867 } 868 } 869 870 /** 871 * Return the additional string to be logged by LogRec. 872 * 873 * @param msg that was processed 874 * @return information to be logged as a String 875 */ 876 @Override getLogRecString(Message msg)877 protected String getLogRecString(Message msg) { 878 StringBuilder sb = new StringBuilder(); 879 sb.append(msg.arg1) 880 .append(" ").append(msg.arg2); 881 if (msg.obj != null) { 882 sb.append(" ").append(msg.obj); 883 } 884 return sb.toString(); 885 } 886 887 /** 888 * Convert the |what| field in logs from int to String. 889 */ 890 @Override getWhatToString(int what)891 protected String getWhatToString(int what) { 892 switch (what) { 893 case CMD_START: 894 return "CMD_START"; 895 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 896 return "CMD_SWITCH_TO_SCAN_ONLY_MODE"; 897 case CMD_SWITCH_TO_CONNECT_MODE: 898 return "CMD_SWITCH_TO_CONNECT_MODE"; 899 case CMD_INTERFACE_STATUS_CHANGED: 900 return "CMD_INTERFACE_STATUS_CHANGED"; 901 case CMD_INTERFACE_DESTROYED: 902 return "CMD_INTERFACE_DESTROYED"; 903 case CMD_INTERFACE_DOWN: 904 return "CMD_INTERFACE_DOWN"; 905 case CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE: 906 return "CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE"; 907 case RunnerState.STATE_ENTER_CMD: 908 return "Enter"; 909 case RunnerState.STATE_EXIT_CMD: 910 return "Exit"; 911 default: 912 return "what:" + what; 913 } 914 } 915 916 /** 917 * Reset this ConcreteClientModeManager when its role changes, so that it can be reused for 918 * another purpose. 919 */ reset()920 private void reset() { 921 // Therefore, the caller must ensure that the role change has been completed and these 922 // settings have already reset before setting them, otherwise the new setting would be 923 // lost. 924 setShouldReduceNetworkScore(false); 925 } 926 setRoleInternal(@onNull RoleChangeInfo roleChangeInfo)927 private void setRoleInternal(@NonNull RoleChangeInfo roleChangeInfo) { 928 mPreviousRole = mRole; 929 mLastRoleChangeSinceBootMs = mClock.getElapsedSinceBootMillis(); 930 mRole = roleChangeInfo.role; 931 if (roleChangeInfo.requestorWs != null) { 932 mRequestorWs = roleChangeInfo.requestorWs; 933 } 934 if (roleChangeInfo.modeListener != null) { 935 mModeListener = roleChangeInfo.modeListener; 936 } 937 } 938 setRoleInternalAndInvokeCallback(@onNull RoleChangeInfo roleChangeInfo)939 private void setRoleInternalAndInvokeCallback(@NonNull RoleChangeInfo roleChangeInfo) { 940 if (roleChangeInfo.role == mRole) return; 941 if (mRole == null) { 942 if (mVerboseLoggingEnabled) { 943 Log.v(getTag(), "CurState:" + getCurrentStateName() 944 + ", clientModeManager started in role: " + roleChangeInfo); 945 } 946 setRoleInternal(roleChangeInfo); 947 mModeListener.onStarted(ConcreteClientModeManager.this); 948 } else { 949 if (mVerboseLoggingEnabled) { 950 Log.v(getTag(), "CurState:" + getCurrentStateName() 951 + ", clientModeManager role changed: " + roleChangeInfo); 952 } 953 setRoleInternal(roleChangeInfo); 954 reset(); 955 mModeListener.onRoleChanged(ConcreteClientModeManager.this); 956 } 957 if (mClientModeImpl != null) { 958 mClientModeImpl.onRoleChanged(); 959 } 960 } 961 962 private class IdleState extends RunnerState { IdleState(int threshold)963 IdleState(int threshold) { 964 super(threshold, mWifiInjector.getWifiHandlerLocalLog()); 965 } 966 967 @Override enterImpl()968 public void enterImpl() { 969 Log.d(getTag(), "entering IdleState"); 970 mClientInterfaceName = null; 971 mIfaceIsUp = false; 972 } 973 974 @Override exitImpl()975 public void exitImpl() { 976 // Sometimes the wifi handler thread may become blocked that the statemachine 977 // will exit in the IdleState without first entering StartedState. Trigger a 978 // cleanup here in case the above sequence happens. This the statemachine was 979 // started normally this will will not send a duplicate broadcast since mIsStopped 980 // will get set to false the first time the exit happens. 981 cleanupOnQuitIfApplicable(); 982 Log.d(getTag(), "IdleState.exit()"); 983 } 984 985 @Override getMessageLogRec(int what)986 public String getMessageLogRec(int what) { 987 return ConcreteClientModeManager.class.getSimpleName() + "." 988 + IdleState.class.getSimpleName() + "." 989 + getWhatToString(what); 990 } 991 992 @Override processMessageImpl(Message message)993 public boolean processMessageImpl(Message message) { 994 if (mVerboseLoggingEnabled) { 995 Log.d(getTag(), 996 getName() + " cmd = " + getWhatToString(message.what) + " " 997 + message.toString()); 998 } 999 switch (message.what) { 1000 case CMD_START: 1001 // Always start in scan mode first. 1002 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 1003 mClientInterfaceName = mWifiNative.setupInterfaceForClientInScanMode( 1004 mWifiNativeInterfaceCallback, roleChangeInfo.requestorWs, 1005 ConcreteClientModeManager.this); 1006 if (TextUtils.isEmpty(mClientInterfaceName)) { 1007 Log.e(getTag(), "Failed to create ClientInterface. Sit in Idle"); 1008 takeBugReportInterfaceFailureIfNeeded( 1009 "Wi-Fi BugReport (scan STA interface failure):", 1010 "Failed to create client interface in idle state"); 1011 mModeListener.onStartFailure(ConcreteClientModeManager.this); 1012 break; 1013 } 1014 mWifiNative.setWifiNativeInterfaceEventCallback( 1015 mWifiNativeInterfaceEventCallback); 1016 if (roleChangeInfo.role instanceof ClientConnectivityRole) { 1017 sendMessage(CMD_SWITCH_TO_CONNECT_MODE, roleChangeInfo); 1018 transitionTo(mStartedState); 1019 } else { 1020 mScanRoleChangeInfoToSetOnTransition = roleChangeInfo; 1021 transitionTo(mScanOnlyModeState); 1022 } 1023 break; 1024 case CMD_INTERFACE_ADDED: 1025 Log.d(getTag(), "IdleState received CMD_INTERFACE_ADDED"); 1026 mSelfRecovery.trigger(SelfRecovery.REASON_IFACE_ADDED); 1027 break; 1028 default: 1029 Log.d(getTag(), getName() + ", received an invalid message: " + message); 1030 return NOT_HANDLED; 1031 } 1032 return HANDLED; 1033 } 1034 } 1035 1036 private class StartedState extends RunnerState { StartedState(int threshold)1037 StartedState(int threshold) { 1038 super(threshold, mWifiInjector.getWifiHandlerLocalLog()); 1039 } 1040 onUpChanged(boolean isUp)1041 private void onUpChanged(boolean isUp) { 1042 if (isUp == mIfaceIsUp) { 1043 return; // no change 1044 } 1045 mIfaceIsUp = isUp; 1046 if (!isUp) { 1047 // if the interface goes down we should exit and go back to idle state. 1048 Log.d(getTag(), getName() + ", interface down!"); 1049 mStateMachine.sendMessage(CMD_INTERFACE_DOWN); 1050 } 1051 if (mClientModeImpl != null) { 1052 mClientModeImpl.onUpChanged(isUp); 1053 } 1054 } 1055 1056 @Override enterImpl()1057 public void enterImpl() { 1058 Log.d(getTag(), "entering StartedState"); 1059 mIfaceIsUp = false; 1060 mIsStopped = false; 1061 onUpChanged(mWifiNative.isInterfaceUp(mClientInterfaceName)); 1062 } 1063 1064 @Override getMessageLogRec(int what)1065 public String getMessageLogRec(int what) { 1066 return ConcreteClientModeManager.class.getSimpleName() + "." 1067 + StartedState.class.getSimpleName() + "." 1068 + getWhatToString(what); 1069 } 1070 1071 @Override processMessageImpl(Message message)1072 public boolean processMessageImpl(Message message) { 1073 if (mVerboseLoggingEnabled) { 1074 Log.d(getTag(), 1075 getName() + " cmd = " + getWhatToString(message.what) + " " 1076 + message.toString()); 1077 } 1078 switch (message.what) { 1079 case CMD_START: 1080 // Already started, ignore this command. 1081 break; 1082 case CMD_SWITCH_TO_CONNECT_MODE: { 1083 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 1084 updateConnectModeState(roleChangeInfo.role, 1085 WifiManager.WIFI_STATE_ENABLING, 1086 WifiManager.WIFI_STATE_DISABLED); 1087 if (!mWifiNative.switchClientInterfaceToConnectivityMode( 1088 mClientInterfaceName, roleChangeInfo.requestorWs)) { 1089 updateConnectModeState(roleChangeInfo.role, 1090 WifiManager.WIFI_STATE_UNKNOWN, 1091 WifiManager.WIFI_STATE_ENABLING); 1092 updateConnectModeState(roleChangeInfo.role, 1093 WifiManager.WIFI_STATE_DISABLED, 1094 WifiManager.WIFI_STATE_UNKNOWN); 1095 takeBugReportInterfaceFailureIfNeeded( 1096 "Wi-Fi BugReport (STA interface failure):", 1097 "Fail to switch to connection mode in started state"); 1098 mModeListener.onStartFailure(ConcreteClientModeManager.this); 1099 break; 1100 } 1101 // Role set in the enter of ConnectModeState. 1102 mConnectRoleChangeInfoToSetOnTransition = roleChangeInfo; 1103 transitionTo(mConnectModeState); 1104 break; 1105 } 1106 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 1107 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 1108 WifiManager.WIFI_STATE_ENABLED); 1109 mDeferStopHandler.start(getWifiOffDeferringTimeMs()); 1110 break; 1111 case CMD_SWITCH_TO_SCAN_ONLY_MODE_CONTINUE: { 1112 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 1113 mScanRoleChangeInfoToSetOnTransition = roleChangeInfo; 1114 transitionTo(mScanOnlyModeState); 1115 break; 1116 } 1117 case CMD_INTERFACE_DOWN: 1118 Log.e(getTag(), 1119 getName() + ", detected an interface down, reporting failure to " 1120 + "SelfRecovery"); 1121 mSelfRecovery.trigger(SelfRecovery.REASON_STA_IFACE_DOWN); 1122 // once interface down, nothing else to do... stop the state machine 1123 captureObituaryAndQuitNow(); 1124 break; 1125 case CMD_INTERFACE_STATUS_CHANGED: 1126 boolean isUp = message.arg1 == 1; 1127 onUpChanged(isUp); 1128 break; 1129 case CMD_INTERFACE_DESTROYED: 1130 Log.e(getTag(), getName() + ", interface destroyed - client mode stopping"); 1131 mClientInterfaceName = null; 1132 // once interface destroyed, nothing else to do... stop the state machine 1133 captureObituaryAndQuitNow(); 1134 break; 1135 default: 1136 return NOT_HANDLED; 1137 } 1138 return HANDLED; 1139 } 1140 1141 /** 1142 * Clean up state, unregister listeners and update wifi state. 1143 */ 1144 @Override exitImpl()1145 public void exitImpl() { 1146 if (mClientInterfaceName != null) { 1147 mWifiNative.teardownInterface(mClientInterfaceName); 1148 mClientInterfaceName = null; 1149 mIfaceIsUp = false; 1150 } 1151 1152 Log.i(getTag(), "StartedState.exit(), setting mRole = null"); 1153 mIsStopped = true; 1154 cleanupOnQuitIfApplicable(); 1155 } 1156 } 1157 1158 private class ScanOnlyModeState extends RunnerState { ScanOnlyModeState(int threshold)1159 ScanOnlyModeState(int threshold) { 1160 super(threshold, mWifiInjector.getWifiHandlerLocalLog()); 1161 } 1162 1163 @Override enterImpl()1164 public void enterImpl() { 1165 Log.d(getTag(), "entering ScanOnlyModeState"); 1166 1167 if (mClientInterfaceName != null) { 1168 mScanOnlyModeImpl = mWifiInjector.makeScanOnlyModeImpl( 1169 mClientInterfaceName); 1170 } else { 1171 Log.e(getTag(), "Entered ScanOnlyModeState with a null interface name!"); 1172 } 1173 1174 if (mScanRoleChangeInfoToSetOnTransition == null 1175 || (mScanRoleChangeInfoToSetOnTransition.role != ROLE_CLIENT_SCAN_ONLY)) { 1176 Log.wtf(TAG, "Unexpected mScanRoleChangeInfoToSetOnTransition: " 1177 + mScanRoleChangeInfoToSetOnTransition); 1178 // Should never happen, but fallback to scan only to avoid a crash. 1179 mScanRoleChangeInfoToSetOnTransition = 1180 new RoleChangeInfo(ROLE_CLIENT_SCAN_ONLY); 1181 } 1182 1183 setRoleInternalAndInvokeCallback(mScanRoleChangeInfoToSetOnTransition); 1184 // If we're in ScanOnlyModeState, there is only 1 CMM. So it's ok to call 1185 // WakeupController directly, there won't be multiple CMMs trampling over each other 1186 mWakeupController.start(); 1187 mWifiNative.setScanMode(mClientInterfaceName, true); 1188 } 1189 1190 @Override getMessageLogRec(int what)1191 public String getMessageLogRec(int what) { 1192 return ConcreteClientModeManager.class.getSimpleName() + "." 1193 + ScanOnlyModeState.class.getSimpleName() + "." 1194 + getWhatToString(what); 1195 } 1196 1197 @Override processMessageImpl(Message message)1198 public boolean processMessageImpl(Message message) { 1199 if (mVerboseLoggingEnabled) { 1200 Log.d(getTag(), 1201 getName() + " cmd = " + getWhatToString(message.what) + " " 1202 + message.toString()); 1203 } 1204 switch (message.what) { 1205 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 1206 // Already in scan only mode, ignore this command. 1207 break; 1208 default: 1209 return NOT_HANDLED; 1210 } 1211 return HANDLED; 1212 } 1213 1214 @Override exitImpl()1215 public void exitImpl() { 1216 mScanOnlyModeImpl = null; 1217 mScanRoleChangeInfoToSetOnTransition = null; 1218 1219 // If we're in ScanOnlyModeState, there is only 1 CMM. So it's ok to call 1220 // WakeupController directly, there won't be multiple CMMs trampling over each other 1221 mWakeupController.stop(); 1222 mWifiNative.setScanMode(mClientInterfaceName, false); 1223 } 1224 } 1225 1226 private class ConnectModeState extends RunnerState { ConnectModeState(int threshold)1227 ConnectModeState(int threshold) { 1228 super(threshold, mWifiInjector.getWifiHandlerLocalLog()); 1229 } 1230 1231 @Override enterImpl()1232 public void enterImpl() { 1233 Log.d(getTag(), "entering ConnectModeState, starting ClientModeImpl"); 1234 if (mClientInterfaceName == null) { 1235 Log.e(getTag(), "Supposed to start ClientModeImpl, but iface is null!"); 1236 } else { 1237 if (mClientModeImpl != null) { 1238 Log.e(getTag(), "ConnectModeState.enter(): mClientModeImpl is already " 1239 + "instantiated?!"); 1240 } 1241 mClientModeImpl = mWifiInjector.makeClientModeImpl( 1242 mClientInterfaceName, ConcreteClientModeManager.this, 1243 mVerboseLoggingEnabled); 1244 mClientModeImpl.setShouldReduceNetworkScore(mShouldReduceNetworkScore); 1245 } 1246 if (mConnectRoleChangeInfoToSetOnTransition == null 1247 || !(mConnectRoleChangeInfoToSetOnTransition.role 1248 instanceof ClientConnectivityRole)) { 1249 Log.wtf(TAG, "Unexpected mConnectRoleChangeInfoToSetOnTransition: " 1250 + mConnectRoleChangeInfoToSetOnTransition); 1251 // Should never happen, but fallback to primary to avoid a crash. 1252 mConnectRoleChangeInfoToSetOnTransition = 1253 new RoleChangeInfo(ROLE_CLIENT_PRIMARY); 1254 } 1255 1256 // Could be any one of possible connect mode roles. 1257 setRoleInternalAndInvokeCallback(mConnectRoleChangeInfoToSetOnTransition); 1258 updateConnectModeState(mConnectRoleChangeInfoToSetOnTransition.role, 1259 WIFI_STATE_ENABLED, WIFI_STATE_ENABLING); 1260 } 1261 1262 @Override getMessageLogRec(int what)1263 public String getMessageLogRec(int what) { 1264 return ConcreteClientModeManager.class.getSimpleName() + "." 1265 + ConnectModeState.class.getSimpleName() + "." 1266 + getWhatToString(what); 1267 } 1268 1269 @Override processMessageImpl(Message message)1270 public boolean processMessageImpl(Message message) { 1271 if (mVerboseLoggingEnabled) { 1272 Log.d(getTag(), 1273 getName() + " cmd = " + getWhatToString(message.what) + " " 1274 + message.toString()); 1275 } 1276 switch (message.what) { 1277 case CMD_SWITCH_TO_CONNECT_MODE: 1278 RoleChangeInfo roleChangeInfo = (RoleChangeInfo) message.obj; 1279 // switching to connect mode when already in connect mode, just update the 1280 // requestor WorkSource. 1281 boolean success = mWifiNative.replaceStaIfaceRequestorWs( 1282 mClientInterfaceName, roleChangeInfo.requestorWs); 1283 if (success) { 1284 setRoleInternalAndInvokeCallback(roleChangeInfo); 1285 } else { 1286 // If this call failed, the iface would be torn down. 1287 // Thus, simply abort and let the iface down handling take care of the 1288 // rest. 1289 Log.e(getTag(), getName() + ", Failed to switch ClientModeManager=" 1290 + ConcreteClientModeManager.this + "'s requestorWs"); 1291 } 1292 break; 1293 case CMD_SWITCH_TO_SCAN_ONLY_MODE: 1294 case CMD_INTERFACE_DESTROYED: 1295 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 1296 WifiManager.WIFI_STATE_ENABLED); 1297 return NOT_HANDLED; // Handled in StartedState. 1298 case CMD_INTERFACE_DOWN: 1299 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLING, 1300 WifiManager.WIFI_STATE_UNKNOWN); 1301 return NOT_HANDLED; // Handled in StartedState. 1302 case CMD_INTERFACE_STATUS_CHANGED: 1303 boolean isUp = message.arg1 == 1; 1304 if (isUp == mIfaceIsUp) { 1305 break; // no change 1306 } 1307 if (!isUp) { 1308 // TODO(b/201584491) Figure out what to do with this block of code 1309 // handling iface down since most devices should have MAC randomization 1310 // enabled, which makes the "else" block essentially no-op. Also, the 1311 // "else" block would actually fully disable wifi which is not desirable 1312 // behavior because the firmware can recover the iface after it is down. 1313 if (mWifiGlobals.isConnectedMacRandomizationEnabled()) { 1314 return HANDLED; // For MAC randomization, ignore... 1315 } else { 1316 // Handle the error case where our underlying interface went down if 1317 // we do not have mac randomization enabled (b/72459123). 1318 // if the interface goes down we should exit and go back to idle 1319 // state. 1320 updateConnectModeState(mRole, WifiManager.WIFI_STATE_UNKNOWN, 1321 WifiManager.WIFI_STATE_ENABLED); 1322 } 1323 } 1324 return NOT_HANDLED; // Handled in StartedState. 1325 default: 1326 return NOT_HANDLED; 1327 } 1328 return HANDLED; 1329 } 1330 1331 @Override exitImpl()1332 public void exitImpl() { 1333 updateConnectModeState(mRole, WifiManager.WIFI_STATE_DISABLED, 1334 WifiManager.WIFI_STATE_DISABLING); 1335 1336 if (mClientModeImpl == null) { 1337 Log.w(getTag(), "ConnectModeState.exit(): mClientModeImpl is already null?!"); 1338 } else { 1339 Log.d(getTag(), "ConnectModeState.exit(): Stopping ClientModeImpl"); 1340 mClientModeImpl.stop(); 1341 mGraveyard.inter(mClientModeImpl); 1342 mClientModeImpl = null; 1343 } 1344 1345 mConnectRoleChangeInfoToSetOnTransition = null; 1346 } 1347 } 1348 } 1349 1350 /** Called by a ClientModeImpl owned by this CMM informing it has fully stopped. */ onClientModeImplQuit()1351 public void onClientModeImplQuit() { 1352 cleanupOnQuitIfApplicable(); 1353 } 1354 1355 /** 1356 * Only clean up this CMM once the CMM and all associated ClientModeImpls have been stopped. 1357 * This is necessary because ClientModeImpl sends broadcasts during stop, and the role must 1358 * remain primary for {@link ClientModeManagerBroadcastQueue} to send them out. 1359 */ cleanupOnQuitIfApplicable()1360 private void cleanupOnQuitIfApplicable() { 1361 if (mIsStopped && mGraveyard.hasAllClientModeImplsQuit()) { 1362 mPreviousRole = mRole; 1363 mLastRoleChangeSinceBootMs = mClock.getElapsedSinceBootMillis(); 1364 mRole = null; 1365 // only call onStopped() after role has been reset to null since ActiveModeWarden 1366 // expects the CMM to be fully stopped before onStopped(). 1367 mModeListener.onStopped(ConcreteClientModeManager.this); 1368 1369 // reset to false so that onStopped() won't be triggered again. 1370 mIsStopped = false; 1371 } 1372 } 1373 takeBugReportInterfaceFailureIfNeeded(String bugTitle, String bugDetail)1374 private void takeBugReportInterfaceFailureIfNeeded(String bugTitle, String bugDetail) { 1375 if (mWifiInjector.getDeviceConfigFacade().isInterfaceFailureBugreportEnabled()) { 1376 mWifiInjector.getWifiDiagnostics().takeBugReport(bugTitle, bugDetail); 1377 } 1378 } 1379 1380 @NonNull getClientMode()1381 private ClientMode getClientMode() { 1382 if (mClientModeImpl != null) { 1383 return mClientModeImpl; 1384 } 1385 if (mScanOnlyModeImpl != null) { 1386 return mScanOnlyModeImpl; 1387 } 1388 return mDefaultClientModeManager; 1389 } 1390 1391 /* 1392 * Note: These are simple wrappers over methods to {@link ClientModeImpl}. 1393 */ 1394 1395 @Override connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, @NonNull String packageName, @Nullable String attributionTag)1396 public void connectNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, 1397 int callingUid, @NonNull String packageName, @Nullable String attributionTag) { 1398 getClientMode().connectNetwork(result, wrapper, callingUid, packageName, attributionTag); 1399 } 1400 1401 @Override saveNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, int callingUid, @NonNull String packageName)1402 public void saveNetwork(NetworkUpdateResult result, ActionListenerWrapper wrapper, 1403 int callingUid, @NonNull String packageName) { 1404 getClientMode().saveNetwork(result, wrapper, callingUid, packageName); 1405 } 1406 1407 @Override disconnect()1408 public void disconnect() { 1409 getClientMode().disconnect(); 1410 } 1411 1412 @Override reconnect(WorkSource ws)1413 public void reconnect(WorkSource ws) { 1414 getClientMode().reconnect(ws); 1415 } 1416 1417 @Override reassociate()1418 public void reassociate() { 1419 getClientMode().reassociate(); 1420 } 1421 1422 @Override startConnectToNetwork(int networkId, int uid, String bssid)1423 public void startConnectToNetwork(int networkId, int uid, String bssid) { 1424 getClientMode().startConnectToNetwork(networkId, uid, bssid); 1425 } 1426 1427 @Override startRoamToNetwork(int networkId, String bssid)1428 public void startRoamToNetwork(int networkId, String bssid) { 1429 getClientMode().startRoamToNetwork(networkId, bssid); 1430 } 1431 1432 @Override onDeviceMobilityStateUpdated(@eviceMobilityState int newState)1433 public void onDeviceMobilityStateUpdated(@DeviceMobilityState int newState) { 1434 getClientMode().onDeviceMobilityStateUpdated(newState); 1435 } 1436 1437 @Override setLinkLayerStatsPollingInterval(int newIntervalMs)1438 public void setLinkLayerStatsPollingInterval(int newIntervalMs) { 1439 getClientMode().setLinkLayerStatsPollingInterval(newIntervalMs); 1440 } 1441 1442 @Override setWifiConnectedNetworkScorer( IBinder binder, IWifiConnectedNetworkScorer scorer, int callerUid)1443 public boolean setWifiConnectedNetworkScorer( 1444 IBinder binder, IWifiConnectedNetworkScorer scorer, int callerUid) { 1445 return getClientMode().setWifiConnectedNetworkScorer(binder, scorer, callerUid); 1446 } 1447 1448 @Override clearWifiConnectedNetworkScorer()1449 public void clearWifiConnectedNetworkScorer() { 1450 getClientMode().clearWifiConnectedNetworkScorer(); 1451 } 1452 1453 @Override onNetworkSwitchAccepted(int targetNetworkId, String targetBssid)1454 public void onNetworkSwitchAccepted(int targetNetworkId, String targetBssid) { 1455 getClientMode().onNetworkSwitchAccepted(targetNetworkId, targetBssid); 1456 } 1457 1458 @Override onNetworkSwitchRejected(int targetNetworkId, String targetBssid)1459 public void onNetworkSwitchRejected(int targetNetworkId, String targetBssid) { 1460 getClientMode().onNetworkSwitchRejected(targetNetworkId, targetBssid); 1461 } 1462 1463 @Override resetSimAuthNetworks(@lientModeImpl.ResetSimReason int resetReason)1464 public void resetSimAuthNetworks(@ClientModeImpl.ResetSimReason int resetReason) { 1465 getClientMode().resetSimAuthNetworks(resetReason); 1466 } 1467 1468 @Override onBluetoothConnectionStateChanged()1469 public void onBluetoothConnectionStateChanged() { 1470 getClientMode().onBluetoothConnectionStateChanged(); 1471 } 1472 1473 @Override getConnectionInfo()1474 public WifiInfo getConnectionInfo() { 1475 return getClientMode().getConnectionInfo(); 1476 } 1477 1478 @Override syncQueryPasspointIcon(long bssid, String fileName)1479 public boolean syncQueryPasspointIcon(long bssid, String fileName) { 1480 return getClientMode().syncQueryPasspointIcon(bssid, fileName); 1481 } 1482 1483 @Override getCurrentNetwork()1484 public Network getCurrentNetwork() { 1485 return getClientMode().getCurrentNetwork(); 1486 } 1487 1488 @Override syncGetDhcpResultsParcelable()1489 public DhcpResultsParcelable syncGetDhcpResultsParcelable() { 1490 return getClientMode().syncGetDhcpResultsParcelable(); 1491 } 1492 1493 @Override getSupportedFeaturesBitSet()1494 public @NonNull BitSet getSupportedFeaturesBitSet() { 1495 return getClientMode().getSupportedFeaturesBitSet(); 1496 } 1497 1498 @Override 1499 @Keep getSupportedFeatures()1500 public long getSupportedFeatures() { 1501 return bitsetToLong(getSupportedFeaturesBitSet()); 1502 } 1503 1504 @Override syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider, IProvisioningCallback callback)1505 public boolean syncStartSubscriptionProvisioning(int callingUid, OsuProvider provider, 1506 IProvisioningCallback callback) { 1507 return getClientMode().syncStartSubscriptionProvisioning( 1508 callingUid, provider, callback); 1509 } 1510 1511 @Override isWifiStandardSupported(@ifiAnnotations.WifiStandard int standard)1512 public boolean isWifiStandardSupported(@WifiAnnotations.WifiStandard int standard) { 1513 return getClientMode().isWifiStandardSupported(standard); 1514 } 1515 1516 @Override enableTdls(String remoteMacAddress, boolean enable)1517 public boolean enableTdls(String remoteMacAddress, boolean enable) { 1518 return getClientMode().enableTdls(remoteMacAddress, enable); 1519 } 1520 1521 @Override enableTdlsWithRemoteIpAddress(String remoteIpAddress, boolean enable)1522 public boolean enableTdlsWithRemoteIpAddress(String remoteIpAddress, boolean enable) { 1523 return getClientMode().enableTdlsWithRemoteIpAddress(remoteIpAddress, enable); 1524 } 1525 1526 @Override isTdlsOperationCurrentlyAvailable()1527 public boolean isTdlsOperationCurrentlyAvailable() { 1528 return getClientMode().isTdlsOperationCurrentlyAvailable(); 1529 } 1530 1531 @Override getMaxSupportedConcurrentTdlsSessions()1532 public int getMaxSupportedConcurrentTdlsSessions() { 1533 return getClientMode().getMaxSupportedConcurrentTdlsSessions(); 1534 } 1535 1536 @Override getNumberOfEnabledTdlsSessions()1537 public int getNumberOfEnabledTdlsSessions() { 1538 return getClientMode().getNumberOfEnabledTdlsSessions(); 1539 } 1540 1541 @Override dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args)1542 public void dumpIpClient(FileDescriptor fd, PrintWriter pw, String[] args) { 1543 getClientMode().dumpIpClient(fd, pw, args); 1544 } 1545 1546 @Override dumpWifiScoreReport(FileDescriptor fd, PrintWriter pw, String[] args)1547 public void dumpWifiScoreReport(FileDescriptor fd, PrintWriter pw, String[] args) { 1548 getClientMode().dumpWifiScoreReport(fd, pw, args); 1549 } 1550 1551 @Override enableVerboseLogging(boolean verbose)1552 public void enableVerboseLogging(boolean verbose) { 1553 mVerboseLoggingEnabled = verbose; 1554 getClientMode().enableVerboseLogging(verbose); 1555 } 1556 1557 @Override getFactoryMacAddress()1558 public String getFactoryMacAddress() { 1559 return getClientMode().getFactoryMacAddress(); 1560 } 1561 1562 @Override getConnectedWifiConfiguration()1563 public WifiConfiguration getConnectedWifiConfiguration() { 1564 return getClientMode().getConnectedWifiConfiguration(); 1565 } 1566 1567 @Override getConnectingWifiConfiguration()1568 public WifiConfiguration getConnectingWifiConfiguration() { 1569 return getClientMode().getConnectingWifiConfiguration(); 1570 } 1571 1572 @Override getConnectedBssid()1573 public String getConnectedBssid() { 1574 return getClientMode().getConnectedBssid(); 1575 } 1576 1577 @Override getConnectingBssid()1578 public String getConnectingBssid() { 1579 return getClientMode().getConnectingBssid(); 1580 } 1581 1582 @Override getWifiLinkLayerStats()1583 public WifiLinkLayerStats getWifiLinkLayerStats() { 1584 return getClientMode().getWifiLinkLayerStats(); 1585 } 1586 1587 @Override setPowerSave(@owerSaveClientType int client, boolean ps)1588 public boolean setPowerSave(@PowerSaveClientType int client, boolean ps) { 1589 return getClientMode().setPowerSave(client, ps); 1590 } 1591 1592 @Override enablePowerSave()1593 public boolean enablePowerSave() { 1594 return getClientMode().enablePowerSave(); 1595 } 1596 1597 @Override setLowLatencyMode(boolean enabled)1598 public boolean setLowLatencyMode(boolean enabled) { 1599 return getClientMode().setLowLatencyMode(enabled); 1600 } 1601 1602 @Override getMcastLockManagerFilterController()1603 public WifiMulticastLockManager.FilterController getMcastLockManagerFilterController() { 1604 return getClientMode().getMcastLockManagerFilterController(); 1605 } 1606 1607 @Override isConnected()1608 public boolean isConnected() { 1609 return getClientMode().isConnected(); 1610 } 1611 1612 @Override isConnecting()1613 public boolean isConnecting() { 1614 return getClientMode().isConnecting(); 1615 } 1616 1617 @Override isRoaming()1618 public boolean isRoaming() { 1619 return getClientMode().isRoaming(); 1620 } 1621 1622 @Override isDisconnected()1623 public boolean isDisconnected() { 1624 return getClientMode().isDisconnected(); 1625 } 1626 1627 @Override isIpProvisioningTimedOut()1628 public boolean isIpProvisioningTimedOut() { 1629 return getClientMode().isIpProvisioningTimedOut(); 1630 } 1631 1632 @Override isSupplicantTransientState()1633 public boolean isSupplicantTransientState() { 1634 return getClientMode().isSupplicantTransientState(); 1635 } 1636 1637 @Override onCellularConnectivityChanged(@ifiDataStall.CellularDataStatusCode int status)1638 public void onCellularConnectivityChanged(@WifiDataStall.CellularDataStatusCode int status) { 1639 getClientMode().onCellularConnectivityChanged(status); 1640 } 1641 1642 @Override probeLink(LinkProbeCallback callback, int mcs)1643 public void probeLink(LinkProbeCallback callback, int mcs) { 1644 getClientMode().probeLink(callback, mcs); 1645 } 1646 1647 @Override sendMessageToClientModeImpl(Message msg)1648 public void sendMessageToClientModeImpl(Message msg) { 1649 getClientMode().sendMessageToClientModeImpl(msg); 1650 } 1651 1652 @Override getId()1653 public long getId() { 1654 return mId; 1655 } 1656 1657 @Override setMboCellularDataStatus(boolean available)1658 public void setMboCellularDataStatus(boolean available) { 1659 getClientMode().setMboCellularDataStatus(available); 1660 } 1661 1662 @Override getRoamingCapabilities()1663 public WifiNative.RoamingCapabilities getRoamingCapabilities() { 1664 return getClientMode().getRoamingCapabilities(); 1665 } 1666 1667 @Override configureRoaming(WifiNative.RoamingConfig config)1668 public boolean configureRoaming(WifiNative.RoamingConfig config) { 1669 return getClientMode().configureRoaming(config); 1670 } 1671 1672 @Override enableRoaming(boolean enabled)1673 public boolean enableRoaming(boolean enabled) { 1674 return getClientMode().enableRoaming(enabled); 1675 } 1676 1677 @Override setCountryCode(String countryCode)1678 public boolean setCountryCode(String countryCode) { 1679 return getClientMode().setCountryCode(countryCode); 1680 } 1681 1682 @Override getTxPktFates()1683 public List<TxFateReport> getTxPktFates() { 1684 return getClientMode().getTxPktFates(); 1685 } 1686 1687 @Override getRxPktFates()1688 public List<RxFateReport> getRxPktFates() { 1689 return getClientMode().getRxPktFates(); 1690 } 1691 1692 @Override getDeviceWiphyCapabilities()1693 public DeviceWiphyCapabilities getDeviceWiphyCapabilities() { 1694 return getClientMode().getDeviceWiphyCapabilities(); 1695 } 1696 1697 @Override requestAnqp(String bssid, Set<Integer> anqpIds, Set<Integer> hs20Subtypes)1698 public boolean requestAnqp(String bssid, Set<Integer> anqpIds, Set<Integer> hs20Subtypes) { 1699 return getClientMode().requestAnqp(bssid, anqpIds, hs20Subtypes); 1700 } 1701 1702 @Override requestVenueUrlAnqp(String bssid)1703 public boolean requestVenueUrlAnqp(String bssid) { 1704 return getClientMode().requestVenueUrlAnqp(bssid); 1705 } 1706 1707 @Override requestIcon(String bssid, String fileName)1708 public boolean requestIcon(String bssid, String fileName) { 1709 return getClientMode().requestIcon(bssid, fileName); 1710 } 1711 1712 @Override setShouldReduceNetworkScore(boolean shouldReduceNetworkScore)1713 public void setShouldReduceNetworkScore(boolean shouldReduceNetworkScore) { 1714 mShouldReduceNetworkScore = shouldReduceNetworkScore; 1715 getClientMode().setShouldReduceNetworkScore(shouldReduceNetworkScore); 1716 } 1717 1718 @Override toString()1719 public String toString() { 1720 return "ConcreteClientModeManager{id=" + getId() 1721 + " iface=" + getInterfaceName() 1722 + " role=" + getRole() 1723 + "}"; 1724 } 1725 1726 @Override updateCapabilities()1727 public void updateCapabilities() { 1728 getClientMode().updateCapabilities(); 1729 } 1730 1731 @Override isAffiliatedLinkBssid(MacAddress bssid)1732 public boolean isAffiliatedLinkBssid(MacAddress bssid) { 1733 return getClientMode().isAffiliatedLinkBssid(bssid); 1734 } 1735 1736 @Override isMlo()1737 public boolean isMlo() { 1738 return getClientMode().isMlo(); 1739 } 1740 1741 @Override onIdleModeChanged(boolean isIdle)1742 public void onIdleModeChanged(boolean isIdle) { 1743 getClientMode().onIdleModeChanged(isIdle); 1744 } 1745 1746 @Override blockNetwork(BlockingOption option)1747 public void blockNetwork(BlockingOption option) { 1748 getClientMode().blockNetwork(option); 1749 } 1750 } 1751