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