1 /* 2 * Copyright (C) 2006 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.internal.telephony; 18 19 import static com.android.internal.telephony.SmsResponse.NO_ERROR_CODE; 20 import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE; 21 import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY; 22 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.app.Activity; 26 import android.app.PendingIntent; 27 import android.app.PendingIntent.CanceledException; 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.content.IntentFilter; 32 import android.net.Uri; 33 import android.os.AsyncResult; 34 import android.os.Binder; 35 import android.os.Handler; 36 import android.os.Looper; 37 import android.os.Message; 38 import android.os.UserHandle; 39 import android.os.UserManager; 40 import android.provider.Telephony.Sms; 41 import android.provider.Telephony.Sms.Intents; 42 import android.telephony.Annotation.DisconnectCauses; 43 import android.telephony.DomainSelectionService; 44 import android.telephony.NetworkRegistrationInfo; 45 import android.telephony.ServiceState; 46 import android.telephony.SmsManager; 47 import android.telephony.SmsMessage; 48 import android.telephony.SubscriptionManager; 49 import android.telephony.TelephonyManager; 50 import android.telephony.emergency.EmergencyNumber; 51 import android.telephony.satellite.SatelliteManager; 52 import android.text.TextUtils; 53 54 import com.android.ims.ImsManager; 55 import com.android.internal.R; 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.internal.os.SomeArgs; 58 import com.android.internal.telephony.cdma.CdmaInboundSmsHandler; 59 import com.android.internal.telephony.cdma.CdmaSMSDispatcher; 60 import com.android.internal.telephony.domainselection.DomainSelectionConnection; 61 import com.android.internal.telephony.domainselection.DomainSelectionResolver; 62 import com.android.internal.telephony.domainselection.EmergencySmsDomainSelectionConnection; 63 import com.android.internal.telephony.domainselection.SmsDomainSelectionConnection; 64 import com.android.internal.telephony.emergency.EmergencyStateTracker; 65 import com.android.internal.telephony.flags.FeatureFlags; 66 import com.android.internal.telephony.gsm.GsmInboundSmsHandler; 67 import com.android.internal.telephony.gsm.GsmSMSDispatcher; 68 import com.android.internal.telephony.satellite.DatagramDispatcher; 69 import com.android.internal.telephony.satellite.SatelliteController; 70 import com.android.telephony.Rlog; 71 72 import java.io.FileDescriptor; 73 import java.io.PrintWriter; 74 import java.util.ArrayList; 75 import java.util.Collection; 76 import java.util.HashMap; 77 import java.util.List; 78 import java.util.Map; 79 import java.util.concurrent.CompletableFuture; 80 import java.util.concurrent.atomic.AtomicLong; 81 82 /** 83 * 84 */ 85 public class SmsDispatchersController extends Handler { 86 private static final String TAG = "SmsDispatchersController"; 87 private static final boolean VDBG = false; // STOPSHIP if true 88 private static final boolean ENABLE_CDMA_DISPATCHER = true; // see b/388540508 89 90 /** Radio is ON */ 91 private static final int EVENT_RADIO_ON = 11; 92 93 /** IMS registration/SMS format changed */ 94 private static final int EVENT_IMS_STATE_CHANGED = 12; 95 96 /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */ 97 private static final int EVENT_IMS_STATE_DONE = 13; 98 99 /** Service state changed */ 100 private static final int EVENT_SERVICE_STATE_CHANGED = 14; 101 102 /** Purge old message segments */ 103 private static final int EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY = 15; 104 105 /** User unlocked the device */ 106 private static final int EVENT_USER_UNLOCKED = 16; 107 108 /** InboundSmsHandler exited WaitingState */ 109 protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17; 110 111 /** Called when SMS should be sent using AP domain selection. */ 112 private static final int EVENT_SEND_SMS_USING_DOMAIN_SELECTION = 18; 113 114 /** Called when SMS is completely sent using AP domain selection regardless of the result. */ 115 private static final int EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION = 19; 116 117 /** Called when AP domain selection is abnormally terminated. */ 118 private static final int EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY = 20; 119 120 /** Called when MT SMS is received via IMS. */ 121 private static final int EVENT_SMS_RECEIVED_VIA_IMS = 21; 122 123 /** Called when the domain selection should be performed. */ 124 private static final int EVENT_REQUEST_DOMAIN_SELECTION = 22; 125 126 /** Called when {@link DatagramDispatcher} informs to send carrier roaming nb iot ntn sms. */ 127 private static final int CMD_SEND_TEXT = 23; 128 129 /** Called when {@link DatagramDispatcher} informs sms cannot be sent over ntn due to error. */ 130 private static final int EVENT_SEND_TEXT_OVER_NTN_ERROR = 24; 131 132 /** Delete any partial message segments after being IN_SERVICE for 1 day. */ 133 private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24; 134 /** Constant for invalid time */ 135 private static final long INVALID_TIME = -1; 136 /** Time at which last IN_SERVICE event was received */ 137 private long mLastInServiceTime = INVALID_TIME; 138 /** Current IN_SERVICE duration */ 139 private long mCurrentWaitElapsedDuration = 0; 140 /** Time at which the current PARTIAL_SEGMENT_WAIT_DURATION timer was started */ 141 private long mCurrentWaitStartTime = INVALID_TIME; 142 143 private SMSDispatcher mCdmaDispatcher = null; 144 private SMSDispatcher mGsmDispatcher; 145 private ImsSmsDispatcher mImsSmsDispatcher; 146 147 private GsmInboundSmsHandler mGsmInboundSmsHandler; 148 private CdmaInboundSmsHandler mCdmaInboundSmsHandler = null; 149 150 private Phone mPhone; 151 /** Outgoing message counter. Shared by all dispatchers. */ 152 private final SmsUsageMonitor mUsageMonitor; 153 private final CommandsInterface mCi; 154 private final Context mContext; 155 private final @NonNull FeatureFlags mFeatureFlags; 156 157 /** true if IMS is registered and sms is supported, false otherwise.*/ 158 private boolean mIms = false; 159 private String mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN; 160 161 /** 3GPP format sent messages awaiting a delivery status report. */ 162 private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP = new HashMap<>(); 163 164 /** 3GPP2 format sent messages awaiting a delivery status report. */ 165 private HashMap<Integer, SMSDispatcher.SmsTracker> mDeliveryPendingMapFor3GPP2 = 166 new HashMap<>(); 167 168 /** 169 * Testing interface for injecting mock DomainSelectionConnection and a flag to indicate 170 * whether the domain selection is supported. 171 */ 172 @VisibleForTesting 173 public interface DomainSelectionResolverProxy { 174 /** 175 * Returns a {@link DomainSelectionConnection} created using the specified 176 * context and callback. 177 * 178 * @param phone The {@link Phone} instance. 179 * @param selectorType The domain selector type to identify the domain selection connection. 180 * A {@link DomainSelectionService#SELECTOR_TYPE_SMS} is used for SMS. 181 * @param isEmergency A flag to indicate whether this connection is 182 * for an emergency SMS or not. 183 */ getDomainSelectionConnection(Phone phone, @DomainSelectionService.SelectorType int selectorType, boolean isEmergency)184 @Nullable DomainSelectionConnection getDomainSelectionConnection(Phone phone, 185 @DomainSelectionService.SelectorType int selectorType, boolean isEmergency); 186 187 /** 188 * Checks if the device supports the domain selection service to route the call / SMS / 189 * supplementary services to the appropriate domain. 190 * 191 * @return {@code true} if the domain selection is supported on the device, 192 * {@code false} otherwise. 193 */ isDomainSelectionSupported()194 boolean isDomainSelectionSupported(); 195 } 196 197 private DomainSelectionResolverProxy mDomainSelectionResolverProxy = 198 new DomainSelectionResolverProxy() { 199 @Override 200 @Nullable 201 public DomainSelectionConnection getDomainSelectionConnection(Phone phone, 202 @DomainSelectionService.SelectorType int selectorType, 203 boolean isEmergency) { 204 try { 205 return DomainSelectionResolver.getInstance().getDomainSelectionConnection( 206 phone, selectorType, isEmergency); 207 } catch (IllegalStateException e) { 208 // In general, DomainSelectionResolver is always initialized by TeleService, 209 // but if it's not initialized (like in unit tests), 210 // it returns null to perform the legacy behavior in this case. 211 return null; 212 } 213 } 214 215 @Override 216 public boolean isDomainSelectionSupported() { 217 return DomainSelectionResolver.getInstance().isDomainSelectionSupported(); 218 } 219 }; 220 221 /** Stores the sending SMS information for a pending request. */ 222 public static class PendingRequest { 223 public static final int TYPE_DATA = 1; 224 public static final int TYPE_TEXT = 2; 225 public static final int TYPE_MULTIPART_TEXT = 3; 226 public static final int TYPE_RETRY_SMS = 4; 227 private static final AtomicLong sNextUniqueMessageId = new AtomicLong(0); 228 229 public final int type; 230 public final SMSDispatcher.SmsTracker tracker; 231 public final String callingPackage; 232 public final int callingUser; 233 public final String destAddr; 234 public final String scAddr; 235 public final ArrayList<PendingIntent> sentIntents; 236 public final ArrayList<PendingIntent> deliveryIntents; 237 public final boolean isForVvm; 238 // sendData specific 239 public final byte[] data; 240 public final int destPort; 241 // sendText / sendMultipartText specific 242 public final ArrayList<String> texts; 243 public final Uri messageUri; 244 public final boolean persistMessage; 245 public final int priority; 246 public final boolean expectMore; 247 public final int validityPeriod; 248 public final long messageId; 249 public final boolean skipShortCodeCheck; 250 public final long uniqueMessageId; 251 public final boolean isMtSmsPolling; 252 PendingRequest(int type, SMSDispatcher.SmsTracker tracker, String callingPackage, int callingUser, String destAddr, String scAddr, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, boolean isForVvm, byte[] data, int destPort, ArrayList<String> texts, Uri messageUri, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId, boolean skipShortCodeCheck, boolean isMtSmsPolling)253 public PendingRequest(int type, SMSDispatcher.SmsTracker tracker, String callingPackage, 254 int callingUser, String destAddr, String scAddr, 255 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, 256 boolean isForVvm, byte[] data, int destPort, ArrayList<String> texts, 257 Uri messageUri, boolean persistMessage, int priority, boolean expectMore, 258 int validityPeriod, long messageId, boolean skipShortCodeCheck, 259 boolean isMtSmsPolling) { 260 this.type = type; 261 this.tracker = tracker; 262 this.callingPackage = callingPackage; 263 this.callingUser = callingUser; 264 this.destAddr = destAddr; 265 this.scAddr = scAddr; 266 this.sentIntents = sentIntents; 267 this.deliveryIntents = deliveryIntents; 268 this.isForVvm = isForVvm; 269 270 this.data = data; 271 this.destPort = destPort; 272 273 this.texts = texts; 274 this.messageUri = messageUri; 275 this.persistMessage = persistMessage; 276 this.priority = priority; 277 this.expectMore = expectMore; 278 this.validityPeriod = validityPeriod; 279 this.messageId = messageId; 280 this.skipShortCodeCheck = skipShortCodeCheck; 281 if (tracker != null) { 282 this.uniqueMessageId = tracker.mUniqueMessageId; 283 } else { 284 this.uniqueMessageId = getNextUniqueMessageId(); 285 } 286 this.isMtSmsPolling = isMtSmsPolling; 287 } 288 getNextUniqueMessageId()289 public static long getNextUniqueMessageId() { 290 return sNextUniqueMessageId.getAndUpdate( 291 id -> ((id + 1) % Long.MAX_VALUE)); 292 } 293 } 294 295 /** 296 * Manages the {@link DomainSelectionConnection} instance and its related information. 297 */ 298 @VisibleForTesting 299 protected class DomainSelectionConnectionHolder 300 implements DomainSelectionConnection.DomainSelectionConnectionCallback { 301 private final boolean mEmergency; 302 // Manages the pending request while selecting a proper domain. 303 private final List<PendingRequest> mPendingRequests = new ArrayList<>(); 304 // Manages the domain selection connections: MO SMS or emergency SMS. 305 private DomainSelectionConnection mConnection; 306 DomainSelectionConnectionHolder(boolean emergency)307 DomainSelectionConnectionHolder(boolean emergency) { 308 mEmergency = emergency; 309 } 310 311 /** 312 * Returns a {@link DomainSelectionConnection} instance. 313 */ getConnection()314 public DomainSelectionConnection getConnection() { 315 return mConnection; 316 } 317 318 /** 319 * Returns a list of {@link PendingRequest} that was added 320 * while the domain selection is performed. 321 */ getPendingRequests()322 public List<PendingRequest> getPendingRequests() { 323 return mPendingRequests; 324 } 325 326 /** 327 * Checks whether or not the domain selection is requested. 328 * If there is no pending request, the domain selection request is needed to 329 * select a proper domain for MO SMS. 330 */ isDomainSelectionRequested()331 public boolean isDomainSelectionRequested() { 332 return !mPendingRequests.isEmpty(); 333 } 334 335 /** 336 * Checks whether or not this holder is for an emergency SMS. 337 */ isEmergency()338 public boolean isEmergency() { 339 return mEmergency; 340 } 341 342 /** 343 * Clears all pending requests. 344 */ clearAllRequests()345 public void clearAllRequests() { 346 mPendingRequests.clear(); 347 } 348 349 /** 350 * Add a new pending request. 351 */ addRequest(@onNull PendingRequest request)352 public void addRequest(@NonNull PendingRequest request) { 353 mPendingRequests.add(request); 354 } 355 356 /** 357 * Sets a {@link DomainSelectionConnection} instance. 358 */ setConnection(DomainSelectionConnection connection)359 public void setConnection(DomainSelectionConnection connection) { 360 mConnection = connection; 361 } 362 363 364 @Override onSelectionTerminated(@isconnectCauses int cause)365 public void onSelectionTerminated(@DisconnectCauses int cause) { 366 logd("onSelectionTerminated: emergency=" + mEmergency + ", cause=" + cause); 367 // This callback is invoked by another thread, so this operation is posted and handled 368 // through the execution flow of SmsDispatchersController. 369 SmsDispatchersController.this.sendMessage( 370 obtainMessage(EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY, this)); 371 } 372 } 373 374 /** Manages the domain selection connections: MO SMS or emergency SMS. */ 375 private DomainSelectionConnectionHolder mDscHolder; 376 private DomainSelectionConnectionHolder mEmergencyDscHolder; 377 private EmergencyStateTracker mEmergencyStateTracker; 378 379 /** 380 * Puts a delivery pending tracker to the map based on the format. 381 * 382 * @param tracker the tracker awaiting a delivery status report. 383 */ putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker)384 public void putDeliveryPendingTracker(SMSDispatcher.SmsTracker tracker) { 385 if (isCdmaFormat(tracker.mFormat)) { 386 mDeliveryPendingMapFor3GPP2.put(tracker.mMessageRef, tracker); 387 } else { 388 mDeliveryPendingMapFor3GPP.put(tracker.mMessageRef, tracker); 389 } 390 } 391 SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor, @NonNull FeatureFlags featureFlags)392 public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, 393 SmsUsageMonitor usageMonitor, @NonNull FeatureFlags featureFlags) { 394 this(phone, storageMonitor, usageMonitor, phone.getLooper(), featureFlags); 395 } 396 397 @VisibleForTesting SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, SmsUsageMonitor usageMonitor, Looper looper, @NonNull FeatureFlags featureFlags)398 public SmsDispatchersController(Phone phone, SmsStorageMonitor storageMonitor, 399 SmsUsageMonitor usageMonitor, Looper looper, @NonNull FeatureFlags featureFlags) { 400 super(looper); 401 402 Rlog.d(TAG, "SmsDispatchersController created"); 403 404 mContext = phone.getContext(); 405 mUsageMonitor = usageMonitor; 406 mCi = phone.mCi; 407 mFeatureFlags = featureFlags; 408 mPhone = phone; 409 410 // Create dispatchers, inbound SMS handlers and 411 // broadcast undelivered messages in raw table. 412 mImsSmsDispatcher = new ImsSmsDispatcher(phone, this, ImsManager::getConnector); 413 mGsmInboundSmsHandler = GsmInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 414 storageMonitor, phone, looper, mFeatureFlags); 415 if (ENABLE_CDMA_DISPATCHER) { 416 mCdmaDispatcher = new CdmaSMSDispatcher(phone, this); 417 mCdmaInboundSmsHandler = CdmaInboundSmsHandler.makeInboundSmsHandler(phone.getContext(), 418 storageMonitor, phone, (CdmaSMSDispatcher) mCdmaDispatcher, looper, 419 mFeatureFlags); 420 } 421 mGsmDispatcher = new GsmSMSDispatcher(phone, this, mGsmInboundSmsHandler); 422 SmsBroadcastUndelivered.initialize(phone.getContext(), 423 mGsmInboundSmsHandler, mCdmaInboundSmsHandler, mFeatureFlags); 424 InboundSmsHandler.registerNewMessageNotificationActionHandler(phone.getContext()); 425 426 mCi.registerForOn(this, EVENT_RADIO_ON, null); 427 mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null); 428 429 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 430 if (userManager.isUserUnlocked()) { 431 if (VDBG) { 432 logd("SmsDispatchersController: user unlocked; registering for service" 433 + "state changed"); 434 } 435 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); 436 resetPartialSegmentWaitTimer(); 437 } else { 438 if (VDBG) { 439 logd("SmsDispatchersController: user locked; waiting for USER_UNLOCKED"); 440 } 441 IntentFilter userFilter = new IntentFilter(); 442 userFilter.addAction(Intent.ACTION_USER_UNLOCKED); 443 mContext.registerReceiver(mBroadcastReceiver, userFilter); 444 } 445 } 446 447 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 448 @Override 449 public void onReceive(final Context context, Intent intent) { 450 Rlog.d(TAG, "Received broadcast " + intent.getAction()); 451 if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 452 sendMessage(obtainMessage(EVENT_USER_UNLOCKED)); 453 } 454 } 455 }; 456 dispose()457 public void dispose() { 458 mCi.unregisterForOn(this); 459 mCi.unregisterForImsNetworkStateChanged(this); 460 mPhone.unregisterForServiceStateChanged(this); 461 mGsmDispatcher.dispose(); 462 if (mCdmaDispatcher != null) mCdmaDispatcher.dispose(); 463 mGsmInboundSmsHandler.dispose(); 464 if (mCdmaInboundSmsHandler != null) mCdmaInboundSmsHandler.dispose(); 465 // Cancels the domain selection request if it's still in progress. 466 finishDomainSelection(mDscHolder); 467 finishDomainSelection(mEmergencyDscHolder); 468 } 469 470 /** 471 * Handles events coming from the phone stack. Overridden from handler. 472 * 473 * @param msg the message to handle 474 */ 475 @Override handleMessage(Message msg)476 public void handleMessage(Message msg) { 477 AsyncResult ar; 478 479 switch (msg.what) { 480 case EVENT_RADIO_ON: 481 case EVENT_IMS_STATE_CHANGED: // received unsol 482 mCi.getImsRegistrationState(this.obtainMessage(EVENT_IMS_STATE_DONE)); 483 break; 484 485 case EVENT_IMS_STATE_DONE: 486 ar = (AsyncResult) msg.obj; 487 488 if (ar.exception == null) { 489 updateImsInfo(ar); 490 } else { 491 Rlog.e(TAG, "IMS State query failed with exp " 492 + ar.exception); 493 } 494 break; 495 496 case EVENT_SERVICE_STATE_CHANGED: 497 case EVENT_SMS_HANDLER_EXITING_WAITING_STATE: 498 reevaluateTimerStatus(); 499 break; 500 501 case EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY: 502 handlePartialSegmentTimerExpiry((Long) msg.obj); 503 break; 504 505 case EVENT_USER_UNLOCKED: 506 if (VDBG) { 507 logd("handleMessage: EVENT_USER_UNLOCKED"); 508 } 509 mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); 510 resetPartialSegmentWaitTimer(); 511 break; 512 case EVENT_SEND_SMS_USING_DOMAIN_SELECTION: { 513 SomeArgs args = (SomeArgs) msg.obj; 514 DomainSelectionConnectionHolder holder = 515 (DomainSelectionConnectionHolder) args.arg1; 516 PendingRequest request = (PendingRequest) args.arg2; 517 String logTag = (String) args.arg3; 518 try { 519 handleSendSmsUsingDomainSelection(holder, request, logTag); 520 } finally { 521 args.recycle(); 522 } 523 break; 524 } 525 case EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION: { 526 SomeArgs args = (SomeArgs) msg.obj; 527 String destAddr = (String) args.arg1; 528 Long messageId = (Long) args.arg2; 529 Boolean success = (Boolean) args.arg3; 530 Boolean isOverIms = (Boolean) args.arg4; 531 Boolean isLastSmsPart = (Boolean) args.arg5; 532 try { 533 handleSmsSentCompletedUsingDomainSelection( 534 destAddr, messageId, success, isOverIms, isLastSmsPart); 535 } finally { 536 args.recycle(); 537 } 538 break; 539 } 540 case EVENT_DOMAIN_SELECTION_TERMINATED_ABNORMALLY: { 541 handleDomainSelectionTerminatedAbnormally( 542 (DomainSelectionConnectionHolder) msg.obj); 543 break; 544 } 545 case EVENT_SMS_RECEIVED_VIA_IMS: { 546 handleSmsReceivedViaIms((String) msg.obj); 547 break; 548 } 549 case EVENT_REQUEST_DOMAIN_SELECTION: { 550 SomeArgs args = (SomeArgs) msg.obj; 551 DomainSelectionConnectionHolder holder = 552 (DomainSelectionConnectionHolder) args.arg1; 553 PendingRequest request = (PendingRequest) args.arg2; 554 String logTag = (String) args.arg3; 555 try { 556 requestDomainSelection(holder, request, logTag); 557 } finally { 558 args.recycle(); 559 } 560 break; 561 } 562 case CMD_SEND_TEXT: { 563 PendingRequest request = (PendingRequest) msg.obj; 564 if (request.type == PendingRequest.TYPE_TEXT) { 565 sendTextInternal(request); 566 } else if (request.type == PendingRequest.TYPE_MULTIPART_TEXT) { 567 sendMultipartTextInternal(request); 568 } else { 569 logd("CMD_SEND_TEXT: type=" + request.type 570 + " messageId=" + request.messageId); 571 } 572 break; 573 } 574 case EVENT_SEND_TEXT_OVER_NTN_ERROR: { 575 PendingRequest request = (PendingRequest) msg.obj; 576 logd("EVENT_SEND_TEXT_OVER_NTN_ERROR: type=" + request.type 577 + " messageId=" + request.messageId); 578 triggerSentIntentForFailure(request.sentIntents); 579 break; 580 } 581 582 default: 583 if (isCdmaMo()) { 584 if (mCdmaDispatcher != null) mCdmaDispatcher.handleMessage(msg); 585 } else { 586 mGsmDispatcher.handleMessage(msg); 587 } 588 } 589 } 590 getSmscAddressFromUSIMWithPhoneIdentity(String callingPkg)591 private String getSmscAddressFromUSIMWithPhoneIdentity(String callingPkg) { 592 final long identity = Binder.clearCallingIdentity(); 593 try { 594 IccSmsInterfaceManager iccSmsIntMgr = mPhone.getIccSmsInterfaceManager(); 595 if (iccSmsIntMgr != null) { 596 return iccSmsIntMgr.getSmscAddressFromIccEf(callingPkg); 597 } else { 598 Rlog.d(TAG, "getSmscAddressFromIccEf iccSmsIntMgr is null"); 599 } 600 } finally { 601 Binder.restoreCallingIdentity(identity); 602 } 603 return null; 604 } 605 reevaluateTimerStatus()606 private void reevaluateTimerStatus() { 607 long currentTime = System.currentTimeMillis(); 608 609 // Remove unhandled timer expiry message. A new message will be posted if needed. 610 removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); 611 // Update timer duration elapsed time (add time since last IN_SERVICE to now). 612 // This is needed for IN_SERVICE as well as OUT_OF_SERVICE because same events can be 613 // received back to back 614 if (mLastInServiceTime != INVALID_TIME) { 615 mCurrentWaitElapsedDuration += (currentTime - mLastInServiceTime); 616 } 617 618 if (VDBG) { 619 logd("reevaluateTimerStatus: currentTime: " + currentTime 620 + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); 621 } 622 623 if (mCurrentWaitElapsedDuration > PARTIAL_SEGMENT_WAIT_DURATION) { 624 // handle this event as timer expiry 625 handlePartialSegmentTimerExpiry(mCurrentWaitStartTime); 626 } else { 627 if (isInService()) { 628 handleInService(currentTime); 629 } else { 630 handleOutOfService(currentTime); 631 } 632 } 633 } 634 handleInService(long currentTime)635 private void handleInService(long currentTime) { 636 if (VDBG) { 637 logd("handleInService: timer expiry in " 638 + (PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration) + "ms"); 639 } 640 641 // initialize mCurrentWaitStartTime if needed 642 if (mCurrentWaitStartTime == INVALID_TIME) mCurrentWaitStartTime = currentTime; 643 644 // Post a message for timer expiry time. mCurrentWaitElapsedDuration is the duration already 645 // elapsed from the timer. 646 sendMessageDelayed( 647 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), 648 PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration); 649 650 // update mLastInServiceTime as the current time 651 mLastInServiceTime = currentTime; 652 } 653 handleOutOfService(long currentTime)654 private void handleOutOfService(long currentTime) { 655 if (VDBG) { 656 logd("handleOutOfService: currentTime: " + currentTime 657 + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); 658 } 659 660 // mLastInServiceTime is not relevant now since state is OUT_OF_SERVICE; set it to INVALID 661 mLastInServiceTime = INVALID_TIME; 662 } 663 handlePartialSegmentTimerExpiry(long waitTimerStart)664 private void handlePartialSegmentTimerExpiry(long waitTimerStart) { 665 if (mGsmInboundSmsHandler.getCurrentState().getName().equals("WaitingState") 666 || (mCdmaInboundSmsHandler != null 667 && mCdmaInboundSmsHandler.getCurrentState().getName().equals("WaitingState"))) { 668 logd("handlePartialSegmentTimerExpiry: ignoring timer expiry as InboundSmsHandler is" 669 + " in WaitingState"); 670 return; 671 } 672 673 if (VDBG) { 674 logd("handlePartialSegmentTimerExpiry: calling scanRawTable()"); 675 } 676 // Timer expired. This indicates that device has been in service for 677 // PARTIAL_SEGMENT_WAIT_DURATION since waitTimerStart. Delete orphaned message segments 678 // older than waitTimerStart. 679 SmsBroadcastUndelivered.scanRawTable(mContext, waitTimerStart); 680 if (VDBG) { 681 logd("handlePartialSegmentTimerExpiry: scanRawTable() done"); 682 } 683 684 resetPartialSegmentWaitTimer(); 685 } 686 resetPartialSegmentWaitTimer()687 private void resetPartialSegmentWaitTimer() { 688 long currentTime = System.currentTimeMillis(); 689 690 removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); 691 if (isInService()) { 692 if (VDBG) { 693 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime 694 + " IN_SERVICE"); 695 } 696 mCurrentWaitStartTime = currentTime; 697 mLastInServiceTime = currentTime; 698 sendMessageDelayed( 699 obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), 700 PARTIAL_SEGMENT_WAIT_DURATION); 701 } else { 702 if (VDBG) { 703 logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime 704 + " not IN_SERVICE"); 705 } 706 mCurrentWaitStartTime = INVALID_TIME; 707 mLastInServiceTime = INVALID_TIME; 708 } 709 710 mCurrentWaitElapsedDuration = 0; 711 } 712 isInService()713 private boolean isInService() { 714 ServiceState serviceState = mPhone.getServiceState(); 715 return serviceState != null && serviceState.getState() == ServiceState.STATE_IN_SERVICE; 716 } 717 setImsSmsFormat(int format)718 private void setImsSmsFormat(int format) { 719 switch (format) { 720 case PhoneConstants.PHONE_TYPE_GSM: 721 mImsSmsFormat = SmsConstants.FORMAT_3GPP; 722 break; 723 case PhoneConstants.PHONE_TYPE_CDMA: 724 mImsSmsFormat = SmsConstants.FORMAT_3GPP2; 725 break; 726 default: 727 mImsSmsFormat = SmsConstants.FORMAT_UNKNOWN; 728 break; 729 } 730 } 731 updateImsInfo(AsyncResult ar)732 private void updateImsInfo(AsyncResult ar) { 733 int[] responseArray = (int[]) ar.result; 734 setImsSmsFormat(responseArray[1]); 735 mIms = responseArray[0] == 1 && !SmsConstants.FORMAT_UNKNOWN.equals(mImsSmsFormat); 736 Rlog.d(TAG, "IMS registration state: " + mIms + " format: " + mImsSmsFormat); 737 } 738 739 /** 740 * Inject an SMS PDU into the android platform only if it is class 1. 741 * 742 * @param pdu is the byte array of pdu to be injected into android telephony layer 743 * @param format is the format of SMS pdu (3gpp or 3gpp2) 744 * @param callback if not NULL this callback is triggered when the message is successfully 745 * received by the android telephony layer. This callback is triggered at 746 * the same time an SMS received from radio is responded back. 747 */ 748 @VisibleForTesting injectSmsPdu(byte[] pdu, String format, boolean isOverIms, SmsInjectionCallback callback)749 public void injectSmsPdu(byte[] pdu, String format, boolean isOverIms, 750 SmsInjectionCallback callback) { 751 // TODO We need to decide whether we should allow injecting GSM(3gpp) 752 // SMS pdus when the phone is camping on CDMA(3gpp2) network and vice versa. 753 android.telephony.SmsMessage msg = 754 android.telephony.SmsMessage.createFromPdu(pdu, format); 755 injectSmsPdu(msg, format, callback, false /* ignoreClass */, isOverIms, 0 /* unused */); 756 } 757 758 @VisibleForTesting setImsSmsDispatcher(ImsSmsDispatcher imsSmsDispatcher)759 public void setImsSmsDispatcher(ImsSmsDispatcher imsSmsDispatcher) { 760 mImsSmsDispatcher = imsSmsDispatcher; 761 } 762 763 /** 764 * Inject an SMS PDU into the android platform. 765 * 766 * @param msg is the {@link SmsMessage} to be injected into android telephony layer 767 * @param format is the format of SMS pdu (3gpp or 3gpp2) 768 * @param callback if not NULL this callback is triggered when the message is successfully 769 * received by the android telephony layer. This callback is triggered at 770 * the same time an SMS received from radio is responded back. 771 * @param ignoreClass if set to false, this method will inject class 1 sms only. 772 */ 773 @VisibleForTesting injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, boolean ignoreClass, boolean isOverIms, int token)774 public void injectSmsPdu(SmsMessage msg, String format, SmsInjectionCallback callback, 775 boolean ignoreClass, boolean isOverIms, int token) { 776 Rlog.d(TAG, "SmsDispatchersController:injectSmsPdu"); 777 try { 778 if (msg == null) { 779 Rlog.e(TAG, "injectSmsPdu: createFromPdu returned null"); 780 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 781 return; 782 } 783 784 if (!ignoreClass 785 && msg.getMessageClass() != android.telephony.SmsMessage.MessageClass.CLASS_1) { 786 Rlog.e(TAG, "injectSmsPdu: not class 1"); 787 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 788 return; 789 } 790 791 AsyncResult ar = new AsyncResult(callback, msg, null); 792 793 if (format.equals(SmsConstants.FORMAT_3GPP)) { 794 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg 795 + ", format=" + format + "to mGsmInboundSmsHandler"); 796 mGsmInboundSmsHandler.sendMessage( 797 InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, token, ar); 798 } else if (format.equals(SmsConstants.FORMAT_3GPP2) && mCdmaInboundSmsHandler != null) { 799 Rlog.i(TAG, "SmsDispatchersController:injectSmsText Sending msg=" + msg 800 + ", format=" + format + "to mCdmaInboundSmsHandler"); 801 mCdmaInboundSmsHandler.sendMessage( 802 InboundSmsHandler.EVENT_INJECT_SMS, isOverIms ? 1 : 0, 0, ar); 803 } else { 804 // Invalid pdu format. 805 Rlog.e(TAG, "Invalid pdu format: " + format); 806 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 807 } 808 } catch (Exception e) { 809 Rlog.e(TAG, "injectSmsPdu failed: ", e); 810 callback.onSmsInjectedResult(Intents.RESULT_SMS_GENERIC_ERROR); 811 } 812 } 813 814 /** 815 * sets ImsManager object. 816 * 817 * @param imsManager holds a valid object or a null for setting 818 */ setImsManager(ImsManager imsManager)819 public boolean setImsManager(ImsManager imsManager) { 820 if (mGsmInboundSmsHandler != null) { 821 mGsmInboundSmsHandler.setImsManager(imsManager); 822 return true; 823 } 824 return false; 825 } 826 827 /** 828 * Retry the message along to the radio. 829 * 830 * @param tracker holds the SMS message to send 831 */ sendRetrySms(SMSDispatcher.SmsTracker tracker)832 public void sendRetrySms(SMSDispatcher.SmsTracker tracker) { 833 boolean retryUsingImsService = false; 834 835 if (!tracker.mUsesImsServiceForIms) { 836 if (isSmsDomainSelectionEnabled()) { 837 boolean isEmergency = isEmergencyNumber(tracker.mDestAddress); 838 // This may be invoked by another thread, so this operation is posted and 839 // handled through the execution flow of SmsDispatchersController. 840 SomeArgs args = SomeArgs.obtain(); 841 args.arg1 = getDomainSelectionConnectionHolder(isEmergency); 842 args.arg2 = new PendingRequest(PendingRequest.TYPE_RETRY_SMS, tracker, 843 null, UserHandle.USER_NULL, null, null, 844 null, null, false, null, 0, 845 null, null, false, 846 0, false, 0, 0L, false, false); 847 args.arg3 = "sendRetrySms"; 848 sendMessage(obtainMessage(EVENT_REQUEST_DOMAIN_SELECTION, args)); 849 return; 850 } 851 852 if (mImsSmsDispatcher.isAvailable()) { 853 // If this tracker has not been handled by ImsSmsDispatcher yet and IMS Service is 854 // available now, retry this failed tracker using IMS Service. 855 retryUsingImsService = true; 856 } 857 } 858 859 sendRetrySms(tracker, retryUsingImsService); 860 } 861 862 /** 863 * Retry the message along to the radio. 864 * 865 * @param tracker holds the SMS message to send 866 * @param retryUsingImsService a flag to indicate whether the retry SMS can use the ImsService 867 */ sendRetrySms(SMSDispatcher.SmsTracker tracker, boolean retryUsingImsService)868 public void sendRetrySms(SMSDispatcher.SmsTracker tracker, boolean retryUsingImsService) { 869 String oldFormat = tracker.mFormat; 870 // If retryUsingImsService is true, newFormat will be IMS SMS format. Otherwise, newFormat 871 // will be based on voice technology. 872 String newFormat = 873 retryUsingImsService 874 ? mImsSmsDispatcher.getFormat() 875 : (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()) 876 ? mCdmaDispatcher.getFormat() 877 : mGsmDispatcher.getFormat(); 878 879 Rlog.d(TAG, "old format(" + oldFormat + ") ==> new format (" + newFormat + ")"); 880 if (!oldFormat.equals(newFormat)) { 881 // format didn't match, need to re-encode. 882 HashMap map = tracker.getData(); 883 884 // to re-encode, fields needed are: scAddr, destAddr and text if originally sent as 885 // sendText or data and destPort if originally sent as sendData. 886 if (!(map.containsKey("scAddr") && map.containsKey("destAddr") 887 && (map.containsKey("text") 888 || (map.containsKey("data") && map.containsKey("destPort"))))) { 889 // should never come here... 890 Rlog.e(TAG, "sendRetrySms failed to re-encode per missing fields!"); 891 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 892 notifySmsSent(tracker, !retryUsingImsService, 893 true /*isLastSmsPart*/, false /*success*/); 894 return; 895 } 896 String scAddr = (String) map.get("scAddr"); 897 String destAddr = (String) map.get("destAddr"); 898 if (destAddr == null) { 899 Rlog.e(TAG, "sendRetrySms failed due to null destAddr"); 900 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 901 notifySmsSent(tracker, !retryUsingImsService, 902 true /*isLastSmsPart*/, false /*success*/); 903 return; 904 } 905 906 SmsMessageBase.SubmitPduBase pdu = null; 907 // figure out from tracker if this was sendText/Data 908 if (map.containsKey("text")) { 909 String text = (String) map.get("text"); 910 Rlog.d(TAG, "sms failed was text with length: " 911 + (text == null ? null : text.length())); 912 913 if (isCdmaFormat(newFormat)) { 914 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 915 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null); 916 } else { 917 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 918 scAddr, destAddr, text, (tracker.mDeliveryIntent != null), null, 919 0, 0, 0, -1, tracker.mMessageRef); 920 } 921 } else if (map.containsKey("data")) { 922 byte[] data = (byte[]) map.get("data"); 923 Integer destPort = (Integer) map.get("destPort"); 924 Rlog.d(TAG, "sms failed was data with length: " 925 + (data == null ? null : data.length)); 926 927 if (isCdmaFormat(newFormat)) { 928 pdu = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( 929 scAddr, destAddr, destPort.intValue(), data, 930 (tracker.mDeliveryIntent != null)); 931 } else { 932 pdu = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu( 933 scAddr, destAddr, destPort.intValue(), data, 934 (tracker.mDeliveryIntent != null), tracker.mMessageRef); 935 } 936 } 937 938 if (pdu == null) { 939 Rlog.e(TAG, String.format("sendRetrySms failed to encode message." 940 + "scAddr: %s, " 941 + "destPort: %s", scAddr, map.get("destPort"))); 942 tracker.onFailed(mContext, SmsManager.RESULT_SMS_SEND_RETRY_FAILED, NO_ERROR_CODE); 943 notifySmsSent(tracker, !retryUsingImsService, 944 true /*isLastSmsPart*/, false /*success*/); 945 return; 946 } 947 // replace old smsc and pdu with newly encoded ones 948 map.put("smsc", pdu.encodedScAddress); 949 map.put("pdu", pdu.encodedMessage); 950 tracker.mFormat = newFormat; 951 } 952 953 SMSDispatcher dispatcher = 954 retryUsingImsService 955 ? mImsSmsDispatcher 956 : (isCdmaFormat(newFormat)) ? mCdmaDispatcher : mGsmDispatcher; 957 958 dispatcher.sendSms(tracker); 959 } 960 961 /** 962 * Memory Available Event 963 * @param result callback message 964 */ reportSmsMemoryStatus(Message result)965 public void reportSmsMemoryStatus(Message result) { 966 Rlog.d(TAG, "reportSmsMemoryStatus: "); 967 try { 968 mImsSmsDispatcher.onMemoryAvailable(); 969 AsyncResult.forMessage(result, null, null); 970 result.sendToTarget(); 971 } catch (Exception e) { 972 Rlog.e(TAG, "reportSmsMemoryStatus Failed ", e); 973 AsyncResult.forMessage(result, null, e); 974 result.sendToTarget(); 975 } 976 } 977 978 /** 979 * SMS over IMS is supported if IMS is registered and SMS is supported on IMS. 980 * 981 * @return true if SMS over IMS is supported via an IMS Service or mIms is true for the older 982 * implementation. Otherwise, false. 983 */ isIms()984 public boolean isIms() { 985 return mImsSmsDispatcher.isAvailable() ? true : mIms; 986 } 987 988 /** 989 * Gets SMS format supported on IMS. 990 * 991 * @return the SMS format from an IMS Service if available. Otherwise, mImsSmsFormat for the 992 * older implementation. 993 */ getImsSmsFormat()994 public String getImsSmsFormat() { 995 return mImsSmsDispatcher.isAvailable() ? mImsSmsDispatcher.getFormat() : mImsSmsFormat; 996 } 997 998 /** 999 * Determines whether or not to use CDMA format for MO SMS. 1000 * If SMS over IMS is supported, then format is based on IMS SMS format, 1001 * otherwise format is based on current phone type. 1002 * 1003 * @return true if Cdma format should be used for MO SMS, false otherwise. 1004 */ isCdmaMo()1005 protected boolean isCdmaMo() { 1006 if (!ENABLE_CDMA_DISPATCHER) return false; 1007 if (!isIms()) { 1008 // IMS is not registered, use Voice technology to determine SMS format. 1009 return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()); 1010 } 1011 // IMS is registered with SMS support 1012 return isCdmaFormat(getImsSmsFormat()); 1013 } 1014 1015 /** 1016 * Determines whether or not format given is CDMA format. 1017 * 1018 * @param format 1019 * @return true if format given is CDMA format, false otherwise. 1020 */ isCdmaFormat(String format)1021 public boolean isCdmaFormat(String format) { 1022 if (!ENABLE_CDMA_DISPATCHER) return false; 1023 return (mCdmaDispatcher.getFormat().equals(format)); 1024 } 1025 1026 /** Sets a proxy interface for accessing the methods of {@link DomainSelectionResolver}. */ 1027 @VisibleForTesting setDomainSelectionResolverProxy(@onNull DomainSelectionResolverProxy proxy)1028 public void setDomainSelectionResolverProxy(@NonNull DomainSelectionResolverProxy proxy) { 1029 mDomainSelectionResolverProxy = proxy; 1030 } 1031 1032 /** 1033 * Checks whether the SMS domain selection is enabled or not. 1034 * 1035 * @return {@code true} if the SMS domain selection is enabled, {@code false} otherwise. 1036 */ isSmsDomainSelectionEnabled()1037 private boolean isSmsDomainSelectionEnabled() { 1038 return mFeatureFlags.smsDomainSelectionEnabled() 1039 && mDomainSelectionResolverProxy.isDomainSelectionSupported(); 1040 } 1041 1042 /** 1043 * Determines whether or not to use CDMA format for MO SMS when the domain selection uses. 1044 * If the domain is {@link NetworkRegistrationInfo#DOMAIN_PS}, then format is based on 1045 * IMS SMS format, otherwise format is based on current phone type. 1046 * 1047 * @return {@code true} if CDMA format should be used for MO SMS, {@code false} otherwise. 1048 */ isCdmaMo(@etworkRegistrationInfo.Domain int domain)1049 private boolean isCdmaMo(@NetworkRegistrationInfo.Domain int domain) { 1050 if (domain != NetworkRegistrationInfo.DOMAIN_PS) { 1051 // IMS is not registered, use voice technology to determine SMS format. 1052 return (PhoneConstants.PHONE_TYPE_CDMA == mPhone.getPhoneType()); 1053 } 1054 // IMS is registered with SMS support 1055 return isCdmaFormat(mImsSmsDispatcher.getFormat()); 1056 } 1057 1058 /** 1059 * Returns a {@link DomainSelectionConnectionHolder} according to the flag specified. 1060 * 1061 * @param emergency The flag to indicate that the domain selection is for an emergency SMS. 1062 * @return A {@link DomainSelectionConnectionHolder} instance. 1063 */ 1064 @VisibleForTesting 1065 @Nullable getDomainSelectionConnectionHolder( boolean emergency)1066 protected DomainSelectionConnectionHolder getDomainSelectionConnectionHolder( 1067 boolean emergency) { 1068 if (emergency) { 1069 if (mEmergencyDscHolder == null) { 1070 mEmergencyDscHolder = new DomainSelectionConnectionHolder(emergency); 1071 } 1072 return mEmergencyDscHolder; 1073 } else { 1074 if (mDscHolder == null) { 1075 mDscHolder = new DomainSelectionConnectionHolder(emergency); 1076 } 1077 return mDscHolder; 1078 } 1079 } 1080 1081 /** 1082 * Requests the domain selection for MO SMS. 1083 * 1084 * @param holder The {@link DomainSelectionConnectionHolder} that contains the 1085 * {@link DomainSelectionConnection} and its related information. 1086 */ 1087 @SuppressWarnings("FutureReturnValueIgnored") requestDomainSelection(@onNull DomainSelectionConnectionHolder holder)1088 private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder) { 1089 DomainSelectionService.SelectionAttributes attr = 1090 new DomainSelectionService.SelectionAttributes.Builder(mPhone.getPhoneId(), 1091 mPhone.getSubId(), DomainSelectionService.SELECTOR_TYPE_SMS) 1092 .setEmergency(holder.isEmergency()) 1093 .build(); 1094 1095 if (holder.isEmergency()) { 1096 EmergencySmsDomainSelectionConnection emergencyConnection = 1097 (EmergencySmsDomainSelectionConnection) holder.getConnection(); 1098 CompletableFuture<Integer> future = 1099 emergencyConnection.requestDomainSelection(attr, holder); 1100 future.thenAcceptAsync((domain) -> { 1101 if (VDBG) { 1102 logd("requestDomainSelection(emergency): domain=" 1103 + DomainSelectionService.getDomainName(domain)); 1104 } 1105 sendAllPendingRequests(holder, domain); 1106 finishDomainSelection(holder); 1107 }, this::post); 1108 } else { 1109 SmsDomainSelectionConnection connection = 1110 (SmsDomainSelectionConnection) holder.getConnection(); 1111 CompletableFuture<Integer> future = connection.requestDomainSelection(attr, holder); 1112 future.thenAcceptAsync((domain) -> { 1113 if (VDBG) { 1114 logd("requestDomainSelection: domain=" 1115 + DomainSelectionService.getDomainName(domain)); 1116 } 1117 sendAllPendingRequests(holder, domain); 1118 finishDomainSelection(holder); 1119 }, this::post); 1120 } 1121 } 1122 1123 /** 1124 * Requests the domain selection for MO SMS. 1125 * 1126 * @param holder The {@link DomainSelectionConnectionHolder} that contains the 1127 * {@link DomainSelectionConnection} and its related information. 1128 * @param request The {@link PendingRequest} that stores the SMS request 1129 * (data, text, multipart text) to be sent. 1130 * @param logTag The log string. 1131 */ requestDomainSelection(@onNull DomainSelectionConnectionHolder holder, @NonNull PendingRequest request, String logTag)1132 private void requestDomainSelection(@NonNull DomainSelectionConnectionHolder holder, 1133 @NonNull PendingRequest request, String logTag) { 1134 boolean isDomainSelectionRequested = holder.isDomainSelectionRequested(); 1135 // The domain selection is in progress so waits for the result of 1136 // the domain selection by adding this request to the pending list. 1137 holder.addRequest(request); 1138 1139 if (holder.getConnection() == null) { 1140 DomainSelectionConnection connection = 1141 mDomainSelectionResolverProxy.getDomainSelectionConnection( 1142 mPhone, DomainSelectionService.SELECTOR_TYPE_SMS, holder.isEmergency()); 1143 if (connection == null) { 1144 logd("requestDomainSelection: fallback for " + logTag); 1145 // If the domain selection connection is not available, 1146 // fallback to the legacy implementation. 1147 sendAllPendingRequests(holder, NetworkRegistrationInfo.DOMAIN_UNKNOWN); 1148 return; 1149 } else { 1150 holder.setConnection(connection); 1151 } 1152 } 1153 1154 if (!isDomainSelectionRequested) { 1155 if (VDBG) { 1156 logd("requestDomainSelection: " + logTag); 1157 } 1158 requestDomainSelection(holder); 1159 } 1160 } 1161 1162 /** 1163 * Handles an event for sending a SMS after selecting the domain via the domain selection 1164 * service. 1165 * 1166 * @param holder The {@link DomainSelectionConnectionHolder} that contains the 1167 * {@link DomainSelectionConnection} and its related information. 1168 * @param request The {@link PendingRequest} that stores the SMS request 1169 * (data, text, multipart text) to be sent. 1170 * @param logTag The log tag to display which method called this method. 1171 */ 1172 @SuppressWarnings("FutureReturnValueIgnored") handleSendSmsUsingDomainSelection(@onNull DomainSelectionConnectionHolder holder, @NonNull PendingRequest request, @NonNull String logTag)1173 private void handleSendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder, 1174 @NonNull PendingRequest request, @NonNull String logTag) { 1175 if (holder.isEmergency()) { 1176 if (mEmergencyStateTracker == null) { 1177 mEmergencyStateTracker = EmergencyStateTracker.getInstance(); 1178 } 1179 1180 CompletableFuture<Integer> future = mEmergencyStateTracker.startEmergencySms(mPhone, 1181 String.valueOf(request.messageId), 1182 isTestEmergencyNumber(request.destAddr)); 1183 future.thenAccept((result) -> { 1184 logi("startEmergencySms(" + logTag + "): messageId=" + request.messageId 1185 + ", result=" + result); 1186 // An emergency SMS should be proceeded regardless of the result of the 1187 // EmergencyStateTracker. 1188 // So the domain selection request should be invoked without checking the result. 1189 requestDomainSelection(holder, request, logTag); 1190 }); 1191 } else { 1192 requestDomainSelection(holder, request, logTag); 1193 } 1194 } 1195 1196 /** 1197 * Sends a SMS after selecting the domain via the domain selection service. 1198 * 1199 * @param holder The {@link DomainSelectionConnectionHolder} that contains the 1200 * {@link DomainSelectionConnection} and its related information. 1201 * @param request The {@link PendingRequest} that stores the SMS request 1202 * (data, text, multipart text) to be sent. 1203 * @param logTag The log tag to display which method called this method. 1204 */ sendSmsUsingDomainSelection(@onNull DomainSelectionConnectionHolder holder, @NonNull PendingRequest request, @NonNull String logTag)1205 private void sendSmsUsingDomainSelection(@NonNull DomainSelectionConnectionHolder holder, 1206 @NonNull PendingRequest request, @NonNull String logTag) { 1207 // Run on main thread for interworking with EmergencyStateTracker 1208 // and adding the pending request. 1209 SomeArgs args = SomeArgs.obtain(); 1210 args.arg1 = holder; 1211 args.arg2 = request; 1212 args.arg3 = logTag; 1213 sendMessage(obtainMessage(EVENT_SEND_SMS_USING_DOMAIN_SELECTION, args)); 1214 } 1215 1216 /** 1217 * Called when sending MO SMS is complete regardless of the sent result. 1218 * 1219 * @param destAddr The destination address for SMS. 1220 * @param messageId The message id for SMS. 1221 * @param success A flag specifying whether MO SMS is successfully sent or not. 1222 * @param isOverIms A flag specifying whether MO SMS is sent over IMS or not. 1223 * @param isLastSmsPart A flag specifying whether this result is for the last SMS part or not. 1224 */ handleSmsSentCompletedUsingDomainSelection(@onNull String destAddr, long messageId, boolean success, boolean isOverIms, boolean isLastSmsPart)1225 private void handleSmsSentCompletedUsingDomainSelection(@NonNull String destAddr, 1226 long messageId, boolean success, boolean isOverIms, boolean isLastSmsPart) { 1227 if (mEmergencyStateTracker != null) { 1228 if (isEmergencyNumber(destAddr)) { 1229 mEmergencyStateTracker.endSms(String.valueOf(messageId), success, 1230 isOverIms ? NetworkRegistrationInfo.DOMAIN_PS 1231 : NetworkRegistrationInfo.DOMAIN_CS, 1232 isLastSmsPart); 1233 } 1234 } 1235 } 1236 1237 /** 1238 * Called when MO SMS is sent. 1239 */ notifySmsSent(@onNull SMSDispatcher.SmsTracker tracker, boolean isOverIms, boolean isLastSmsPart, boolean success)1240 protected void notifySmsSent(@NonNull SMSDispatcher.SmsTracker tracker, 1241 boolean isOverIms, boolean isLastSmsPart, boolean success) { 1242 notifySmsSentToEmergencyStateTracker(tracker.mDestAddress, 1243 tracker.mMessageId, isOverIms, isLastSmsPart, success); 1244 notifySmsSentToDatagramDispatcher(tracker.mUniqueMessageId, 1245 tracker.isSinglePartOrLastPart(), success && !tracker.isAnyPartFailed()); 1246 } 1247 1248 /** 1249 * Called when MO SMS is sent. 1250 */ notifySmsSentToEmergencyStateTracker(@onNull String destAddr, long messageId, boolean isOverIms, boolean isLastSmsPart, boolean success)1251 private void notifySmsSentToEmergencyStateTracker(@NonNull String destAddr, long messageId, 1252 boolean isOverIms, boolean isLastSmsPart, boolean success) { 1253 if (isSmsDomainSelectionEnabled()) { 1254 // Run on main thread for interworking with EmergencyStateTracker. 1255 SomeArgs args = SomeArgs.obtain(); 1256 args.arg1 = destAddr; 1257 args.arg2 = Long.valueOf(messageId); 1258 args.arg3 = Boolean.valueOf(success); 1259 args.arg4 = Boolean.valueOf(isOverIms); 1260 args.arg5 = Boolean.valueOf(isLastSmsPart); 1261 sendMessage(obtainMessage(EVENT_SMS_SENT_COMPLETED_USING_DOMAIN_SELECTION, args)); 1262 } 1263 } 1264 notifySmsSentToDatagramDispatcher( long messageId, boolean isLastSmsPart, boolean success)1265 private void notifySmsSentToDatagramDispatcher( 1266 long messageId, boolean isLastSmsPart, boolean success) { 1267 if (SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone) 1268 && isLastSmsPart) { 1269 DatagramDispatcher.getInstance().onSendSmsDone( 1270 mPhone.getSubId(), messageId, success); 1271 } 1272 } 1273 1274 /** 1275 * Called when MT SMS is received via IMS. 1276 * 1277 * @param origAddr The originating address of MT SMS. 1278 */ handleSmsReceivedViaIms(@ullable String origAddr)1279 private void handleSmsReceivedViaIms(@Nullable String origAddr) { 1280 if (mEmergencyStateTracker != null) { 1281 if (origAddr != null && isEmergencyNumber(origAddr)) { 1282 mEmergencyStateTracker.onEmergencySmsReceived(); 1283 } 1284 } 1285 } 1286 1287 /** 1288 * Called when MT SMS is received via IMS. 1289 */ notifySmsReceivedViaImsToEmergencyStateTracker(@ullable String origAddr)1290 protected void notifySmsReceivedViaImsToEmergencyStateTracker(@Nullable String origAddr) { 1291 if (isSmsDomainSelectionEnabled()) { 1292 // Run on main thread for interworking with EmergencyStateTracker. 1293 sendMessage(obtainMessage(EVENT_SMS_RECEIVED_VIA_IMS, origAddr)); 1294 } 1295 } 1296 isTestEmergencyNumber(String number)1297 private boolean isTestEmergencyNumber(String number) { 1298 try { 1299 if (!mPhone.hasCalling()) return false; 1300 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 1301 if (tm == null) return false; 1302 Map<Integer, List<EmergencyNumber>> eMap = tm.getEmergencyNumberList(); 1303 return eMap.values().stream().flatMap(Collection::stream).anyMatch(eNumber -> 1304 eNumber.isFromSources(EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST) 1305 && number.equals(eNumber.getNumber())); 1306 } catch (IllegalStateException ise) { 1307 return false; 1308 } catch (RuntimeException r) { 1309 return false; 1310 } 1311 } 1312 1313 /** 1314 * Finishes the domain selection for MO SMS. 1315 * 1316 * @param holder The {@link DomainSelectionConnectionHolder} object that is being finished. 1317 */ finishDomainSelection(DomainSelectionConnectionHolder holder)1318 private void finishDomainSelection(DomainSelectionConnectionHolder holder) { 1319 DomainSelectionConnection connection = (holder != null) ? holder.getConnection() : null; 1320 1321 if (connection != null) { 1322 // After this method is called, the domain selection service will clean up 1323 // its resources and finish the procedure that are related to the current domain 1324 // selection request. 1325 connection.finishSelection(); 1326 } 1327 1328 if (holder != null) { 1329 final List<PendingRequest> pendingRequests = holder.getPendingRequests(); 1330 1331 logd("finishDomainSelection: pendingRequests=" + pendingRequests.size()); 1332 1333 for (PendingRequest r : pendingRequests) { 1334 triggerSentIntentForFailure(r.sentIntents); 1335 } 1336 1337 holder.clearAllRequests(); 1338 holder.setConnection(null); 1339 } 1340 } 1341 1342 /** 1343 * Called when MO SMS is not sent by the error of domain selection. 1344 * 1345 * @param holder The {@link DomainSelectionConnectionHolder} object that is being terminated. 1346 */ handleDomainSelectionTerminatedAbnormally( @onNull DomainSelectionConnectionHolder holder)1347 private void handleDomainSelectionTerminatedAbnormally( 1348 @NonNull DomainSelectionConnectionHolder holder) { 1349 logd("handleDomainSelectionTerminatedAbnormally: pendingRequests=" 1350 + holder.getPendingRequests().size()); 1351 sendAllPendingRequests(holder, NetworkRegistrationInfo.DOMAIN_UNKNOWN); 1352 holder.setConnection(null); 1353 } 1354 1355 /** 1356 * Sends all pending requests for MO SMS. 1357 * 1358 * @param holder The {@link DomainSelectionConnectionHolder} object that all the pending 1359 * requests are handled. 1360 * @param domain The domain where the SMS is being sent, which can be one of the following: 1361 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1362 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1363 */ sendAllPendingRequests(@onNull DomainSelectionConnectionHolder holder, @NetworkRegistrationInfo.Domain int domain)1364 private void sendAllPendingRequests(@NonNull DomainSelectionConnectionHolder holder, 1365 @NetworkRegistrationInfo.Domain int domain) { 1366 final List<PendingRequest> pendingRequests = holder.getPendingRequests(); 1367 1368 if (VDBG) { 1369 logd("sendAllPendingRequests: domain=" + DomainSelectionService.getDomainName(domain) 1370 + ", size=" + pendingRequests.size()); 1371 } 1372 1373 // When the domain selection request is failed, SMS should be fallback 1374 // to the legacy implementation. 1375 boolean wasDomainUnknown = false; 1376 1377 if (domain == NetworkRegistrationInfo.DOMAIN_UNKNOWN) { 1378 logd("sendAllPendingRequests: fallback - imsAvailable=" 1379 + mImsSmsDispatcher.isAvailable()); 1380 1381 wasDomainUnknown = true; 1382 1383 if (mImsSmsDispatcher.isAvailable()) { 1384 domain = NetworkRegistrationInfo.DOMAIN_PS; 1385 } else { 1386 domain = NetworkRegistrationInfo.DOMAIN_CS; 1387 } 1388 } 1389 1390 for (PendingRequest r : pendingRequests) { 1391 switch (r.type) { 1392 case PendingRequest.TYPE_DATA: 1393 sendData(domain, r); 1394 break; 1395 case PendingRequest.TYPE_TEXT: 1396 // When the domain selection request is failed, emergency SMS should be fallback 1397 // to the legacy implementation. 1398 if (wasDomainUnknown 1399 && domain != NetworkRegistrationInfo.DOMAIN_PS 1400 && mImsSmsDispatcher.isEmergencySmsSupport(r.destAddr)) { 1401 domain = NetworkRegistrationInfo.DOMAIN_PS; 1402 } 1403 sendText(domain, r); 1404 break; 1405 case PendingRequest.TYPE_MULTIPART_TEXT: 1406 sendMultipartText(domain, r); 1407 break; 1408 case PendingRequest.TYPE_RETRY_SMS: 1409 sendRetrySms(r.tracker, (domain == NetworkRegistrationInfo.DOMAIN_PS)); 1410 break; 1411 default: 1412 // Not reachable. 1413 break; 1414 } 1415 } 1416 1417 holder.clearAllRequests(); 1418 } 1419 1420 /** 1421 * Sends a data based SMS to a specific application port. 1422 * 1423 * @param domain The domain where the SMS is being sent, which can be one of the following: 1424 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1425 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1426 * @param request The pending request for MO SMS. 1427 */ sendData(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1428 private void sendData(@NetworkRegistrationInfo.Domain int domain, 1429 @NonNull PendingRequest request) { 1430 if (domain == NetworkRegistrationInfo.DOMAIN_PS) { 1431 mImsSmsDispatcher.sendData(request.callingPackage, request.callingUser, 1432 request.destAddr, request.scAddr, request.destPort, request.data, 1433 request.sentIntents.get(0), request.deliveryIntents.get(0), request.isForVvm, 1434 request.uniqueMessageId); 1435 } else if (isCdmaMo(domain)) { 1436 mCdmaDispatcher.sendData(request.callingPackage, request.callingUser, request.destAddr, 1437 request.scAddr, request.destPort, request.data, 1438 request.sentIntents.get(0), request.deliveryIntents.get(0), request.isForVvm, 1439 request.uniqueMessageId); 1440 } else { 1441 mGsmDispatcher.sendData(request.callingPackage, request.callingUser, request.destAddr, 1442 request.scAddr, request.destPort, request.data, 1443 request.sentIntents.get(0), request.deliveryIntents.get(0), request.isForVvm, 1444 request.uniqueMessageId); 1445 } 1446 } 1447 1448 /** 1449 * Sends a text based SMS. 1450 * 1451 * @param domain The domain where the SMS is being sent, which can be one of the following: 1452 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1453 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1454 * @param request The pending request for MO SMS. 1455 */ sendText(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1456 private void sendText(@NetworkRegistrationInfo.Domain int domain, 1457 @NonNull PendingRequest request) { 1458 if (domain == NetworkRegistrationInfo.DOMAIN_PS) { 1459 mImsSmsDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1460 request.sentIntents.get(0), request.deliveryIntents.get(0), 1461 request.messageUri, request.callingPackage, request.callingUser, 1462 request.persistMessage, request.priority, /*request.expectMore*/ false, 1463 request.validityPeriod, request.isForVvm, request.messageId, 1464 request.skipShortCodeCheck, request.uniqueMessageId); 1465 } else { 1466 if (isCdmaMo(domain)) { 1467 mCdmaDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1468 request.sentIntents.get(0), request.deliveryIntents.get(0), 1469 request.messageUri, request.callingPackage, request.callingUser, 1470 request.persistMessage, request.priority, request.expectMore, 1471 request.validityPeriod, request.isForVvm, request.messageId, 1472 request.skipShortCodeCheck, request.uniqueMessageId); 1473 } else { 1474 mGsmDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1475 request.sentIntents.get(0), request.deliveryIntents.get(0), 1476 request.messageUri, request.callingPackage, request.callingUser, 1477 request.persistMessage, request.priority, request.expectMore, 1478 request.validityPeriod, request.isForVvm, request.messageId, 1479 request.skipShortCodeCheck, request.uniqueMessageId); 1480 } 1481 } 1482 } 1483 1484 /** 1485 * Sends a multi-part text based SMS. 1486 * 1487 * @param domain The domain where the SMS is being sent, which can be one of the following: 1488 * - {@link NetworkRegistrationInfo#DOMAIN_PS} 1489 * - {@link NetworkRegistrationInfo#DOMAIN_CS} 1490 * @param request The pending request for MO SMS. 1491 */ sendMultipartText(@etworkRegistrationInfo.Domain int domain, @NonNull PendingRequest request)1492 private void sendMultipartText(@NetworkRegistrationInfo.Domain int domain, 1493 @NonNull PendingRequest request) { 1494 if (domain == NetworkRegistrationInfo.DOMAIN_PS) { 1495 mImsSmsDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 1496 request.sentIntents, request.deliveryIntents, request.messageUri, 1497 request.callingPackage, request.callingUser, request.persistMessage, 1498 request.priority, false /*request.expectMore*/, request.validityPeriod, 1499 request.messageId, request.uniqueMessageId); 1500 } else { 1501 if (isCdmaMo(domain)) { 1502 mCdmaDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 1503 request.sentIntents, request.deliveryIntents, request.messageUri, 1504 request.callingPackage, request.callingUser, request.persistMessage, 1505 request.priority, request.expectMore, request.validityPeriod, 1506 request.messageId, request.uniqueMessageId); 1507 } else { 1508 mGsmDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 1509 request.sentIntents, request.deliveryIntents, request.messageUri, 1510 request.callingPackage, request.callingUser, request.persistMessage, 1511 request.priority, request.expectMore, request.validityPeriod, 1512 request.messageId, request.uniqueMessageId); 1513 } 1514 } 1515 } 1516 triggerSentIntentForFailure(PendingIntent sentIntent)1517 private void triggerSentIntentForFailure(PendingIntent sentIntent) { 1518 if (sentIntent == null) { 1519 logd("sentIntent is null"); 1520 return; 1521 } 1522 try { 1523 sentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); 1524 } catch (CanceledException e) { 1525 logd("Intent has been canceled!"); 1526 } 1527 } 1528 triggerSentIntentForFailure(List<PendingIntent> sentIntents)1529 private void triggerSentIntentForFailure(List<PendingIntent> sentIntents) { 1530 if (sentIntents == null) { 1531 logd("sentIntents is null"); 1532 return; 1533 } 1534 for (PendingIntent sentIntent : sentIntents) { 1535 triggerSentIntentForFailure(sentIntent); 1536 } 1537 } 1538 1539 /** 1540 * Creates an ArrayList object from any object. 1541 */ asArrayList(T object)1542 private static <T> ArrayList<T> asArrayList(T object) { 1543 ArrayList<T> list = new ArrayList<>(); 1544 list.add(object); 1545 return list; 1546 } 1547 1548 /** 1549 * Send a data based SMS to a specific application port. 1550 * 1551 * @param callingPackage the package name of the calling app 1552 * @param destAddr the address to send the message to 1553 * @param scAddr is the service center address or null to use 1554 * the current default SMSC 1555 * @param destPort the port to deliver the message to 1556 * @param data the body of the message to send 1557 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1558 * broadcast when the message is successfully sent, or failed. 1559 * The result code will be <code>Activity.RESULT_OK<code> for success, 1560 * or one of these errors:<br> 1561 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1562 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1563 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1564 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1565 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1566 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1567 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1568 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1569 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1570 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1571 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1572 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1573 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1574 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1575 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1576 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1577 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1578 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1579 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1580 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1581 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1582 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1583 * <code>SmsManager.RESULT_CANCELLED</code><br> 1584 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1585 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1586 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1587 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1588 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1589 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1590 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1591 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1592 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1593 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1594 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1595 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1596 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1597 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1598 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1599 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1600 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1601 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1602 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1603 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1604 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1605 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1606 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1607 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1608 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1609 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1610 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1611 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1612 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1613 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1614 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1615 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1616 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1617 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1618 * the sentIntent may include the extra "errorCode" containing a radio technology specific 1619 * value, generally only useful for troubleshooting.<br> 1620 * The per-application based SMS control checks sentIntent. If sentIntent 1621 * is NULL the caller will be checked against all unknown applications, 1622 * which cause smaller number of SMS to be sent in checking period. 1623 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1624 * broadcast when the message is delivered to the recipient. The 1625 * raw pdu of the status report is in the extended data ("pdu"). 1626 */ sendData(String callingPackage, int callingUser, String destAddr, String scAddr, int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean isForVvm)1627 protected void sendData(String callingPackage, int callingUser, String destAddr, String scAddr, 1628 int destPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent, 1629 boolean isForVvm) { 1630 if (TextUtils.isEmpty(scAddr)) { 1631 scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPackage); 1632 } 1633 1634 if (isSmsDomainSelectionEnabled()) { 1635 sendSmsUsingDomainSelection(getDomainSelectionConnectionHolder(false), 1636 new PendingRequest(PendingRequest.TYPE_DATA, null, callingPackage, callingUser, 1637 destAddr, scAddr, asArrayList(sentIntent), 1638 asArrayList(deliveryIntent), isForVvm, data, destPort, null, 1639 null, false, 0, false, 0, 1640 0L, false, false), 1641 "sendData"); 1642 return; 1643 } 1644 1645 if (mImsSmsDispatcher.isAvailable()) { 1646 mImsSmsDispatcher.sendData(callingPackage, callingUser, destAddr, scAddr, destPort, 1647 data, sentIntent, deliveryIntent, isForVvm, 1648 PendingRequest.getNextUniqueMessageId()); 1649 } else if (isCdmaMo()) { 1650 mCdmaDispatcher.sendData(callingPackage, callingUser, destAddr, scAddr, destPort, data, 1651 sentIntent, deliveryIntent, isForVvm, 1652 PendingRequest.getNextUniqueMessageId()); 1653 } else { 1654 mGsmDispatcher.sendData(callingPackage, callingUser, destAddr, scAddr, destPort, data, 1655 sentIntent, deliveryIntent, isForVvm, 1656 PendingRequest.getNextUniqueMessageId()); 1657 } 1658 } 1659 1660 /** 1661 * Send a text based SMS. 1662 * 1663 * @param destAddr the address to send the message to 1664 * @param scAddr is the service center address or null to use 1665 * the current default SMSC 1666 * @param text the body of the message to send 1667 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1668 * broadcast when the message is successfully sent, or failed. 1669 * The result code will be <code>Activity.RESULT_OK<code> for success, 1670 * or one of these errors:<br> 1671 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1672 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1673 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1674 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1675 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1676 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1677 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1678 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1679 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1680 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1681 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1682 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1683 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1684 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1685 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1686 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1687 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1688 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1689 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1690 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1691 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1692 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1693 * <code>SmsManager.RESULT_CANCELLED</code><br> 1694 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1695 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1696 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1697 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1698 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1699 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1700 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1701 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1702 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1703 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1704 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1705 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1706 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1707 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1708 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1709 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1710 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1711 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1712 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1713 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1714 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1715 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1716 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1717 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1718 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1719 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1720 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1721 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1722 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1723 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1724 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1725 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1726 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1727 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1728 * the sentIntent may include the extra "errorCode" containing a radio technology specific 1729 * value, generally only useful for troubleshooting.<br> 1730 * The per-application based SMS control checks sentIntent. If sentIntent 1731 * is NULL the caller will be checked against all unknown applications, 1732 * which cause smaller number of SMS to be sent in checking period. 1733 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1734 * broadcast when the message is delivered to the recipient. The 1735 * @param messageUri optional URI of the message if it is already stored in the system 1736 * @param callingPkg the calling package name 1737 * @param persistMessage whether to save the sent message into SMS DB for a 1738 * non-default SMS app. 1739 * @param priority Priority level of the message 1740 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 1741 * --------------------------------- 1742 * PRIORITY | Level of Priority 1743 * --------------------------------- 1744 * '00' | Normal 1745 * '01' | Interactive 1746 * '10' | Urgent 1747 * '11' | Emergency 1748 * ---------------------------------- 1749 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 1750 * @param expectMore is a boolean to indicate the sending messages through same link or not. 1751 * @param validityPeriod Validity Period of the message in mins. 1752 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 1753 * Validity Period(Minimum) -> 5 mins 1754 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 1755 * Any Other values included Negative considered as Invalid Validity Period of the message. 1756 */ sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, int callingUser, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId)1757 public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, 1758 PendingIntent deliveryIntent, Uri messageUri, String callingPkg, int callingUser, 1759 boolean persistMessage, int priority, boolean expectMore, int validityPeriod, 1760 boolean isForVvm, long messageId) { 1761 sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, messageUri, callingPkg, 1762 callingUser, persistMessage, priority, expectMore, validityPeriod, isForVvm, 1763 messageId, false); 1764 } 1765 1766 /** 1767 * Send a text based SMS. 1768 * 1769 * @param destAddr the address to send the message to 1770 * @param scAddr is the service center address or null to use 1771 * the current default SMSC 1772 * @param text the body of the message to send 1773 * @param sentIntent if not NULL this <code>PendingIntent</code> is 1774 * broadcast when the message is successfully sent, or failed. 1775 * The result code will be <code>Activity.RESULT_OK<code> for success, 1776 * or one of these errors:<br> 1777 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1778 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1779 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1780 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1781 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1782 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1783 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1784 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1785 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1786 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1787 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1788 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1789 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1790 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1791 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1792 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1793 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1794 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1795 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1796 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1797 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1798 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1799 * <code>SmsManager.RESULT_CANCELLED</code><br> 1800 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1801 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1802 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1803 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1804 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1805 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1806 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1807 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1808 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1809 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1810 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1811 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1812 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1813 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1814 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1815 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1816 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1817 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1818 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1819 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1820 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1821 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1822 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1823 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1824 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1825 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1826 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1827 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1828 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1829 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1830 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1831 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1832 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1833 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1834 * the sentIntent may include the extra "errorCode" containing a radio technology specific 1835 * value, generally only useful for troubleshooting.<br> 1836 * The per-application based SMS control checks sentIntent. If sentIntent 1837 * is NULL the caller will be checked against all unknown applications, 1838 * which cause smaller number of SMS to be sent in checking period. 1839 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 1840 * broadcast when the message is delivered to the recipient. The 1841 * @param messageUri optional URI of the message if it is already stored in the system 1842 * @param callingPkg the calling package name 1843 * @param persistMessage whether to save the sent message into SMS DB for a 1844 * non-default SMS app. 1845 * @param priority Priority level of the message 1846 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 1847 * --------------------------------- 1848 * PRIORITY | Level of Priority 1849 * --------------------------------- 1850 * '00' | Normal 1851 * '01' | Interactive 1852 * '10' | Urgent 1853 * '11' | Emergency 1854 * ---------------------------------- 1855 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 1856 * @param expectMore is a boolean to indicate the sending messages through same link or not. 1857 * @param validityPeriod Validity Period of the message in mins. 1858 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 1859 * Validity Period(Minimum) -> 5 mins 1860 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 1861 * Any Other values included Negative considered as Invalid Validity Period of the message. 1862 * @param skipShortCodeCheck Skip check for short code type destination address. 1863 */ sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg, int callingUser, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, boolean isForVvm, long messageId, boolean skipShortCodeCheck)1864 public void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, 1865 PendingIntent deliveryIntent, Uri messageUri, String callingPkg, int callingUser, 1866 boolean persistMessage, int priority, boolean expectMore, int validityPeriod, 1867 boolean isForVvm, long messageId, boolean skipShortCodeCheck) { 1868 if (TextUtils.isEmpty(scAddr)) { 1869 scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); 1870 } 1871 1872 PendingRequest pendingRequest = new PendingRequest(PendingRequest.TYPE_TEXT, null, 1873 callingPkg, callingUser, destAddr, scAddr, asArrayList(sentIntent), 1874 asArrayList(deliveryIntent), isForVvm, null, 0, asArrayList(text), 1875 messageUri, persistMessage, priority, expectMore, validityPeriod, messageId, 1876 skipShortCodeCheck, false); 1877 1878 if (SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone)) { 1879 // Send P2P SMS using carrier roaming NB IOT NTN 1880 DatagramDispatcher.getInstance().sendSms(pendingRequest); 1881 return; 1882 } else if (SatelliteController.getInstance().isInCarrierRoamingNbIotNtn()) { 1883 Rlog.d(TAG, "Block SMS in carrier roaming NB IOT NTN mode."); 1884 // Block SMS in satellite mode if P2P SMS is not supported. 1885 triggerSentIntentForFailure(pendingRequest.sentIntents); 1886 return; 1887 } 1888 1889 sendTextInternal(pendingRequest); 1890 } 1891 sendTextInternal(PendingRequest request)1892 private void sendTextInternal(PendingRequest request) { 1893 logd("sendTextInternal: messageId=" + request.messageId 1894 + ", uniqueMessageId=" + request.uniqueMessageId); 1895 if (isSmsDomainSelectionEnabled()) { 1896 boolean isEmergency = isEmergencyNumber(request.destAddr); 1897 sendSmsUsingDomainSelection(getDomainSelectionConnectionHolder(isEmergency), 1898 request, "sendText"); 1899 return; 1900 } 1901 1902 if (mImsSmsDispatcher.isAvailable() || mImsSmsDispatcher.isEmergencySmsSupport( 1903 request.destAddr)) { 1904 mImsSmsDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1905 request.sentIntents.get(0), request.deliveryIntents.get(0), 1906 request.messageUri, request.callingPackage, request.callingUser, 1907 request.persistMessage, request.priority, false /*expectMore*/, 1908 request.validityPeriod, request.isForVvm, request.messageId, 1909 request.skipShortCodeCheck, request.uniqueMessageId); 1910 } else { 1911 if (isCdmaMo()) { 1912 mCdmaDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1913 request.sentIntents.get(0), request.deliveryIntents.get(0), 1914 request.messageUri, request.callingPackage, request.callingUser, 1915 request.persistMessage, request.priority, request.expectMore, 1916 request.validityPeriod, request.isForVvm, request.messageId, 1917 request.skipShortCodeCheck, request.uniqueMessageId); 1918 } else { 1919 mGsmDispatcher.sendText(request.destAddr, request.scAddr, request.texts.get(0), 1920 request.sentIntents.get(0), request.deliveryIntents.get(0), 1921 request.messageUri, request.callingPackage, request.callingUser, 1922 request.persistMessage, request.priority, request.expectMore, 1923 request.validityPeriod, request.isForVvm, request.messageId, 1924 request.skipShortCodeCheck, request.uniqueMessageId); 1925 } 1926 } 1927 } 1928 1929 /** 1930 * Send a multi-part text based SMS. 1931 * 1932 * @param destAddr the address to send the message to 1933 * @param scAddr is the service center address or null to use 1934 * the current default SMSC 1935 * @param parts an <code>ArrayList</code> of strings that, in order, 1936 * comprise the original message 1937 * @param sentIntents if not null, an <code>ArrayList</code> of 1938 * <code>PendingIntent</code>s (one for each message part) that is 1939 * broadcast when the corresponding message part has been sent. 1940 * The result code will be <code>Activity.RESULT_OK<code> for success, 1941 * or one of these errors:<br> 1942 * <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code><br> 1943 * <code>SmsManager.RESULT_ERROR_RADIO_OFF</code><br> 1944 * <code>SmsManager.RESULT_ERROR_NULL_PDU</code><br> 1945 * <code>SmsManager.RESULT_ERROR_NO_SERVICE</code><br> 1946 * <code>SmsManager.RESULT_ERROR_LIMIT_EXCEEDED</code><br> 1947 * <code>SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE</code><br> 1948 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> 1949 * <code>SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED</code><br> 1950 * <code>SmsManager.RESULT_RADIO_NOT_AVAILABLE</code><br> 1951 * <code>SmsManager.RESULT_NETWORK_REJECT</code><br> 1952 * <code>SmsManager.RESULT_INVALID_ARGUMENTS</code><br> 1953 * <code>SmsManager.RESULT_INVALID_STATE</code><br> 1954 * <code>SmsManager.RESULT_NO_MEMORY</code><br> 1955 * <code>SmsManager.RESULT_INVALID_SMS_FORMAT</code><br> 1956 * <code>SmsManager.RESULT_SYSTEM_ERROR</code><br> 1957 * <code>SmsManager.RESULT_MODEM_ERROR</code><br> 1958 * <code>SmsManager.RESULT_NETWORK_ERROR</code><br> 1959 * <code>SmsManager.RESULT_ENCODING_ERROR</code><br> 1960 * <code>SmsManager.RESULT_INVALID_SMSC_ADDRESS</code><br> 1961 * <code>SmsManager.RESULT_OPERATION_NOT_ALLOWED</code><br> 1962 * <code>SmsManager.RESULT_INTERNAL_ERROR</code><br> 1963 * <code>SmsManager.RESULT_NO_RESOURCES</code><br> 1964 * <code>SmsManager.RESULT_CANCELLED</code><br> 1965 * <code>SmsManager.RESULT_REQUEST_NOT_SUPPORTED</code><br> 1966 * <code>SmsManager.RESULT_NO_BLUETOOTH_SERVICE</code><br> 1967 * <code>SmsManager.RESULT_INVALID_BLUETOOTH_ADDRESS</code><br> 1968 * <code>SmsManager.RESULT_BLUETOOTH_DISCONNECTED</code><br> 1969 * <code>SmsManager.RESULT_UNEXPECTED_EVENT_STOP_SENDING</code><br> 1970 * <code>SmsManager.RESULT_SMS_BLOCKED_DURING_EMERGENCY</code><br> 1971 * <code>SmsManager.RESULT_SMS_SEND_RETRY_FAILED</code><br> 1972 * <code>SmsManager.RESULT_REMOTE_EXCEPTION</code><br> 1973 * <code>SmsManager.RESULT_NO_DEFAULT_SMS_APP</code><br> 1974 * <code>SmsManager.RESULT_RIL_RADIO_NOT_AVAILABLE</code><br> 1975 * <code>SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY</code><br> 1976 * <code>SmsManager.RESULT_RIL_NETWORK_REJECT</code><br> 1977 * <code>SmsManager.RESULT_RIL_INVALID_STATE</code><br> 1978 * <code>SmsManager.RESULT_RIL_INVALID_ARGUMENTS</code><br> 1979 * <code>SmsManager.RESULT_RIL_NO_MEMORY</code><br> 1980 * <code>SmsManager.RESULT_RIL_REQUEST_RATE_LIMITED</code><br> 1981 * <code>SmsManager.RESULT_RIL_INVALID_SMS_FORMAT</code><br> 1982 * <code>SmsManager.RESULT_RIL_SYSTEM_ERR</code><br> 1983 * <code>SmsManager.RESULT_RIL_ENCODING_ERR</code><br> 1984 * <code>SmsManager.RESULT_RIL_INVALID_SMSC_ADDRESS</code><br> 1985 * <code>SmsManager.RESULT_RIL_MODEM_ERR</code><br> 1986 * <code>SmsManager.RESULT_RIL_NETWORK_ERR</code><br> 1987 * <code>SmsManager.RESULT_RIL_INTERNAL_ERR</code><br> 1988 * <code>SmsManager.RESULT_RIL_REQUEST_NOT_SUPPORTED</code><br> 1989 * <code>SmsManager.RESULT_RIL_INVALID_MODEM_STATE</code><br> 1990 * <code>SmsManager.RESULT_RIL_NETWORK_NOT_READY</code><br> 1991 * <code>SmsManager.RESULT_RIL_OPERATION_NOT_ALLOWED</code><br> 1992 * <code>SmsManager.RESULT_RIL_NO_RESOURCES</code><br> 1993 * <code>SmsManager.RESULT_RIL_CANCELLED</code><br> 1994 * <code>SmsManager.RESULT_RIL_SIM_ABSENT</code><br> 1995 * <code>SmsManager.RESULT_RIL_SIMULTANEOUS_SMS_AND_CALL_NOT_ALLOWED</code><br> 1996 * <code>SmsManager.RESULT_RIL_ACCESS_BARRED</code><br> 1997 * <code>SmsManager.RESULT_RIL_BLOCKED_DUE_TO_CALL</code><br> 1998 * For <code>SmsManager.RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, 1999 * the sentIntent may include the extra "errorCode" containing a radio technology specific 2000 * value, generally only useful for troubleshooting.<br> 2001 * The per-application based SMS control checks sentIntent. If sentIntent 2002 * is NULL the caller will be checked against all unknown applications, 2003 * which cause smaller number of SMS to be sent in checking period. 2004 * @param deliveryIntents if not null, an <code>ArrayList</code> of 2005 * <code>PendingIntent</code>s (one for each message part) that is 2006 * broadcast when the corresponding message part has been delivered 2007 * to the recipient. The raw pdu of the status report is in the 2008 * @param messageUri optional URI of the message if it is already stored in the system 2009 * @param callingPkg the calling package name 2010 * @param persistMessage whether to save the sent message into SMS DB for a 2011 * non-default SMS app. 2012 * @param priority Priority level of the message 2013 * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 2014 * --------------------------------- 2015 * PRIORITY | Level of Priority 2016 * --------------------------------- 2017 * '00' | Normal 2018 * '01' | Interactive 2019 * '10' | Urgent 2020 * '11' | Emergency 2021 * ---------------------------------- 2022 * Any Other values included Negative considered as Invalid Priority Indicator of the message. 2023 * @param expectMore is a boolean to indicate the sending messages through same link or not. 2024 * @param validityPeriod Validity Period of the message in mins. 2025 * Refer specification 3GPP TS 23.040 V6.8.1 section 9.2.3.12.1. 2026 * Validity Period(Minimum) -> 5 mins 2027 * Validity Period(Maximum) -> 635040 mins(i.e.63 weeks). 2028 * Any Other values included Negative considered as Invalid Validity Period of the message. 2029 * @param messageId An id that uniquely identifies the message requested to be sent. 2030 * Used for logging and diagnostics purposes. The id may be 0. 2031 * 2032 */ sendMultipartText(String destAddr, String scAddr, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, int callingUser, boolean persistMessage, int priority, boolean expectMore, int validityPeriod, long messageId)2033 protected void sendMultipartText(String destAddr, String scAddr, 2034 ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, 2035 ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg, 2036 int callingUser, boolean persistMessage, int priority, boolean expectMore, 2037 int validityPeriod, long messageId) { 2038 if (TextUtils.isEmpty(scAddr)) { 2039 scAddr = getSmscAddressFromUSIMWithPhoneIdentity(callingPkg); 2040 } 2041 2042 PendingRequest pendingRequest = new PendingRequest(PendingRequest.TYPE_MULTIPART_TEXT, null, 2043 callingPkg, callingUser, destAddr, scAddr, sentIntents, deliveryIntents, false, 2044 null, 0, parts, messageUri, persistMessage, priority, expectMore, 2045 validityPeriod, messageId, false, false); 2046 2047 if (SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone)) { 2048 // Send multipart P2P SMS using carrier roaming NB IOT NTN 2049 DatagramDispatcher.getInstance().sendSms(pendingRequest); 2050 return; 2051 } else if (SatelliteController.getInstance().isInCarrierRoamingNbIotNtn()) { 2052 Rlog.d(TAG, "Block SMS in carrier roaming NB IOT NTN mode."); 2053 // Block SMS in satellite mode if P2P SMS is not supported. 2054 triggerSentIntentForFailure(pendingRequest.sentIntents); 2055 return; 2056 } 2057 2058 sendMultipartTextInternal(pendingRequest); 2059 } 2060 isEmergencyNumber(String number)2061 private boolean isEmergencyNumber(String number) { 2062 if (!mPhone.hasCalling()) return false; 2063 TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); 2064 if (tm == null) return false; 2065 return tm.isEmergencyNumber(number); 2066 } 2067 sendMultipartTextInternal(PendingRequest request)2068 private void sendMultipartTextInternal(PendingRequest request) { 2069 logd("sendMultipartTextInternal: messageId=" + request.messageId); 2070 if (isSmsDomainSelectionEnabled()) { 2071 boolean isEmergency = isEmergencyNumber(request.destAddr); 2072 sendSmsUsingDomainSelection(getDomainSelectionConnectionHolder(isEmergency), 2073 request, "sendMultipartText"); 2074 return; 2075 } 2076 2077 if (mImsSmsDispatcher.isAvailable()) { 2078 mImsSmsDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 2079 request.sentIntents, request.deliveryIntents, request.messageUri, 2080 request.callingPackage, request.callingUser, request.persistMessage, 2081 request.priority, false /*expectMore*/, request.validityPeriod, 2082 request.messageId, request.uniqueMessageId); 2083 } else { 2084 if (isCdmaMo()) { 2085 mCdmaDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 2086 request.sentIntents, request.deliveryIntents, request.messageUri, 2087 request.callingPackage, request.callingUser, request.persistMessage, 2088 request.priority, request.expectMore, request.validityPeriod, 2089 request.messageId, request.uniqueMessageId); 2090 } else { 2091 mGsmDispatcher.sendMultipartText(request.destAddr, request.scAddr, request.texts, 2092 request.sentIntents, request.deliveryIntents, request.messageUri, 2093 request.callingPackage, request.callingUser, request.persistMessage, 2094 request.priority, request.expectMore, request.validityPeriod, 2095 request.messageId, request.uniqueMessageId); 2096 } 2097 } 2098 } 2099 2100 /** 2101 * Returns the premium SMS permission for the specified package. If the package has never 2102 * been seen before, the default {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN} 2103 * will be returned. 2104 * @param packageName the name of the package to query permission 2105 * @return one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_UNKNOWN}, 2106 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}, 2107 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 2108 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 2109 */ getPremiumSmsPermission(String packageName)2110 public int getPremiumSmsPermission(String packageName) { 2111 return mUsageMonitor.getPremiumSmsPermission(packageName); 2112 } 2113 2114 /** 2115 * Sets the premium SMS permission for the specified package and save the value asynchronously 2116 * to persistent storage. 2117 * @param packageName the name of the package to set permission 2118 * @param permission one of {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ASK_USER}, 2119 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 2120 * {@link SmsUsageMonitor#PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 2121 */ setPremiumSmsPermission(String packageName, int permission)2122 public void setPremiumSmsPermission(String packageName, int permission) { 2123 mUsageMonitor.setPremiumSmsPermission(packageName, permission); 2124 } 2125 getUsageMonitor()2126 public SmsUsageMonitor getUsageMonitor() { 2127 return mUsageMonitor; 2128 } 2129 2130 /** 2131 * Handles the sms status report based on the format. 2132 * 2133 * @param format the format. 2134 * @param pdu the pdu of the report. 2135 */ handleSmsStatusReport(String format, byte[] pdu)2136 public void handleSmsStatusReport(String format, byte[] pdu) { 2137 int messageRef; 2138 SMSDispatcher.SmsTracker tracker; 2139 boolean handled = false; 2140 if (isCdmaFormat(format)) { 2141 com.android.internal.telephony.cdma.SmsMessage sms = 2142 com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); 2143 if (sms != null) { 2144 boolean foundIn3GPPMap = false; 2145 messageRef = sms.mMessageRef; 2146 tracker = mDeliveryPendingMapFor3GPP2.get(messageRef); 2147 if (tracker == null) { 2148 // A tracker for this 3GPP2 report may be in the 3GPP map instead if the 2149 // previously submitted SMS was 3GPP format. 2150 // (i.e. Some carriers require that devices receive 3GPP2 SMS also even if IMS 2151 // SMS format is 3GGP.) 2152 tracker = mDeliveryPendingMapFor3GPP.get(messageRef); 2153 if (tracker != null) { 2154 foundIn3GPPMap = true; 2155 } 2156 } 2157 if (tracker != null) { 2158 // The status is composed of an error class (bits 25-24) and a status code 2159 // (bits 23-16). 2160 int errorClass = (sms.getStatus() >> 24) & 0x03; 2161 if (errorClass != ERROR_TEMPORARY) { 2162 // Update the message status (COMPLETE or FAILED) 2163 tracker.updateSentMessageStatus( 2164 mContext, 2165 (errorClass == ERROR_NONE) 2166 ? Sms.STATUS_COMPLETE 2167 : Sms.STATUS_FAILED); 2168 // No longer need to be kept. 2169 if (foundIn3GPPMap) { 2170 mDeliveryPendingMapFor3GPP.remove(messageRef); 2171 } else { 2172 mDeliveryPendingMapFor3GPP2.remove(messageRef); 2173 } 2174 } 2175 handled = triggerDeliveryIntent(tracker, format, pdu); 2176 } 2177 } 2178 } else { 2179 com.android.internal.telephony.gsm.SmsMessage sms = 2180 com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); 2181 if (sms != null) { 2182 messageRef = sms.mMessageRef; 2183 tracker = mDeliveryPendingMapFor3GPP.get(messageRef); 2184 if (tracker != null) { 2185 int tpStatus = sms.getStatus(); 2186 if (tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING) { 2187 // Update the message status (COMPLETE or FAILED) 2188 tracker.updateSentMessageStatus(mContext, tpStatus); 2189 // No longer need to be kept. 2190 mDeliveryPendingMapFor3GPP.remove(messageRef); 2191 } 2192 handled = triggerDeliveryIntent(tracker, format, pdu); 2193 } 2194 } 2195 } 2196 2197 if (!handled) { 2198 Rlog.e(TAG, "handleSmsStatusReport: can not handle the status report!"); 2199 } 2200 } 2201 triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, byte[] pdu)2202 private boolean triggerDeliveryIntent(SMSDispatcher.SmsTracker tracker, String format, 2203 byte[] pdu) { 2204 PendingIntent intent = tracker.mDeliveryIntent; 2205 Intent fillIn = new Intent(); 2206 fillIn.putExtra("pdu", pdu); 2207 fillIn.putExtra("format", format); 2208 try { 2209 intent.send(mContext, Activity.RESULT_OK, fillIn); 2210 return true; 2211 } catch (CanceledException ex) { 2212 return false; 2213 } 2214 } 2215 2216 /** 2217 * Get InboundSmsHandler for the phone. 2218 */ getInboundSmsHandler(boolean is3gpp2)2219 public InboundSmsHandler getInboundSmsHandler(boolean is3gpp2) { 2220 if (is3gpp2) return mCdmaInboundSmsHandler; 2221 else return mGsmInboundSmsHandler; 2222 } 2223 2224 /** 2225 * This API should be used only by {@link DatagramDispatcher} to send SMS over 2226 * non-terrestrial network. 2227 * 2228 * @param request {@link PendingRequest} object that contains all the information required to 2229 * send MO SMS. 2230 */ sendCarrierRoamingNbIotNtnText(@onNull PendingRequest request)2231 public void sendCarrierRoamingNbIotNtnText(@NonNull PendingRequest request) { 2232 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 2233 logd("sendCarrierRoamingNbIotNtnText: carrier roaming nb iot ntn " 2234 + "feature flag is disabled"); 2235 return; 2236 } 2237 2238 sendMessage(obtainMessage(CMD_SEND_TEXT, request)); 2239 } 2240 2241 /** 2242 * Send error code to pending MO SMS request. 2243 * 2244 * @param pendingRequest {@link PendingRequest} object that contains all the information 2245 * related to MO SMS. 2246 * @param errorCode error code to be returned. 2247 */ onSendCarrierRoamingNbIotNtnTextError(@onNull PendingRequest pendingRequest, @SatelliteManager.SatelliteResult int errorCode)2248 public void onSendCarrierRoamingNbIotNtnTextError(@NonNull PendingRequest pendingRequest, 2249 @SatelliteManager.SatelliteResult int errorCode) { 2250 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 2251 logd("onSendCarrierRoamingNbIotNtnTextError: carrier roaming nb iot ntn " 2252 + "feature flag is disabled"); 2253 return; 2254 } 2255 2256 logd("onSendCarrierRoamingNbIotNtnTextError: messageId=" + pendingRequest.messageId 2257 + " errorCode=" + errorCode); 2258 sendMessage(obtainMessage(EVENT_SEND_TEXT_OVER_NTN_ERROR, pendingRequest)); 2259 } 2260 2261 /** 2262 * This API should be used only by {@link DatagramDispatcher} to send MT SMS Polling message 2263 * over non-terrestrial network. 2264 * To enable users to receive incoming messages, the device needs to send an MO SMS to itself 2265 * to trigger SMSC to send all pending SMS to the particular subscription. 2266 */ sendMtSmsPollingMessage()2267 public void sendMtSmsPollingMessage() { 2268 if (!SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone)) { 2269 logd("sendMtSmsPollingMessage: not in roaming nb iot ntn"); 2270 return; 2271 } 2272 2273 SubscriptionManager subscriptionManager = (SubscriptionManager) mContext 2274 .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE); 2275 String destAddr = subscriptionManager.getPhoneNumber(mPhone.getSubId()); 2276 if (TextUtils.isEmpty(destAddr)) { 2277 logd("sendMtSmsPollingMessage: destAddr is null or empty."); 2278 return; 2279 } 2280 2281 String mtSmsPollingText = mContext.getResources() 2282 .getString(R.string.config_mt_sms_polling_text); 2283 if (TextUtils.isEmpty(mtSmsPollingText)) { 2284 logd("sendMtSmsPollingMessage: mtSmsPollingText is null or empty."); 2285 return; 2286 } 2287 2288 String callingPackage = mContext.getPackageName(); 2289 PendingRequest pendingRequest = new PendingRequest(PendingRequest.TYPE_TEXT, null, 2290 callingPackage, Binder.getCallingUserHandle().getIdentifier(), destAddr, 2291 getSmscAddressFromUSIMWithPhoneIdentity(callingPackage), asArrayList(null), 2292 asArrayList(null), false, null, 0, asArrayList(mtSmsPollingText), null, false, 0, 2293 false, 5, 0L, true, true); 2294 2295 if (SatelliteController.getInstance().shouldSendSmsToDatagramDispatcher(mPhone)) { 2296 DatagramDispatcher.getInstance().sendSms(pendingRequest); 2297 } 2298 } 2299 2300 public interface SmsInjectionCallback { onSmsInjectedResult(int result)2301 void onSmsInjectedResult(int result); 2302 } 2303 dump(FileDescriptor fd, PrintWriter pw, String[] args)2304 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2305 mGsmInboundSmsHandler.dump(fd, pw, args); 2306 if (mCdmaInboundSmsHandler != null) mCdmaInboundSmsHandler.dump(fd, pw, args); 2307 mGsmDispatcher.dump(fd, pw, args); 2308 if (mCdmaDispatcher != null) mCdmaDispatcher.dump(fd, pw, args); 2309 mImsSmsDispatcher.dump(fd, pw, args); 2310 } 2311 logd(String msg)2312 private void logd(String msg) { 2313 Rlog.d(TAG, msg); 2314 } 2315 logi(String s)2316 private void logi(String s) { 2317 Rlog.i(TAG + " [" + mPhone.getPhoneId() + "]", s); 2318 } 2319 } 2320