1 /* 2 * Copyright (C) 2014 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.mms.service; 18 19 import android.annotation.NonNull; 20 import android.app.Activity; 21 import android.app.PendingIntent; 22 import android.content.Context; 23 import android.content.Intent; 24 import android.net.Uri; 25 import android.net.wifi.WifiInfo; 26 import android.net.wifi.WifiManager; 27 import android.os.Bundle; 28 import android.service.carrier.CarrierMessagingService; 29 import android.service.carrier.CarrierMessagingServiceWrapper.CarrierMessagingCallback; 30 import android.telephony.AnomalyReporter; 31 import android.telephony.CarrierConfigManager; 32 import android.telephony.PreciseDataConnectionState; 33 import android.telephony.ServiceState; 34 import android.telephony.SmsManager; 35 import android.telephony.TelephonyCallback; 36 import android.telephony.TelephonyManager; 37 import android.telephony.data.ApnSetting; 38 import android.telephony.ims.ImsMmTelManager; 39 import android.telephony.ims.feature.MmTelFeature; 40 import android.telephony.ims.stub.ImsRegistrationImplBase; 41 import android.util.SparseArray; 42 43 import com.android.internal.annotations.GuardedBy; 44 import com.android.internal.annotations.VisibleForTesting; 45 import com.android.internal.telephony.flags.Flags; 46 import com.android.mms.service.exception.ApnException; 47 import com.android.mms.service.exception.MmsHttpException; 48 import com.android.mms.service.exception.MmsNetworkException; 49 import com.android.mms.service.metrics.MmsStats; 50 51 import java.util.UUID; 52 import java.util.concurrent.CountDownLatch; 53 import java.util.concurrent.TimeUnit; 54 55 /** 56 * Base class for MMS requests. This has the common logic of sending/downloading MMS. 57 */ 58 public abstract class MmsRequest { 59 private static final int RETRY_TIMES = 3; 60 // Signal level threshold for both wifi and cellular 61 private static final int SIGNAL_LEVEL_THRESHOLD = 2; 62 public static final String EXTRA_LAST_CONNECTION_FAILURE_CAUSE_CODE 63 = "android.telephony.extra.LAST_CONNECTION_FAILURE_CAUSE_CODE"; 64 public static final String EXTRA_HANDLED_BY_CARRIER_APP 65 = "android.telephony.extra.HANDLED_BY_CARRIER_APP"; 66 67 /** 68 * Interface for certain functionalities from MmsService 69 */ 70 public static interface RequestManager { 71 /** 72 * Enqueue an MMS request 73 * 74 * @param request the request to enqueue 75 */ addSimRequest(MmsRequest request)76 public void addSimRequest(MmsRequest request); 77 78 /* 79 * @return Whether to auto persist received MMS 80 */ getAutoPersistingPref()81 public boolean getAutoPersistingPref(); 82 83 /** 84 * Read pdu (up to maxSize bytes) from supplied content uri 85 * @param contentUri content uri from which to read 86 * @param maxSize maximum number of bytes to read 87 * @param callingUser user id of the calling app 88 * @return read pdu (else null in case of error or too big) 89 */ readPduFromContentUri(final Uri contentUri, final int maxSize, int callingUser)90 public byte[] readPduFromContentUri(final Uri contentUri, final int maxSize, 91 int callingUser); 92 93 /** 94 * Write pdu to supplied content uri 95 * @param contentUri content uri to which bytes should be written 96 * @param pdu pdu bytes to write 97 * @return true in case of success (else false) 98 */ writePduToContentUri(final Uri contentUri, final byte[] pdu)99 public boolean writePduToContentUri(final Uri contentUri, final byte[] pdu); 100 } 101 102 // The reference to the pending requests manager (i.e. the MmsService) 103 protected RequestManager mRequestManager; 104 // The SIM id 105 protected int mSubId; 106 // The creator app 107 protected String mCreator; 108 // MMS config 109 protected Bundle mMmsConfig; 110 // Context used to get TelephonyManager. 111 protected Context mContext; 112 protected long mMessageId; 113 protected int mLastConnectionFailure; 114 private MmsStats mMmsStats; 115 private int result; 116 private int httpStatusCode; 117 protected TelephonyManager mTelephonyManager; 118 @VisibleForTesting 119 public int SATELLITE_MMS_SIZE_LIMIT = 3 * 1024; // TODO - read from a carrier config setting 120 121 protected enum MmsRequestState { 122 Unknown, 123 Created, 124 PrepareForHttpRequest, 125 AcquiringNetwork, 126 LoadingApn, 127 DoingHttp, 128 Success, 129 Failure 130 }; 131 protected MmsRequestState currentState = MmsRequestState.Unknown; 132 133 class MonitorTelephonyCallback extends TelephonyCallback implements 134 TelephonyCallback.PreciseDataConnectionStateListener { 135 136 /** The lock to update mNetworkIdToApn. */ 137 private final Object mLock = new Object(); 138 /** 139 * Track the network agent Id to APN. Usually we have at most 2 networks that are capable of 140 * MMS at the same time (terrestrial and satellite) 141 */ 142 @GuardedBy("mLock") 143 private final SparseArray<ApnSetting> mNetworkIdToApn = new SparseArray<>(2); 144 @Override onPreciseDataConnectionStateChanged( @onNull PreciseDataConnectionState connectionState)145 public void onPreciseDataConnectionStateChanged( 146 @NonNull PreciseDataConnectionState connectionState) { 147 ApnSetting apnSetting = connectionState.getApnSetting(); 148 if (apnSetting != null) { 149 // Only track networks that are capable of MMS. 150 if ((apnSetting.getApnTypeBitmask() & ApnSetting.TYPE_MMS) != 0) { 151 LogUtil.d("onPreciseDataConnectionStateChanged: " + connectionState); 152 mLastConnectionFailure = connectionState.getLastCauseCode(); 153 if (Flags.mmsGetApnFromPdsc()) { 154 synchronized (mLock) { 155 mNetworkIdToApn.put(connectionState.getNetId(), apnSetting); 156 } 157 } 158 } 159 } 160 } 161 } 162 MmsRequest(RequestManager requestManager, int subId, String creator, Bundle mmsConfig, Context context, long messageId, MmsStats mmsStats, TelephonyManager telephonyManager)163 public MmsRequest(RequestManager requestManager, int subId, String creator, 164 Bundle mmsConfig, Context context, long messageId, MmsStats mmsStats, 165 TelephonyManager telephonyManager) { 166 currentState = MmsRequestState.Created; 167 mRequestManager = requestManager; 168 mSubId = subId; 169 mCreator = creator; 170 mMmsConfig = mmsConfig; 171 mContext = context; 172 mMessageId = messageId; 173 mMmsStats = mmsStats; 174 mTelephonyManager = telephonyManager; 175 } 176 getSubId()177 public int getSubId() { 178 return mSubId; 179 } 180 181 /** 182 * Execute the request 183 * 184 * @param context The context 185 * @param networkManager The network manager to use 186 */ execute(Context context, MmsNetworkManager networkManager)187 public void execute(Context context, MmsNetworkManager networkManager) { 188 final String requestId = this.getRequestId(); 189 LogUtil.i(requestId, "Executing..."); 190 result = SmsManager.MMS_ERROR_UNSPECIFIED; 191 httpStatusCode = 0; 192 byte[] response = null; 193 int retryId = 0; 194 currentState = MmsRequestState.PrepareForHttpRequest; 195 196 if (!prepareForHttpRequest()) { // Prepare request, like reading pdu data from user 197 LogUtil.e(requestId, "Failed to prepare for request"); 198 result = SmsManager.MMS_ERROR_IO_ERROR; 199 } else { // Execute 200 long retryDelaySecs = 2; 201 // Try multiple times of MMS HTTP request, depending on the error. 202 for (retryId = 0; retryId < RETRY_TIMES; retryId++) { 203 httpStatusCode = 0; // Clear for retry. 204 MonitorTelephonyCallback connectionStateCallback = new MonitorTelephonyCallback(); 205 try { 206 listenToDataConnectionState(connectionStateCallback); 207 currentState = MmsRequestState.AcquiringNetwork; 208 int networkId = networkManager.acquireNetwork(requestId); 209 currentState = MmsRequestState.LoadingApn; 210 ApnSettings apn = null; 211 ApnSetting networkApn = null; 212 if (Flags.mmsGetApnFromPdsc()) { 213 synchronized (connectionStateCallback.mLock) { 214 networkApn = connectionStateCallback.mNetworkIdToApn.get(networkId); 215 } 216 if (networkApn != null) { 217 apn = ApnSettings.getApnSettingsFromNetworkApn(networkApn); 218 } 219 } 220 if (apn == null) { 221 final String apnName = networkManager.getApnName(); 222 LogUtil.d(requestId, "APN name is " + apnName); 223 try { 224 apn = ApnSettings.load(context, apnName, mSubId, requestId); 225 } catch (ApnException e) { 226 // If no APN could be found, fall back to trying without the APN name 227 if (apnName == null) { 228 // If the APN name was already null then don't need to retry 229 throw (e); 230 } 231 LogUtil.i(requestId, "No match with APN name: " 232 + apnName + ", try with no name"); 233 apn = ApnSettings.load(context, null, mSubId, requestId); 234 } 235 } 236 237 if (Flags.mmsGetApnFromPdsc() && networkApn == null && apn != null) { 238 reportAnomaly("Can't find MMS APN in mms network", 239 UUID.fromString("2bdda74d-3cf4-44ad-a87f-24c961212a6f")); 240 } 241 242 LogUtil.d(requestId, "Using APN " + apn); 243 if (networkManager.isSatelliteTransport() 244 && !canTransferPayloadOnCurrentNetwork()) { 245 LogUtil.e(requestId, "PDU too large for satellite"); 246 result = SmsManager.MMS_ERROR_TOO_LARGE_FOR_TRANSPORT; 247 break; 248 } 249 currentState = MmsRequestState.DoingHttp; 250 response = doHttp(context, networkManager, apn); 251 result = Activity.RESULT_OK; 252 // Success 253 break; 254 } catch (ApnException e) { 255 LogUtil.e(requestId, "APN failure", e); 256 result = SmsManager.MMS_ERROR_INVALID_APN; 257 break; 258 } catch (MmsNetworkException e) { 259 LogUtil.e(requestId, "MMS network acquiring failure", e); 260 result = SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS; 261 break; 262 } catch (MmsHttpException e) { 263 LogUtil.e(requestId, "HTTP or network I/O failure", e); 264 result = SmsManager.MMS_ERROR_HTTP_FAILURE; 265 httpStatusCode = e.getStatusCode(); 266 // Retry 267 } catch (Exception e) { 268 LogUtil.e(requestId, "Unexpected failure", e); 269 result = SmsManager.MMS_ERROR_UNSPECIFIED; 270 break; 271 } finally { 272 // Release the MMS network immediately except successful DownloadRequest. 273 networkManager.releaseNetwork(requestId, 274 this instanceof DownloadRequest 275 && result == Activity.RESULT_OK); 276 stopListeningToDataConnectionState(connectionStateCallback); 277 } 278 279 if (result != Activity.RESULT_CANCELED) { 280 try { // Cool down retry if the previous attempt wasn't voluntarily cancelled. 281 new CountDownLatch(1).await(retryDelaySecs, TimeUnit.SECONDS); 282 } catch (InterruptedException e) { } 283 // Double the cool down time if the next try fails again. 284 retryDelaySecs <<= 1; 285 } 286 } 287 } 288 processResult(context, result, response, httpStatusCode, /* handledByCarrierApp= */ false, 289 retryId); 290 } 291 listenToDataConnectionState(MonitorTelephonyCallback connectionStateCallback)292 private void listenToDataConnectionState(MonitorTelephonyCallback connectionStateCallback) { 293 final TelephonyManager telephonyManager = mContext.getSystemService( 294 TelephonyManager.class).createForSubscriptionId(mSubId); 295 telephonyManager.registerTelephonyCallback(r -> r.run(), connectionStateCallback); 296 } 297 stopListeningToDataConnectionState( MonitorTelephonyCallback connectionStateCallback)298 private void stopListeningToDataConnectionState( 299 MonitorTelephonyCallback connectionStateCallback) { 300 final TelephonyManager telephonyManager = mContext.getSystemService( 301 TelephonyManager.class).createForSubscriptionId(mSubId); 302 telephonyManager.unregisterTelephonyCallback(connectionStateCallback); 303 } 304 305 /** 306 * Process the result of the completed request, including updating the message status 307 * in database and sending back the result via pending intents. 308 * @param context The context 309 * @param result The result code of execution 310 * @param response The response body 311 * @param httpStatusCode The optional http status code in case of http failure 312 * @param handledByCarrierApp True if the sending/downloading was handled by a carrier app 313 * rather than MmsService. 314 */ processResult(Context context, int result, byte[] response, int httpStatusCode, boolean handledByCarrierApp)315 public void processResult(Context context, int result, byte[] response, int httpStatusCode, 316 boolean handledByCarrierApp) { 317 processResult(context, result, response, httpStatusCode, handledByCarrierApp, 0); 318 } 319 processResult(Context context, int result, byte[] response, int httpStatusCode, boolean handledByCarrierApp, int retryId)320 private void processResult(Context context, int result, byte[] response, int httpStatusCode, 321 boolean handledByCarrierApp, int retryId) { 322 final Uri messageUri = persistIfRequired(context, result, response); 323 324 final String requestId = this.getRequestId(); 325 currentState = result == Activity.RESULT_OK ? MmsRequestState.Success 326 : MmsRequestState.Failure; 327 // As noted in the @param comment above, the httpStatusCode is only set when there's 328 // an http failure. On success, such as an http code of 200, the value here will be 0. 329 // "httpStatusCode: xxx" is now reported for an http failure only. 330 LogUtil.i(requestId, "processResult: " 331 + (result == Activity.RESULT_OK ? "success" : "failure(" + result + ")") 332 + (httpStatusCode != 0 ? ", httpStatusCode: " + httpStatusCode : "") 333 + " handledByCarrierApp: " + handledByCarrierApp 334 + " mLastConnectionFailure: " + mLastConnectionFailure); 335 336 // Return MMS HTTP request result via PendingIntent 337 final PendingIntent pendingIntent = getPendingIntent(); 338 if (pendingIntent != null) { 339 boolean succeeded = true; 340 // Extra information to send back with the pending intent 341 Intent fillIn = new Intent(); 342 if (response != null) { 343 succeeded = transferResponse(fillIn, response); 344 } 345 if (messageUri != null) { 346 fillIn.putExtra("uri", messageUri.toString()); 347 } 348 if (result == SmsManager.MMS_ERROR_HTTP_FAILURE && httpStatusCode != 0) { 349 fillIn.putExtra(SmsManager.EXTRA_MMS_HTTP_STATUS, httpStatusCode); 350 } 351 fillIn.putExtra(EXTRA_LAST_CONNECTION_FAILURE_CAUSE_CODE, 352 mLastConnectionFailure); 353 fillIn.putExtra(EXTRA_HANDLED_BY_CARRIER_APP, handledByCarrierApp); 354 try { 355 if (!succeeded) { 356 result = SmsManager.MMS_ERROR_IO_ERROR; 357 } 358 reportPossibleAnomaly(result, httpStatusCode); 359 pendingIntent.send(context, result, fillIn); 360 mMmsStats.addAtomToStorage(result, retryId, handledByCarrierApp, mMessageId); 361 } catch (PendingIntent.CanceledException e) { 362 LogUtil.e(requestId, "Sending pending intent canceled", e); 363 } 364 } 365 366 revokeUriPermission(context); 367 } 368 reportPossibleAnomaly(int result, int httpStatusCode)369 private void reportPossibleAnomaly(int result, int httpStatusCode) { 370 switch (result) { 371 case SmsManager.MMS_ERROR_HTTP_FAILURE: 372 if (isPoorSignal()) { 373 LogUtil.i(this.toString(), "Poor Signal"); 374 break; 375 } 376 case SmsManager.MMS_ERROR_INVALID_APN: 377 case SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS: 378 case SmsManager.MMS_ERROR_UNSPECIFIED: 379 case SmsManager.MMS_ERROR_IO_ERROR: 380 String message = "MMS failed"; 381 LogUtil.i(this.toString(), 382 message + " with error: " + result + " httpStatus:" + httpStatusCode); 383 reportAnomaly(message, generateUUID(result, httpStatusCode)); 384 break; 385 default: 386 break; 387 } 388 } 389 reportAnomaly(@onNull String anomalyMsg, @NonNull UUID uuid)390 private void reportAnomaly(@NonNull String anomalyMsg, @NonNull UUID uuid) { 391 TelephonyManager telephonyManager = 392 mContext.getSystemService(TelephonyManager.class) 393 .createForSubscriptionId(mSubId); 394 if (telephonyManager != null) { 395 AnomalyReporter.reportAnomaly( 396 uuid, 397 anomalyMsg, 398 telephonyManager.getSimCarrierId()); 399 } 400 } 401 generateUUID(int result, int httpStatusCode)402 private UUID generateUUID(int result, int httpStatusCode) { 403 long lresult = result; 404 long lhttpStatusCode = httpStatusCode; 405 return new UUID(MmsConstants.MMS_ANOMALY_UUID.getMostSignificantBits(), 406 MmsConstants.MMS_ANOMALY_UUID.getLeastSignificantBits() 407 + ((lhttpStatusCode << 32) + lresult)); 408 } 409 isPoorSignal()410 private boolean isPoorSignal() { 411 // Check Wifi signal strength when IMS registers via Wifi 412 if (isImsOnWifi()) { 413 int rssi = 0; 414 WifiManager wifiManager = mContext.getSystemService(WifiManager.class); 415 final WifiInfo wifiInfo = wifiManager.getConnectionInfo(); 416 if (wifiInfo != null) { 417 rssi = wifiInfo.getRssi(); 418 } else { 419 return false; 420 } 421 final int wifiLevel = wifiManager.calculateSignalLevel(rssi); 422 LogUtil.d(this.toString(), "Wifi signal rssi: " + rssi + " level:" + wifiLevel); 423 if (wifiLevel <= SIGNAL_LEVEL_THRESHOLD) { 424 return true; 425 } 426 return false; 427 } else { 428 // Check cellular signal strength 429 final TelephonyManager telephonyManager = mContext.getSystemService( 430 TelephonyManager.class).createForSubscriptionId(mSubId); 431 final int cellLevel = telephonyManager.getSignalStrength().getLevel(); 432 LogUtil.d(this.toString(), "Cellular signal level:" + cellLevel); 433 if (cellLevel <= SIGNAL_LEVEL_THRESHOLD) { 434 return true; 435 } 436 return false; 437 } 438 } 439 isImsOnWifi()440 private boolean isImsOnWifi() { 441 ImsMmTelManager imsManager; 442 try { 443 imsManager = ImsMmTelManager.createForSubscriptionId(mSubId); 444 } catch (IllegalArgumentException e) { 445 LogUtil.e(this.toString(), "invalid subid:" + mSubId); 446 return false; 447 } 448 if (imsManager != null) { 449 return imsManager.isAvailable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, 450 ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN); 451 } else { 452 return false; 453 } 454 } 455 456 /** 457 * Returns true if sending / downloading using the carrier app has failed and completes the 458 * action using platform API's, otherwise false. 459 */ maybeFallbackToRegularDelivery(int carrierMessagingAppResult)460 protected boolean maybeFallbackToRegularDelivery(int carrierMessagingAppResult) { 461 if (carrierMessagingAppResult 462 == CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK 463 || carrierMessagingAppResult 464 == CarrierMessagingService.DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK) { 465 LogUtil.d(this.toString(), "Sending/downloading MMS by IP failed. " 466 + MmsService.formatCrossStackMessageId(mMessageId)); 467 mRequestManager.addSimRequest(MmsRequest.this); 468 return true; 469 } else { 470 return false; 471 } 472 } 473 474 /** 475 * Converts from {@code carrierMessagingAppResult} to a platform result code. 476 */ toSmsManagerResult(int carrierMessagingAppResult)477 protected static int toSmsManagerResult(int carrierMessagingAppResult) { 478 switch (carrierMessagingAppResult) { 479 case CarrierMessagingService.SEND_STATUS_OK: 480 return Activity.RESULT_OK; 481 case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK: 482 return SmsManager.MMS_ERROR_RETRY; 483 default: 484 return SmsManager.MMS_ERROR_UNSPECIFIED; 485 } 486 } 487 488 /** 489 * Converts from {@code carrierMessagingAppResult} to a platform result code for outbound MMS 490 * requests. 491 */ toSmsManagerResultForOutboundMms(int carrierMessagingAppResult)492 protected static int toSmsManagerResultForOutboundMms(int carrierMessagingAppResult) { 493 if (Flags.temporaryFailuresInCarrierMessagingService()) { 494 switch (carrierMessagingAppResult) { 495 case CarrierMessagingService.SEND_STATUS_OK: 496 // TODO: b/378931437 - Update to an SmsManager result code when one is 497 // available. 498 return Activity.RESULT_OK; 499 case CarrierMessagingService.SEND_STATUS_RETRY_ON_CARRIER_NETWORK, // fall through 500 CarrierMessagingService.SEND_STATUS_MMS_ERROR_RETRY: 501 return SmsManager.MMS_ERROR_RETRY; 502 case CarrierMessagingService.SEND_STATUS_ERROR: // fall through 503 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_UNSPECIFIED: 504 return SmsManager.MMS_ERROR_UNSPECIFIED; 505 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_INVALID_APN: 506 return SmsManager.MMS_ERROR_INVALID_APN; 507 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS: 508 return SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS; 509 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_HTTP_FAILURE: 510 return SmsManager.MMS_ERROR_HTTP_FAILURE; 511 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_IO_ERROR: 512 return SmsManager.MMS_ERROR_IO_ERROR; 513 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_CONFIGURATION_ERROR: 514 return SmsManager.MMS_ERROR_CONFIGURATION_ERROR; 515 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_NO_DATA_NETWORK: 516 return SmsManager.MMS_ERROR_NO_DATA_NETWORK; 517 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID: 518 return SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID; 519 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION: 520 return SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION; 521 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_DATA_DISABLED: 522 return SmsManager.MMS_ERROR_DATA_DISABLED; 523 case CarrierMessagingService.SEND_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER: 524 return SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER; 525 default: 526 return SmsManager.MMS_ERROR_UNSPECIFIED; 527 } 528 } else { 529 return toSmsManagerResult(carrierMessagingAppResult); 530 } 531 } 532 533 /** 534 * Converts from {@code carrierMessagingAppResult} to a platform result code for download MMS 535 * requests. 536 */ toSmsManagerResultForInboundMms(int carrierMessagingAppResult)537 protected static int toSmsManagerResultForInboundMms(int carrierMessagingAppResult) { 538 if (Flags.temporaryFailuresInCarrierMessagingService()) { 539 switch (carrierMessagingAppResult) { 540 case CarrierMessagingService.DOWNLOAD_STATUS_OK: 541 return Activity.RESULT_OK; 542 case CarrierMessagingService.DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK: 543 return SmsManager.MMS_ERROR_RETRY; 544 case CarrierMessagingService.DOWNLOAD_STATUS_ERROR: // fall through 545 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_UNSPECIFIED: 546 return SmsManager.MMS_ERROR_UNSPECIFIED; 547 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_INVALID_APN: 548 return SmsManager.MMS_ERROR_INVALID_APN; 549 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_UNABLE_CONNECT_MMS: 550 return SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS; 551 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_HTTP_FAILURE: 552 return SmsManager.MMS_ERROR_HTTP_FAILURE; 553 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_IO_ERROR: 554 return SmsManager.MMS_ERROR_IO_ERROR; 555 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_RETRY: 556 return SmsManager.MMS_ERROR_RETRY; 557 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_CONFIGURATION_ERROR: 558 return SmsManager.MMS_ERROR_CONFIGURATION_ERROR; 559 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_NO_DATA_NETWORK: 560 return SmsManager.MMS_ERROR_NO_DATA_NETWORK; 561 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_INVALID_SUBSCRIPTION_ID: 562 return SmsManager.MMS_ERROR_INVALID_SUBSCRIPTION_ID; 563 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_INACTIVE_SUBSCRIPTION: 564 return SmsManager.MMS_ERROR_INACTIVE_SUBSCRIPTION; 565 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_DATA_DISABLED: 566 return SmsManager.MMS_ERROR_DATA_DISABLED; 567 case CarrierMessagingService.DOWNLOAD_STATUS_MMS_ERROR_MMS_DISABLED_BY_CARRIER: 568 return SmsManager.MMS_ERROR_MMS_DISABLED_BY_CARRIER; 569 default: 570 return SmsManager.MMS_ERROR_UNSPECIFIED; 571 } 572 } else { 573 return toSmsManagerResult(carrierMessagingAppResult); 574 } 575 } 576 577 @Override toString()578 public String toString() { 579 return getClass().getSimpleName() + '@' + Integer.toHexString(hashCode()) 580 + " " + MmsService.formatCrossStackMessageId(mMessageId) 581 + " subId: " + mSubId 582 + " currentState: \"" + currentState.name() + "\"" 583 + " result: " + result; 584 } 585 getRequestId()586 protected String getRequestId() { 587 return this.toString(); 588 } 589 590 /** 591 * Making the HTTP request to MMSC 592 * 593 * @param context The context 594 * @param netMgr The current {@link MmsNetworkManager} 595 * @param apn The APN setting 596 * @return The HTTP response data 597 * @throws MmsHttpException If any network error happens 598 */ doHttp(Context context, MmsNetworkManager netMgr, ApnSettings apn)599 protected abstract byte[] doHttp(Context context, MmsNetworkManager netMgr, ApnSettings apn) 600 throws MmsHttpException; 601 602 /** 603 * @return The PendingIntent associate with the MMS sending invocation 604 */ getPendingIntent()605 protected abstract PendingIntent getPendingIntent(); 606 607 /** 608 * @return The queue should be used by this request, 0 is sending and 1 is downloading 609 */ getQueueType()610 protected abstract int getQueueType(); 611 612 /** 613 * Persist message into telephony if required (i.e. when auto-persisting is on or 614 * the calling app is non-default sms app for sending) 615 * 616 * @param context The context 617 * @param result The result code of execution 618 * @param response The response body 619 * @return The persisted URI of the message or null if we don't persist or fail 620 */ persistIfRequired(Context context, int result, byte[] response)621 protected abstract Uri persistIfRequired(Context context, int result, byte[] response); 622 623 /** 624 * Prepare to make the HTTP request - will download message for sending 625 * @return true if preparation succeeds (and request can proceed) else false 626 */ prepareForHttpRequest()627 protected abstract boolean prepareForHttpRequest(); 628 629 /** 630 * Transfer the received response to the caller 631 * 632 * @param fillIn the intent that will be returned to the caller 633 * @param response the pdu to transfer 634 * @return true if response transfer succeeds else false 635 */ transferResponse(Intent fillIn, byte[] response)636 protected abstract boolean transferResponse(Intent fillIn, byte[] response); 637 638 /** 639 * Revoke the content URI permission granted by the MMS app to the phone package. 640 * 641 * @param context The context 642 */ revokeUriPermission(Context context)643 protected abstract void revokeUriPermission(Context context); 644 645 /** 646 * Base class for handling carrier app send / download result. 647 */ 648 protected abstract class CarrierMmsActionCallback implements CarrierMessagingCallback { 649 @Override onSendSmsComplete(int result, int messageRef)650 public void onSendSmsComplete(int result, int messageRef) { 651 LogUtil.e("Unexpected onSendSmsComplete call for " 652 + MmsService.formatCrossStackMessageId(mMessageId) 653 + " with result: " + result); 654 } 655 656 @Override onSendMultipartSmsComplete(int result, int[] messageRefs)657 public void onSendMultipartSmsComplete(int result, int[] messageRefs) { 658 LogUtil.e("Unexpected onSendMultipartSmsComplete call for " 659 + MmsService.formatCrossStackMessageId(mMessageId) 660 + " with result: " + result); 661 } 662 663 @Override onReceiveSmsComplete(int result)664 public void onReceiveSmsComplete(int result) { 665 LogUtil.e("Unexpected onFilterComplete call for " 666 + MmsService.formatCrossStackMessageId(mMessageId) 667 + " with result: " + result); 668 } 669 } 670 671 /** 672 * Get the size of the pdu to send or download. 673 */ getPayloadSize()674 protected abstract long getPayloadSize(); 675 676 /** 677 * Determine whether the send or to-be-downloaded pdu is within size limits for the 678 * current connection. 679 */ 680 @VisibleForTesting canTransferPayloadOnCurrentNetwork()681 public boolean canTransferPayloadOnCurrentNetwork() { 682 ServiceState serviceState = mTelephonyManager.getServiceState(); 683 if (serviceState == null) { 684 // serviceState can be null when the subscription is inactive 685 // or when there was an error communicating with the phone process. 686 LogUtil.d("canTransferPayloadOnCurrentNetwork serviceState null"); 687 return true; // assume we're not connected to a satellite 688 } 689 long payloadSize = getPayloadSize(); 690 int maxPduSize = mMmsConfig 691 .getInt(CarrierConfigManager.KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT); 692 LogUtil.d("canTransferPayloadOnCurrentNetwork payloadSize: " + payloadSize 693 + " maxPduSize: " + maxPduSize); 694 return payloadSize > 0 && (maxPduSize == -1 || payloadSize <= maxPduSize); 695 } 696 } 697