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 android.annotation.NonNull;
20 import android.content.Context;
21 import android.os.CancellationSignal;
22 import android.os.Looper;
23 import android.os.Message;
24 import android.os.PersistableBundle;
25 import android.telephony.AccessNetworkConstants;
26 import android.telephony.AccessNetworkConstants.AccessNetworkType;
27 import android.telephony.BarringInfo;
28 import android.telephony.CarrierConfigManager;
29 import android.telephony.DataSpecificRegistrationInfo;
30 import android.telephony.DomainSelectionService;
31 import android.telephony.EmergencyRegistrationResult;
32 import android.telephony.NetworkRegistrationInfo;
33 import android.telephony.ServiceState;
34 import android.telephony.TelephonyManager;
35 import android.telephony.VopsSupportInfo;
36 
37 import com.android.internal.annotations.VisibleForTesting;
38 
39 import java.util.List;
40 
41 /**
42  * Implements an emergency SMS domain selector for sending an emergency SMS.
43  */
44 public class EmergencySmsDomainSelector extends SmsDomainSelector implements
45         ImsStateTracker.BarringInfoListener, ImsStateTracker.ServiceStateListener {
46     protected static final int EVENT_EMERGENCY_NETWORK_SCAN_RESULT = 201;
47     /**
48      * Stores the configuration value of
49      * {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL}.
50      * This value is always updated whenever the domain selection is requested.
51      */
52     private Boolean mEmergencySmsOverImsSupportedByConfig;
53     private ServiceState mServiceState;
54     private boolean mServiceStateReceived;
55     private BarringInfo mBarringInfo;
56     private boolean mBarringInfoReceived;
57     private boolean mEmergencyNetworkScanInProgress;
58     private CancellationSignal mEmergencyNetworkScanSignal;
59 
EmergencySmsDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener listener)60     public EmergencySmsDomainSelector(Context context, int slotId, int subId,
61             @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
62             @NonNull DestroyListener listener) {
63         super(context, slotId, subId, looper, imsStateTracker, listener,
64                 "DomainSelector-EmergencySMS");
65 
66         mImsStateTracker.addServiceStateListener(this);
67         mImsStateTracker.addBarringInfoListener(this);
68     }
69 
70     @Override
destroy()71     public void destroy() {
72         if (mDestroyed) {
73             return;
74         }
75         mImsStateTracker.removeServiceStateListener(this);
76         mImsStateTracker.removeBarringInfoListener(this);
77         super.destroy();
78     }
79 
80     @Override
handleMessage(@onNull Message msg)81     public void handleMessage(@NonNull Message msg) {
82         switch (msg.what) {
83             case EVENT_EMERGENCY_NETWORK_SCAN_RESULT:
84                 handleEmergencyNetworkScanResult((EmergencyRegistrationResult) msg.obj);
85                 break;
86             default:
87                 super.handleMessage(msg);
88                 break;
89         }
90     }
91 
92     @Override
finishSelection()93     public void finishSelection() {
94         super.finishSelection();
95         mServiceStateReceived = false;
96         mServiceState = null;
97         mBarringInfoReceived = false;
98         mBarringInfo = null;
99         mEmergencySmsOverImsSupportedByConfig = null;
100 
101         mEmergencyNetworkScanInProgress = false;
102         if (mEmergencyNetworkScanSignal != null) {
103             mEmergencyNetworkScanSignal.cancel();
104             mEmergencyNetworkScanSignal = null;
105         }
106     }
107 
108     @Override
onBarringInfoUpdated(BarringInfo barringInfo)109     public void onBarringInfoUpdated(BarringInfo barringInfo) {
110         mBarringInfoReceived = true;
111         mBarringInfo = barringInfo;
112         sendMessageForDomainSelection();
113     }
114 
115     @Override
onServiceStateUpdated(ServiceState serviceState)116     public void onServiceStateUpdated(ServiceState serviceState) {
117         mServiceStateReceived = true;
118         mServiceState = serviceState;
119         sendMessageForDomainSelection();
120     }
121 
122     /**
123      * Checks whether the domain selector is ready to select the domain or not.
124      * The emergency SMS requires to be updated for the {@link ServiceState} and
125      * {@link BarringInfo} to confirm that the cellular network supports to send emergency SMS
126      * messages over IMS.
127      */
128     @VisibleForTesting
isDomainSelectionReady()129     public boolean isDomainSelectionReady() {
130         return mServiceStateReceived && mBarringInfoReceived;
131     }
132 
133     @Override
isSmsOverImsAvailable()134     protected boolean isSmsOverImsAvailable() {
135         if (super.isSmsOverImsAvailable()) {
136             /**
137              * Even though IMS is successfully registered, the cellular domain should be
138              * available for the emergency SMS according to the carrier's requirement
139              * when {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL} is set
140              * to true.
141              */
142             if (isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService()) {
143                 /**
144                  * Emergency SMS should be supported via emergency PDN.
145                  * If this condition is false, then need to fallback to CS network
146                  * because the current PS network does not allow the emergency service.
147                  */
148                 return isNetworkAvailableForImsEmergencySms();
149             }
150 
151             // Emergency SMS is supported via IMS PDN.
152             return true;
153         }
154 
155         return isImsEmergencySmsAvailable();
156     }
157 
158     @Override
selectDomain()159     protected void selectDomain() {
160         if (!isDomainSelectionRequested()) {
161             logi("Domain selection is not requested!");
162             return;
163         }
164 
165         if (!isDomainSelectionReady()) {
166             logd("Wait for the readiness of the domain selection!");
167             return;
168         }
169 
170         if (mEmergencyNetworkScanInProgress) {
171             logi("Emergency network scan is in progress.");
172             return;
173         }
174 
175         logi("selectDomain: " + mImsStateTracker.imsStateToString());
176 
177         if (isSmsOverImsAvailable()) {
178             boolean isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService =
179                     isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService();
180 
181             if (mImsStateTracker.isImsRegisteredOverWlan()) {
182                 /**
183                  * When {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL}
184                  * is set to true, the emergency SMS supports on the LTE/NR network using the
185                  * emergency PDN. As of now, since the emergency SMS doesn't use the emergency PDN
186                  * over WLAN, the domain selector reports the domain as WLAN only if
187                  * {@code isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService} is set to false
188                  * and IMS is registered over WLAN.
189                  * Otherwise, the domain selector reports the domain as WWAN.
190                  */
191                 if (!isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService) {
192                     notifyWlanSelected(false);
193                     return;
194                 }
195 
196                 logi("DomainSelected: WLAN >> WWAN");
197             }
198 
199             /**
200              * The request of emergency network scan triggers the modem to request the emergency
201              * service fallback because NR network doesn't support the emergency service.
202              */
203             if (isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService
204                     && isNrEmergencyServiceFallbackRequired()) {
205                 requestEmergencyNetworkScan(List.of(AccessNetworkType.EUTRAN));
206             } else {
207                 notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_PS,
208                         isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService);
209             }
210         } else {
211             notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_CS, false);
212         }
213     }
214 
requestEmergencyNetworkScan(List<Integer> preferredNetworks)215     private void requestEmergencyNetworkScan(List<Integer> preferredNetworks) {
216         mEmergencyNetworkScanInProgress = true;
217 
218         if (mWwanSelectorCallback == null) {
219             mTransportSelectorCallback.onWwanSelected((callback) -> {
220                 mWwanSelectorCallback = callback;
221                 requestEmergencyNetworkScanInternal(preferredNetworks);
222             });
223         } else {
224             requestEmergencyNetworkScanInternal(preferredNetworks);
225         }
226     }
227 
requestEmergencyNetworkScanInternal(List<Integer> preferredNetworks)228     private void requestEmergencyNetworkScanInternal(List<Integer> preferredNetworks) {
229         logi("requestEmergencyNetworkScan: preferredNetworks=" + preferredNetworks);
230         mEmergencyNetworkScanSignal = new CancellationSignal();
231         mWwanSelectorCallback.onRequestEmergencyNetworkScan(
232                 preferredNetworks,
233                 DomainSelectionService.SCAN_TYPE_FULL_SERVICE, false,
234                 mEmergencyNetworkScanSignal,
235                 (regResult) -> {
236                     logi("requestEmergencyNetworkScan-onComplete");
237                     obtainMessage(EVENT_EMERGENCY_NETWORK_SCAN_RESULT, regResult).sendToTarget();
238                 });
239     }
240 
241     /**
242      * Handles the emergency network scan result.
243      *
244      * This triggers the emergency service fallback to modem when the emergency service is not
245      * supported but the emergency service fallback is supported in the current network.
246      *
247      * @param regResult The emergency registration result that is triggered
248      *                  by the emergency network scan.
249      */
handleEmergencyNetworkScanResult(EmergencyRegistrationResult regResult)250     private void handleEmergencyNetworkScanResult(EmergencyRegistrationResult regResult) {
251         logi("handleEmergencyNetworkScanResult: " + regResult);
252 
253         mEmergencyNetworkScanInProgress = false;
254         mEmergencyNetworkScanSignal = null;
255 
256         int accessNetworkType = regResult.getAccessNetwork();
257         int domain = NetworkRegistrationInfo.DOMAIN_CS;
258 
259         if (accessNetworkType == AccessNetworkType.NGRAN) {
260             domain = NetworkRegistrationInfo.DOMAIN_PS;
261         } else if (accessNetworkType == AccessNetworkType.EUTRAN) {
262             if (regResult.getDomain() == NetworkRegistrationInfo.DOMAIN_CS) {
263                 logi("PS emergency service is not supported in LTE network.");
264             } else {
265                 domain = NetworkRegistrationInfo.DOMAIN_PS;
266             }
267         }
268 
269         notifyWwanSelected(domain, (domain == NetworkRegistrationInfo.DOMAIN_PS));
270     }
271 
272     /**
273      * Checks if the emergency SMS messages over IMS is available according to the carrier
274      * configuration and the current network states.
275      */
isImsEmergencySmsAvailable()276     private boolean isImsEmergencySmsAvailable() {
277         boolean isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService =
278                 isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService();
279         boolean networkAvailable = isNetworkAvailableForImsEmergencySms();
280 
281         logi("isImsEmergencySmsAvailable: "
282                 + "emergencySmsOverIms=" + isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService
283                 + ", mmTelFeatureAvailable=" + mImsStateTracker.isMmTelFeatureAvailable()
284                 + ", networkAvailable=" + networkAvailable);
285 
286         return isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService
287                 && mImsStateTracker.isMmTelFeatureAvailable()
288                 && networkAvailable;
289     }
290 
291     /**
292      * Checks if sending emergency SMS messages over IMS is supported when in the network(LTE/NR)
293      * normal/limited(Emergency only) service mode from the carrier configuration.
294      */
isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService()295     private boolean isEmergencySmsOverImsSupportedIfNetworkLimitedOrInService() {
296         if (mEmergencySmsOverImsSupportedByConfig == null) {
297             CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class);
298 
299             if (ccm == null) {
300                 loge("CarrierConfigManager is null");
301                 return false;
302             }
303 
304             PersistableBundle b = ccm.getConfigForSubId(getSubId());
305 
306             if (b == null) {
307                 loge("PersistableBundle is null");
308                 return false;
309             }
310 
311             mEmergencySmsOverImsSupportedByConfig = b.getBoolean(
312                     CarrierConfigManager.KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL);
313         }
314 
315         return mEmergencySmsOverImsSupportedByConfig;
316     }
317 
318     /**
319      * Checks if the emergency service is available in the LTE service mode.
320      */
isLteEmergencyAvailableInService()321     private boolean isLteEmergencyAvailableInService() {
322         if (mServiceState == null) {
323             return false;
324         }
325 
326         final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
327                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
328 
329         if (regInfo != null
330                 && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_LTE
331                 && regInfo.isRegistered()) {
332             return isEmergencyServiceSupported(regInfo) && isEmergencyServiceAllowed();
333         }
334         return false;
335     }
336 
337     /**
338      * Checks if the emergency service is available in the limited LTE service(Emergency only) mode.
339      */
isLteEmergencyAvailableInLimitedService()340     private boolean isLteEmergencyAvailableInLimitedService() {
341         if (mServiceState == null) {
342             return false;
343         }
344 
345         final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
346                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
347         if (regInfo != null
348                 && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_LTE
349                 && regInfo.isEmergencyEnabled()) {
350             return isEmergencyServiceSupported(regInfo) && isEmergencyServiceAllowed();
351         }
352         return false;
353     }
354 
355     /**
356      * Checks if the network is available for the IMS emergency SMS.
357      */
isNetworkAvailableForImsEmergencySms()358     private boolean isNetworkAvailableForImsEmergencySms() {
359         return isLteEmergencyAvailableInService()
360                 || isLteEmergencyAvailableInLimitedService()
361                 || isNrEmergencyAvailable();
362     }
363 
364     /**
365      * Checks if the emergency service is supported by the network.
366      *
367      * This checks if "Emergency bearer services indicator (EMC-BS)" field (bits) set to
368      * the "Emergency bearer services in S1 mode supported".
369      *
370      * @return {@code true} if the emergency service is supported by the network,
371      *         {@code false} otherwise.
372      */
isEmergencyServiceSupported(@onNull NetworkRegistrationInfo regInfo)373     private boolean isEmergencyServiceSupported(@NonNull NetworkRegistrationInfo regInfo) {
374         final DataSpecificRegistrationInfo dsRegInfo = regInfo.getDataSpecificInfo();
375         if (dsRegInfo != null) {
376             final VopsSupportInfo vopsSupportInfo = dsRegInfo.getVopsSupportInfo();
377             return vopsSupportInfo != null
378                     && vopsSupportInfo.isEmergencyServiceSupported();
379         }
380         return false;
381     }
382 
383     /**
384      * Checks if the emergency service fallback is supported by the network.
385      *
386      * @return {@code true} if the emergency service fallback is supported by the network,
387      *         {@code false} otherwise.
388      */
isEmergencyServiceFallbackSupported(@onNull NetworkRegistrationInfo regInfo)389     private boolean isEmergencyServiceFallbackSupported(@NonNull NetworkRegistrationInfo regInfo) {
390         final DataSpecificRegistrationInfo dsRegInfo = regInfo.getDataSpecificInfo();
391         if (dsRegInfo != null) {
392             final VopsSupportInfo vopsSupportInfo = dsRegInfo.getVopsSupportInfo();
393             return vopsSupportInfo != null
394                     && vopsSupportInfo.isEmergencyServiceFallbackSupported();
395         }
396         return false;
397     }
398 
399     /**
400      * Checks if the emergency service is allowed (not barred) by the network.
401      *
402      * This checks if SystemInformationBlockType2 includes the ac-BarringInfo and
403      * with the ac-BarringForEmergency set to FALSE or
404      * if the SystemInformationBlockType2 does not include the ac-BarringInfo.
405      *
406      * @return {@code true} if the emergency service is allowed by the network,
407      *         {@code false} otherwise.
408      */
isEmergencyServiceAllowed()409     private boolean isEmergencyServiceAllowed() {
410         if (mBarringInfo == null) {
411             return true;
412         }
413         final BarringInfo.BarringServiceInfo bsi =
414                 mBarringInfo.getBarringServiceInfo(BarringInfo.BARRING_SERVICE_TYPE_EMERGENCY);
415         return !bsi.isBarred();
416     }
417 
418     /**
419      * Checks if the emergency service fallback is available in the NR network
420      * because the emergency service is not supported.
421      */
isNrEmergencyServiceFallbackRequired()422     private boolean isNrEmergencyServiceFallbackRequired() {
423         if (mServiceState == null) {
424             return false;
425         }
426 
427         final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
428                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
429 
430         if (regInfo != null
431                 && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_NR
432                 && regInfo.isRegistered()) {
433             return !isEmergencyServiceSupported(regInfo)
434                     && isEmergencyServiceFallbackSupported(regInfo);
435         }
436         return false;
437     }
438 
439     /**
440      * Checks if the emergency service is available in the NR network.
441      */
isNrEmergencyAvailable()442     private boolean isNrEmergencyAvailable() {
443         if (mServiceState == null) {
444             return false;
445         }
446 
447         final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
448                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
449 
450         if (regInfo != null
451                 && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_NR
452                 && regInfo.isRegistered()) {
453             return isEmergencyServiceSupported(regInfo)
454                     || isEmergencyServiceFallbackSupported(regInfo);
455         }
456         return false;
457     }
458 }
459