From c18d4886582c5a857f9da63a51eac870497e034e Mon Sep 17 00:00:00 2001 From: Zhomart Mukhamejanov Date: Fri, 14 Dec 2018 10:36:20 -0800 Subject: Add verification before downloading whole package UpdateEngine has a feature that verifies payload without downloading the whole update package. If UpdateEngine detects invalid payload, the sample app aborts the update. No JUnit tests, because it accesses files on the device and migrating tests to robolectric is not worth for this sample app. Bug: 77150191 Test: device Change-Id: Ib8ce73508a02cf5fdcb326d8ba46c1d05ed5efe5 --- .../services/PrepareUpdateService.java | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'updater_sample/src') diff --git a/updater_sample/src/com/example/android/systemupdatersample/services/PrepareUpdateService.java b/updater_sample/src/com/example/android/systemupdatersample/services/PrepareUpdateService.java index 06581bee3..29eb13da7 100644 --- a/updater_sample/src/com/example/android/systemupdatersample/services/PrepareUpdateService.java +++ b/updater_sample/src/com/example/android/systemupdatersample/services/PrepareUpdateService.java @@ -42,7 +42,9 @@ import com.google.common.collect.ImmutableSet; import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.Optional; /** @@ -144,6 +146,13 @@ public class PrepareUpdateService extends IntentService { private PayloadSpec execute(UpdateConfig config) throws IOException, PreparationFailedException { + if (config.getAbConfig().getVerifyPayloadMetadata()) { + Log.i(TAG, "Verifying payload metadata with UpdateEngine."); + if (!verifyPayloadMetadata(config)) { + throw new PreparationFailedException("Payload metadata is not compatible"); + } + } + if (config.getInstallType() == UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING) { return mPayloadSpecs.forNonStreaming(config.getUpdatePackageFile()); } @@ -178,6 +187,48 @@ public class PrepareUpdateService extends IntentService { Paths.get(OTA_PACKAGE_DIR, PAYLOAD_PROPERTIES_FILE_NAME).toFile()); } + /** + * Downloads only payload_metadata.bin and verifies with + * {@link UpdateEngine#verifyPayloadMetadata}. + * Returns {@code true} if the payload is verified or the result is unknown because of + * exception from UpdateEngine. + * By downloading only small portion of the package, it allows to verify if UpdateEngine + * will install the update. + */ + private boolean verifyPayloadMetadata(UpdateConfig config) { + Optional metadataPackageFile = + Arrays.stream(config.getAbConfig().getPropertyFiles()) + .filter(p -> p.getFilename().equals( + PackageFiles.PAYLOAD_METADATA_FILE_NAME)) + .findFirst(); + if (!metadataPackageFile.isPresent()) { + Log.w(TAG, String.format("ab_config.property_files doesn't contain %s", + PackageFiles.PAYLOAD_METADATA_FILE_NAME)); + return true; + } + Path metadataPath = Paths.get(OTA_PACKAGE_DIR, PackageFiles.PAYLOAD_METADATA_FILE_NAME); + try { + Files.deleteIfExists(metadataPath); + FileDownloader d = new FileDownloader( + config.getUrl(), + metadataPackageFile.get().getOffset(), + metadataPackageFile.get().getSize(), + metadataPath.toFile()); + d.download(); + } catch (IOException e) { + Log.w(TAG, String.format("Downloading %s from %s failed", + PackageFiles.PAYLOAD_METADATA_FILE_NAME, + config.getUrl()), e); + return true; + } + try { + return mUpdateEngine.verifyPayloadMetadata(metadataPath.toAbsolutePath().toString()); + } catch (Exception e) { + Log.w(TAG, "UpdateEngine#verifyPayloadMetadata failed", e); + return true; + } + } + /** * Downloads files defined in {@link UpdateConfig#getAbConfig()} * and exists in {@code PRE_STREAMING_FILES_SET}, and put them -- cgit v1.2.3