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

Commit 07417520 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

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

Change-Id: Ic618bb85e0f8be9468fa1158b9f9e62682b9932d
parents b351365a 259c28e9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -211,6 +211,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();