Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55bfb23d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix potential OOM issues when APEXs are too large."

parents 60e26f7a 74b4af53
Loading
Loading
Loading
Loading
+58 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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 */
    }
@@ -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);
    }
}
+4 −18
Original line number Diff line number Diff line
@@ -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;
@@ -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 "
@@ -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));
@@ -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));
@@ -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;
        }
    }
}