Loading src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java +14 −17 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,7 @@ package com.android.internal.telephony.uicc.euicc.apdu; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.Context; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; import android.preference.PreferenceManager; import android.preference.PreferenceManager; Loading @@ -34,7 +34,6 @@ import com.android.telephony.Rlog; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.IOException; import java.util.List; import java.util.List; import java.util.NoSuchElementException; /** /** * This class sends a list of APDU commands to an AID on a UICC. A logical channel will be opened * This class sends a list of APDU commands to an AID on a UICC. A logical channel will be opened Loading @@ -58,7 +57,7 @@ public class ApduSender { private static final int WAIT_TIME_MS = 2000; private static final int WAIT_TIME_MS = 2000; private static final String CHANNEL_ID_PRE = "esim-channel"; private static final String CHANNEL_ID_PRE = "esim-channel"; private static final String ISD_R_AID = "A0000005591010FFFFFFFF8900000100"; static final String ISD_R_AID = "A0000005591010FFFFFFFF8900000100"; private static final String CHANNEL_RESPONSE_ID_PRE = "esim-res-id"; private static final String CHANNEL_RESPONSE_ID_PRE = "esim-res-id"; private static void logv(String msg) { private static void logv(String msg) { Loading Loading @@ -88,6 +87,9 @@ public class ApduSender { */ */ public ApduSender(Context context, int phoneId, CommandsInterface ci, String aid, public ApduSender(Context context, int phoneId, CommandsInterface ci, String aid, boolean supportExtendedApdu) { boolean supportExtendedApdu) { if (!aid.equals(ISD_R_AID) && !"user".equals(Build.TYPE)) { throw new IllegalArgumentException("Only ISD-R AID is supported."); } mAid = aid; mAid = aid; mContext = context; mContext = context; mSupportExtendedApdu = supportExtendedApdu; mSupportExtendedApdu = supportExtendedApdu; Loading Loading @@ -145,8 +147,7 @@ public class ApduSender { int channel = openChannelResponse.getChannel(); int channel = openChannelResponse.getChannel(); int status = openChannelResponse.getStatus(); int status = openChannelResponse.getStatus(); byte[] selectResponse = openChannelResponse.getSelectResponse(); byte[] selectResponse = openChannelResponse.getSelectResponse(); if (mAid.equals(ISD_R_AID) if (status == IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT) { && status == IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT) { channel = PreferenceManager.getDefaultSharedPreferences(mContext) channel = PreferenceManager.getDefaultSharedPreferences(mContext) .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL); .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL); if (channel != IccOpenLogicalChannelResponse.INVALID_CHANNEL) { if (channel != IccOpenLogicalChannelResponse.INVALID_CHANNEL) { Loading @@ -172,13 +173,11 @@ public class ApduSender { RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu); RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu); Throwable requestException = null; Throwable requestException = null; if (mAid.equals(ISD_R_AID)) { PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().putInt(mChannelKey, channel).apply(); .edit().putInt(mChannelKey, channel).apply(); PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().putString(mChannelResponseKey, .edit().putString(mChannelResponseKey, Base64.encodeToString(selectResponse, Base64.DEFAULT)).apply(); Base64.encodeToString(selectResponse, Base64.DEFAULT)).apply(); } try { try { requestProvider.buildRequest(selectResponse, builder); requestProvider.buildRequest(selectResponse, builder); } catch (Throwable e) { } catch (Throwable e) { Loading Loading @@ -317,12 +316,10 @@ public class ApduSender { @Override @Override public void onResult(Boolean aBoolean) { public void onResult(Boolean aBoolean) { synchronized (mChannelLock) { synchronized (mChannelLock) { if (mAid.equals(ISD_R_AID)) { PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().remove(mChannelKey).apply(); .edit().remove(mChannelKey).apply(); PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().remove(mChannelResponseKey).apply(); .edit().remove(mChannelResponseKey).apply(); } mChannelOpened = false; mChannelOpened = false; mChannelLock.notify(); mChannelLock.notify(); } } Loading tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java +17 −6 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.telephony.uicc.euicc.apdu; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean; Loading @@ -33,11 +34,12 @@ import android.os.Looper; import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.uicc.IccIoResult; import com.android.internal.telephony.uicc.IccIoResult; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.IccUtils; import androidx.test.InstrumentationRegistry; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; Loading Loading @@ -83,7 +85,6 @@ public class ApduSenderTest { private Handler mHandler; private Handler mHandler; private ResponseCaptor mResponseCaptor; private ResponseCaptor mResponseCaptor; private byte[] mSelectResponse; private byte[] mSelectResponse; private static final String AID = "B2C3D4"; private ApduSender mSender; private ApduSender mSender; @Before @Before Loading @@ -95,7 +96,7 @@ public class ApduSenderTest { mSelectResponse = null; mSelectResponse = null; mSender = new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */, mSender = new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */, mMockCi, AID, false /* supportExtendedApdu */); mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */); mLooper = TestableLooper.get(this); mLooper = TestableLooper.get(this); } } Loading @@ -109,6 +110,16 @@ public class ApduSenderTest { mSender = null; mSender = null; } } @Test public void testWrongAid_throwsIllegalArgumentException() { String wrongAid = "-1"; assertThrows(IllegalArgumentException.class, () -> { new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */, mMockCi, wrongAid, false /* supportExtendedApdu */); }); } @Test @Test public void testSendEmptyCommands() throws InterruptedException { public void testSendEmptyCommands() throws InterruptedException { int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "A1A1A19000"); int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "A1A1A19000"); Loading @@ -121,7 +132,7 @@ public class ApduSenderTest { assertEquals("A1A1A19000", IccUtils.bytesToHexString(mSelectResponse)); assertEquals("A1A1A19000", IccUtils.bytesToHexString(mSelectResponse)); assertNull(mResponseCaptor.response); assertNull(mResponseCaptor.response); assertNull(mResponseCaptor.exception); assertNull(mResponseCaptor.exception); verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any()); verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any()); verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any()); verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any()); } } Loading @@ -137,7 +148,7 @@ public class ApduSenderTest { assertNull("Request provider should not be called when failed to open channel.", assertNull("Request provider should not be called when failed to open channel.", mSelectResponse); mSelectResponse); assertTrue(mResponseCaptor.exception instanceof ApduException); assertTrue(mResponseCaptor.exception instanceof ApduException); verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any()); verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any()); } } @Test @Test Loading Loading @@ -341,6 +352,6 @@ public class ApduSenderTest { assertNull("Should not open channel when another one is already opened.", mSelectResponse); assertNull("Should not open channel when another one is already opened.", mSelectResponse); assertTrue(mResponseCaptor.exception instanceof ApduException); assertTrue(mResponseCaptor.exception instanceof ApduException); verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(AID), anyInt(), any()); verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any()); } } } } Loading
src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java +14 −17 Original line number Original line Diff line number Diff line Loading @@ -18,7 +18,7 @@ package com.android.internal.telephony.uicc.euicc.apdu; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.Context; import android.content.Context; import android.content.SharedPreferences; import android.os.Build; import android.os.Handler; import android.os.Handler; import android.os.Looper; import android.os.Looper; import android.preference.PreferenceManager; import android.preference.PreferenceManager; Loading @@ -34,7 +34,6 @@ import com.android.telephony.Rlog; import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.IOException; import java.util.List; import java.util.List; import java.util.NoSuchElementException; /** /** * This class sends a list of APDU commands to an AID on a UICC. A logical channel will be opened * This class sends a list of APDU commands to an AID on a UICC. A logical channel will be opened Loading @@ -58,7 +57,7 @@ public class ApduSender { private static final int WAIT_TIME_MS = 2000; private static final int WAIT_TIME_MS = 2000; private static final String CHANNEL_ID_PRE = "esim-channel"; private static final String CHANNEL_ID_PRE = "esim-channel"; private static final String ISD_R_AID = "A0000005591010FFFFFFFF8900000100"; static final String ISD_R_AID = "A0000005591010FFFFFFFF8900000100"; private static final String CHANNEL_RESPONSE_ID_PRE = "esim-res-id"; private static final String CHANNEL_RESPONSE_ID_PRE = "esim-res-id"; private static void logv(String msg) { private static void logv(String msg) { Loading Loading @@ -88,6 +87,9 @@ public class ApduSender { */ */ public ApduSender(Context context, int phoneId, CommandsInterface ci, String aid, public ApduSender(Context context, int phoneId, CommandsInterface ci, String aid, boolean supportExtendedApdu) { boolean supportExtendedApdu) { if (!aid.equals(ISD_R_AID) && !"user".equals(Build.TYPE)) { throw new IllegalArgumentException("Only ISD-R AID is supported."); } mAid = aid; mAid = aid; mContext = context; mContext = context; mSupportExtendedApdu = supportExtendedApdu; mSupportExtendedApdu = supportExtendedApdu; Loading Loading @@ -145,8 +147,7 @@ public class ApduSender { int channel = openChannelResponse.getChannel(); int channel = openChannelResponse.getChannel(); int status = openChannelResponse.getStatus(); int status = openChannelResponse.getStatus(); byte[] selectResponse = openChannelResponse.getSelectResponse(); byte[] selectResponse = openChannelResponse.getSelectResponse(); if (mAid.equals(ISD_R_AID) if (status == IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT) { && status == IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT) { channel = PreferenceManager.getDefaultSharedPreferences(mContext) channel = PreferenceManager.getDefaultSharedPreferences(mContext) .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL); .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL); if (channel != IccOpenLogicalChannelResponse.INVALID_CHANNEL) { if (channel != IccOpenLogicalChannelResponse.INVALID_CHANNEL) { Loading @@ -172,13 +173,11 @@ public class ApduSender { RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu); RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu); Throwable requestException = null; Throwable requestException = null; if (mAid.equals(ISD_R_AID)) { PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().putInt(mChannelKey, channel).apply(); .edit().putInt(mChannelKey, channel).apply(); PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().putString(mChannelResponseKey, .edit().putString(mChannelResponseKey, Base64.encodeToString(selectResponse, Base64.DEFAULT)).apply(); Base64.encodeToString(selectResponse, Base64.DEFAULT)).apply(); } try { try { requestProvider.buildRequest(selectResponse, builder); requestProvider.buildRequest(selectResponse, builder); } catch (Throwable e) { } catch (Throwable e) { Loading Loading @@ -317,12 +316,10 @@ public class ApduSender { @Override @Override public void onResult(Boolean aBoolean) { public void onResult(Boolean aBoolean) { synchronized (mChannelLock) { synchronized (mChannelLock) { if (mAid.equals(ISD_R_AID)) { PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().remove(mChannelKey).apply(); .edit().remove(mChannelKey).apply(); PreferenceManager.getDefaultSharedPreferences(mContext) PreferenceManager.getDefaultSharedPreferences(mContext) .edit().remove(mChannelResponseKey).apply(); .edit().remove(mChannelResponseKey).apply(); } mChannelOpened = false; mChannelOpened = false; mChannelLock.notify(); mChannelLock.notify(); } } Loading
tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java +17 −6 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.telephony.uicc.euicc.apdu; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyBoolean; Loading @@ -33,11 +34,12 @@ import android.os.Looper; import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper; import androidx.test.InstrumentationRegistry; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.uicc.IccIoResult; import com.android.internal.telephony.uicc.IccIoResult; import com.android.internal.telephony.uicc.IccUtils; import com.android.internal.telephony.uicc.IccUtils; import androidx.test.InstrumentationRegistry; import org.junit.After; import org.junit.After; import org.junit.Before; import org.junit.Before; Loading Loading @@ -83,7 +85,6 @@ public class ApduSenderTest { private Handler mHandler; private Handler mHandler; private ResponseCaptor mResponseCaptor; private ResponseCaptor mResponseCaptor; private byte[] mSelectResponse; private byte[] mSelectResponse; private static final String AID = "B2C3D4"; private ApduSender mSender; private ApduSender mSender; @Before @Before Loading @@ -95,7 +96,7 @@ public class ApduSenderTest { mSelectResponse = null; mSelectResponse = null; mSender = new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */, mSender = new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */, mMockCi, AID, false /* supportExtendedApdu */); mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */); mLooper = TestableLooper.get(this); mLooper = TestableLooper.get(this); } } Loading @@ -109,6 +110,16 @@ public class ApduSenderTest { mSender = null; mSender = null; } } @Test public void testWrongAid_throwsIllegalArgumentException() { String wrongAid = "-1"; assertThrows(IllegalArgumentException.class, () -> { new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */, mMockCi, wrongAid, false /* supportExtendedApdu */); }); } @Test @Test public void testSendEmptyCommands() throws InterruptedException { public void testSendEmptyCommands() throws InterruptedException { int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "A1A1A19000"); int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "A1A1A19000"); Loading @@ -121,7 +132,7 @@ public class ApduSenderTest { assertEquals("A1A1A19000", IccUtils.bytesToHexString(mSelectResponse)); assertEquals("A1A1A19000", IccUtils.bytesToHexString(mSelectResponse)); assertNull(mResponseCaptor.response); assertNull(mResponseCaptor.response); assertNull(mResponseCaptor.exception); assertNull(mResponseCaptor.exception); verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any()); verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any()); verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any()); verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any()); } } Loading @@ -137,7 +148,7 @@ public class ApduSenderTest { assertNull("Request provider should not be called when failed to open channel.", assertNull("Request provider should not be called when failed to open channel.", mSelectResponse); mSelectResponse); assertTrue(mResponseCaptor.exception instanceof ApduException); assertTrue(mResponseCaptor.exception instanceof ApduException); verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any()); verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any()); } } @Test @Test Loading Loading @@ -341,6 +352,6 @@ public class ApduSenderTest { assertNull("Should not open channel when another one is already opened.", mSelectResponse); assertNull("Should not open channel when another one is already opened.", mSelectResponse); assertTrue(mResponseCaptor.exception instanceof ApduException); assertTrue(mResponseCaptor.exception instanceof ApduException); verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(AID), anyInt(), any()); verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any()); } } } }