Merge "updater_sample: add HAL compatibility check"

This commit is contained in:
Zhomart Mukhamejanov
2018-05-11 03:05:21 +00:00
committed by Gerrit Code Review
2 changed files with 60 additions and 27 deletions
+1 -1
View File
@@ -84,8 +84,8 @@ which HTTP headers are supported.
- [x] Add applying streaming update - [x] Add applying streaming update
- [x] Add stop/reset the update - [x] Add stop/reset the update
- [x] Add demo for passing HTTP headers to `UpdateEngine#applyPayload` - [x] Add demo for passing HTTP headers to `UpdateEngine#applyPayload`
- [x] [Package compatibility check](https://source.android.com/devices/architecture/vintf/match-rules)
- [ ] Add tests for `MainActivity` - [ ] Add tests for `MainActivity`
- [ ] HAL compatibility check
- [ ] Change partition demo - [ ] Change partition demo
- [ ] Verify system partition checksum for package - [ ] Verify system partition checksum for package
- [ ] Add non-A/B updates demo - [ ] Add non-A/B updates demo
@@ -16,6 +16,7 @@
package com.example.android.systemupdatersample.services; package com.example.android.systemupdatersample.services;
import static com.example.android.systemupdatersample.util.PackageFiles.COMPATIBILITY_ZIP_FILE_NAME;
import static com.example.android.systemupdatersample.util.PackageFiles.OTA_PACKAGE_DIR; import static com.example.android.systemupdatersample.util.PackageFiles.OTA_PACKAGE_DIR;
import static com.example.android.systemupdatersample.util.PackageFiles.PAYLOAD_BINARY_FILE_NAME; import static com.example.android.systemupdatersample.util.PackageFiles.PAYLOAD_BINARY_FILE_NAME;
import static com.example.android.systemupdatersample.util.PackageFiles.PAYLOAD_PROPERTIES_FILE_NAME; import static com.example.android.systemupdatersample.util.PackageFiles.PAYLOAD_PROPERTIES_FILE_NAME;
@@ -25,6 +26,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.RecoverySystem;
import android.os.ResultReceiver; import android.os.ResultReceiver;
import android.util.Log; import android.util.Log;
@@ -36,7 +38,9 @@ import com.example.android.systemupdatersample.util.PayloadSpecs;
import com.example.android.systemupdatersample.util.UpdateConfigs; import com.example.android.systemupdatersample.util.UpdateConfigs;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Optional; import java.util.Optional;
@@ -119,45 +123,51 @@ public class PrepareStreamingService extends IntentService {
ResultReceiver resultReceiver = intent.getParcelableExtra(EXTRA_PARAM_RESULT_RECEIVER); ResultReceiver resultReceiver = intent.getParcelableExtra(EXTRA_PARAM_RESULT_RECEIVER);
try { try {
downloadPreStreamingFiles(config, OTA_PACKAGE_DIR); PayloadSpec spec = execute(config);
} catch (IOException e) { resultReceiver.send(RESULT_CODE_SUCCESS, CallbackResultReceiver.createBundle(spec));
Log.e(TAG, "Failed to download pre-streaming files", e); } catch (Exception e) {
Log.e(TAG, "Failed to prepare streaming update", e);
resultReceiver.send(RESULT_CODE_ERROR, null); resultReceiver.send(RESULT_CODE_ERROR, null);
return;
} }
}
/**
* 1. Downloads files for streaming updates.
* 2. Makes sure required files are present.
* 3. Checks OTA package compatibility with the device.
* 4. Constructs {@link PayloadSpec} for streaming update.
*/
private static PayloadSpec execute(UpdateConfig config)
throws IOException, PreparationFailedException {
downloadPreStreamingFiles(config, OTA_PACKAGE_DIR);
Optional<UpdateConfig.PackageFile> payloadBinary = Optional<UpdateConfig.PackageFile> payloadBinary =
UpdateConfigs.getPropertyFile(PAYLOAD_BINARY_FILE_NAME, config); UpdateConfigs.getPropertyFile(PAYLOAD_BINARY_FILE_NAME, config);
if (!payloadBinary.isPresent()) { if (!payloadBinary.isPresent()) {
Log.e(TAG, "Failed to find " + PAYLOAD_BINARY_FILE_NAME + " in config"); throw new PreparationFailedException(
resultReceiver.send(RESULT_CODE_ERROR, null); "Failed to find " + PAYLOAD_BINARY_FILE_NAME + " in config");
return;
} }
Optional<UpdateConfig.PackageFile> properties = if (!UpdateConfigs.getPropertyFile(PAYLOAD_PROPERTIES_FILE_NAME, config).isPresent()
UpdateConfigs.getPropertyFile(PAYLOAD_PROPERTIES_FILE_NAME, config); || !Paths.get(OTA_PACKAGE_DIR, PAYLOAD_PROPERTIES_FILE_NAME).toFile().exists()) {
throw new IOException(PAYLOAD_PROPERTIES_FILE_NAME + " not found");
if (!properties.isPresent()) {
Log.e(TAG, "Failed to find " + PAYLOAD_PROPERTIES_FILE_NAME + " in config");
resultReceiver.send(RESULT_CODE_ERROR, null);
return;
} }
PayloadSpec spec; File compatibilityFile = Paths.get(OTA_PACKAGE_DIR, COMPATIBILITY_ZIP_FILE_NAME).toFile();
try { if (compatibilityFile.isFile()) {
spec = PayloadSpecs.forStreaming(config.getUrl(), Log.i(TAG, "Verifying OTA package for compatibility with the device");
payloadBinary.get().getOffset(), if (!verifyPackageCompatibility(compatibilityFile)) {
payloadBinary.get().getSize(), throw new PreparationFailedException(
Paths.get(OTA_PACKAGE_DIR, properties.get().getFilename()).toFile() "OTA package is not compatible with this device");
); }
} catch (IOException e) {
Log.e(TAG, "PayloadSpecs failed to create PayloadSpec for streaming", e);
resultReceiver.send(RESULT_CODE_ERROR, null);
return;
} }
resultReceiver.send(RESULT_CODE_SUCCESS, CallbackResultReceiver.createBundle(spec)); return PayloadSpecs.forStreaming(config.getUrl(),
payloadBinary.get().getOffset(),
payloadBinary.get().getSize(),
Paths.get(OTA_PACKAGE_DIR, PAYLOAD_PROPERTIES_FILE_NAME).toFile());
} }
/** /**
@@ -168,6 +178,10 @@ public class PrepareStreamingService extends IntentService {
*/ */
private static void downloadPreStreamingFiles(UpdateConfig config, String dir) private static void downloadPreStreamingFiles(UpdateConfig config, String dir)
throws IOException { throws IOException {
Log.d(TAG, "Deleting existing files from " + dir);
for (String file : PRE_STREAMING_FILES_SET) {
Files.deleteIfExists(Paths.get(OTA_PACKAGE_DIR, file));
}
Log.d(TAG, "Downloading files to " + dir); Log.d(TAG, "Downloading files to " + dir);
for (UpdateConfig.PackageFile file : config.getStreamingMetadata().getPropertyFiles()) { for (UpdateConfig.PackageFile file : config.getStreamingMetadata().getPropertyFiles()) {
if (PRE_STREAMING_FILES_SET.contains(file.getFilename())) { if (PRE_STREAMING_FILES_SET.contains(file.getFilename())) {
@@ -182,6 +196,19 @@ public class PrepareStreamingService extends IntentService {
} }
} }
/**
* @param file physical location of {@link PackageFiles#COMPATIBILITY_ZIP_FILE_NAME}
* @return true if OTA package is compatible with this device
*/
private static boolean verifyPackageCompatibility(File file) {
try {
return RecoverySystem.verifyPackageCompatibility(file);
} catch (IOException e) {
Log.e(TAG, "Failed to verify package compatibility", e);
return false;
}
}
/** /**
* Used by {@link PrepareStreamingService} to pass {@link PayloadSpec} * Used by {@link PrepareStreamingService} to pass {@link PayloadSpec}
* to {@link UpdateResultCallback#onReceiveResult}. * to {@link UpdateResultCallback#onReceiveResult}.
@@ -213,4 +240,10 @@ public class PrepareStreamingService extends IntentService {
} }
} }
private static class PreparationFailedException extends Exception {
PreparationFailedException(String message) {
super(message);
}
}
} }