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