[automerger skipped] Merge Android 24Q2 Release (ab/11526283) to aosp-main-future am: dd1eeb280f -s ours
am skip reason: Merged-In Iba5169f65fbba4b90e6767caebf1d0c96f299a63 with SHA-1 e189fb70f7 is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Mms/+/27273847
Change-Id: Ifca56a8216ade16d8ab63329ac2fc04741890530
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/OWNERS b/OWNERS
index 01985bc..1befe3e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,3 +6,4 @@
jianxiangp@google.com
stephshi@google.com
bellavicevh@google.com
+sasindran@google.com
diff --git a/proto/src/persist_mms_atoms.proto b/proto/src/persist_mms_atoms.proto
index bde1cb9..8be233b 100644
--- a/proto/src/persist_mms_atoms.proto
+++ b/proto/src/persist_mms_atoms.proto
@@ -51,6 +51,7 @@
optional int32 retry_id = 10;
optional bool handled_by_carrier_app = 11;
optional bool is_managed_profile = 12;
+ optional bool is_ntn = 13;
}
message OutgoingMms {
@@ -67,4 +68,5 @@
optional int32 retry_id = 11;
optional bool handled_by_carrier_app = 12;
optional bool is_managed_profile = 13;
+ optional bool is_ntn = 14;
}
diff --git a/src/com/android/mms/service/ApnSettings.java b/src/com/android/mms/service/ApnSettings.java
index 42d6427..8ac3482 100644
--- a/src/com/android/mms/service/ApnSettings.java
+++ b/src/com/android/mms/service/ApnSettings.java
@@ -16,6 +16,8 @@
package com.android.mms.service;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -158,6 +160,31 @@
return null;
}
+ /**
+ * Convert the APN received from network to an APN used by MMS to make http request. Essentially
+ * the same as {@link #getApnSettingsFromCursor}.
+ * @param apn network APN for setup network.
+ * @return APN to make http request.
+ */
+ @Nullable
+ public static ApnSettings getApnSettingsFromNetworkApn(@NonNull ApnSetting apn) {
+ // Default proxy port to 80
+ int proxyPort = 80;
+ // URL
+ if (apn.getMmsc() == null) return null;
+ String mmscUrl = apn.getMmsc().toString().trim();
+ if (TextUtils.isEmpty(mmscUrl)) return null;
+ // proxy address
+ String proxy = trimWithNullCheck(apn.getMmsProxyAddressAsString());
+ if (!TextUtils.isEmpty(proxy)) {
+ proxy = Inet4AddressUtils.trimAddressZeros(proxy);
+ // proxy port
+ if (apn.getMmsProxyPort() != -1 /*UNSPECIFIED_INT*/) proxyPort = apn.getMmsProxyPort();
+ }
+
+ return new ApnSettings(mmscUrl, proxy, proxyPort, apn.toString());
+ }
+
private static String getDebugText(Cursor cursor) {
final StringBuilder sb = new StringBuilder();
sb.append("APN [");
@@ -217,7 +244,8 @@
return false;
}
+ @Override
public String toString() {
- return mDebugText;
+ return mServiceCenter + " " + mProxyAddress + " " + mProxyPort + " " + mDebugText;
}
}
diff --git a/src/com/android/mms/service/LogUtil.java b/src/com/android/mms/service/LogUtil.java
index 349af32..49ab3f1 100644
--- a/src/com/android/mms/service/LogUtil.java
+++ b/src/com/android/mms/service/LogUtil.java
@@ -16,71 +16,72 @@
package com.android.mms.service;
-import android.util.Log;
+
+import android.telephony.Rlog;
/**
* Logging utility
*/
public class LogUtil {
- private static final String TAG = "MmsService";
+ public static final String TAG = "MmsService";
public static void i(final String requestId, final String message) {
- Log.i(TAG, "[" + requestId + "] " + message);
+ Rlog.i(TAG, "[" + requestId + "] " + message);
}
public static void i(final String message) {
- Log.i(TAG, message);
+ Rlog.i(TAG, message);
}
public static void d(final String requestId, final String message) {
- Log.d(TAG, "[" + requestId + "] " + message);
+ Rlog.d(TAG, "[" + requestId + "] " + message);
}
public static void d(final String message) {
- Log.d(TAG, message);
+ Rlog.d(TAG, message);
}
public static void v(final String requestId, final String message) {
- Log.v(TAG, "[" + requestId + "] " + message);
+ Rlog.v(TAG, "[" + requestId + "] " + message);
}
public static void v(final String message) {
- Log.v(TAG, message);
+ Rlog.v(TAG, message);
}
public static void e(final String requestId, final String message, final Throwable t) {
- Log.e(TAG, "[" + requestId + "] " + message, t);
+ Rlog.e(TAG, "[" + requestId + "] " + message, t);
}
public static void e(final String message, final Throwable t) {
- Log.e(TAG, message, t);
+ Rlog.e(TAG, message, t);
}
public static void e(final String requestId, final String message) {
- Log.e(TAG, "[" + requestId + "] " + message);
+ Rlog.e(TAG, "[" + requestId + "] " + message);
}
public static void e(final String message) {
- Log.e(TAG, message);
+ Rlog.e(TAG, message);
}
public static void w(final String requestId, final String message, final Throwable t) {
- Log.w(TAG, "[" + requestId + "] " + message, t);
+ Rlog.w(TAG, "[" + requestId + "] " + message, t);
}
public static void w(final String message, final Throwable t) {
- Log.w(TAG, message, t);
+ Rlog.w(TAG, message, t);
}
public static void w(final String requestId, final String message) {
- Log.w(TAG, "[" + requestId + "] " + message);
+ Rlog.w(TAG, "[" + requestId + "] " + message);
}
public static void w(final String message) {
- Log.w(TAG, message);
+ Rlog.w(TAG, message);
}
public static boolean isLoggable(final int logLevel) {
- return Log.isLoggable(TAG, logLevel);
+ return Rlog.isLoggable(TAG, logLevel);
}
}
diff --git a/src/com/android/mms/service/MmsHttpClient.java b/src/com/android/mms/service/MmsHttpClient.java
index 7978a71..367253e 100644
--- a/src/com/android/mms/service/MmsHttpClient.java
+++ b/src/com/android/mms/service/MmsHttpClient.java
@@ -31,7 +31,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.mms.service.exception.MmsHttpException;
-import com.android.mms.service.exception.VoluntaryDisconnectMmsHttpException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -51,9 +50,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -90,11 +86,6 @@
private final Network mNetwork;
private final ConnectivityManager mConnectivityManager;
- /** Store all currently open connections, for potential voluntarily early disconnect. */
- private final Set<HttpURLConnection> mAllUrlConnections = ConcurrentHashMap.newKeySet();
- /** Flag indicating whether a disconnection is voluntary. */
- private final AtomicBoolean mVoluntarilyDisconnectingConnections = new AtomicBoolean(false);
-
/**
* Constructor
*
@@ -144,7 +135,6 @@
maybeWaitForIpv4(requestId, url);
// Now get the connection
connection = (HttpURLConnection) mNetwork.openConnection(url, proxy);
- if (connection != null) mAllUrlConnections.add(connection);
connection.setDoInput(true);
connection.setConnectTimeout(
mmsConfig.getInt(SmsManager.MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
@@ -247,46 +237,15 @@
LogUtil.e(requestId, "HTTP: invalid URL protocol " + redactedUrl, e);
throw new MmsHttpException(0/*statusCode*/, "Invalid URL protocol " + redactedUrl, e);
} catch (IOException e) {
- if (mVoluntarilyDisconnectingConnections.get()) {
- // If in the process of voluntarily disconnecting all connections, the exception
- // is casted as VoluntaryDisconnectMmsHttpException to indicate this attempt is
- // cancelled rather than failure.
- LogUtil.d(requestId,
- "HTTP voluntarily disconnected due to WLAN network available");
- throw new VoluntaryDisconnectMmsHttpException(0/*statusCode*/,
- "Expected disconnection due to WLAN network available");
- } else {
- LogUtil.e(requestId, "HTTP: IO failure ", e);
- throw new MmsHttpException(0/*statusCode*/, e);
- }
+ LogUtil.e(requestId, "HTTP: IO failure", e);
+ throw new MmsHttpException(0/*statusCode*/, e);
} finally {
if (connection != null) {
connection.disconnect();
- mAllUrlConnections.remove(connection);
- // If all connections are done disconnected, flag voluntary disconnection done if
- // applicable.
- if (mAllUrlConnections.isEmpty() && mVoluntarilyDisconnectingConnections
- .compareAndSet(/*expectedValue*/true, /*newValue*/false)) {
- LogUtil.d("All voluntarily disconnected connections are removed.");
- }
}
}
}
- /**
- * Voluntarily disconnect all Http URL connections. This will trigger
- * {@link VoluntaryDisconnectMmsHttpException} to be thrown, to indicate voluntary disconnection
- */
- public void disconnectAllUrlConnections() {
- LogUtil.d("Disconnecting all Url connections, size = " + mAllUrlConnections.size());
- if (mAllUrlConnections.isEmpty()) return;
- mVoluntarilyDisconnectingConnections.set(true);
- for (HttpURLConnection connection : mAllUrlConnections) {
- // TODO: An improvement is to check the writing/reading progress before disconnect.
- connection.disconnect();
- }
- }
-
private void maybeWaitForIpv4(final String requestId, final URL url) {
// If it's a literal IPv4 address and we're on an IPv6-only network,
// wait until IPv4 is available.
diff --git a/src/com/android/mms/service/MmsNetworkManager.java b/src/com/android/mms/service/MmsNetworkManager.java
index 73c749a..bcafbc7 100644
--- a/src/com/android/mms/service/MmsNetworkManager.java
+++ b/src/com/android/mms/service/MmsNetworkManager.java
@@ -33,7 +33,6 @@
import android.os.PersistableBundle;
import android.provider.DeviceConfig;
import android.telephony.CarrierConfigManager;
-import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -46,10 +45,8 @@
* Manages the MMS network connectivity
*/
public class MmsNetworkManager {
- /** Device Config Keys */
private static final String MMS_SERVICE_NETWORK_REQUEST_TIMEOUT_MILLIS =
"mms_service_network_request_timeout_millis";
- private static final String MMS_ENHANCEMENT_ENABLED = "mms_enhancement_enabled";
// Default timeout used to call ConnectivityManager.requestNetwork if the
// MMS_SERVICE_NETWORK_REQUEST_TIMEOUT_MILLIS flag is not set.
@@ -62,8 +59,6 @@
/* Event created when receiving ACTION_CARRIER_CONFIG_CHANGED */
private static final int EVENT_CARRIER_CONFIG_CHANGED = 1;
- /** Event when a WLAN network newly available despite of the existing available one. */
- private static final int EVENT_IWLAN_NETWORK_NEWLY_AVAILABLE = 2;
private final Context mContext;
@@ -71,8 +66,6 @@
// We need this when we unbind from it. This is also used to indicate if the
// MMS network is available.
private Network mNetwork;
- /** Whether an Iwlan MMS network is available to use. */
- private boolean mIsLastAvailableNetworkIwlan;
// The current count of MMS requests that require the MMS network
// If mMmsRequestCount is 0, we should release the MMS network.
private int mMmsRequestCount;
@@ -104,6 +97,10 @@
private final Dependencies mDeps;
private int mNetworkReleaseTimeoutMillis;
+
+ // satellite transport status of associated mms active network
+ private boolean mIsSatelliteTransport;
+
private EventHandler mEventHandler;
private final class EventHandler extends Handler {
@@ -123,9 +120,6 @@
// Reload mNetworkReleaseTimeoutMillis from CarrierConfigManager.
handleCarrierConfigChanged();
break;
- case EVENT_IWLAN_NETWORK_NEWLY_AVAILABLE:
- onIwlanNetworkNewlyAvailable();
- break;
default:
LogUtil.e("MmsNetworkManager: ignoring message of unexpected type " + msg.what);
}
@@ -197,17 +191,6 @@
}
};
- /**
- * Called when a WLAN network newly available. This new WLAN network should replace the
- * existing network and retry sending traffic on this network.
- */
- private void onIwlanNetworkNewlyAvailable() {
- if (mMmsHttpClient == null || mNetwork == null) return;
- LogUtil.d("onIwlanNetworkNewlyAvailable net " + mNetwork.getNetId());
- mMmsHttpClient.disconnectAllUrlConnections();
- populateHttpClientWithCurrentNetwork();
- }
-
private void handleCarrierConfigChanged() {
final CarrierConfigManager configManager =
(CarrierConfigManager)
@@ -251,13 +234,8 @@
// onAvailable will always immediately be followed by a onCapabilitiesChanged. Check
// network status here is enough.
super.onCapabilitiesChanged(network, nc);
- final NetworkInfo networkInfo = getConnectivityManager().getNetworkInfo(network);
- // wlan network is preferred over wwan network, because its existence meaning it's
- // recommended by QualifiedNetworksService.
- final boolean isWlan = networkInfo != null
- && networkInfo.getSubtype() == TelephonyManager.NETWORK_TYPE_IWLAN;
LogUtil.w("NetworkCallbackListener.onCapabilitiesChanged: network="
- + network + ", isWlan=" + isWlan + ", nc=" + nc);
+ + network + ", nc=" + nc);
synchronized (MmsNetworkManager.this) {
final boolean isAvailable =
nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
@@ -270,18 +248,12 @@
return;
}
- // Use new available network
- if (isAvailable) {
- if (mNetwork == null) {
- mNetwork = network;
- MmsNetworkManager.this.notifyAll();
- } else if (mDeps.isMmsEnhancementEnabled()
- // Iwlan network newly available, try send MMS over the new network.
- && !mIsLastAvailableNetworkIwlan && isWlan) {
- mNetwork = network;
- mEventHandler.sendEmptyMessage(EVENT_IWLAN_NETWORK_NEWLY_AVAILABLE);
- }
- mIsLastAvailableNetworkIwlan = isWlan;
+ // New available network
+ if (mNetwork == null && isAvailable) {
+ mIsSatelliteTransport = Flags.satelliteInternet()
+ && nc.hasTransport(NetworkCapabilities.TRANSPORT_SATELLITE);
+ mNetwork = network;
+ MmsNetworkManager.this.notifyAll();
}
}
}
@@ -305,11 +277,6 @@
DEFAULT_MMS_SERVICE_NETWORK_REQUEST_TIMEOUT_MILLIS);
}
- public boolean isMmsEnhancementEnabled() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_TELEPHONY, MMS_ENHANCEMENT_ENABLED, true);
- }
-
public int getAdditionalNetworkAcquireTimeoutMillis() {
return ADDITIONAL_NETWORK_ACQUIRE_TIMEOUT_MILLIS;
}
@@ -327,31 +294,24 @@
mSubId = subId;
mReleaseHandler = new Handler(Looper.getMainLooper());
- TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
- ServiceState serviceState = null;
- if (telephonyManager != null) {
- serviceState = telephonyManager.getServiceState();
- }
+ NetworkRequest.Builder builder = new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
+ .setSubscriptionId(mSubId).build());
- // During Satellite network , network available is Satellite transport with restricted
- // capability only . So build mms message network request with related capability
- if (Flags.carrierEnabledSatelliteFlag()
- && serviceState != null && serviceState.isUsingNonTerrestrialNetwork()) {
- mNetworkRequest = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(mSubId).build())
- .build();
- } else {
- mNetworkRequest = new NetworkRequest.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_MMS)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder()
- .setSubscriptionId(mSubId).build())
- .build();
+ // With Satellite internet support, add satellite transport with restricted capability to
+ // support mms over satellite network
+ if (Flags.satelliteInternet()) {
+ builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ try {
+ // TODO: b/331622062 remove the try/catch
+ builder.addTransportType(NetworkCapabilities.TRANSPORT_SATELLITE);
+ } catch (IllegalArgumentException exception) {
+ LogUtil.e("TRANSPORT_SATELLITE is not supported.");
+ }
}
+ mNetworkRequest = builder.build();
mNetworkReleaseTask = new Runnable() {
@Override
@@ -381,8 +341,9 @@
*
* @param requestId request ID for logging
* @throws com.android.mms.service.exception.MmsNetworkException if we fail to acquire it
+ * @return The net Id of the acquired network.
*/
- public void acquireNetwork(final String requestId) throws MmsNetworkException {
+ public int acquireNetwork(final String requestId) throws MmsNetworkException {
int networkRequestTimeoutMillis = mDeps.getNetworkRequestTimeoutMillis();
synchronized (this) {
@@ -392,7 +353,7 @@
if (mNetwork != null) {
// Already available
LogUtil.d(requestId, "MmsNetworkManager: already available");
- return;
+ return mNetwork.getNetId();
}
if (!mSimCardStateChangedReceiverRegistered) {
@@ -430,7 +391,7 @@
if (mNetwork != null) {
// Success
- return;
+ return mNetwork.getNetId();
}
if (mNetworkCallback != null) { // Timed out
@@ -454,22 +415,17 @@
* Release the MMS network when nobody is holding on to it.
*
* @param requestId request ID for logging.
- * @param canRelease whether the request can be released. An early release of a request
- * can result in unexpected network torn down, as that network is used
- * for immediate retry.
* @param shouldDelayRelease whether the release should be delayed for a carrier-configured
* timeout (default 5 seconds), the regular use case is to delay this
* for DownloadRequests to use the network for sending an
* acknowledgement on the same network.
*/
- public void releaseNetwork(final String requestId, final boolean canRelease,
- final boolean shouldDelayRelease) {
+ public void releaseNetwork(final String requestId, final boolean shouldDelayRelease) {
synchronized (this) {
if (mMmsRequestCount > 0) {
mMmsRequestCount -= 1;
- LogUtil.d(requestId, "MmsNetworkManager: release, count=" + mMmsRequestCount
- + " canRelease=" + canRelease);
- if (mMmsRequestCount < 1 && canRelease) {
+ LogUtil.d(requestId, "MmsNetworkManager: release, count=" + mMmsRequestCount);
+ if (mMmsRequestCount < 1) {
if (shouldDelayRelease) {
// remove previously posted task and post a delayed task on the release
// handler to release the network
@@ -544,19 +500,15 @@
public MmsHttpClient getOrCreateHttpClient() {
synchronized (this) {
if (mMmsHttpClient == null) {
- populateHttpClientWithCurrentNetwork();
+ if (mNetwork != null) {
+ // Create new MmsHttpClient for the current Network
+ mMmsHttpClient = new MmsHttpClient(mContext, mNetwork, mConnectivityManager);
+ }
}
return mMmsHttpClient;
}
}
- // Create new MmsHttpClient for the current Network
- private void populateHttpClientWithCurrentNetwork() {
- if (mNetwork != null) {
- mMmsHttpClient = new MmsHttpClient(mContext, mNetwork, mConnectivityManager);
- }
- }
-
/**
* Get the APN name for the active network
*
@@ -583,4 +535,15 @@
protected int getNetworkReleaseTimeoutMillis() {
return mNetworkReleaseTimeoutMillis;
}
+
+ /**
+ * Indicates satellite transport status for active network
+ *
+ * @return {@code true} if satellite transport, otherwise {@code false}
+ */
+ public boolean isSatelliteTransport() {
+ LogUtil.w("satellite transport status: " + mIsSatelliteTransport);
+ return mIsSatelliteTransport;
+ }
+
}
diff --git a/src/com/android/mms/service/MmsRequest.java b/src/com/android/mms/service/MmsRequest.java
index 1d0cb2b..604d9de 100644
--- a/src/com/android/mms/service/MmsRequest.java
+++ b/src/com/android/mms/service/MmsRequest.java
@@ -38,13 +38,14 @@
import android.telephony.ims.ImsMmTelManager;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.flags.Flags;
import com.android.mms.service.exception.ApnException;
import com.android.mms.service.exception.MmsHttpException;
import com.android.mms.service.exception.MmsNetworkException;
-import com.android.mms.service.exception.VoluntaryDisconnectMmsHttpException;
import com.android.mms.service.metrics.MmsStats;
import java.util.UUID;
@@ -129,18 +130,30 @@
class MonitorTelephonyCallback extends TelephonyCallback implements
TelephonyCallback.PreciseDataConnectionStateListener {
+
+ /** The lock to update mNetworkIdToApn. */
+ private final Object mLock = new Object();
+ /**
+ * Track the network agent Id to APN. Usually we have at most 2 networks that are capable of
+ * MMS at the same time (terrestrial and satellite)
+ */
+ @GuardedBy("mLock")
+ private final SparseArray<ApnSetting> mNetworkIdToApn = new SparseArray<>(2);
@Override
public void onPreciseDataConnectionStateChanged(
- PreciseDataConnectionState connectionState) {
- if (connectionState == null) {
- return;
- }
+ @NonNull PreciseDataConnectionState connectionState) {
ApnSetting apnSetting = connectionState.getApnSetting();
- int apnTypes = apnSetting.getApnTypeBitmask();
- if ((apnTypes & ApnSetting.TYPE_MMS) != 0) {
- mLastConnectionFailure = connectionState.getLastCauseCode();
- LogUtil.d("onPreciseDataConnectionStateChanged mLastConnectionFailure: "
- + mLastConnectionFailure);
+ if (apnSetting != null) {
+ // Only track networks that are capable of MMS.
+ if ((apnSetting.getApnTypeBitmask() & ApnSetting.TYPE_MMS) != 0) {
+ LogUtil.d("onPreciseDataConnectionStateChanged: " + connectionState);
+ mLastConnectionFailure = connectionState.getLastCauseCode();
+ if (Flags.mmsGetApnFromPdsc()) {
+ synchronized (mLock) {
+ mNetworkIdToApn.put(connectionState.getNetId(), apnSetting);
+ }
+ }
+ }
}
}
}
@@ -177,38 +190,56 @@
byte[] response = null;
int retryId = 0;
currentState = MmsRequestState.PrepareForHttpRequest;
- int attemptedTimes = 0;
+
if (!prepareForHttpRequest()) { // Prepare request, like reading pdu data from user
LogUtil.e(requestId, "Failed to prepare for request");
result = SmsManager.MMS_ERROR_IO_ERROR;
} else { // Execute
long retryDelaySecs = 2;
// Try multiple times of MMS HTTP request, depending on the error.
- while (retryId < RETRY_TIMES) {
+ for (retryId = 0; retryId < RETRY_TIMES; retryId++) {
httpStatusCode = 0; // Clear for retry.
MonitorTelephonyCallback connectionStateCallback = new MonitorTelephonyCallback();
try {
listenToDataConnectionState(connectionStateCallback);
currentState = MmsRequestState.AcquiringNetwork;
- networkManager.acquireNetwork(requestId);
- final String apnName = networkManager.getApnName();
- LogUtil.d(requestId, "APN name is " + apnName);
- ApnSettings apn = null;
+ int networkId = networkManager.acquireNetwork(requestId);
currentState = MmsRequestState.LoadingApn;
- try {
- apn = ApnSettings.load(context, apnName, mSubId, requestId);
- } catch (ApnException e) {
- // If no APN could be found, fall back to trying without the APN name
- if (apnName == null) {
- // If the APN name was already null then don't need to retry
- throw (e);
+ ApnSettings apn = null;
+ ApnSetting networkApn = null;
+ if (Flags.mmsGetApnFromPdsc()) {
+ synchronized (connectionStateCallback.mLock) {
+ networkApn = connectionStateCallback.mNetworkIdToApn.get(networkId);
}
- LogUtil.i(requestId, "No match with APN name: "
- + apnName + ", try with no name");
- apn = ApnSettings.load(context, null, mSubId, requestId);
+ if (networkApn != null) {
+ apn = ApnSettings.getApnSettingsFromNetworkApn(networkApn);
+ }
}
- LogUtil.d(requestId, "Using " + apn.toString());
+ if (apn == null) {
+ final String apnName = networkManager.getApnName();
+ LogUtil.d(requestId, "APN name is " + apnName);
+ try {
+ apn = ApnSettings.load(context, apnName, mSubId, requestId);
+ } catch (ApnException e) {
+ // If no APN could be found, fall back to trying without the APN name
+ if (apnName == null) {
+ // If the APN name was already null then don't need to retry
+ throw (e);
+ }
+ LogUtil.i(requestId, "No match with APN name: "
+ + apnName + ", try with no name");
+ apn = ApnSettings.load(context, null, mSubId, requestId);
+ }
+ }
+
+ if (Flags.mmsGetApnFromPdsc() && networkApn == null && apn != null) {
+ reportAnomaly("Can't find MMS APN in mms network",
+ UUID.fromString("2bdda74d-3cf4-44ad-a87f-24c961212a6f"));
+ }
+
+ LogUtil.d(requestId, "Using APN " + apn);
if (Flags.carrierEnabledSatelliteFlag()
+ && networkManager.isSatelliteTransport()
&& !canTransferPayloadOnCurrentNetwork()) {
LogUtil.e(requestId, "PDU too large for satellite");
result = SmsManager.MMS_ERROR_TOO_LARGE_FOR_TRANSPORT;
@@ -228,12 +259,8 @@
result = SmsManager.MMS_ERROR_UNABLE_CONNECT_MMS;
break;
} catch (MmsHttpException e) {
- if (e instanceof VoluntaryDisconnectMmsHttpException) {
- result = Activity.RESULT_CANCELED;
- } else {
- LogUtil.e(requestId, "HTTP or network I/O failure", e);
- result = SmsManager.MMS_ERROR_HTTP_FAILURE;
- }
+ LogUtil.e(requestId, "HTTP or network I/O failure", e);
+ result = SmsManager.MMS_ERROR_HTTP_FAILURE;
httpStatusCode = e.getStatusCode();
// Retry
} catch (Exception e) {
@@ -241,36 +268,13 @@
result = SmsManager.MMS_ERROR_UNSPECIFIED;
break;
} finally {
- // Don't release the MMS network if the last attempt was voluntarily
- // cancelled (due to better network available), because releasing the request
- // could result that network being torn down as it's thought to be useless.
- boolean canRelease = false;
- if (result != Activity.RESULT_CANCELED) {
- retryId++;
- canRelease = true;
- }
- // Otherwise, delay the release for successful download request.
- networkManager.releaseNetwork(requestId, canRelease,
- this instanceof DownloadRequest && result == Activity.RESULT_OK);
-
+ // Release the MMS network immediately except successful DownloadRequest.
+ networkManager.releaseNetwork(requestId,
+ this instanceof DownloadRequest
+ && result == Activity.RESULT_OK);
stopListeningToDataConnectionState(connectionStateCallback);
}
- // THEORETICALLY WOULDN'T OCCUR - PUTTING HERE AS A SAFETY NET.
- // TODO: REMOVE WITH FLAG mms_enhancement_enabled after soaking enough time, V-QPR.
- // Only possible if network kept disconnecting due to Activity.RESULT_CANCELED,
- // causing retryId doesn't increase and thus stuck in the infinite loop.
- // However, it's theoretically impossible because RESULT_CANCELED is only triggered
- // when a WLAN network becomes newly available in addition to an existing network.
- // Therefore, the WLAN network's own death cannot be triggered by RESULT_CANCELED,
- // and thus must result in retryId++.
- if (++attemptedTimes > RETRY_TIMES * 2) {
- LogUtil.e(requestId, "Retry is performed too many times");
- reportAnomaly("MMS retried too many times",
- UUID.fromString("038c9155-5daa-4515-86ae-aafdd33c1435"));
- break;
- }
-
if (result != Activity.RESULT_CANCELED) {
try { // Cool down retry if the previous attempt wasn't voluntarily cancelled.
new CountDownLatch(1).await(retryDelaySecs, TimeUnit.SECONDS);
@@ -592,11 +596,6 @@
LogUtil.d("canTransferPayloadOnCurrentNetwork serviceState null");
return true; // assume we're not connected to a satellite
}
- LogUtil.d("canTransferPayloadOnCurrentNetwork onSatellite: "
- + serviceState.isUsingNonTerrestrialNetwork());
- if (!serviceState.isUsingNonTerrestrialNetwork()) {
- return true; // not connected to satellite, no size limit
- }
long payloadSize = getPayloadSize();
int maxPduSize = mMmsConfig
.getInt(CarrierConfigManager.KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT);
diff --git a/src/com/android/mms/service/MmsService.java b/src/com/android/mms/service/MmsService.java
index 388eceb..6213513 100644
--- a/src/com/android/mms/service/MmsService.java
+++ b/src/com/android/mms/service/MmsService.java
@@ -24,6 +24,7 @@
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.app.Service;
+import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -1095,6 +1096,11 @@
LogUtil.e("Uri is null");
return 0;
}
+ int contentUriUserID = ContentProvider.getUserIdFromUri(contentUri, UserHandle.myUserId());
+ if (UserHandle.myUserId() != contentUriUserID) {
+ LogUtil.e("Uri is invalid");
+ return 0;
+ }
Callable<Integer> copyPduToArray = new Callable<Integer>() {
public Integer call() {
ParcelFileDescriptor.AutoCloseInputStream inStream = null;
diff --git a/src/com/android/mms/service/exception/VoluntaryDisconnectMmsHttpException.java b/src/com/android/mms/service/exception/VoluntaryDisconnectMmsHttpException.java
deleted file mode 100644
index 2b6840a..0000000
--- a/src/com/android/mms/service/exception/VoluntaryDisconnectMmsHttpException.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mms.service.exception;
-
-/**
- * Thrown when voluntarily disconnect an MMS http connection to trigger immediate retry. This
- * exception indicates the connection is voluntarily cancelled, instead of a failure.
- */
-public class VoluntaryDisconnectMmsHttpException extends MmsHttpException{
- public VoluntaryDisconnectMmsHttpException(int statusCode, String message) {
- super(statusCode, message);
- }
-}
diff --git a/src/com/android/mms/service/metrics/MmsMetricsCollector.java b/src/com/android/mms/service/metrics/MmsMetricsCollector.java
index 8da61ba..1bf9211 100644
--- a/src/com/android/mms/service/metrics/MmsMetricsCollector.java
+++ b/src/com/android/mms/service/metrics/MmsMetricsCollector.java
@@ -26,14 +26,13 @@
import androidx.annotation.VisibleForTesting;
+import com.android.internal.util.ConcurrentUtils;
import com.android.mms.IncomingMms;
import com.android.mms.MmsStatsLog;
import com.android.mms.OutgoingMms;
-import com.android.internal.util.ConcurrentUtils;
import java.time.Duration;
import java.util.List;
-import java.util.concurrent.Executor;
/**
* Implements statsd pullers for Mms.
@@ -91,7 +90,8 @@
mms.getMmsCount(),
mms.getRetryId(),
mms.getHandledByCarrierApp(),
- mms.getIsManagedProfile());
+ mms.getIsManagedProfile(),
+ mms.getIsNtn());
}
private static StatsEvent buildStatsEvent(OutgoingMms mms) {
@@ -109,7 +109,8 @@
mms.getIsFromDefaultApp(),
mms.getRetryId(),
mms.getHandledByCarrierApp(),
- mms.getIsManagedProfile());
+ mms.getIsManagedProfile(),
+ mms.getIsNtn());
}
@Override
diff --git a/src/com/android/mms/service/metrics/MmsStats.java b/src/com/android/mms/service/metrics/MmsStats.java
index fd45a5d..6df9f79 100644
--- a/src/com/android/mms/service/metrics/MmsStats.java
+++ b/src/com/android/mms/service/metrics/MmsStats.java
@@ -33,6 +33,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.UiccCardInfo;
+import android.util.Log;
import com.android.internal.telephony.SmsApplication;
import com.android.internal.telephony.flags.Flags;
@@ -104,6 +105,7 @@
.setRetryId(retryId)
.setHandledByCarrierApp(handledByCarrierApp)
.setIsManagedProfile(isManagedProfile())
+ .setIsNtn(isUsingNonTerrestrialNetwork())
.build();
mPersistMmsAtomsStorage.addIncomingMms(incomingMms);
}
@@ -124,6 +126,7 @@
.setRetryId(retryId)
.setHandledByCarrierApp(handledByCarrierApp)
.setIsManagedProfile(isManagedProfile())
+ .setIsNtn(isUsingNonTerrestrialNetwork())
.build();
mPersistMmsAtomsStorage.addOutgoingMms(outgoingMms);
}
@@ -224,6 +227,21 @@
return SmsApplication.isDefaultMmsApplicationAsUser(mContext, mCallingPkg, userHandle);
}
+ /** Determines whether device is non-terrestrial network or not. */
+ private boolean isUsingNonTerrestrialNetwork() {
+ if (!Flags.carrierEnabledSatelliteFlag()) {
+ return false;
+ }
+
+ ServiceState ss = mTelephonyManager.getServiceState();
+ if (ss != null) {
+ return ss.isUsingNonTerrestrialNetwork();
+ } else {
+ Log.e(TAG, "isUsingNonTerrestrialNetwork(): ServiceState is null");
+ }
+ return false;
+ }
+
/**
* Returns the interval in milliseconds between sending/receiving MMS message and current time.
* Calculates the time taken to send message to the network
diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp
index 9689e31..0c41dbf 100644
--- a/tests/robotests/Android.bp
+++ b/tests/robotests/Android.bp
@@ -21,4 +21,6 @@
instrumentation_for: "MmsService",
upstream: true,
+
+ strict_mode: false,
}
diff --git a/tests/robotests/src/com/android/mms/service/ApnSettingsTest.java b/tests/robotests/src/com/android/mms/service/ApnSettingsTest.java
index b184e16..7f920ef 100644
--- a/tests/robotests/src/com/android/mms/service/ApnSettingsTest.java
+++ b/tests/robotests/src/com/android/mms/service/ApnSettingsTest.java
@@ -43,6 +43,11 @@
@RunWith(RobolectricTestRunner.class)
public final class ApnSettingsTest {
+ private static final String APN_NAME = "mms.com";
+ private static final String ENTRY_NAME = "mms apn";
+ private static final String URI = "mmscUrl";
+ private static final String ADDRESS = "mmsProxyAddress";
+ private static final int PORT = 15;
private Context context;
@@ -94,6 +99,42 @@
Telephony.Carriers.CONTENT_URI.getAuthority(), new FakeApnSettingsProvider(cursor));
}
+ @Test
+ public void getApnSettingsFromNetworkApn_normal() {
+ ApnSetting networkApn = new ApnSetting.Builder().setApnName(APN_NAME)
+ .setEntryName(ENTRY_NAME)
+ .setApnTypeBitmask(ApnSetting.TYPE_MMS)
+ .setMmsc(Uri.parse(URI))
+ .setMmsProxyPort(PORT)
+ .setMmsProxyAddress(ADDRESS).build();
+ ApnSettings apnSettings = ApnSettings.getApnSettingsFromNetworkApn(networkApn);
+ assertThat(apnSettings.getMmscUrl()).isEqualTo(URI);
+ assertThat(apnSettings.getProxyPort()).isEqualTo(PORT);
+ assertThat(apnSettings.getProxyAddress()).isEqualTo(ADDRESS);
+ }
+
+ @Test
+ public void getApnSettingsFromNetworkApn_emptyMmsUrl_returnEmpty() {
+ ApnSetting networkApn = new ApnSetting.Builder().setApnName(APN_NAME)
+ .setEntryName(ENTRY_NAME)
+ .setApnTypeBitmask(ApnSetting.TYPE_MMS)
+ .setMmsProxyPort(PORT)
+ .setMmsProxyAddress(ADDRESS).build();
+ ApnSettings apnSettings = ApnSettings.getApnSettingsFromNetworkApn(networkApn);
+ assertThat(apnSettings).isNull();
+ }
+
+ @Test
+ public void getApnSettingsFromNetworkApn_nullMmsPort_defaultProxyPortUsed() {
+ ApnSetting networkApn = new ApnSetting.Builder().setApnName(APN_NAME)
+ .setEntryName(ENTRY_NAME)
+ .setApnTypeBitmask(ApnSetting.TYPE_MMS)
+ .setMmsc(Uri.parse(URI))
+ .setMmsProxyAddress(ADDRESS).build();
+ ApnSettings apnSettings = ApnSettings.getApnSettingsFromNetworkApn(networkApn);
+ assertThat(apnSettings.getProxyPort()).isEqualTo(80);
+ }
+
private final class FakeApnSettingsProvider extends ContentProvider {
private final Cursor cursor;
diff --git a/tests/robotests/src/com/android/mms/service/MmsNetworkManagerTest.java b/tests/robotests/src/com/android/mms/service/MmsNetworkManagerTest.java
index 70b1a0a..dff2bab 100644
--- a/tests/robotests/src/com/android/mms/service/MmsNetworkManagerTest.java
+++ b/tests/robotests/src/com/android/mms/service/MmsNetworkManagerTest.java
@@ -22,16 +22,13 @@
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.fail;
-import static org.junit.Assert.assertNotSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
-import static org.robolectric.RuntimeEnvironment.getMasterScheduler;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -41,7 +38,6 @@
import android.net.NetworkInfo;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
-import android.telephony.TelephonyManager;
import org.junit.Before;
import org.junit.Test;
@@ -51,7 +47,6 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import java.lang.reflect.Field;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -155,29 +150,6 @@
}
@Test
- public void testAvailableNetwork_wwanNetworkReplacedByWlanNetwork() throws Exception {
- MmsHttpClient mockMmsHttpClient = mock(MmsHttpClient.class);
- doReturn(true).when(mDeps).isMmsEnhancementEnabled();
-
- // WWAN network is always available, whereas WLAN network needs extra time to be set up.
- doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mNetworkInfo).getSubtype();
- doReturn(TelephonyManager.NETWORK_TYPE_IWLAN).when(mNetworkInfo2).getSubtype();
-
- final NetworkCallback callback = acquireAvailableNetworkAndGetCallback(
- mTestNetwork /* expectNetwork */, MMS_APN /* expectApn */);
- replaceInstance(MmsNetworkManager.class, "mMmsHttpClient", mMnm,
- mockMmsHttpClient);
-
- // The WLAN network become available.
- callback.onCapabilitiesChanged(mTestNetwork2, USABLE_NC);
- getMasterScheduler().advanceToLastPostedRunnable();
-
- // Verify current connections disconnect, then the client is replaced with a new network.
- verify(mockMmsHttpClient).disconnectAllUrlConnections();
- assertNotSame(mMnm.getOrCreateHttpClient(), mockMmsHttpClient);
- }
-
- @Test
public void testAvailableNetwork_networkBecomeSuspend() throws Exception {
final NetworkCallback callback = acquireAvailableNetworkAndGetCallback(
mTestNetwork /* expectNetwork */, MMS_APN /* expectApn */);
@@ -284,12 +256,4 @@
return future;
}
-
- /** Helper to replace instance field with reflection. */
- private void replaceInstance(final Class c, final String instanceName,
- final Object obj, final Object newValue) throws Exception {
- Field field = c.getDeclaredField(instanceName);
- field.setAccessible(true);
- field.set(obj, newValue);
- }
}
diff --git a/tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java b/tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java
index e144ef7..6fc2e72 100644
--- a/tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java
+++ b/tests/unittests/src/com/android/mms/service/MmsHttpClientTest.java
@@ -18,10 +18,7 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -31,29 +28,17 @@
import static org.mockito.Mockito.when;
import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Network;
import android.os.Bundle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import androidx.test.core.app.ApplicationProvider;
-import com.android.mms.service.exception.VoluntaryDisconnectMmsHttpException;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
-import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.SocketException;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
public class MmsHttpClientTest {
// Mocked classes
private Context mContext;
@@ -153,39 +138,4 @@
assertThat(phoneNo).contains(subscriberPhoneNumber);
verify(mSubscriptionManager).getPhoneNumber(subId);
}
-
- @Test
- public void testDisconnectAllUrlConnections() throws IOException {
- Network mockNetwork = mock(Network.class);
- HttpURLConnection mockConnection = mock(HttpURLConnection.class);
- doReturn(mockConnection).when(mockNetwork).openConnection(any(), any());
- doReturn(mockNetwork).when(mockNetwork).getPrivateDnsBypassingCopy();
- ConnectivityManager mockCm = mock(ConnectivityManager.class);
- Bundle config = new Bundle();
-
- // The external thread that voluntarily silently close the socket.
- CountDownLatch latch = new CountDownLatch(1);
- final ExecutorService externalThread = Executors.newSingleThreadExecutor();
- doAnswer(invok -> {
- latch.countDown();
- return null;
- }).when(mockConnection).disconnect();
-
- MmsHttpClient clientUT = new MmsHttpClient(mContext, mockNetwork, mockCm);
- doAnswer(invok -> {
- externalThread.execute(clientUT::disconnectAllUrlConnections);
- // connection.disconnect is silent, but it will trigger SocketException thrown from the
- // connect thread.
- if (latch.await(1, TimeUnit.SECONDS)) {
- throw new SocketException("Socket Closed");
- }
- return null;
- }).when(mockConnection).getResponseCode();
-
- // Verify SocketException is transformed into VoluntaryDisconnectMmsHttpException
- assertThrows(VoluntaryDisconnectMmsHttpException.class, () -> {
- clientUT.execute("http://test", new byte[0], "GET", false,
- "", 0, config, 1, "requestId");
- });
- }
}
diff --git a/tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java b/tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java
index 2b2cae5..089b3d7 100644
--- a/tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java
+++ b/tests/unittests/src/com/android/mms/service/metrics/MmsStatsTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -34,13 +35,13 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import com.android.internal.telephony.flags.Flags;
import com.android.mms.IncomingMms;
import com.android.mms.OutgoingMms;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-
import org.mockito.ArgumentCaptor;
public class MmsStatsTest {
@@ -92,6 +93,7 @@
assertThat(incomingMms.getRetryId()).isEqualTo(0);
assertThat(incomingMms.getHandledByCarrierApp()).isEqualTo(false);
assertThat(incomingMms.getIsManagedProfile()).isEqualTo(false);
+ assertThat(incomingMms.getIsNtn()).isEqualTo(false);
verifyNoMoreInteractions(mPersistMmsAtomsStorage);
}
@@ -120,6 +122,7 @@
assertThat(outgoingMms.getHandledByCarrierApp()).isEqualTo(false);
assertThat(outgoingMms.getIsFromDefaultApp()).isEqualTo(false);
assertThat(outgoingMms.getIsManagedProfile()).isEqualTo(false);
+ assertThat(outgoingMms.getIsNtn()).isEqualTo(false);
verifyNoMoreInteractions(mPersistMmsAtomsStorage);
}
@@ -151,4 +154,55 @@
// getSubscriptionUserHandle should not be called if subID is inactive.
verify(mSubscriptionManager, never()).getSubscriptionUserHandle(eq(inactiveSubId));
}
+
+ @Test
+ public void testIsNtn_serviceState_notNull() {
+ if (!Flags.carrierEnabledSatelliteFlag()) {
+ return;
+ }
+
+ ServiceState serviceState = mock(ServiceState.class);
+ doReturn(serviceState).when(mTelephonyManager).getServiceState();
+ doReturn(true).when(serviceState).isUsingNonTerrestrialNetwork();
+
+ MmsStats mmsStats = new MmsStats(mContext, mPersistMmsAtomsStorage, 1,
+ mTelephonyManager, null, true);
+ mmsStats.addAtomToStorage(Activity.RESULT_OK);
+
+ ArgumentCaptor<IncomingMms> incomingMmsCaptor = ArgumentCaptor.forClass(IncomingMms.class);
+ verify(mPersistMmsAtomsStorage).addIncomingMms(incomingMmsCaptor.capture());
+ IncomingMms incomingMms = incomingMmsCaptor.getValue();
+ assertThat(incomingMms.getIsNtn()).isEqualTo(true);
+
+ reset(mPersistMmsAtomsStorage);
+ reset(serviceState);
+ doReturn(false).when(serviceState).isUsingNonTerrestrialNetwork();
+
+ mmsStats = new MmsStats(mContext, mPersistMmsAtomsStorage, 1,
+ mTelephonyManager, null, true);
+ mmsStats.addAtomToStorage(Activity.RESULT_OK);
+
+ incomingMmsCaptor = ArgumentCaptor.forClass(IncomingMms.class);
+ verify(mPersistMmsAtomsStorage).addIncomingMms(incomingMmsCaptor.capture());
+ incomingMms = incomingMmsCaptor.getValue();
+ assertThat(incomingMms.getIsNtn()).isEqualTo(false);
+ }
+
+ @Test
+ public void testIsNtn_serviceState_Null() {
+ if (!Flags.carrierEnabledSatelliteFlag()) {
+ return;
+ }
+
+ doReturn(null).when(mTelephonyManager).getServiceState();
+
+ MmsStats mmsStats = new MmsStats(mContext, mPersistMmsAtomsStorage, 1,
+ mTelephonyManager, null, true);
+ mmsStats.addAtomToStorage(Activity.RESULT_OK);
+
+ ArgumentCaptor<IncomingMms> incomingMmsCaptor = ArgumentCaptor.forClass(IncomingMms.class);
+ verify(mPersistMmsAtomsStorage).addIncomingMms(incomingMmsCaptor.capture());
+ IncomingMms incomingMms = incomingMmsCaptor.getValue();
+ assertThat(incomingMms.getIsNtn()).isEqualTo(false);
+ }
}
\ No newline at end of file