aboutsummaryrefslogtreecommitdiff
path: root/src/java/com/android/internal/telephony/SmsDispatchersController.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/com/android/internal/telephony/SmsDispatchersController.java')
-rw-r--r--src/java/com/android/internal/telephony/SmsDispatchersController.java256
1 files changed, 226 insertions, 30 deletions
diff --git a/src/java/com/android/internal/telephony/SmsDispatchersController.java b/src/java/com/android/internal/telephony/SmsDispatchersController.java
index d2dfcacdfb..8795840e9a 100644
--- a/src/java/com/android/internal/telephony/SmsDispatchersController.java
+++ b/src/java/com/android/internal/telephony/SmsDispatchersController.java
@@ -45,16 +45,20 @@ import android.telephony.ServiceState;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
import android.text.TextUtils;
import com.android.ims.ImsManager;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
import com.android.internal.telephony.cdma.CdmaSMSDispatcher;
import com.android.internal.telephony.domainselection.DomainSelectionConnection;
import com.android.internal.telephony.domainselection.DomainSelectionResolver;
import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection;
import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection;
+import com.android.internal.telephony.emergency.EmergencyStateTracker;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
import com.android.internal.telephony.gsm.GsmSMSDispatcher;
import com.android.telephony.Rlog;
@@ -62,8 +66,10 @@ import com.android.telephony.Rlog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
/**
@@ -94,6 +100,15 @@ public class SmsDispatchersController extends Handler {
/** InboundSmsHandler exited WaitingState */
protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17;
+ /** Called when SMS should be sent using AP domain selection. */
+ private static final int EVENT_SEND_SMS_USING_DOMAIN_SELECTION = 18;
+
+ /** Called when SMS is completely sent using AP domain selection regardless of the result. */
+ private static final int EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION = 19;
+
+ /** Called when AP domain selection is abnormally terminated. */
+ private static final int EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY = 20;
+
/** Delete any partial message segments after being IN_SERVICE for 1 day. */
private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24;
/** Constant for invalid time */
@@ -117,6 +132,7 @@ public class SmsDispatchersController extends Handler {
private final SmsUsageMonitor mUsageMonitor;
private final CommandsInterface mCi;
private final Context mContext;
+ private final @NonNull FeatureFlags mFeatureFlags;
/** true if IMS is registered and sms is supported, false otherwise.*/
private boolean mIms = false;
@@ -183,7 +199,7 @@ public class SmsDispatchersController extends Handler {
};
/** Stores the sending SMS information for a pending request. */
- private class PendingRequest {
+ private static class PendingRequest {
public static final int TYPE_DATA = 1;
public static final int TYPE_TEXT = 2;
public static final int TYPE_MULTIPART_TEXT = 3;
@@ -310,13 +326,18 @@ public class SmsDispatchersController extends Handler {
@Override
public void onSelectionTerminated(@DisconnectCauses int cause) {
- notifyDomainSelectionTerminated(this);
+ logd("onSelectionTerminated: emergency=" + mEmergency + ", cause=" + cause);
+ // This callback is invoked by another thread, so this operation is posted and handled
+ // through the execution flow of SmsDispatchersController.
+ SmsDispatchersController.this.sendMessage(
+ obtainMessage(EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY, this));
}
}
/** Manages the domain selection connections: MO SMS or emergency SMS. */
private DomainSelectionConnectionHolder mDscHolder;
private DomainSelectionConnectionHolder mEmergencyDscHolder;
+ private EmergencyStateTracker mEmergencyStateTracker;
/**
* Puts a delivery pending tracker to the map based on the format.
@@ -332,13 +353,13 @@ public class SmsDispatchersController extends Handler {
}
public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
- SmsUsageMonitor usageMonitor) {
- this(phone, storageMonitor, usageMonitor, phone.getLooper());
+ SmsUsageMonitor usageMonitor, @NonNull FeatureFlags featureFlags) {
+ this(phone, storageMonitor, usageMonitor, phone.getLooper(), featureFlags);
}
@VisibleForTesting
public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor,
- SmsUsageMonitor usageMonitor, Looper looper) {
+ SmsUsageMonitor usageMonitor, Looper looper, @NonNull FeatureFlags featureFlags) {
super(looper);
Rlog.d(TAG, "SmsDispatchersController created");
@@ -346,6 +367,7 @@ public class SmsDispatchersController extends Handler {
mContext = phone.getContext();
mUsageMonitor = usageMonitor;
mCi = phone.mCi;
+ mFeatureFlags = featureFlags;
mPhone = phone;
// Create dispatchers, inbound SMS handlers and
@@ -447,7 +469,36 @@ public class SmsDispatchersController extends Handler {
mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
resetPartialSegmentWaitTimer();
break;
-
+ case EVENT_SEND_SMS_USING_DOMAIN_SELECTION: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ DomainSelectionConnectionHolder holder =
+ (DomainSelectionConnectionHolder) args.arg1;
+ PendingRequest request = (PendingRequest) args.arg2;
+ String logTag = (String) args.arg3;
+ try {
+ handleSendSmsUsingDomainSelection(holder, request, logTag);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ String destAddr = (String) args.arg1;
+ Long messageId = (Long) args.arg2;
+ Boolean success = (Boolean) args.arg3;
+ try {
+ handleSmsSentCompletedUsingDomainSelection(destAddr, messageId, success);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY: {
+ handleDomainSelectionTerminatedAbnormally(
+ (DomainSelectionConnectionHolder) msg.obj);
+ break;
+ }
default:
if (isCdmaMo()) {
mCdmaDispatcher.handleMessage(msg);
@@ -701,7 +752,7 @@ public class SmsDispatchersController extends Handler {
boolean retryUsingImsService = false;
if (!tracker.mUsesImsServiceForIms) {
- if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+ if (isSmsDomainSelectionEnabled()) {
DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
// If the DomainSelectionConnection is not available,
@@ -756,6 +807,8 @@ public class SmsDispatchersController extends Handler {
// should never come here...
Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!");
tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
+ notifySmsSentFailedToEmergencyStateTracker(
+ tracker.mDestAddress, tracker.mMessageId);
return;
}
String scAddr = (String) map.get("scAddr");
@@ -763,6 +816,8 @@ public class SmsDispatchersController extends Handler {
if (destAddr == null) {
Rlog.e(TAG, "sendRetrySms failed due to null destAddr");
tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
+ notifySmsSentFailedToEmergencyStateTracker(
+ tracker.mDestAddress, tracker.mMessageId);
return;
}
@@ -803,6 +858,8 @@ public class SmsDispatchersController extends Handler {
+ "scAddr: %s, "
+ "destPort: %s", scAddr, map.get("destPort")));
tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE);
+ notifySmsSentFailedToEmergencyStateTracker(
+ tracker.mDestAddress, tracker.mMessageId);
return;
}
// replace old smsc and pdu with newly encoded ones
@@ -889,6 +946,16 @@ public class SmsDispatchersController extends Handler {
}
/**
+ * Checks whether the SMS domain selection is enabled or not.
+ *
+ * @return {@code true} if the SMS domain selection is enabled, {@code false} otherwise.
+ */
+ private boolean isSmsDomainSelectionEnabled() {
+ return mFeatureFlags.smsDomainSelectionEnabled()
+ && mDomainSelectionResolverProxy.isDomainSelectionSupported();
+ }
+
+ /**
* Determines whether or not to use CDMA format for MO SMS when the domain selection uses.
* If the domain is {@link NetworkRegistrationInfo#DOMAIN_PS}, then format is based on
* IMS SMS format, otherwise format is based on current phone type.
@@ -929,7 +996,6 @@ public class SmsDispatchersController extends Handler {
private DomainSelectionConnectionHolder getDomainSelectionConnection(boolean emergency) {
DomainSelectionConnectionHolder holder = getDomainSelectionConnectionHolder(emergency);
DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null;
- boolean created = false;
if (connection == null) {
connection = mDomainSelectionResolverProxy.getDomainSelectionConnection(
@@ -940,8 +1006,6 @@ public class SmsDispatchersController extends Handler {
// Use the legacy architecture.
return null;
}
-
- created = true;
}
if (holder == null) {
@@ -965,6 +1029,7 @@ public class SmsDispatchersController extends Handler {
* @param holder The {@link DomainSelectionConnectionHolder} that contains the
* {@link DomainSelectionConnection} and its related information.
*/
+ @SuppressWarnings("FutureReturnValueIgnored")
private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder) {
DomainSelectionService.SelectionAttributes attr =
new DomainSelectionService.SelectionAttributes.Builder(mPhone.getPhoneId(),
@@ -1001,16 +1066,14 @@ public class SmsDispatchersController extends Handler {
}
/**
- * Sends a SMS after selecting the domain via the domain selection service.
+ * Requests the domain selection for MO SMS.
*
* @param holder The {@link DomainSelectionConnectionHolder} that contains the
* {@link DomainSelectionConnection} and its related information.
- * @param request The {@link PendingRequest} that stores the SMS request
- * (data, text, multipart text) to be sent.
- * @param logTag The log tag to display which method called this method.
+ * @param logTag The log string.
*/
- private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
- @NonNull PendingRequest request, @NonNull String logTag) {
+ private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
+ @NonNull PendingRequest request, String logTag) {
boolean isDomainSelectionRequested = holder.isDomainSelectionRequested();
// The domain selection is in progress so waits for the result of
// the domain selection by adding this request to the pending list.
@@ -1025,6 +1088,120 @@ public class SmsDispatchersController extends Handler {
}
/**
+ * Handles an event for sending a SMS after selecting the domain via the domain selection
+ * service.
+ *
+ * @param holder The {@link DomainSelectionConnectionHolder} that contains the
+ * {@link DomainSelectionConnection} and its related information.
+ * @param request The {@link PendingRequest} that stores the SMS request
+ * (data, text, multipart text) to be sent.
+ * @param logTag The log tag to display which method called this method.
+ */
+ @SuppressWarnings("FutureReturnValueIgnored")
+ private void handleSendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
+ @NonNull PendingRequest request, @NonNull String logTag) {
+ if (holder.isEmergency()) {
+ if (mEmergencyStateTracker == null) {
+ mEmergencyStateTracker = EmergencyStateTracker.getInstance();
+ }
+
+ CompletableFuture<Integer> future = mEmergencyStateTracker.startEmergencySms(mPhone,
+ String.valueOf(request.messageId),
+ isTestEmergencyNumber(request.destAddr));
+ future.thenAccept((result) -> {
+ logi("startEmergencySms(" + logTag + "): messageId=" + request.messageId
+ + ", result=" + result);
+ // An emergency SMS should be proceeded regardless of the result of the
+ // EmergencyStateTracker.
+ // So the domain selection request should be invoked without checking the result.
+ requestDomainSelection(holder, request, logTag);
+ });
+ } else {
+ requestDomainSelection(holder, request, logTag);
+ }
+ }
+
+ /**
+ * Sends a SMS after selecting the domain via the domain selection service.
+ *
+ * @param holder The {@link DomainSelectionConnectionHolder} that contains the
+ * {@link DomainSelectionConnection} and its related information.
+ * @param request The {@link PendingRequest} that stores the SMS request
+ * (data, text, multipart text) to be sent.
+ * @param logTag The log tag to display which method called this method.
+ */
+ private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder,
+ @NonNull PendingRequest request, @NonNull String logTag) {
+ // Run on main thread for interworking with EmergencyStateTracker
+ // and adding the pending request.
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = holder;
+ args.arg2 = request;
+ args.arg3 = logTag;
+ sendMessage(obtainMessage(EVENT_SEND_SMS_USING_DOMAIN_SELECTION, args));
+ }
+
+ /**
+ * Called when sending MO SMS is complete regardless of the sent result.
+ *
+ * @param destAddr The destination address for SMS.
+ * @param messageId The message id for SMS.
+ * @param success A flag specifying whether MO SMS is successfully sent or not.
+ */
+ private void handleSmsSentCompletedUsingDomainSelection(@NonNull String destAddr,
+ long messageId, boolean success) {
+ if (mEmergencyStateTracker != null) {
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ if (tm.isEmergencyNumber(destAddr)) {
+ mEmergencyStateTracker.endSms(String.valueOf(messageId), success);
+ }
+ }
+ }
+
+ /**
+ * Called when MO SMS is successfully sent.
+ */
+ protected void notifySmsSentToEmergencyStateTracker(@NonNull String destAddr, long messageId) {
+ if (isSmsDomainSelectionEnabled()) {
+ // Run on main thread for interworking with EmergencyStateTracker.
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = destAddr;
+ args.arg2 = Long.valueOf(messageId);
+ args.arg3 = Boolean.TRUE;
+ sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args));
+ }
+ }
+
+ /**
+ * Called when sending MO SMS is failed.
+ */
+ protected void notifySmsSentFailedToEmergencyStateTracker(@NonNull String destAddr,
+ long messageId) {
+ if (isSmsDomainSelectionEnabled()) {
+ // Run on main thread for interworking with EmergencyStateTracker.
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = destAddr;
+ args.arg2 = Long.valueOf(messageId);
+ args.arg3 = Boolean.FALSE;
+ sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args));
+ }
+ }
+
+ private boolean isTestEmergencyNumber(String number) {
+ try {
+ TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
+ Map<Integer, List<EmergencyNumber>> eMap = tm.getEmergencyNumberList();
+ return eMap.values().stream().flatMap(Collection::stream).anyMatch(eNumber ->
+ eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST)
+ && number.equals(eNumber.getNumber()));
+ } catch (IllegalStateException ise) {
+ return false;
+ } catch (RuntimeException r) {
+ return false;
+ }
+ }
+
+ /**
* Finishes the domain selection for MO SMS.
*
* @param holder The {@link DomainSelectionConnectionHolder} object that is being finished.
@@ -1054,21 +1231,16 @@ public class SmsDispatchersController extends Handler {
}
/**
- * Notifies the application that MO SMS is not sent by the error of domain selection.
+ * Called when MO SMS is not sent by the error of domain selection.
*
* @param holder The {@link DomainSelectionConnectionHolder} object that is being terminated.
*/
- private void notifyDomainSelectionTerminated(@NonNull DomainSelectionConnectionHolder holder) {
- final List<PendingRequest> pendingRequests = holder.getPendingRequests();
-
- logd("notifyDomainSelectionTerminated: pendingRequests=" + pendingRequests.size());
-
- for (PendingRequest r : pendingRequests) {
- triggerSentIntentForFailure(r.sentIntents);
- }
-
+ private void handleDomainSelectionTerminatedAbnormally(
+ @NonNull DomainSelectionConnectionHolder holder) {
+ logd("handleDomainSelectionTerminatedAbnormally: pendingRequests="
+ + holder.getPendingRequests().size());
+ sendAllPendingRequests(holder, NetworkRegistrationInfo.DOMAIN_UNKNOWN);
holder.setConnection(null);
- holder.clearAllRequests();
}
/**
@@ -1089,12 +1261,36 @@ public class SmsDispatchersController extends Handler {
+ ", size=" + pendingRequests.size());
}
+ // When the domain selection request is failed, SMS should be fallback
+ // to the legacy implementation.
+ boolean wasDomainUnknown = false;
+
+ if (domain == NetworkRegistrationInfo.DOMAIN_UNKNOWN) {
+ logd("sendAllPendingRequests: fallback - imsAvailable="
+ + mImsSmsDispatcher.isAvailable());
+
+ wasDomainUnknown = true;
+
+ if (mImsSmsDispatcher.isAvailable()) {
+ domain = NetworkRegistrationInfo.DOMAIN_PS;
+ } else {
+ domain = NetworkRegistrationInfo.DOMAIN_CS;
+ }
+ }
+
for (PendingRequest r : pendingRequests) {
switch (r.type) {
case PendingRequest.TYPE_DATA:
sendData(domain, r);
break;
case PendingRequest.TYPE_TEXT:
+ // When the domain selection request is failed, emergency SMS should be fallback
+ // to the legacy implementation.
+ if (wasDomainUnknown
+ && domain != NetworkRegistrationInfo.DOMAIN_PS
+ && mImsSmsDispatcher.isEmergencySmsSupport(r.destAddr)) {
+ domain = NetworkRegistrationInfo.DOMAIN_PS;
+ }
sendText(domain, r);
break;
case PendingRequest.TYPE_MULTIPART_TEXT:
@@ -1308,7 +1504,7 @@ public class SmsDispatchersController extends Handler {
scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPackage);
}
- if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+ if (isSmsDomainSelectionEnabled()) {
DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
// If the DomainSelectionConnection is not available,
@@ -1547,7 +1743,7 @@ public class SmsDispatchersController extends Handler {
scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg);
}
- if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+ if (isSmsDomainSelectionEnabled()) {
TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
boolean isEmergency = tm.isEmergencyNumber(destAddr);
DomainSelectionConnectionHolder holder = getDomainSelectionConnection(isEmergency);
@@ -1696,7 +1892,7 @@ public class SmsDispatchersController extends Handler {
scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg);
}
- if (mDomainSelectionResolverProxy.isDomainSelectionSupported()) {
+ if (isSmsDomainSelectionEnabled()) {
DomainSelectionConnectionHolder holder = getDomainSelectionConnection(false);
// If the DomainSelectionConnection is not available,