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

Commit 8e9e6a32 authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

Signature streaming from local file, property to disable incremental.

+Tests

Test: atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest
Bug: b/136132412 b/133435829

Change-Id: I826900e120c72e7cdd0549c70da28d817982dcd3
parent 780d2bb7
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ import java.nio.file.Paths;
public final class IncrementalManager {
    private static final String TAG = "IncrementalManager";

    private static final String ALLOWED_PROPERTY = "incremental.allowed";

    public static final int CREATE_MODE_TEMPORARY_BIND =
            IIncrementalService.CREATE_MODE_TEMPORARY_BIND;
    public static final int CREATE_MODE_PERMANENT_BIND =
@@ -288,12 +290,20 @@ public final class IncrementalManager {
    }

    /**
     * Checks if Incremental is enabled
     * Checks if Incremental feature is enabled on this device.
     */
    public static boolean isEnabled() {
    public static boolean isFeatureEnabled() {
        return nativeIsEnabled();
    }

    /**
     * Checks if Incremental installations are allowed.
     * A developer can disable Incremental installations by setting the property.
     */
    public static boolean isAllowed() {
        return isFeatureEnabled() && android.os.SystemProperties.getBoolean(ALLOWED_PROPERTY, true);
    }

    /**
     * Checks if path is mounted on Incremental File System.
     */
+42 −11
Original line number Diff line number Diff line
@@ -16,8 +16,11 @@

package android.os.incremental;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
@@ -26,20 +29,36 @@ import java.io.IOException;
 * @hide
 */
public class V4Signature {
    public static final String EXT = ".idsig";

    public final byte[] verityRootHash;
    public final byte[] v3Digest;
    public final byte[] pkcs7SignatureBlock;

    V4Signature(byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
        this.verityRootHash = verityRootHash;
        this.v3Digest = v3Digest;
        this.pkcs7SignatureBlock = pkcs7SignatureBlock;
    /**
     * Construct a V4Signature from .idsig file.
     */
    public static V4Signature readFrom(File file) {
        try (DataInputStream stream = new DataInputStream(new FileInputStream(file))) {
            return readFrom(stream);
        } catch (IOException e) {
            return null;
        }
    }

    static byte[] readBytes(DataInputStream stream) throws IOException {
        byte[] result = new byte[stream.readInt()];
        stream.read(result);
        return result;
    /**
     * Store the V4Signature to a byte-array.
     */
    public byte[] toByteArray() {
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
            try (DataOutputStream steam = new DataOutputStream(byteArrayOutputStream)) {
                this.writeTo(steam);
                steam.flush();
            }
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            return null;
        }
    }

    static V4Signature readFrom(DataInputStream stream) throws IOException {
@@ -49,9 +68,10 @@ public class V4Signature {
        return new V4Signature(verityRootHash, v3Digest, pkcs7SignatureBlock);
    }

    static void writeBytes(DataOutputStream stream, byte[] bytes) throws IOException {
        stream.writeInt(bytes.length);
        stream.write(bytes);
    V4Signature(byte[] verityRootHash, byte[] v3Digest, byte[] pkcs7SignatureBlock) {
        this.verityRootHash = verityRootHash;
        this.v3Digest = v3Digest;
        this.pkcs7SignatureBlock = pkcs7SignatureBlock;
    }

    void writeTo(DataOutputStream stream) throws IOException {
@@ -59,4 +79,15 @@ public class V4Signature {
        writeBytes(stream, this.v3Digest);
        writeBytes(stream, this.pkcs7SignatureBlock);
    }

    private static byte[] readBytes(DataInputStream stream) throws IOException {
        byte[] result = new byte[stream.readInt()];
        stream.read(result);
        return result;
    }

    private static void writeBytes(DataOutputStream stream, byte[] bytes) throws IOException {
        stream.writeInt(bytes.length);
        stream.write(bytes);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -1156,7 +1156,7 @@ public class SystemConfig {
            addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);
        }

        if (IncrementalManager.isEnabled()) {
        if (IncrementalManager.isFeatureEnabled()) {
            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0);
        }

+14 −6
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ import android.os.RevocableFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.incremental.IncrementalFileStorages;
import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.provider.Settings.Secure;
import android.stats.devicepolicy.DevicePolicyEnums;
@@ -538,17 +539,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                throw new IllegalArgumentException(
                        "DataLoader installation of APEX modules is not allowed.");
            }
            if (this.params.dataLoaderParams.getComponentName().getPackageName()
                    == SYSTEM_DATA_LOADER_PACKAGE) {
                assertShellOrSystemCalling("System data loaders");
            }
        }

        if (isStreamingInstallation()) {
        if (isIncrementalInstallation()) {
            if (!IncrementalManager.isAllowed()) {
                throw new IllegalArgumentException("Incremental installation not allowed.");
            }
            if (!isIncrementalInstallationAllowed(mPackageName)) {
                throw new IllegalArgumentException(
                        "Incremental installation of this package is not allowed.");
            }
            if (this.params.dataLoaderParams.getComponentName().getPackageName()
                    == SYSTEM_DATA_LOADER_PACKAGE) {
                assertShellOrSystemCalling("System data loaders");
            }
        }
    }

@@ -2385,12 +2389,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            throw new IllegalStateException(
                    "Cannot add files to non-data loader installation session.");
        }
        if (!isIncrementalInstallation()) {
        if (isStreamingInstallation()) {
            if (location != LOCATION_DATA_APP) {
                throw new IllegalArgumentException(
                        "Non-incremental installation only supports /data/app placement: " + name);
            }
        }
        if (metadata == null) {
            throw new IllegalArgumentException(
                    "DataLoader installation requires valid metadata: " + name);
        }
        // Use installer provided name for now; we always rename later
        if (!FileUtils.isValidExtFilename(name)) {
            throw new IllegalArgumentException("Invalid name: " + name);
+9 −2
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.incremental.V4Signature;
import android.os.storage.StorageManager;
import android.permission.IPermissionManager;
import android.system.ErrnoException;
@@ -3024,9 +3025,15 @@ class PackageManagerShellCommand extends ShellCommand {
                final File file = new File(inPath);
                final String name = file.getName();
                final long size = file.length();
                byte[] metadata = inPath.getBytes(StandardCharsets.UTF_8);
                final byte[] metadata = inPath.getBytes(StandardCharsets.UTF_8);

                session.addFile(LOCATION_DATA_APP, name, size, metadata, null);
                // Try to load a v4 signature for the APK.
                final V4Signature v4signature = V4Signature.readFrom(
                        new File(inPath + V4Signature.EXT));
                final byte[] v4signatureBytes =
                        (v4signature != null) ? v4signature.toByteArray() : null;

                session.addFile(LOCATION_DATA_APP, name, size, metadata, v4signatureBytes);
            }
            return 0;
        } finally {
Loading