Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c33d7f5 authored by Muralidhar Reddy's avatar Muralidhar Reddy
Browse files

[MEP] Resolve port index in case apps are calling switchToSubscription(without...

[MEP] Resolve port index in case apps are calling switchToSubscription(without portIndex) API for disable operation.

Subscription enable/disable is done through a single EuiccManager.switchToSubscription API. If the passing subId is invalid which means to disable the currently enabled profile on eUICC. With MEP, there can be more than one active subscription so apps should explicitly calling new API switchToSubscripti.on(with portIndex) to specify disable which profile from eUICC.

Bug: 218393363
Test: atest FrameworksTelephonyTests
Change-Id: I8694cf2cbe6637ca4e1e44a4c12cf1126da2eca3
parent c5496c01
Loading
Loading
Loading
Loading
+68 −10
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.compat.CompatChanges;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -987,7 +988,8 @@ public class EuiccController extends IEuiccController.Stub {
        boolean callerCanWriteEmbeddedSubscriptions = callerCanWriteEmbeddedSubscriptions();
        mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
        Log.d(TAG, " subId: " + subscriptionId + " portIndex: " + portIndex
                + " forceDeactivateSim: " + forceDeactivateSim + " usePortIndex: " + usePortIndex);
                + " forceDeactivateSim: " + forceDeactivateSim + " usePortIndex: " + usePortIndex
                + " callingPackage: " + callingPackage);
        long token = Binder.clearCallingIdentity();
        try {
            if (callerCanWriteEmbeddedSubscriptions) {
@@ -997,19 +999,23 @@ public class EuiccController extends IEuiccController.Stub {
                forceDeactivateSim = true;
            }

            // if the caller is not privileged caller and does not have the carrier privilege over
            // any active subscription, do not continue.
            if (!callerCanWriteEmbeddedSubscriptions && usePortIndex
                    && (mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
                    != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS)) {
                Log.e(TAG, "Not permitted to use switchToSubscription with portIndex");
                throw new SecurityException(
                        "Must have carrier privileges to use switchToSubscription with portIndex");
            }
            final String iccid;
            boolean passConsent = false;
            boolean isConsentNeededToResolvePortIndex = false;
            if (subscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
                if (!usePortIndex) {
                    // Resolve the portIndex internally if apps are calling switchToSubscription
                    // API without portIndex and subscription id is invalid.
                    portIndex = getResolvedPortIndexForDisableSubscription(cardId, callingPackage,
                            callerCanWriteEmbeddedSubscriptions);
                    if (portIndex == TelephonyManager.INVALID_PORT_INDEX) {
                        Log.e(TAG, "Disable is not permitted: no active subscription or cannot"
                                + " manage subscription");
                        sendResult(callbackIntent, ERROR, null /* extrasIntent */);
                        return;
                    }
                    usePortIndex = true;
                }
                if (callerCanWriteEmbeddedSubscriptions
                        || canManageActiveSubscriptionOnTargetSim(cardId, callingPackage,
                        usePortIndex, portIndex)) {
@@ -1085,6 +1091,34 @@ public class EuiccController extends IEuiccController.Stub {
        }
    }

    /**
     * Returns the resolved portIndex or {@link TelephonyManager#INVALID_PORT_INDEX} if calling
     * cannot manage any active subscription.
     */
    private int getResolvedPortIndexForDisableSubscription(int cardId, String callingPackage,
            boolean callerCanWriteEmbeddedSubscriptions) {
        List<SubscriptionInfo> subInfoList = mSubscriptionManager
                .getActiveSubscriptionInfoList(/* userVisibleOnly */false);
        if (subInfoList == null || subInfoList.size() == 0) {
            // No active subscription on any SIM.
            return TelephonyManager.INVALID_PORT_INDEX;
        }
        // Return the portIndex of the first active subscription managed by the calling app.
        for (SubscriptionInfo subInfo : subInfoList) {
            // If cardId == TelephonyManager.UNSUPPORTED_CARD_ID, we assume it does not support
            // multiple eSIMs. There are older multi-active SIM devices which do not implement HAL
            // 1.2 and if they have multiple eSIMs, we let it pass if the app can manage an active
            // subscription on any eSIM. That's the best we can do here.
            if ((cardId == TelephonyManager.UNSUPPORTED_CARD_ID || subInfo.getCardId() == cardId)
                    && subInfo.isEmbedded()
                    && (callerCanWriteEmbeddedSubscriptions
                    || mSubscriptionManager.canManageSubscription(subInfo, callingPackage))) {
                return subInfo.getPortIndex();
            }
        }
        return TelephonyManager.INVALID_PORT_INDEX;
    }

    /**
     * Returns the resolved portIndex or {@link TelephonyManager#INVALID_PORT_INDEX} if no port
     * is available without user consent.
@@ -1852,4 +1886,28 @@ public class EuiccController extends IEuiccController.Stub {
        }
        return false;
    }

    @Override
    public boolean hasCarrierPrivilegesForPackageOnAnyPhone(String callingPackage) {
        final long token = Binder.clearCallingIdentity();
        try {
            // checkCarrierPrivilegesForPackageAnyPhone API requires READ_PHONE_STATE permission,
            // hence cannot call directly from EuiccManager switchToSubscription
            return mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
                    == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
        } finally {
            Binder.restoreCallingIdentity(token);
        }
    }

    @Override
    public boolean isCompatChangeEnabled(String callingPackage, long changeId) {
        // Platform compat framework kills the callingPackage app to ensure that the change
        // takes affect immediately. So the corresponding compat checking is moved to controller.
        boolean changeEnabled = CompatChanges.isChangeEnabled(changeId, callingPackage,
                Binder.getCallingUserHandle());
        Log.i(TAG, "isCompatChangeEnabled changeId: " + changeId
                + " changeEnabled: " + changeEnabled);
        return changeEnabled;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ android_test {
        "services.net",
        "truth-prebuilt",
        "testables",
        "platform-compat-test-rules"
    ],

    jarjar_rules: ":jarjar-rules-telephony-tests",
+40 −3
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.internal.telephony.euicc;

import static android.telephony.euicc.EuiccCardManager.RESET_OPTION_DELETE_OPERATIONAL_PROFILES;
import static android.telephony.euicc.EuiccManager.EUICC_OTA_STATUS_UNAVAILABLE;
import static android.telephony.euicc.EuiccManager.SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -39,6 +40,7 @@ import static org.mockito.Mockito.when;
import android.Manifest;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.compat.testing.PlatformCompatChangeRule;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
@@ -68,9 +70,14 @@ import com.android.internal.telephony.euicc.EuiccConnector.GetOtaStatusCommandCa
import com.android.internal.telephony.euicc.EuiccConnector.OtaStatusChangedCallback;
import com.android.internal.telephony.uicc.UiccSlot;

import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
@@ -86,11 +93,14 @@ import java.util.Collections;

@RunWith(AndroidJUnit4.class)
public class EuiccControllerTest extends TelephonyTest {
    @Rule
    public TestRule compatChangeRule = new PlatformCompatChangeRule();
    private static final DownloadableSubscription SUBSCRIPTION =
            DownloadableSubscription.forActivationCode("abcde");

    private static final String PACKAGE_NAME = "test.package";
    private static final String CARRIER_NAME = "test name";
    private static final String TEST_PACKAGE_NAME = "com.android.frameworks.telephonytests";
    private static final byte[] SIGNATURE_BYTES = new byte[] {1, 2, 3, 4, 5};

    private static final UiccAccessRule ACCESS_RULE;
@@ -821,9 +831,22 @@ public class EuiccControllerTest extends TelephonyTest {
        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0 /* detailedCode */);
    }

    @Test
    public void testSwitchToSubscription_emptySubscription_noActiveSubscription() throws Exception {
        setHasWriteEmbeddedPermission(true);
        callSwitchToSubscription(
                SubscriptionManager.INVALID_SUBSCRIPTION_ID, null /* iccid */, true /* complete */,
                EuiccService.RESULT_OK, "whatever" /* callingPackage */);
        verifyIntentSent(EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR,
                0 /* detailedCode */);
        verify(mMockConnector, never()).switchToSubscription(anyInt(), anyInt(), anyString(),
                anyBoolean(), any(), anyBoolean());
    }

    @Test
    public void testSwitchToSubscription_emptySubscription_success() throws Exception {
        setHasWriteEmbeddedPermission(true);
        setHasCarrierPrivilegesOnActiveSubscription(false);
        callSwitchToSubscription(
                SubscriptionManager.INVALID_SUBSCRIPTION_ID, null /* iccid */, true /* complete */,
                EuiccService.RESULT_OK, "whatever" /* callingPackage */);
@@ -1139,6 +1162,20 @@ public class EuiccControllerTest extends TelephonyTest {
                EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_ERROR_CODE, -1), 0x345678);
    }

    @Test
    @DisableCompatChanges({SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE})
    public void testIsCompactChangeEnabled_disable() {
        assertFalse(mController.isCompatChangeEnabled(TEST_PACKAGE_NAME,
                SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE));
    }

    @Test
    @EnableCompatChanges({SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE})
    public void testIsCompactChangeEnabled_enable() {
        assertTrue(mController.isCompatChangeEnabled(TEST_PACKAGE_NAME,
                SWITCH_WITHOUT_PORT_INDEX_EXCEPTION_ON_DISABLE));
    }

    private void setUpUiccSlotData() {
        when(mUiccController.getUiccSlot(anyInt())).thenReturn(mUiccSlot);
        // TODO(b/199559633): Add test cases for isMultipleEnabledProfileSupported true case
@@ -1173,7 +1210,7 @@ public class EuiccControllerTest extends TelephonyTest {
        SubscriptionInfo subInfo = new SubscriptionInfo(
                0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */,
                hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID,
                false, null, false, 0, 0, 0, null, null, true, -1);
                false, null, false, 0, 0, 0, null, null, true, 0);
        when(mSubscriptionManager.canManageSubscription(subInfo, PACKAGE_NAME)).thenReturn(
                hasPrivileges);
        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(
@@ -1202,11 +1239,11 @@ public class EuiccControllerTest extends TelephonyTest {
        SubscriptionInfo subInfo1 = new SubscriptionInfo(
                0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */,
                hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "", CARD_ID,
                false, null, false, 0, 0, 0, null, null, true, -1);
                false, null, false, 0, 0, 0, null, null, true, 0);
        SubscriptionInfo subInfo2 = new SubscriptionInfo(
                0, "", 0, "", "", 0, 0, "", 0, null, "", "", "", true /* isEmbedded */,
                hasPrivileges ? new UiccAccessRule[] { ACCESS_RULE } : null, "",
                1 /* cardId */, false, null, false, 0, 0, 0, null, null, true, -1);
                1 /* cardId */, false, null, false, 0, 0, 0, null, null, true, 0);
        when(mSubscriptionManager.canManageSubscription(subInfo1, PACKAGE_NAME)).thenReturn(
                hasPrivileges);
        when(mSubscriptionManager.canManageSubscription(subInfo2, PACKAGE_NAME)).thenReturn(