Loading services/core/java/com/android/server/BinaryTransparencyService.java +129 −25 Original line number Original line Diff line number Diff line Loading @@ -27,15 +27,20 @@ import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobScheduler; import android.app.job.JobService; import android.app.job.JobService; import android.compat.annotation.ChangeId; import android.compat.annotation.ChangeId; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApexStagedEvent; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IBackgroundInstallControlService; import android.content.pm.IBackgroundInstallControlService; import android.content.pm.IPackageManagerNative; import android.content.pm.IStagedApexObserver; import android.content.pm.InstallSourceInfo; import android.content.pm.InstallSourceInfo; import android.content.pm.ModuleInfo; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ParceledListSlice; import android.content.pm.SharedLibraryInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; import android.content.pm.Signature; Loading @@ -51,6 +56,7 @@ import android.hardware.face.FaceSensorProperties; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.net.Uri; import android.os.Binder; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.Bundle; import android.os.Bundle; Loading Loading @@ -142,7 +148,6 @@ public class BinaryTransparencyService extends SystemService { private String mVbmetaDigest; private String mVbmetaDigest; // the system time (in ms) the last measurement was taken // the system time (in ms) the last measurement was taken private long mMeasurementsLastRecordedMs; private long mMeasurementsLastRecordedMs; private PackageManagerInternal mPackageManagerInternal; private BiometricLogger mBiometricLogger; private BiometricLogger mBiometricLogger; /** /** Loading Loading @@ -1103,7 +1108,6 @@ public class BinaryTransparencyService extends SystemService { mServiceImpl = new BinaryTransparencyServiceImpl(); mServiceImpl = new BinaryTransparencyServiceImpl(); mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED; mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED; mMeasurementsLastRecordedMs = 0; mMeasurementsLastRecordedMs = 0; mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mBiometricLogger = biometricLogger; mBiometricLogger = biometricLogger; } } Loading @@ -1119,28 +1123,6 @@ public class BinaryTransparencyService extends SystemService { } catch (Throwable t) { } catch (Throwable t) { Slog.e(TAG, "Failed to start BinaryTransparencyService.", t); Slog.e(TAG, "Failed to start BinaryTransparencyService.", t); } } // register a package observer to detect updates to preloads mPackageManagerInternal.getPackageList(new PackageManagerInternal.PackageListObserver() { @Override public void onPackageChanged(String packageName, int uid) { // check if the updated package is a preloaded app. PackageManager pm = mContext.getPackageManager(); try { pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of( PackageManager.MATCH_FACTORY_ONLY)); } catch (PackageManager.NameNotFoundException e) { // this means that this package is not a preloaded app return; } Slog.d(TAG, "Preload " + packageName + " was updated. Scheduling measurement..."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); } }); // TODO(b/264428429): Register observer for updates to APEXs. } } /** /** Loading Loading @@ -1172,6 +1154,8 @@ public class BinaryTransparencyService extends SystemService { Slog.i(TAG, "Scheduling measurements to be taken."); Slog.i(TAG, "Scheduling measurements to be taken."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); BinaryTransparencyService.this); registerAllPackageUpdateObservers(); } } } } Loading Loading @@ -1415,6 +1399,126 @@ public class BinaryTransparencyService extends SystemService { FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest); FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest); } } /** * Listen for APK updates. * * There are two ways available to us to do this: * 1. Register an observer using * {@link PackageManagerInternal#getPackageList(PackageManagerInternal.PackageListObserver)}. * 2. Register broadcast receivers, listening to either {@code ACTION_PACKAGE_ADDED} or * {@code ACTION_PACKAGE_REPLACED}. * * After experimentation, we found that Option #1 does not catch updates to non-staged APEXs. * Thus, we are implementing Option #2 here. More specifically, listening to * {@link Intent#ACTION_PACKAGE_ADDED} allows us to capture all events we care about. * * We did not use {@link Intent#ACTION_PACKAGE_REPLACED} because it unfortunately does not * detect updates to non-staged APEXs. Thus, we rely on {@link Intent#EXTRA_REPLACING} to * filter out new installation from updates instead. */ private void registerApkAndNonStagedApexUpdateListener() { Slog.d(TAG, "Registering APK & Non-Staged APEX updates..."); IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addDataScheme("package"); // this is somehow necessary mContext.registerReceiver(new PackageUpdatedReceiver(), filter); } /** * Listen for staged-APEX updates. * * This method basically covers cases that are not caught by * {@link #registerApkAndNonStagedApexUpdateListener()}, namely updates to APEXs that are staged * for the subsequent reboot. */ private void registerStagedApexUpdateObserver() { Slog.d(TAG, "Registering APEX updates..."); IPackageManagerNative iPackageManagerNative = IPackageManagerNative.Stub.asInterface( ServiceManager.getService("package_native")); if (iPackageManagerNative == null) { Slog.e(TAG, "IPackageManagerNative is null"); return; } try { iPackageManagerNative.registerStagedApexObserver(new IStagedApexObserver.Stub() { @Override public void onApexStaged(ApexStagedEvent event) throws RemoteException { Slog.d(TAG, "A new APEX has been staged for update. There are currently " + event.stagedApexModuleNames.length + " APEX(s) staged for update. " + "Scheduling measurement..."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); } }); } catch (RemoteException e) { Slog.e(TAG, "Failed to register a StagedApexObserver."); } } private boolean isPackagePreloaded(String packageName) { PackageManager pm = mContext.getPackageManager(); try { pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of( PackageManager.MATCH_FACTORY_ONLY)); } catch (PackageManager.NameNotFoundException e) { return false; } return true; } private boolean isPackageAnApex(String packageName) { PackageManager pm = mContext.getPackageManager(); try { PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX)); return packageInfo.isApex; } catch (PackageManager.NameNotFoundException e) { return false; } } private class PackageUpdatedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) { return; } Uri data = intent.getData(); if (data == null) { Slog.e(TAG, "Shouldn't happen: intent data is null!"); return; } if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { Slog.d(TAG, "Not an update. Skipping..."); return; } String packageName = data.getSchemeSpecificPart(); // now we've got to check what package is this if (isPackagePreloaded(packageName) || isPackageAnApex(packageName)) { Slog.d(TAG, packageName + " was updated. Scheduling measurement..."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); } } } /** * Register observers for APK and APEX updates. The current implementation breaks this process * into 2 cases/methods because PackageManager does not offer a unified interface to register * for all package updates in a universal and comprehensive manner. * Thus, the observers will be invoked when either * i) APK or non-staged APEX update; or * ii) APEX staging happens. * This will then be used as signals to schedule measurement for the relevant binaries. */ private void registerAllPackageUpdateObservers() { registerApkAndNonStagedApexUpdateListener(); registerStagedApexUpdateObserver(); } private String translateContentDigestAlgorithmIdToString(int algorithmId) { private String translateContentDigestAlgorithmIdToString(int algorithmId) { switch (algorithmId) { switch (algorithmId) { case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256: case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256: Loading Loading
services/core/java/com/android/server/BinaryTransparencyService.java +129 −25 Original line number Original line Diff line number Diff line Loading @@ -27,15 +27,20 @@ import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobScheduler; import android.app.job.JobService; import android.app.job.JobService; import android.compat.annotation.ChangeId; import android.compat.annotation.ChangeId; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ComponentName; import android.content.Context; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApexStagedEvent; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IBackgroundInstallControlService; import android.content.pm.IBackgroundInstallControlService; import android.content.pm.IPackageManagerNative; import android.content.pm.IStagedApexObserver; import android.content.pm.InstallSourceInfo; import android.content.pm.InstallSourceInfo; import android.content.pm.ModuleInfo; import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; import android.content.pm.ParceledListSlice; import android.content.pm.SharedLibraryInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.Signature; import android.content.pm.Signature; Loading @@ -51,6 +56,7 @@ import android.hardware.face.FaceSensorProperties; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorProperties; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.net.Uri; import android.os.Binder; import android.os.Binder; import android.os.Build; import android.os.Build; import android.os.Bundle; import android.os.Bundle; Loading Loading @@ -142,7 +148,6 @@ public class BinaryTransparencyService extends SystemService { private String mVbmetaDigest; private String mVbmetaDigest; // the system time (in ms) the last measurement was taken // the system time (in ms) the last measurement was taken private long mMeasurementsLastRecordedMs; private long mMeasurementsLastRecordedMs; private PackageManagerInternal mPackageManagerInternal; private BiometricLogger mBiometricLogger; private BiometricLogger mBiometricLogger; /** /** Loading Loading @@ -1103,7 +1108,6 @@ public class BinaryTransparencyService extends SystemService { mServiceImpl = new BinaryTransparencyServiceImpl(); mServiceImpl = new BinaryTransparencyServiceImpl(); mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED; mVbmetaDigest = VBMETA_DIGEST_UNINITIALIZED; mMeasurementsLastRecordedMs = 0; mMeasurementsLastRecordedMs = 0; mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mBiometricLogger = biometricLogger; mBiometricLogger = biometricLogger; } } Loading @@ -1119,28 +1123,6 @@ public class BinaryTransparencyService extends SystemService { } catch (Throwable t) { } catch (Throwable t) { Slog.e(TAG, "Failed to start BinaryTransparencyService.", t); Slog.e(TAG, "Failed to start BinaryTransparencyService.", t); } } // register a package observer to detect updates to preloads mPackageManagerInternal.getPackageList(new PackageManagerInternal.PackageListObserver() { @Override public void onPackageChanged(String packageName, int uid) { // check if the updated package is a preloaded app. PackageManager pm = mContext.getPackageManager(); try { pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of( PackageManager.MATCH_FACTORY_ONLY)); } catch (PackageManager.NameNotFoundException e) { // this means that this package is not a preloaded app return; } Slog.d(TAG, "Preload " + packageName + " was updated. Scheduling measurement..."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); } }); // TODO(b/264428429): Register observer for updates to APEXs. } } /** /** Loading Loading @@ -1172,6 +1154,8 @@ public class BinaryTransparencyService extends SystemService { Slog.i(TAG, "Scheduling measurements to be taken."); Slog.i(TAG, "Scheduling measurements to be taken."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); BinaryTransparencyService.this); registerAllPackageUpdateObservers(); } } } } Loading Loading @@ -1415,6 +1399,126 @@ public class BinaryTransparencyService extends SystemService { FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest); FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest); } } /** * Listen for APK updates. * * There are two ways available to us to do this: * 1. Register an observer using * {@link PackageManagerInternal#getPackageList(PackageManagerInternal.PackageListObserver)}. * 2. Register broadcast receivers, listening to either {@code ACTION_PACKAGE_ADDED} or * {@code ACTION_PACKAGE_REPLACED}. * * After experimentation, we found that Option #1 does not catch updates to non-staged APEXs. * Thus, we are implementing Option #2 here. More specifically, listening to * {@link Intent#ACTION_PACKAGE_ADDED} allows us to capture all events we care about. * * We did not use {@link Intent#ACTION_PACKAGE_REPLACED} because it unfortunately does not * detect updates to non-staged APEXs. Thus, we rely on {@link Intent#EXTRA_REPLACING} to * filter out new installation from updates instead. */ private void registerApkAndNonStagedApexUpdateListener() { Slog.d(TAG, "Registering APK & Non-Staged APEX updates..."); IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addDataScheme("package"); // this is somehow necessary mContext.registerReceiver(new PackageUpdatedReceiver(), filter); } /** * Listen for staged-APEX updates. * * This method basically covers cases that are not caught by * {@link #registerApkAndNonStagedApexUpdateListener()}, namely updates to APEXs that are staged * for the subsequent reboot. */ private void registerStagedApexUpdateObserver() { Slog.d(TAG, "Registering APEX updates..."); IPackageManagerNative iPackageManagerNative = IPackageManagerNative.Stub.asInterface( ServiceManager.getService("package_native")); if (iPackageManagerNative == null) { Slog.e(TAG, "IPackageManagerNative is null"); return; } try { iPackageManagerNative.registerStagedApexObserver(new IStagedApexObserver.Stub() { @Override public void onApexStaged(ApexStagedEvent event) throws RemoteException { Slog.d(TAG, "A new APEX has been staged for update. There are currently " + event.stagedApexModuleNames.length + " APEX(s) staged for update. " + "Scheduling measurement..."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); } }); } catch (RemoteException e) { Slog.e(TAG, "Failed to register a StagedApexObserver."); } } private boolean isPackagePreloaded(String packageName) { PackageManager pm = mContext.getPackageManager(); try { pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of( PackageManager.MATCH_FACTORY_ONLY)); } catch (PackageManager.NameNotFoundException e) { return false; } return true; } private boolean isPackageAnApex(String packageName) { PackageManager pm = mContext.getPackageManager(); try { PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(PackageManager.MATCH_APEX)); return packageInfo.isApex; } catch (PackageManager.NameNotFoundException e) { return false; } } private class PackageUpdatedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (!intent.getAction().equals(Intent.ACTION_PACKAGE_ADDED)) { return; } Uri data = intent.getData(); if (data == null) { Slog.e(TAG, "Shouldn't happen: intent data is null!"); return; } if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { Slog.d(TAG, "Not an update. Skipping..."); return; } String packageName = data.getSchemeSpecificPart(); // now we've got to check what package is this if (isPackagePreloaded(packageName) || isPackageAnApex(packageName)) { Slog.d(TAG, packageName + " was updated. Scheduling measurement..."); UpdateMeasurementsJobService.scheduleBinaryMeasurements(mContext, BinaryTransparencyService.this); } } } /** * Register observers for APK and APEX updates. The current implementation breaks this process * into 2 cases/methods because PackageManager does not offer a unified interface to register * for all package updates in a universal and comprehensive manner. * Thus, the observers will be invoked when either * i) APK or non-staged APEX update; or * ii) APEX staging happens. * This will then be used as signals to schedule measurement for the relevant binaries. */ private void registerAllPackageUpdateObservers() { registerApkAndNonStagedApexUpdateListener(); registerStagedApexUpdateObserver(); } private String translateContentDigestAlgorithmIdToString(int algorithmId) { private String translateContentDigestAlgorithmIdToString(int algorithmId) { switch (algorithmId) { switch (algorithmId) { case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256: case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256: Loading