1 /* 2 * Copyright (C) 2025 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 android.nfc.cardemulation; 18 19 import static android.nfc.cardemulation.HostApduService.MSG_RESPONSE_APDU; 20 import static android.nfc.cardemulation.HostApduService.MSG_UNHANDLED; 21 22 import static org.junit.Assert.assertEquals; 23 import static org.mockito.Mockito.CALLS_REAL_METHODS; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.never; 26 import static org.mockito.Mockito.only; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.content.Intent; 31 import android.nfc.Flags; 32 import android.os.Bundle; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.Messenger; 36 import android.os.RemoteException; 37 38 import com.android.dx.mockito.inline.extended.ExtendedMockito; 39 40 import org.junit.After; 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.mockito.MockitoAnnotations; 44 import org.mockito.MockitoSession; 45 import org.mockito.quality.Strictness; 46 47 public class HostApduServiceTest { 48 private byte[] sampleApdu = "EO00001800".getBytes(); 49 private HostApduService.MsgHandler mHandler; 50 private SampleHostApduService mSampleService; 51 private MockitoSession mMockitoSession; 52 53 class SampleHostApduService extends HostApduService { 54 55 @Override processCommandApdu(byte[] commandApdu, Bundle extras)56 public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) { 57 return new byte[0]; 58 } 59 60 @Override onDeactivated(int reason)61 public void onDeactivated(int reason) { 62 63 } 64 } 65 66 @Before setUp()67 public void setUp() { 68 mMockitoSession = ExtendedMockito.mockitoSession() 69 .mockStatic(Flags.class) 70 .mockStatic(com.android.nfc.module.flags.Flags.class) 71 .strictness(Strictness.LENIENT) 72 .startMocking(); 73 MockitoAnnotations.initMocks(this); 74 if (Looper.myLooper() == null) { 75 Looper.prepare(); 76 } 77 mSampleService = mock(SampleHostApduService.class, CALLS_REAL_METHODS); 78 mHandler = mSampleService.getMsgHandler(); 79 } 80 81 @After tearDown()82 public void tearDown() { 83 mMockitoSession.finishMocking(); 84 } 85 86 @Test testHandleMessageWithCmdApdu()87 public void testHandleMessageWithCmdApdu() { 88 Bundle bundle = mock(Bundle.class); 89 Message msg = mock(Message.class); 90 Messenger mNfcService = mock(Messenger.class); 91 msg.what = HostApduService.MSG_COMMAND_APDU; 92 msg.replyTo = mNfcService; 93 when(msg.getData()).thenReturn(bundle); 94 when(bundle.getByteArray(HostApduService.KEY_DATA)).thenReturn(sampleApdu); 95 96 mHandler.post(() -> { 97 mHandler.handleMessage(msg); 98 verify(msg).getData(); 99 }); 100 } 101 102 @Test testHandleMessageWithResponseApduWhenServiceDeactivated()103 public void testHandleMessageWithResponseApduWhenServiceDeactivated() { 104 Message msg = mock(Message.class); 105 msg.what = MSG_RESPONSE_APDU; 106 107 when(mSampleService.getNfcService()).thenReturn(null); 108 mHandler.post(() -> { 109 mHandler.handleMessage(msg); 110 verify(mSampleService).getNfcService(); 111 }); 112 } 113 114 @Test testHandleMessageWithResponseApdu()115 public void testHandleMessageWithResponseApdu() { 116 Message msg = mock(Message.class); 117 Messenger mNfcService = mock(Messenger.class); 118 msg.what = MSG_RESPONSE_APDU; 119 msg.replyTo = mNfcService; 120 121 when(mSampleService.getNfcService()).thenReturn(mNfcService); 122 mHandler.post(() -> { 123 mHandler.handleMessage(msg); 124 verify(mSampleService).getMessenger(); 125 try { 126 verify(mNfcService).send(msg); 127 } catch (RemoteException e) { 128 throw new RuntimeException(e); 129 } 130 }); 131 } 132 133 @Test testHandleMessageWithApduAck()134 public void testHandleMessageWithApduAck() { 135 Message msg = mock(Message.class); 136 msg.what = HostApduService.MSG_RESPONSE_APDU_ACK; 137 138 mHandler.post(() -> { 139 mHandler.handleMessage(msg); 140 verify(mSampleService, never()).getNfcService(); 141 }); 142 } 143 144 @Test testHandleMessageWithMsgDeactivated()145 public void testHandleMessageWithMsgDeactivated() { 146 Message msg = Message.obtain(); 147 msg.what = HostApduService.MSG_DEACTIVATED; 148 msg.arg1 = 1; 149 150 mHandler.post(() -> { 151 mHandler.handleMessage(msg); 152 verify(mSampleService).setNfcService(null); 153 verify(mSampleService).onDeactivated(1); 154 }); 155 } 156 157 @Test testHandleMessageWithMsgUnhandledWhenServiceDeactivated()158 public void testHandleMessageWithMsgUnhandledWhenServiceDeactivated() { 159 Message msg = mock(Message.class); 160 msg.what = MSG_UNHANDLED; 161 when(mSampleService.getNfcService()).thenReturn(null); 162 163 mHandler.post(() -> { 164 mHandler.handleMessage(msg); 165 verify(mSampleService, only()).getNfcService(); 166 }); 167 } 168 169 @Test testHandleMessageWithMsgUnhandled()170 public void testHandleMessageWithMsgUnhandled() { 171 Message msg = mock(Message.class); 172 msg.what = MSG_UNHANDLED; 173 Messenger mNfcService = mock(Messenger.class); 174 when(mSampleService.getNfcService()).thenReturn(mNfcService); 175 176 mHandler.post(() -> { 177 mHandler.handleMessage(msg); 178 verify(mSampleService).getMessenger(); 179 }); 180 } 181 182 @Test testHandleMessageWithPollingLoop()183 public void testHandleMessageWithPollingLoop() { 184 Message msg = mock(Message.class); 185 msg.what = HostApduService.MSG_POLLING_LOOP; 186 when(com.android.nfc.module.flags.Flags.nfcHceLatencyEvents()).thenReturn(true); 187 188 mHandler.post(() -> { 189 mHandler.handleMessage(msg); 190 verify(mSampleService).getMessenger(); 191 }); 192 } 193 194 @Test testOnBinder()195 public void testOnBinder() { 196 Messenger messenger = mock(Messenger.class); 197 when(mSampleService.getMessenger()).thenReturn(messenger); 198 199 mSampleService.onBind(mock(Intent.class)); 200 verify(messenger).getBinder(); 201 } 202 203 @Test testNfcService()204 public void testNfcService() { 205 Messenger nfcService = mock(Messenger.class); 206 mSampleService.setNfcService(nfcService); 207 208 assertEquals(nfcService, mSampleService.getNfcService()); 209 } 210 } 211