• 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 android.annotation.NonNull;
20 import android.content.Context;
21 import android.os.Looper;
22 import android.os.PersistableBundle;
23 import android.telephony.AccessNetworkConstants;
24 import android.telephony.BarringInfo;
25 import android.telephony.CarrierConfigManager;
26 import android.telephony.DataSpecificRegistrationInfo;
27 import android.telephony.NetworkRegistrationInfo;
28 import android.telephony.ServiceState;
29 import android.telephony.TelephonyManager;
30 import android.telephony.VopsSupportInfo;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 
34 /**
35  * Implements an emergency SMS domain selector for sending an emergency SMS.
36  */
37 public class EmergencySmsDomainSelector extends SmsDomainSelector implements
38         ImsStateTracker.BarringInfoListener, ImsStateTracker.ServiceStateListener {
39     /**
40      * Stores the configuration value of
41      * {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL}.
42      * This value is always updated whenever the domain selection is requested.
43      */
44     private Boolean mEmergencySmsOverImsSupportedByConfig;
45     private ServiceState mServiceState;
46     private boolean mServiceStateReceived;
47     private BarringInfo mBarringInfo;
48     private boolean mBarringInfoReceived;
49 
EmergencySmsDomainSelector(Context context, int slotId, int subId, @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker, @NonNull DestroyListener listener)50     public EmergencySmsDomainSelector(Context context, int slotId, int subId,
51             @NonNull Looper looper, @NonNull ImsStateTracker imsStateTracker,
52             @NonNull DestroyListener listener) {
53         super(context, slotId, subId, looper, imsStateTracker, listener,
54                 "DomainSelector-EmergencySMS");
55 
56         mImsStateTracker.addServiceStateListener(this);
57         mImsStateTracker.addBarringInfoListener(this);
58     }
59 
60     @Override
destroy()61     public void destroy() {
62         if (mDestroyed) {
63             return;
64         }
65         mImsStateTracker.removeServiceStateListener(this);
66         mImsStateTracker.removeBarringInfoListener(this);
67         super.destroy();
68     }
69 
70     @Override
finishSelection()71     public void finishSelection() {
72         super.finishSelection();
73         mServiceStateReceived = false;
74         mServiceState = null;
75         mBarringInfoReceived = false;
76         mBarringInfo = null;
77         mEmergencySmsOverImsSupportedByConfig = null;
78     }
79 
80     @Override
onBarringInfoUpdated(BarringInfo barringInfo)81     public void onBarringInfoUpdated(BarringInfo barringInfo) {
82         mBarringInfoReceived = true;
83         mBarringInfo = barringInfo;
84         sendMessageForDomainSelection();
85     }
86 
87     @Override
onServiceStateUpdated(ServiceState serviceState)88     public void onServiceStateUpdated(ServiceState serviceState) {
89         mServiceStateReceived = true;
90         mServiceState = serviceState;
91         sendMessageForDomainSelection();
92     }
93 
94     /**
95      * Checks whether the domain selector is ready to select the domain or not.
96      * The emergency SMS requires to be updated for the {@link ServiceState} and
97      * {@link BarringInfo} to confirm that the cellular network supports to send emergency SMS
98      * messages over IMS.
99      */
100     @VisibleForTesting
isDomainSelectionReady()101     public boolean isDomainSelectionReady() {
102         return mServiceStateReceived && mBarringInfoReceived;
103     }
104 
105     @Override
isSmsOverImsAvailable()106     protected boolean isSmsOverImsAvailable() {
107         if (super.isSmsOverImsAvailable()) {
108             /**
109              * Even though IMS is successfully registered, the cellular domain should be
110              * available for the emergency SMS according to the carrier's requirement
111              * when {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL} is set
112              * to true.
113              */
114             if (isEmergencySmsOverImsSupportedIfLteLimitedOrInService()) {
115                 /**
116                  * Emergency SMS should be supported via emergency PDN.
117                  * If this condition is false, then need to fallback to CS network
118                  * because the current PS network does not allow the emergency service.
119                  */
120                 return isNetworkAvailableForImsEmergencySms();
121             }
122 
123             // Emergency SMS is supported via IMS PDN.
124             return true;
125         }
126 
127         return isImsEmergencySmsAvailable();
128     }
129 
130     @Override
selectDomain()131     protected void selectDomain() {
132         if (!isDomainSelectionRequested()) {
133             logi("Domain selection is not requested!");
134             return;
135         }
136 
137         if (!isDomainSelectionReady()) {
138             logd("Wait for the readiness of the domain selection!");
139             return;
140         }
141 
142         logi("selectDomain: " + mImsStateTracker.imsStateToString());
143 
144         if (isSmsOverImsAvailable()) {
145             boolean isEmergencySmsOverImsSupportedIfLteLimitedOrInService =
146                     isEmergencySmsOverImsSupportedIfLteLimitedOrInService();
147 
148             if (mImsStateTracker.isImsRegisteredOverWlan()) {
149                 /**
150                  * When {@link CarrierConfigManager#KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL}
151                  * is set to true, the emergency SMS supports on the LTE network using the
152                  * emergency PDN. As of now, since the emergency SMS doesn't use the emergency PDN
153                  * over WLAN, the domain selector reports the domain as WLAN only if
154                  * {@code isEmergencySmsOverImsSupportedIfLteLimitedOrInService} is set to false
155                  * and IMS is registered over WLAN.
156                  * Otherwise, the domain selector reports the domain as WWAN.
157                  */
158                 if (!isEmergencySmsOverImsSupportedIfLteLimitedOrInService) {
159                     notifyWlanSelected(false);
160                     return;
161                 }
162 
163                 logi("DomainSelected: WLAN >> WWAN");
164             }
165             notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_PS,
166                     isEmergencySmsOverImsSupportedIfLteLimitedOrInService);
167         } else {
168             notifyWwanSelected(NetworkRegistrationInfo.DOMAIN_CS, false);
169         }
170     }
171 
172     /**
173      * Checks if the emergency SMS messages over IMS is available according to the carrier
174      * configuration and the current network states.
175      */
isImsEmergencySmsAvailable()176     private boolean isImsEmergencySmsAvailable() {
177         boolean isEmergencySmsOverImsSupportedIfLteLimitedOrInService =
178                 isEmergencySmsOverImsSupportedIfLteLimitedOrInService();
179         boolean networkAvailable = isNetworkAvailableForImsEmergencySms();
180 
181         logi("isImsEmergencySmsAvailable: "
182                 + "emergencySmsOverIms=" + isEmergencySmsOverImsSupportedIfLteLimitedOrInService
183                 + ", mmTelFeatureAvailable=" + mImsStateTracker.isMmTelFeatureAvailable()
184                 + ", networkAvailable=" + networkAvailable);
185 
186         return isEmergencySmsOverImsSupportedIfLteLimitedOrInService
187                 && mImsStateTracker.isMmTelFeatureAvailable()
188                 && networkAvailable;
189     }
190 
191     /**
192      * Checks if sending emergency SMS messages over IMS is supported when in LTE/limited LTE
193      * (Emergency only) service mode from the carrier configuration.
194      */
isEmergencySmsOverImsSupportedIfLteLimitedOrInService()195     private boolean isEmergencySmsOverImsSupportedIfLteLimitedOrInService() {
196         if (mEmergencySmsOverImsSupportedByConfig == null) {
197             CarrierConfigManager ccm = mContext.getSystemService(CarrierConfigManager.class);
198 
199             if (ccm == null) {
200                 loge("CarrierConfigManager is null");
201                 return false;
202             }
203 
204             PersistableBundle b = ccm.getConfigForSubId(getSubId());
205 
206             if (b == null) {
207                 loge("PersistableBundle is null");
208                 return false;
209             }
210 
211             mEmergencySmsOverImsSupportedByConfig = b.getBoolean(
212                     CarrierConfigManager.KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL);
213         }
214 
215         return mEmergencySmsOverImsSupportedByConfig;
216     }
217 
218     /**
219      * Checks if the emergency service is available in the LTE service mode.
220      */
isLteEmergencyAvailableInService()221     private boolean isLteEmergencyAvailableInService() {
222         if (mServiceState == null) {
223             return false;
224         }
225 
226         final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
227                 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
228 
229         if (regInfo != null
230                 && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_LTE
231                 && regInfo.isRegistered()) {
232             return isEmergencyServiceSupported(regInfo) && isEmergencyServiceAllowed();
233         }
234         return false;
235     }
236 
237     /**
238      * Checks if the emergency service is available in the limited LTE service(Emergency only) mode.
239      */
isLteEmergencyAvailableInLimitedService()240     private boolean isLteEmergencyAvailableInLimitedService() {
241         if (mServiceState == null) {
242             return false;
243         }
244 
245         final NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo(
246                 NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
247         if (regInfo != null
248                 && regInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_LTE
249                 && regInfo.isEmergencyEnabled()) {
250             return isEmergencyServiceSupported(regInfo) && isEmergencyServiceAllowed();
251         }
252         return false;
253     }
254 
255     /**
256      * Checks if the network is available for the IMS emergency SMS.
257      */
isNetworkAvailableForImsEmergencySms()258     private boolean isNetworkAvailableForImsEmergencySms() {
259         return isLteEmergencyAvailableInService()
260                 || isLteEmergencyAvailableInLimitedService();
261     }
262 
263     /**
264      * Checks if the emergency service is supported by the network.
265      *
266      * This checks if "Emergency bearer services indicator (EMC-BS)" field (bits) set to
267      * the "Emergency bearer services in S1 mode supported".
268      *
269      * @return {@code true} if the emergency service is supported by the network,
270      *         {@code false} otherwise.
271      */
isEmergencyServiceSupported(@onNull NetworkRegistrationInfo regInfo)272     private boolean isEmergencyServiceSupported(@NonNull NetworkRegistrationInfo regInfo) {
273         final DataSpecificRegistrationInfo dsRegInfo = regInfo.getDataSpecificInfo();
274         if (dsRegInfo != null) {
275             final VopsSupportInfo vopsSupportInfo = dsRegInfo.getVopsSupportInfo();
276             return vopsSupportInfo != null
277                     && vopsSupportInfo.isEmergencyServiceSupported();
278         }
279         return false;
280     }
281 
282     /**
283      * Checks if the emergency service is allowed (not barred) by the network.
284      *
285      * This checks if SystemInformationBlockType2 includes the ac-BarringInfo and
286      * with the ac-BarringForEmergency set to FALSE or
287      * if the SystemInformationBlockType2 does not include the ac-BarringInfo.
288      *
289      * @return {@code true} if the emergency service is allowed by the network,
290      *         {@code false} otherwise.
291      */
isEmergencyServiceAllowed()292     private boolean isEmergencyServiceAllowed() {
293         if (mBarringInfo == null) {
294             return true;
295         }
296         final BarringInfo.BarringServiceInfo bsi =
297                 mBarringInfo.getBarringServiceInfo(BarringInfo.BARRING_SERVICE_TYPE_EMERGENCY);
298         return !bsi.isBarred();
299     }
300 }
301