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 
17 package com.android.server;
18 
19 import static org.mockito.ArgumentMatchers.anyInt;
20 import static org.mockito.ArgumentMatchers.anyString;
21 import static org.mockito.Mockito.doReturn;
22 import static org.mockito.Mockito.eq;
23 import static org.mockito.Mockito.never;
24 import static org.mockito.Mockito.spy;
25 import static org.mockito.Mockito.times;
26 import static org.mockito.Mockito.verify;
27 import static org.mockito.Mockito.when;
28 
29 import android.app.job.JobScheduler;
30 import android.content.Context;
31 import android.content.pm.PackageManager;
32 import android.content.pm.PackageManagerInternal;
33 import android.hardware.biometrics.ComponentInfoInternal;
34 import android.hardware.biometrics.SensorProperties;
35 import android.hardware.face.FaceManager;
36 import android.hardware.face.FaceSensorProperties;
37 import android.hardware.face.FaceSensorPropertiesInternal;
38 import android.hardware.face.IFaceAuthenticatorsRegisteredCallback;
39 import android.hardware.fingerprint.FingerprintManager;
40 import android.hardware.fingerprint.FingerprintSensorProperties;
41 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
42 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
43 import android.os.RemoteException;
44 import android.os.ResultReceiver;
45 import android.os.SystemProperties;
46 import android.provider.DeviceConfig;
47 import android.util.Log;
48 
49 import androidx.test.core.app.ApplicationProvider;
50 import androidx.test.ext.junit.runners.AndroidJUnit4;
51 
52 import com.android.internal.util.FrameworkStatsLog;
53 
54 import org.junit.After;
55 import org.junit.Assert;
56 import org.junit.Before;
57 import org.junit.Test;
58 import org.junit.runner.RunWith;
59 import org.mockito.ArgumentCaptor;
60 import org.mockito.Captor;
61 import org.mockito.Mock;
62 import org.mockito.MockitoAnnotations;
63 
64 import java.io.FileDescriptor;
65 import java.util.List;
66 
67 @RunWith(AndroidJUnit4.class)
68 public class BinaryTransparencyServiceTest {
69     private static final String TAG = "BinaryTransparencyServiceTest";
70 
71     private Context mContext;
72     private BinaryTransparencyService mBinaryTransparencyService;
73     private BinaryTransparencyService.BinaryTransparencyServiceImpl mTestInterface;
74     private DeviceConfig.Properties mOriginalBiometricsFlags;
75 
76     @Mock
77     private BinaryTransparencyService.BiometricLogger mBiometricLogger;
78     @Mock
79     private FingerprintManager mFpManager;
80     @Mock
81     private FaceManager mFaceManager;
82     @Mock
83     private PackageManager mPackageManager;
84     @Mock
85     private PackageManagerInternal mPackageManagerInternal;
86 
87     @Captor
88     private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback>
89             mFpAuthenticatorsRegisteredCaptor;
90     @Captor
91     private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback>
92             mFaceAuthenticatorsRegisteredCaptor;
93 
94     @Before
setUp()95     public void setUp() {
96         MockitoAnnotations.initMocks(this);
97 
98         mContext = spy(ApplicationProvider.getApplicationContext());
99         LocalServices.removeServiceForTest(PackageManagerInternal.class);
100         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
101 
102         mBinaryTransparencyService = new BinaryTransparencyService(mContext, mBiometricLogger);
103         mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl();
104         mOriginalBiometricsFlags = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BIOMETRICS);
105     }
106 
107     @After
tearDown()108     public void tearDown() throws Exception {
109         try {
110             DeviceConfig.setProperties(mOriginalBiometricsFlags);
111         } catch (DeviceConfig.BadConfigException e) {
112             Log.e(TAG, "Failed to reset biometrics flags to the original values before test. "
113                     + e);
114         }
115         LocalServices.removeServiceForTest(PackageManagerInternal.class);
116     }
117 
prepSignedInfo()118     private void prepSignedInfo() {
119         // simulate what happens on boot completed phase
120         // but we avoid calling JobScheduler.schedule by returning a null.
121         doReturn(null).when(mContext).getSystemService(JobScheduler.class);
122         mBinaryTransparencyService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
123     }
124 
prepApexInfo()125     private void prepApexInfo() throws RemoteException {
126         // simulates what happens to apex info after computations are done.
127         String[] args = {"get", "apex_info"};
128         mTestInterface.onShellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
129                 args, null, new ResultReceiver(null));
130     }
131 
prepBiometricsTesting()132     private void prepBiometricsTesting() {
133         when(mContext.getPackageManager()).thenReturn(mPackageManager);
134         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true);
135         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true);
136         when(mContext.getSystemService(FingerprintManager.class)).thenReturn(mFpManager);
137         when(mContext.getSystemService(FaceManager.class)).thenReturn(mFaceManager);
138     }
139 
140     @Test
getSignedImageInfo_preInitialize_returnsUninitializedString()141     public void getSignedImageInfo_preInitialize_returnsUninitializedString() {
142         String result = mTestInterface.getSignedImageInfo();
143         Assert.assertNotNull("VBMeta digest value should not be null", result);
144         Assert.assertEquals(BinaryTransparencyService.VBMETA_DIGEST_UNINITIALIZED, result);
145     }
146 
147     @Test
getSignedImageInfo_postInitialize_returnsNonErrorStrings()148     public void getSignedImageInfo_postInitialize_returnsNonErrorStrings() {
149         prepSignedInfo();
150         String result = mTestInterface.getSignedImageInfo();
151         Assert.assertNotNull("Initialized VBMeta digest string should not be null", result);
152         Assert.assertNotEquals("VBMeta digest value is uninitialized",
153                 BinaryTransparencyService.VBMETA_DIGEST_UNINITIALIZED, result);
154         Assert.assertNotEquals("VBMeta value should not be unavailable",
155                 BinaryTransparencyService.VBMETA_DIGEST_UNAVAILABLE, result);
156     }
157 
158     @Test
getSignedImageInfo_postInitialize_returnsCorrectValue()159     public void getSignedImageInfo_postInitialize_returnsCorrectValue() {
160         prepSignedInfo();
161         String result = mTestInterface.getSignedImageInfo();
162         Assert.assertEquals(
163                 SystemProperties.get(BinaryTransparencyService.SYSPROP_NAME_VBETA_DIGEST,
164                         BinaryTransparencyService.VBMETA_DIGEST_UNAVAILABLE), result);
165     }
166 
167     @Test
testCollectBiometricProperties_disablesFeature()168     public void testCollectBiometricProperties_disablesFeature() {
169         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
170                 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
171                 Boolean.FALSE.toString(),
172                 false /* makeDefault */);
173 
174         mBinaryTransparencyService.collectBiometricProperties();
175 
176         verify(mBiometricLogger, never()).logStats(anyInt(), anyInt(), anyInt(), anyInt(),
177                 anyString(), anyString(), anyString(), anyString(), anyString());
178     }
179 
180     @Test
testCollectBiometricProperties_enablesFeature_logsFingerprintProperties()181     public void testCollectBiometricProperties_enablesFeature_logsFingerprintProperties()
182             throws RemoteException {
183         prepBiometricsTesting();
184         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
185                 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
186                 Boolean.TRUE.toString(),
187                 false /* makeDefault */);
188         final List<FingerprintSensorPropertiesInternal> props = List.of(
189                 new FingerprintSensorPropertiesInternal(
190                         1 /* sensorId */,
191                         SensorProperties.STRENGTH_STRONG,
192                         5 /* maxEnrollmentsPerUser */,
193                         List.of(new ComponentInfoInternal("sensor" /* componentId */,
194                                 "vendor/model/revision" /* hardwareVersion */,
195                                 "1.01" /* firmwareVersion */, "00000001" /* serialNumber */,
196                                 "" /* softwareVersion */)),
197                         FingerprintSensorProperties.TYPE_REAR,
198                         true /* resetLockoutRequiresHardwareAuthToken */));
199 
200         mBinaryTransparencyService.collectBiometricProperties();
201 
202         verify(mFpManager).addAuthenticatorsRegisteredCallback(mFpAuthenticatorsRegisteredCaptor
203                 .capture());
204         mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props);
205 
206         verify(mBiometricLogger, times(1)).logStats(
207                 eq(1) /* sensorId */,
208                 eq(FrameworkStatsLog
209                         .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FINGERPRINT),
210                 eq(FrameworkStatsLog
211                         .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_REAR),
212                 eq(FrameworkStatsLog
213                         .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_STRONG),
214                 eq("sensor") /* componentId */,
215                 eq("vendor/model/revision") /* hardwareVersion */,
216                 eq("1.01") /* firmwareVersion */,
217                 eq("00000001") /* serialNumber */,
218                 eq("") /* softwareVersion */
219         );
220     }
221 
222     @Test
testCollectBiometricProperties_enablesFeature_logsFaceProperties()223     public void testCollectBiometricProperties_enablesFeature_logsFaceProperties()
224             throws RemoteException {
225         prepBiometricsTesting();
226         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS,
227                 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION,
228                 Boolean.TRUE.toString(),
229                 false /* makeDefault */);
230         final List<FaceSensorPropertiesInternal> props = List.of(
231                 new FaceSensorPropertiesInternal(
232                         1 /* sensorId */,
233                         SensorProperties.STRENGTH_CONVENIENCE,
234                         1 /* maxEnrollmentsPerUser */,
235                         List.of(new ComponentInfoInternal("sensor" /* componentId */,
236                                 "vendor/model/revision" /* hardwareVersion */,
237                                 "1.01" /* firmwareVersion */, "00000001" /* serialNumber */,
238                                 "" /* softwareVersion */)),
239                         FaceSensorProperties.TYPE_RGB,
240                         true /* supportsFaceDetection */,
241                         true /* supportsSelfIllumination */,
242                         true /* resetLockoutRequiresHardwareAuthToken */));
243 
244         mBinaryTransparencyService.collectBiometricProperties();
245 
246         verify(mFaceManager).addAuthenticatorsRegisteredCallback(mFaceAuthenticatorsRegisteredCaptor
247                 .capture());
248         mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props);
249 
250         verify(mBiometricLogger, times(1)).logStats(
251                 eq(1) /* sensorId */,
252                 eq(FrameworkStatsLog
253                         .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FACE),
254                 eq(FrameworkStatsLog
255                         .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FACE_RGB),
256                 eq(FrameworkStatsLog
257                         .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_CONVENIENCE),
258                 eq("sensor") /* componentId */,
259                 eq("vendor/model/revision") /* hardwareVersion */,
260                 eq("1.01") /* firmwareVersion */,
261                 eq("00000001") /* serialNumber */,
262                 eq("") /* softwareVersion */
263         );
264     }
265 }
266