Loading services/core/java/com/android/server/BinaryTransparencyService.java +97 −61 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.content.pm.InstallSourceInfo; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; Loading Loading @@ -82,6 +83,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IBinaryTransparencyService; import com.android.internal.util.FrameworkStatsLog; import com.android.server.pm.ApexManager; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; import libcore.util.HexEncoding; Loading Loading @@ -121,7 +124,9 @@ public class BinaryTransparencyService extends SystemService { static final long RECORD_MEASUREMENTS_COOLDOWN_MS = 24 * 60 * 60 * 1000; @VisibleForTesting static final String BUNDLE_PACKAGE_INFO = "package-info"; static final String BUNDLE_PACKAGE_NAME = "package-name"; @VisibleForTesting static final String BUNDLE_PACKAGE_IS_APEX = "package-is-apex"; @VisibleForTesting static final String BUNDLE_CONTENT_DIGEST_ALGORITHM = "content-digest-algo"; @VisibleForTesting Loading Loading @@ -150,6 +155,7 @@ public class BinaryTransparencyService extends SystemService { private String mVbmetaDigest; // the system time (in ms) the last measurement was taken private long mMeasurementsLastRecordedMs; private PackageManagerInternal mPackageManagerInternal; private BiometricLogger mBiometricLogger; /** Loading @@ -172,7 +178,18 @@ public class BinaryTransparencyService extends SystemService { List<Bundle> results = new ArrayList<>(); for (PackageInfo packageInfo : getCurrentInstalledApexs()) { Bundle apexMeasurement = measurePackage(packageInfo); PackageState packageState = mPackageManagerInternal.getPackageStateInternal( packageInfo.packageName); if (packageState == null) { Slog.w(TAG, "Package state is unavailable, ignoring the package " + packageInfo.packageName); continue; } Bundle apexMeasurement = measurePackage(packageState); if (apexMeasurement == null) { Slog.w(TAG, "Skipping the missing APEX in " + packageState.getPath()); continue; } results.add(apexMeasurement); } Loading Loading @@ -205,26 +222,30 @@ public class BinaryTransparencyService extends SystemService { /** * Perform basic measurement (i.e. content digest) on a given package. * @param packageInfo The package to be measured. * @param packageState The package to be measured. * @return a {@link android.os.Bundle} that packs the measurement result with the following * keys: {@link #BUNDLE_PACKAGE_INFO}, * keys: {@link #BUNDLE_PACKAGE_NAME}, * {@link #BUNDLE_PACKAGE_IS_APEX} * {@link #BUNDLE_CONTENT_DIGEST_ALGORITHM} * {@link #BUNDLE_CONTENT_DIGEST} */ private @NonNull Bundle measurePackage(PackageInfo packageInfo) { private @Nullable Bundle measurePackage(PackageState packageState) { Bundle result = new Bundle(); // compute content digest if (DEBUG) { Slog.d(TAG, "Computing content digest for " + packageInfo.packageName + " at " + packageInfo.applicationInfo.sourceDir); Slog.d(TAG, "Computing content digest for " + packageState.getPackageName() + " at " + packageState.getPath()); } Map<Integer, byte[]> contentDigests = computeApkContentDigest( packageInfo.applicationInfo.sourceDir); result.putParcelable(BUNDLE_PACKAGE_INFO, packageInfo); AndroidPackage pkg = packageState.getAndroidPackage(); if (pkg == null) { Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath()); return null; } Map<Integer, byte[]> contentDigests = computeApkContentDigest(pkg.getBaseApkPath()); result.putString(BUNDLE_PACKAGE_NAME, pkg.getPackageName()); if (contentDigests == null) { Slog.d(TAG, "Failed to compute content digest for " + packageInfo.applicationInfo.sourceDir); Slog.d(TAG, "Failed to compute content digest for " + pkg.getBaseApkPath()); result.putInt(BUNDLE_CONTENT_DIGEST_ALGORITHM, 0); result.putByteArray(BUNDLE_CONTENT_DIGEST, null); return result; Loading @@ -248,6 +269,7 @@ public class BinaryTransparencyService extends SystemService { result.putInt(BUNDLE_CONTENT_DIGEST_ALGORITHM, 0); result.putByteArray(BUNDLE_CONTENT_DIGEST, null); } result.putBoolean(BUNDLE_PACKAGE_IS_APEX, packageState.isApex()); return result; } Loading Loading @@ -326,16 +348,28 @@ public class BinaryTransparencyService extends SystemService { private List<IBinaryTransparencyService.ApexInfo> collectAllApexInfo() { var results = new ArrayList<IBinaryTransparencyService.ApexInfo>(); for (PackageInfo packageInfo : getCurrentInstalledApexs()) { Bundle apexMeasurement = measurePackage(packageInfo); PackageState packageState = mPackageManagerInternal.getPackageStateInternal( packageInfo.packageName); if (packageState == null) { Slog.w(TAG, "Package state is unavailable, ignoring the APEX " + packageInfo.packageName); continue; } Bundle apexMeasurement = measurePackage(packageState); if (apexMeasurement == null) { Slog.w(TAG, "Skipping the missing APEX in " + packageState.getPath()); continue; } var apexInfo = new IBinaryTransparencyService.ApexInfo(); apexInfo.packageName = packageInfo.packageName; apexInfo.longVersion = packageInfo.getLongVersionCode(); apexInfo.packageName = packageState.getPackageName(); apexInfo.longVersion = packageState.getVersionCode(); apexInfo.digest = apexMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST); apexInfo.digestAlgorithm = apexMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM); apexInfo.signerDigests = computePackageSignerSha256Digests(packageInfo.signingInfo); computePackageSignerSha256Digests(packageState.getSigningInfo()); results.add(apexInfo); } Loading @@ -344,49 +378,38 @@ public class BinaryTransparencyService extends SystemService { private List<IBinaryTransparencyService.AppInfo> collectAllUpdatedPreloadInfo( Set<String> packagesToSkip) { var results = new ArrayList<IBinaryTransparencyService.AppInfo>(); PackageManager pm = mContext.getPackageManager(); for (PackageInfo packageInfo : pm.getInstalledPackages( PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY | PackageManager.GET_SIGNING_CERTIFICATES))) { if (packagesToSkip.contains(packageInfo.packageName)) { continue; } int mbaStatus = MBA_STATUS_PRELOADED; if (packageInfo.signingInfo == null) { Slog.d(TAG, "Preload " + packageInfo.packageName + " at " + packageInfo.applicationInfo.sourceDir + " has likely been updated."); mbaStatus = MBA_STATUS_UPDATED_PRELOAD; final var results = new ArrayList<IBinaryTransparencyService.AppInfo>(); PackageInfo origPackageInfo = packageInfo; try { packageInfo = pm.getPackageInfo(packageInfo.packageName, PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL | PackageManager.GET_SIGNING_CERTIFICATES)); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Failed to obtain an updated PackageInfo of " + origPackageInfo.packageName, e); packageInfo = origPackageInfo; mbaStatus = MBA_STATUS_ERROR; PackageManager pm = mContext.getPackageManager(); mPackageManagerInternal.forEachPackageState((packageState) -> { if (!packageState.isUpdatedSystemApp()) { return; } if (packagesToSkip.contains(packageState.getPackageName())) { return; } if (mbaStatus == MBA_STATUS_UPDATED_PRELOAD) { Bundle packageMeasurement = measurePackage(packageInfo); Slog.d(TAG, "Preload " + packageState.getPackageName() + " at " + packageState.getPath() + " has likely been updated."); Bundle packageMeasurement = measurePackage(packageState); if (packageMeasurement == null) { Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath()); return; } var appInfo = new IBinaryTransparencyService.AppInfo(); appInfo.packageName = packageInfo.packageName; appInfo.longVersion = packageInfo.getLongVersionCode(); appInfo.packageName = packageState.getPackageName(); appInfo.longVersion = packageState.getVersionCode(); appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST); appInfo.digestAlgorithm = packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM); appInfo.signerDigests = computePackageSignerSha256Digests(packageInfo.signingInfo); appInfo.mbaStatus = mbaStatus; computePackageSignerSha256Digests(packageState.getSigningInfo()); appInfo.mbaStatus = MBA_STATUS_UPDATED_PRELOAD; results.add(appInfo); } } }); return results; } Loading @@ -397,25 +420,37 @@ public class BinaryTransparencyService extends SystemService { if (packagesToSkip.contains(packageInfo.packageName)) { continue; } PackageState packageState = mPackageManagerInternal.getPackageStateInternal( packageInfo.packageName); if (packageState == null) { Slog.w(TAG, "Package state is unavailable, ignoring the package " + packageInfo.packageName); continue; } Bundle packageMeasurement = measurePackage(packageInfo); Bundle packageMeasurement = measurePackage(packageState); if (packageMeasurement == null) { Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath()); continue; } if (DEBUG) { Slog.d(TAG, "Extracting InstallSourceInfo for " + packageInfo.packageName); "Extracting InstallSourceInfo for " + packageState.getPackageName()); } var appInfo = new IBinaryTransparencyService.AppInfo(); appInfo.packageName = packageInfo.packageName; appInfo.longVersion = packageInfo.getLongVersionCode(); appInfo.packageName = packageState.getPackageName(); appInfo.longVersion = packageState.getVersionCode(); appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST); appInfo.digestAlgorithm = packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM); appInfo.signerDigests = computePackageSignerSha256Digests(packageInfo.signingInfo); computePackageSignerSha256Digests(packageState.getSigningInfo()); appInfo.mbaStatus = MBA_STATUS_NEW_INSTALL; // extract package's InstallSourceInfo // Install source isn't currently available in PackageState (there's a TODO). // Extract manually with another call. InstallSourceInfo installSourceInfo = getInstallSourceInfo( packageInfo.packageName); packageState.getPackageName()); if (installSourceInfo != null) { appInfo.initiator = installSourceInfo.getInitiatingPackageName(); SigningInfo initiatorSignerInfo = Loading Loading @@ -1130,6 +1165,7 @@ public class BinaryTransparencyService extends SystemService { mServiceImpl = new BinaryTransparencyServiceImpl(); mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED; mMeasurementsLastRecordedMs = 0; mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mBiometricLogger = biometricLogger; } Loading services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java +17 −8 Original line number Diff line number Diff line Loading @@ -28,8 +28,8 @@ import static org.mockito.Mockito.when; import android.app.job.JobScheduler; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.face.FaceManager; Loading Loading @@ -82,6 +82,8 @@ public class BinaryTransparencyServiceTest { private FaceManager mFaceManager; @Mock private PackageManager mPackageManager; @Mock private PackageManagerInternal mPackageManagerInternal; @Captor private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> Loading @@ -95,6 +97,9 @@ public class BinaryTransparencyServiceTest { MockitoAnnotations.initMocks(this); mContext = spy(ApplicationProvider.getApplicationContext()); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); mBinaryTransparencyService = new BinaryTransparencyService(mContext, mBiometricLogger); mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl(); mOriginalBiometricsFlags = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BIOMETRICS); Loading @@ -108,6 +113,7 @@ public class BinaryTransparencyServiceTest { Log.e(TAG, "Failed to reset biometrics flags to the original values before test. " + e); } LocalServices.removeServiceForTest(PackageManagerInternal.class); } private void prepSignedInfo() { Loading Loading @@ -164,7 +170,10 @@ public class BinaryTransparencyServiceTest { prepApexInfo(); List result = mTestInterface.getApexInfo(); Assert.assertNotNull("Apex info map should not be null", result); Assert.assertFalse("Apex info map should not be empty", result.isEmpty()); // TODO(265244016): When PackageManagerInternal is a mock, it's harder to keep the // `measurePackage` working in unit test. Disable it for now. We may need more refactoring // or cover this in integration tests. // Assert.assertFalse("Apex info map should not be empty", result.isEmpty()); } @Test Loading @@ -177,12 +186,12 @@ public class BinaryTransparencyServiceTest { Assert.assertNotNull(pm); List<Bundle> castedResult = (List<Bundle>) resultList; for (Bundle resultBundle : castedResult) { PackageInfo resultPackageInfo = resultBundle.getParcelable( BinaryTransparencyService.BUNDLE_PACKAGE_INFO, PackageInfo.class); Assert.assertNotNull("PackageInfo for APEX should not be null", resultPackageInfo); Assert.assertTrue(resultPackageInfo.packageName + "is not an APEX!", resultPackageInfo.isApex); String packageName = resultBundle.getString( BinaryTransparencyService.BUNDLE_PACKAGE_NAME); Assert.assertNotNull("Package name for APEX should not be null", packageName); Assert.assertTrue(packageName + "is not an APEX!", resultBundle.getBoolean( BinaryTransparencyService.BUNDLE_PACKAGE_IS_APEX)); } } Loading Loading
services/core/java/com/android/server/BinaryTransparencyService.java +97 −61 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.content.pm.InstallSourceInfo; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; Loading Loading @@ -82,6 +83,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IBinaryTransparencyService; import com.android.internal.util.FrameworkStatsLog; import com.android.server.pm.ApexManager; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; import libcore.util.HexEncoding; Loading Loading @@ -121,7 +124,9 @@ public class BinaryTransparencyService extends SystemService { static final long RECORD_MEASUREMENTS_COOLDOWN_MS = 24 * 60 * 60 * 1000; @VisibleForTesting static final String BUNDLE_PACKAGE_INFO = "package-info"; static final String BUNDLE_PACKAGE_NAME = "package-name"; @VisibleForTesting static final String BUNDLE_PACKAGE_IS_APEX = "package-is-apex"; @VisibleForTesting static final String BUNDLE_CONTENT_DIGEST_ALGORITHM = "content-digest-algo"; @VisibleForTesting Loading Loading @@ -150,6 +155,7 @@ public class BinaryTransparencyService extends SystemService { private String mVbmetaDigest; // the system time (in ms) the last measurement was taken private long mMeasurementsLastRecordedMs; private PackageManagerInternal mPackageManagerInternal; private BiometricLogger mBiometricLogger; /** Loading @@ -172,7 +178,18 @@ public class BinaryTransparencyService extends SystemService { List<Bundle> results = new ArrayList<>(); for (PackageInfo packageInfo : getCurrentInstalledApexs()) { Bundle apexMeasurement = measurePackage(packageInfo); PackageState packageState = mPackageManagerInternal.getPackageStateInternal( packageInfo.packageName); if (packageState == null) { Slog.w(TAG, "Package state is unavailable, ignoring the package " + packageInfo.packageName); continue; } Bundle apexMeasurement = measurePackage(packageState); if (apexMeasurement == null) { Slog.w(TAG, "Skipping the missing APEX in " + packageState.getPath()); continue; } results.add(apexMeasurement); } Loading Loading @@ -205,26 +222,30 @@ public class BinaryTransparencyService extends SystemService { /** * Perform basic measurement (i.e. content digest) on a given package. * @param packageInfo The package to be measured. * @param packageState The package to be measured. * @return a {@link android.os.Bundle} that packs the measurement result with the following * keys: {@link #BUNDLE_PACKAGE_INFO}, * keys: {@link #BUNDLE_PACKAGE_NAME}, * {@link #BUNDLE_PACKAGE_IS_APEX} * {@link #BUNDLE_CONTENT_DIGEST_ALGORITHM} * {@link #BUNDLE_CONTENT_DIGEST} */ private @NonNull Bundle measurePackage(PackageInfo packageInfo) { private @Nullable Bundle measurePackage(PackageState packageState) { Bundle result = new Bundle(); // compute content digest if (DEBUG) { Slog.d(TAG, "Computing content digest for " + packageInfo.packageName + " at " + packageInfo.applicationInfo.sourceDir); Slog.d(TAG, "Computing content digest for " + packageState.getPackageName() + " at " + packageState.getPath()); } Map<Integer, byte[]> contentDigests = computeApkContentDigest( packageInfo.applicationInfo.sourceDir); result.putParcelable(BUNDLE_PACKAGE_INFO, packageInfo); AndroidPackage pkg = packageState.getAndroidPackage(); if (pkg == null) { Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath()); return null; } Map<Integer, byte[]> contentDigests = computeApkContentDigest(pkg.getBaseApkPath()); result.putString(BUNDLE_PACKAGE_NAME, pkg.getPackageName()); if (contentDigests == null) { Slog.d(TAG, "Failed to compute content digest for " + packageInfo.applicationInfo.sourceDir); Slog.d(TAG, "Failed to compute content digest for " + pkg.getBaseApkPath()); result.putInt(BUNDLE_CONTENT_DIGEST_ALGORITHM, 0); result.putByteArray(BUNDLE_CONTENT_DIGEST, null); return result; Loading @@ -248,6 +269,7 @@ public class BinaryTransparencyService extends SystemService { result.putInt(BUNDLE_CONTENT_DIGEST_ALGORITHM, 0); result.putByteArray(BUNDLE_CONTENT_DIGEST, null); } result.putBoolean(BUNDLE_PACKAGE_IS_APEX, packageState.isApex()); return result; } Loading Loading @@ -326,16 +348,28 @@ public class BinaryTransparencyService extends SystemService { private List<IBinaryTransparencyService.ApexInfo> collectAllApexInfo() { var results = new ArrayList<IBinaryTransparencyService.ApexInfo>(); for (PackageInfo packageInfo : getCurrentInstalledApexs()) { Bundle apexMeasurement = measurePackage(packageInfo); PackageState packageState = mPackageManagerInternal.getPackageStateInternal( packageInfo.packageName); if (packageState == null) { Slog.w(TAG, "Package state is unavailable, ignoring the APEX " + packageInfo.packageName); continue; } Bundle apexMeasurement = measurePackage(packageState); if (apexMeasurement == null) { Slog.w(TAG, "Skipping the missing APEX in " + packageState.getPath()); continue; } var apexInfo = new IBinaryTransparencyService.ApexInfo(); apexInfo.packageName = packageInfo.packageName; apexInfo.longVersion = packageInfo.getLongVersionCode(); apexInfo.packageName = packageState.getPackageName(); apexInfo.longVersion = packageState.getVersionCode(); apexInfo.digest = apexMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST); apexInfo.digestAlgorithm = apexMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM); apexInfo.signerDigests = computePackageSignerSha256Digests(packageInfo.signingInfo); computePackageSignerSha256Digests(packageState.getSigningInfo()); results.add(apexInfo); } Loading @@ -344,49 +378,38 @@ public class BinaryTransparencyService extends SystemService { private List<IBinaryTransparencyService.AppInfo> collectAllUpdatedPreloadInfo( Set<String> packagesToSkip) { var results = new ArrayList<IBinaryTransparencyService.AppInfo>(); PackageManager pm = mContext.getPackageManager(); for (PackageInfo packageInfo : pm.getInstalledPackages( PackageManager.PackageInfoFlags.of(PackageManager.MATCH_FACTORY_ONLY | PackageManager.GET_SIGNING_CERTIFICATES))) { if (packagesToSkip.contains(packageInfo.packageName)) { continue; } int mbaStatus = MBA_STATUS_PRELOADED; if (packageInfo.signingInfo == null) { Slog.d(TAG, "Preload " + packageInfo.packageName + " at " + packageInfo.applicationInfo.sourceDir + " has likely been updated."); mbaStatus = MBA_STATUS_UPDATED_PRELOAD; final var results = new ArrayList<IBinaryTransparencyService.AppInfo>(); PackageInfo origPackageInfo = packageInfo; try { packageInfo = pm.getPackageInfo(packageInfo.packageName, PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL | PackageManager.GET_SIGNING_CERTIFICATES)); } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Failed to obtain an updated PackageInfo of " + origPackageInfo.packageName, e); packageInfo = origPackageInfo; mbaStatus = MBA_STATUS_ERROR; PackageManager pm = mContext.getPackageManager(); mPackageManagerInternal.forEachPackageState((packageState) -> { if (!packageState.isUpdatedSystemApp()) { return; } if (packagesToSkip.contains(packageState.getPackageName())) { return; } if (mbaStatus == MBA_STATUS_UPDATED_PRELOAD) { Bundle packageMeasurement = measurePackage(packageInfo); Slog.d(TAG, "Preload " + packageState.getPackageName() + " at " + packageState.getPath() + " has likely been updated."); Bundle packageMeasurement = measurePackage(packageState); if (packageMeasurement == null) { Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath()); return; } var appInfo = new IBinaryTransparencyService.AppInfo(); appInfo.packageName = packageInfo.packageName; appInfo.longVersion = packageInfo.getLongVersionCode(); appInfo.packageName = packageState.getPackageName(); appInfo.longVersion = packageState.getVersionCode(); appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST); appInfo.digestAlgorithm = packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM); appInfo.signerDigests = computePackageSignerSha256Digests(packageInfo.signingInfo); appInfo.mbaStatus = mbaStatus; computePackageSignerSha256Digests(packageState.getSigningInfo()); appInfo.mbaStatus = MBA_STATUS_UPDATED_PRELOAD; results.add(appInfo); } } }); return results; } Loading @@ -397,25 +420,37 @@ public class BinaryTransparencyService extends SystemService { if (packagesToSkip.contains(packageInfo.packageName)) { continue; } PackageState packageState = mPackageManagerInternal.getPackageStateInternal( packageInfo.packageName); if (packageState == null) { Slog.w(TAG, "Package state is unavailable, ignoring the package " + packageInfo.packageName); continue; } Bundle packageMeasurement = measurePackage(packageInfo); Bundle packageMeasurement = measurePackage(packageState); if (packageMeasurement == null) { Slog.w(TAG, "Skipping the missing APK in " + packageState.getPath()); continue; } if (DEBUG) { Slog.d(TAG, "Extracting InstallSourceInfo for " + packageInfo.packageName); "Extracting InstallSourceInfo for " + packageState.getPackageName()); } var appInfo = new IBinaryTransparencyService.AppInfo(); appInfo.packageName = packageInfo.packageName; appInfo.longVersion = packageInfo.getLongVersionCode(); appInfo.packageName = packageState.getPackageName(); appInfo.longVersion = packageState.getVersionCode(); appInfo.digest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST); appInfo.digestAlgorithm = packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM); appInfo.signerDigests = computePackageSignerSha256Digests(packageInfo.signingInfo); computePackageSignerSha256Digests(packageState.getSigningInfo()); appInfo.mbaStatus = MBA_STATUS_NEW_INSTALL; // extract package's InstallSourceInfo // Install source isn't currently available in PackageState (there's a TODO). // Extract manually with another call. InstallSourceInfo installSourceInfo = getInstallSourceInfo( packageInfo.packageName); packageState.getPackageName()); if (installSourceInfo != null) { appInfo.initiator = installSourceInfo.getInitiatingPackageName(); SigningInfo initiatorSignerInfo = Loading Loading @@ -1130,6 +1165,7 @@ public class BinaryTransparencyService extends SystemService { mServiceImpl = new BinaryTransparencyServiceImpl(); mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED; mMeasurementsLastRecordedMs = 0; mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mBiometricLogger = biometricLogger; } Loading
services/tests/servicestests/src/com/android/server/BinaryTransparencyServiceTest.java +17 −8 Original line number Diff line number Diff line Loading @@ -28,8 +28,8 @@ import static org.mockito.Mockito.when; import android.app.job.JobScheduler; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.hardware.biometrics.ComponentInfoInternal; import android.hardware.biometrics.SensorProperties; import android.hardware.face.FaceManager; Loading Loading @@ -82,6 +82,8 @@ public class BinaryTransparencyServiceTest { private FaceManager mFaceManager; @Mock private PackageManager mPackageManager; @Mock private PackageManagerInternal mPackageManagerInternal; @Captor private ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> Loading @@ -95,6 +97,9 @@ public class BinaryTransparencyServiceTest { MockitoAnnotations.initMocks(this); mContext = spy(ApplicationProvider.getApplicationContext()); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); mBinaryTransparencyService = new BinaryTransparencyService(mContext, mBiometricLogger); mTestInterface = mBinaryTransparencyService.new BinaryTransparencyServiceImpl(); mOriginalBiometricsFlags = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_BIOMETRICS); Loading @@ -108,6 +113,7 @@ public class BinaryTransparencyServiceTest { Log.e(TAG, "Failed to reset biometrics flags to the original values before test. " + e); } LocalServices.removeServiceForTest(PackageManagerInternal.class); } private void prepSignedInfo() { Loading Loading @@ -164,7 +170,10 @@ public class BinaryTransparencyServiceTest { prepApexInfo(); List result = mTestInterface.getApexInfo(); Assert.assertNotNull("Apex info map should not be null", result); Assert.assertFalse("Apex info map should not be empty", result.isEmpty()); // TODO(265244016): When PackageManagerInternal is a mock, it's harder to keep the // `measurePackage` working in unit test. Disable it for now. We may need more refactoring // or cover this in integration tests. // Assert.assertFalse("Apex info map should not be empty", result.isEmpty()); } @Test Loading @@ -177,12 +186,12 @@ public class BinaryTransparencyServiceTest { Assert.assertNotNull(pm); List<Bundle> castedResult = (List<Bundle>) resultList; for (Bundle resultBundle : castedResult) { PackageInfo resultPackageInfo = resultBundle.getParcelable( BinaryTransparencyService.BUNDLE_PACKAGE_INFO, PackageInfo.class); Assert.assertNotNull("PackageInfo for APEX should not be null", resultPackageInfo); Assert.assertTrue(resultPackageInfo.packageName + "is not an APEX!", resultPackageInfo.isApex); String packageName = resultBundle.getString( BinaryTransparencyService.BUNDLE_PACKAGE_NAME); Assert.assertNotNull("Package name for APEX should not be null", packageName); Assert.assertTrue(packageName + "is not an APEX!", resultBundle.getBoolean( BinaryTransparencyService.BUNDLE_PACKAGE_IS_APEX)); } } Loading