diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java index c5ab82dbf0c51..11481209284a5 100644 --- a/core/java/android/util/PackageUtils.java +++ b/core/java/android/util/PackageUtils.java @@ -171,39 +171,53 @@ public final class PackageUtils { } /** - * @see #computeSha256DigestForLargeFile(String, String) + * Creates a fixed size buffer based on whether the device is low ram or not. This is to be used + * with the {@link #computeSha256DigestForLargeFile(String, byte[])} and + * {@link #computeSha256DigestForLargeFile(String, byte[], String)} methods. + * @return a byte array of size {@link #LOW_RAM_BUFFER_SIZE_BYTES} if the device is a low RAM + * device, otherwise a byte array of size {@link #HIGH_RAM_BUFFER_SIZE_BYTES} */ - public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath) { - return computeSha256DigestForLargeFile(filePath, null); + public static @NonNull byte[] createLargeFileBuffer() { + int bufferSize = ActivityManager.isLowRamDeviceStatic() + ? LOW_RAM_BUFFER_SIZE_BYTES : HIGH_RAM_BUFFER_SIZE_BYTES; + return new byte[bufferSize]; } /** - * Computes the SHA256 digest of large files. - * @param filePath The path to which the file's content is to be hashed. - * @param separator Separator between each pair of characters, such as colon, or null to omit. - * @return The digest or null if an error occurs. + * @see #computeSha256DigestForLargeFile(String, byte[], String) */ public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, - @Nullable String separator) { + @NonNull byte[] fileBuffer) { + return computeSha256DigestForLargeFile(filePath, fileBuffer, null); + } + + /** + * Computes the SHA256 digest of large files. This is typically useful for large APEXs. + * @param filePath The path to which the file's content is to be hashed. + * @param fileBuffer A buffer to read file's content into memory. It is strongly recommended to + * make use of the {@link #createLargeFileBuffer()} method to create this + * buffer. + * @param separator Separator between each pair of characters, such as colon, or null to omit. + * @return The SHA256 digest or null if an error occurs. + */ + public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, + @NonNull byte[] fileBuffer, @Nullable String separator) { MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance("SHA256"); messageDigest.reset(); } catch (NoSuchAlgorithmException e) { - // this shouldn't happen! + // this really shouldn't happen! return null; } - boolean isLowRamDevice = ActivityManager.isLowRamDeviceStatic(); - int bufferSize = isLowRamDevice ? LOW_RAM_BUFFER_SIZE_BYTES : HIGH_RAM_BUFFER_SIZE_BYTES; - File f = new File(filePath); try { - DigestInputStream digestStream = new DigestInputStream(new FileInputStream(f), + DigestInputStream digestInputStream = new DigestInputStream(new FileInputStream(f), messageDigest); - byte[] buffer = new byte[bufferSize]; - while (digestStream.read(buffer) != -1); + while (digestInputStream.read(fileBuffer) != -1); } catch (IOException e) { + e.printStackTrace(); return null; } diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java index 877ee8218ea69..fa52ac905a433 100644 --- a/services/core/java/com/android/server/BinaryTransparencyService.java +++ b/services/core/java/com/android/server/BinaryTransparencyService.java @@ -500,6 +500,7 @@ public class BinaryTransparencyService extends SystemService { // ones appearing out of the blue. Thus, we're going to only go through our cache to check // for changes, rather than freshly invoking `getInstalledPackages()` and // `getInstalledModules()` + byte[] largeFileBuffer = PackageUtils.createLargeFileBuffer(); for (Map.Entry entry : mBinaryLastUpdateTimes.entrySet()) { String packageName = entry.getKey(); try { @@ -513,7 +514,7 @@ public class BinaryTransparencyService extends SystemService { // compute the digest for the updated package String sha256digest = PackageUtils.computeSha256DigestForLargeFile( - packageInfo.applicationInfo.sourceDir); + packageInfo.applicationInfo.sourceDir, largeFileBuffer); if (sha256digest == null) { Slog.e(TAG, "Failed to compute SHA256sum for file at " + packageInfo.applicationInfo.sourceDir); @@ -545,11 +546,13 @@ public class BinaryTransparencyService extends SystemService { // In general, we care about all APEXs, *and* all Modules, which may include some APKs. // First, we deal with all installed APEXs. + byte[] largeFileBuffer = PackageUtils.createLargeFileBuffer(); for (PackageInfo packageInfo : getInstalledApexs()) { ApplicationInfo appInfo = packageInfo.applicationInfo; // compute SHA256 for these APEXs - String sha256digest = PackageUtils.computeSha256DigestForLargeFile(appInfo.sourceDir); + String sha256digest = PackageUtils.computeSha256DigestForLargeFile(appInfo.sourceDir, + largeFileBuffer); if (sha256digest == null) { Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s", packageInfo.packageName)); @@ -585,7 +588,7 @@ public class BinaryTransparencyService extends SystemService { // compute SHA256 digest for these modules String sha256digest = PackageUtils.computeSha256DigestForLargeFile( - appInfo.sourceDir); + appInfo.sourceDir, largeFileBuffer); if (sha256digest == null) { Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s", packageName));