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.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 21 import static android.telephony.SubscriptionManager.INVALID_PHONE_INDEX; 22 import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; 23 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; 24 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_SUCCESS; 25 import static android.telephony.TelephonyManager.SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; 26 27 import android.annotation.UnsupportedAppUsage; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.net.ConnectivityManager; 33 import android.net.ConnectivityManager.NetworkCallback; 34 import android.net.MatchAllNetworkSpecifier; 35 import android.net.Network; 36 import android.net.NetworkCapabilities; 37 import android.net.NetworkFactory; 38 import android.net.NetworkRequest; 39 import android.net.NetworkSpecifier; 40 import android.net.StringNetworkSpecifier; 41 import android.os.AsyncResult; 42 import android.os.Handler; 43 import android.os.Looper; 44 import android.os.Message; 45 import android.os.Registrant; 46 import android.os.RegistrantList; 47 import android.os.RemoteException; 48 import android.os.ServiceManager; 49 import android.telephony.PhoneCapability; 50 import android.telephony.PhoneStateListener; 51 import android.telephony.Rlog; 52 import android.telephony.SubscriptionManager; 53 import android.telephony.TelephonyManager; 54 import android.telephony.data.ApnSetting; 55 import android.util.LocalLog; 56 57 import com.android.internal.annotations.VisibleForTesting; 58 import com.android.internal.telephony.dataconnection.DcRequest; 59 import com.android.internal.telephony.metrics.TelephonyMetrics; 60 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent; 61 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.DataSwitch; 62 import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.OnDemandDataSwitch; 63 import com.android.internal.util.IndentingPrintWriter; 64 65 import java.io.FileDescriptor; 66 import java.io.PrintWriter; 67 import java.util.ArrayList; 68 import java.util.Calendar; 69 import java.util.Collections; 70 import java.util.List; 71 import java.util.concurrent.CompletableFuture; 72 73 /** 74 * Utility singleton to monitor subscription changes and incoming NetworkRequests 75 * and determine which phone/phones are active. 76 * 77 * Manages the ALLOW_DATA calls to modems and notifies phones about changes to 78 * the active phones. Note we don't wait for data attach (which may not happen anyway). 79 */ 80 public class PhoneSwitcher extends Handler { 81 private static final String LOG_TAG = "PhoneSwitcher"; 82 private static final boolean VDBG = false; 83 84 private static final int DEFAULT_NETWORK_CHANGE_TIMEOUT_MS = 5000; 85 private static final int MODEM_COMMAND_RETRY_PERIOD_MS = 5000; 86 // After the emergency call ends, wait for a few seconds to see if we enter ECBM before starting 87 // the countdown to remove the emergency DDS override. 88 @VisibleForTesting 89 // not final for testing. 90 public static int ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS = 5000; 91 // Wait for a few seconds after the override request comes in to receive the outgoing call 92 // event. If it does not happen before the timeout specified, cancel the override. 93 @VisibleForTesting 94 public static int DEFAULT_DATA_OVERRIDE_TIMEOUT_MS = 5000; 95 96 // If there are no subscriptions in a device, then the phone to be used for emergency should 97 // always be the "first" phone. 98 private static final int DEFAULT_EMERGENCY_PHONE_ID = 0; 99 100 /** 101 * Container for an ongoing request to override the DDS in the context of an ongoing emergency 102 * call to allow for carrier specific operations, such as provide SUPL updates during or after 103 * the emergency call, since some modems do not support these operations on the non DDS. 104 */ 105 private static final class EmergencyOverrideRequest { 106 /* The Phone ID that the DDS should be set to. */ 107 int mPhoneId = INVALID_PHONE_INDEX; 108 /* The time after the emergency call ends that the DDS should be overridden for. */ 109 int mGnssOverrideTimeMs = -1; 110 /* A callback to the requester notifying them if the initial call to the modem to override 111 * the DDS was successful. 112 */ 113 CompletableFuture<Boolean> mOverrideCompleteFuture; 114 /* In the special case that the device goes into emergency callback mode after the emergency 115 * call ends, keep the override until ECM finishes and then start the mGnssOverrideTimeMs 116 * timer to leave DDS override. 117 */ 118 boolean mRequiresEcmFinish = false; 119 120 /* 121 * Keeps track of whether or not this request has already serviced the outgoing emergency 122 * call. Once finished, do not delay for any other calls. 123 */ 124 boolean mPendingOriginatingCall = true; 125 126 /** 127 * @return true if there is a pending override complete callback. 128 */ isCallbackAvailable()129 boolean isCallbackAvailable() { 130 return mOverrideCompleteFuture != null; 131 } 132 133 /** 134 * Send the override complete callback the result of setting the DDS to the new value. 135 */ sendOverrideCompleteCallbackResultAndClear(boolean result)136 void sendOverrideCompleteCallbackResultAndClear(boolean result) { 137 if (isCallbackAvailable()) { 138 mOverrideCompleteFuture.complete(result); 139 mOverrideCompleteFuture = null; 140 } 141 } 142 143 144 @Override toString()145 public String toString() { 146 return String.format("EmergencyOverrideRequest: [phoneId= %d, overrideMs= %d," 147 + " hasCallback= %b, ecmFinishStatus= %b]", mPhoneId, mGnssOverrideTimeMs, 148 isCallbackAvailable(), mRequiresEcmFinish); 149 } 150 } 151 152 private final List<DcRequest> mPrioritizedDcRequests = new ArrayList<DcRequest>(); 153 private final RegistrantList mActivePhoneRegistrants; 154 private final SubscriptionController mSubscriptionController; 155 private final int[] mPhoneSubscriptions; 156 private final CommandsInterface[] mCommandsInterfaces; 157 private final Context mContext; 158 private final PhoneState[] mPhoneStates; 159 @UnsupportedAppUsage 160 private final int mNumPhones; 161 @UnsupportedAppUsage 162 private final Phone[] mPhones; 163 private final LocalLog mLocalLog; 164 @VisibleForTesting 165 public final PhoneStateListener mPhoneStateListener; 166 private final CellularNetworkValidator mValidator; 167 @VisibleForTesting 168 public final CellularNetworkValidator.ValidationCallback mValidationCallback = 169 (validated, subId) -> Message.obtain(PhoneSwitcher.this, 170 EVENT_NETWORK_VALIDATION_DONE, subId, validated ? 1 : 0).sendToTarget(); 171 @UnsupportedAppUsage 172 private int mMaxActivePhones; 173 private static PhoneSwitcher sPhoneSwitcher = null; 174 175 // Which primary (non-opportunistic) subscription is set as data subscription among all primary 176 // subscriptions. This value usually comes from user setting, and it's the subscription used for 177 // Internet data if mOpptDataSubId is not set. 178 private int mPrimaryDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 179 180 // mOpptDataSubId must be an active subscription. If it's set, it overrides mPrimaryDataSubId 181 // to be used for Internet data. 182 private int mOpptDataSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; 183 184 // The phone ID that has an active voice call. If set, and its mobile data setting is on, 185 // it will become the mPreferredDataPhoneId. 186 private int mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; 187 188 @VisibleForTesting 189 // It decides: 190 // 1. In modem layer, which modem is DDS (preferred to have data traffic on) 191 // 2. In TelephonyNetworkFactory, which subscription will apply default network requests, which 192 // are requests without specifying a subId. 193 // Corresponding phoneId after considering mOpptDataSubId, mPrimaryDataSubId and 194 // mPhoneIdInVoiceCall above. 195 protected int mPreferredDataPhoneId = SubscriptionManager.INVALID_PHONE_INDEX; 196 197 // Subscription ID corresponds to mPreferredDataPhoneId. 198 private int mPreferredDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; 199 200 // If non-null, An emergency call is about to be started, is ongoing, or has just ended and we 201 // are overriding the DDS. 202 // Internal state, should ONLY be accessed/modified inside of the handler. 203 private EmergencyOverrideRequest mEmergencyOverride; 204 205 private ISetOpportunisticDataCallback mSetOpptSubCallback; 206 207 private static final int EVENT_PRIMARY_DATA_SUB_CHANGED = 101; 208 private static final int EVENT_SUBSCRIPTION_CHANGED = 102; 209 private static final int EVENT_REQUEST_NETWORK = 103; 210 private static final int EVENT_RELEASE_NETWORK = 104; 211 // ECBM has started/ended. If we just ended an emergency call and mEmergencyOverride is not 212 // null, we will wait for EVENT_EMERGENCY_TOGGLE again with ECBM ending to send the message 213 // EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE to remove the override after the mEmergencyOverride 214 // override timer ends. 215 private static final int EVENT_EMERGENCY_TOGGLE = 105; 216 private static final int EVENT_RADIO_CAPABILITY_CHANGED = 106; 217 private static final int EVENT_OPPT_DATA_SUB_CHANGED = 107; 218 private static final int EVENT_RADIO_AVAILABLE = 108; 219 // A call has either started or ended. If an emergency ended and DDS is overridden using 220 // mEmergencyOverride, start the countdown to remove the override using the message 221 // EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE. The only exception to this is if the device moves to 222 // ECBM, which is detected by EVENT_EMERGENCY_TOGGLE. 223 @VisibleForTesting 224 public static final int EVENT_PRECISE_CALL_STATE_CHANGED = 109; 225 private static final int EVENT_NETWORK_VALIDATION_DONE = 110; 226 private static final int EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK = 111; 227 private static final int EVENT_MODEM_COMMAND_DONE = 112; 228 private static final int EVENT_MODEM_COMMAND_RETRY = 113; 229 @VisibleForTesting 230 public static final int EVENT_DATA_ENABLED_CHANGED = 114; 231 // An emergency call is about to be originated and requires the DDS to be overridden. 232 // Uses EVENT_PRECISE_CALL_STATE_CHANGED message to start countdown to finish override defined 233 // in mEmergencyOverride. If EVENT_PRECISE_CALL_STATE_CHANGED does not come in 234 // DEFAULT_DATA_OVERRIDE_TIMEOUT_MS milliseconds, then the override will be removed. 235 private static final int EVENT_OVERRIDE_DDS_FOR_EMERGENCY = 115; 236 // If it exists, remove the current mEmergencyOverride DDS override. 237 private static final int EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE = 116; 238 239 // Depending on version of IRadioConfig, we need to send either RIL_REQUEST_ALLOW_DATA if it's 240 // 1.0, or RIL_REQUEST_SET_PREFERRED_DATA if it's 1.1 or later. So internally mHalCommandToUse 241 // will be either HAL_COMMAND_ALLOW_DATA or HAL_COMMAND_ALLOW_DATA or HAL_COMMAND_UNKNOWN. 242 private static final int HAL_COMMAND_UNKNOWN = 0; 243 private static final int HAL_COMMAND_ALLOW_DATA = 1; 244 private static final int HAL_COMMAND_PREFERRED_DATA = 2; 245 private int mHalCommandToUse = HAL_COMMAND_UNKNOWN; 246 247 private RadioConfig mRadioConfig; 248 249 private final static int MAX_LOCAL_LOG_LINES = 30; 250 251 // Default timeout value of network validation in millisecond. 252 private final static int DEFAULT_VALIDATION_EXPIRATION_TIME = 2000; 253 254 private Boolean mHasRegisteredDefaultNetworkChangeCallback = false; 255 256 private ConnectivityManager mConnectivityManager; 257 258 private final ConnectivityManager.NetworkCallback mDefaultNetworkCallback = 259 new NetworkCallback() { 260 @Override 261 public void onAvailable(Network network) { 262 if (mConnectivityManager.getNetworkCapabilities(network) 263 .hasTransport(TRANSPORT_CELLULAR)) { 264 logDataSwitchEvent( 265 mOpptDataSubId, 266 TelephonyEvent.EventState.EVENT_STATE_END, 267 TelephonyEvent.DataSwitch.Reason.DATA_SWITCH_REASON_UNKNOWN); 268 } 269 removeDefaultNetworkChangeCallback(); 270 } 271 }; 272 273 /** 274 * Method to get singleton instance. 275 */ getInstance()276 public static PhoneSwitcher getInstance() { 277 return sPhoneSwitcher; 278 } 279 280 /** 281 * Method to create singleton instance. 282 */ make(int maxActivePhones, int numPhones, Context context, SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr, CommandsInterface[] cis, Phone[] phones)283 public static PhoneSwitcher make(int maxActivePhones, int numPhones, Context context, 284 SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr, 285 CommandsInterface[] cis, Phone[] phones) { 286 if (sPhoneSwitcher == null) { 287 sPhoneSwitcher = new PhoneSwitcher(maxActivePhones, numPhones, context, 288 subscriptionController, looper, tr, cis, phones); 289 } 290 291 return sPhoneSwitcher; 292 } 293 294 /** This constructor is only used for testing purpose. */ 295 @VisibleForTesting PhoneSwitcher(int numPhones, Looper looper)296 public PhoneSwitcher(int numPhones, Looper looper) { 297 super(looper); 298 mMaxActivePhones = 0; 299 mSubscriptionController = null; 300 mCommandsInterfaces = null; 301 mContext = null; 302 mPhoneStates = null; 303 mPhones = null; 304 mLocalLog = null; 305 mActivePhoneRegistrants = null; 306 mNumPhones = numPhones; 307 mPhoneSubscriptions = new int[numPhones]; 308 mRadioConfig = RadioConfig.getInstance(mContext); 309 mPhoneStateListener = new PhoneStateListener(looper) { 310 public void onPhoneCapabilityChanged(PhoneCapability capability) { 311 onPhoneCapabilityChangedInternal(capability); 312 } 313 }; 314 mValidator = CellularNetworkValidator.getInstance(); 315 } 316 isPhoneInVoiceCallChanged()317 private boolean isPhoneInVoiceCallChanged() { 318 int oldPhoneIdInVoiceCall = mPhoneIdInVoiceCall; 319 // If there's no active call, the value will become INVALID_PHONE_INDEX 320 // and internet data will be switched back to system selected or user selected 321 // subscription. 322 mPhoneIdInVoiceCall = SubscriptionManager.INVALID_PHONE_INDEX; 323 for (Phone phone : mPhones) { 324 if (isCallActive(phone) || isCallActive(phone.getImsPhone())) { 325 mPhoneIdInVoiceCall = phone.getPhoneId(); 326 break; 327 } 328 } 329 330 return (mPhoneIdInVoiceCall != oldPhoneIdInVoiceCall); 331 } 332 333 @VisibleForTesting PhoneSwitcher(int maxActivePhones, int numPhones, Context context, SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr, CommandsInterface[] cis, Phone[] phones)334 public PhoneSwitcher(int maxActivePhones, int numPhones, Context context, 335 SubscriptionController subscriptionController, Looper looper, ITelephonyRegistry tr, 336 CommandsInterface[] cis, Phone[] phones) { 337 super(looper); 338 mContext = context; 339 mNumPhones = numPhones; 340 mPhones = phones; 341 mPhoneSubscriptions = new int[numPhones]; 342 mMaxActivePhones = maxActivePhones; 343 mLocalLog = new LocalLog(MAX_LOCAL_LOG_LINES); 344 345 mSubscriptionController = subscriptionController; 346 mRadioConfig = RadioConfig.getInstance(mContext); 347 348 mPhoneStateListener = new PhoneStateListener(looper) { 349 @Override 350 public void onPhoneCapabilityChanged(PhoneCapability capability) { 351 onPhoneCapabilityChangedInternal(capability); 352 } 353 }; 354 355 mValidator = CellularNetworkValidator.getInstance(); 356 357 mActivePhoneRegistrants = new RegistrantList(); 358 mPhoneStates = new PhoneState[numPhones]; 359 for (int i = 0; i < numPhones; i++) { 360 mPhoneStates[i] = new PhoneState(); 361 if (mPhones[i] != null) { 362 mPhones[i].registerForEmergencyCallToggle(this, EVENT_EMERGENCY_TOGGLE, null); 363 // TODO (b/135566422): combine register for both GsmCdmaPhone and ImsPhone. 364 mPhones[i].registerForPreciseCallStateChanged( 365 this, EVENT_PRECISE_CALL_STATE_CHANGED, null); 366 if (mPhones[i].getImsPhone() != null) { 367 mPhones[i].getImsPhone().registerForPreciseCallStateChanged( 368 this, EVENT_PRECISE_CALL_STATE_CHANGED, null); 369 } 370 mPhones[i].getDataEnabledSettings().registerForDataEnabledChanged( 371 this, EVENT_DATA_ENABLED_CHANGED, null); 372 } 373 } 374 375 mCommandsInterfaces = cis; 376 377 if (numPhones > 0) { 378 mCommandsInterfaces[0].registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); 379 } 380 381 try { 382 tr.addOnSubscriptionsChangedListener(context.getOpPackageName(), 383 mSubscriptionsChangedListener); 384 } catch (RemoteException e) { 385 } 386 387 mConnectivityManager = 388 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 389 390 mContext.registerReceiver(mDefaultDataChangedReceiver, 391 new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)); 392 393 NetworkCapabilities netCap = new NetworkCapabilities(); 394 netCap.addTransportType(TRANSPORT_CELLULAR); 395 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MMS); 396 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL); 397 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN); 398 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA); 399 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS); 400 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS); 401 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_IA); 402 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_RCS); 403 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_XCAP); 404 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); 405 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 406 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 407 netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_MCX); 408 netCap.setNetworkSpecifier(new MatchAllNetworkSpecifier()); 409 410 NetworkFactory networkFactory = new PhoneSwitcherNetworkRequestListener(looper, context, 411 netCap, this); 412 // we want to see all requests 413 networkFactory.setScoreFilter(101); 414 networkFactory.register(); 415 416 log("PhoneSwitcher started"); 417 } 418 419 private final BroadcastReceiver mDefaultDataChangedReceiver = new BroadcastReceiver() { 420 @Override 421 public void onReceive(Context context, Intent intent) { 422 Message msg = PhoneSwitcher.this.obtainMessage(EVENT_PRIMARY_DATA_SUB_CHANGED); 423 msg.sendToTarget(); 424 } 425 }; 426 427 private final IOnSubscriptionsChangedListener mSubscriptionsChangedListener = 428 new IOnSubscriptionsChangedListener.Stub() { 429 @Override 430 public void onSubscriptionsChanged() { 431 Message msg = PhoneSwitcher.this.obtainMessage(EVENT_SUBSCRIPTION_CHANGED); 432 msg.sendToTarget(); 433 } 434 }; 435 436 @Override handleMessage(Message msg)437 public void handleMessage(Message msg) { 438 switch (msg.what) { 439 case EVENT_SUBSCRIPTION_CHANGED: { 440 onEvaluate(REQUESTS_UNCHANGED, "subChanged"); 441 break; 442 } 443 case EVENT_PRIMARY_DATA_SUB_CHANGED: { 444 if (onEvaluate(REQUESTS_UNCHANGED, "primary data subId changed")) { 445 logDataSwitchEvent(mOpptDataSubId, 446 TelephonyEvent.EventState.EVENT_STATE_START, 447 DataSwitch.Reason.DATA_SWITCH_REASON_MANUAL); 448 registerDefaultNetworkChangeCallback(); 449 } 450 break; 451 } 452 case EVENT_REQUEST_NETWORK: { 453 onRequestNetwork((NetworkRequest)msg.obj); 454 break; 455 } 456 case EVENT_RELEASE_NETWORK: { 457 onReleaseNetwork((NetworkRequest)msg.obj); 458 break; 459 } 460 case EVENT_EMERGENCY_TOGGLE: { 461 boolean isInEcm = isInEmergencyCallbackMode(); 462 if (mEmergencyOverride != null) { 463 log("Emergency override - ecbm status = " + isInEcm); 464 if (isInEcm) { 465 // The device has gone into ECBM. Wait until it's out. 466 removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 467 mEmergencyOverride.mRequiresEcmFinish = true; 468 } else if (mEmergencyOverride.mRequiresEcmFinish) { 469 // we have exited ECM! Start the timer to exit DDS override. 470 Message msg2 = obtainMessage(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 471 sendMessageDelayed(msg2, mEmergencyOverride.mGnssOverrideTimeMs); 472 } 473 } 474 onEvaluate(REQUESTS_CHANGED, "emergencyToggle"); 475 break; 476 } 477 case EVENT_RADIO_CAPABILITY_CHANGED: { 478 final int phoneId = msg.arg1; 479 sendRilCommands(phoneId); 480 break; 481 } 482 case EVENT_OPPT_DATA_SUB_CHANGED: { 483 int subId = msg.arg1; 484 boolean needValidation = (msg.arg2 == 1); 485 ISetOpportunisticDataCallback callback = 486 (ISetOpportunisticDataCallback) msg.obj; 487 setOpportunisticDataSubscription(subId, needValidation, callback); 488 break; 489 } 490 case EVENT_RADIO_AVAILABLE: { 491 updateHalCommandToUse(); 492 onEvaluate(REQUESTS_UNCHANGED, "EVENT_RADIO_AVAILABLE"); 493 break; 494 } 495 case EVENT_PRECISE_CALL_STATE_CHANGED: { 496 // If the phoneId in voice call didn't change, do nothing. 497 if (!isPhoneInVoiceCallChanged()) break; 498 499 // Only handle this event if we are currently waiting for the emergency call 500 // associated with the override request to start or end. 501 if (mEmergencyOverride != null && mEmergencyOverride.mPendingOriginatingCall) { 502 removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 503 if (mPhoneIdInVoiceCall == SubscriptionManager.INVALID_PHONE_INDEX) { 504 // not in a call anymore. 505 Message msg2 = obtainMessage(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 506 sendMessageDelayed(msg2, mEmergencyOverride.mGnssOverrideTimeMs 507 + ECBM_DEFAULT_DATA_SWITCH_BASE_TIME_MS); 508 // Do not extend the emergency override by waiting for other calls to end. 509 // If it needs to be extended, a new request will come in and replace the 510 // current override. 511 mEmergencyOverride.mPendingOriginatingCall = false; 512 } 513 } 514 } 515 // fall through 516 case EVENT_DATA_ENABLED_CHANGED: 517 if (onEvaluate(REQUESTS_UNCHANGED, "EVENT_PRECISE_CALL_STATE_CHANGED")) { 518 logDataSwitchEvent(mOpptDataSubId, 519 TelephonyEvent.EventState.EVENT_STATE_START, 520 DataSwitch.Reason.DATA_SWITCH_REASON_IN_CALL); 521 registerDefaultNetworkChangeCallback(); 522 } 523 break; 524 case EVENT_NETWORK_VALIDATION_DONE: { 525 int subId = msg.arg1; 526 boolean passed = (msg.arg2 == 1); 527 onValidationDone(subId, passed); 528 break; 529 } 530 case EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK: { 531 removeDefaultNetworkChangeCallback(); 532 break; 533 } 534 case EVENT_MODEM_COMMAND_DONE: { 535 AsyncResult ar = (AsyncResult) msg.obj; 536 boolean commandSuccess = ar != null && ar.exception == null; 537 if (mEmergencyOverride != null) { 538 log("Emergency override result sent = " + commandSuccess); 539 mEmergencyOverride.sendOverrideCompleteCallbackResultAndClear(commandSuccess); 540 // Do not retry , as we do not allow changes in onEvaluate during an emergency 541 // call. When the call ends, we will start the countdown to remove the override. 542 } else if (!commandSuccess) { 543 int phoneId = (int) ar.userObj; 544 log("Modem command failed. with exception " + ar.exception); 545 sendMessageDelayed(Message.obtain(this, EVENT_MODEM_COMMAND_RETRY, 546 phoneId), MODEM_COMMAND_RETRY_PERIOD_MS); 547 } 548 break; 549 } 550 case EVENT_MODEM_COMMAND_RETRY: { 551 int phoneId = (int) msg.obj; 552 log("Resend modem command on phone " + phoneId); 553 sendRilCommands(phoneId); 554 break; 555 } 556 case EVENT_OVERRIDE_DDS_FOR_EMERGENCY: { 557 EmergencyOverrideRequest req = (EmergencyOverrideRequest) msg.obj; 558 if (mEmergencyOverride != null) { 559 // If an override request comes in for a different phone ID than what is already 560 // being overridden, ignore. We should not try to switch DDS while already 561 // waiting for SUPL. 562 if (mEmergencyOverride.mPhoneId != req.mPhoneId) { 563 log("emergency override requested for phone id " + req.mPhoneId + " when " 564 + "there is already an override in place for phone id " 565 + mEmergencyOverride.mPhoneId + ". Ignoring."); 566 if (req.isCallbackAvailable()) { 567 // Send failed result 568 req.mOverrideCompleteFuture.complete(false); 569 } 570 break; 571 } else { 572 if (mEmergencyOverride.isCallbackAvailable()) { 573 // Unblock any waiting overrides if a new request comes in before the 574 // previous one is processed. 575 mEmergencyOverride.mOverrideCompleteFuture.complete(false); 576 } 577 } 578 mEmergencyOverride = req; 579 } else { 580 mEmergencyOverride = req; 581 } 582 583 log("new emergency override - " + mEmergencyOverride); 584 // a new request has been created, remove any previous override complete scheduled. 585 removeMessages(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 586 Message msg2 = obtainMessage(EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE); 587 // Make sure that if we never get an incall indication that we remove the override. 588 sendMessageDelayed(msg2, DEFAULT_DATA_OVERRIDE_TIMEOUT_MS); 589 // Wait for call to end and EVENT_PRECISE_CALL_STATE_CHANGED to be called, then 590 // start timer to remove DDS emergency override. 591 if (!onEvaluate(REQUESTS_UNCHANGED, "emer_override_dds")) { 592 // Nothing changed as a result of override, so no modem command was sent. Treat 593 // as success. 594 mEmergencyOverride.sendOverrideCompleteCallbackResultAndClear(true); 595 // Do not clear mEmergencyOverride here, as we still want to keep the override 596 // active for the time specified in case the user tries to switch default data. 597 } 598 break; 599 } 600 case EVENT_REMOVE_DDS_EMERGENCY_OVERRIDE: { 601 log("Emergency override removed - " + mEmergencyOverride); 602 mEmergencyOverride = null; 603 onEvaluate(REQUESTS_UNCHANGED, "emer_rm_override_dds"); 604 break; 605 } 606 } 607 } 608 isEmergency()609 private boolean isEmergency() { 610 if (isInEmergencyCallbackMode()) return true; 611 for (Phone p : mPhones) { 612 if (p == null) continue; 613 if (p.isInEmergencyCall()) return true; 614 Phone imsPhone = p.getImsPhone(); 615 if (imsPhone != null && imsPhone.isInEmergencyCall()) { 616 return true; 617 } 618 } 619 return false; 620 } 621 isInEmergencyCallbackMode()622 private boolean isInEmergencyCallbackMode() { 623 for (Phone p : mPhones) { 624 if (p == null) continue; 625 if (p.isInEcm()) return true; 626 Phone imsPhone = p.getImsPhone(); 627 if (imsPhone != null && imsPhone.isInEcm()) { 628 return true; 629 } 630 } 631 return false; 632 } 633 634 private static class PhoneSwitcherNetworkRequestListener extends NetworkFactory { 635 private final PhoneSwitcher mPhoneSwitcher; PhoneSwitcherNetworkRequestListener(Looper l, Context c, NetworkCapabilities nc, PhoneSwitcher ps)636 public PhoneSwitcherNetworkRequestListener (Looper l, Context c, 637 NetworkCapabilities nc, PhoneSwitcher ps) { 638 super(l, c, "PhoneSwitcherNetworkRequstListener", nc); 639 mPhoneSwitcher = ps; 640 } 641 642 @Override needNetworkFor(NetworkRequest networkRequest, int score)643 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 644 if (VDBG) log("needNetworkFor " + networkRequest + ", " + score); 645 Message msg = mPhoneSwitcher.obtainMessage(EVENT_REQUEST_NETWORK); 646 msg.obj = networkRequest; 647 msg.sendToTarget(); 648 } 649 650 @Override releaseNetworkFor(NetworkRequest networkRequest)651 protected void releaseNetworkFor(NetworkRequest networkRequest) { 652 if (VDBG) log("releaseNetworkFor " + networkRequest); 653 Message msg = mPhoneSwitcher.obtainMessage(EVENT_RELEASE_NETWORK); 654 msg.obj = networkRequest; 655 msg.sendToTarget(); 656 } 657 } 658 onRequestNetwork(NetworkRequest networkRequest)659 private void onRequestNetwork(NetworkRequest networkRequest) { 660 final DcRequest dcRequest = new DcRequest(networkRequest, mContext); 661 if (!mPrioritizedDcRequests.contains(dcRequest)) { 662 collectRequestNetworkMetrics(networkRequest); 663 mPrioritizedDcRequests.add(dcRequest); 664 Collections.sort(mPrioritizedDcRequests); 665 onEvaluate(REQUESTS_CHANGED, "netRequest"); 666 } 667 } 668 onReleaseNetwork(NetworkRequest networkRequest)669 private void onReleaseNetwork(NetworkRequest networkRequest) { 670 final DcRequest dcRequest = new DcRequest(networkRequest, mContext); 671 672 if (mPrioritizedDcRequests.remove(dcRequest)) { 673 onEvaluate(REQUESTS_CHANGED, "netReleased"); 674 collectReleaseNetworkMetrics(networkRequest); 675 } 676 } 677 removeDefaultNetworkChangeCallback()678 private void removeDefaultNetworkChangeCallback() { 679 synchronized (mHasRegisteredDefaultNetworkChangeCallback) { 680 if (mHasRegisteredDefaultNetworkChangeCallback) { 681 mHasRegisteredDefaultNetworkChangeCallback = false; 682 removeMessages(EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK); 683 mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback); 684 } 685 } 686 } 687 registerDefaultNetworkChangeCallback()688 private void registerDefaultNetworkChangeCallback() { 689 removeDefaultNetworkChangeCallback(); 690 691 synchronized (mHasRegisteredDefaultNetworkChangeCallback) { 692 mHasRegisteredDefaultNetworkChangeCallback = true; 693 mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback); 694 sendMessageDelayed( 695 obtainMessage(EVENT_REMOVE_DEFAULT_NETWORK_CHANGE_CALLBACK), 696 DEFAULT_NETWORK_CHANGE_TIMEOUT_MS); 697 } 698 } 699 collectRequestNetworkMetrics(NetworkRequest networkRequest)700 private void collectRequestNetworkMetrics(NetworkRequest networkRequest) { 701 // Request network for MMS will temporary disable the network on default data subscription, 702 // this only happen on multi-sim device. 703 if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability( 704 NetworkCapabilities.NET_CAPABILITY_MMS)) { 705 OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch(); 706 onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS; 707 onDemandDataSwitch.state = TelephonyEvent.EventState.EVENT_STATE_START; 708 TelephonyMetrics.getInstance().writeOnDemandDataSwitch(onDemandDataSwitch); 709 } 710 } 711 collectReleaseNetworkMetrics(NetworkRequest networkRequest)712 private void collectReleaseNetworkMetrics(NetworkRequest networkRequest) { 713 // Release network for MMS will recover the network on default data subscription, this only 714 // happen on multi-sim device. 715 if (mNumPhones > 1 && networkRequest.networkCapabilities.hasCapability( 716 NetworkCapabilities.NET_CAPABILITY_MMS)) { 717 OnDemandDataSwitch onDemandDataSwitch = new OnDemandDataSwitch(); 718 onDemandDataSwitch.apn = TelephonyEvent.ApnType.APN_TYPE_MMS; 719 onDemandDataSwitch.state = TelephonyEvent.EventState.EVENT_STATE_END; 720 TelephonyMetrics.getInstance().writeOnDemandDataSwitch(onDemandDataSwitch); 721 } 722 } 723 724 private static final boolean REQUESTS_CHANGED = true; 725 private static final boolean REQUESTS_UNCHANGED = false; 726 /** 727 * Re-evaluate things. Do nothing if nothing's changed. 728 * 729 * Otherwise, go through the requests in priority order adding their phone until we've added up 730 * to the max allowed. Then go through shutting down phones that aren't in the active phone 731 * list. Finally, activate all phones in the active phone list. 732 * 733 * @return {@code True} if the default data subscription need to be changed. 734 */ onEvaluate(boolean requestsChanged, String reason)735 private boolean onEvaluate(boolean requestsChanged, String reason) { 736 StringBuilder sb = new StringBuilder(reason); 737 if (isEmergency()) { 738 log("onEvaluate for reason " + reason + " aborted due to Emergency"); 739 return false; 740 } 741 742 // If we use HAL_COMMAND_PREFERRED_DATA, 743 boolean diffDetected = mHalCommandToUse != HAL_COMMAND_PREFERRED_DATA && requestsChanged; 744 745 // Check if user setting of default non-opportunistic data sub is changed. 746 final int primaryDataSubId = mSubscriptionController.getDefaultDataSubId(); 747 if (primaryDataSubId != mPrimaryDataSubId) { 748 sb.append(" mPrimaryDataSubId ").append(mPrimaryDataSubId).append("->") 749 .append(primaryDataSubId); 750 mPrimaryDataSubId = primaryDataSubId; 751 } 752 753 // Check to see if there is any active subscription on any phone 754 boolean hasAnyActiveSubscription = false; 755 756 // Check if phoneId to subId mapping is changed. 757 for (int i = 0; i < mNumPhones; i++) { 758 int sub = mSubscriptionController.getSubIdUsingPhoneId(i); 759 760 if (SubscriptionManager.isValidSubscriptionId(sub)) hasAnyActiveSubscription = true; 761 762 if (sub != mPhoneSubscriptions[i]) { 763 sb.append(" phone[").append(i).append("] ").append(mPhoneSubscriptions[i]); 764 sb.append("->").append(sub); 765 mPhoneSubscriptions[i] = sub; 766 diffDetected = true; 767 } 768 } 769 770 if (!hasAnyActiveSubscription) { 771 transitionToEmergencyPhone(); 772 } else { 773 if (VDBG) log("Found an active subscription"); 774 } 775 776 // Check if phoneId for preferred data is changed. 777 int oldPreferredDataPhoneId = mPreferredDataPhoneId; 778 779 // When there are no subscriptions, the preferred data phone ID is invalid, but we want 780 // to keep a valid phoneId for Emergency, so skip logic that updates for preferred data 781 // phone ID. Ideally there should be a single set of checks that evaluate the correct 782 // phoneId on a service-by-service basis (EIMS being one), but for now... just bypass 783 // this logic in the no-SIM case. 784 if (hasAnyActiveSubscription) updatePreferredDataPhoneId(); 785 786 if (oldPreferredDataPhoneId != mPreferredDataPhoneId) { 787 sb.append(" preferred phoneId ").append(oldPreferredDataPhoneId) 788 .append("->").append(mPreferredDataPhoneId); 789 diffDetected = true; 790 } 791 792 if (diffDetected) { 793 log("evaluating due to " + sb.toString()); 794 if (mHalCommandToUse == HAL_COMMAND_PREFERRED_DATA) { 795 // With HAL_COMMAND_PREFERRED_DATA, all phones are assumed to allow PS attach. 796 // So marking all phone as active, and the phone with mPreferredDataPhoneId 797 // will send radioConfig command. 798 for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { 799 mPhoneStates[phoneId].active = true; 800 } 801 sendRilCommands(mPreferredDataPhoneId); 802 } else { 803 List<Integer> newActivePhones = new ArrayList<Integer>(); 804 805 /** 806 * If all phones can have PS attached, activate all. 807 * Otherwise, choose to activate phones according to requests. And 808 * if list is not full, add mPreferredDataPhoneId. 809 */ 810 if (mMaxActivePhones == mPhones.length) { 811 for (int i = 0; i < mMaxActivePhones; i++) { 812 newActivePhones.add(mPhones[i].getPhoneId()); 813 } 814 } else { 815 for (DcRequest dcRequest : mPrioritizedDcRequests) { 816 int phoneIdForRequest = phoneIdForRequest(dcRequest.networkRequest); 817 if (phoneIdForRequest == INVALID_PHONE_INDEX) continue; 818 if (newActivePhones.contains(phoneIdForRequest)) continue; 819 newActivePhones.add(phoneIdForRequest); 820 if (newActivePhones.size() >= mMaxActivePhones) break; 821 } 822 823 if (newActivePhones.size() < mMaxActivePhones 824 && newActivePhones.contains(mPreferredDataPhoneId) 825 && SubscriptionManager.isUsableSubIdValue(mPreferredDataPhoneId)) { 826 newActivePhones.add(mPreferredDataPhoneId); 827 } 828 } 829 830 if (VDBG) { 831 log("mPrimaryDataSubId = " + mPrimaryDataSubId); 832 log("mOpptDataSubId = " + mOpptDataSubId); 833 for (int i = 0; i < mNumPhones; i++) { 834 log(" phone[" + i + "] using sub[" + mPhoneSubscriptions[i] + "]"); 835 } 836 log(" newActivePhones:"); 837 for (Integer i : newActivePhones) log(" " + i); 838 } 839 840 for (int phoneId = 0; phoneId < mNumPhones; phoneId++) { 841 if (!newActivePhones.contains(phoneId)) { 842 deactivate(phoneId); 843 } 844 } 845 846 // only activate phones up to the limit 847 for (int phoneId : newActivePhones) { 848 activate(phoneId); 849 } 850 } 851 852 notifyPreferredDataSubIdChanged(); 853 854 // Notify all registrants. 855 mActivePhoneRegistrants.notifyRegistrants(); 856 } 857 return diffDetected; 858 } 859 860 private static class PhoneState { 861 public volatile boolean active = false; 862 public long lastRequested = 0; 863 } 864 865 @UnsupportedAppUsage activate(int phoneId)866 private void activate(int phoneId) { 867 switchPhone(phoneId, true); 868 } 869 870 @UnsupportedAppUsage deactivate(int phoneId)871 private void deactivate(int phoneId) { 872 switchPhone(phoneId, false); 873 } 874 switchPhone(int phoneId, boolean active)875 private void switchPhone(int phoneId, boolean active) { 876 PhoneState state = mPhoneStates[phoneId]; 877 if (state.active == active) return; 878 state.active = active; 879 log((active ? "activate " : "deactivate ") + phoneId); 880 state.lastRequested = System.currentTimeMillis(); 881 sendRilCommands(phoneId); 882 } 883 884 /** 885 * Used when the modem may have been rebooted and we 886 * want to resend setDataAllowed or setPreferredDataSubscriptionId 887 */ onRadioCapChanged(int phoneId)888 public void onRadioCapChanged(int phoneId) { 889 validatePhoneId(phoneId); 890 Message msg = obtainMessage(EVENT_RADIO_CAPABILITY_CHANGED); 891 msg.arg1 = phoneId; 892 msg.sendToTarget(); 893 } 894 895 /** 896 * Switch the Default data for the context of an outgoing emergency call. 897 * 898 * In some cases, we need to try to switch the Default Data subscription before placing the 899 * emergency call on DSDS devices. This includes the following situation: 900 * - The modem does not support processing GNSS SUPL requests on the non-default data 901 * subscription. For some carriers that do not provide a control plane fallback mechanism, the 902 * SUPL request will be dropped and we will not be able to get the user's location for the 903 * emergency call. In this case, we need to swap default data temporarily. 904 * @param phoneId The phone to use to evaluate whether or not the default data should be moved 905 * to this subscription. 906 * @param overrideTimeSec The amount of time to override the default data setting for after the 907 * emergency call ends. 908 * @param dataSwitchResult A {@link CompletableFuture} to be called with a {@link Boolean} 909 * result when the default data switch has either completed (true) or 910 * failed (false). 911 */ overrideDefaultDataForEmergency(int phoneId, int overrideTimeSec, CompletableFuture<Boolean> dataSwitchResult)912 public void overrideDefaultDataForEmergency(int phoneId, int overrideTimeSec, 913 CompletableFuture<Boolean> dataSwitchResult) { 914 validatePhoneId(phoneId); 915 Message msg = obtainMessage(EVENT_OVERRIDE_DDS_FOR_EMERGENCY); 916 EmergencyOverrideRequest request = new EmergencyOverrideRequest(); 917 request.mPhoneId = phoneId; 918 request.mGnssOverrideTimeMs = overrideTimeSec * 1000; 919 request.mOverrideCompleteFuture = dataSwitchResult; 920 msg.obj = request; 921 msg.sendToTarget(); 922 } 923 sendRilCommands(int phoneId)924 private void sendRilCommands(int phoneId) { 925 if (!SubscriptionManager.isValidPhoneId(phoneId) || phoneId >= mNumPhones) return; 926 927 Message message = Message.obtain(this, EVENT_MODEM_COMMAND_DONE, phoneId); 928 if (mHalCommandToUse == HAL_COMMAND_ALLOW_DATA || mHalCommandToUse == HAL_COMMAND_UNKNOWN) { 929 // Skip ALLOW_DATA for single SIM device 930 if (mNumPhones > 1) { 931 mCommandsInterfaces[phoneId].setDataAllowed(isPhoneActive(phoneId), message); 932 } 933 } else if (phoneId == mPreferredDataPhoneId) { 934 // Only setPreferredDataModem if the phoneId equals to current mPreferredDataPhoneId. 935 mRadioConfig.setPreferredDataModem(mPreferredDataPhoneId, message); 936 } 937 } 938 onPhoneCapabilityChangedInternal(PhoneCapability capability)939 private void onPhoneCapabilityChangedInternal(PhoneCapability capability) { 940 int newMaxActivePhones = TelephonyManager.getDefault() 941 .getNumberOfModemsWithSimultaneousDataConnections(); 942 if (mMaxActivePhones != newMaxActivePhones) { 943 mMaxActivePhones = newMaxActivePhones; 944 log("Max active phones changed to " + mMaxActivePhones); 945 onEvaluate(REQUESTS_UNCHANGED, "phoneCfgChanged"); 946 } 947 } 948 phoneIdForRequest(NetworkRequest netRequest)949 private int phoneIdForRequest(NetworkRequest netRequest) { 950 int subId = getSubIdFromNetworkRequest(netRequest); 951 952 if (subId == DEFAULT_SUBSCRIPTION_ID) return mPreferredDataPhoneId; 953 if (subId == INVALID_SUBSCRIPTION_ID) return INVALID_PHONE_INDEX; 954 955 int preferredDataSubId = SubscriptionManager.isValidPhoneId(mPreferredDataPhoneId) 956 ? mPhoneSubscriptions[mPreferredDataPhoneId] : INVALID_SUBSCRIPTION_ID; 957 958 // Currently we assume multi-SIM devices will only support one Internet PDN connection. So 959 // if Internet PDN is established on the non-preferred phone, it will interrupt 960 // Internet connection on the preferred phone. So we only accept Internet request with 961 // preferred data subscription or no specified subscription. 962 // One exception is, if it's restricted request (doesn't have NET_CAPABILITY_NOT_RESTRICTED) 963 // it will be accepted, which is used temporary data usage from system. 964 if (netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 965 && netRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 966 && subId != preferredDataSubId && subId != mValidator.getSubIdInValidation()) { 967 // Returning INVALID_PHONE_INDEX will result in netRequest not being handled. 968 return INVALID_PHONE_INDEX; 969 } 970 971 // Try to find matching phone ID. If it doesn't exist, we'll end up returning INVALID. 972 int phoneId = INVALID_PHONE_INDEX; 973 for (int i = 0; i < mNumPhones; i++) { 974 if (mPhoneSubscriptions[i] == subId) { 975 phoneId = i; 976 break; 977 } 978 } 979 return phoneId; 980 } 981 getSubIdFromNetworkRequest(NetworkRequest networkRequest)982 private int getSubIdFromNetworkRequest(NetworkRequest networkRequest) { 983 NetworkSpecifier specifier = networkRequest.networkCapabilities.getNetworkSpecifier(); 984 if (specifier == null) { 985 return DEFAULT_SUBSCRIPTION_ID; 986 } 987 988 int subId; 989 990 if (specifier instanceof StringNetworkSpecifier) { 991 try { 992 subId = Integer.parseInt(((StringNetworkSpecifier) specifier).specifier); 993 } catch (NumberFormatException e) { 994 Rlog.e(LOG_TAG, "NumberFormatException on " 995 + ((StringNetworkSpecifier) specifier).specifier); 996 return INVALID_SUBSCRIPTION_ID; 997 } 998 } else { 999 return INVALID_SUBSCRIPTION_ID; 1000 } 1001 1002 return subId; 1003 } 1004 getSubIdForDefaultNetworkRequests()1005 private int getSubIdForDefaultNetworkRequests() { 1006 if (mSubscriptionController.isActiveSubId(mOpptDataSubId)) { 1007 return mOpptDataSubId; 1008 } else { 1009 return mPrimaryDataSubId; 1010 } 1011 } 1012 1013 // This updates mPreferredDataPhoneId which decides which phone should handle default network 1014 // requests. updatePreferredDataPhoneId()1015 private void updatePreferredDataPhoneId() { 1016 Phone voicePhone = findPhoneById(mPhoneIdInVoiceCall); 1017 if (mEmergencyOverride != null && findPhoneById(mEmergencyOverride.mPhoneId) != null) { 1018 // Override DDS for emergency even if user data is not enabled, since it is an 1019 // emergency. 1020 // TODO: Provide a notification to the user that metered data is currently being 1021 // used during this period. 1022 log("updatePreferredDataPhoneId: preferred data overridden for emergency." 1023 + " phoneId = " + mEmergencyOverride.mPhoneId); 1024 mPreferredDataPhoneId = mEmergencyOverride.mPhoneId; 1025 } else if (voicePhone != null && voicePhone.getDataEnabledSettings().isDataEnabled( 1026 ApnSetting.TYPE_DEFAULT)) { 1027 // If a phone is in call and user enabled its mobile data, we 1028 // should switch internet connection to it. Because the other modem 1029 // will lose data connection anyway. 1030 // TODO: validate network first. 1031 mPreferredDataPhoneId = mPhoneIdInVoiceCall; 1032 } else { 1033 int subId = getSubIdForDefaultNetworkRequests(); 1034 int phoneId = SubscriptionManager.INVALID_PHONE_INDEX; 1035 1036 if (SubscriptionManager.isUsableSubIdValue(subId)) { 1037 for (int i = 0; i < mNumPhones; i++) { 1038 if (mPhoneSubscriptions[i] == subId) { 1039 phoneId = i; 1040 break; 1041 } 1042 } 1043 } 1044 1045 mPreferredDataPhoneId = phoneId; 1046 } 1047 1048 mPreferredDataSubId = mSubscriptionController.getSubIdUsingPhoneId(mPreferredDataPhoneId); 1049 } 1050 transitionToEmergencyPhone()1051 private void transitionToEmergencyPhone() { 1052 if (mPreferredDataPhoneId != DEFAULT_EMERGENCY_PHONE_ID) { 1053 log("No active subscriptions: resetting preferred phone to 0 for emergency"); 1054 mPreferredDataPhoneId = DEFAULT_EMERGENCY_PHONE_ID; 1055 } 1056 1057 if (mPreferredDataSubId != INVALID_SUBSCRIPTION_ID) { 1058 mPreferredDataSubId = INVALID_SUBSCRIPTION_ID; 1059 notifyPreferredDataSubIdChanged(); 1060 } 1061 } 1062 findPhoneById(final int phoneId)1063 private Phone findPhoneById(final int phoneId) { 1064 if (phoneId < 0 || phoneId >= mNumPhones) { 1065 return null; 1066 } 1067 return mPhones[phoneId]; 1068 } 1069 shouldApplyNetworkRequest(NetworkRequest networkRequest, int phoneId)1070 public boolean shouldApplyNetworkRequest(NetworkRequest networkRequest, int phoneId) { 1071 validatePhoneId(phoneId); 1072 1073 // In any case, if phone state is inactive, don't apply the network request. 1074 if (!isPhoneActive(phoneId) || ( 1075 mSubscriptionController.getSubIdUsingPhoneId(phoneId) == INVALID_SUBSCRIPTION_ID 1076 && !isEmergencyNetworkRequest(networkRequest))) { 1077 return false; 1078 } 1079 1080 int phoneIdToHandle = phoneIdForRequest(networkRequest); 1081 1082 return phoneId == phoneIdToHandle; 1083 } 1084 isEmergencyNetworkRequest(NetworkRequest networkRequest)1085 boolean isEmergencyNetworkRequest(NetworkRequest networkRequest) { 1086 return networkRequest.hasCapability(NetworkCapabilities.NET_CAPABILITY_EIMS); 1087 } 1088 1089 @VisibleForTesting isPhoneActive(int phoneId)1090 protected boolean isPhoneActive(int phoneId) { 1091 return mPhoneStates[phoneId].active; 1092 } 1093 1094 /** 1095 * If preferred phone changes, or phone activation status changes, registrants 1096 * will be notified. 1097 */ registerForActivePhoneSwitch(Handler h, int what, Object o)1098 public void registerForActivePhoneSwitch(Handler h, int what, Object o) { 1099 Registrant r = new Registrant(h, what, o); 1100 mActivePhoneRegistrants.add(r); 1101 r.notifyRegistrant(); 1102 } 1103 unregisterForActivePhoneSwitch(Handler h)1104 public void unregisterForActivePhoneSwitch(Handler h) { 1105 mActivePhoneRegistrants.remove(h); 1106 } 1107 1108 @VisibleForTesting validatePhoneId(int phoneId)1109 protected void validatePhoneId(int phoneId) { 1110 if (phoneId < 0 || phoneId >= mNumPhones) { 1111 throw new IllegalArgumentException("Invalid PhoneId"); 1112 } 1113 } 1114 1115 /** 1116 * Set opportunistic data subscription. It's an indication to switch Internet data to this 1117 * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate 1118 * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting 1119 * opportunistic data sub and switch data back to primary sub. 1120 * 1121 * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID 1122 * if un-setting it. 1123 * @param needValidation whether Telephony will wait until the network is validated by 1124 * connectivity service before switching data to it. More details see 1125 * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. 1126 * @param callback Callback will be triggered once it succeeds or failed. 1127 * Pass null if don't care about the result. 1128 */ setOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback)1129 private void setOpportunisticDataSubscription(int subId, boolean needValidation, 1130 ISetOpportunisticDataCallback callback) { 1131 if (!mSubscriptionController.isActiveSubId(subId) 1132 && subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 1133 log("Can't switch data to inactive subId " + subId); 1134 sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION); 1135 return; 1136 } 1137 1138 int subIdToValidate = (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) 1139 ? mPrimaryDataSubId : subId; 1140 1141 if (mValidator.isValidating() 1142 && (!needValidation || subIdToValidate != mValidator.getSubIdInValidation())) { 1143 mValidator.stopValidation(); 1144 } 1145 1146 if (subId == mOpptDataSubId) { 1147 sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); 1148 return; 1149 } 1150 1151 // If validation feature is not supported, set it directly. Otherwise, 1152 // start validation on the subscription first. 1153 if (mValidator.isValidationFeatureSupported() && needValidation) { 1154 logDataSwitchEvent(subId, TelephonyEvent.EventState.EVENT_STATE_START, 1155 DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); 1156 registerDefaultNetworkChangeCallback(); 1157 mSetOpptSubCallback = callback; 1158 mValidator.validate(subIdToValidate, DEFAULT_VALIDATION_EXPIRATION_TIME, 1159 false, mValidationCallback); 1160 } else { 1161 setOpportunisticSubscriptionInternal(subId); 1162 sendSetOpptCallbackHelper(callback, SET_OPPORTUNISTIC_SUB_SUCCESS); 1163 } 1164 } 1165 sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result)1166 private void sendSetOpptCallbackHelper(ISetOpportunisticDataCallback callback, int result) { 1167 if (callback == null) return; 1168 try { 1169 callback.onComplete(result); 1170 } catch (RemoteException exception) { 1171 log("RemoteException " + exception); 1172 } 1173 } 1174 1175 /** 1176 * Set opportunistic data subscription. 1177 */ setOpportunisticSubscriptionInternal(int subId)1178 private void setOpportunisticSubscriptionInternal(int subId) { 1179 if (mOpptDataSubId != subId) { 1180 mOpptDataSubId = subId; 1181 if (onEvaluate(REQUESTS_UNCHANGED, "oppt data subId changed")) { 1182 logDataSwitchEvent(mOpptDataSubId, 1183 TelephonyEvent.EventState.EVENT_STATE_START, 1184 DataSwitch.Reason.DATA_SWITCH_REASON_CBRS); 1185 registerDefaultNetworkChangeCallback(); 1186 } 1187 } 1188 } 1189 onValidationDone(int subId, boolean passed)1190 private void onValidationDone(int subId, boolean passed) { 1191 log("onValidationDone: " + (passed ? "passed" : "failed") 1192 + " on subId " + subId); 1193 int resultForCallBack; 1194 1195 if (!mSubscriptionController.isActiveSubId(subId)) { 1196 log("onValidationDone: subId " + subId + " is no longer active"); 1197 resultForCallBack = SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION; 1198 } else if (!passed) { 1199 resultForCallBack = SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED; 1200 } else { 1201 if (mSubscriptionController.isOpportunistic(subId)) { 1202 setOpportunisticSubscriptionInternal(subId); 1203 } else { 1204 // Switching data back to primary subscription. 1205 setOpportunisticSubscriptionInternal(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID); 1206 } 1207 resultForCallBack = SET_OPPORTUNISTIC_SUB_SUCCESS; 1208 } 1209 1210 // Trigger callback if needed 1211 sendSetOpptCallbackHelper(mSetOpptSubCallback, resultForCallBack); 1212 mSetOpptSubCallback = null; 1213 } 1214 1215 /** 1216 * Notify PhoneSwitcher to try to switch data to an opportunistic subscription. 1217 * 1218 * Set opportunistic data subscription. It's an indication to switch Internet data to this 1219 * subscription. It has to be an active subscription, and PhoneSwitcher will try to validate 1220 * it first if needed. If subId is DEFAULT_SUBSCRIPTION_ID, it means we are un-setting 1221 * opportunistic data sub and switch data back to primary sub. 1222 * 1223 * @param subId the opportunistic data subscription to switch to. pass DEFAULT_SUBSCRIPTION_ID 1224 * if un-setting it. 1225 * @param needValidation whether Telephony will wait until the network is validated by 1226 * connectivity service before switching data to it. More details see 1227 * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}. 1228 * @param callback Callback will be triggered once it succeeds or failed. 1229 * Pass null if don't care about the result. 1230 */ trySetOpportunisticDataSubscription(int subId, boolean needValidation, ISetOpportunisticDataCallback callback)1231 public void trySetOpportunisticDataSubscription(int subId, boolean needValidation, 1232 ISetOpportunisticDataCallback callback) { 1233 log("Try set opportunistic data subscription to subId " + subId 1234 + (needValidation ? " with " : " without ") + "validation"); 1235 PhoneSwitcher.this.obtainMessage(EVENT_OPPT_DATA_SUB_CHANGED, 1236 subId, needValidation ? 1 : 0, callback).sendToTarget(); 1237 } 1238 isCallActive(Phone phone)1239 private boolean isCallActive(Phone phone) { 1240 if (phone == null) { 1241 return false; 1242 } 1243 1244 return (phone.getForegroundCall().getState() == Call.State.ACTIVE 1245 || phone.getForegroundCall().getState() == Call.State.ALERTING); 1246 } 1247 updateHalCommandToUse()1248 private void updateHalCommandToUse() { 1249 mHalCommandToUse = mRadioConfig.isSetPreferredDataCommandSupported() 1250 ? HAL_COMMAND_PREFERRED_DATA : HAL_COMMAND_ALLOW_DATA; 1251 } 1252 getOpportunisticDataSubscriptionId()1253 public int getOpportunisticDataSubscriptionId() { 1254 return mOpptDataSubId; 1255 } 1256 getPreferredDataPhoneId()1257 public int getPreferredDataPhoneId() { 1258 return mPreferredDataPhoneId; 1259 } 1260 1261 @UnsupportedAppUsage log(String l)1262 private void log(String l) { 1263 Rlog.d(LOG_TAG, l); 1264 mLocalLog.log(l); 1265 } 1266 logDataSwitchEvent(int subId, int state, int reason)1267 private void logDataSwitchEvent(int subId, int state, int reason) { 1268 subId = subId == DEFAULT_SUBSCRIPTION_ID ? mPrimaryDataSubId : subId; 1269 DataSwitch dataSwitch = new DataSwitch(); 1270 dataSwitch.state = state; 1271 dataSwitch.reason = reason; 1272 TelephonyMetrics.getInstance().writeDataSwitch(subId, dataSwitch); 1273 } 1274 1275 /** 1276 * See {@link PhoneStateListener#LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE}. 1277 */ notifyPreferredDataSubIdChanged()1278 private void notifyPreferredDataSubIdChanged() { 1279 ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( 1280 "telephony.registry")); 1281 try { 1282 log("notifyPreferredDataSubIdChanged to " + mPreferredDataSubId); 1283 tr.notifyActiveDataSubIdChanged(mPreferredDataSubId); 1284 } catch (RemoteException ex) { 1285 // Should never happen because its always available. 1286 } 1287 } 1288 dump(FileDescriptor fd, PrintWriter writer, String[] args)1289 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 1290 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1291 pw.println("PhoneSwitcher:"); 1292 Calendar c = Calendar.getInstance(); 1293 for (int i = 0; i < mNumPhones; i++) { 1294 PhoneState ps = mPhoneStates[i]; 1295 c.setTimeInMillis(ps.lastRequested); 1296 pw.println("PhoneId(" + i + ") active=" + ps.active + ", lastRequest=" + 1297 (ps.lastRequested == 0 ? "never" : 1298 String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c))); 1299 } 1300 pw.increaseIndent(); 1301 mLocalLog.dump(fd, pw, args); 1302 pw.decreaseIndent(); 1303 } 1304 } 1305