Add subscription-user association check.
Bug: 250620312
Test: Manually sending/receiving SMS/MMS,
atest com.android.internal.telephony.SmsControllerTest,
atest com.android.internal.telephony.SubscriptionControllerTest,
atest CtsTelephonyTestCases
Merged-In: Ieb22f8ef2f57d15f1e72874268216ec32b7d2026
Change-Id: Ieb22f8ef2f57d15f1e72874268216ec32b7d2026
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 59db686..f149fda 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -45,6 +45,7 @@
import android.util.Slog;
import com.android.internal.telephony.IMms;
+import com.android.internal.telephony.TelephonyPermissions;
import com.android.server.uri.NeededUriGrants;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -337,6 +338,14 @@
throws RemoteException {
Slog.d(TAG, "sendMessage() by " + callingPkg);
mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
+
+ // Check if user is associated with the subscription
+ if (!TelephonyPermissions.checkSubscriptionAssociatedWithUser(mContext, subId,
+ Binder.getCallingUserHandle())) {
+ // TODO(b/258629881): Display error dialog.
+ return;
+ }
+
if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
callingPkg, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
Slog.e(TAG, callingPkg + " is not allowed to call sendMessage()");
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index fdf69430..f90eabc 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.Manifest;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
@@ -822,4 +823,35 @@
}
return Integer.MAX_VALUE;
}
+
+ /**
+ * Check if calling user is associated with the given subscription.
+ * @param context Context
+ * @param subId subscription ID
+ * @param callerUserHandle caller user handle
+ * @return false if user is not associated with the subscription.
+ */
+ public static boolean checkSubscriptionAssociatedWithUser(@NonNull Context context, int subId,
+ @NonNull UserHandle callerUserHandle) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ // No subscription on device, return true.
+ return true;
+ }
+
+ SubscriptionManager subManager = context.getSystemService(SubscriptionManager.class);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if ((subManager != null) &&
+ (!subManager.isSubscriptionAssociatedWithUser(subId, callerUserHandle))) {
+ // If subId is not associated with calling user, return false.
+ Log.e(LOG_TAG,"User[User ID:" + callerUserHandle.getIdentifier()
+ + "] is not associated with Subscription ID:" + subId);
+ return false;
+
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return true;
+ }
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index d670e55..1cf2969 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2245,6 +2245,7 @@
RESULT_SMS_SEND_RETRY_FAILED,
RESULT_REMOTE_EXCEPTION,
RESULT_NO_DEFAULT_SMS_APP,
+ RESULT_USER_NOT_ALLOWED,
RESULT_RIL_RADIO_NOT_AVAILABLE,
RESULT_RIL_SMS_SEND_FAIL_RETRY,
RESULT_RIL_NETWORK_REJECT,
@@ -2425,6 +2426,13 @@
*/
public static final int RESULT_NO_DEFAULT_SMS_APP = 32;
+ /**
+ * User is not associated with the subscription.
+ * TODO(b/263279115): Make this error code public.
+ * @hide
+ */
+ public static final int RESULT_USER_NOT_ALLOWED = 33;
+
// Radio Error results
/**
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 37bfa72..b99f3d6 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -4394,5 +4394,70 @@
}
return null;
}
+
+ /**
+ * Check if subscription and user are associated with each other.
+ *
+ * @param subscriptionId the subId of the subscription
+ * @param userHandle user handle of the user
+ * @return {@code true} if subscription is associated with user
+ * {code true} if there are no subscriptions on device
+ * else {@code false} if subscription is not associated with user.
+ *
+ * @throws IllegalArgumentException if subscription is invalid.
+ * @throws SecurityException if the caller doesn't have permissions required.
+ * @throws IllegalStateException if subscription service is not available.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION)
+ public boolean isSubscriptionAssociatedWithUser(int subscriptionId,
+ @NonNull UserHandle userHandle) {
+ if (!isValidSubscriptionId(subscriptionId)) {
+ throw new IllegalArgumentException("[isSubscriptionAssociatedWithUser]: "
+ + "Invalid subscriptionId: " + subscriptionId);
+ }
+
+ try {
+ ISub iSub = TelephonyManager.getSubscriptionService();
+ if (iSub != null) {
+ return iSub.isSubscriptionAssociatedWithUser(subscriptionId, userHandle);
+ } else {
+ throw new IllegalStateException("[isSubscriptionAssociatedWithUser]: "
+ + "subscription service unavailable");
+ }
+ } catch (RemoteException ex) {
+ ex.rethrowAsRuntimeException();
+ }
+ return false;
+ }
+
+ /**
+ * Get list of subscriptions associated with user.
+ *
+ * @param userHandle user handle of the user
+ * @return list of subscriptionInfo associated with the user.
+ *
+ * @throws SecurityException if the caller doesn't have permissions required.
+ * @throws IllegalStateException if subscription service is not available.
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.MANAGE_SUBSCRIPTION_USER_ASSOCIATION)
+ public @NonNull List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(
+ @NonNull UserHandle userHandle) {
+ try {
+ ISub iSub = TelephonyManager.getSubscriptionService();
+ if (iSub != null) {
+ return iSub.getSubscriptionInfoListAssociatedWithUser(userHandle);
+ } else {
+ throw new IllegalStateException("[getSubscriptionInfoListAssociatedWithUser]: "
+ + "subscription service unavailable");
+ }
+ } catch (RemoteException ex) {
+ ex.rethrowAsRuntimeException();
+ }
+ return new ArrayList<>();
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index c5f6902..25a714a 100644
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -326,4 +326,34 @@
* @throws IllegalArgumentException if subId is invalid.
*/
UserHandle getSubscriptionUserHandle(int subId);
+
+ /**
+ * Check if subscription and user are associated with each other.
+ *
+ * @param subscriptionId the subId of the subscription
+ * @param userHandle user handle of the user
+ * @return {@code true} if subscription is associated with user
+ * {code true} if there are no subscriptions on device
+ * else {@code false} if subscription is not associated with user.
+ *
+ * @throws IllegalArgumentException if subscription is invalid.
+ * @throws SecurityException if the caller doesn't have permissions required.
+ * @throws IllegalStateException if subscription service is not available.
+ *
+ * @hide
+ */
+ boolean isSubscriptionAssociatedWithUser(int subscriptionId, in UserHandle userHandle);
+
+ /**
+ * Get list of subscriptions associated with user.
+ *
+ * @param userHandle user handle of the user
+ * @return list of subscriptionInfo associated with the user.
+ *
+ * @throws SecurityException if the caller doesn't have permissions required.
+ * @throws IllegalStateException if subscription service is not available.
+ *
+ * @hide
+ */
+ List<SubscriptionInfo> getSubscriptionInfoListAssociatedWithUser(in UserHandle userHandle);
}