• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.services.telephony.domainselection;
18 
19 import static android.telephony.AccessNetworkConstants.AccessNetworkType.CDMA2000;
20 import static android.telephony.AccessNetworkConstants.AccessNetworkType.EUTRAN;
21 import static android.telephony.AccessNetworkConstants.AccessNetworkType.NGRAN;
22 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UNKNOWN;
23 import static android.telephony.AccessNetworkConstants.AccessNetworkType.UTRAN;
24 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
25 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN;
26 import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
27 import static android.telephony.BarringInfo.BARRING_SERVICE_TYPE_EMERGENCY;
28 import static android.telephony.CarrierConfigManager.ImsEmergency.DOMAIN_CS;
29 import static android.telephony.CarrierConfigManager.ImsEmergency.DOMAIN_PS_3GPP;
30 import static android.telephony.CarrierConfigManager.ImsEmergency.DOMAIN_PS_NON_3GPP;
31 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT;
32 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY;
33 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY;
34 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY;
35 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL;
36 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT;
37 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY;
38 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY;
39 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY;
40 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY;
41 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL;
42 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL;
43 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_SCAN_TIMER_SEC_INT;
44 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT;
45 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT;
46 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT;
47 import static android.telephony.CarrierConfigManager.ImsEmergency.KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL;
48 import static android.telephony.CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE;
49 import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_SETTING_ENABLED;
50 import static android.telephony.CarrierConfigManager.ImsEmergency.VOWIFI_REQUIRES_VALID_EID;
51 import static android.telephony.CarrierConfigManager.ImsWfc.KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL;
52 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME;
53 import static android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING;
54 import static android.telephony.PreciseDisconnectCause.EMERGENCY_PERM_FAILURE;
55 import static android.telephony.PreciseDisconnectCause.EMERGENCY_TEMP_FAILURE;
56 
57 import android.annotation.NonNull;
58 import android.content.Context;
59 import android.net.ConnectivityManager;
60 import android.net.Network;
61 import android.net.NetworkCapabilities;
62 import android.net.NetworkRequest;
63 import android.os.CancellationSignal;
64 import android.os.Looper;
65 import android.os.Message;
66 import android.os.PersistableBundle;
67 import android.os.PowerManager;
68 import android.os.SystemProperties;
69 import android.telephony.AccessNetworkConstants.AccessNetworkType;
70 import android.telephony.AccessNetworkConstants.RadioAccessNetworkType;
71 import android.telephony.AccessNetworkConstants.TransportType;
72 import android.telephony.BarringInfo;
73 import android.telephony.CarrierConfigManager;
74 import android.telephony.DisconnectCause;
75 import android.telephony.DomainSelectionService;
76 import android.telephony.DomainSelectionService.SelectionAttributes;
77 import android.telephony.EmergencyRegResult;
78 import android.telephony.NetworkRegistrationInfo;
79 import android.telephony.PhoneNumberUtils;
80 import android.telephony.SubscriptionManager;
81 import android.telephony.TelephonyManager;
82 import android.telephony.TransportSelectorCallback;
83 import android.telephony.emergency.EmergencyNumber;
84 import android.telephony.ims.ImsManager;
85 import android.telephony.ims.ImsMmTelManager;
86 import android.telephony.ims.ImsReasonInfo;
87 import android.telephony.ims.ProvisioningManager;
88 import android.text.TextUtils;
89 import android.util.LocalLog;
90 
91 import com.android.internal.annotations.VisibleForTesting;
92 
93 import java.util.ArrayList;
94 import java.util.Arrays;
95 import java.util.HashMap;
96 import java.util.List;
97 import java.util.Map;
98 import java.util.function.IntFunction;
99 
100 /**
101  * Selects the domain for emergency calling.
102  */
103 public class EmergencyCallDomainSelector extends DomainSelectorBase
104         implements ImsStateTracker.BarringInfoListener, ImsStateTracker.ImsStateListener {
105     private static final String TAG = "DomainSelector-EmergencyCall";
106     private static final boolean DBG = (SystemProperties.getInt("ro.debuggable", 0) == 1);
107     private static final int LOG_SIZE = 50;
108 
109     private static final int MSG_START_DOMAIN_SELECTION = 11;
110     @VisibleForTesting
111     public static final int MSG_NETWORK_SCAN_TIMEOUT = 12;
112     private static final int MSG_NETWORK_SCAN_RESULT = 13;
113     @VisibleForTesting
114     public static final int MSG_MAX_CELLULAR_TIMEOUT = 14;
115 
116     private static final int NOT_SUPPORTED = -1;
117 
118     private static final LocalLog sLocalLog = new LocalLog(LOG_SIZE);
119 
120     private static final ArrayList<String> sAllowOnlyWithSimReady = new ArrayList<>();
121 
122     static {
123         // b/177967010, JP
124         sAllowOnlyWithSimReady.add("jp"); // Japan
125         // b/198393826, DE
126         sAllowOnlyWithSimReady.add("de"); // Germany
127         // b/230443699, IN and SG
128         sAllowOnlyWithSimReady.add("in"); // India
129         sAllowOnlyWithSimReady.add("sg"); // Singapore
130     }
131 
132     /**
133      * Network callback used to determine whether Wi-Fi is connected or not.
134      */
135     private ConnectivityManager.NetworkCallback mNetworkCallback =
136             new ConnectivityManager.NetworkCallback() {
137                 @Override
138                 public void onAvailable(Network network) {
139                     logi("onAvailable: " + network);
140                     mWiFiAvailable = true;
141                 }
142 
143                 @Override
144                 public void onLost(Network network) {
145                     logi("onLost: " + network);
146                     mWiFiAvailable = false;
147                 }
148 
149                 @Override
150                 public void onUnavailable() {
151                     logi("onUnavailable");
152                     mWiFiAvailable = false;
153                 }
154             };
155 
156     private boolean mIsEmergencyBarred;
157     private boolean mImsRegistered;
158     private boolean mIsVoiceCapable;
159     private boolean mBarringInfoReceived;
160     private boolean mImsRegStateReceived;
161     private boolean mMmTelCapabilitiesReceived;
162     private int mVoWifiTrialCount = 0;
163 
164     private @RadioAccessNetworkType int mCsNetworkType = UNKNOWN;
165     private @RadioAccessNetworkType int mPsNetworkType = UNKNOWN;
166     private @RadioAccessNetworkType int mLastNetworkType = UNKNOWN;
167     private @TransportType int mLastTransportType = TRANSPORT_TYPE_INVALID;
168     private @DomainSelectionService.EmergencyScanType int mScanType;
169     private @RadioAccessNetworkType List<Integer> mLastPreferredNetworks;
170     private boolean mIsTestEmergencyNumber;
171 
172     private CancellationSignal mCancelSignal;
173 
174     private @RadioAccessNetworkType int[] mImsRatsConfig;
175     private @RadioAccessNetworkType int[] mCsRatsConfig;
176     private @RadioAccessNetworkType int[] mImsRoamRatsConfig;
177     private @RadioAccessNetworkType int[] mCsRoamRatsConfig;
178     private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreference;
179     private @CarrierConfigManager.ImsEmergency.EmergencyDomain int[] mDomainPreferenceRoam;
180     private List<String> mCdmaPreferredNumbers;
181     private boolean mPreferImsWhenCallsOnCs;
182     private int mVoWifiRequiresCondition;
183     private boolean mIsMonitoringConnectivity;
184     private boolean mWiFiAvailable;
185     private int mScanTimeout;
186     private int mMaxCellularTimeout;
187     private int mMaxNumOfVoWifiTries;
188     private boolean mVoWifiOverEmergencyPdn;
189     private @CarrierConfigManager.ImsEmergency.EmergencyScanType int mPreferredNetworkScanType;
190     private int mCallSetupTimerOnCurrentRat;
191     private boolean mRequiresImsRegistration;
192     private boolean mRequiresVoLteEnabled;
193     private boolean mLtePreferredAfterNrFailure;
194     private boolean mTryCsWhenPsFails;
195     private boolean mTryEpsFallback;
196     private int mModemCount;
197 
198     /** Indicates whether this instance is deactivated. */
199     private boolean mDestroyed = false;
200     /** Indicates whether emergency network scan is requested. */
201     private boolean mIsScanRequested = false;
202     /** Indicates whether selected domain has been notified. */
203     private boolean mDomainSelected = false;
204     /** Indicates whether the cross sim redialing timer has expired. */
205     private boolean mCrossStackTimerExpired = false;
206     /** Indicates whether max cellular timer expired. */
207     private boolean mMaxCellularTimerExpired = false;
208 
209     /**
210      * Indicates whether {@link #selectDomain(SelectionAttributes, TransportSelectionCallback)}
211      * is called or not.
212      */
213     private boolean mDomainSelectionRequested = false;
214 
215     private final PowerManager.WakeLock mPartialWakeLock;
216     private final CrossSimRedialingController mCrossSimRedialingController;
217 
218     /** Constructor. */
EmergencyCallDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener destroyListener, @NonNull CrossSimRedialingController csrController)219     public EmergencyCallDomainSelector(Context context, int slotId, int subId,
220             @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
221             @NonNull DestroyListener destroyListener,
222             @NonNull CrossSimRedialingController csrController) {
223         super(context, slotId, subId, looper, imsStateTracker, destroyListener, TAG);
224 
225         mImsStateTracker.addBarringInfoListener(this);
226         mImsStateTracker.addImsStateListener(this);
227 
228         PowerManager pm = context.getSystemService(PowerManager.class);
229         mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
230 
231         mCrossSimRedialingController = csrController;
232         acquireWakeLock();
233     }
234 
235     @Override
handleMessage(Message msg)236     public void handleMessage(Message msg) {
237         if (mDestroyed) return;
238 
239         switch(msg.what) {
240             case MSG_START_DOMAIN_SELECTION:
241                 startDomainSelection();
242                 break;
243 
244             case MSG_NETWORK_SCAN_TIMEOUT:
245                 handleNetworkScanTimeout();
246                 break;
247 
248             case MSG_NETWORK_SCAN_RESULT:
249                 handleScanResult((EmergencyRegResult) msg.obj);
250                 break;
251 
252             case MSG_MAX_CELLULAR_TIMEOUT:
253                 handleMaxCellularTimeout();
254                 break;
255 
256             default:
257                 super.handleMessage(msg);
258                 break;
259         }
260     }
261 
262     /**
263      * Handles the scan result.
264      *
265      * @param result The scan result.
266      */
handleScanResult(EmergencyRegResult result)267     private void handleScanResult(EmergencyRegResult result) {
268         logi("handleScanResult result=" + result);
269 
270         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
271             logi("handleScanResult timer expired, WLAN has been selected, ignore stale result");
272             return;
273         }
274 
275         // Detected the country and found that emergency calls are not allowed with this slot.
276         if (!allowEmergencyCalls(result)) {
277             terminateSelectionPermanentlyForSlot();
278             return;
279         }
280 
281         if (result.getAccessNetwork() == UNKNOWN) {
282             if ((mPreferredNetworkScanType == SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE)
283                       && (mScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
284                 mScanType = DomainSelectionService.SCAN_TYPE_LIMITED_SERVICE;
285                 mWwanSelectorCallback.onRequestEmergencyNetworkScan(
286                         mLastPreferredNetworks, mScanType, mCancelSignal,
287                         (regResult) -> {
288                             logi("requestScan-onComplete");
289                             sendMessage(obtainMessage(MSG_NETWORK_SCAN_RESULT, regResult));
290                         });
291             } else {
292                 // Continuous scan, do not start a new timer.
293                 requestScan(false);
294             }
295             return;
296         }
297 
298         removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
299         onWwanNetworkTypeSelected(getAccessNetworkType(result));
300         mCancelSignal = null;
301     }
302 
303     /**
304      * Determines the scanned network type.
305      *
306      * @param result The result of network scan.
307      * @return The selected network type.
308      */
getAccessNetworkType(EmergencyRegResult result)309     private @RadioAccessNetworkType int getAccessNetworkType(EmergencyRegResult result) {
310         int accessNetworkType = result.getAccessNetwork();
311         if (accessNetworkType != EUTRAN) return accessNetworkType;
312 
313         int regState = result.getRegState();
314         int domain = result.getDomain();
315 
316         // Emergency is not supported with LTE, but CSFB is possible.
317         if ((regState == REGISTRATION_STATE_HOME || regState == REGISTRATION_STATE_ROAMING)
318                 && (domain == NetworkRegistrationInfo.DOMAIN_CS)) {
319             logi("getAccessNetworkType emergency not supported but CSFB is possible");
320             accessNetworkType = UTRAN;
321         }
322 
323         return accessNetworkType;
324     }
325 
326     @Override
cancelSelection()327     public void cancelSelection() {
328         logi("cancelSelection");
329         finishSelection();
330     }
331 
332     @Override
reselectDomain(SelectionAttributes attr)333     public void reselectDomain(SelectionAttributes attr) {
334         logi("reselectDomain attr=" + attr);
335         mSelectionAttributes = attr;
336         post(() -> { reselectDomain(); });
337     }
338 
reselectDomain()339     private void reselectDomain() {
340         logi("reselectDomain tryCsWhenPsFails=" + mTryCsWhenPsFails);
341 
342         int cause = mSelectionAttributes.getCsDisconnectCause();
343         mCrossSimRedialingController.notifyCallFailure(cause);
344 
345         // TODO(b/258112541) make EMERGENCY_PERM_FAILURE and EMERGENCY_TEMP_FAILURE public api
346         if (cause == EMERGENCY_PERM_FAILURE
347                 || cause == EMERGENCY_TEMP_FAILURE) {
348             logi("reselectDomain should redial on the other subscription");
349             terminateSelectionForCrossSimRedialing(cause == EMERGENCY_PERM_FAILURE);
350             return;
351         }
352 
353         if (mCrossStackTimerExpired) {
354             logi("reselectDomain cross stack timer expired");
355             terminateSelectionForCrossSimRedialing(false);
356             return;
357         }
358 
359         if (mIsTestEmergencyNumber) {
360             selectDomainForTestEmergencyNumber();
361             return;
362         }
363 
364         if (mTryCsWhenPsFails) {
365             mTryCsWhenPsFails = false;
366             // Initial state was CSFB available and dial PS failed.
367             // Dial CS for CSFB instead of scanning with CS preferred network list.
368             logi("reselectDomain tryCs=" + accessNetworkTypeToString(mCsNetworkType));
369             if (mCsNetworkType != UNKNOWN) {
370                 onWwanNetworkTypeSelected(mCsNetworkType);
371                 return;
372             }
373         }
374 
375         if (mMaxCellularTimerExpired) {
376             if (mLastTransportType == TRANSPORT_TYPE_WWAN
377                     && maybeDialOverWlan()) {
378                 // Cellular call failed and max cellular search timer expired, so redial on Wi-Fi.
379                 // If this VoWi-Fi fails, the timer shall be restarted on next reselectDomain().
380                 return;
381             } else if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
382                 // Since VoWi-Fi failed, allow for requestScan to restart max cellular timer.
383                 mMaxCellularTimerExpired = false;
384             }
385         }
386 
387         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
388             // Dialing over Wi-Fi failed. Try scanning cellular networks.
389             onWwanSelected(this::reselectDomainInternal);
390             return;
391         }
392 
393         requestScan(true);
394         mDomainSelected = false;
395     }
396 
reselectDomainInternal()397     private void reselectDomainInternal() {
398         post(() -> {
399             requestScan(true, false, true);
400             mDomainSelected = false;
401         });
402     }
403 
404     @Override
finishSelection()405     public void finishSelection() {
406         logi("finishSelection");
407         destroy();
408     }
409 
410     @Override
onBarringInfoUpdated(BarringInfo barringInfo)411     public void onBarringInfoUpdated(BarringInfo barringInfo) {
412         if (mDestroyed) return;
413 
414         mBarringInfoReceived = true;
415         BarringInfo.BarringServiceInfo serviceInfo =
416                 barringInfo.getBarringServiceInfo(BARRING_SERVICE_TYPE_EMERGENCY);
417         mIsEmergencyBarred = serviceInfo.isBarred();
418         logi("onBarringInfoUpdated emergencyBarred=" + mIsEmergencyBarred
419                 + ", serviceInfo=" + serviceInfo);
420         selectDomain();
421     }
422 
423     @Override
selectDomain(SelectionAttributes attr, TransportSelectorCallback cb)424     public void selectDomain(SelectionAttributes attr, TransportSelectorCallback cb) {
425         logi("selectDomain attr=" + attr);
426         mTransportSelectorCallback = cb;
427         mSelectionAttributes = attr;
428         mIsTestEmergencyNumber = isTestEmergencyNumber(attr.getNumber());
429 
430         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
431         mModemCount = tm.getActiveModemCount();
432 
433         sendEmptyMessage(MSG_START_DOMAIN_SELECTION);
434     }
435 
startDomainSelection()436     private void startDomainSelection() {
437         logi("startDomainSelection modemCount=" + mModemCount);
438         updateCarrierConfiguration();
439         mDomainSelectionRequested = true;
440         startCrossStackTimer();
441         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
442             selectDomain();
443         } else {
444             logi("startDomainSelection invalid subId");
445             onImsRegistrationStateChanged();
446             onImsMmTelCapabilitiesChanged();
447         }
448     }
449 
450     @Override
onImsMmTelFeatureAvailableChanged()451     public void onImsMmTelFeatureAvailableChanged() {
452         // DOMAIN_CS shall be selected when ImsService is not available.
453         // TODO(b/258289015) Recover the temporary failure in ImsService connection.
454     }
455 
456     @Override
onImsRegistrationStateChanged()457     public void onImsRegistrationStateChanged() {
458         mImsRegStateReceived = true;
459         mImsRegistered = mImsStateTracker.isImsRegistered();
460         logi("onImsRegistrationStateChanged " + mImsRegistered);
461         selectDomain();
462     }
463 
464     @Override
onImsMmTelCapabilitiesChanged()465     public void onImsMmTelCapabilitiesChanged() {
466         mMmTelCapabilitiesReceived = true;
467         mIsVoiceCapable = mImsStateTracker.isImsVoiceCapable();
468         logi("onImsMmTelCapabilitiesChanged " + mIsVoiceCapable);
469         selectDomain();
470     }
471 
472     /**
473      * Caches the configuration.
474      */
updateCarrierConfiguration()475     private void updateCarrierConfiguration() {
476         CarrierConfigManager configMgr = mContext.getSystemService(CarrierConfigManager.class);
477         PersistableBundle b = configMgr.getConfigForSubId(getSubId());
478         if (b == null) {
479             b = CarrierConfigManager.getDefaultConfig();
480         }
481 
482         mImsRatsConfig =
483                 b.getIntArray(KEY_EMERGENCY_OVER_IMS_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
484         mImsRoamRatsConfig = b.getIntArray(
485                 KEY_EMERGENCY_OVER_IMS_ROAMING_SUPPORTED_3GPP_NETWORK_TYPES_INT_ARRAY);
486         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) {
487             // Default configuration includes only EUTRAN . In case of no SIM, add NGRAN.
488             mImsRatsConfig = new int[] { EUTRAN, NGRAN };
489             mImsRoamRatsConfig = new int[] { EUTRAN, NGRAN };
490         }
491 
492         mCsRatsConfig =
493                 b.getIntArray(KEY_EMERGENCY_OVER_CS_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY);
494         mCsRoamRatsConfig = b.getIntArray(
495                 KEY_EMERGENCY_OVER_CS_ROAMING_SUPPORTED_ACCESS_NETWORK_TYPES_INT_ARRAY);
496         mDomainPreference = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_INT_ARRAY);
497         mDomainPreferenceRoam = b.getIntArray(KEY_EMERGENCY_DOMAIN_PREFERENCE_ROAMING_INT_ARRAY);
498         mPreferImsWhenCallsOnCs = b.getBoolean(
499                 KEY_PREFER_IMS_EMERGENCY_WHEN_VOICE_CALLS_ON_CS_BOOL);
500         mVoWifiRequiresCondition = b.getInt(KEY_EMERGENCY_VOWIFI_REQUIRES_CONDITION_INT);
501         mScanTimeout = b.getInt(KEY_EMERGENCY_SCAN_TIMER_SEC_INT) * 1000;
502         mMaxCellularTimeout = b.getInt(KEY_MAXIMUM_CELLULAR_SEARCH_TIMER_SEC_INT) * 1000;
503         mMaxNumOfVoWifiTries = b.getInt(KEY_MAXIMUM_NUMBER_OF_EMERGENCY_TRIES_OVER_VOWIFI_INT);
504         mVoWifiOverEmergencyPdn = b.getBoolean(KEY_EMERGENCY_CALL_OVER_EMERGENCY_PDN_BOOL);
505         mPreferredNetworkScanType = b.getInt(KEY_EMERGENCY_NETWORK_SCAN_TYPE_INT);
506         mCallSetupTimerOnCurrentRat = b.getInt(
507                 KEY_EMERGENCY_CALL_SETUP_TIMER_ON_CURRENT_NETWORK_SEC_INT) * 1000;
508         mRequiresImsRegistration = b.getBoolean(KEY_EMERGENCY_REQUIRES_IMS_REGISTRATION_BOOL);
509         mRequiresVoLteEnabled = b.getBoolean(KEY_EMERGENCY_REQUIRES_VOLTE_ENABLED_BOOL);
510         mLtePreferredAfterNrFailure = b.getBoolean(
511                 KEY_EMERGENCY_LTE_PREFERRED_AFTER_NR_FAILED_BOOL);
512         String[] numbers = b.getStringArray(KEY_EMERGENCY_CDMA_PREFERRED_NUMBERS_STRING_ARRAY);
513 
514         if (mImsRatsConfig == null) mImsRatsConfig = new int[0];
515         if (mCsRatsConfig == null) mCsRatsConfig = new int[0];
516         if (mImsRoamRatsConfig == null) mImsRoamRatsConfig = new int[0];
517         if (mCsRoamRatsConfig == null) mCsRoamRatsConfig = new int[0];
518         if (mDomainPreference == null) mDomainPreference = new int[0];
519         if (mDomainPreferenceRoam == null) mDomainPreferenceRoam = new int[0];
520         if (numbers == null) numbers = new String[0];
521 
522         logi("updateCarrierConfiguration "
523                 + "imsRats=" + arrayToString(mImsRatsConfig,
524                         EmergencyCallDomainSelector::accessNetworkTypeToString)
525                 + ", csRats=" + arrayToString(mCsRatsConfig,
526                         EmergencyCallDomainSelector::accessNetworkTypeToString)
527                 + ", imsRoamRats=" + arrayToString(mImsRoamRatsConfig,
528                         EmergencyCallDomainSelector::accessNetworkTypeToString)
529                 + ", csRoamRats=" + arrayToString(mCsRoamRatsConfig,
530                         EmergencyCallDomainSelector::accessNetworkTypeToString)
531                 + ", domainPref=" + arrayToString(mDomainPreference,
532                         EmergencyCallDomainSelector::domainPreferenceToString)
533                 + ", domainPrefRoam=" + arrayToString(mDomainPreferenceRoam,
534                         EmergencyCallDomainSelector::domainPreferenceToString)
535                 + ", preferImsOnCs=" + mPreferImsWhenCallsOnCs
536                 + ", voWifiRequiresCondition=" + mVoWifiRequiresCondition
537                 + ", scanTimeout=" + mScanTimeout
538                 + ", maxCellularTimeout=" + mMaxCellularTimeout
539                 + ", maxNumOfVoWifiTries=" + mMaxNumOfVoWifiTries
540                 + ", voWifiOverEmergencyPdn=" + mVoWifiOverEmergencyPdn
541                 + ", preferredScanType=" + carrierConfigNetworkScanTypeToString(
542                         mPreferredNetworkScanType)
543                 + ", callSetupTimer=" + mCallSetupTimerOnCurrentRat
544                 + ", requiresImsReg=" + mRequiresImsRegistration
545                 + ", requiresVoLteEnabled=" + mRequiresVoLteEnabled
546                 + ", ltePreferredAfterNr=" + mLtePreferredAfterNrFailure
547                 + ", cdmaPreferredNumbers=" + arrayToString(numbers));
548 
549         mCdmaPreferredNumbers = Arrays.asList(numbers);
550 
551         if ((mPreferredNetworkScanType == CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE)
552                 || (mPreferredNetworkScanType
553                         == SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE)) {
554             mScanType = DomainSelectionService.SCAN_TYPE_FULL_SERVICE;
555         } else {
556             mScanType = DomainSelectionService.SCAN_TYPE_NO_PREFERENCE;
557         }
558     }
559 
selectDomain()560     private void selectDomain() {
561         // State updated right after creation.
562         if (!mDomainSelectionRequested) return;
563 
564         // Emergency network scan requested has not been completed.
565         if (mIsScanRequested) return;
566 
567         // Domain selection completed, {@link #reselectDomain()} will restart domain selection.
568         if (mDomainSelected) return;
569 
570         if (!mBarringInfoReceived || !mImsRegStateReceived || !mMmTelCapabilitiesReceived) {
571             logi("selectDomain not received"
572                     + " BarringInfo, IMS registration state, or MMTEL capabilities");
573             return;
574         }
575 
576         if (!allowEmergencyCalls(mSelectionAttributes.getEmergencyRegResult())) {
577             // Detected the country and found that emergency calls are not allowed with this slot.
578             terminateSelectionPermanentlyForSlot();
579             return;
580         }
581 
582         if (isWifiPreferred()) {
583             onWlanSelected();
584             return;
585         }
586 
587         onWwanSelected(this::selectDomainInternal);
588     }
589 
selectDomainInternal()590     private void selectDomainInternal() {
591         post(this::selectDomainFromInitialState);
592     }
593 
selectDomainFromInitialState()594     private void selectDomainFromInitialState() {
595         if (mIsTestEmergencyNumber) {
596             selectDomainForTestEmergencyNumber();
597             return;
598         }
599 
600         boolean csInService = isCsInService();
601         boolean psInService = isPsInService();
602 
603         if (!csInService && !psInService) {
604             mPsNetworkType = getSelectablePsNetworkType(false);
605             logi("selectDomain limited service ps=" + accessNetworkTypeToString(mPsNetworkType));
606             if (mPsNetworkType == UNKNOWN) {
607                 requestScan(true);
608             } else {
609                 onWwanNetworkTypeSelected(mPsNetworkType);
610             }
611             return;
612         }
613 
614         // Domain selection per 3GPP TS 23.167 Table H.1.
615         // PS is preferred in case selection between CS and PS is implementation option.
616         mCsNetworkType = UNKNOWN;
617         mPsNetworkType = UNKNOWN;
618         if (csInService) mCsNetworkType = getSelectableCsNetworkType();
619         if (psInService) mPsNetworkType = getSelectablePsNetworkType(true);
620 
621         boolean csAvailable = mCsNetworkType != UNKNOWN;
622         boolean psAvailable = mPsNetworkType != UNKNOWN;
623 
624         logi("selectDomain CS={" + csInService + ", " + accessNetworkTypeToString(mCsNetworkType)
625                 + "}, PS={" + psInService + ", " + accessNetworkTypeToString(mPsNetworkType) + "}");
626         if (csAvailable && psAvailable) {
627             if (mPreferImsWhenCallsOnCs || isImsRegisteredWithVoiceCapability()) {
628                 mTryCsWhenPsFails = true;
629                 onWwanNetworkTypeSelected(mPsNetworkType);
630             } else if (isDeactivatedSim()) {
631                 // Deactivated SIM but PS is in service and supports emergency calls.
632                 onWwanNetworkTypeSelected(mPsNetworkType);
633             } else {
634                 onWwanNetworkTypeSelected(mCsNetworkType);
635             }
636         } else if (psAvailable) {
637             mTryEpsFallback = (mPsNetworkType == NGRAN) && isEpsFallbackAvailable();
638             if (!mRequiresImsRegistration || isImsRegisteredWithVoiceCapability()) {
639                 onWwanNetworkTypeSelected(mPsNetworkType);
640             } else if (isDeactivatedSim()) {
641                 // Deactivated SIM but PS is in service and supports emergency calls.
642                 onWwanNetworkTypeSelected(mPsNetworkType);
643             } else {
644                 // Carrier configuration requires IMS registration for emergency services over PS,
645                 // but not registered. Try CS emergency call.
646                 mTryEpsFallback = false;
647                 requestScan(true, true);
648             }
649         } else if (csAvailable) {
650             onWwanNetworkTypeSelected(mCsNetworkType);
651         } else {
652             // PS is in service but not supports emergency calls.
653             if (mRequiresImsRegistration && !isImsRegisteredWithVoiceCapability()) {
654                 // Carrier configuration requires IMS registration for emergency services over PS,
655                 // but not registered. Try CS emergency call.
656                 requestScan(true, true);
657             } else {
658                 mTryEpsFallback = isEpsFallbackAvailable();
659                 requestScan(true);
660             }
661         }
662     }
663 
664     /**
665      * Requests network scan.
666      *
667      * @param startVoWifiTimer Indicates whether a VoWifi timer will be started.
668      */
requestScan(boolean startVoWifiTimer)669     private void requestScan(boolean startVoWifiTimer) {
670         requestScan(startVoWifiTimer, false);
671     }
672 
673     /**
674      * Requests network scan.
675      *
676      * @param startVoWifiTimer Indicates whether a VoWifi timer will be started.
677      * @param csPreferred Indicates whether CS preferred scan is requested.
678      */
requestScan(boolean startVoWifiTimer, boolean csPreferred)679     private void requestScan(boolean startVoWifiTimer, boolean csPreferred) {
680         requestScan(startVoWifiTimer, csPreferred, false);
681     }
682 
683     /**
684      * Requests network scan.
685      *
686      * @param startVoWifiTimer Indicates whether a VoWifi timer will be started.
687      * @param csPreferred Indicates whether CS preferred scan is requested.
688      * @param wifiFailed Indicates dialing over Wi-Fi has failed.
689      */
requestScan(boolean startVoWifiTimer, boolean csPreferred, boolean wifiFailed)690     private void requestScan(boolean startVoWifiTimer, boolean csPreferred, boolean wifiFailed) {
691         logi("requestScan timer=" + startVoWifiTimer + ", csPreferred=" + csPreferred
692                 + ", wifiFailed=" + wifiFailed);
693 
694         mCancelSignal = new CancellationSignal();
695         // In case dialing over Wi-Fi has failed, do not the change the domain preference.
696         if (!wifiFailed) {
697             mLastPreferredNetworks = getNextPreferredNetworks(csPreferred, mTryEpsFallback,
698                     !startVoWifiTimer);
699         }
700         mTryEpsFallback = false;
701 
702         if (isInRoaming()
703                 && (mPreferredNetworkScanType == DomainSelectionService.SCAN_TYPE_FULL_SERVICE)) {
704             // FULL_SERVICE only preference is available only when not in roaming.
705             mScanType = DomainSelectionService.SCAN_TYPE_NO_PREFERENCE;
706         }
707 
708         mIsScanRequested = true;
709         mWwanSelectorCallback.onRequestEmergencyNetworkScan(
710                 mLastPreferredNetworks, mScanType, mCancelSignal,
711                 (result) -> {
712                     logi("requestScan-onComplete");
713                     sendMessage(obtainMessage(MSG_NETWORK_SCAN_RESULT, result));
714                 });
715 
716         if (startVoWifiTimer && SubscriptionManager.isValidSubscriptionId(getSubId())) {
717             if (isEmcOverWifiSupported()
718                     && mScanTimeout > 0 && mVoWifiTrialCount < mMaxNumOfVoWifiTries) {
719                 logi("requestScan start scan timer");
720                 // remove any pending timers.
721                 removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
722                 sendEmptyMessageDelayed(MSG_NETWORK_SCAN_TIMEOUT, mScanTimeout);
723                 registerForConnectivityChanges();
724             }
725         }
726         if (!mMaxCellularTimerExpired && !hasMessages(MSG_MAX_CELLULAR_TIMEOUT)) {
727             startMaxCellularTimer();
728         }
729     }
730 
731     /**
732      * Gets the list of preferred network type for the new scan request.
733      *
734      * @param csPreferred Indicates whether CS preferred scan is requested.
735      * @param tryEpsFallback Indicates whether scan requested for EPS fallback.
736      * @param lastScanFailed Indicates whether this a scan request due to the failure of last scan
737      *        request.
738      * @return The list of preferred network types.
739      */
740     @VisibleForTesting
getNextPreferredNetworks(boolean csPreferred, boolean tryEpsFallback, boolean lastScanFailed)741     public @RadioAccessNetworkType List<Integer> getNextPreferredNetworks(boolean csPreferred,
742             boolean tryEpsFallback, boolean lastScanFailed) {
743         if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
744             // Emergency call over IMS is not supported.
745             logi("getNextPreferredNetworks VoLte setting is not enabled.");
746             return generatePreferredNetworks(getCsNetworkTypeConfiguration());
747         }
748 
749         List<Integer> preferredNetworks = new ArrayList<>();
750 
751         List<Integer> domains = getDomainPreference();
752         int psPriority = domains.indexOf(DOMAIN_PS_3GPP);
753         int csPriority = domains.indexOf(DOMAIN_CS);
754         logi("getNextPreferredNetworks psPriority=" + psPriority + ", csPriority=" + csPriority
755                 + ", csPreferred=" + csPreferred + ", epsFallback=" + tryEpsFallback
756                 + ", lastNetworkType=" + accessNetworkTypeToString(mLastNetworkType));
757 
758         if (!csPreferred && (mLastNetworkType == UNKNOWN || tryEpsFallback)) {
759             // Generate the list per the domain preference.
760 
761             if (psPriority == NOT_SUPPORTED && csPriority == NOT_SUPPORTED) {
762                 // should not reach here. However, to avoid unexpected problems.
763                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
764                         getImsNetworkTypeConfiguration());
765             } else if (psPriority == NOT_SUPPORTED && csPriority > NOT_SUPPORTED) {
766                 // CS networks only.
767                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration());
768             } else if (psPriority > NOT_SUPPORTED && csPriority == NOT_SUPPORTED) {
769                 // PS networks only.
770                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration());
771             } else if (psPriority < csPriority) {
772                 // PS preferred.
773                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration(),
774                         getCsNetworkTypeConfiguration());
775             } else {
776                 // CS preferred.
777                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
778                         getImsNetworkTypeConfiguration());
779             }
780 
781             // Make NGRAN have the lowest priority
782             if (tryEpsFallback && preferredNetworks.contains(NGRAN)) {
783                 preferredNetworks.remove(Integer.valueOf(NGRAN));
784                 preferredNetworks.add(NGRAN);
785             }
786         } else if (csPreferred || mLastNetworkType == EUTRAN || mLastNetworkType == NGRAN) {
787             if (!csPreferred && mLastNetworkType == NGRAN && mLtePreferredAfterNrFailure) {
788                 // LTE is preferred after dialing over NR failed.
789                 List<Integer> imsRats = getImsNetworkTypeConfiguration();
790                 imsRats.remove(Integer.valueOf(NGRAN));
791                 preferredNetworks = generatePreferredNetworks(imsRats,
792                         getCsNetworkTypeConfiguration());
793             } else  if (csPriority > NOT_SUPPORTED) {
794                 // PS tried, generate the list with CS preferred.
795                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration(),
796                         getImsNetworkTypeConfiguration());
797             } else {
798                 // CS not suppored.
799                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration());
800             }
801         } else {
802             // CS tried, generate the list with PS preferred.
803             if (psPriority > NOT_SUPPORTED) {
804                 preferredNetworks = generatePreferredNetworks(getImsNetworkTypeConfiguration(),
805                         getCsNetworkTypeConfiguration());
806             } else {
807                 // PS not suppored.
808                 preferredNetworks = generatePreferredNetworks(getCsNetworkTypeConfiguration());
809             }
810         }
811 
812         // There can be cases that dialing IMS call failed but the modem doesn't know this
813         // situation with some vendor solutions. For example, dialing failure due to the
814         // emergency registration failure.
815         // Remove the current RAT from the scan list to avoid modem select current PLMN.
816         // If the scan fails, the next scan will include this RAT again.
817         //
818         // TODO (b/278183420) Replace this with a better solution by adding indication
819         // of call setup failure to the scan request.
820         ImsReasonInfo reasonInfo = mSelectionAttributes.getPsDisconnectCause();
821         if (!lastScanFailed && reasonInfo != null
822                 && reasonInfo.getCode() == ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED) {
823             logi("getNextPreferredNetworks remove " + mLastNetworkType);
824             if (preferredNetworks.size() > 1) {
825                 preferredNetworks.remove(Integer.valueOf(mLastNetworkType));
826             }
827         }
828 
829         return preferredNetworks;
830     }
831 
generatePreferredNetworks(List<Integer>....lists)832     private @RadioAccessNetworkType List<Integer> generatePreferredNetworks(List<Integer>...lists) {
833         List<Integer> preferredNetworks = new ArrayList<>();
834         for (List<Integer> list : lists) {
835             preferredNetworks.addAll(list);
836         }
837 
838         return preferredNetworks;
839     }
840 
handleMaxCellularTimeout()841     private void handleMaxCellularTimeout() {
842         logi("handleMaxCellularTimeout");
843         if (mVoWifiTrialCount >= mMaxNumOfVoWifiTries) {
844             logi("handleMaxCellularTimeout already tried maximum");
845             return;
846         }
847 
848         mMaxCellularTimerExpired = true;
849 
850         if (mDomainSelected) {
851             // Dialing is already requested.
852             logi("handleMaxCellularTimeout wait for reselectDomain");
853             return;
854         }
855 
856         if (!maybeDialOverWlan()) {
857             logd("handleMaxCellularTimeout VoWi-Fi is not available");
858         }
859     }
860 
handleNetworkScanTimeout()861     private void handleNetworkScanTimeout() {
862         logi("handleNetworkScanTimeout");
863         maybeDialOverWlan();
864     }
865 
maybeDialOverWlan()866     private boolean maybeDialOverWlan() {
867         logi("maybeDialOverWlan overEmergencyPdn=" + mVoWifiOverEmergencyPdn
868                 + ", wifiAvailable=" + mWiFiAvailable);
869         boolean available = mWiFiAvailable;
870         if (mVoWifiOverEmergencyPdn) {
871             // SOS APN
872             if (!available && isImsRegisteredOverCrossSim()) {
873                 available = true;
874             }
875             if (available) {
876                 switch (mVoWifiRequiresCondition) {
877                     case VOWIFI_REQUIRES_SETTING_ENABLED:
878                         available = isWifiCallingSettingEnabled();
879                         break;
880                     case VOWIFI_REQUIRES_VALID_EID:
881                         available = isWifiCallingActivated();
882                         break;
883                     default:
884                         break;
885                 }
886             }
887         } else {
888             // IMS APN. When IMS is already registered over Wi-Fi.
889             available = isImsRegisteredWithVoiceCapability() && isImsRegisteredOverWifi();
890         }
891 
892         logi("maybeDialOverWlan VoWi-Fi available=" + available);
893         if (available) {
894             if (mCancelSignal != null) {
895                 mCancelSignal.cancel();
896                 mCancelSignal = null;
897             }
898             onWlanSelected();
899         }
900 
901         return available;
902     }
903 
904     /**
905      * Determines whether CS is in service.
906      *
907      * @return {@code true} if CS is in service.
908      */
isCsInService()909     private boolean isCsInService() {
910         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
911         if (regResult == null) return false;
912 
913         int regState = regResult.getRegState();
914         int domain = regResult.getDomain();
915 
916         if ((regState == REGISTRATION_STATE_HOME || regState == REGISTRATION_STATE_ROAMING)
917                 && ((domain & NetworkRegistrationInfo.DOMAIN_CS) > 0)) {
918             return true;
919         }
920 
921         return false;
922     }
923 
924     /**
925      * Determines the network type of the circuit-switched(CS) network.
926      *
927      * @return The network type of the CS network.
928      */
getSelectableCsNetworkType()929     private @RadioAccessNetworkType int getSelectableCsNetworkType() {
930         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
931         logi("getSelectableCsNetworkType regResult=" + regResult);
932         if (regResult == null) return UNKNOWN;
933 
934         int accessNetwork = regResult.getAccessNetwork();
935 
936         List<Integer> ratList = getCsNetworkTypeConfiguration();
937         if (ratList.contains(accessNetwork)) {
938             return accessNetwork;
939         }
940 
941         if ((regResult.getAccessNetwork() == EUTRAN)
942                 && ((regResult.getDomain() & NetworkRegistrationInfo.DOMAIN_CS) > 0)) {
943             if (ratList.contains(UTRAN)) return UTRAN;
944         }
945 
946         return UNKNOWN;
947     }
948 
949     /**
950      * Determines whether PS is in service.
951      *
952      * @return {@code true} if PS is in service.
953      */
isPsInService()954     private boolean isPsInService() {
955         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
956         if (regResult == null) return false;
957 
958         int regState = regResult.getRegState();
959         int domain = regResult.getDomain();
960 
961         if ((regState == REGISTRATION_STATE_HOME || regState == REGISTRATION_STATE_ROAMING)
962                 && ((domain & NetworkRegistrationInfo.DOMAIN_PS) > 0)) {
963             return true;
964         }
965 
966         return false;
967     }
968 
969     /**
970      * Determines the network type supporting emergency services over packet-switched(PS) network.
971      *
972      * @param inService Indicates whether PS is IN_SERVICE state.
973      * @return The network type if the network supports emergency services over PS network.
974      */
getSelectablePsNetworkType(boolean inService)975     private @RadioAccessNetworkType int getSelectablePsNetworkType(boolean inService) {
976         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
977         logi("getSelectablePsNetworkType regResult=" + regResult);
978         if (regResult == null) return UNKNOWN;
979         if (mRequiresVoLteEnabled && !isAdvancedCallingSettingEnabled()) {
980             // Emergency call over IMS is not supported.
981             logi("getSelectablePsNetworkType VoLte setting is not enabled.");
982             return UNKNOWN;
983         }
984 
985         int accessNetwork = regResult.getAccessNetwork();
986         List<Integer> ratList = getImsNetworkTypeConfiguration();
987         if (ratList.contains(accessNetwork)) {
988             if (mIsEmergencyBarred) {
989                 logi("getSelectablePsNetworkType barred");
990                 return UNKNOWN;
991             }
992             if (accessNetwork == NGRAN) {
993                 return (regResult.getNwProvidedEmc() > 0 && regResult.isVopsSupported())
994                         ? NGRAN : UNKNOWN;
995             } else if (accessNetwork == EUTRAN) {
996                 return (regResult.isEmcBearerSupported()
997                                 && (regResult.isVopsSupported() || !inService))
998                         ? EUTRAN : UNKNOWN;
999             }
1000         }
1001 
1002         return UNKNOWN;
1003     }
1004 
isEpsFallbackAvailable()1005     private boolean isEpsFallbackAvailable() {
1006         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
1007         if (regResult == null) return false;
1008 
1009         List<Integer> ratList = getImsNetworkTypeConfiguration();
1010         if (ratList.contains(EUTRAN)) {
1011             return (regResult.getNwProvidedEmf() > 0);
1012         }
1013         return false;
1014     }
1015 
1016     /**
1017      * Determines whether the SIM is a deactivated one.
1018      *
1019      * @return {@code true} if the SIM is a deactivated one.
1020      */
isDeactivatedSim()1021     private boolean isDeactivatedSim() {
1022         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1023             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1024             tm = tm.createForSubscriptionId(getSubId());
1025             int state = tm.getDataActivationState();
1026             logi("isDeactivatedSim state=" + state);
1027             return (state == TelephonyManager.SIM_ACTIVATION_STATE_DEACTIVATED);
1028         }
1029         return false;
1030     }
1031 
1032     /**
1033      * Determines whether emergency call over Wi-Fi is allowed.
1034      *
1035      * @return {@code true} if emergency call over Wi-Fi allowed.
1036      */
isEmcOverWifiSupported()1037     private boolean isEmcOverWifiSupported() {
1038         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1039             List<Integer> domains = getDomainPreference();
1040             boolean ret = domains.contains(DOMAIN_PS_NON_3GPP);
1041             logi("isEmcOverWifiSupported " + ret);
1042             return ret;
1043         } else {
1044             logi("isEmcOverWifiSupported invalid subId");
1045         }
1046         return false;
1047     }
1048 
1049     /**
1050      * Determines whether Wi-Fi is preferred when IMS registered over Wi-Fi.
1051      *
1052      * @return {@code true} if Wi-Fi is preferred when IMS registered over Wi-Fi.
1053      */
isWifiPreferred()1054     private boolean isWifiPreferred() {
1055         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1056             List<Integer> domains = getDomainPreference();
1057             int priority = domains.indexOf(DOMAIN_PS_NON_3GPP);
1058             logi("isWifiPreferred priority=" + priority);
1059 
1060             if ((priority == 0)
1061                     && isImsRegisteredWithVoiceCapability()
1062                     && isImsRegisteredOverWifi()) {
1063                 logi("isWifiPreferred try emergency call over Wi-Fi");
1064                 return true;
1065             }
1066         }
1067 
1068         return false;
1069     }
1070 
isAdvancedCallingSettingEnabled()1071     private boolean isAdvancedCallingSettingEnabled() {
1072         try {
1073             if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1074                 ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
1075                 ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
1076                 boolean result = mmTelManager.isAdvancedCallingSettingEnabled();
1077                 logi("isAdvancedCallingSettingEnabled " + result);
1078                 return result;
1079             }
1080         } catch (Exception e) {
1081             logi("isAdvancedCallingSettingEnabled e=" + e);
1082         }
1083         return true;
1084     }
1085 
isWifiCallingActivated()1086     private boolean isWifiCallingActivated() {
1087         try {
1088             ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
1089             ProvisioningManager pm = imsMngr.getProvisioningManager(getSubId());
1090             String eid = pm.getProvisioningStringValue(
1091                     ProvisioningManager.KEY_VOICE_OVER_WIFI_ENTITLEMENT_ID);
1092             boolean activated = (!TextUtils.isEmpty(eid)) && (!TextUtils.equals("0", eid));
1093             logi("isWifiCallingActivated " + activated);
1094             return activated;
1095         } catch (Exception e) {
1096             logi("isWifiCallingActivated e=" + e);
1097         }
1098         return false;
1099     }
1100 
isWifiCallingSettingEnabled()1101     private boolean isWifiCallingSettingEnabled() {
1102         boolean result = false;
1103         try {
1104             if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1105                 ImsManager imsMngr = mContext.getSystemService(ImsManager.class);
1106                 ImsMmTelManager mmTelManager = imsMngr.getImsMmTelManager(getSubId());
1107                 if (isInRoaming()) {
1108                     result = mmTelManager.isVoWiFiRoamingSettingEnabled();
1109                 } else {
1110                     result = mmTelManager.isVoWiFiSettingEnabled();
1111                 }
1112                 logi("isWifiCallingSettingEnabled " + result);
1113                 return result;
1114             }
1115         } catch (Exception e) {
1116             logi("isWifiCallingSettingEnabled e=" + e);
1117         }
1118         return result;
1119     }
1120 
getImsNetworkTypeConfiguration()1121     private @NonNull List<Integer> getImsNetworkTypeConfiguration() {
1122         int[] rats = mImsRatsConfig;
1123         if (isInRoaming()) rats = mImsRoamRatsConfig;
1124 
1125         List<Integer> ratList = new ArrayList<Integer>();
1126         for (int i = 0; i < rats.length; i++) {
1127             ratList.add(rats[i]);
1128         }
1129         return ratList;
1130     }
1131 
getCsNetworkTypeConfiguration()1132     private @NonNull List<Integer> getCsNetworkTypeConfiguration() {
1133         int[] rats = mCsRatsConfig;
1134         if (isInRoaming()) rats = mCsRoamRatsConfig;
1135 
1136         List<Integer> ratList = new ArrayList<Integer>();
1137         for (int i = 0; i < rats.length; i++) {
1138             ratList.add(rats[i]);
1139         }
1140 
1141         if (!mCdmaPreferredNumbers.isEmpty()) {
1142             if (mCdmaPreferredNumbers.contains(mSelectionAttributes.getNumber())) {
1143                 // The number will be dialed over CDMA.
1144                 ratList.clear();
1145                 ratList.add(new Integer(CDMA2000));
1146             } else {
1147                 // The number will be dialed over UTRAN or GERAN.
1148                 ratList.remove(new Integer(CDMA2000));
1149             }
1150         }
1151 
1152         return ratList;
1153     }
1154 
getDomainPreference()1155     private @NonNull List<Integer> getDomainPreference() {
1156         int[] domains = mDomainPreference;
1157         if (isInRoaming()) domains = mDomainPreferenceRoam;
1158 
1159         List<Integer> domainList = new ArrayList<Integer>();
1160         for (int i = 0; i < domains.length; i++) {
1161             domainList.add(domains[i]);
1162         }
1163         return domainList;
1164     }
1165 
isInRoaming()1166     private boolean isInRoaming() {
1167         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) return false;
1168 
1169         TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1170         tm = tm.createForSubscriptionId(getSubId());
1171         String netIso = tm.getNetworkCountryIso();
1172 
1173         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
1174         if (regResult != null) {
1175             if (regResult.getRegState() == REGISTRATION_STATE_HOME) return false;
1176             if (regResult.getRegState() == REGISTRATION_STATE_ROAMING) return true;
1177 
1178             String iso = regResult.getIso();
1179             if (!TextUtils.isEmpty(iso)) netIso = iso;
1180         }
1181 
1182         String simIso = tm.getSimCountryIso();
1183         logi("isInRoaming simIso=" + simIso + ", netIso=" + netIso);
1184 
1185         if (TextUtils.isEmpty(simIso)) return false;
1186         if (TextUtils.isEmpty(netIso)) return false;
1187 
1188         return !(TextUtils.equals(simIso, netIso));
1189     }
1190 
1191     /**
1192      * Determines whether IMS is registered over Wi-Fi.
1193      *
1194      * @return {@code true} if IMS is registered over Wi-Fi.
1195      */
isImsRegisteredOverWifi()1196     private boolean isImsRegisteredOverWifi() {
1197         boolean ret = false;
1198         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1199             ret = mImsStateTracker.isImsRegisteredOverWlan();
1200         }
1201 
1202         logi("isImsRegisteredOverWifi " + ret);
1203         return ret;
1204     }
1205 
1206     /**
1207      * Determines whether IMS is registered over the mobile data of another subscription.
1208      *
1209      * @return {@code true} if IMS is registered over the mobile data of another subscription.
1210      */
isImsRegisteredOverCrossSim()1211     private boolean isImsRegisteredOverCrossSim() {
1212         boolean ret = false;
1213         if (SubscriptionManager.isValidSubscriptionId(getSubId())) {
1214             ret = mImsStateTracker.isImsRegisteredOverCrossSim();
1215         }
1216 
1217         logi("isImsRegisteredOverCrossSim " + ret);
1218         return ret;
1219     }
1220 
1221     /**
1222      * Determines whether IMS is registered with voice capability.
1223      *
1224      * @return {@code true} if IMS is registered with voice capability.
1225      */
isImsRegisteredWithVoiceCapability()1226     private boolean isImsRegisteredWithVoiceCapability() {
1227         boolean ret = mImsRegistered && mIsVoiceCapable;
1228 
1229         logi("isImsRegisteredWithVoiceCapability " + ret);
1230         return ret;
1231     }
1232 
onWlanSelected()1233     private void onWlanSelected() {
1234         logi("onWlanSelected");
1235         if (mLastTransportType == TRANSPORT_TYPE_WLAN) {
1236             logi("onWlanSelected ignore duplicated callback");
1237             return;
1238         }
1239 
1240         mDomainSelected = true;
1241         mLastTransportType = TRANSPORT_TYPE_WLAN;
1242         mVoWifiTrialCount++;
1243         mTransportSelectorCallback.onWlanSelected(mVoWifiOverEmergencyPdn);
1244         mWwanSelectorCallback = null;
1245         removeMessages(MSG_NETWORK_SCAN_TIMEOUT);
1246         removeMessages(MSG_MAX_CELLULAR_TIMEOUT);
1247     }
1248 
onWwanSelected(Runnable runnable)1249     private void onWwanSelected(Runnable runnable) {
1250         logi("onWwanSelected");
1251         if (mLastTransportType == TRANSPORT_TYPE_WWAN) {
1252             logi("onWwanSelected ignore duplicated callback");
1253             return;
1254         }
1255 
1256         mLastTransportType = TRANSPORT_TYPE_WWAN;
1257         mTransportSelectorCallback.onWwanSelected((callback) -> {
1258             mWwanSelectorCallback = callback;
1259             runnable.run();
1260         });
1261     }
1262 
onWwanNetworkTypeSelected(@adioAccessNetworkType int accessNetworkType)1263     private void onWwanNetworkTypeSelected(@RadioAccessNetworkType int accessNetworkType) {
1264         logi("onWwanNetworkTypeSelected " + accessNetworkTypeToString(accessNetworkType));
1265         if (mWwanSelectorCallback == null) {
1266             logi("onWwanNetworkTypeSelected callback is null");
1267             return;
1268         }
1269 
1270         mDomainSelected = true;
1271         mLastNetworkType = accessNetworkType;
1272         int domain = NetworkRegistrationInfo.DOMAIN_CS;
1273         if (accessNetworkType == EUTRAN || accessNetworkType == NGRAN) {
1274             domain = NetworkRegistrationInfo.DOMAIN_PS;
1275         }
1276         mWwanSelectorCallback.onDomainSelected(domain,
1277                 (domain == NetworkRegistrationInfo.DOMAIN_PS));
1278     }
1279 
1280     /**
1281      * Registers for changes to network connectivity.
1282      */
registerForConnectivityChanges()1283     private void registerForConnectivityChanges() {
1284         if (mIsMonitoringConnectivity) {
1285             return;
1286         }
1287 
1288         ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1289         if (cm != null) {
1290             logi("registerForConnectivityChanges");
1291             NetworkRequest.Builder builder = new NetworkRequest.Builder();
1292             builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
1293             cm.registerNetworkCallback(builder.build(), mNetworkCallback);
1294             mIsMonitoringConnectivity = true;
1295         }
1296     }
1297 
1298     /**
1299      * Unregisters for connectivity changes.
1300      */
unregisterForConnectivityChanges()1301     private void unregisterForConnectivityChanges() {
1302         if (!mIsMonitoringConnectivity) {
1303             return;
1304         }
1305 
1306         ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1307         if (cm != null) {
1308             logi("unregisterForConnectivityChanges");
1309             cm.unregisterNetworkCallback(mNetworkCallback);
1310             mIsMonitoringConnectivity = false;
1311         }
1312     }
1313 
1314     /** Starts the max cellular timer. */
startMaxCellularTimer()1315     private void startMaxCellularTimer() {
1316         logd("startMaxCellularTimer tried=" + mVoWifiTrialCount
1317                 + ", max=" + mMaxNumOfVoWifiTries);
1318         if (isEmcOverWifiSupported()
1319                 && (mMaxCellularTimeout > 0)
1320                 && (mVoWifiTrialCount < mMaxNumOfVoWifiTries)) {
1321             logi("startMaxCellularTimer start timer");
1322             sendEmptyMessageDelayed(MSG_MAX_CELLULAR_TIMEOUT, mMaxCellularTimeout);
1323             registerForConnectivityChanges();
1324         }
1325     }
1326 
allowEmergencyCalls(EmergencyRegResult regResult)1327     private boolean allowEmergencyCalls(EmergencyRegResult regResult) {
1328         if (mModemCount < 2) return true;
1329         if (regResult == null) {
1330             loge("allowEmergencyCalls null regResult");
1331             return true;
1332         }
1333 
1334         String iso = regResult.getIso();
1335         if (sAllowOnlyWithSimReady.contains(iso)) {
1336             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1337             int simState = tm.getSimState(getSlotId());
1338             if (simState != TelephonyManager.SIM_STATE_READY) {
1339                 logi("allowEmergencyCalls not ready, simState=" + simState + ", iso=" + iso);
1340                 if (mCrossSimRedialingController.isThereOtherSlot()) {
1341                     return false;
1342                 }
1343                 logi("allowEmergencyCalls there is no other slot available");
1344             }
1345         }
1346 
1347         return true;
1348     }
1349 
terminateSelectionPermanentlyForSlot()1350     private void terminateSelectionPermanentlyForSlot() {
1351         logi("terminateSelectionPermanentlyForSlot");
1352         terminateSelection(true);
1353     }
1354 
terminateSelectionForCrossSimRedialing(boolean permanent)1355     private void terminateSelectionForCrossSimRedialing(boolean permanent) {
1356         logi("terminateSelectionForCrossSimRedialing perm=" + permanent);
1357         terminateSelection(permanent);
1358     }
1359 
terminateSelection(boolean permanent)1360     private void terminateSelection(boolean permanent) {
1361         mTransportSelectorCallback.onSelectionTerminated(permanent
1362                 ? DisconnectCause.EMERGENCY_PERM_FAILURE
1363                 : DisconnectCause.EMERGENCY_TEMP_FAILURE);
1364 
1365         if (mIsScanRequested && mCancelSignal != null) {
1366             mCancelSignal.cancel();
1367             mCancelSignal = null;
1368         }
1369     }
1370 
1371     /** Starts the cross stack timer. */
startCrossStackTimer()1372     public void startCrossStackTimer() {
1373         boolean inService = false;
1374         boolean inRoaming = false;
1375 
1376         if (mModemCount == 1) return;
1377 
1378         EmergencyRegResult regResult = mSelectionAttributes.getEmergencyRegResult();
1379         if (regResult != null) {
1380             int regState = regResult.getRegState();
1381 
1382             if ((regResult.getDomain() > 0)
1383                     && (regState == REGISTRATION_STATE_HOME
1384                             || regState == REGISTRATION_STATE_ROAMING)) {
1385                 inService = true;
1386             }
1387             inRoaming = (regState == REGISTRATION_STATE_ROAMING) || isInRoaming();
1388         }
1389 
1390         mCrossSimRedialingController.startTimer(mContext, this, mSelectionAttributes.getCallId(),
1391                 mSelectionAttributes.getNumber(), inService, inRoaming, mModemCount);
1392     }
1393 
1394     /** Notifies that the cross stack redilaing timer has been expired. */
notifyCrossStackTimerExpired()1395     public void notifyCrossStackTimerExpired() {
1396         logi("notifyCrossStackTimerExpired");
1397 
1398         mCrossStackTimerExpired = true;
1399         if (mDomainSelected) {
1400             // When reselecting domain, terminateSelection will be called.
1401             return;
1402         }
1403         terminateSelectionForCrossSimRedialing(false);
1404     }
1405 
arrayToString(int[] intArray, IntFunction<String> func)1406     private static String arrayToString(int[] intArray, IntFunction<String> func) {
1407         int length = intArray.length;
1408         StringBuilder sb = new StringBuilder("{");
1409         if (length > 0) {
1410             int i = 0;
1411             sb.append(func.apply(intArray[i++]));
1412             while (i < length) {
1413                 sb.append(", ").append(func.apply(intArray[i++]));
1414             }
1415         }
1416         sb.append("}");
1417         return sb.toString();
1418     }
1419 
arrayToString(String[] stringArray)1420     private static String arrayToString(String[] stringArray) {
1421         StringBuilder sb;
1422         int length = stringArray.length;
1423         sb = new StringBuilder("{");
1424         if (length > 0) {
1425             int i = 0;
1426             sb.append(stringArray[i++]);
1427             while (i < length) {
1428                 sb.append(", ").append(stringArray[i++]);
1429             }
1430         }
1431         sb.append("}");
1432         return sb.toString();
1433     }
1434 
domainPreferenceToString( @arrierConfigManager.ImsEmergency.EmergencyDomain int domain)1435     private static String domainPreferenceToString(
1436             @CarrierConfigManager.ImsEmergency.EmergencyDomain int domain) {
1437         switch (domain) {
1438             case DOMAIN_CS: return "CS";
1439             case DOMAIN_PS_3GPP: return "PS_3GPP";
1440             case DOMAIN_PS_NON_3GPP: return "PS_NON_3GPP";
1441             default: return "UNKNOWN";
1442         }
1443     }
1444 
carrierConfigNetworkScanTypeToString( @arrierConfigManager.ImsEmergency.EmergencyScanType int scanType)1445     private static String carrierConfigNetworkScanTypeToString(
1446             @CarrierConfigManager.ImsEmergency.EmergencyScanType int scanType) {
1447         switch (scanType) {
1448             case CarrierConfigManager.ImsEmergency.SCAN_TYPE_NO_PREFERENCE: return "NO_PREF";
1449             case CarrierConfigManager.ImsEmergency.SCAN_TYPE_FULL_SERVICE: return "FULL";
1450             case SCAN_TYPE_FULL_SERVICE_FOLLOWED_BY_LIMITED_SERVICE: return "FULL_N_LIMITED";
1451             default: return "UNKNOWN";
1452         }
1453     }
1454 
accessNetworkTypeToString( @adioAccessNetworkType int accessNetworkType)1455     private static String accessNetworkTypeToString(
1456             @RadioAccessNetworkType int accessNetworkType) {
1457         switch (accessNetworkType) {
1458             case AccessNetworkType.UNKNOWN: return "UNKNOWN";
1459             case AccessNetworkType.GERAN: return "GERAN";
1460             case AccessNetworkType.UTRAN: return "UTRAN";
1461             case AccessNetworkType.EUTRAN: return "EUTRAN";
1462             case AccessNetworkType.CDMA2000: return "CDMA2000";
1463             case AccessNetworkType.IWLAN: return "IWLAN";
1464             case AccessNetworkType.NGRAN: return "NGRAN";
1465             default: return Integer.toString(accessNetworkType);
1466         }
1467     }
1468 
1469     /**
1470      * Destroys the instance.
1471      */
1472     @VisibleForTesting
destroy()1473     public void destroy() {
1474         if (DBG) logd("destroy");
1475 
1476         mCrossSimRedialingController.stopTimer();
1477         releaseWakeLock();
1478 
1479         mDestroyed = true;
1480         mImsStateTracker.removeBarringInfoListener(this);
1481         mImsStateTracker.removeImsStateListener(this);
1482         unregisterForConnectivityChanges();
1483 
1484         super.destroy();
1485     }
1486 
acquireWakeLock()1487     private void acquireWakeLock() {
1488         if (mPartialWakeLock != null) {
1489             synchronized (mPartialWakeLock) {
1490                 logi("acquireWakeLock");
1491                 mPartialWakeLock.acquire();
1492             }
1493         }
1494     }
1495 
releaseWakeLock()1496     private void releaseWakeLock() {
1497         if (mPartialWakeLock != null) {
1498             synchronized (mPartialWakeLock) {
1499                 if (mPartialWakeLock.isHeld()) {
1500                     logi("releaseWakeLock");
1501                     mPartialWakeLock.release();
1502                 }
1503             }
1504         }
1505     }
1506 
selectDomainForTestEmergencyNumber()1507     private void selectDomainForTestEmergencyNumber() {
1508         logi("selectDomainForTestEmergencyNumber");
1509         if (isImsRegisteredWithVoiceCapability()) {
1510             onWwanNetworkTypeSelected(EUTRAN);
1511         } else {
1512             onWwanNetworkTypeSelected(UTRAN);
1513         }
1514     }
1515 
isTestEmergencyNumber(String number)1516     private boolean isTestEmergencyNumber(String number) {
1517         number = PhoneNumberUtils.stripSeparators(number);
1518         Map<Integer, List<EmergencyNumber>> list = new HashMap<>();
1519         try {
1520             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
1521             list = tm.getEmergencyNumberList();
1522         } catch (IllegalStateException ise) {
1523             loge("isTestEmergencyNumber ise=" + ise);
1524         }
1525 
1526         for (Integer sub : list.keySet()) {
1527             for (EmergencyNumber eNumber : list.get(sub)) {
1528                 if (number.equals(eNumber.getNumber())
1529                         && eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST)) {
1530                     logd("isTestEmergencyNumber: " + number + " is a test emergency number.");
1531                     return true;
1532                 }
1533             }
1534         }
1535         return false;
1536     }
1537 
1538     @Override
logi(String msg)1539     protected void logi(String msg) {
1540         super.logi(msg);
1541         sLocalLog.log(msg);
1542     }
1543 
1544     @Override
loge(String msg)1545     protected void loge(String msg) {
1546         super.loge(msg);
1547         sLocalLog.log(msg);
1548     }
1549 }
1550