1 /* 2 * Copyright (C) 2015 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.internal.telephony.data; 18 19 import static android.telephony.CarrierConfigManager.KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG; 20 import static android.telephony.SubscriptionManager.DEFAULT_PHONE_INDEX; 21 import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 22 import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX; 23 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 24 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; 25 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS; 26 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; 27 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_CROSS_SIM; 28 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN; 29 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_NONE; 30 31 import static java.util.Arrays.copyOf; 32 33 import android.annotation.CallbackExecutor; 34 import android.annotation.NonNull; 35 import android.annotation.Nullable; 36 import android.content.BroadcastReceiver; 37 import android.content.Context; 38 import android.content.Intent; 39 import android.content.IntentFilter; 40 import android.net.ConnectivityManager; 41 import android.net.Network; 42 import android.net.NetworkCapabilities; 43 import android.net.NetworkRequest; 44 import android.net.NetworkSpecifier; 45 import android.net.TelephonyNetworkSpecifier; 46 import android.os.AsyncResult; 47 import android.os.Handler; 48 import android.os.Looper; 49 import android.os.Message; 50 import android.os.PersistableBundle; 51 import android.os.RegistrantList; 52 import android.os.RemoteException; 53 import android.telephony.CarrierConfigManager; 54 import android.telephony.PhoneStateListener; 55 import android.telephony.SubscriptionInfo; 56 import android.telephony.SubscriptionManager; 57 import android.telephony.TelephonyManager; 58 import android.telephony.TelephonyRegistryManager; 59 import android.telephony.ims.ImsReasonInfo; 60 import android.telephony.ims.ImsRegistrationAttributes; 61 import android.telephony.ims.RegistrationManager; 62 import android.telephony.ims.stub.ImsRegistrationImplBase; 63 import android.util.ArrayMap; 64 import android.util.ArraySet; 65 import android.util.LocalLog; 66 import android.util.Log; 67 import android.util.SparseIntArray; 68 69 import com.android.ims.ImsException; 70 import com.android.ims.ImsManager; 71 import com.android.internal.annotations.VisibleForTesting; 72 import com.android.internal.telephony.Call; 73 import com.android.internal.telephony.CommandException; 74 import com.android.internal.telephony.ISetOpportunisticDataCallback; 75 import com.android.internal.telephony.IccCard; 76 import com.android.internal.telephony.Phone; 77 import com.android.internal.telephony.PhoneConfigurationManager; 78 import com.android.internal.telephony.PhoneFactory; 79 import com.android.internal.telephony.RadioConfig; 80 import com.android.internal.telephony.TelephonyIntents; 81 import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; 82 import com.android.internal.telephony.data.DataSettingsManager.DataSettingsManagerCallback; 83 import com.android.internal.telephony.flags.FeatureFlags; 84 import com.android.internal.telephony.imsphone.ImsPhone; 85 import com.android.internal.telephony.metrics.TelephonyMetrics; 86 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; 87 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; 88 import com.android.internal.telephony.subscription.SubscriptionInfoInternal; 89 import com.android.internal.telephony.subscription.SubscriptionManagerService; 90 import com.android.internal.telephony.subscription.SubscriptionManagerService.SubscriptionManagerServiceCallback; 91 import com.android.internal.telephony.subscription.SubscriptionManagerService.WatchedInt; 92 import com.android.internal.util.IndentingPrintWriter; 93 import com.android.telephony.Rlog; 94 95 import java.io.FileDescriptor; 96 import java.io.PrintWriter; 97 import java.util.ArrayList; 98 import java.util.Calendar; 99 import java.util.HashSet; 100 import java.util.List; 101 import java.util.Map; 102 import java.util.Set; 103 import java.util.concurrent.CompletableFuture; 104 import java.util.concurrent.Executor; 105 106 /** 107 * Utility singleton to monitor subscription changes and incoming NetworkRequests 108 * and determine which phone/phones are active. 109 * <p> 110 * Manages the ALLOW_DATA calls to modems and notifies phones about changes to 111 * the active phones. Note we don't wait for data attach (which may not happen anyway). 112 */ 113 public class PhoneSwitcher extends Handler { 114 private static final String LOG_TAG = "PhoneSwitcher"; 115 protected static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE); 116 117 private static final int MODEM_COMMAND_RETRY_PERIOD_MS = 5000; 118 // After the emergency call ends, wait for a few seconds to see if we enter ECBM before starting 119 // the countdown to remove the emergency DDS override. 120 @VisibleForTesting 121 // not final for testing. 122 public static int ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 5000; 123 // Wait for a few seconds after the override request comes in to receive the outgoing call 124 // event. If it does not happen before the timeout specified, cancel the override. 125 @VisibleForTesting 126 public static int DEFAULT_DATA_OVERRIDE_TIMEOUT_MS = 5000; 127 128 // If there are no subscriptions in a device, then the phone to be used for emergency should 129 // always be the "first" phone. 130 private static final int DEFAULT_EMERGENCY_PHONE_ID = 0; 131 132 /** 133 * Container for an ongoing request to override the DDS in the context of an ongoing emergency 134 * call to allow for carrier specific operations, such as provide SUPL updates during or after 135 * the emergency call, since some modems do not support these operations on the non DDS. 136 */ 137 private static final class EmergencyOverrideRequest { 138 /* The Phone ID that the DDS should be set to. */ 139 int mPhoneId = INVALID_PHONE_INDEX; 140 /* The time after the emergency call ends that the DDS should be overridden for. */ 141 int mGnssOverrideTimeMs = -1; 142 /* A callback to the requester notifying them if the initial call to the modem to override 143 * the DDS was successful. 144 */ 145 CompletableFuture<Boolean> mOverrideCompleteFuture; 146 /* In the special case that the device goes into emergency callback mode after the emergency 147 * call ends, keep the override until ECM finishes and then start the mGnssOverrideTimeMs 148 * timer to leave DDS override. 149 */ 150 boolean mRequiresEcmFinish = false; 151 152 /* 153 * Keeps track of whether or not this request has already serviced the outgoing emergency 154 * call. Once finished, do not delay for any other calls. 155 */ 156 boolean mPendingOriginatingCall = true; 157 158 /** 159 * @return true if there is a pending override complete callback. 160 */ isCallbackAvailable()161 boolean isCallbackAvailable() { 162 return mOverrideCompleteFuture != null; 163 } 164 165 /** 166 * Send the override complete callback the result of setting the DDS to the new value. 167 */ sendOverrideCompleteCallbackResultAndClear(boolean result)168 void sendOverrideCompleteCallbackResultAndClear(boolean result) { 169 if (isCallbackAvailable()) { 170 mOverrideCompleteFuture.complete(result); 171 mOverrideCompleteFuture = null; 172 } 173 } 174 175 176 @Override toString()177 public String toString() { 178 return String.format("EmergencyOverrideRequest: [phoneId= %d, overrideMs= %d," 179 + " hasCallback= %b, ecmFinishStatus= %b]", mPhoneId, mGnssOverrideTimeMs, 180 isCallbackAvailable(), mRequiresEcmFinish); 181 } 182 } 183 184 /** 185 * Callback from PhoneSwitcher 186 */ 187 public static class PhoneSwitcherCallback extends DataCallback { 188 /** 189 * Constructor 190 * 191 * @param executor The executor of the callback. 192 */ PhoneSwitcherCallback(@onNull @allbackExecutor Executor executor)193 public PhoneSwitcherCallback(@NonNull @CallbackExecutor Executor executor) { 194 super(executor); 195 } 196 197 /** 198 * Called when preferred data phone id changed. 199 * 200 * @param phoneId The phone id of the preferred data. 201 */ onPreferredDataPhoneIdChanged(int phoneId)202 public void onPreferredDataPhoneIdChanged(int phoneId) {} 203 } 204 205 @NonNull 206 private final NetworkRequestList mNetworkRequestList = new NetworkRequestList(); 207 protected final RegistrantList mActivePhoneRegistrants; 208 private final SubscriptionManagerService mSubscriptionManagerService; 209 @NonNull 210 private final FeatureFlags mFlags; 211 protected final Context mContext; 212 private final LocalLog mLocalLog; 213 protected PhoneState[] mPhoneStates; 214 protected int[] mPhoneSubscriptions; 215 private boolean mIsRegisteredForImsRadioTechChange; 216 @VisibleForTesting 217 protected final CellularNetworkValidator mValidator; 218 private int mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; 219 /** The reason for the last time changing preferred data sub **/ 220 private int mLastSwitchPreferredDataReason = -1; 221 private boolean mPendingSwitchNeedValidation; 222 @VisibleForTesting 223 public final CellularNetworkValidator.ValidationCallback mValidationCallback = 224 new CellularNetworkValidator.ValidationCallback() { 225 @Override 226 public void onValidationDone(boolean validated, int subId) { 227 Message.obtain(PhoneSwitcher.this, 228 EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget(); 229 } 230 231 @Override 232 public void onNetworkAvailable(Network network, int subId) { 233 Message.obtain(PhoneSwitcher.this, 234 EVENT_NETWORK_AVAILABLE, subId, 0, network).sendToTarget(); 235 236 } 237 }; 238 239 // How many phones (correspondingly logical modems) are allowed for PS attach. This is used 240 // when we specifically use setDataAllowed to initiate on-demand PS(data) attach for each phone. 241 protected int mMaxDataAttachModemCount; 242 // Local cache of TelephonyManager#getActiveModemCount(). 1 if in single SIM mode, 2 if in dual 243 // SIM mode. 244 protected int mActiveModemCount; 245 protected static PhoneSwitcher sPhoneSwitcher = null; 246 247 // Which primary (non-opportunistic) subscription is set as data subscription among all primary 248 // subscriptions. This value usually comes from user setting, and it's the subscription used for 249 // Internet data if mOpptDataSubId is not set. 250 protected int mPrimaryDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 251 252 // The automatically suggested preferred data subId (by e.g. CBRS or auto data switch), a 253 // candidate for preferred data subId, which is eventually presided by 254 // updatePreferredDataPhoneId(). 255 // If CBRS/auto switch feature selects the primary data subId as the preferred data subId, 256 // its value will be DEFAULT_SUBSCRIPTION_ID. 257 private int mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 258 259 // The phone ID that has an active voice call. If set, and its mobile data setting is on, 260 // it will become the mPreferredDataPhoneId. 261 protected int mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; 262 263 @VisibleForTesting 264 // It decides: 265 // 1. In modem layer, which modem is DDS (preferred to have data traffic on) 266 // 2. In TelephonyNetworkProvider, which subscription will apply default network requests, which 267 // are requests without specifying a subId. 268 // Corresponding phoneId after considering mOpptDataSubId, mPrimaryDataSubId and 269 // mPhoneIdInVoiceCall above. 270 protected int mPreferredDataPhoneId = SubscriptionManager.INVALID_PHONE_INDEX; 271 272 // Subscription ID corresponds to mPreferredDataPhoneId. 273 protected WatchedInt mPreferredDataSubId = new WatchedInt( 274 SubscriptionManager.INVALID_SUBSCRIPTION_ID); 275 276 // If non-null, An emergency call is about to be started, is ongoing, or has just ended and we 277 // are overriding the DDS. 278 // Internal state, should ONLY be accessed/modified inside of the handler. 279 private EmergencyOverrideRequest mEmergencyOverride; 280 281 private ISetOpportunisticDataCallback mSetOpptSubCallback; 282 283 /** Phone switcher callbacks. */ 284 @NonNull 285 private final Set<PhoneSwitcherCallback> mPhoneSwitcherCallbacks = new ArraySet<>(); 286 287 private static final int EVENT_PRIMARY_DATA_SUB_CHANGED = 101; 288 protected static final int EVENT_SUBSCRIPTION_CHANGED = 102; 289 // ECBM has started/ended. If we just ended an emergency call and mEmergencyOverride is not 290 // null, we will wait for EVENT_EMERGENCY_TOGGLE again with ECBM ending to send the message 291 // EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE to remove the override after the mEmergencyOverride 292 // override timer ends. 293 private static final int EVENT_EMERGENCY_TOGGLE = 105; 294 private static final int EVENT_RADIO_CAPABILITY_CHANGED = 106; 295 private static final int EVENT_OPPT_DATA_SUB_CHANGED = 107; 296 private static final int EVENT_RADIO_ON = 108; 297 // A call has either started or ended. If an emergency ended and DDS is overridden using 298 // mEmergencyOverride, start the countdown to remove the override using the message 299 // EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE. The only exception to this is if the device moves to 300 // ECBM, which is detected by EVENT_EMERGENCY_TOGGLE. 301 private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 109; 302 private static final int EVENT_NETWORK_VALIDATION_DONE = 110; 303 304 private static final int EVENT_MODEM_COMMAND_DONE = 112; 305 private static final int EVENT_MODEM_COMMAND_RETRY = 113; 306 307 // An emergency call is about to be originated and requires the DDS to be overridden. 308 // Uses EVENT_PRECISE_CALL_STATE_CHANGED message to start countdown to finish override defined 309 // in mEmergencyOverride. If EVENT_PRECISE_CALL_STATE_CHANGED does not come in 310 // DEFAULT_DATA_OVERRIDE_TIMEOUT_MS milliseconds, then the override will be removed. 311 private static final int EVENT_OVERRIDE_DDS_FOR_EMERGENCY = 115; 312 // If it exists, remove the current mEmergencyOverride DDS override. 313 private static final int EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE = 116; 314 // If it exists, remove the current mEmergencyOverride DDS override. 315 private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 117; 316 private static final int EVENT_NETWORK_AVAILABLE = 118; 317 private static final int EVENT_PROCESS_SIM_STATE_CHANGE = 119; 318 private static final int EVENT_IMS_RADIO_TECH_CHANGED = 120; 319 320 // List of events triggers re-evaluations 321 private static final String EVALUATION_REASON_RADIO_ON = "EVENT_RADIO_ON"; 322 323 // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's 324 // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse 325 // will be either HAL_COMMAND_ALLOW_DATA or HAL_COMMAND_ALLOW_DATA or HAL_COMMAND_UNKNOWN. 326 protected static final int HAL_COMMAND_UNKNOWN = 0; 327 protected static final int HAL_COMMAND_ALLOW_DATA = 1; 328 protected static final int HAL_COMMAND_PREFERRED_DATA = 2; 329 protected int mHalCommandToUse = HAL_COMMAND_UNKNOWN; 330 331 protected RadioConfig mRadioConfig; 332 333 private static final int MAX_LOCAL_LOG_LINES = 256; 334 335 // Default timeout value of network validation in millisecond. 336 private static final int DEFAULT_VALIDATION_EXPIRATION_TIME = 2000; 337 338 /** Controller that tracks {@link TelephonyManager#MOBILE_DATA_POLICY_AUTO_DATA_SWITCH} */ 339 @NonNull private final AutoDataSwitchController mAutoDataSwitchController; 340 /** Callback to deal with requests made by the auto data switch controller. */ 341 @NonNull private final AutoDataSwitchController.AutoDataSwitchControllerCallback 342 mAutoDataSwitchCallback; 343 344 private final ConnectivityManager mConnectivityManager; 345 private int mImsRegistrationTech = REGISTRATION_TECH_NONE; 346 @VisibleForTesting 347 public final SparseIntArray mImsRegistrationRadioTechMap = new SparseIntArray(); 348 @NonNull 349 private final List<Set<CommandException.Error>> mCurrentDdsSwitchFailure; 350 351 /** Data settings manager callback. Key is the phone id. */ 352 @NonNull 353 private final Map<Integer, DataSettingsManagerCallback> mDataSettingsManagerCallbacks = 354 new ArrayMap<>(); 355 356 private class DefaultNetworkCallback extends ConnectivityManager.NetworkCallback { 357 public int mExpectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 358 public int mSwitchReason = TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; 359 @Override onCapabilitiesChanged(@onNull Network network, NetworkCapabilities networkCapabilities)360 public void onCapabilitiesChanged(@NonNull Network network, 361 NetworkCapabilities networkCapabilities) { 362 if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { 363 if (SubscriptionManager.isValidSubscriptionId(mExpectedSubId) 364 && mExpectedSubId == getSubIdFromNetworkSpecifier( 365 networkCapabilities.getNetworkSpecifier())) { 366 logDataSwitchEvent( 367 mExpectedSubId, 368 TelephonyEvent.EventState.EVENT_STATE_END, 369 mSwitchReason); 370 mExpectedSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 371 mSwitchReason = TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; 372 } 373 } 374 mAutoDataSwitchController.updateDefaultNetworkCapabilities(networkCapabilities); 375 } 376 377 @Override onLost(@onNull Network network)378 public void onLost(@NonNull Network network) { 379 mAutoDataSwitchController.updateDefaultNetworkCapabilities(null); 380 } 381 } 382 383 private final RegistrationManager.RegistrationCallback mRegistrationCallback = 384 new RegistrationManager.RegistrationCallback() { 385 @Override 386 public void onRegistered(@NonNull ImsRegistrationAttributes attributes) { 387 int imsRegistrationTech = attributes.getRegistrationTechnology(); 388 if (imsRegistrationTech != mImsRegistrationTech) { 389 mImsRegistrationTech = imsRegistrationTech; 390 sendMessage(obtainMessage(EVENT_IMS_RADIO_TECH_CHANGED)); 391 } 392 } 393 394 @Override 395 public void onUnregistered(@NonNull ImsReasonInfo info) { 396 if (mImsRegistrationTech != REGISTRATION_TECH_NONE) { 397 mImsRegistrationTech = REGISTRATION_TECH_NONE; 398 sendMessage(obtainMessage(EVENT_IMS_RADIO_TECH_CHANGED)); 399 } 400 } 401 }; 402 403 private final DefaultNetworkCallback mDefaultNetworkCallback = new DefaultNetworkCallback(); 404 405 /** 406 * Interface to get ImsRegistrationTech. It's a wrapper of ImsManager#getRegistrationTech, 407 * to make it mock-able in unittests. 408 */ 409 public interface ImsRegTechProvider { 410 /** Get IMS registration tech. */ get(Context context, int phoneId)411 @ImsRegistrationImplBase.ImsRegistrationTech int get(Context context, int phoneId); 412 } 413 414 @VisibleForTesting 415 public ImsRegTechProvider mImsRegTechProvider = 416 (context, phoneId) -> ImsManager.getInstance(context, phoneId).getRegistrationTech(); 417 418 /** 419 * Interface to register RegistrationCallback. It's a wrapper of 420 * ImsManager#addRegistrationCallback, to make it mock-able in unittests. 421 */ 422 public interface ImsRegisterCallback { 423 /** Set RegistrationCallback. */ setCallback(Context context, int phoneId, RegistrationManager.RegistrationCallback cb, Executor executor)424 void setCallback(Context context, int phoneId, RegistrationManager.RegistrationCallback cb, 425 Executor executor) throws ImsException; 426 } 427 428 @VisibleForTesting 429 public ImsRegisterCallback mImsRegisterCallback = 430 (context, phoneId, cb, executor)-> ImsManager.getInstance(context, phoneId) 431 .addRegistrationCallback(cb, executor); 432 433 /** 434 * Method to get singleton instance. 435 */ getInstance()436 public static PhoneSwitcher getInstance() { 437 return sPhoneSwitcher; 438 } 439 440 /** 441 * Method to create singleton instance. 442 */ make(int maxDataAttachModemCount, Context context, Looper looper, @NonNull FeatureFlags flags)443 public static PhoneSwitcher make(int maxDataAttachModemCount, Context context, Looper looper, 444 @NonNull FeatureFlags flags) { 445 if (sPhoneSwitcher == null) { 446 sPhoneSwitcher = new PhoneSwitcher(maxDataAttachModemCount, context, looper, flags); 447 } 448 449 return sPhoneSwitcher; 450 } 451 updatesIfPhoneInVoiceCallChanged()452 private boolean updatesIfPhoneInVoiceCallChanged() { 453 int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall; 454 // If there's no active call, the value will become INVALID_PHONE_INDEX 455 // and internet data will be switched back to system selected or user selected 456 // subscription. 457 mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; 458 for (Phone phone : PhoneFactory.getPhones()) { 459 if (isPhoneInVoiceCall(phone) || isPhoneInVoiceCall(phone.getImsPhone())) { 460 mPhoneIdInVoiceCall = phone.getPhoneId(); 461 break; 462 } 463 } 464 465 if (mPhoneIdInVoiceCall != oldPhoneIdInVoiceCall) { 466 logl("isPhoneInVoiceCallChanged from phoneId " + oldPhoneIdInVoiceCall 467 + " to phoneId " + mPhoneIdInVoiceCall); 468 return true; 469 } else { 470 return false; 471 } 472 } 473 registerForImsRadioTechChange(Context context, int phoneId)474 private void registerForImsRadioTechChange(Context context, int phoneId) { 475 try { 476 mImsRegisterCallback.setCallback(context, phoneId, mRegistrationCallback, this::post); 477 mIsRegisteredForImsRadioTechChange = true; 478 } catch (ImsException imsException) { 479 mIsRegisteredForImsRadioTechChange = false; 480 } 481 } 482 registerForImsRadioTechChange()483 private void registerForImsRadioTechChange() { 484 // register for radio tech change to listen to radio tech handover. 485 if (!mIsRegisteredForImsRadioTechChange) { 486 for (int i = 0; i < mActiveModemCount; i++) { 487 registerForImsRadioTechChange(mContext, i); 488 } 489 } 490 } 491 492 /** 493 * Register the callback for receiving information from {@link PhoneSwitcher}. 494 * 495 * @param callback The callback. 496 */ registerCallback(@onNull PhoneSwitcherCallback callback)497 public void registerCallback(@NonNull PhoneSwitcherCallback callback) { 498 mPhoneSwitcherCallbacks.add(callback); 499 } 500 501 /** 502 * Unregister the callback for receiving information from {@link PhoneSwitcher}. 503 * 504 * @param callback The callback. 505 */ unregisterCallback(@onNull PhoneSwitcherCallback callback)506 public void unregisterCallback(@NonNull PhoneSwitcherCallback callback) { 507 mPhoneSwitcherCallbacks.remove(callback); 508 } 509 evaluateIfImmediateDataSwitchIsNeeded(String evaluationReason, int switchReason)510 private void evaluateIfImmediateDataSwitchIsNeeded(String evaluationReason, int switchReason) { 511 if (onEvaluate(REQUESTS_UNCHANGED, evaluationReason)) { 512 logDataSwitchEvent(mPreferredDataSubId.get(), 513 TelephonyEvent.EventState.EVENT_STATE_START, 514 switchReason); 515 registerDefaultNetworkChangeCallback(mPreferredDataSubId.get(), 516 switchReason); 517 } 518 } 519 520 @VisibleForTesting PhoneSwitcher(int maxActivePhones, Context context, Looper looper, @NonNull FeatureFlags featureFlags)521 public PhoneSwitcher(int maxActivePhones, Context context, Looper looper, 522 @NonNull FeatureFlags featureFlags) { 523 super(looper); 524 mContext = context; 525 mFlags = featureFlags; 526 mActiveModemCount = getTm().getActiveModemCount(); 527 mPhoneSubscriptions = new int[mActiveModemCount]; 528 mPhoneStates = new PhoneState[mActiveModemCount]; 529 mMaxDataAttachModemCount = maxActivePhones; 530 mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); 531 532 mSubscriptionManagerService = SubscriptionManagerService.getInstance(); 533 534 mRadioConfig = RadioConfig.getInstance(); 535 mValidator = CellularNetworkValidator.getInstance(); 536 537 mCurrentDdsSwitchFailure = new ArrayList<>(); 538 IntentFilter filter = new IntentFilter(); 539 filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); 540 mContext.registerReceiver(mSimStateIntentReceiver, filter); 541 542 mActivePhoneRegistrants = new RegistrantList(); 543 for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { 544 mPhoneStates[phoneId] = new PhoneState(); 545 Phone phone = PhoneFactory.getPhone(phoneId); 546 if (phone != null) { 547 phone.registerForEmergencyCallToggle( 548 this, EVENT_EMERGENCY_TOGGLE, null); 549 // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone. 550 phone.registerForPreciseCallStateChanged( 551 this, EVENT_PRECISE_CALL_STATE_CHANGED, null); 552 if (phone.getImsPhone() != null) { 553 phone.getImsPhone().registerForPreciseCallStateChanged( 554 this, EVENT_PRECISE_CALL_STATE_CHANGED, null); 555 if (mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 556 // Initialize IMS registration tech 557 mImsRegistrationRadioTechMap.put(phoneId, REGISTRATION_TECH_NONE); 558 ((ImsPhone) phone.getImsPhone()).registerForImsRegistrationChanges( 559 this, EVENT_IMS_RADIO_TECH_CHANGED, null); 560 561 log("register handler to receive IMS registration : " + phoneId); 562 } 563 } 564 mDataSettingsManagerCallbacks.computeIfAbsent(phoneId, 565 v -> new DataSettingsManagerCallback(this::post) { 566 @Override 567 public void onDataEnabledChanged(boolean enabled, 568 @TelephonyManager.DataEnabledChangedReason int reason, 569 @NonNull String callingPackage) { 570 PhoneSwitcher.this.onDataEnabledChanged(); 571 } 572 @Override 573 public void onDataRoamingEnabledChanged(boolean enabled) { 574 PhoneSwitcher.this.mAutoDataSwitchController.evaluateAutoDataSwitch( 575 AutoDataSwitchController 576 .EVALUATION_REASON_DATA_SETTINGS_CHANGED); 577 }}); 578 phone.getDataSettingsManager().registerCallback( 579 mDataSettingsManagerCallbacks.get(phoneId)); 580 581 if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 582 registerForImsRadioTechChange(context, phoneId); 583 } 584 } 585 Set<CommandException.Error> ddsFailure = new HashSet<>(); 586 mCurrentDdsSwitchFailure.add(ddsFailure); 587 } 588 589 if (mActiveModemCount > 0) { 590 PhoneFactory.getPhone(0).mCi.registerForOn(this, EVENT_RADIO_ON, null); 591 } 592 593 TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) 594 context.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); 595 telephonyRegistryManager.addOnSubscriptionsChangedListener( 596 mSubscriptionsChangedListener, this::post); 597 598 mConnectivityManager = 599 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 600 601 mAutoDataSwitchCallback = new AutoDataSwitchController.AutoDataSwitchControllerCallback() { 602 @Override 603 public void onRequireValidation(int targetPhoneId, boolean needValidation) { 604 int targetSubId = targetPhoneId == DEFAULT_PHONE_INDEX 605 ? DEFAULT_SUBSCRIPTION_ID 606 : mSubscriptionManagerService.getSubId(targetPhoneId); 607 PhoneSwitcher.this.validate(targetSubId, needValidation, 608 DataSwitch.Reason.DATA_SWITCH_REASON_AUTO, null); 609 } 610 611 @Override 612 public void onRequireImmediatelySwitchToPhone(int targetPhoneId, 613 @AutoDataSwitchController.AutoDataSwitchEvaluationReason int reason) { 614 PhoneSwitcher.this.mAutoSelectedDataSubId = 615 targetPhoneId == DEFAULT_PHONE_INDEX 616 ? DEFAULT_SUBSCRIPTION_ID 617 : mSubscriptionManagerService.getSubId(targetPhoneId); 618 PhoneSwitcher.this.evaluateIfImmediateDataSwitchIsNeeded( 619 AutoDataSwitchController.evaluationReasonToString(reason), 620 DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); 621 } 622 623 @Override 624 public void onRequireCancelAnyPendingAutoSwitchValidation() { 625 PhoneSwitcher.this.cancelPendingAutoDataSwitchValidation(); 626 } 627 }; 628 mAutoDataSwitchController = new AutoDataSwitchController(context, looper, this, 629 mFlags, mAutoDataSwitchCallback); 630 if (!mFlags.ddsCallback()) { 631 mContext.registerReceiver(mDefaultDataChangedReceiver, 632 new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); 633 } else { 634 mSubscriptionManagerService.registerCallback(new SubscriptionManagerServiceCallback( 635 this::post) { 636 @Override 637 public void onDefaultDataSubscriptionChanged(int subId) { 638 evaluateIfImmediateDataSwitchIsNeeded("default data sub changed to " + subId, 639 DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); 640 } 641 }); 642 } 643 644 PhoneConfigurationManager.registerForMultiSimConfigChange( 645 this, EVENT_MULTI_SIM_CONFIG_CHANGED, null); 646 647 mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, this); 648 updateHalCommandToUse(); 649 650 logl("PhoneSwitcher started"); 651 } 652 653 private final BroadcastReceiver mDefaultDataChangedReceiver = new BroadcastReceiver() { 654 @Override 655 public void onReceive(Context context, Intent intent) { 656 Message msg = PhoneSwitcher.this.obtainMessage(EVENT_PRIMARY_DATA_SUB_CHANGED); 657 msg.sendToTarget(); 658 } 659 }; 660 661 private final BroadcastReceiver mSimStateIntentReceiver = new BroadcastReceiver() { 662 @Override 663 public void onReceive(Context context, Intent intent) { 664 String action = intent.getAction(); 665 if (action.equals(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { 666 int state = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE, 667 TelephonyManager.SIM_STATE_UNKNOWN); 668 int slotIndex = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 669 SubscriptionManager.INVALID_SIM_SLOT_INDEX); 670 logl("mSimStateIntentReceiver: slotIndex = " + slotIndex + " state = " + state); 671 obtainMessage(EVENT_PROCESS_SIM_STATE_CHANGE, slotIndex, state).sendToTarget(); 672 } 673 } 674 }; 675 isSimApplicationReady(int slotIndex)676 private boolean isSimApplicationReady(int slotIndex) { 677 if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { 678 return false; 679 } 680 681 SubscriptionInfo info = mSubscriptionManagerService 682 .getActiveSubscriptionInfoForSimSlotIndex(slotIndex, 683 mContext.getOpPackageName(), mContext.getAttributionTag()); 684 boolean uiccAppsEnabled = info != null && info.areUiccApplicationsEnabled(); 685 686 IccCard iccCard = PhoneFactory.getPhone(slotIndex).getIccCard(); 687 if (!iccCard.isEmptyProfile() && uiccAppsEnabled) { 688 logl("isSimApplicationReady: SIM is ready for slotIndex: " + slotIndex); 689 return true; 690 } else { 691 return false; 692 } 693 } 694 695 private final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangedListener = 696 new SubscriptionManager.OnSubscriptionsChangedListener() { 697 @Override 698 public void onSubscriptionsChanged() { 699 Message msg = PhoneSwitcher.this.obtainMessage(EVENT_SUBSCRIPTION_CHANGED); 700 msg.sendToTarget(); 701 } 702 }; 703 704 @Override handleMessage(Message msg)705 public void handleMessage(Message msg) { 706 switch (msg.what) { 707 case EVENT_SUBSCRIPTION_CHANGED: { 708 onEvaluate(REQUESTS_UNCHANGED, "subscription changed"); 709 break; 710 } 711 case EVENT_PRIMARY_DATA_SUB_CHANGED: { 712 evaluateIfImmediateDataSwitchIsNeeded("primary data sub changed", 713 DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); 714 break; 715 } 716 case EVENT_EMERGENCY_TOGGLE: { 717 boolean isInEcm = isInEmergencyCallbackMode(); 718 if (mEmergencyOverride != null) { 719 logl("Emergency override - ecbm status = " + isInEcm); 720 if (isInEcm) { 721 // The device has gone into ECBM. Wait until it's out. 722 removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 723 mEmergencyOverride.mRequiresEcmFinish = true; 724 } else if (mEmergencyOverride.mRequiresEcmFinish) { 725 // we have exited ECM! Start the timer to exit DDS override. 726 Message msg2 = obtainMessage(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 727 sendMessageDelayed(msg2, mEmergencyOverride.mGnssOverrideTimeMs); 728 } 729 } 730 onEvaluate(REQUESTS_CHANGED, "emergencyToggle"); 731 break; 732 } 733 case EVENT_RADIO_CAPABILITY_CHANGED: { 734 final int phoneId = msg.arg1; 735 sendRilCommands(phoneId); 736 break; 737 } 738 case EVENT_OPPT_DATA_SUB_CHANGED: { 739 int subId = msg.arg1; 740 boolean needValidation = (msg.arg2 == 1); 741 ISetOpportunisticDataCallback callback = 742 (ISetOpportunisticDataCallback) msg.obj; 743 setOpportunisticDataSubscription(subId, needValidation, callback); 744 break; 745 } 746 case EVENT_RADIO_ON: { 747 updateHalCommandToUse(); 748 onEvaluate(REQUESTS_UNCHANGED, EVALUATION_REASON_RADIO_ON); 749 break; 750 } 751 case EVENT_IMS_RADIO_TECH_CHANGED: { 752 // register for radio tech change to listen to radio tech handover in case previous 753 // attempt was not successful 754 if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 755 registerForImsRadioTechChange(); 756 } else { 757 if (msg.obj == null) { 758 log("EVENT_IMS_RADIO_TECH_CHANGED but parameter is not available"); 759 break; 760 } 761 if (!onImsRadioTechChanged((AsyncResult) (msg.obj))) { 762 break; 763 } 764 } 765 766 // if voice call state changes or in voice call didn't change 767 // but RAT changes(e.g. Iwlan -> cross sim), reevaluate for data switch. 768 if (updatesIfPhoneInVoiceCallChanged() || isAnyVoiceCallActiveOnDevice()) { 769 evaluateIfImmediateDataSwitchIsNeeded("Ims radio tech changed", 770 DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); 771 } 772 break; 773 } 774 case EVENT_PRECISE_CALL_STATE_CHANGED: { 775 // register for radio tech change to listen to radio tech handover in case previous 776 // attempt was not successful 777 if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 778 registerForImsRadioTechChange(); 779 } 780 781 // If the phoneId in voice call didn't change, do nothing. 782 if (!updatesIfPhoneInVoiceCallChanged()) { 783 break; 784 } 785 786 if (!isAnyVoiceCallActiveOnDevice()) { 787 for (int i = 0; i < mActiveModemCount; i++) { 788 if (mCurrentDdsSwitchFailure.get(i).contains( 789 CommandException.Error.OP_NOT_ALLOWED_DURING_VOICE_CALL) 790 && isPhoneIdValidForRetry(i)) { 791 sendRilCommands(i); 792 } 793 } 794 } 795 796 // Only handle this event if we are currently waiting for the emergency call 797 // associated with the override request to start or end. 798 if (mEmergencyOverride != null && mEmergencyOverride.mPendingOriginatingCall) { 799 removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 800 if (mPhoneIdInVoiceCall == SubscriptionManager.INVALID_PHONE_INDEX) { 801 // not in a call anymore. 802 Message msg2 = obtainMessage(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 803 sendMessageDelayed(msg2, mEmergencyOverride.mGnssOverrideTimeMs 804 + ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS); 805 // Do not extend the emergency override by waiting for other calls to end. 806 // If it needs to be extended, a new request will come in and replace the 807 // current override. 808 mEmergencyOverride.mPendingOriginatingCall = false; 809 } 810 } 811 // Always update data modem via data during call code path, because 812 // mAutoSelectedDataSubId doesn't know about any data switch due to voice call 813 evaluateIfImmediateDataSwitchIsNeeded("precise call state changed", 814 DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); 815 if (!isAnyVoiceCallActiveOnDevice()) { 816 // consider auto switch on hang up all voice call 817 mAutoDataSwitchController.evaluateAutoDataSwitch( 818 AutoDataSwitchController.EVALUATION_REASON_VOICE_CALL_END); 819 } 820 break; 821 } 822 case EVENT_NETWORK_VALIDATION_DONE: { 823 int subId = msg.arg1; 824 boolean passed = (msg.arg2 == 1); 825 onValidationDone(subId, passed); 826 break; 827 } 828 case EVENT_NETWORK_AVAILABLE: { 829 int subId = msg.arg1; 830 Network network = (Network) msg.obj; 831 onNetworkAvailable(subId, network); 832 break; 833 } 834 case EVENT_MODEM_COMMAND_DONE: { 835 AsyncResult ar = (AsyncResult) msg.obj; 836 onDdsSwitchResponse(ar); 837 break; 838 } 839 case EVENT_MODEM_COMMAND_RETRY: { 840 int phoneId = (int) msg.obj; 841 if (mActiveModemCount <= phoneId) { 842 break; 843 } 844 if (isPhoneIdValidForRetry(phoneId)) { 845 logl("EVENT_MODEM_COMMAND_RETRY: resend modem command on phone " + phoneId); 846 sendRilCommands(phoneId); 847 } else { 848 logl("EVENT_MODEM_COMMAND_RETRY: skip retry as DDS sub changed"); 849 mCurrentDdsSwitchFailure.get(phoneId).clear(); 850 } 851 break; 852 } 853 case EVENT_OVERRIDE_DDS_FOR_EMERGENCY: { 854 EmergencyOverrideRequest req = (EmergencyOverrideRequest) msg.obj; 855 if (mEmergencyOverride != null) { 856 // If an override request comes in for a different phone ID than what is already 857 // being overridden, ignore. We should not try to switch DDS while already 858 // waiting for SUPL. 859 if (mEmergencyOverride.mPhoneId != req.mPhoneId) { 860 logl("emergency override requested for phone id " + req.mPhoneId + " when " 861 + "there is already an override in place for phone id " 862 + mEmergencyOverride.mPhoneId + ". Ignoring."); 863 if (req.isCallbackAvailable()) { 864 // Send failed result 865 req.mOverrideCompleteFuture.complete(false); 866 } 867 break; 868 } else { 869 if (mEmergencyOverride.isCallbackAvailable()) { 870 // Unblock any waiting overrides if a new request comes in before the 871 // previous one is processed. 872 mEmergencyOverride.mOverrideCompleteFuture.complete(false); 873 } 874 } 875 } 876 mEmergencyOverride = req; 877 878 logl("new emergency override - " + mEmergencyOverride); 879 // a new request has been created, remove any previous override complete scheduled. 880 removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 881 Message msg2 = obtainMessage(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 882 // Make sure that if we never get an incall indication that we remove the override. 883 sendMessageDelayed(msg2, DEFAULT_DATA_OVERRIDE_TIMEOUT_MS); 884 // Wait for call to end and EVENT_PRECISE_CALL_STATE_CHANGED to be called, then 885 // start timer to remove DDS emergency override. 886 if (!onEvaluate(REQUESTS_UNCHANGED, "emer_override_dds")) { 887 // Nothing changed as a result of override, so no modem command was sent. Treat 888 // as success. 889 mEmergencyOverride.sendOverrideCompleteCallbackResultAndClear(true); 890 // Do not clear mEmergencyOverride here, as we still want to keep the override 891 // active for the time specified in case the user tries to switch default data. 892 } 893 break; 894 } 895 case EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE: { 896 logl("Emergency override removed - " + mEmergencyOverride); 897 mEmergencyOverride = null; 898 onEvaluate(REQUESTS_UNCHANGED, "emer_rm_override_dds"); 899 break; 900 } 901 case EVENT_MULTI_SIM_CONFIG_CHANGED: { 902 int activeModemCount = (int) ((AsyncResult) msg.obj).result; 903 onMultiSimConfigChanged(activeModemCount); 904 break; 905 } 906 case EVENT_PROCESS_SIM_STATE_CHANGE: { 907 int slotIndex = msg.arg1; 908 int simState = msg.arg2; 909 910 if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { 911 logl("EVENT_PROCESS_SIM_STATE_CHANGE: skip processing due to invalid slotId: " 912 + slotIndex); 913 } else if (TelephonyManager.SIM_STATE_LOADED == simState) { 914 if (mCurrentDdsSwitchFailure.get(slotIndex).contains( 915 CommandException.Error.INVALID_SIM_STATE) 916 && isSimApplicationReady(slotIndex)) { 917 sendRilCommands(slotIndex); 918 } 919 // SIM loaded after subscriptions slot mapping are done. Evaluate for auto 920 // data switch. 921 mAutoDataSwitchController.evaluateAutoDataSwitch( 922 AutoDataSwitchController.EVALUATION_REASON_SIM_LOADED); 923 } 924 break; 925 } 926 } 927 } 928 929 /** 930 * Only provide service for the handler of PhoneSwitcher. 931 * @return true if the radio tech changed, otherwise false 932 */ onImsRadioTechChanged(@onNull AsyncResult asyncResult)933 private boolean onImsRadioTechChanged(@NonNull AsyncResult asyncResult) { 934 ImsPhone.ImsRegistrationRadioTechInfo imsRegistrationRadioTechInfo = 935 (ImsPhone.ImsRegistrationRadioTechInfo) asyncResult.result; 936 if (imsRegistrationRadioTechInfo == null 937 || imsRegistrationRadioTechInfo.phoneId() == INVALID_PHONE_INDEX 938 || imsRegistrationRadioTechInfo.imsRegistrationState() 939 == RegistrationManager.REGISTRATION_STATE_REGISTERING) { 940 // Ignore REGISTERING state, handle only REGISTERED and NOT_REGISTERED 941 log("onImsRadioTechChanged : result is not available"); 942 return false; 943 } 944 945 int phoneId = imsRegistrationRadioTechInfo.phoneId(); 946 int subId = SubscriptionManager.getSubscriptionId(phoneId); 947 int tech = imsRegistrationRadioTechInfo.imsRegistrationTech(); 948 log("onImsRadioTechChanged phoneId : " + phoneId + " subId : " + subId + " old tech : " 949 + mImsRegistrationRadioTechMap.get(phoneId, REGISTRATION_TECH_NONE) 950 + " new tech : " + tech); 951 952 if (mImsRegistrationRadioTechMap.get(phoneId, REGISTRATION_TECH_NONE) == tech) { 953 // Registration tech not changed 954 return false; 955 } 956 957 mImsRegistrationRadioTechMap.put(phoneId, tech); 958 959 // Need to update the cached IMS registration tech but no need to do any of the 960 // following. When the SIM removed, REGISTRATION_STATE_NOT_REGISTERED is notified. 961 return subId != INVALID_SUBSCRIPTION_ID; 962 } 963 onMultiSimConfigChanged(int activeModemCount)964 private synchronized void onMultiSimConfigChanged(int activeModemCount) { 965 // No change. 966 if (mActiveModemCount == activeModemCount) return; 967 int oldActiveModemCount = mActiveModemCount; 968 mActiveModemCount = activeModemCount; 969 970 mPhoneSubscriptions = copyOf(mPhoneSubscriptions, mActiveModemCount); 971 mPhoneStates = copyOf(mPhoneStates, mActiveModemCount); 972 973 // Dual SIM -> Single SIM switch. 974 for (int phoneId = oldActiveModemCount - 1; phoneId >= mActiveModemCount; phoneId--) { 975 mCurrentDdsSwitchFailure.remove(phoneId); 976 } 977 978 // Single SIM -> Dual SIM switch. 979 for (int phoneId = oldActiveModemCount; phoneId < mActiveModemCount; phoneId++) { 980 mPhoneStates[phoneId] = new PhoneState(); 981 Phone phone = PhoneFactory.getPhone(phoneId); 982 if (phone == null) continue; 983 984 phone.registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null); 985 // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone. 986 phone.registerForPreciseCallStateChanged(this, EVENT_PRECISE_CALL_STATE_CHANGED, null); 987 if (phone.getImsPhone() != null) { 988 phone.getImsPhone().registerForPreciseCallStateChanged( 989 this, EVENT_PRECISE_CALL_STATE_CHANGED, null); 990 if (mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 991 // Initialize IMS registration tech for new phoneId 992 mImsRegistrationRadioTechMap.put(phoneId, REGISTRATION_TECH_NONE); 993 ((ImsPhone) phone.getImsPhone()).registerForImsRegistrationChanges( 994 this, EVENT_IMS_RADIO_TECH_CHANGED, null); 995 996 log("register handler to receive IMS registration : " + phoneId); 997 } 998 } 999 1000 mDataSettingsManagerCallbacks.computeIfAbsent(phone.getPhoneId(), 1001 v -> new DataSettingsManagerCallback(this::post) { 1002 @Override 1003 public void onDataEnabledChanged(boolean enabled, 1004 @TelephonyManager.DataEnabledChangedReason int reason, 1005 @NonNull String callingPackage) { 1006 PhoneSwitcher.this.onDataEnabledChanged(); 1007 } 1008 @Override 1009 public void onDataRoamingEnabledChanged(boolean enabled) { 1010 PhoneSwitcher.this.mAutoDataSwitchController.evaluateAutoDataSwitch( 1011 AutoDataSwitchController 1012 .EVALUATION_REASON_DATA_SETTINGS_CHANGED); 1013 } 1014 }); 1015 phone.getDataSettingsManager().registerCallback( 1016 mDataSettingsManagerCallbacks.get(phone.getPhoneId())); 1017 1018 Set<CommandException.Error> ddsFailure = new HashSet<>(); 1019 mCurrentDdsSwitchFailure.add(ddsFailure); 1020 1021 if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 1022 registerForImsRadioTechChange(mContext, phoneId); 1023 } 1024 } 1025 1026 mAutoDataSwitchController.onMultiSimConfigChanged(activeModemCount); 1027 } 1028 1029 /** 1030 * Called when 1031 * 1. user changed mobile data settings 1032 * 2. OR user changed auto data switch feature 1033 */ onDataEnabledChanged()1034 private void onDataEnabledChanged() { 1035 if (isAnyVoiceCallActiveOnDevice()) { 1036 // user changed data related settings during call, switch or turn off immediately 1037 evaluateIfImmediateDataSwitchIsNeeded( 1038 "user changed data settings during call", 1039 DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); 1040 } else { 1041 mAutoDataSwitchController.evaluateAutoDataSwitch(AutoDataSwitchController 1042 .EVALUATION_REASON_DATA_SETTINGS_CHANGED); 1043 } 1044 } 1045 isInEmergencyCallbackMode()1046 private boolean isInEmergencyCallbackMode() { 1047 for (Phone p : PhoneFactory.getPhones()) { 1048 if (p == null) continue; 1049 if (p.isInEcm()) return true; 1050 Phone imsPhone = p.getImsPhone(); 1051 if (imsPhone != null && imsPhone.isInEcm()) { 1052 return true; 1053 } 1054 } 1055 return false; 1056 } 1057 1058 /** 1059 * Called when receiving a network request. 1060 * 1061 * @param networkRequest The network request. 1062 */ 1063 // TODO: Transform to TelephonyNetworkRequest after removing TelephonyNetworkFactory onRequestNetwork(@onNull TelephonyNetworkRequest networkRequest)1064 public void onRequestNetwork(@NonNull TelephonyNetworkRequest networkRequest) { 1065 if (!mNetworkRequestList.contains(networkRequest)) { 1066 mNetworkRequestList.add(networkRequest); 1067 onEvaluate(REQUESTS_CHANGED, "netRequest"); 1068 } 1069 } 1070 1071 /** 1072 * Called when releasing a network request. 1073 * 1074 * @param networkRequest The network request to release. 1075 */ onReleaseNetwork(@onNull TelephonyNetworkRequest networkRequest)1076 public void onReleaseNetwork(@NonNull TelephonyNetworkRequest networkRequest) { 1077 if (mNetworkRequestList.remove(networkRequest)) { 1078 onEvaluate(REQUESTS_CHANGED, "netReleased"); 1079 } 1080 } 1081 registerDefaultNetworkChangeCallback(int expectedSubId, int reason)1082 private void registerDefaultNetworkChangeCallback(int expectedSubId, int reason) { 1083 mDefaultNetworkCallback.mExpectedSubId = expectedSubId; 1084 mDefaultNetworkCallback.mSwitchReason = reason; 1085 } 1086 1087 /** 1088 * Cancel any auto switch attempts when the current environment is not suitable for auto switch. 1089 */ cancelPendingAutoDataSwitchValidation()1090 private void cancelPendingAutoDataSwitchValidation() { 1091 if (mValidator.isValidating()) { 1092 mValidator.stopValidation(); 1093 1094 removeMessages(EVENT_NETWORK_VALIDATION_DONE); 1095 removeMessages(EVENT_NETWORK_AVAILABLE); 1096 mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; 1097 mPendingSwitchNeedValidation = false; 1098 } 1099 } 1100 getTm()1101 private TelephonyManager getTm() { 1102 return (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 1103 } 1104 1105 protected static final boolean REQUESTS_CHANGED = true; 1106 protected static final boolean REQUESTS_UNCHANGED = false; 1107 /** 1108 * Re-evaluate things. Do nothing if nothing's changed. 1109 * <p> 1110 * Otherwise, go through the requests in priority order adding their phone until we've added up 1111 * to the max allowed. Then go through shutting down phones that aren't in the active phone 1112 * list. Finally, activate all phones in the active phone list. 1113 * 1114 * @return {@code True} if the default data subscription need to be changed. 1115 */ onEvaluate(boolean requestsChanged, String reason)1116 protected boolean onEvaluate(boolean requestsChanged, String reason) { 1117 StringBuilder sb = new StringBuilder(reason); 1118 1119 // If we use HAL_COMMAND_PREFERRED_DATA, 1120 boolean diffDetected = mHalCommandToUse != HAL_COMMAND_PREFERRED_DATA && requestsChanged; 1121 1122 // Check if user setting of default non-opportunistic data sub is changed. 1123 int primaryDataSubId = mSubscriptionManagerService.getDefaultDataSubId(); 1124 if (primaryDataSubId != mPrimaryDataSubId) { 1125 sb.append(" mPrimaryDataSubId ").append(mPrimaryDataSubId).append("->") 1126 .append(primaryDataSubId); 1127 mPrimaryDataSubId = primaryDataSubId; 1128 mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL; 1129 } 1130 1131 // Check to see if there is any active subscription on any phone 1132 boolean hasAnyActiveSubscription = false; 1133 1134 // Check if phoneId to subId mapping is changed. 1135 for (int i = 0; i < mActiveModemCount; i++) { 1136 int sub = SubscriptionManager.getSubscriptionId(i); 1137 1138 if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true; 1139 1140 if (sub != mPhoneSubscriptions[i]) { 1141 sb.append(" phone[").append(i).append("] ").append(mPhoneSubscriptions[i]); 1142 sb.append("->").append(sub); 1143 if (mAutoSelectedDataSubId == mPhoneSubscriptions[i]) { 1144 mAutoSelectedDataSubId = DEFAULT_SUBSCRIPTION_ID; 1145 } 1146 mPhoneSubscriptions[i] = sub; 1147 1148 if (!mFlags.changeMethodOfObtainingImsRegistrationRadioTech()) { 1149 // Listen to IMS radio tech change for new sub 1150 if (SubscriptionManager.isValidSubscriptionId(sub)) { 1151 registerForImsRadioTechChange(mContext, i); 1152 } 1153 } 1154 1155 diffDetected = true; 1156 mAutoDataSwitchController.notifySubscriptionsMappingChanged(); 1157 } 1158 } 1159 1160 if (!hasAnyActiveSubscription) { 1161 transitionToEmergencyPhone(); 1162 } else { 1163 if (VDBG) log("Found an active subscription"); 1164 } 1165 1166 // Check if phoneId for preferred data is changed. 1167 int oldPreferredDataPhoneId = mPreferredDataPhoneId; 1168 1169 // Check if subId for preferred data is changed. 1170 int oldPreferredDataSubId = mPreferredDataSubId.get(); 1171 1172 // When there are no subscriptions, the preferred data phone ID is invalid, but we want 1173 // to keep a valid phoneId for Emergency, so skip logic that updates for preferred data 1174 // phone ID. Ideally there should be a single set of checks that evaluate the correct 1175 // phoneId on a service-by-service basis (EIMS being one), but for now... just bypass 1176 // this logic in the no-SIM case. 1177 if (hasAnyActiveSubscription) updatePreferredDataPhoneId(); 1178 1179 if (oldPreferredDataPhoneId != mPreferredDataPhoneId) { 1180 sb.append(" preferred data phoneId ").append(oldPreferredDataPhoneId) 1181 .append("->").append(mPreferredDataPhoneId); 1182 diffDetected = true; 1183 } else if (oldPreferredDataSubId != mPreferredDataSubId.get()) { 1184 logl("SIM refresh, notify dds change"); 1185 // Inform connectivity about the active data phone 1186 notifyPreferredDataSubIdChanged(); 1187 } 1188 1189 // Always force DDS when radio on. This is to handle the corner cases that modem and android 1190 // DDS are out of sync after APM, AP should force DDS when radio on. long term solution 1191 // should be having API to query preferred data modem to detect the out-of-sync scenarios. 1192 if (diffDetected || EVALUATION_REASON_RADIO_ON.equals(reason)) { 1193 logl("evaluating due to " + sb); 1194 if (mHalCommandToUse == HAL_COMMAND_PREFERRED_DATA) { 1195 // With HAL_COMMAND_PREFERRED_DATA, all phones are assumed to allow PS attach. 1196 // So marking all phone as active, and the phone with mPreferredDataPhoneId 1197 // will send radioConfig command. 1198 for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { 1199 mPhoneStates[phoneId].active = true; 1200 } 1201 sendRilCommands(mPreferredDataPhoneId); 1202 } else { 1203 List<Integer> newActivePhones = new ArrayList<>(); 1204 1205 // If all phones can have PS attached, activate all. 1206 // Otherwise, choose to activate phones according to requests. And 1207 // if list is not full, add mPreferredDataPhoneId. 1208 if (mMaxDataAttachModemCount == mActiveModemCount) { 1209 for (int i = 0; i < mMaxDataAttachModemCount; i++) { 1210 newActivePhones.add(i); 1211 } 1212 } else { 1213 // First try to activate phone in voice call. 1214 if (mPhoneIdInVoiceCall != SubscriptionManager.INVALID_PHONE_INDEX) { 1215 newActivePhones.add(mPhoneIdInVoiceCall); 1216 } 1217 1218 if (newActivePhones.size() < mMaxDataAttachModemCount) { 1219 for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { 1220 int phoneIdForRequest = phoneIdForRequest(networkRequest); 1221 if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; 1222 if (newActivePhones.contains(phoneIdForRequest)) continue; 1223 newActivePhones.add(phoneIdForRequest); 1224 if (newActivePhones.size() >= mMaxDataAttachModemCount) break; 1225 } 1226 } 1227 1228 if (newActivePhones.size() < mMaxDataAttachModemCount 1229 && !newActivePhones.contains(mPreferredDataPhoneId) 1230 && SubscriptionManager.isUsableSubIdValue(mPreferredDataPhoneId)) { 1231 newActivePhones.add(mPreferredDataPhoneId); 1232 } 1233 } 1234 1235 if (VDBG) { 1236 log("mPrimaryDataSubId = " + mPrimaryDataSubId); 1237 log("mAutoSelectedDataSubId = " + mAutoSelectedDataSubId); 1238 for (int i = 0; i < mActiveModemCount; i++) { 1239 log(" phone[" + i + "] using sub[" + mPhoneSubscriptions[i] + "]"); 1240 } 1241 log(" newActivePhones:"); 1242 for (Integer i : newActivePhones) log(" " + i); 1243 } 1244 1245 for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { 1246 if (!newActivePhones.contains(phoneId)) { 1247 deactivate(phoneId); 1248 } 1249 } 1250 1251 // only activate phones up to the limit 1252 for (int phoneId : newActivePhones) { 1253 activate(phoneId); 1254 } 1255 } 1256 } 1257 return diffDetected; 1258 } 1259 1260 protected static class PhoneState { 1261 public volatile boolean active = false; 1262 public long lastRequested = 0; 1263 } 1264 activate(int phoneId)1265 protected void activate(int phoneId) { 1266 switchPhone(phoneId, true); 1267 } 1268 deactivate(int phoneId)1269 protected void deactivate(int phoneId) { 1270 switchPhone(phoneId, false); 1271 } 1272 switchPhone(int phoneId, boolean active)1273 private void switchPhone(int phoneId, boolean active) { 1274 PhoneState state = mPhoneStates[phoneId]; 1275 if (state.active == active) return; 1276 state.active = active; 1277 logl((active ? "activate " : "deactivate ") + phoneId); 1278 state.lastRequested = System.currentTimeMillis(); 1279 sendRilCommands(phoneId); 1280 } 1281 1282 /** 1283 * Used when the modem may have been rebooted and we 1284 * want to resend setDataAllowed or setPreferredDataSubscriptionId 1285 */ onRadioCapChanged(int phoneId)1286 public void onRadioCapChanged(int phoneId) { 1287 if (!SubscriptionManager.isValidPhoneId(phoneId)) return; 1288 Message msg = obtainMessage(EVENT_RADIO_CAPABILITY_CHANGED); 1289 msg.arg1 = phoneId; 1290 msg.sendToTarget(); 1291 } 1292 1293 /** 1294 * Switch the Default data for the context of an outgoing emergency call. 1295 * <p> 1296 * In some cases, we need to try to switch the Default Data subscription before placing the 1297 * emergency call on DSDS devices. This includes the following situation: 1298 * - The modem does not support processing GNSS SUPL requests on the non-default data 1299 * subscription. For some carriers that do not provide a control plane fallback mechanism, the 1300 * SUPL request will be dropped and we will not be able to get the user's location for the 1301 * emergency call. In this case, we need to swap default data temporarily. 1302 * @param phoneId The phone to use to evaluate whether or not the default data should be moved 1303 * to this subscription. 1304 * @param overrideTimeSec The amount of time to override the default data setting for after the 1305 * emergency call ends. 1306 * @param dataSwitchResult A {@link CompletableFuture} to be called with a {@link Boolean} 1307 * result when the default data switch has either completed (true) or 1308 * failed (false). 1309 */ overrideDefaultDataForEmergency(int phoneId, int overrideTimeSec, CompletableFuture<Boolean> dataSwitchResult)1310 public void overrideDefaultDataForEmergency(int phoneId, int overrideTimeSec, 1311 CompletableFuture<Boolean> dataSwitchResult) { 1312 if (!SubscriptionManager.isValidPhoneId(phoneId)) return; 1313 Message msg = obtainMessage(EVENT_OVERRIDE_DDS_FOR_EMERGENCY); 1314 EmergencyOverrideRequest request = new EmergencyOverrideRequest(); 1315 request.mPhoneId = phoneId; 1316 request.mGnssOverrideTimeMs = overrideTimeSec * 1000; 1317 request.mOverrideCompleteFuture = dataSwitchResult; 1318 msg.obj = request; 1319 msg.sendToTarget(); 1320 } 1321 sendRilCommands(int phoneId)1322 protected void sendRilCommands(int phoneId) { 1323 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 1324 logl("sendRilCommands: skip dds switch due to invalid phoneId=" + phoneId); 1325 return; 1326 } 1327 1328 Message message = Message.obtain(this, EVENT_MODEM_COMMAND_DONE, phoneId); 1329 if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) { 1330 // Skip ALLOW_DATA for single SIM device 1331 if (mActiveModemCount > 1) { 1332 PhoneFactory.getPhone(phoneId).mCi.setDataAllowed(isPhoneActive(phoneId), message); 1333 } 1334 } else if (phoneId == mPreferredDataPhoneId) { 1335 // Only setPreferredDataModem if the phoneId equals to current mPreferredDataPhoneId 1336 logl("sendRilCommands: setPreferredDataModem - phoneId: " + phoneId); 1337 mRadioConfig.setPreferredDataModem(mPreferredDataPhoneId, message); 1338 } 1339 } 1340 phoneIdForRequest(TelephonyNetworkRequest networkRequest)1341 private int phoneIdForRequest(TelephonyNetworkRequest networkRequest) { 1342 NetworkRequest netRequest = networkRequest.getNativeNetworkRequest(); 1343 int subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier()); 1344 1345 if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId; 1346 if (subId == INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX; 1347 1348 int preferredDataSubId = (mPreferredDataPhoneId >= 0 1349 && mPreferredDataPhoneId < mActiveModemCount) 1350 ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID; 1351 1352 // Currently we assume multi-SIM devices will only support one Internet PDN connection. So 1353 // if Internet PDN is established on the non-preferred phone, it will interrupt 1354 // Internet connection on the preferred phone. So we only accept Internet request with 1355 // preferred data subscription or no specified subscription. 1356 // One exception is, if it's restricted request (doesn't have NET_CAPABILITY_NOT_RESTRICTED) 1357 // it will be accepted, which is used temporary data usage from system. 1358 if (netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 1359 && netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 1360 && subId != preferredDataSubId && subId != mValidator.getSubIdInValidation()) { 1361 // Returning INVALID_PHONE_INDEX will result in netRequest not being handled. 1362 return INVALID_PHONE_INDEX; 1363 } 1364 1365 // Try to find matching phone ID. If it doesn't exist, we'll end up returning INVALID. 1366 int phoneId = INVALID_PHONE_INDEX; 1367 for (int i = 0; i < mActiveModemCount; i++) { 1368 if (mPhoneSubscriptions[i] == subId) { 1369 phoneId = i; 1370 break; 1371 } 1372 } 1373 return phoneId; 1374 } 1375 getSubIdFromNetworkSpecifier(NetworkSpecifier specifier)1376 protected int getSubIdFromNetworkSpecifier(NetworkSpecifier specifier) { 1377 if (specifier == null) { 1378 return DEFAULT_SUBSCRIPTION_ID; 1379 } 1380 if (specifier instanceof TelephonyNetworkSpecifier) { 1381 return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); 1382 } 1383 return INVALID_SUBSCRIPTION_ID; 1384 } 1385 isActiveSubId(int subId)1386 private boolean isActiveSubId(int subId) { 1387 SubscriptionInfoInternal subInfo = mSubscriptionManagerService 1388 .getSubscriptionInfoInternal(subId); 1389 return subInfo != null && subInfo.isActive(); 1390 } 1391 1392 // This updates mPreferredDataPhoneId which decides which phone should handle default network 1393 // requests. updatePreferredDataPhoneId()1394 protected void updatePreferredDataPhoneId() { 1395 if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { 1396 // Override DDS for emergency even if user data is not enabled, since it is an 1397 // emergency. 1398 // TODO: Provide a notification to the user that metered data is currently being 1399 // used during this period. 1400 logl("updatePreferredDataPhoneId: preferred data overridden for emergency." 1401 + " phoneId = " + mEmergencyOverride.mPhoneId); 1402 mPreferredDataPhoneId = mEmergencyOverride.mPhoneId; 1403 mLastSwitchPreferredDataReason = DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN; 1404 } else { 1405 if (isAnyVoiceCallActiveOnDevice()) { 1406 int imsRegTech = mImsRegTechProvider.get(mContext, mPhoneIdInVoiceCall); 1407 if (imsRegTech != REGISTRATION_TECH_IWLAN) { 1408 if (imsRegTech != REGISTRATION_TECH_CROSS_SIM) { 1409 mPreferredDataPhoneId = shouldSwitchDataDueToInCall() 1410 ? mPhoneIdInVoiceCall : getFallbackDataPhoneIdForInternetRequests(); 1411 } else { 1412 logl("IMS call on cross-SIM, skip switching data to phone " 1413 + mPhoneIdInVoiceCall); 1414 } 1415 } else { 1416 mPreferredDataPhoneId = getFallbackDataPhoneIdForInternetRequests(); 1417 } 1418 } else { 1419 mPreferredDataPhoneId = getFallbackDataPhoneIdForInternetRequests(); 1420 } 1421 } 1422 1423 mPreferredDataSubId.set(SubscriptionManager.getSubscriptionId(mPreferredDataPhoneId)); 1424 } 1425 1426 /** 1427 * @return the default data phone Id (or auto selected phone Id in auto data switch/CBRS case) 1428 */ getFallbackDataPhoneIdForInternetRequests()1429 private int getFallbackDataPhoneIdForInternetRequests() { 1430 int fallbackSubId = isActiveSubId(mAutoSelectedDataSubId) 1431 ? mAutoSelectedDataSubId : mPrimaryDataSubId; 1432 1433 if (SubscriptionManager.isUsableSubIdValue(fallbackSubId)) { 1434 for (int phoneId = 0; phoneId < mActiveModemCount; phoneId++) { 1435 if (mPhoneSubscriptions[phoneId] == fallbackSubId) { 1436 return phoneId; 1437 } 1438 } 1439 } 1440 return SubscriptionManager.INVALID_PHONE_INDEX; 1441 } 1442 1443 /** 1444 * If a phone is in call and user enabled its mobile data and auto data switch feature, we 1445 * should switch internet connection to it because the other modem will lose data connection 1446 * anyway. 1447 * @return {@code true} if should switch data to the phone in voice call 1448 */ shouldSwitchDataDueToInCall()1449 private boolean shouldSwitchDataDueToInCall() { 1450 Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); 1451 Phone defaultDataPhone = getPhoneBySubId(mPrimaryDataSubId); 1452 return defaultDataPhone != null // check user enabled data 1453 && defaultDataPhone.isUserDataEnabled() 1454 && voicePhone != null // check user enabled voice during call feature 1455 && voicePhone.getDataSettingsManager().isDataEnabled(); 1456 } 1457 transitionToEmergencyPhone()1458 protected void transitionToEmergencyPhone() { 1459 if (mActiveModemCount <= 0) { 1460 logl("No phones: unable to reset preferred phone for emergency"); 1461 return; 1462 } 1463 1464 if (mPreferredDataPhoneId != DEFAULT_EMERGENCY_PHONE_ID) { 1465 logl("No active subscriptions: resetting preferred phone to 0 for emergency"); 1466 mPreferredDataPhoneId = DEFAULT_EMERGENCY_PHONE_ID; 1467 } 1468 1469 if (mPreferredDataSubId.get() != INVALID_SUBSCRIPTION_ID) { 1470 mPreferredDataSubId.set(INVALID_SUBSCRIPTION_ID); 1471 notifyPreferredDataSubIdChanged(); 1472 } 1473 } 1474 getPhoneBySubId(int subId)1475 private Phone getPhoneBySubId(int subId) { 1476 return findPhoneById(mSubscriptionManagerService.getPhoneId(subId)); 1477 } 1478 findPhoneById(final int phoneId)1479 private Phone findPhoneById(final int phoneId) { 1480 if (!SubscriptionManager.isValidPhoneId(phoneId)) { 1481 return null; 1482 } 1483 return PhoneFactory.getPhone(phoneId); 1484 } 1485 shouldApplyNetworkRequest( TelephonyNetworkRequest networkRequest, int phoneId)1486 public synchronized boolean shouldApplyNetworkRequest( 1487 TelephonyNetworkRequest networkRequest, int phoneId) { 1488 if (!SubscriptionManager.isValidPhoneId(phoneId)) return false; 1489 1490 int subId = SubscriptionManager.getSubscriptionId(phoneId); 1491 1492 // In any case, if phone state is inactive, don't apply the network request. 1493 if (!isPhoneActive(phoneId) || (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID 1494 && !isEmergencyNetworkRequest(networkRequest))) { 1495 return false; 1496 } 1497 1498 NetworkRequest netRequest = networkRequest.getNativeNetworkRequest(); 1499 subId = getSubIdFromNetworkSpecifier(netRequest.getNetworkSpecifier()); 1500 1501 //if this phone is an emergency networkRequest 1502 //and subId is not specified that is invalid or default 1503 if (isAnyVoiceCallActiveOnDevice() && isEmergencyNetworkRequest(networkRequest) 1504 && (subId == DEFAULT_SUBSCRIPTION_ID || subId == INVALID_SUBSCRIPTION_ID)) { 1505 return phoneId == mPhoneIdInVoiceCall; 1506 } 1507 1508 int phoneIdToHandle = phoneIdForRequest(networkRequest); 1509 return phoneId == phoneIdToHandle; 1510 } 1511 isEmergencyNetworkRequest(TelephonyNetworkRequest networkRequest)1512 boolean isEmergencyNetworkRequest(TelephonyNetworkRequest networkRequest) { 1513 return networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); 1514 } 1515 1516 @VisibleForTesting isPhoneActive(int phoneId)1517 protected boolean isPhoneActive(int phoneId) { 1518 if (phoneId >= mActiveModemCount) 1519 return false; 1520 return mPhoneStates[phoneId].active; 1521 } 1522 1523 /** 1524 * Set opportunistic data subscription. It's an indication to switch Internet data to this 1525 * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate 1526 * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting 1527 * opportunistic data sub and switch data back to primary sub. 1528 * 1529 * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID 1530 * if un-setting it. 1531 * @param needValidation whether Telephony will wait until the network is validated by 1532 * connectivity service before switching data to it. More details see 1533 * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. 1534 * @param callback Callback will be triggered once it succeeds or failed. 1535 * Pass null if don't care about the result. 1536 */ setOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback)1537 private void setOpportunisticDataSubscription(int subId, boolean needValidation, 1538 ISetOpportunisticDataCallback callback) { 1539 validate(subId, needValidation, 1540 DataSwitch.Reason.DATA_SWITCH_REASON_CBRS, callback); 1541 } 1542 1543 /** 1544 * Try setup a new internet connection on the subId that's pending validation. If the validation 1545 * succeeds, this subId will be evaluated for being the preferred data subId; If fails, nothing 1546 * happens. 1547 * Callback will be updated with the validation result. 1548 * 1549 * @param subId Sub Id that's pending switch, awaiting validation. 1550 * @param needValidation {@code false} if switch to the subId even if validation fails. 1551 * @param switchReason The switch reason for this validation 1552 * @param callback Optional - specific for external opportunistic sub validation request. 1553 */ validate(int subId, boolean needValidation, int switchReason, @Nullable ISetOpportunisticDataCallback callback)1554 private void validate(int subId, boolean needValidation, int switchReason, 1555 @Nullable ISetOpportunisticDataCallback callback) { 1556 int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) 1557 ? mPrimaryDataSubId : subId; 1558 logl("Validate subId " + subId + " due to " + switchReasonToString(switchReason) 1559 + " needValidation=" + needValidation + " subIdToValidate=" + subIdToValidate 1560 + " mAutoSelectedDataSubId=" + mAutoSelectedDataSubId 1561 + " mPreferredDataSubId=" + mPreferredDataSubId.get()); 1562 if (!isActiveSubId(subIdToValidate)) { 1563 logl("Can't switch data to inactive subId " + subIdToValidate); 1564 if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 1565 // the default data sub is not selected yet, store the intent of switching to 1566 // default subId once it becomes available. 1567 mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 1568 sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); 1569 } else { 1570 sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); 1571 } 1572 return; 1573 } 1574 1575 if (mValidator.isValidating()) { 1576 mValidator.stopValidation(); 1577 sendSetOpptCallbackHelper(mSetOpptSubCallback, SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED); 1578 mSetOpptSubCallback = null; 1579 } 1580 1581 // Remove EVENT_NETWORK_VALIDATION_DONE. Don't handle validation result of previous subId 1582 // if queued. 1583 removeMessages(EVENT_NETWORK_VALIDATION_DONE); 1584 removeMessages(EVENT_NETWORK_AVAILABLE); 1585 1586 mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; 1587 1588 if (subIdToValidate == mPreferredDataSubId.get()) { 1589 if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 1590 mAutoSelectedDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 1591 } 1592 sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); 1593 return; 1594 } 1595 1596 mLastSwitchPreferredDataReason = switchReason; 1597 logDataSwitchEvent(subIdToValidate, 1598 TelephonyEvent.EventState.EVENT_STATE_START, 1599 switchReason); 1600 registerDefaultNetworkChangeCallback(subIdToValidate, 1601 switchReason); 1602 1603 // If validation feature is not supported, set it directly. Otherwise, 1604 // start validation on the subscription first. 1605 if (!mValidator.isValidationFeatureSupported()) { 1606 setAutoSelectedDataSubIdInternal(subId); 1607 sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); 1608 return; 1609 } 1610 1611 // Even if needValidation is false, we still send request to validator. The reason is we 1612 // want to delay data switch until network is available on the target sub, to have a 1613 // smoothest transition possible. 1614 // In this case, even if data connection eventually failed in 2 seconds, we still 1615 // confirm the switch, to maximally respect the request. 1616 mPendingSwitchSubId = subIdToValidate; 1617 mPendingSwitchNeedValidation = needValidation; 1618 mSetOpptSubCallback = callback; 1619 long validationTimeout = getValidationTimeout(subIdToValidate, needValidation); 1620 mValidator.validate(subIdToValidate, validationTimeout, 1621 mPendingSwitchNeedValidation, mValidationCallback); 1622 } 1623 getValidationTimeout(int subId, boolean needValidation)1624 private long getValidationTimeout(int subId, boolean needValidation) { 1625 if (!needValidation) return DEFAULT_VALIDATION_EXPIRATION_TIME; 1626 1627 long validationTimeout = DEFAULT_VALIDATION_EXPIRATION_TIME; 1628 CarrierConfigManager configManager = (CarrierConfigManager) 1629 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 1630 if (configManager != null) { 1631 PersistableBundle b = configManager.getConfigForSubId(subId); 1632 if (b != null) { 1633 validationTimeout = b.getLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG); 1634 } 1635 } 1636 return validationTimeout; 1637 } 1638 sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result)1639 private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) { 1640 if (callback == null) return; 1641 try { 1642 callback.onComplete(result); 1643 } catch (RemoteException exception) { 1644 logl("RemoteException " + exception); 1645 } 1646 } 1647 1648 /** 1649 * Evaluate whether the specified sub Id can be set to be the preferred data sub Id. 1650 * 1651 * @param subId The subId that we tried to validate: could possibly be unvalidated if validation 1652 * feature is not supported. 1653 */ setAutoSelectedDataSubIdInternal(int subId)1654 private void setAutoSelectedDataSubIdInternal(int subId) { 1655 if (mAutoSelectedDataSubId != subId) { 1656 mAutoSelectedDataSubId = subId; 1657 onEvaluate(REQUESTS_UNCHANGED, switchReasonToString(mLastSwitchPreferredDataReason)); 1658 } 1659 } 1660 confirmSwitch(int subId, boolean confirm)1661 private void confirmSwitch(int subId, boolean confirm) { 1662 logl("confirmSwitch: subId " + subId + (confirm ? " confirmed." : " cancelled.")); 1663 int resultForCallBack; 1664 if (!isActiveSubId(subId)) { 1665 logl("confirmSwitch: subId " + subId + " is no longer active"); 1666 resultForCallBack = SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; 1667 } else if (!confirm) { 1668 resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; 1669 1670 // retry for auto data switch validation failure 1671 if (mLastSwitchPreferredDataReason == DataSwitch.Reason.DATA_SWITCH_REASON_AUTO) { 1672 mAutoDataSwitchController.evaluateRetryOnValidationFailed(); 1673 } 1674 } else { 1675 if (subId == mPrimaryDataSubId) { 1676 setAutoSelectedDataSubIdInternal(DEFAULT_SUBSCRIPTION_ID); 1677 } else { 1678 setAutoSelectedDataSubIdInternal(subId); 1679 } 1680 resultForCallBack = SET_OPPORTUNISTIC_SUB_SUCCESS; 1681 mAutoDataSwitchController.resetFailedCount(); 1682 } 1683 1684 // Trigger callback if needed 1685 sendSetOpptCallbackHelper(mSetOpptSubCallback, resultForCallBack); 1686 mSetOpptSubCallback = null; 1687 mPendingSwitchSubId = INVALID_SUBSCRIPTION_ID; 1688 } 1689 onNetworkAvailable(int subId, Network network)1690 private void onNetworkAvailable(int subId, Network network) { 1691 log("onNetworkAvailable: on subId " + subId); 1692 // Do nothing unless pending switch matches target subId and it doesn't require 1693 // validation pass. 1694 if (mPendingSwitchSubId == INVALID_SUBSCRIPTION_ID || mPendingSwitchSubId != subId 1695 || mPendingSwitchNeedValidation) { 1696 return; 1697 } 1698 confirmSwitch(subId, true); 1699 } 1700 onValidationDone(int subId, boolean passed)1701 private void onValidationDone(int subId, boolean passed) { 1702 logl("onValidationDone: " + (passed ? "passed" : "failed") + " on subId " + subId); 1703 if (mPendingSwitchSubId == INVALID_SUBSCRIPTION_ID || mPendingSwitchSubId != subId) return; 1704 1705 // If validation failed and mPendingSwitch.mNeedValidation is false, we still confirm 1706 // the switch. 1707 confirmSwitch(subId, passed || !mPendingSwitchNeedValidation); 1708 } 1709 1710 /** 1711 * Notify PhoneSwitcher to try to switch data to an opportunistic subscription. 1712 * <p> 1713 * Set opportunistic data subscription. It's an indication to switch Internet data to this 1714 * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate 1715 * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting 1716 * opportunistic data sub and switch data back to primary sub. 1717 * 1718 * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID 1719 * if un-setting it. 1720 * @param needValidation whether Telephony will wait until the network is validated by 1721 * connectivity service before switching data to it. More details see 1722 * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. 1723 * @param callback Callback will be triggered once it succeeds or failed. 1724 * Pass null if don't care about the result. 1725 */ trySetOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback)1726 public void trySetOpportunisticDataSubscription(int subId, boolean needValidation, 1727 ISetOpportunisticDataCallback callback) { 1728 logl("Try set opportunistic data subscription to subId " + subId 1729 + (needValidation ? " with " : " without ") + "validation"); 1730 PhoneSwitcher.this.obtainMessage(EVENT_OPPT_DATA_SUB_CHANGED, 1731 subId, needValidation ? 1 : 0, callback).sendToTarget(); 1732 } 1733 isPhoneInVoiceCall(Phone phone)1734 protected boolean isPhoneInVoiceCall(Phone phone) { 1735 if (phone == null) { 1736 return false; 1737 } 1738 Call bgCall = phone.getBackgroundCall(); 1739 Call fgCall = phone.getForegroundCall(); 1740 if (bgCall == null || fgCall == null) { 1741 return false; 1742 } 1743 // A phone in voice call might trigger data being switched to it. 1744 // Exclude dialing to give modem time to process an EMC first before dealing with DDS switch 1745 // Include alerting because modem RLF leads to delay in switch, so carrier required to 1746 // switch in alerting phase. 1747 // TODO: check ringing call for vDADA 1748 return (!bgCall.isIdle() && bgCall.getState() != Call.State.DIALING) 1749 || (!fgCall.isIdle() && fgCall.getState() != Call.State.DIALING); 1750 } 1751 updateHalCommandToUse()1752 private void updateHalCommandToUse() { 1753 mHalCommandToUse = mRadioConfig.isSetPreferredDataCommandSupported() 1754 ? HAL_COMMAND_PREFERRED_DATA : HAL_COMMAND_ALLOW_DATA; 1755 } 1756 getPreferredDataPhoneId()1757 public int getPreferredDataPhoneId() { 1758 return mPreferredDataPhoneId; 1759 } 1760 1761 /** 1762 * Log debug messages and also log into the local log. 1763 * @param l debug messages 1764 */ logl(String l)1765 protected void logl(String l) { 1766 log(l); 1767 mLocalLog.log(l); 1768 } 1769 1770 /** 1771 * Log debug messages. 1772 * @param s debug messages 1773 */ log(@onNull String s)1774 private void log(@NonNull String s) { 1775 Rlog.d(LOG_TAG, s); 1776 } 1777 1778 /** 1779 * Log debug error messages. 1780 * @param s debug messages 1781 */ loge(@onNull String s)1782 private void loge(@NonNull String s) { 1783 Rlog.e(LOG_TAG, s); 1784 } 1785 1786 1787 /** 1788 * Convert data switch reason into string. 1789 * 1790 * @param reason The switch reason. 1791 * @return The switch reason in string format. 1792 */ 1793 @NonNull switchReasonToString(int reason)1794 private static String switchReasonToString(int reason) { 1795 return switch (reason) { 1796 case DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN -> "UNKNOWN"; 1797 case DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL -> "MANUAL"; 1798 case DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL -> "IN_CALL"; 1799 case DataSwitch.Reason.DATA_SWITCH_REASON_CBRS -> "CBRS"; 1800 case DataSwitch.Reason.DATA_SWITCH_REASON_AUTO -> "AUTO"; 1801 default -> "UNKNOWN(" + reason + ")"; 1802 }; 1803 } 1804 1805 /** 1806 * Concert switching state to string 1807 * 1808 * @param state The switching state. 1809 * @return The switching state in string format. 1810 */ 1811 @NonNull switchStateToString(int state)1812 private static String switchStateToString(int state) { 1813 return switch (state) { 1814 case TelephonyEvent.EventState.EVENT_STATE_UNKNOWN -> "UNKNOWN"; 1815 case TelephonyEvent.EventState.EVENT_STATE_START -> "START"; 1816 case TelephonyEvent.EventState.EVENT_STATE_END -> "END"; 1817 default -> "UNKNOWN(" + state + ")"; 1818 }; 1819 } 1820 1821 /** 1822 * Log data switch event 1823 * 1824 * @param subId Subscription index. 1825 * @param state The switching state. 1826 * @param reason The switching reason. 1827 */ 1828 private void logDataSwitchEvent(int subId, int state, int reason) { 1829 logl("Data switch state=" + switchStateToString(state) + " due to reason=" 1830 + switchReasonToString(reason) + " on subId " + subId); 1831 DataSwitch dataSwitch = new DataSwitch(); 1832 dataSwitch.state = state; 1833 dataSwitch.reason = reason; 1834 TelephonyMetrics.getInstance().writeDataSwitch(subId, dataSwitch); 1835 } 1836 1837 /** 1838 * See {@link PhoneStateListener#LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE}. 1839 */ 1840 protected void notifyPreferredDataSubIdChanged() { 1841 TelephonyRegistryManager telephonyRegistryManager = (TelephonyRegistryManager) mContext 1842 .getSystemService(Context.TELEPHONY_REGISTRY_SERVICE); 1843 logl("notifyPreferredDataSubIdChanged to " + mPreferredDataSubId.get()); 1844 telephonyRegistryManager.notifyActiveDataSubIdChanged(mPreferredDataSubId.get()); 1845 } 1846 1847 /** 1848 * @return The active data subscription id 1849 */ 1850 public int getActiveDataSubId() { 1851 return mPreferredDataSubId.get(); 1852 } 1853 1854 /** 1855 * @return The auto selected data subscription id. 1856 */ 1857 public int getAutoSelectedDataSubId() { 1858 return mAutoSelectedDataSubId; 1859 } 1860 1861 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1862 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1863 pw.println("PhoneSwitcher:"); 1864 pw.increaseIndent(); 1865 Calendar c = Calendar.getInstance(); 1866 for (int i = 0; i < mActiveModemCount; i++) { 1867 PhoneState ps = mPhoneStates[i]; 1868 c.setTimeInMillis(ps.lastRequested); 1869 pw.println("PhoneId(" + i + ") active=" + ps.active 1870 + ", lastRequest=" 1871 + (ps.lastRequested == 0 ? "never" : 1872 String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c))); 1873 } 1874 pw.println("mPreferredDataPhoneId=" + mPreferredDataPhoneId); 1875 pw.println("mPreferredDataSubId=" + mPreferredDataSubId.get()); 1876 pw.println("DefaultDataSubId=" + mSubscriptionManagerService.getDefaultDataSubId()); 1877 pw.println("DefaultDataPhoneId=" + mSubscriptionManagerService.getPhoneId( 1878 mSubscriptionManagerService.getDefaultDataSubId())); 1879 pw.println("mPrimaryDataSubId=" + mPrimaryDataSubId); 1880 pw.println("mAutoSelectedDataSubId=" + mAutoSelectedDataSubId); 1881 pw.println("mIsRegisteredForImsRadioTechChange=" + mIsRegisteredForImsRadioTechChange); 1882 pw.println("mPendingSwitchNeedValidation=" + mPendingSwitchNeedValidation); 1883 pw.println("mMaxDataAttachModemCount=" + mMaxDataAttachModemCount); 1884 pw.println("mActiveModemCount=" + mActiveModemCount); 1885 pw.println("mPhoneIdInVoiceCall=" + mPhoneIdInVoiceCall); 1886 pw.println("mCurrentDdsSwitchFailure=" + mCurrentDdsSwitchFailure); 1887 pw.println("mLastSwitchPreferredDataReason=" 1888 + switchReasonToString(mLastSwitchPreferredDataReason)); 1889 pw.println("Local logs:"); 1890 pw.increaseIndent(); 1891 mLocalLog.dump(fd, pw, args); 1892 pw.decreaseIndent(); 1893 mAutoDataSwitchController.dump(fd, pw, args); 1894 pw.decreaseIndent(); 1895 } 1896 1897 private boolean isAnyVoiceCallActiveOnDevice() { 1898 boolean ret = mPhoneIdInVoiceCall != SubscriptionManager.INVALID_PHONE_INDEX; 1899 if (VDBG) log("isAnyVoiceCallActiveOnDevice: " + ret); 1900 return ret; 1901 } 1902 1903 private void onDdsSwitchResponse(AsyncResult ar) { 1904 boolean commandSuccess = ar != null && ar.exception == null; 1905 int phoneId = (int) ar.userObj; 1906 if (mEmergencyOverride != null) { 1907 logl("Emergency override result sent = " + commandSuccess); 1908 mEmergencyOverride.sendOverrideCompleteCallbackResultAndClear(commandSuccess); 1909 // Do not retry , as we do not allow changes in onEvaluate during an emergency 1910 // call. When the call ends, we will start the countdown to remove the override. 1911 } else if (!commandSuccess) { 1912 logl("onDdsSwitchResponse: DDS switch failed. with exception " + ar.exception); 1913 if (ar.exception instanceof CommandException) { 1914 CommandException.Error error = ((CommandException) 1915 (ar.exception)).getCommandError(); 1916 mCurrentDdsSwitchFailure.get(phoneId).add(error); 1917 if (error == CommandException.Error.OP_NOT_ALLOWED_DURING_VOICE_CALL) { 1918 logl("onDdsSwitchResponse: Wait for call end indication"); 1919 return; 1920 } else if (error == CommandException.Error.INVALID_SIM_STATE) { 1921 /* If there is a attach failure due to sim not ready then 1922 hold the retry until sim gets ready */ 1923 logl("onDdsSwitchResponse: Wait for SIM to get READY"); 1924 return; 1925 } 1926 } 1927 logl("onDdsSwitchResponse: Scheduling DDS switch retry"); 1928 sendMessageDelayed(Message.obtain(this, EVENT_MODEM_COMMAND_RETRY, 1929 phoneId), MODEM_COMMAND_RETRY_PERIOD_MS); 1930 return; 1931 } 1932 if (commandSuccess) { 1933 logl("onDdsSwitchResponse: DDS switch success on phoneId = " + phoneId); 1934 mAutoDataSwitchController.displayAutoDataSwitchNotification(phoneId, 1935 mLastSwitchPreferredDataReason == DataSwitch.Reason.DATA_SWITCH_REASON_AUTO); 1936 } 1937 mCurrentDdsSwitchFailure.get(phoneId).clear(); 1938 // Notify all registrants 1939 mActivePhoneRegistrants.notifyRegistrants(); 1940 notifyPreferredDataSubIdChanged(); 1941 mPhoneSwitcherCallbacks.forEach(callback -> callback.invokeFromExecutor( 1942 () -> callback.onPreferredDataPhoneIdChanged(phoneId))); 1943 } 1944 1945 private boolean isPhoneIdValidForRetry(int phoneId) { 1946 int ddsPhoneId = mSubscriptionManagerService.getPhoneId( 1947 mSubscriptionManagerService.getDefaultDataSubId()); 1948 if (ddsPhoneId != INVALID_PHONE_INDEX && ddsPhoneId == phoneId) { 1949 return true; 1950 } else { 1951 if (mNetworkRequestList.isEmpty()) return false; 1952 for (TelephonyNetworkRequest networkRequest : mNetworkRequestList) { 1953 if (phoneIdForRequest(networkRequest) == phoneId) { 1954 return true; 1955 } 1956 } 1957 } 1958 return false; 1959 } 1960 } 1961