Loading core/java/android/util/PackageUtils.java +58 −0 Original line number Diff line number Diff line Loading @@ -18,13 +18,17 @@ package android.util; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.pm.Signature; import android.text.TextUtils; import libcore.util.HexEncoding; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; Loading @@ -35,6 +39,9 @@ import java.util.Arrays; */ public final class PackageUtils { private static final int LOW_RAM_BUFFER_SIZE_BYTES = 1 * 1000; // 1 kB private static final int HIGH_RAM_BUFFER_SIZE_BYTES = 1 * 1000 * 1000; // 1 MB private PackageUtils() { /* hide constructor */ } Loading Loading @@ -162,4 +169,55 @@ public final class PackageUtils { return TextUtils.join(separator, pieces); } /** * @see #computeSha256DigestForLargeFile(String, String) */ public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath) { return computeSha256DigestForLargeFile(filePath, null); } /** * 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. */ public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, @Nullable String separator) { MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance("SHA256"); messageDigest.reset(); } catch (NoSuchAlgorithmException e) { // this 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), messageDigest); byte[] buffer = new byte[bufferSize]; while (digestStream.read(buffer) != -1); } catch (IOException e) { return null; } byte[] resultBytes = messageDigest.digest(); if (separator == null) { return HexEncoding.encodeToString(resultBytes, true); } int length = resultBytes.length; String[] pieces = new String[length]; for (int index = 0; index < length; index++) { pieces[index] = HexEncoding.encodeToString(resultBytes[index], true); } return TextUtils.join(separator, pieces); } } services/core/java/com/android/server/BinaryTransparencyService.java +4 −18 Original line number Diff line number Diff line Loading @@ -36,11 +36,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IBinaryTransparencyService; import com.android.internal.util.FrameworkStatsLog; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; Loading Loading @@ -434,7 +431,7 @@ public class BinaryTransparencyService extends SystemService { entry.setValue(packageInfo.lastUpdateTime); // compute the digest for the updated package String sha256digest = computeSha256DigestOfFile( String sha256digest = PackageUtils.computeSha256DigestForLargeFile( packageInfo.applicationInfo.sourceDir); if (sha256digest == null) { Slog.e(TAG, "Failed to compute SHA256sum for file at " Loading Loading @@ -471,7 +468,7 @@ public class BinaryTransparencyService extends SystemService { ApplicationInfo appInfo = packageInfo.applicationInfo; // compute SHA256 for these APEXs String sha256digest = computeSha256DigestOfFile(appInfo.sourceDir); String sha256digest = PackageUtils.computeSha256DigestForLargeFile(appInfo.sourceDir); if (sha256digest == null) { Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s", packageInfo.packageName)); Loading Loading @@ -506,7 +503,8 @@ public class BinaryTransparencyService extends SystemService { ApplicationInfo appInfo = packageInfo.applicationInfo; // compute SHA256 digest for these modules String sha256digest = computeSha256DigestOfFile(appInfo.sourceDir); String sha256digest = PackageUtils.computeSha256DigestForLargeFile( appInfo.sourceDir); if (sha256digest == null) { Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s", packageName)); Loading @@ -525,16 +523,4 @@ public class BinaryTransparencyService extends SystemService { } } @Nullable private String computeSha256DigestOfFile(@NonNull String pathToFile) { File apexFile = new File(pathToFile); try { byte[] apexFileBytes = Files.readAllBytes(apexFile.toPath()); return PackageUtils.computeSha256Digest(apexFileBytes); } catch (IOException e) { Slog.e(TAG, String.format("I/O error occurs when reading from %s", pathToFile)); return null; } } } Loading
core/java/android/util/PackageUtils.java +58 −0 Original line number Diff line number Diff line Loading @@ -18,13 +18,17 @@ package android.util; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; import android.content.pm.Signature; import android.text.TextUtils; import libcore.util.HexEncoding; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; Loading @@ -35,6 +39,9 @@ import java.util.Arrays; */ public final class PackageUtils { private static final int LOW_RAM_BUFFER_SIZE_BYTES = 1 * 1000; // 1 kB private static final int HIGH_RAM_BUFFER_SIZE_BYTES = 1 * 1000 * 1000; // 1 MB private PackageUtils() { /* hide constructor */ } Loading Loading @@ -162,4 +169,55 @@ public final class PackageUtils { return TextUtils.join(separator, pieces); } /** * @see #computeSha256DigestForLargeFile(String, String) */ public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath) { return computeSha256DigestForLargeFile(filePath, null); } /** * 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. */ public static @Nullable String computeSha256DigestForLargeFile(@NonNull String filePath, @Nullable String separator) { MessageDigest messageDigest; try { messageDigest = MessageDigest.getInstance("SHA256"); messageDigest.reset(); } catch (NoSuchAlgorithmException e) { // this 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), messageDigest); byte[] buffer = new byte[bufferSize]; while (digestStream.read(buffer) != -1); } catch (IOException e) { return null; } byte[] resultBytes = messageDigest.digest(); if (separator == null) { return HexEncoding.encodeToString(resultBytes, true); } int length = resultBytes.length; String[] pieces = new String[length]; for (int index = 0; index < length; index++) { pieces[index] = HexEncoding.encodeToString(resultBytes[index], true); } return TextUtils.join(separator, pieces); } }
services/core/java/com/android/server/BinaryTransparencyService.java +4 −18 Original line number Diff line number Diff line Loading @@ -36,11 +36,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.IBinaryTransparencyService; import com.android.internal.util.FrameworkStatsLog; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; import java.util.List; Loading Loading @@ -434,7 +431,7 @@ public class BinaryTransparencyService extends SystemService { entry.setValue(packageInfo.lastUpdateTime); // compute the digest for the updated package String sha256digest = computeSha256DigestOfFile( String sha256digest = PackageUtils.computeSha256DigestForLargeFile( packageInfo.applicationInfo.sourceDir); if (sha256digest == null) { Slog.e(TAG, "Failed to compute SHA256sum for file at " Loading Loading @@ -471,7 +468,7 @@ public class BinaryTransparencyService extends SystemService { ApplicationInfo appInfo = packageInfo.applicationInfo; // compute SHA256 for these APEXs String sha256digest = computeSha256DigestOfFile(appInfo.sourceDir); String sha256digest = PackageUtils.computeSha256DigestForLargeFile(appInfo.sourceDir); if (sha256digest == null) { Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s", packageInfo.packageName)); Loading Loading @@ -506,7 +503,8 @@ public class BinaryTransparencyService extends SystemService { ApplicationInfo appInfo = packageInfo.applicationInfo; // compute SHA256 digest for these modules String sha256digest = computeSha256DigestOfFile(appInfo.sourceDir); String sha256digest = PackageUtils.computeSha256DigestForLargeFile( appInfo.sourceDir); if (sha256digest == null) { Slog.e(TAG, String.format("Failed to compute SHA256 digest for %s", packageName)); Loading @@ -525,16 +523,4 @@ public class BinaryTransparencyService extends SystemService { } } @Nullable private String computeSha256DigestOfFile(@NonNull String pathToFile) { File apexFile = new File(pathToFile); try { byte[] apexFileBytes = Files.readAllBytes(apexFile.toPath()); return PackageUtils.computeSha256Digest(apexFileBytes); } catch (IOException e) { Slog.e(TAG, String.format("I/O error occurs when reading from %s", pathToFile)); return null; } } }