Call apexd's API to allocate space before install non-AB package
When installing a non-AB package, if the OS comtains compressed apexes, we need to allocate space for these apexes so that they can be properly decompressed on the next reboot. Test: adb shell cmd recovery install-package /data/ota_package.zip Change-Id: Ia40d0614e0e724cfb17e91720ec88a15795bd8ee
This commit is contained in:
parent
4e8328c972
commit
a48c18e3df
@ -210,6 +210,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",
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user