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