1 /* 2 * Copyright (C) 2021 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 com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_PRIMARY; 20 import static com.android.server.wifi.ActiveModeManager.ROLE_CLIENT_SECONDARY_LONG_LIVED; 21 22 import android.annotation.IntDef; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.content.Context; 26 import android.net.wifi.ScanResult; 27 import android.net.wifi.WifiInfo; 28 import android.net.wifi.WifiManager; 29 import android.os.Handler; 30 import android.os.WorkSource; 31 import android.util.Log; 32 import android.util.SparseArray; 33 34 import com.android.internal.annotations.VisibleForTesting; 35 import com.android.modules.utils.build.SdkLevel; 36 37 import java.io.FileDescriptor; 38 import java.io.PrintWriter; 39 import java.lang.annotation.Retention; 40 import java.lang.annotation.RetentionPolicy; 41 42 /** 43 * Manages STA + STA for multi internet networks. 44 */ 45 public class MultiInternetManager { 46 private static final String TAG = "WifiMultiInternet"; 47 48 private final ActiveModeWarden mActiveModeWarden; 49 private final FrameworkFacade mFrameworkFacade; 50 private final Context mContext; 51 private final ClientModeImplMonitor mCmiMonitor; 52 private final WifiSettingsStore mSettingsStore; 53 private final Handler mEventHandler; 54 private final Clock mClock; 55 private int mStaConcurrencyMultiInternetMode = WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED; 56 @MultiInternetState 57 private int mMultiInternetConnectionState = MULTI_INTERNET_STATE_NONE; 58 private ConnectionStatusListener mConnectionStatusListener; 59 60 private SparseArray<NetworkConnectionState> mNetworkConnectionStates = new SparseArray<>(); 61 private boolean mVerboseLoggingEnabled = false; 62 63 /** No multi internet connection needed. */ 64 public static final int MULTI_INTERNET_STATE_NONE = 0; 65 /** Multi internet connection is connecting. */ 66 public static final int MULTI_INTERNET_STATE_CONNECTION_REQUESTED = 1; 67 /** No multi internet connection is connected. */ 68 public static final int MULTI_INTERNET_STATE_CONNECTED = 2; 69 /** @hide */ 70 @Retention(RetentionPolicy.SOURCE) 71 @IntDef(prefix = {"MULTI_INTERNET_STATE_"}, value = { 72 MULTI_INTERNET_STATE_NONE, 73 MULTI_INTERNET_STATE_CONNECTION_REQUESTED, 74 MULTI_INTERNET_STATE_CONNECTED}) 75 public @interface MultiInternetState {} 76 77 /** The internal network connection state per each Wi-Fi band. */ 78 class NetworkConnectionState { 79 // If the supplicant connection is completed. 80 private boolean mConnected; 81 // If the internet has been validated. 82 private boolean mValidated; 83 // The connection start time in millisecond 84 public long connectionStartTimeMillis; 85 // The WorkSource of the connection requestor. 86 public WorkSource requestorWorkSource; 87 NetworkConnectionState(WorkSource workSource)88 NetworkConnectionState(WorkSource workSource) { 89 this(workSource, -1L); 90 } 91 NetworkConnectionState(WorkSource workSource, long connectionStartTime)92 NetworkConnectionState(WorkSource workSource, long connectionStartTime) { 93 requestorWorkSource = workSource; 94 connectionStartTimeMillis = connectionStartTime; 95 96 mConnected = false; 97 mValidated = false; 98 } 99 setConnected(boolean connected)100 public NetworkConnectionState setConnected(boolean connected) { 101 mConnected = connected; 102 return this; 103 } 104 105 @VisibleForTesting isConnected()106 public boolean isConnected() { 107 return mConnected; 108 } 109 setValidated(boolean validated)110 public NetworkConnectionState setValidated(boolean validated) { 111 mValidated = validated; 112 return this; 113 } 114 115 @VisibleForTesting isValidated()116 public boolean isValidated() { 117 return mValidated; 118 } 119 } 120 121 @VisibleForTesting getNetworkConnectionState()122 SparseArray<NetworkConnectionState> getNetworkConnectionState() { 123 return mNetworkConnectionStates; 124 } 125 126 /** The Multi Internet Connection Status Listener. The registered listener will be notified 127 * for the connection status change and scan needed. */ 128 public interface ConnectionStatusListener { 129 /** Called when connection status changed */ onStatusChange( @ultiInternetManager.MultiInternetState int state, WorkSource requestorWs)130 void onStatusChange( 131 @MultiInternetManager.MultiInternetState int state, 132 WorkSource requestorWs); 133 /** Called when a scan is needed */ onStartScan(WorkSource requestorWs)134 void onStartScan(WorkSource requestorWs); 135 } 136 getRequestorWorkSource(int band)137 @Nullable private WorkSource getRequestorWorkSource(int band) { 138 if (!mNetworkConnectionStates.contains(band)) { 139 return null; 140 } 141 return mNetworkConnectionStates.get(band).requestorWorkSource; 142 } 143 144 private class ModeChangeCallback implements ActiveModeWarden.ModeChangeCallback { 145 @Override onActiveModeManagerAdded(@onNull ActiveModeManager activeModeManager)146 public void onActiveModeManagerAdded(@NonNull ActiveModeManager activeModeManager) { 147 if (!mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet() 148 || !isStaConcurrencyForMultiInternetEnabled()) { 149 return; 150 } 151 if (!(activeModeManager instanceof ConcreteClientModeManager)) { 152 return; 153 } 154 final ConcreteClientModeManager ccm = (ConcreteClientModeManager) activeModeManager; 155 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 156 if (ccm.getRole() != ROLE_CLIENT_SECONDARY_LONG_LIVED || !ccm.isSecondaryInternet()) { 157 return; 158 } 159 if (mVerboseLoggingEnabled) { 160 Log.v(TAG, "Secondary ClientModeManager created for internet, connecting!"); 161 } 162 updateNetworkConnectionStates(); 163 } 164 165 @Override onActiveModeManagerRemoved(@onNull ActiveModeManager activeModeManager)166 public void onActiveModeManagerRemoved(@NonNull ActiveModeManager activeModeManager) { 167 if (!mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet() 168 || !isStaConcurrencyForMultiInternetEnabled()) { 169 return; 170 } 171 if (!(activeModeManager instanceof ConcreteClientModeManager)) { 172 return; 173 } 174 final ConcreteClientModeManager ccm = (ConcreteClientModeManager) activeModeManager; 175 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 176 if (ccm.getRole() != ROLE_CLIENT_SECONDARY_LONG_LIVED || !ccm.isSecondaryInternet()) { 177 return; 178 } 179 if (mVerboseLoggingEnabled) { 180 Log.v(TAG, "ClientModeManager for internet removed"); 181 } 182 // A secondary cmm was removed because of the connection was lost, start scan 183 // to find the new network connection. 184 updateNetworkConnectionStates(); 185 if (hasPendingConnectionRequests()) { 186 startConnectivityScan(); 187 } 188 } 189 190 @Override onActiveModeManagerRoleChanged(@onNull ActiveModeManager activeModeManager)191 public void onActiveModeManagerRoleChanged(@NonNull ActiveModeManager activeModeManager) { 192 if (!mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet() 193 || !isStaConcurrencyForMultiInternetEnabled()) { 194 return; 195 } 196 if (!(activeModeManager instanceof ConcreteClientModeManager)) { 197 return; 198 } 199 final ConcreteClientModeManager ccm = (ConcreteClientModeManager) activeModeManager; 200 if (ccm.getPreviousRole() == ROLE_CLIENT_SECONDARY_LONG_LIVED 201 && ccm.isSecondaryInternet()) { 202 Log.w(TAG, "Secondary client mode manager changed role to " 203 + ccm.getRole()); 204 } 205 updateNetworkConnectionStates(); 206 } 207 } 208 209 private class ClientModeListenerInternal implements ClientModeImplListener { 210 @Override onInternetValidated(@onNull ConcreteClientModeManager clientModeManager)211 public void onInternetValidated(@NonNull ConcreteClientModeManager clientModeManager) { 212 if (!mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet() 213 || !isStaConcurrencyForMultiInternetEnabled()) { 214 return; 215 } 216 final WifiInfo info = clientModeManager.syncRequestConnectionInfo(); 217 if (info != null) { 218 final int band = ScanResult.toBand(info.getFrequency()); 219 if (mNetworkConnectionStates.contains(band)) { 220 mNetworkConnectionStates.get(band).setValidated(true); 221 } 222 } 223 if (mVerboseLoggingEnabled) { 224 Log.v(TAG, "ClientModeManager role " + clientModeManager.getRole() 225 + " internet validated for connection"); 226 } 227 // If the primary role was connected and internet validated, update the connection state 228 // immediately and issue scan for secondary network connection if needed. 229 // If the secondary role was connected and internet validated, update the connection 230 // state and notify connectivity manager. 231 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 232 if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY) { 233 updateNetworkConnectionStates(); 234 final int band = findUnconnectedRequestBand(); 235 if (band != ScanResult.UNSPECIFIED) { 236 // Trigger the connectivity scan 237 mConnectionStatusListener.onStartScan(getRequestorWorkSource(band)); 238 } 239 } else if (clientModeManager.getRole() == ROLE_CLIENT_SECONDARY_LONG_LIVED 240 && clientModeManager.isSecondaryInternet()) { 241 updateNetworkConnectionStates(); 242 } 243 } 244 245 // TODO(b/175896748): not yet triggered by ClientModeImpl 246 @Override onL3Connected(@onNull ConcreteClientModeManager clientModeManager)247 public void onL3Connected(@NonNull ConcreteClientModeManager clientModeManager) { 248 if (!mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet() 249 || !isStaConcurrencyForMultiInternetEnabled()) { 250 return; 251 } 252 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 253 if (clientModeManager.getRole() != ROLE_CLIENT_SECONDARY_LONG_LIVED 254 || !clientModeManager.isSecondaryInternet()) { 255 return; 256 } 257 updateNetworkConnectionStates(); 258 // If no pending connection requests, update connection listener. 259 if (!hasPendingConnectionRequests()) { 260 final int band = getSecondaryConnectedNetworkBand(); 261 if (band == ScanResult.UNSPECIFIED) return; 262 final long connectionTime = mClock.getElapsedSinceBootMillis() 263 - mNetworkConnectionStates.get(band).connectionStartTimeMillis; 264 if (mVerboseLoggingEnabled) { 265 Log.v(TAG, "ClientModeManager for internet L3 connected for " 266 + connectionTime + " ms."); 267 } 268 handleConnectionStateChange(MULTI_INTERNET_STATE_CONNECTED, 269 getRequestorWorkSource(band)); 270 } 271 } 272 273 @Override onConnectionEnd(@onNull ConcreteClientModeManager clientModeManager)274 public void onConnectionEnd(@NonNull ConcreteClientModeManager clientModeManager) { 275 if (!mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet() 276 || !isStaConcurrencyForMultiInternetEnabled()) { 277 return; 278 } 279 if (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY) { 280 if (mVerboseLoggingEnabled) { 281 Log.v(TAG, "Connection end on primary client mode manager"); 282 } 283 // When the primary network connection is ended, disconnect the secondary network, 284 // as the secondary network is opportunistic. 285 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 286 for (ConcreteClientModeManager cmm : mActiveModeWarden.getClientModeManagersInRoles( 287 ROLE_CLIENT_SECONDARY_LONG_LIVED)) { 288 if (cmm.isSecondaryInternet()) { 289 if (mVerboseLoggingEnabled) { 290 Log.v(TAG, "Disconnect secondary client mode manager"); 291 } 292 cmm.disconnect(); 293 } 294 } 295 // As the secondary network is disconnected, mark all bands as disconnected. 296 for (int i = 0; i < mNetworkConnectionStates.size(); i++) { 297 mNetworkConnectionStates.valueAt(i).setConnected(false); 298 } 299 } 300 updateNetworkConnectionStates(); 301 } 302 } 303 MultiInternetManager( @onNull ActiveModeWarden activeModeWarden, @NonNull FrameworkFacade frameworkFacade, @NonNull Context context, @NonNull ClientModeImplMonitor cmiMonitor, @NonNull WifiSettingsStore settingsStore, @NonNull Handler handler, @NonNull Clock clock)304 public MultiInternetManager( 305 @NonNull ActiveModeWarden activeModeWarden, 306 @NonNull FrameworkFacade frameworkFacade, 307 @NonNull Context context, 308 @NonNull ClientModeImplMonitor cmiMonitor, 309 @NonNull WifiSettingsStore settingsStore, 310 @NonNull Handler handler, 311 @NonNull Clock clock) { 312 mActiveModeWarden = activeModeWarden; 313 mFrameworkFacade = frameworkFacade; 314 mContext = context; 315 mCmiMonitor = cmiMonitor; 316 mSettingsStore = settingsStore; 317 mEventHandler = handler; 318 mClock = clock; 319 mActiveModeWarden.registerModeChangeCallback(new ModeChangeCallback()); 320 cmiMonitor.registerListener(new ClientModeListenerInternal()); 321 mStaConcurrencyMultiInternetMode = mSettingsStore.getWifiMultiInternetMode(); 322 } 323 324 /** 325 * Check if Wi-Fi multi internet use case is enabled. 326 * 327 * @return true if Wi-Fi multi internet use case is enabled. 328 */ isStaConcurrencyForMultiInternetEnabled()329 public boolean isStaConcurrencyForMultiInternetEnabled() { 330 return mStaConcurrencyMultiInternetMode 331 != WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED; 332 } 333 334 /** 335 * Check if Wi-Fi multi internet use case allows multi AP. 336 * 337 * @return true if Wi-Fi multi internet use case allows multi AP. 338 */ isStaConcurrencyForMultiInternetMultiApAllowed()339 public boolean isStaConcurrencyForMultiInternetMultiApAllowed() { 340 return mStaConcurrencyMultiInternetMode 341 == WifiManager.WIFI_MULTI_INTERNET_MODE_MULTI_AP; 342 } 343 344 /** 345 * Return Wi-Fi multi internet use case mode. 346 * 347 * @return Current mode of Wi-Fi multi internet use case. 348 */ getStaConcurrencyForMultiInternetMode()349 public @WifiManager.WifiMultiInternetMode int getStaConcurrencyForMultiInternetMode() { 350 if (mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet()) { 351 return mStaConcurrencyMultiInternetMode; 352 } 353 return WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED; 354 } 355 356 /** 357 * Set the multi internet use case mode. 358 * @return true if the mode set successfully, false if failed. 359 */ setStaConcurrencyForMultiInternetMode( @ifiManager.WifiMultiInternetMode int mode)360 public boolean setStaConcurrencyForMultiInternetMode( 361 @WifiManager.WifiMultiInternetMode int mode) { 362 final boolean enabled = (mode != WifiManager.WIFI_MULTI_INTERNET_MODE_DISABLED); 363 if (!mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet()) { 364 return false; 365 } 366 367 if (mode == mStaConcurrencyMultiInternetMode) { 368 return true; 369 } 370 // If the STA+STA multi internet feature was disabled, disconnect the secondary cmm. 371 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 372 if (!enabled) { 373 for (ConcreteClientModeManager cmm : mActiveModeWarden.getClientModeManagersInRoles( 374 ROLE_CLIENT_SECONDARY_LONG_LIVED)) { 375 if (cmm.isSecondaryInternet()) { 376 cmm.disconnect(); 377 } 378 } 379 for (int i = 0; i < mNetworkConnectionStates.size(); i++) { 380 // Clear the connection state for all bands. 381 mNetworkConnectionStates.setValueAt(i, new NetworkConnectionState(null)); 382 } 383 handleConnectionStateChange(MULTI_INTERNET_STATE_NONE, null); 384 } else { 385 updateNetworkConnectionStates(); 386 final int band = findUnconnectedRequestBand(); 387 if (band != ScanResult.UNSPECIFIED) { 388 handleConnectionStateChange(MULTI_INTERNET_STATE_CONNECTION_REQUESTED, 389 getRequestorWorkSource(band)); 390 } 391 } 392 mStaConcurrencyMultiInternetMode = mode; 393 mSettingsStore.handleWifiMultiInternetMode(mode); 394 // Check if there is already multi internet request then start scan for connection. 395 if (hasPendingConnectionRequests()) { 396 startConnectivityScan(); 397 } 398 return true; 399 } 400 setVerboseLoggingEnabled(boolean enabled)401 public void setVerboseLoggingEnabled(boolean enabled) { 402 mVerboseLoggingEnabled = enabled; 403 } 404 405 /** Set the Multi Internet Connection Status listener. 406 * 407 * @param listener The Multi Internet Connection Status listener. 408 */ setConnectionStatusListener(ConnectionStatusListener listener)409 public void setConnectionStatusListener(ConnectionStatusListener listener) { 410 mConnectionStatusListener = listener; 411 } 412 413 /** Notify the BSSID associated event from ClientModeImpl. Triggered by 414 * WifiMonitor.ASSOCIATED_BSSID_EVENT. 415 * @param clientModeManager the client mode manager with BSSID associated event. 416 */ notifyBssidAssociatedEvent(ConcreteClientModeManager clientModeManager)417 public void notifyBssidAssociatedEvent(ConcreteClientModeManager clientModeManager) { 418 if (clientModeManager.getRole() != ROLE_CLIENT_PRIMARY 419 || !mActiveModeWarden.isStaStaConcurrencySupportedForMultiInternet() 420 || !isStaConcurrencyForMultiInternetEnabled()) { 421 return; 422 } 423 // If primary CMM has associated to a new BSSID, need to check if it is in a different band 424 // of secondary CMM. 425 final WifiInfo info = clientModeManager.syncRequestConnectionInfo(); 426 final ConcreteClientModeManager secondaryCcmm = 427 mActiveModeWarden.getClientModeManagerInRole(ROLE_CLIENT_SECONDARY_LONG_LIVED); 428 // If no secondary client mode manager then it's ok 429 if (secondaryCcmm == null) return; 430 // If secondary client mode manager is not connected or not for secondary internet 431 if (!secondaryCcmm.isConnected() || !secondaryCcmm.isSecondaryInternet()) return; 432 final WifiInfo info2 = secondaryCcmm.syncRequestConnectionInfo(); 433 // If secondary network is in same band as primary now 434 if (ScanResult.toBand(info.getFrequency()) == ScanResult.toBand(info2.getFrequency())) { 435 // Need to disconnect secondary network 436 secondaryCcmm.disconnect(); 437 // As the secondary network is disconnected, mark all bands as disconnected. 438 for (int i = 0; i < mNetworkConnectionStates.size(); i++) { 439 mNetworkConnectionStates.valueAt(i).setConnected(false); 440 } 441 updateNetworkConnectionStates(); 442 } 443 } 444 445 /** Check if there is a connection request for multi internet 446 * @return true if there is one or more connection request 447 */ hasPendingConnectionRequests()448 public boolean hasPendingConnectionRequests() { 449 return findUnconnectedRequestBand() != ScanResult.UNSPECIFIED; 450 } 451 452 /** 453 * Check if there is connection request on a specific band. 454 * @param band The band for the connection request. 455 * @return true if there is connection request on specific band. 456 */ hasConnectionRequest(int band)457 public boolean hasConnectionRequest(int band) { 458 return mNetworkConnectionStates.contains(band) 459 ? (getRequestorWorkSource(band) != null) : false; 460 } 461 462 /** 463 * Check if there is unconnected network connection request. 464 * @return the band of the connection request that is still not connected. 465 */ findUnconnectedRequestBand()466 public int findUnconnectedRequestBand() { 467 for (int i = 0; i < mNetworkConnectionStates.size(); i++) { 468 if (!mNetworkConnectionStates.valueAt(i).isConnected()) { 469 return mNetworkConnectionStates.keyAt(i); 470 } 471 } 472 return ScanResult.UNSPECIFIED; 473 } 474 475 /** 476 * Traverse the client mode managers and update the internal connection states. 477 */ updateNetworkConnectionStates()478 private void updateNetworkConnectionStates() { 479 for (int i = 0; i < mNetworkConnectionStates.size(); i++) { 480 mNetworkConnectionStates.valueAt(i).setConnected(false); 481 } 482 483 for (ClientModeManager clientModeManager : 484 mActiveModeWarden.getInternetConnectivityClientModeManagers()) { 485 // TODO: b/197670907 : Add client role ROLE_CLIENT_SECONDARY_INTERNET 486 if (clientModeManager instanceof ConcreteClientModeManager 487 && (clientModeManager.getRole() == ROLE_CLIENT_PRIMARY 488 || clientModeManager.getRole() == ROLE_CLIENT_SECONDARY_LONG_LIVED)) { 489 ConcreteClientModeManager ccmm = (ConcreteClientModeManager) clientModeManager; 490 // Exclude the secondary client mode manager not for secondary internet. 491 if (ccmm.getRole() == ROLE_CLIENT_SECONDARY_LONG_LIVED 492 && !ccmm.isSecondaryInternet()) { 493 continue; 494 } 495 WifiInfo info = clientModeManager.syncRequestConnectionInfo(); 496 // Exclude the network that is not connected or restricted. 497 if (info == null || !clientModeManager.isConnected() 498 || info.isRestricted()) continue; 499 // Exclude the network that is oem paid/private. 500 if (SdkLevel.isAtLeastT() && (info.isOemPaid() || info.isOemPrivate())) continue; 501 final int band = ScanResult.toBand(info.getFrequency()); 502 if (mNetworkConnectionStates.contains(band)) { 503 // Update the connected state 504 mNetworkConnectionStates.get(band).setConnected(true); 505 } 506 if (mVerboseLoggingEnabled) { 507 Log.v(TAG, "network band " + band + " role " 508 + clientModeManager.getRole().toString()); 509 } 510 } 511 } 512 // Handle the state change and notify listener 513 if (!hasPendingConnectionRequests()) { 514 if (mNetworkConnectionStates.size() == 0) { 515 handleConnectionStateChange(MULTI_INTERNET_STATE_NONE, null); 516 } else { 517 final int band = getSecondaryConnectedNetworkBand(); 518 if (band == ScanResult.UNSPECIFIED) return; 519 handleConnectionStateChange(MULTI_INTERNET_STATE_CONNECTED, 520 getRequestorWorkSource(band)); 521 } 522 } else { 523 final int band = findUnconnectedRequestBand(); 524 handleConnectionStateChange(MULTI_INTERNET_STATE_CONNECTION_REQUESTED, 525 getRequestorWorkSource(band)); 526 } 527 } 528 529 /** 530 * Set a network connection request from a requestor WorkSource for a specific band, or clear 531 * the connection request if the WorkSource is null. 532 * Triggered when {@link MultiInternetWifiNetworkFactory} has a pending network request. 533 * @param band The band of the Wi-Fi network requested. 534 * @param requestorWs The requestor's WorkSource. Null to clear a network request for a 535 * a band. 536 */ setMultiInternetConnectionWorksource(int band, WorkSource requestorWs)537 public void setMultiInternetConnectionWorksource(int band, WorkSource requestorWs) { 538 if (!isStaConcurrencyForMultiInternetEnabled()) { 539 Log.w(TAG, "MultInternet is not enabled."); 540 return; 541 } 542 if (mVerboseLoggingEnabled) { 543 Log.v(TAG, "setMultiInternetConnectionWorksource: band=" + band + ", requestorWs=" 544 + requestorWs); 545 } 546 if (requestorWs == null) { 547 // Disconnect secondary network if the request is removed. 548 if (band == getSecondaryConnectedNetworkBand()) { 549 for (ConcreteClientModeManager cmm : mActiveModeWarden.getClientModeManagersInRoles( 550 ROLE_CLIENT_SECONDARY_LONG_LIVED)) { 551 if (cmm.isSecondaryInternet()) { 552 cmm.disconnect(); 553 } 554 } 555 } 556 mNetworkConnectionStates.remove(band); 557 updateNetworkConnectionStates(); 558 return; 559 } 560 if (mNetworkConnectionStates.contains(band)) { 561 Log.w(TAG, "band " + band + " already requested."); 562 } 563 mNetworkConnectionStates.put(band, new NetworkConnectionState(requestorWs, 564 mClock.getElapsedSinceBootMillis())); 565 startConnectivityScan(); 566 } 567 568 /** Returns the band of the secondary network connected. */ getSecondaryConnectedNetworkBand()569 private int getSecondaryConnectedNetworkBand() { 570 final ConcreteClientModeManager secondaryCcmm = 571 mActiveModeWarden.getClientModeManagerInRole(ROLE_CLIENT_SECONDARY_LONG_LIVED); 572 if (secondaryCcmm == null) { 573 return ScanResult.UNSPECIFIED; 574 } 575 final WifiInfo info = secondaryCcmm.syncRequestConnectionInfo(); 576 // Make sure secondary network is connected. 577 if (info == null || !secondaryCcmm.isConnected() || !secondaryCcmm.isSecondaryInternet()) { 578 return ScanResult.UNSPECIFIED; 579 } 580 return ScanResult.toBand(info.getFrequency()); 581 } 582 583 /** 584 * Handles the connection state change and notifies the status listener. 585 * The listener will only be notified when the state changes. If the state remains the same 586 * but with a different requestor WorkSource then the listener is not notified. 587 * 588 * @param state 589 * @param workSource 590 */ handleConnectionStateChange(int state, WorkSource workSource)591 private void handleConnectionStateChange(int state, WorkSource workSource) { 592 if (mMultiInternetConnectionState == state) { 593 return; 594 } 595 mMultiInternetConnectionState = state; 596 mConnectionStatusListener.onStatusChange(state, workSource); 597 } 598 599 /** 600 * Start a connectivity scan to trigger the network selection process and connect to 601 * the requested multi internet networks. 602 */ startConnectivityScan()603 private void startConnectivityScan() { 604 if (!isStaConcurrencyForMultiInternetEnabled()) { 605 return; 606 } 607 updateNetworkConnectionStates(); 608 609 final int band = findUnconnectedRequestBand(); 610 if (band == ScanResult.UNSPECIFIED) return; 611 NetworkConnectionState state = mNetworkConnectionStates.get(band); 612 if (mVerboseLoggingEnabled) { 613 Log.v(TAG, "Schedule connectivity scan for network request with band " + band 614 + " start time " + state.connectionStartTimeMillis + " now " 615 + mClock.getElapsedSinceBootMillis()); 616 } 617 // Trigger the connectivity scan 618 mConnectionStatusListener.onStartScan(getRequestorWorkSource(band)); 619 } 620 621 /** Dump the internal states of MultiInternetManager */ dump(FileDescriptor fd, PrintWriter pw, String[] args)622 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 623 pw.println("Dump of MultiInternetManager"); 624 pw.println(TAG + ": mStaConcurrencyMultiInternetMode " 625 + mStaConcurrencyMultiInternetMode); 626 for (int i = 0; i < mNetworkConnectionStates.size(); i++) { 627 pw.println("band " + mNetworkConnectionStates.keyAt(i) + " connected " 628 + mNetworkConnectionStates.valueAt(i).isConnected() 629 + " validated " + mNetworkConnectionStates.valueAt(i).isValidated()); 630 } 631 } 632 633 } 634