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