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

Commit 919348e6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Call apexd's API to allocate space before install non-AB package" am:...

Merge "Call apexd's API to allocate space before install non-AB package" am: 3736d7ac am: 259c28e9 am: 07417520

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1673927

Change-Id: Ib101cbb3f574780d6f34592340e9b67d493c3654
parents 4cc4892b 07417520
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -225,6 +225,7 @@ java_library {
        "apex_aidl_interface-java",
        "framework-protos",
        "updatable-driver-protos",
        "ota_metadata_proto_java",
        "android.hidl.base-V1.0-java",
        "android.hardware.cas-V1.0-java",
        "android.hardware.cas-V1.1-java",
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.os.IRecoverySystemProgressListener;
/** @hide */

interface IRecoverySystem {
    boolean allocateSpaceForUpdate(in String packageFilePath);
    boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
    boolean setupBcb(in String command);
    boolean clearBcb();
+15 −0
Original line number Diff line number Diff line
@@ -672,6 +672,14 @@ public class RecoverySystem {
            if (!rs.setupBcb(command)) {
                throw new IOException("Setup BCB failed");
            }
            try {
                if (!rs.allocateSpaceForUpdate(packageFile)) {
                    throw new IOException("Failed to allocate space for update "
                            + packageFile.getAbsolutePath());
                }
            } catch (RemoteException e) {
                e.rethrowAsRuntimeException();
            }

            // Having set up the BCB (bootloader control block), go ahead and reboot
            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -1391,6 +1399,13 @@ public class RecoverySystem {
        return false;
    }

    /**
     * Talks to RecoverySystemService via Binder to allocate space
     */
    private boolean allocateSpaceForUpdate(File packageFile) throws RemoteException {
        return mService.allocateSpaceForUpdate(packageFile.getAbsolutePath());
    }

    /**
     * Talks to RecoverySystemService via Binder to clear up the BCB.
     */
+80 −0
Original line number Diff line number Diff line
@@ -24,10 +24,13 @@ import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_SLOT_MISMA
import static android.os.RecoverySystem.RESUME_ON_REBOOT_REBOOT_ERROR_UNSPECIFIED;
import static android.os.RecoverySystem.ResumeOnRebootRebootErrorCode;
import static android.os.UserHandle.USER_SYSTEM;
import static android.ota.nano.OtaPackageMetadata.ApexMetadata;

import static com.android.internal.widget.LockSettingsInternal.ARM_REBOOT_ERROR_NONE;

import android.annotation.IntDef;
import android.apex.CompressedApexInfo;
import android.apex.CompressedApexInfoList;
import android.content.Context;
import android.content.IntentSender;
import android.content.SharedPreferences;
@@ -47,9 +50,11 @@ import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.sysprop.ApexProperties;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.FastImmutableArraySet;
import android.util.Log;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
@@ -59,6 +64,7 @@ import com.android.internal.widget.LockSettingsInternal;
import com.android.internal.widget.RebootEscrowListener;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.pm.ApexManager;

import libcore.io.IoUtils;

@@ -68,9 +74,13 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * The recovery system service is responsible for coordinating recovery related
@@ -871,6 +881,76 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
        return rebootWithLskfImpl(packageName, reason, slotSwitch);
    }

    public static boolean isUpdatableApexSupported() {
        return ApexProperties.updatable().orElse(false);
    }

    // Metadata should be no more than few MB, if it's larger than 100MB something is wrong.
    private static final long APEX_INFO_SIZE_LIMIT = 24 * 1024 * 100;

    private static CompressedApexInfoList getCompressedApexInfoList(String packageFile)
            throws IOException {
        try (ZipFile zipFile = new ZipFile(packageFile)) {
            final ZipEntry entry = zipFile.getEntry("apex_info.pb");
            if (entry == null) {
                return null;
            }
            if (entry.getSize() >= APEX_INFO_SIZE_LIMIT) {
                throw new IllegalArgumentException("apex_info.pb has size "
                        + entry.getSize()
                        + " which is larger than the permitted limit" + APEX_INFO_SIZE_LIMIT);
            }
            if (entry.getSize() == 0) {
                CompressedApexInfoList infoList = new CompressedApexInfoList();
                infoList.apexInfos = new CompressedApexInfo[0];
                return infoList;
            }
            Log.i(TAG, "Allocating " + entry.getSize()
                    + " bytes of memory to store OTA Metadata");
            byte[] data = new byte[(int) entry.getSize()];

            try (InputStream is = zipFile.getInputStream(entry)) {
                int bytesRead = is.read(data);
                String msg = "Read " + bytesRead + " when expecting " + data.length;
                Log.e(TAG, msg);
                if (bytesRead != data.length) {
                    throw new IOException(msg);
                }
            }
            ApexMetadata metadata = ApexMetadata.parseFrom(data);
            CompressedApexInfoList apexInfoList = new CompressedApexInfoList();
            apexInfoList.apexInfos =
                    Arrays.stream(metadata.apexInfo).filter(apex -> apex.isCompressed).map(apex -> {
                        CompressedApexInfo info = new CompressedApexInfo();
                        info.moduleName = apex.packageName;
                        info.decompressedSize = apex.decompressedSize;
                        info.versionCode = apex.version;
                        return info;
                    }).toArray(CompressedApexInfo[]::new);
            return apexInfoList;
        }
    }

    @Override
    public boolean allocateSpaceForUpdate(String packageFile) {
        if (!isUpdatableApexSupported()) {
            Log.i(TAG, "Updatable Apex not supported, "
                    + "allocateSpaceForUpdate does nothing.");
            return true;
        }
        try {
            CompressedApexInfoList apexInfoList = getCompressedApexInfoList(packageFile);
            ApexManager apexManager = ApexManager.getInstance();
            apexManager.reserveSpaceForCompressedApex(apexInfoList);
            return true;
        } catch (RemoteException e) {
            e.rethrowAsRuntimeException();
        } catch (IOException | UnsupportedOperationException e) {
            Slog.e(TAG, "Failed to reserve space for compressed apex: ", e);
        }
        return false;
    }

    @Override // Binder call
    public boolean isLskfCaptured(String packageName) {
        enforcePermissionForResumeOnReboot();