Enforce simultaneous calling accounts have the same package name
When an app restricts simultaenous calling to a subset of accounts,
ensure that they register accounts with their package name.
Simultaneous calling is always possible across apps as long as
the app being set inactive has the ability to hold.
Bug: 319904227
Test: atest TelecomUnitTests:TelecomServiceImplTest
Change-Id: I555242ef1419fa5cb0d65ae8035db6e80c904e20
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 1701e5a..61fa9ba 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -77,6 +77,7 @@
import com.android.internal.telecom.ICallControl;
import com.android.internal.telecom.ICallEventCallback;
import com.android.internal.telecom.ITelecomService;
+import com.android.internal.telephony.flags.Flags;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.components.UserCallIntentProcessorFactory;
import com.android.server.telecom.flags.FeatureFlags;
@@ -807,6 +808,13 @@
// Validate the profile boundary of the given image URI.
validateAccountIconUserBoundary(account.getIcon());
+ if (mTelephonyFeatureFlags.simultaneousCallingIndications()
+ && account.hasSimultaneousCallingRestriction()) {
+ validateSimultaneousCallingPackageNames(
+ account.getAccountHandle().getComponentName().getPackageName(),
+ account.getSimultaneousCallingRestriction());
+ }
+
final long token = Binder.clearCallingIdentity();
try {
Log.i(this, "registerPhoneAccount: account=%s",
@@ -3292,4 +3300,20 @@
}
}
}
+
+ private void validateSimultaneousCallingPackageNames(String appPackageName,
+ Set<PhoneAccountHandle> handles) {
+ for (PhoneAccountHandle handle : handles) {
+ ComponentName name = handle.getComponentName();
+ if (name == null) {
+ throw new IllegalArgumentException("ComponentName is null");
+ }
+ String restrictionPackageName = name.getPackageName();
+ if (!appPackageName.equals(restrictionPackageName)) {
+ throw new SecurityException("The package name of the PhoneAccount does not "
+ + "match one or more of the package names set in the simultaneous "
+ + "calling restriction.");
+ }
+ }
+ }
}
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index bb6dce0..24b23af 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -111,7 +111,10 @@
import java.lang.reflect.Method;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Executor;
import java.util.function.IntConsumer;
@@ -846,6 +849,62 @@
@SmallTest
@Test
+ public void testRegisterPhoneAccountSimultaneousCallingVerification() throws RemoteException {
+ doReturn(true).when(mTelephonyFeatureFlags).simultaneousCallingIndications();
+ doReturn(PackageManager.PERMISSION_GRANTED)
+ .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
+ String packageNameToUse = "com.android.officialpackage";
+ PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
+ packageNameToUse, "cs"), "test", Binder.getCallingUserHandle());
+ PhoneAccountHandle phAllowedRestriction = new PhoneAccountHandle(new ComponentName(
+ packageNameToUse, "cs"), "test2", Binder.getCallingUserHandle());
+
+ PhoneAccount phoneAccountEmptyRestriction = makePhoneAccount(phHandle)
+ .setSimultaneousCallingRestriction(Collections.emptySet())
+ .build();
+ try {
+ mTSIBinder.registerPhoneAccount(phoneAccountEmptyRestriction, CALLING_PACKAGE);
+ verify(mFakePhoneAccountRegistrar).registerPhoneAccount(phoneAccountEmptyRestriction);
+ } catch (SecurityException e) {
+ fail("registerPhoneAccount must not throw a SecurityException if there is a "
+ + " restriction registered with the same package name.");
+ }
+
+ Set<PhoneAccountHandle> restriction = new HashSet<>(3);
+ restriction.add(phAllowedRestriction);
+ PhoneAccount phoneAccount = makePhoneAccount(phHandle)
+ .setSimultaneousCallingRestriction(restriction)
+ .build();
+
+ try {
+ mTSIBinder.registerPhoneAccount(phoneAccount, CALLING_PACKAGE);
+ verify(mFakePhoneAccountRegistrar).registerPhoneAccount(phoneAccount);
+ } catch (SecurityException e) {
+ fail("registerPhoneAccount must not throw a SecurityException if there is a "
+ + " restriction registered with the same package name.");
+ }
+
+ String anotherPackageName = "com.android.anotherpackage";
+ PhoneAccountHandle phDisallowedRestriction = new PhoneAccountHandle(new ComponentName(
+ anotherPackageName, "cs"), "test", Binder.getCallingUserHandle());
+ restriction.add(phDisallowedRestriction);
+ phoneAccount = makePhoneAccount(phHandle)
+ .setSimultaneousCallingRestriction(restriction)
+ .build();
+
+ try {
+ mTSIBinder.registerPhoneAccount(phoneAccount, CALLING_PACKAGE);
+ // there should not be another call to registerPhoneAccount
+ verify(mFakePhoneAccountRegistrar, times(1)).registerPhoneAccount(phoneAccount);
+ fail("registerPhoneAccount must throw a SecurityException if there is a "
+ + " restriction registered with a different package name.");
+ } catch (SecurityException e) {
+ //expected
+ }
+ }
+
+ @SmallTest
+ @Test
public void testRegisterPhoneAccountWithoutPermissionAnomalyReported() throws RemoteException {
PhoneAccountHandle handle = new PhoneAccountHandle(
new ComponentName("package", "cs"), "test", Binder.getCallingUserHandle());