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

Commit d8a7436f authored by Holly Jiuyu Sun's avatar Holly Jiuyu Sun Committed by Gerrit Code Review
Browse files

Merge "Add device capabilities."

parents 682fac6c ed1756d1
Loading
Loading
Loading
Loading
+85 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.telephony.uicc.euicc;

import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Registrant;
@@ -84,6 +85,16 @@ public class EuiccCard extends UiccCard {

    private static final EuiccSpecVersion SGP_2_0 = new EuiccSpecVersion(2, 0, 0);

    // Device capabilities.
    private static final String DEV_CAP_GSM = "gsm";
    private static final String DEV_CAP_UTRAN = "utran";
    private static final String DEV_CAP_CDMA_1X = "cdma_1x";
    private static final String DEV_CAP_HRPD = "hrpd";
    private static final String DEV_CAP_EHRPD = "ehrpd";
    private static final String DEV_CAP_EUTRAN = "eutran";
    private static final String DEV_CAP_NFC = "nfc";
    private static final String DEV_CAP_CRL = "crl";

    // These interfaces are used for simplifying the code by leveraging lambdas.
    private interface ApduRequestBuilder {
        void build(RequestBuilder requestBuilder)
@@ -599,8 +610,16 @@ public class EuiccCard extends UiccCard {
                    byte[] tacBytes = new byte[4];
                    System.arraycopy(imeiBytes, 0, tacBytes, 0, 4);

                    // TODO: Get device capabilities.
                    Asn1Node.Builder devCapsBuilder = Asn1Node.newBuilder(Tags.TAG_CTX_COMP_1);
                    String[] devCapsStrings = getResources().getStringArray(
                            com.android.internal.R.array.config_telephonyEuiccDeviceCapabilities);
                    if (devCapsStrings != null) {
                        for (String devCapItem : devCapsStrings) {
                            addDeviceCapability(devCapsBuilder, devCapItem);
                        }
                    } else {
                        if (DBG) logd("No device capabilities set.");
                    }

                    Asn1Node.Builder ctxParams1Builder = Asn1Node.newBuilder(Tags.TAG_CTX_COMP_0)
                            .addChildAsString(Tags.TAG_CTX_0, matchingId)
@@ -875,6 +894,62 @@ public class EuiccCard extends UiccCard {
                callback, handler);
    }

    /**
     * Sets a device capability version as the child of the given device capability ASN1 node
     * builder.
     *
     * @param devCapBuilder The ASN1 node builder to modify.
     * @param devCapItem The device capability and its supported version in pair.
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    public void addDeviceCapability(Asn1Node.Builder devCapBuilder, String devCapItem) {
        String[] split = devCapItem.split(",");
        if (split.length != 2) {
            loge("Invalid device capability item: " + Arrays.toString(split));
            return;
        }

        String devCap = split[0].trim();
        Integer version;
        try {
            version = Integer.parseInt(split[1].trim());
        } catch (NumberFormatException e) {
            loge("Invalid device capability version number.", e);
            return;
        }

        byte[] versionBytes = new byte[] { version.byteValue(), 0, 0 };
        switch (devCap) {
            case DEV_CAP_GSM:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_0, versionBytes);
                break;
            case DEV_CAP_UTRAN:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_1, versionBytes);
                break;
            case DEV_CAP_CDMA_1X:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_2, versionBytes);
                break;
            case DEV_CAP_HRPD:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_3, versionBytes);
                break;
            case DEV_CAP_EHRPD:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_4, versionBytes);
                break;
            case DEV_CAP_EUTRAN:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_5, versionBytes);
                break;
            case DEV_CAP_NFC:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_6, versionBytes);
                break;
            case DEV_CAP_CRL:
                devCapBuilder.addChildAsBytes(Tags.TAG_CTX_7, versionBytes);
                break;
            default:
                loge("Invalid device capability name: " + devCap);
                break;
        }
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected byte[] getDeviceId() {
        byte[] imeiBytes = new byte[8];
@@ -885,6 +960,11 @@ public class EuiccCard extends UiccCard {
        return imeiBytes;
    }

    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
    protected Resources getResources()  {
        return Resources.getSystem();
    }

    private RequestProvider newRequestProvider(ApduRequestBuilder builder) {
        return (selectResponse, requestBuilder) -> {
            EuiccSpecVersion ver = getOrExtractSpecVersion(selectResponse);
@@ -1150,6 +1230,10 @@ public class EuiccCard extends UiccCard {
        Rlog.e(LOG_TAG, message);
    }

    private static void loge(String message, Throwable tr) {
        Rlog.e(LOG_TAG, message, tr);
    }

    private static void logi(String message) {
        Rlog.i(LOG_TAG, message);
    }
+132 −0
Original line number Diff line number Diff line
@@ -25,7 +25,9 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.res.Resources;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -44,6 +46,8 @@ import com.android.internal.telephony.uicc.IccCardApplicationStatus;
import com.android.internal.telephony.uicc.IccCardStatus;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.uicc.asn1.Asn1Node;
import com.android.internal.telephony.uicc.asn1.InvalidAsn1DataException;
import com.android.internal.telephony.uicc.asn1.TagNotFoundException;
import com.android.internal.telephony.uicc.euicc.apdu.LogicalChannelMocker;
import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback;

@@ -52,6 +56,7 @@ import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;

import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@@ -106,6 +111,12 @@ public class EuiccCardTest extends TelephonyTest {

                        @Override
                        protected void loadEidAndNotifyRegistrants() {}

                        @Override
                        protected Resources getResources() {
                            return mMockResources;
                        }

                    };
            mHandler = new Handler(mTestHandlerThread.getLooper());
            setReady(true);
@@ -122,6 +133,9 @@ public class EuiccCardTest extends TelephonyTest {

    private EuiccCard mEuiccCard;

    @Mock
    private Resources mMockResources;

    @Before
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
@@ -520,6 +534,10 @@ public class EuiccCardTest extends TelephonyTest {

    @Test
    public void testAuthenticateServer() {
        when(mMockResources.getStringArray(
                com.android.internal.R.array.config_telephonyEuiccDeviceCapabilities))
                .thenReturn(new String[] {});

        int channel = mockLogicalChannelResponses("BF3802A0009000");

        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
@@ -542,6 +560,10 @@ public class EuiccCardTest extends TelephonyTest {

    @Test
    public void testAuthenticateServer_Error() {
        when(mMockResources.getStringArray(
                com.android.internal.R.array.config_telephonyEuiccDeviceCapabilities))
                .thenReturn(new String[] {});

        int channel = mockLogicalChannelResponses("BF38038101039000");

        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
@@ -561,6 +583,39 @@ public class EuiccCardTest extends TelephonyTest {
                        + "82088967452301214305"); // IMEI
    }

    @Test
    public void testAuthenticateService_devCap() {
        when(mMockResources.getStringArray(
                com.android.internal.R.array.config_telephonyEuiccDeviceCapabilities))
                .thenReturn(new String[] {
                        "gsm,11",
                        "utran,11",
                        "cdma1x,1",
                        "hrpd,3",
                        "ehrpd,12",
                        "eutran,11"});

        int channel = mockLogicalChannelResponses("BF3802A0009000");

        ResultCaptor<byte[]> resultCaptor = new ResultCaptor<>();
        mEuiccCard.authenticateServer("A1B2C3-X4Y5Z6", // Matching id
                Asn1Node.newBuilder(0xA0).build().toBytes(),
                Asn1Node.newBuilder(0xA1).build().toBytes(),
                Asn1Node.newBuilder(0xA2).build().toBytes(),
                Asn1Node.newBuilder(0xA3).build().toBytes(), resultCaptor, mHandler);
        resultCaptor.await();

        assertUnexpectedException(resultCaptor.exception);
        assertEquals("BF3802A000", IccUtils.bytesToHexString(resultCaptor.result));
        verifyStoreData(channel,
                "BF3846" + "A000" + "A100" + "A200" + "A300" + "A03C"
                        + "800D4131423243332D583459355A36" // Matching id
                        + "A12B800489674523" // TAC
                        // Device capabilities
                        + "A11980030B000081030B0000830303000084030C000085030B0000"
                        + "82088967452301214305"); // IMEI
    }

    @Test
    public void testPrepareDownload() {
        int channel = mockLogicalChannelResponses("BF2102A0009000");
@@ -852,6 +907,83 @@ public class EuiccCardTest extends TelephonyTest {
        verifyStoreData(channel, "BF3003800105");
    }

    @Test
    public void testAddDeviceCapability() throws InvalidAsn1DataException, TagNotFoundException {
        Asn1Node.Builder devCapsBuilder = Asn1Node.newBuilder(Tags.TAG_CTX_COMP_1);

        String devCapItem = "gsm,11";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        Asn1Node node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_0));
        Asn1Node child = node.getChild(Tags.TAG_CTX_0);
        assertTrue(Arrays.equals(new byte[] {11, 0 , 0}, child.asBytes()));

        devCapItem = "utran,11";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_1));
        child = node.getChild(Tags.TAG_CTX_1);
        assertTrue(Arrays.equals(new byte[] {11, 0 , 0}, child.asBytes()));

        devCapItem = "cdma_1x,1";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_2));
        child = node.getChild(Tags.TAG_CTX_2);
        assertTrue(Arrays.equals(new byte[] {1, 0 , 0}, child.asBytes()));

        devCapItem = "hrpd,1";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_3));
        child = node.getChild(Tags.TAG_CTX_3);
        assertTrue(Arrays.equals(new byte[] {1, 0 , 0}, child.asBytes()));

        devCapItem = "ehrpd,12";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_4));
        child = node.getChild(Tags.TAG_CTX_4);
        assertTrue(Arrays.equals(new byte[] {12, 0 , 0}, child.asBytes()));

        devCapItem = "eutran,11";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_5));
        child = node.getChild(Tags.TAG_CTX_5);
        assertTrue(Arrays.equals(new byte[] {11, 0 , 0}, child.asBytes()));

        devCapItem = "nfc,0";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_6));
        child = node.getChild(Tags.TAG_CTX_6);
        assertTrue(Arrays.equals(new byte[] {0, 0 , 0}, child.asBytes()));

        devCapItem = "crl,0";
        mEuiccCard.addDeviceCapability(devCapsBuilder, devCapItem);
        node = devCapsBuilder.build();

        assertTrue(node.hasChild(Tags.TAG_CTX_7));
        child = node.getChild(Tags.TAG_CTX_7);
        assertTrue(Arrays.equals(new byte[] {0, 0 , 0}, child.asBytes()));

        // Array length should not be 3.
        Asn1Node.Builder devCapsBuilder2 = Asn1Node.newBuilder(Tags.TAG_CTX_COMP_1);
        devCapItem = "gsm,1,1";
        mEuiccCard.addDeviceCapability(devCapsBuilder2, devCapItem);
        node = devCapsBuilder2.build();

        assertFalse(node.hasChild(Tags.TAG_CTX_0));
    }

    private void verifyStoreData(int channel, String command) {
        verify(mMockCi, times(1))
                .iccTransmitApduLogicalChannel(eq(channel), eq(0x80 | channel), eq(0xE2), eq(0x91),