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