Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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", Loading core/java/android/os/IRecoverySystem.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading core/java/android/os/RecoverySystem.java +15 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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. */ Loading services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +80 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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 Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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", Loading
core/java/android/os/IRecoverySystem.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -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(); Loading
core/java/android/os/RecoverySystem.java +15 −0 Original line number Diff line number Diff line Loading @@ -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); Loading Loading @@ -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. */ Loading
services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +80 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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 Loading Loading @@ -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