1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.uicc.euicc.apdu; 18 19 import static org.mockito.ArgumentMatchers.anyInt; 20 import static org.mockito.ArgumentMatchers.anyString; 21 import static org.mockito.ArgumentMatchers.eq; 22 import static org.mockito.Mockito.doAnswer; 23 24 import android.annotation.Nullable; 25 import android.os.AsyncResult; 26 import android.os.Message; 27 28 import com.android.internal.telephony.CommandsInterface; 29 import com.android.internal.telephony.uicc.IccIoResult; 30 import com.android.internal.telephony.uicc.IccUtils; 31 32 import org.mockito.ArgumentCaptor; 33 import org.mockito.invocation.InvocationOnMock; 34 import org.mockito.stubbing.Answer; 35 36 /** Utility to set up mocks for communication with UICC through logical channel. */ 37 public final class LogicalChannelMocker { 38 private static final int LOGICAL_CHANNEL = 1; 39 40 /** 41 * @param responseObject Can be either a string or an exception. 42 * @return The mock channel number. 43 */ mockOpenLogicalChannelResponse(CommandsInterface mockCi, @Nullable Object responseObject)44 public static int mockOpenLogicalChannelResponse(CommandsInterface mockCi, 45 @Nullable Object responseObject) { 46 boolean isException = responseObject instanceof Throwable; 47 int[] responseInts = isException ? null : getSelectResponse(responseObject.toString()); 48 Throwable exception = isException ? (Throwable) responseObject : null; 49 50 ArgumentCaptor<Message> response = ArgumentCaptor.forClass(Message.class); 51 doAnswer((Answer<Void>) invocation -> { 52 Message msg = response.getValue(); 53 AsyncResult.forMessage(msg, responseInts, exception); 54 msg.sendToTarget(); 55 return null; 56 }).when(mockCi).iccOpenLogicalChannel(anyString(), anyInt(), response.capture()); 57 return LOGICAL_CHANNEL; 58 } 59 60 /** 61 * @param responseObjects Can be either a string or an exception. For string, the last 4 62 * digits are the status (sw1, sw1). 63 */ mockSendToLogicalChannel(CommandsInterface mockCi, int channel, Object... responseObjects)64 public static void mockSendToLogicalChannel(CommandsInterface mockCi, int channel, 65 Object... responseObjects) { 66 ArgumentCaptor<Message> response = ArgumentCaptor.forClass(Message.class); 67 doAnswer(new Answer() { 68 private int mIndex = 0; 69 70 @Override 71 public Object answer(InvocationOnMock invocation) throws Throwable { 72 Object responseObject = responseObjects[mIndex++]; 73 boolean isException = responseObject instanceof Throwable; 74 int sw1 = 0; 75 int sw2 = 0; 76 String hex = responseObject.toString(); 77 if (!isException) { 78 int l = hex.length(); 79 sw1 = Integer.parseInt(hex.substring(l - 4, l - 2), 16); 80 sw2 = Integer.parseInt(hex.substring(l - 2), 16); 81 hex = hex.substring(0, l - 4); 82 } 83 IccIoResult result = isException ? null : new IccIoResult(sw1, sw2, hex); 84 Throwable exception = isException ? (Throwable) responseObject : null; 85 86 Message msg = response.getValue(); 87 AsyncResult.forMessage(msg, result, exception); 88 msg.sendToTarget(); 89 return null; 90 } 91 }).when(mockCi).iccTransmitApduLogicalChannel(eq(channel), anyInt(), anyInt(), anyInt(), 92 anyInt(), anyInt(), anyString(), response.capture()); 93 } 94 mockCloseLogicalChannel(CommandsInterface mockCi, int channel)95 public static void mockCloseLogicalChannel(CommandsInterface mockCi, int channel) { 96 ArgumentCaptor<Message> response = ArgumentCaptor.forClass(Message.class); 97 doAnswer((Answer<Void>) invocation -> { 98 Message msg = response.getValue(); 99 AsyncResult.forMessage(msg); 100 msg.sendToTarget(); 101 return null; 102 }).when(mockCi).iccCloseLogicalChannel(eq(channel), response.capture()); 103 } 104 getSelectResponse(String responseHex)105 private static int[] getSelectResponse(String responseHex) { 106 byte[] responseBytes = IccUtils.hexStringToBytes("00" + responseHex); 107 int[] responseInts = new int[responseBytes.length]; 108 responseInts[0] = LOGICAL_CHANNEL; 109 for (int i = 1; i < responseInts.length; ++i) { 110 responseInts[i] = responseBytes[i]; 111 } 112 return responseInts; 113 } 114 LogicalChannelMocker()115 private LogicalChannelMocker() { 116 } 117 } 118