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

Commit 903c1ee8 authored by Holly Jiuyu Sun's avatar Holly Jiuyu Sun Committed by android-build-merger
Browse files

Merge "Add device capabilities." am: d8a7436f

am: 04214a63

Change-Id: Icaf3f70df6e490a95b4da2902e3fdbf2ba77c7f2
parents 0c915cdb 04214a63
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),