summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--etc/init.rc4
-rw-r--r--recovery_main.cpp13
-rw-r--r--tests/component/updater_test.cpp2
-rw-r--r--tests/testdata/new.filebin1388877 -> 0 bytes
-rw-r--r--tests/testdata/old.filebin1348051 -> 0 bytes
-rw-r--r--tests/unit/applypatch_test.cpp103
-rw-r--r--uncrypt/Android.bp12
-rw-r--r--updater_sample/README.md2
-rw-r--r--updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java112
-rw-r--r--updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java2
-rw-r--r--updater_sample/src/com/example/android/systemupdatersample/services/PrepareStreamingService.java4
-rw-r--r--updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java4
-rw-r--r--updater_sample/tests/res/raw/update_config_001_stream.json7
-rw-r--r--updater_sample/tests/res/raw/update_config_002_stream.json7
-rw-r--r--updater_sample/tests/res/raw/update_config_003_nonstream.json10
-rw-r--r--updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java27
-rwxr-xr-xupdater_sample/tools/gen_update_config.py37
-rwxr-xr-xupdater_sample/tools/test_gen_update_config.py6
19 files changed, 194 insertions, 160 deletions
diff --git a/Android.bp b/Android.bp
index 53b74dca5..c5fcd65c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -232,7 +232,7 @@ cc_binary {
required: [
"e2fsdroid.recovery",
"librecovery_ui_ext",
- "mke2fs.conf",
+ "mke2fs.conf.recovery",
"mke2fs.recovery",
"recovery_deps",
],
diff --git a/etc/init.rc b/etc/init.rc
index 9add2494a..2adecb764 100644
--- a/etc/init.rc
+++ b/etc/init.rc
@@ -13,6 +13,10 @@ on init
export ANDROID_DATA /data
export EXTERNAL_STORAGE /sdcard
+ symlink /proc/self/fd/0 /dev/stdin
+ symlink /proc/self/fd/1 /dev/stdout
+ symlink /proc/self/fd/2 /dev/stderr
+
symlink /system/bin /bin
symlink /system/etc /etc
diff --git a/recovery_main.cpp b/recovery_main.cpp
index 99f965098..020a5314f 100644
--- a/recovery_main.cpp
+++ b/recovery_main.cpp
@@ -97,8 +97,13 @@ static std::vector<std::string> get_args(const int argc, char** const argv) {
}
stage = std::string(boot.stage);
+ std::string boot_command;
if (boot.command[0] != 0) {
- std::string boot_command = std::string(boot.command, sizeof(boot.command));
+ if (memchr(boot.command, '\0', sizeof(boot.command))) {
+ boot_command = std::string(boot.command);
+ } else {
+ boot_command = std::string(boot.command, sizeof(boot.command));
+ }
LOG(INFO) << "Boot command: " << boot_command;
}
@@ -149,6 +154,12 @@ static std::vector<std::string> get_args(const int argc, char** const argv) {
LOG(ERROR) << "Failed to set BCB message: " << err;
}
+ // Finally, if no arguments were specified, check whether we should boot
+ // into fastboot.
+ if (args.size() == 1 && boot_command == "boot-fastboot") {
+ args.emplace_back("--fastboot");
+ }
+
return args;
}
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 59757655f..b253abccf 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -221,7 +221,7 @@ TEST_F(UpdaterTest, apply_patch_check) {
// File not found.
expect("", "apply_patch_check(\"/doesntexist\")", kNoCause);
- std::string src_file = from_testdata_base("old.file");
+ std::string src_file = from_testdata_base("boot.img");
std::string src_content;
ASSERT_TRUE(android::base::ReadFileToString(src_file, &src_content));
size_t src_size = src_content.size();
diff --git a/tests/testdata/new.file b/tests/testdata/new.file
deleted file mode 100644
index cdeb8fd50..000000000
--- a/tests/testdata/new.file
+++ /dev/null
Binary files differ
diff --git a/tests/testdata/old.file b/tests/testdata/old.file
deleted file mode 100644
index 166c8732e..000000000
--- a/tests/testdata/old.file
+++ /dev/null
Binary files differ
diff --git a/tests/unit/applypatch_test.cpp b/tests/unit/applypatch_test.cpp
index 0d4123b5e..fe00e1e66 100644
--- a/tests/unit/applypatch_test.cpp
+++ b/tests/unit/applypatch_test.cpp
@@ -46,17 +46,17 @@ using namespace std::string_literals;
class ApplyPatchTest : public ::testing::Test {
protected:
void SetUp() override {
- old_file = from_testdata_base("old.file");
- FileContents old_fc;
- ASSERT_EQ(0, LoadFileContents(old_file, &old_fc));
- old_sha1 = print_sha1(old_fc.sha1);
- old_size = old_fc.data.size();
-
- new_file = from_testdata_base("new.file");
- FileContents new_fc;
- ASSERT_EQ(0, LoadFileContents(new_file, &new_fc));
- new_sha1 = print_sha1(new_fc.sha1);
- new_size = new_fc.data.size();
+ source_file = from_testdata_base("boot.img");
+ FileContents boot_fc;
+ ASSERT_EQ(0, LoadFileContents(source_file, &boot_fc));
+ source_size = boot_fc.data.size();
+ source_sha1 = print_sha1(boot_fc.sha1);
+
+ target_file = from_testdata_base("recovery.img");
+ FileContents recovery_fc;
+ ASSERT_EQ(0, LoadFileContents(target_file, &recovery_fc));
+ target_size = recovery_fc.data.size();
+ target_sha1 = print_sha1(recovery_fc.sha1);
srand(time(nullptr));
bad_sha1_a = android::base::StringPrintf("%040x", rand());
@@ -66,78 +66,83 @@ class ApplyPatchTest : public ::testing::Test {
Paths::Get().set_cache_temp_source("/cache/saved.file");
}
- std::string old_file;
- std::string old_sha1;
- size_t old_size;
+ std::string source_file;
+ std::string source_sha1;
+ size_t source_size;
- std::string new_file;
- std::string new_sha1;
- size_t new_size;
+ std::string target_file;
+ std::string target_sha1;
+ size_t target_size;
std::string bad_sha1_a;
std::string bad_sha1_b;
};
TEST_F(ApplyPatchTest, CheckMode) {
- std::string partition = "EMMC:" + old_file + ":" + std::to_string(old_size) + ":" + old_sha1;
+ std::string partition =
+ "EMMC:" + source_file + ":" + std::to_string(source_size) + ":" + source_sha1;
ASSERT_EQ(0, applypatch_check(partition, {}));
- ASSERT_EQ(0, applypatch_check(partition, { old_sha1 }));
+ ASSERT_EQ(0, applypatch_check(partition, { source_sha1 }));
ASSERT_EQ(0, applypatch_check(partition, { bad_sha1_a, bad_sha1_b }));
- ASSERT_EQ(0, applypatch_check(partition, { bad_sha1_a, old_sha1, bad_sha1_b }));
+ ASSERT_EQ(0, applypatch_check(partition, { bad_sha1_a, source_sha1, bad_sha1_b }));
}
TEST_F(ApplyPatchTest, CheckMode_NonEmmcTarget) {
- ASSERT_NE(0, applypatch_check(old_file, {}));
- ASSERT_NE(0, applypatch_check(old_file, { old_sha1 }));
- ASSERT_NE(0, applypatch_check(old_file, { bad_sha1_a, bad_sha1_b }));
- ASSERT_NE(0, applypatch_check(old_file, { bad_sha1_a, old_sha1, bad_sha1_b }));
+ ASSERT_NE(0, applypatch_check(source_file, {}));
+ ASSERT_NE(0, applypatch_check(source_file, { source_sha1 }));
+ ASSERT_NE(0, applypatch_check(source_file, { bad_sha1_a, bad_sha1_b }));
+ ASSERT_NE(0, applypatch_check(source_file, { bad_sha1_a, source_sha1, bad_sha1_b }));
}
TEST_F(ApplyPatchTest, CheckMode_EmmcTarget) {
- // EMMC:old_file:size:sha1 should pass the check.
- std::string src_file = "EMMC:" + old_file + ":" + std::to_string(old_size) + ":" + old_sha1;
+ // EMMC:source_file:size:sha1 should pass the check.
+ std::string src_file =
+ "EMMC:" + source_file + ":" + std::to_string(source_size) + ":" + source_sha1;
ASSERT_EQ(0, applypatch_check(src_file, {}));
- // EMMC:old_file:(size-1):sha1:(size+1):sha1 should fail the check.
- src_file = "EMMC:" + old_file + ":" + std::to_string(old_size - 1) + ":" + old_sha1 + ":" +
- std::to_string(old_size + 1) + ":" + old_sha1;
+ // EMMC:source_file:(size-1):sha1:(size+1):sha1 should fail the check.
+ src_file = "EMMC:" + source_file + ":" + std::to_string(source_size - 1) + ":" + source_sha1 +
+ ":" + std::to_string(source_size + 1) + ":" + source_sha1;
ASSERT_NE(0, applypatch_check(src_file, {}));
- // EMMC:old_file:(size-1):sha1:size:sha1:(size+1):sha1 should pass the check.
- src_file = "EMMC:" + old_file + ":" + std::to_string(old_size - 1) + ":" + old_sha1 + ":" +
- std::to_string(old_size) + ":" + old_sha1 + ":" + std::to_string(old_size + 1) + ":" +
- old_sha1;
+ // EMMC:source_file:(size-1):sha1:size:sha1:(size+1):sha1 should pass the check.
+ src_file = "EMMC:" + source_file + ":" + std::to_string(source_size - 1) + ":" + source_sha1 +
+ ":" + std::to_string(source_size) + ":" + source_sha1 + ":" +
+ std::to_string(source_size + 1) + ":" + source_sha1;
ASSERT_EQ(0, applypatch_check(src_file, {}));
- // EMMC:old_file:(size+1):sha1:(size-1):sha1:size:sha1 should pass the check.
- src_file = "EMMC:" + old_file + ":" + std::to_string(old_size + 1) + ":" + old_sha1 + ":" +
- std::to_string(old_size - 1) + ":" + old_sha1 + ":" + std::to_string(old_size) + ":" +
- old_sha1;
+ // EMMC:source_file:(size+1):sha1:(size-1):sha1:size:sha1 should pass the check.
+ src_file = "EMMC:" + source_file + ":" + std::to_string(source_size + 1) + ":" + source_sha1 +
+ ":" + std::to_string(source_size - 1) + ":" + source_sha1 + ":" +
+ std::to_string(source_size) + ":" + source_sha1;
ASSERT_EQ(0, applypatch_check(src_file, {}));
- // EMMC:new_file:(size+1):old_sha1:(size-1):old_sha1:size:old_sha1:size:new_sha1
+ // EMMC:target_file:(size+1):source_sha1:(size-1):source_sha1:size:source_sha1:size:target_sha1
// should pass the check.
- src_file = "EMMC:" + new_file + ":" + std::to_string(old_size + 1) + ":" + old_sha1 + ":" +
- std::to_string(old_size - 1) + ":" + old_sha1 + ":" + std::to_string(old_size) + ":" +
- old_sha1 + ":" + std::to_string(new_size) + ":" + new_sha1;
+ src_file = "EMMC:" + target_file + ":" + std::to_string(source_size + 1) + ":" + source_sha1 +
+ ":" + std::to_string(source_size - 1) + ":" + source_sha1 + ":" +
+ std::to_string(source_size) + ":" + source_sha1 + ":" + std::to_string(target_size) +
+ ":" + target_sha1;
ASSERT_EQ(0, applypatch_check(src_file, {}));
}
TEST_F(ApplyPatchTest, CheckMode_UseBackup) {
- std::string corrupted = "EMMC:" + old_file + ":" + std::to_string(old_size) + ":" + bad_sha1_a;
- ASSERT_NE(0, applypatch_check(corrupted, { old_sha1 }));
+ std::string corrupted =
+ "EMMC:" + source_file + ":" + std::to_string(source_size) + ":" + bad_sha1_a;
+ ASSERT_NE(0, applypatch_check(corrupted, { source_sha1 }));
- Paths::Get().set_cache_temp_source(old_file);
- ASSERT_EQ(0, applypatch_check(corrupted, { old_sha1 }));
- ASSERT_EQ(0, applypatch_check(corrupted, { bad_sha1_a, old_sha1, bad_sha1_b }));
+ Paths::Get().set_cache_temp_source(source_file);
+ ASSERT_EQ(0, applypatch_check(corrupted, { source_sha1 }));
+ ASSERT_EQ(0, applypatch_check(corrupted, { bad_sha1_a, source_sha1, bad_sha1_b }));
}
TEST_F(ApplyPatchTest, CheckMode_UseBackup_BothCorrupted) {
- std::string corrupted = "EMMC:" + old_file + ":" + std::to_string(old_size) + ":" + bad_sha1_a;
+ std::string corrupted =
+ "EMMC:" + source_file + ":" + std::to_string(source_size) + ":" + bad_sha1_a;
ASSERT_NE(0, applypatch_check(corrupted, {}));
- ASSERT_NE(0, applypatch_check(corrupted, { old_sha1 }));
+ ASSERT_NE(0, applypatch_check(corrupted, { source_sha1 }));
- Paths::Get().set_cache_temp_source(old_file);
+ Paths::Get().set_cache_temp_source(source_file);
ASSERT_NE(0, applypatch_check(corrupted, { bad_sha1_a, bad_sha1_b }));
}
diff --git a/uncrypt/Android.bp b/uncrypt/Android.bp
index aa56d2f74..107a7f0fc 100644
--- a/uncrypt/Android.bp
+++ b/uncrypt/Android.bp
@@ -24,13 +24,15 @@ cc_binary {
"-Werror",
],
- static_libs: [
- "libbootloader_message",
- "libotautil",
- "libfs_mgr",
+ shared_libs: [
"libbase",
+ "libbootloader_message",
"libcutils",
- "liblog",
+ "libfs_mgr",
+ ],
+
+ static_libs: [
+ "libotautil",
],
init_rc: [
diff --git a/updater_sample/README.md b/updater_sample/README.md
index 69e8e244f..f9c3fb8ec 100644
--- a/updater_sample/README.md
+++ b/updater_sample/README.md
@@ -220,7 +220,7 @@ privileged system app, so it's granted the required permissions to access
- [x] Add Sample app update state (separate from update_engine status)
- [x] Add smart update completion detection using onStatusUpdate
- [x] Add pause/resume demo
-- [ ] Verify system partition checksum for package
+- [x] Verify system partition checksum for package
## Running tests
diff --git a/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java b/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java
index 1e0fadc27..61872a634 100644
--- a/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java
+++ b/updater_sample/src/com/example/android/systemupdatersample/UpdateConfig.java
@@ -25,6 +25,7 @@ import org.json.JSONObject;
import java.io.File;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Optional;
/**
@@ -67,31 +68,28 @@ public class UpdateConfig implements Parcelable {
throw new JSONException("Invalid type, expected either "
+ "NON_STREAMING or STREAMING, got " + o.getString("ab_install_type"));
}
- if (c.mAbInstallType == AB_INSTALL_TYPE_STREAMING) {
- JSONObject meta = o.getJSONObject("ab_streaming_metadata");
- JSONArray propertyFilesJson = meta.getJSONArray("property_files");
- PackageFile[] propertyFiles =
- new PackageFile[propertyFilesJson.length()];
+
+ // TODO: parse only for A/B updates when non-A/B is implemented
+ JSONObject ab = o.getJSONObject("ab_config");
+ boolean forceSwitchSlot = ab.getBoolean("force_switch_slot");
+ boolean verifyPayloadMetadata = ab.getBoolean("verify_payload_metadata");
+ ArrayList<PackageFile> propertyFiles = new ArrayList<>();
+ if (ab.has("property_files")) {
+ JSONArray propertyFilesJson = ab.getJSONArray("property_files");
for (int i = 0; i < propertyFilesJson.length(); i++) {
JSONObject p = propertyFilesJson.getJSONObject(i);
- propertyFiles[i] = new PackageFile(
+ propertyFiles.add(new PackageFile(
p.getString("filename"),
p.getLong("offset"),
- p.getLong("size"));
- }
- String authorization = null;
- if (meta.has("authorization")) {
- authorization = meta.getString("authorization");
+ p.getLong("size")));
}
- c.mAbStreamingMetadata = new StreamingMetadata(
- propertyFiles,
- authorization);
}
-
- // TODO: parse only for A/B updates when non-A/B is implemented
- JSONObject ab = o.getJSONObject("ab_config");
- boolean forceSwitchSlot = ab.getBoolean("force_switch_slot");
- c.mAbConfig = new AbConfig(forceSwitchSlot);
+ String authorization = ab.optString("authorization", null);
+ c.mAbConfig = new AbConfig(
+ forceSwitchSlot,
+ verifyPayloadMetadata,
+ propertyFiles.toArray(new PackageFile[0]),
+ authorization);
c.mRawJson = json;
return c;
@@ -112,9 +110,6 @@ public class UpdateConfig implements Parcelable {
/** non-streaming (first saves locally) OR streaming (on the fly) */
private int mAbInstallType;
- /** metadata is required only for streaming update */
- private StreamingMetadata mAbStreamingMetadata;
-
/** A/B update configurations */
private AbConfig mAbConfig;
@@ -127,7 +122,6 @@ public class UpdateConfig implements Parcelable {
this.mName = in.readString();
this.mUrl = in.readString();
this.mAbInstallType = in.readInt();
- this.mAbStreamingMetadata = (StreamingMetadata) in.readSerializable();
this.mAbConfig = (AbConfig) in.readSerializable();
this.mRawJson = in.readString();
}
@@ -154,10 +148,6 @@ public class UpdateConfig implements Parcelable {
return mAbInstallType;
}
- public StreamingMetadata getStreamingMetadata() {
- return mAbStreamingMetadata;
- }
-
public AbConfig getAbConfig() {
return mAbConfig;
}
@@ -185,43 +175,11 @@ public class UpdateConfig implements Parcelable {
dest.writeString(mName);
dest.writeString(mUrl);
dest.writeInt(mAbInstallType);
- dest.writeSerializable(mAbStreamingMetadata);
dest.writeSerializable(mAbConfig);
dest.writeString(mRawJson);
}
/**
- * Metadata for streaming A/B update.
- */
- public static class StreamingMetadata implements Serializable {
-
- private static final long serialVersionUID = 31042L;
-
- /** defines beginning of update data in archive */
- private PackageFile[] mPropertyFiles;
-
- /**
- * SystemUpdaterSample receives the authorization token from the OTA server, in addition
- * to the package URL. It passes on the info to update_engine, so that the latter can
- * fetch the data from the package server directly with the token.
- */
- private String mAuthorization;
-
- public StreamingMetadata(PackageFile[] propertyFiles, String authorization) {
- this.mPropertyFiles = propertyFiles;
- this.mAuthorization = authorization;
- }
-
- public PackageFile[] getPropertyFiles() {
- return mPropertyFiles;
- }
-
- public Optional<String> getAuthorization() {
- return mAuthorization == null ? Optional.empty() : Optional.of(mAuthorization);
- }
- }
-
- /**
* Description of a file in an OTA package zip file.
*/
public static class PackageFile implements Serializable {
@@ -269,14 +227,48 @@ public class UpdateConfig implements Parcelable {
*/
private boolean mForceSwitchSlot;
- public AbConfig(boolean forceSwitchSlot) {
+ /**
+ * if set true device will boot to new slot, otherwise user manually
+ * switches slot on the screen.
+ */
+ private boolean mVerifyPayloadMetadata;
+
+ /** defines beginning of update data in archive */
+ private PackageFile[] mPropertyFiles;
+
+ /**
+ * SystemUpdaterSample receives the authorization token from the OTA server, in addition
+ * to the package URL. It passes on the info to update_engine, so that the latter can
+ * fetch the data from the package server directly with the token.
+ */
+ private String mAuthorization;
+
+ public AbConfig(
+ boolean forceSwitchSlot,
+ boolean verifyPayloadMetadata,
+ PackageFile[] propertyFiles,
+ String authorization) {
this.mForceSwitchSlot = forceSwitchSlot;
+ this.mVerifyPayloadMetadata = verifyPayloadMetadata;
+ this.mPropertyFiles = propertyFiles;
+ this.mAuthorization = authorization;
}
public boolean getForceSwitchSlot() {
return mForceSwitchSlot;
}
+ public boolean getVerifyPayloadMetadata() {
+ return mVerifyPayloadMetadata;
+ }
+
+ public PackageFile[] getPropertyFiles() {
+ return mPropertyFiles;
+ }
+
+ public Optional<String> getAuthorization() {
+ return mAuthorization == null ? Optional.empty() : Optional.of(mAuthorization);
+ }
}
}
diff --git a/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java b/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java
index a9783e70a..12a8f3f5f 100644
--- a/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java
+++ b/updater_sample/src/com/example/android/systemupdatersample/UpdateManager.java
@@ -324,7 +324,7 @@ public class UpdateManager {
if (code == PrepareStreamingService.RESULT_CODE_SUCCESS) {
builder.setPayload(payloadSpec);
builder.addExtraProperty("USER_AGENT=" + HTTP_USER_AGENT);
- config.getStreamingMetadata()
+ config.getAbConfig()
.getAuthorization()
.ifPresent(s -> builder.addExtraProperty("AUTHORIZATION=" + s));
updateEngineApplyPayload(builder.build());
diff --git a/updater_sample/src/com/example/android/systemupdatersample/services/PrepareStreamingService.java b/updater_sample/src/com/example/android/systemupdatersample/services/PrepareStreamingService.java
index ac6e223e3..931404857 100644
--- a/updater_sample/src/com/example/android/systemupdatersample/services/PrepareStreamingService.java
+++ b/updater_sample/src/com/example/android/systemupdatersample/services/PrepareStreamingService.java
@@ -173,7 +173,7 @@ public class PrepareStreamingService extends IntentService {
}
/**
- * Downloads files defined in {@link UpdateConfig#getStreamingMetadata()}
+ * Downloads files defined in {@link UpdateConfig#getAbConfig()}
* and exists in {@code PRE_STREAMING_FILES_SET}, and put them
* in directory {@code dir}.
* @throws IOException when can't download a file
@@ -185,7 +185,7 @@ public class PrepareStreamingService extends IntentService {
Files.deleteIfExists(Paths.get(OTA_PACKAGE_DIR, file));
}
Log.d(TAG, "Downloading files to " + dir);
- for (UpdateConfig.PackageFile file : config.getStreamingMetadata().getPropertyFiles()) {
+ for (UpdateConfig.PackageFile file : config.getAbConfig().getPropertyFiles()) {
if (PRE_STREAMING_FILES_SET.contains(file.getFilename())) {
Log.d(TAG, "Downloading file " + file.getFilename());
FileDownloader downloader = new FileDownloader(
diff --git a/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java b/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java
index 5080cb6d8..bbefcaf16 100644
--- a/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java
+++ b/updater_sample/src/com/example/android/systemupdatersample/util/UpdateConfigs.java
@@ -83,7 +83,7 @@ public final class UpdateConfigs {
/**
* @param filename searches by given filename
- * @param config searches in {@link UpdateConfig#getStreamingMetadata()}
+ * @param config searches in {@link UpdateConfig#getAbConfig()}
* @return offset and size of {@code filename} in the package zip file
* stored as {@link UpdateConfig.PackageFile}.
*/
@@ -91,7 +91,7 @@ public final class UpdateConfigs {
final String filename,
UpdateConfig config) {
return Arrays
- .stream(config.getStreamingMetadata().getPropertyFiles())
+ .stream(config.getAbConfig().getPropertyFiles())
.filter(file -> filename.equals(file.getFilename()))
.findFirst();
}
diff --git a/updater_sample/tests/res/raw/update_config_001_stream.json b/updater_sample/tests/res/raw/update_config_001_stream.json
index be51b7c95..b024ad947 100644
--- a/updater_sample/tests/res/raw/update_config_001_stream.json
+++ b/updater_sample/tests/res/raw/update_config_001_stream.json
@@ -2,7 +2,9 @@
"name": "streaming-001",
"url": "http://foo.bar/update.zip",
"ab_install_type": "STREAMING",
- "ab_streaming_metadata": {
+ "ab_config": {
+ "verify_payload_metadata": true,
+ "force_switch_slot": true,
"property_files": [
{
"filename": "payload.bin",
@@ -10,8 +12,5 @@
"size": 8
}
]
- },
- "ab_config": {
- "force_switch_slot": true
}
}
diff --git a/updater_sample/tests/res/raw/update_config_002_stream.json b/updater_sample/tests/res/raw/update_config_002_stream.json
index 40c8fe1c1..12c18bb70 100644
--- a/updater_sample/tests/res/raw/update_config_002_stream.json
+++ b/updater_sample/tests/res/raw/update_config_002_stream.json
@@ -1,10 +1,8 @@
{
"__": "*** Generated using tools/gen_update_config.py ***",
"ab_config": {
- "force_switch_slot": false
- },
- "ab_install_type": "STREAMING",
- "ab_streaming_metadata": {
+ "verify_payload_metadata": true,
+ "force_switch_slot": false,
"property_files": [
{
"filename": "payload_metadata.bin",
@@ -38,6 +36,7 @@
}
]
},
+ "ab_install_type": "STREAMING",
"name": "S ota_002_package",
"url": "file:///data/my-sample-ota-builds-dir/ota_002_package.zip"
} \ No newline at end of file
diff --git a/updater_sample/tests/res/raw/update_config_003_nonstream.json b/updater_sample/tests/res/raw/update_config_003_nonstream.json
index 7c78b9d21..2011f76d9 100644
--- a/updater_sample/tests/res/raw/update_config_003_nonstream.json
+++ b/updater_sample/tests/res/raw/update_config_003_nonstream.json
@@ -1,7 +1,15 @@
{
"__": "*** Generated using tools/gen_update_config.py ***",
"ab_config": {
- "force_switch_slot": false
+ "verify_payload_metadata": true,
+ "force_switch_slot": false,
+ "property_files": [
+ {
+ "filename": "payload.bin",
+ "offset": 195,
+ "size": 8
+ }
+ ]
},
"ab_install_type": "NON_STREAMING",
"name": "S ota_002_package",
diff --git a/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java
index 1cbd8601e..48d0e424d 100644
--- a/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java
+++ b/updater_sample/tests/src/com/example/android/systemupdatersample/UpdateConfigTest.java
@@ -44,10 +44,12 @@ import java.io.InputStreamReader;
@SmallTest
public class UpdateConfigTest {
- private static final String JSON_NON_STREAMING =
- "{\"name\": \"vip update\", \"url\": \"file:///builds/a.zip\", "
- + " \"ab_install_type\": \"NON_STREAMING\","
- + " \"ab_config\": { \"force_switch_slot\": false } }";
+ private static final String JSON_NON_STREAMING = "{"
+ + " \"name\": \"vip update\", \"url\": \"file:///my-builds/a.zip\","
+ + " \"ab_install_type\": \"NON_STREAMING\","
+ + " \"ab_config\": {"
+ + " \"force_switch_slot\": false,"
+ + " \"verify_payload_metadata\": false } }";
@Rule
public final ExpectedException thrown = ExpectedException.none();
@@ -71,7 +73,7 @@ public class UpdateConfigTest {
assertSame("type is parsed",
UpdateConfig.AB_INSTALL_TYPE_NON_STREAMING,
config.getInstallType());
- assertEquals("url is parsed", "file:///builds/a.zip", config.getUrl());
+ assertEquals("url is parsed", "file:///my-builds/a.zip", config.getUrl());
}
@Test
@@ -81,9 +83,9 @@ public class UpdateConfigTest {
assertEquals("http://foo.bar/update.zip", config.getUrl());
assertSame(UpdateConfig.AB_INSTALL_TYPE_STREAMING, config.getInstallType());
assertEquals("payload.bin",
- config.getStreamingMetadata().getPropertyFiles()[0].getFilename());
- assertEquals(195, config.getStreamingMetadata().getPropertyFiles()[0].getOffset());
- assertEquals(8, config.getStreamingMetadata().getPropertyFiles()[0].getSize());
+ config.getAbConfig().getPropertyFiles()[0].getFilename());
+ assertEquals(195, config.getAbConfig().getPropertyFiles()[0].getOffset());
+ assertEquals(8, config.getAbConfig().getPropertyFiles()[0].getSize());
assertTrue(config.getAbConfig().getForceSwitchSlot());
}
@@ -96,9 +98,12 @@ public class UpdateConfigTest {
@Test
public void getUpdatePackageFile_throwsErrorIfNotAFile() throws Exception {
- String json = "{\"name\": \"upd\", \"url\": \"http://foo.bar\","
+ String json = "{"
+ + " \"name\": \"upd\", \"url\": \"http://foo.bar\","
+ " \"ab_install_type\": \"NON_STREAMING\","
- + " \"ab_config\": { \"force_switch_slot\": false } }";
+ + " \"ab_config\": {"
+ + " \"force_switch_slot\": false,"
+ + " \"verify_payload_metadata\": false } }";
UpdateConfig config = UpdateConfig.fromJson(json);
thrown.expect(RuntimeException.class);
config.getUpdatePackageFile();
@@ -107,7 +112,7 @@ public class UpdateConfigTest {
@Test
public void getUpdatePackageFile_works() throws Exception {
UpdateConfig c = UpdateConfig.fromJson(JSON_NON_STREAMING);
- assertEquals("/builds/a.zip", c.getUpdatePackageFile().getAbsolutePath());
+ assertEquals("/my-builds/a.zip", c.getUpdatePackageFile().getAbsolutePath());
}
private String readResource(int id) throws IOException {
diff --git a/updater_sample/tools/gen_update_config.py b/updater_sample/tools/gen_update_config.py
index b43e49df8..f2cb1a8bd 100755
--- a/updater_sample/tools/gen_update_config.py
+++ b/updater_sample/tools/gen_update_config.py
@@ -46,11 +46,17 @@ class GenUpdateConfig(object):
AB_INSTALL_TYPE_STREAMING = 'STREAMING'
AB_INSTALL_TYPE_NON_STREAMING = 'NON_STREAMING'
- def __init__(self, package, url, ab_install_type, ab_force_switch_slot):
+ def __init__(self,
+ package,
+ url,
+ ab_install_type,
+ ab_force_switch_slot,
+ ab_verify_payload_metadata):
self.package = package
self.url = url
self.ab_install_type = ab_install_type
self.ab_force_switch_slot = ab_force_switch_slot
+ self.ab_verify_payload_metadata = ab_verify_payload_metadata
self.streaming_required = (
# payload.bin and payload_properties.txt must exist.
'payload.bin',
@@ -71,29 +77,24 @@ class GenUpdateConfig(object):
def run(self):
"""Generates config."""
- streaming_metadata = None
- if self.ab_install_type == GenUpdateConfig.AB_INSTALL_TYPE_STREAMING:
- streaming_metadata = self._gen_ab_streaming_metadata()
-
self._config = {
'__': '*** Generated using tools/gen_update_config.py ***',
'name': self.ab_install_type[0] + ' ' + os.path.basename(self.package)[:-4],
'url': self.url,
- 'ab_streaming_metadata': streaming_metadata,
+ 'ab_config': self._gen_ab_config(),
'ab_install_type': self.ab_install_type,
- 'ab_config': {
- 'force_switch_slot': self.ab_force_switch_slot,
- }
}
- def _gen_ab_streaming_metadata(self):
- """Builds metadata for files required for streaming update."""
+ def _gen_ab_config(self):
+ """Builds config required for A/B update."""
with zipfile.ZipFile(self.package, 'r') as package_zip:
- metadata = {
- 'property_files': self._get_property_files(package_zip)
+ config = {
+ 'property_files': self._get_property_files(package_zip),
+ 'verify_payload_metadata': self.ab_verify_payload_metadata,
+ 'force_switch_slot': self.ab_force_switch_slot,
}
- return metadata
+ return config
@staticmethod
def _get_property_files(package_zip):
@@ -135,6 +136,11 @@ def main(): # pylint: disable=missing-docstring
action='store_true',
help='if set device will boot to a new slot, otherwise user '
'manually switches slot on the screen')
+ parser.add_argument('--ab_verify_payload_metadata',
+ default=False,
+ action='store_true',
+ help='if set the app will verify the update payload metadata using '
+ 'update_engine before downloading the whole package.')
parser.add_argument('package',
type=str,
help='OTA package zip file')
@@ -154,7 +160,8 @@ def main(): # pylint: disable=missing-docstring
package=args.package,
url=args.url,
ab_install_type=args.ab_install_type,
- ab_force_switch_slot=args.ab_force_switch_slot)
+ ab_force_switch_slot=args.ab_force_switch_slot,
+ ab_verify_payload_metadata=args.ab_verify_payload_metadata)
gen.run()
gen.write(args.out)
print('Config is written to ' + args.out)
diff --git a/updater_sample/tools/test_gen_update_config.py b/updater_sample/tools/test_gen_update_config.py
index c907cf2f9..8b77cb2a2 100755
--- a/updater_sample/tools/test_gen_update_config.py
+++ b/updater_sample/tools/test_gen_update_config.py
@@ -32,7 +32,7 @@ class GenUpdateConfigTest(unittest.TestCase): # pylint: disable=missing-docstrin
def test_ab_install_type_streaming(self):
"""tests if streaming property files' offset and size are generated properly"""
config, package = self._generate_config()
- property_files = config['ab_streaming_metadata']['property_files']
+ property_files = config['ab_config']['property_files']
self.assertEqual(len(property_files), 6)
with open(package, 'rb') as pkg_file:
for prop in property_files:
@@ -56,6 +56,8 @@ class GenUpdateConfigTest(unittest.TestCase): # pylint: disable=missing-docstrin
'../tests/res/raw/ota_002_package.zip')
gen = GenUpdateConfig(ota_package,
'file:///foo.bar',
- GenUpdateConfig.AB_INSTALL_TYPE_STREAMING)
+ GenUpdateConfig.AB_INSTALL_TYPE_STREAMING,
+ True, # ab_force_switch_slot
+ True) # ab_verify_payload_metadata
gen.run()
return gen.config, ota_package