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