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