1 /*
2  * Copyright (C) 2022 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 package com.android.nfc.cardemulation;
17 
18 import static org.mockito.ArgumentMatchers.anyString;
19 import static org.mockito.Mockito.when;
20 
21 import android.bluetooth.BluetoothProtoEnums;
22 import android.content.Context;
23 import android.content.ContextWrapper;
24 import android.content.Intent;
25 import android.content.pm.PackageManager;
26 import android.nfc.cardemulation.ApduServiceInfo;
27 import android.nfc.cardemulation.CardEmulation;
28 import android.os.UserHandle;
29 import android.os.test.TestLooper;
30 import android.util.Log;
31 import androidx.test.ext.junit.runners.AndroidJUnit4;
32 import androidx.test.platform.app.InstrumentationRegistry;
33 
34 import android.platform.test.annotations.RequiresFlagsEnabled;
35 import android.platform.test.flag.junit.CheckFlagsRule;
36 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
37 import com.android.dx.mockito.inline.extended.ExtendedMockito;
38 import com.android.nfc.cardemulation.RegisteredAidCache.AidResolveInfo;
39 import com.android.nfc.NfcStatsLog;
40 import com.android.nfc.flags.Flags;
41 
42 import junit.framework.TestListener;
43 
44 import java.util.ArrayList;
45 import java.util.List;
46 
47 import org.junit.After;
48 import org.junit.Assert;
49 import org.junit.Before;
50 import org.junit.Rule;
51 import org.junit.Test;
52 import org.junit.runner.RunWith;
53 import org.mockito.Mockito;
54 import org.mockito.MockitoSession;
55 
56 @RunWith(AndroidJUnit4.class)
57 public final class NfcAidConflictOccurredTest {
58 
59     private static final String TAG = NfcAidConflictOccurredTest.class.getSimpleName();
60     private boolean mNfcSupported;
61 
62     private MockitoSession mStaticMockSession;
63     private HostEmulationManager mHostEmulation;
64     @Rule
65     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
66     private final TestLooper mTestLooper = new TestLooper();
67 
68     @Before
setUp()69     public void setUp() {
70         mStaticMockSession = ExtendedMockito.mockitoSession()
71                 .mockStatic(NfcStatsLog.class)
72                 .startMocking();
73 
74         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
75         PackageManager pm = context.getPackageManager();
76         if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
77             mNfcSupported = false;
78             return;
79         }
80         mNfcSupported = true;
81 
82         RegisteredAidCache mockAidCache = Mockito.mock(RegisteredAidCache.class);
83         ApduServiceInfo apduServiceInfo = Mockito.mock(ApduServiceInfo.class);
84         AidResolveInfo aidResolveInfo = mockAidCache.new AidResolveInfo();
85         // no defaultService and no activeService
86         aidResolveInfo.services = new ArrayList<ApduServiceInfo>();
87         aidResolveInfo.services.add(apduServiceInfo);
88         when(mockAidCache.resolveAid(anyString())).thenReturn(aidResolveInfo);
89 
90         Context mockContext = new ContextWrapper(context) {
91             @Override
92             public void startActivityAsUser(Intent intent, UserHandle user) {
93                 Log.i(TAG, "[Mock] startActivityAsUser");
94             }
95 
96             @Override
97             public void sendBroadcastAsUser(Intent intent, UserHandle user) {
98                 Log.i(TAG, "[Mock] sendBroadcastAsUser");
99             }
100         };
101         InstrumentationRegistry.getInstrumentation().runOnMainSync(
102               () -> mHostEmulation = new HostEmulationManager(
103                       mockContext, mTestLooper.getLooper(), mockAidCache));
104         Assert.assertNotNull(mHostEmulation);
105 
106         mHostEmulation.onHostEmulationActivated();
107     }
108 
109     @After
tearDown()110     public void tearDown() {
111         mHostEmulation.onHostEmulationDeactivated();
112         mStaticMockSession.finishMocking();
113     }
114 
115     @Test
testHCEOther()116     public void testHCEOther() {
117         if (!mNfcSupported) return;
118 
119         byte[] aidBytes = new byte[] {
120             0x00, (byte)0xA4, 0x04, 0x00,  // command
121             0x08,  // data length
122             (byte)0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
123             0x00,  // card manager AID
124             0x00  // trailer
125         };
126         mHostEmulation.onHostEmulationData(aidBytes);
127         ExtendedMockito.verify(() -> NfcStatsLog.write(
128                 NfcStatsLog.NFC_AID_CONFLICT_OCCURRED,
129                 "A000000003000000"));
130     }
131 
132     @Test
133     @RequiresFlagsEnabled(Flags.FLAG_TEST_FLAG)
testHCEOtherWithTestFlagEnabled()134     public void testHCEOtherWithTestFlagEnabled() {
135         if (!mNfcSupported) return;
136 
137         byte[] aidBytes = new byte[] {
138                 0x00, (byte)0xA4, 0x04, 0x00,  // command
139                 0x08,  // data length
140                 (byte)0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
141                 0x00,  // card manager AID
142                 0x00  // trailer
143         };
144         mHostEmulation.onHostEmulationData(aidBytes);
145         ExtendedMockito.verify(() -> NfcStatsLog.write(
146                 NfcStatsLog.NFC_AID_CONFLICT_OCCURRED,
147                 "A000000003000000"));
148     }
149 }
150