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.mock; 24 import static org.mockito.Mockito.never; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.times; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.when; 29 30 import android.app.job.JobScheduler; 31 import android.content.Context; 32 import android.content.pm.PackageManager; 33 import android.content.pm.PackageManagerInternal; 34 import android.hardware.biometrics.ComponentInfoInternal; 35 import android.hardware.biometrics.SensorProperties; 36 import android.hardware.face.FaceManager; 37 import android.hardware.face.FaceSensorProperties; 38 import android.hardware.face.FaceSensorPropertiesInternal; 39 import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; 40 import android.hardware.fingerprint.FingerprintManager; 41 import android.hardware.fingerprint.FingerprintSensorProperties; 42 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 43 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; 44 import android.os.Bundle; 45 import android.os.RemoteException; 46 import android.os.ResultReceiver; 47 import android.os.SystemProperties; 48 import android.provider.DeviceConfig; 49 50 import androidx.test.core.app.ApplicationProvider; 51 import androidx.test.ext.junit.runners.AndroidJUnit4; 52 53 import com.android.internal.os.IBinaryTransparencyService; 54 import com.android.internal.util.FrameworkStatsLog; 55 import com.android.server.pm.BackgroundInstallControlCallbackHelper; 56 import com.android.server.pm.BackgroundInstallControlService; 57 import com.android.server.pm.pkg.PackageStateInternal; 58 59 import org.junit.After; 60 import org.junit.Assert; 61 import org.junit.Before; 62 import org.junit.Test; 63 import org.junit.runner.RunWith; 64 import org.mockito.ArgumentCaptor; 65 import org.mockito.Captor; 66 import org.mockito.Mock; 67 import org.mockito.MockitoAnnotations; 68 69 import java.io.FileDescriptor; 70 import java.util.List; 71 72 @RunWith(AndroidJUnit4.class) 73 public class BinaryTransparencyServiceTest { 74 private static final String TAG = "BinaryTransparencyServiceTest"; 75 76 private static final String TEST_PKG_NAME = "testPackageName"; 77 private static final long TEST_VERSION_CODE = 1L; 78 79 private Context mContext; 80 private BinaryTransparencyService mBinaryTransparencyService; 81 private BinaryTransparencyService.BinaryTransparencyServiceImpl mTestInterface; 82 private String mOriginalBiometricsFlag; 83 84 @Mock 85 private BinaryTransparencyService.BiometricLogger mBiometricLogger; 86 @Mock 87 private FingerprintManager mFpManager; 88 @Mock 89 private FaceManager mFaceManager; 90 @Mock 91 private PackageManager mPackageManager; 92 @Mock 93 private PackageManagerInternal mPackageManagerInternal; 94 @Mock 95 private BinaryTransparencyService.BicCallbackHandler.IBicAppInfoHelper mBicAppInfoHelper; 96 97 @Captor 98 private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> 99 mFpAuthenticatorsRegisteredCaptor; 100 @Captor 101 private ArgumentCaptor<IFaceAuthenticatorsRegisteredCallback> 102 mFaceAuthenticatorsRegisteredCaptor; 103 104 @Captor 105 private ArgumentCaptor<IBinaryTransparencyService.AppInfo> appInfoCaptor; 106 107 @Before setUp()108 public void setUp() { 109 MockitoAnnotations.initMocks(this); 110 111 mContext = spy(ApplicationProvider.getApplicationContext()); 112 LocalServices.removeServiceForTest(PackageManagerInternal.class); 113 LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); 114 115 mBinaryTransparencyService = new BinaryTransparencyService(mContext, mBiometricLogger); 116 mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl(); 117 mOriginalBiometricsFlag = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_BIOMETRICS, 118 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION); 119 } 120 121 @After tearDown()122 public void tearDown() { 123 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS, 124 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION, 125 mOriginalBiometricsFlag, false /* makeDefault */); 126 LocalServices.removeServiceForTest(PackageManagerInternal.class); 127 } 128 prepSignedInfo()129 private void prepSignedInfo() { 130 // simulate what happens on boot completed phase 131 // but we avoid calling JobScheduler.schedule by returning a null. 132 doReturn(null).when(mContext).getSystemService(JobScheduler.class); 133 mBinaryTransparencyService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED); 134 } 135 prepApexInfo()136 private void prepApexInfo() throws RemoteException { 137 // simulates what happens to apex info after computations are done. 138 String[] args = {"get", "apex_info"}; 139 mTestInterface.onShellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, 140 args, null, new ResultReceiver(null)); 141 } 142 prepBiometricsTesting()143 private void prepBiometricsTesting() { 144 when(mContext.getPackageManager()).thenReturn(mPackageManager); 145 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)).thenReturn(true); 146 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); 147 when(mContext.getSystemService(FingerprintManager.class)).thenReturn(mFpManager); 148 when(mContext.getSystemService(FaceManager.class)).thenReturn(mFaceManager); 149 } 150 151 @Test getSignedImageInfo_preInitialize_returnsUninitializedString()152 public void getSignedImageInfo_preInitialize_returnsUninitializedString() { 153 String result = mTestInterface.getSignedImageInfo(); 154 Assert.assertNotNull("VBMeta digest value should not be null", result); 155 Assert.assertEquals(BinaryTransparencyService.VBMETA_DIGEST_UNINITIALIZED, result); 156 } 157 158 @Test getSignedImageInfo_postInitialize_returnsNonErrorStrings()159 public void getSignedImageInfo_postInitialize_returnsNonErrorStrings() { 160 prepSignedInfo(); 161 String result = mTestInterface.getSignedImageInfo(); 162 Assert.assertNotNull("Initialized VBMeta digest string should not be null", result); 163 Assert.assertNotEquals("VBMeta digest value is uninitialized", 164 BinaryTransparencyService.VBMETA_DIGEST_UNINITIALIZED, result); 165 Assert.assertNotEquals("VBMeta value should not be unavailable", 166 BinaryTransparencyService.VBMETA_DIGEST_UNAVAILABLE, result); 167 } 168 169 @Test getSignedImageInfo_postInitialize_returnsCorrectValue()170 public void getSignedImageInfo_postInitialize_returnsCorrectValue() { 171 prepSignedInfo(); 172 String result = mTestInterface.getSignedImageInfo(); 173 Assert.assertEquals( 174 SystemProperties.get(BinaryTransparencyService.SYSPROP_NAME_VBETA_DIGEST, 175 BinaryTransparencyService.VBMETA_DIGEST_UNAVAILABLE), result); 176 } 177 178 @Test testCollectBiometricProperties_disablesFeature()179 public void testCollectBiometricProperties_disablesFeature() { 180 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS, 181 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION, 182 Boolean.FALSE.toString(), 183 false /* makeDefault */); 184 185 mBinaryTransparencyService.collectBiometricProperties(); 186 187 verify(mBiometricLogger, never()).logStats(anyInt(), anyInt(), anyInt(), anyInt(), 188 anyString(), anyString(), anyString(), anyString(), anyString()); 189 } 190 191 @Test testCollectBiometricProperties_enablesFeature_logsFingerprintProperties()192 public void testCollectBiometricProperties_enablesFeature_logsFingerprintProperties() 193 throws RemoteException { 194 prepBiometricsTesting(); 195 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS, 196 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION, 197 Boolean.TRUE.toString(), 198 false /* makeDefault */); 199 final List<FingerprintSensorPropertiesInternal> props = List.of( 200 new FingerprintSensorPropertiesInternal( 201 1 /* sensorId */, 202 SensorProperties.STRENGTH_STRONG, 203 5 /* maxEnrollmentsPerUser */, 204 List.of(new ComponentInfoInternal("sensor" /* componentId */, 205 "vendor/model/revision" /* hardwareVersion */, 206 "1.01" /* firmwareVersion */, "00000001" /* serialNumber */, 207 "" /* softwareVersion */)), 208 FingerprintSensorProperties.TYPE_REAR, 209 true /* resetLockoutRequiresHardwareAuthToken */)); 210 211 mBinaryTransparencyService.collectBiometricProperties(); 212 213 verify(mFpManager).addAuthenticatorsRegisteredCallback(mFpAuthenticatorsRegisteredCaptor 214 .capture()); 215 mFpAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props); 216 217 verify(mBiometricLogger, times(1)).logStats( 218 eq(1) /* sensorId */, 219 eq(FrameworkStatsLog 220 .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FINGERPRINT), 221 eq(FrameworkStatsLog 222 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FP_REAR), 223 eq(FrameworkStatsLog 224 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_STRONG), 225 eq("sensor") /* componentId */, 226 eq("vendor/model/revision") /* hardwareVersion */, 227 eq("1.01") /* firmwareVersion */, 228 eq("00000001") /* serialNumber */, 229 eq("") /* softwareVersion */ 230 ); 231 } 232 233 @Test testCollectBiometricProperties_enablesFeature_logsFaceProperties()234 public void testCollectBiometricProperties_enablesFeature_logsFaceProperties() 235 throws RemoteException { 236 prepBiometricsTesting(); 237 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_BIOMETRICS, 238 BinaryTransparencyService.KEY_ENABLE_BIOMETRIC_PROPERTY_VERIFICATION, 239 Boolean.TRUE.toString(), 240 false /* makeDefault */); 241 final List<FaceSensorPropertiesInternal> props = List.of( 242 new FaceSensorPropertiesInternal( 243 1 /* sensorId */, 244 SensorProperties.STRENGTH_CONVENIENCE, 245 1 /* maxEnrollmentsPerUser */, 246 List.of(new ComponentInfoInternal("sensor" /* componentId */, 247 "vendor/model/revision" /* hardwareVersion */, 248 "1.01" /* firmwareVersion */, "00000001" /* serialNumber */, 249 "" /* softwareVersion */)), 250 FaceSensorProperties.TYPE_RGB, 251 true /* supportsFaceDetection */, 252 true /* supportsSelfIllumination */, 253 true /* resetLockoutRequiresHardwareAuthToken */)); 254 255 mBinaryTransparencyService.collectBiometricProperties(); 256 257 verify(mFaceManager).addAuthenticatorsRegisteredCallback(mFaceAuthenticatorsRegisteredCaptor 258 .capture()); 259 mFaceAuthenticatorsRegisteredCaptor.getValue().onAllAuthenticatorsRegistered(props); 260 261 verify(mBiometricLogger, times(1)).logStats( 262 eq(1) /* sensorId */, 263 eq(FrameworkStatsLog 264 .BIOMETRIC_PROPERTIES_COLLECTED__MODALITY__MODALITY_FACE), 265 eq(FrameworkStatsLog 266 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_TYPE__SENSOR_FACE_RGB), 267 eq(FrameworkStatsLog 268 .BIOMETRIC_PROPERTIES_COLLECTED__SENSOR_STRENGTH__STRENGTH_CONVENIENCE), 269 eq("sensor") /* componentId */, 270 eq("vendor/model/revision") /* hardwareVersion */, 271 eq("1.01") /* firmwareVersion */, 272 eq("00000001") /* serialNumber */, 273 eq("") /* softwareVersion */ 274 ); 275 } 276 277 @Test BicCallbackHandler_uploads_mba_metrics()278 public void BicCallbackHandler_uploads_mba_metrics() { 279 Bundle data = setupBicCallbackHandlerTest(false, 280 BinaryTransparencyService.MBA_STATUS_NEW_INSTALL); 281 282 BinaryTransparencyService.BicCallbackHandler handler = 283 new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper); 284 handler.sendResult(data); 285 286 verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture()); 287 Assert.assertEquals(TEST_PKG_NAME, appInfoCaptor.getValue().packageName); 288 Assert.assertEquals(TEST_VERSION_CODE, appInfoCaptor.getValue().longVersion); 289 } 290 291 @Test BicCallbackHandler_uploads_mba_metrics_for_preloads()292 public void BicCallbackHandler_uploads_mba_metrics_for_preloads() { 293 Bundle data = setupBicCallbackHandlerTest(true, 294 BinaryTransparencyService.MBA_STATUS_UPDATED_PRELOAD); 295 296 BinaryTransparencyService.BicCallbackHandler handler = 297 new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper); 298 handler.sendResult(data); 299 300 verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture()); 301 Assert.assertEquals(TEST_PKG_NAME, appInfoCaptor.getValue().packageName); 302 Assert.assertEquals(TEST_VERSION_CODE, appInfoCaptor.getValue().longVersion); 303 } 304 305 @Test BicCallbackHandler_uploads_mba_metrics_for_uninstalls()306 public void BicCallbackHandler_uploads_mba_metrics_for_uninstalls() { 307 Bundle data = new Bundle(); 308 data.putString(BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY, 309 TEST_PKG_NAME); 310 data.putInt(BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY, 311 BackgroundInstallControlService.INSTALL_EVENT_TYPE_UNINSTALL); 312 313 BinaryTransparencyService.BicCallbackHandler handler = 314 new BinaryTransparencyService.BicCallbackHandler(mBicAppInfoHelper); 315 handler.sendResult(data); 316 317 verify(mBicAppInfoHelper, times(1)).writeAppInfoToLog(appInfoCaptor.capture()); 318 Assert.assertEquals(TEST_PKG_NAME ,appInfoCaptor.getValue().packageName); 319 Assert.assertEquals(BinaryTransparencyService.MBA_STATUS_UNINSTALLED, 320 appInfoCaptor.getValue().mbaStatus); 321 } 322 setupBicCallbackHandlerTest(boolean isUpdatedSystemApp, int expectedBtsMbaStatus)323 private Bundle setupBicCallbackHandlerTest(boolean isUpdatedSystemApp, 324 int expectedBtsMbaStatus) { 325 Bundle data = new Bundle(); 326 data.putString(BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY, 327 TEST_PKG_NAME); 328 data.putInt(BackgroundInstallControlCallbackHelper.INSTALL_EVENT_TYPE_KEY, 329 BackgroundInstallControlService.INSTALL_EVENT_TYPE_INSTALL); 330 PackageStateInternal mockPackageState = mock(PackageStateInternal.class); 331 when(mPackageManagerInternal.getPackageStateInternal(TEST_PKG_NAME)) 332 .thenReturn(mockPackageState); 333 when(mockPackageState.isUpdatedSystemApp()).thenReturn(isUpdatedSystemApp); 334 IBinaryTransparencyService.AppInfo appInfo = new IBinaryTransparencyService.AppInfo(); 335 appInfo.packageName = TEST_PKG_NAME; 336 appInfo.longVersion = TEST_VERSION_CODE; 337 when(mBicAppInfoHelper.collectAppInfo(mockPackageState, expectedBtsMbaStatus)) 338 .thenReturn(List.of(appInfo)); 339 return data; 340 } 341 } 342