summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--applypatch/Android.bp1
-rw-r--r--applypatch/imgdiff.cpp12
-rw-r--r--applypatch/imgpatch.cpp39
-rw-r--r--applypatch/include/applypatch/imgdiff_image.h5
-rw-r--r--minui/Android.mk2
-rw-r--r--tests/Android.mk1
-rw-r--r--tests/common/test_constants.h12
-rw-r--r--tests/component/imgdiff_test.cpp105
-rw-r--r--tests/component/install_test.cpp26
-rw-r--r--tests/component/updater_test.cpp222
-rw-r--r--tests/testdata/deflate_src.zipbin0 -> 164491 bytes
-rw-r--r--tests/testdata/deflate_tgt.zipbin0 -> 160385 bytes
-rw-r--r--tools/recovery_l10n/res/values-hi/strings.xml2
-rw-r--r--tools/recovery_l10n/res/values-mr/strings.xml8
-rw-r--r--tools/recovery_l10n/res/values-pa/strings.xml6
-rw-r--r--tools/recovery_l10n/res/values-te/strings.xml2
-rw-r--r--update_verifier/update_verifier.cpp8
-rw-r--r--updater/blockimg.cpp57
18 files changed, 287 insertions, 221 deletions
diff --git a/applypatch/Android.bp b/applypatch/Android.bp
index 922f67abf..4d2d4b76a 100644
--- a/applypatch/Android.bp
+++ b/applypatch/Android.bp
@@ -158,6 +158,7 @@ cc_binary_host {
"libbase",
"libutils",
"liblog",
+ "libbrotli",
"libbz",
"libz",
],
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 69ad75f37..f57e7942c 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -163,7 +163,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <bsdiff.h>
+#include <bsdiff/bsdiff.h>
#include <ziparchive/zip_archive.h>
#include <zlib.h>
@@ -324,7 +324,8 @@ void ImageChunk::MergeAdjacentNormal(const ImageChunk& other) {
}
bool ImageChunk::MakePatch(const ImageChunk& tgt, const ImageChunk& src,
- std::vector<uint8_t>* patch_data, saidx_t** bsdiff_cache) {
+ std::vector<uint8_t>* patch_data,
+ bsdiff::SuffixArrayIndexInterface** bsdiff_cache) {
#if defined(__ANDROID__)
char ptemp[] = "/data/local/tmp/imgdiff-patch-XXXXXX";
#else
@@ -1083,7 +1084,7 @@ bool ZipModeImage::GeneratePatchesInternal(const ZipModeImage& tgt_image,
printf("Construct patches for %zu chunks...\n", tgt_image.NumOfChunks());
patch_chunks->clear();
- saidx_t* bsdiff_cache = nullptr;
+ bsdiff::SuffixArrayIndexInterface* bsdiff_cache = nullptr;
for (size_t i = 0; i < tgt_image.NumOfChunks(); i++) {
const auto& tgt_chunk = tgt_image[i];
@@ -1097,7 +1098,8 @@ bool ZipModeImage::GeneratePatchesInternal(const ZipModeImage& tgt_image,
: src_image.FindChunkByName(tgt_chunk.GetEntryName());
const auto& src_ref = (src_chunk == nullptr) ? src_image.PseudoSource() : *src_chunk;
- saidx_t** bsdiff_cache_ptr = (src_chunk == nullptr) ? &bsdiff_cache : nullptr;
+ bsdiff::SuffixArrayIndexInterface** bsdiff_cache_ptr =
+ (src_chunk == nullptr) ? &bsdiff_cache : nullptr;
std::vector<uint8_t> patch_data;
if (!ImageChunk::MakePatch(tgt_chunk, src_ref, &patch_data, bsdiff_cache_ptr)) {
@@ -1114,7 +1116,7 @@ bool ZipModeImage::GeneratePatchesInternal(const ZipModeImage& tgt_image,
patch_chunks->emplace_back(tgt_chunk, src_ref, std::move(patch_data));
}
}
- free(bsdiff_cache);
+ delete bsdiff_cache;
CHECK_EQ(patch_chunks->size(), tgt_image.NumOfChunks());
return true;
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp
index 7a43ddbef..25ba0a182 100644
--- a/applypatch/imgpatch.cpp
+++ b/applypatch/imgpatch.cpp
@@ -59,13 +59,13 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
int mem_level = Read4(deflate_header + 52);
int strategy = Read4(deflate_header + 56);
- std::unique_ptr<z_stream, decltype(&deflateEnd)> strm(new z_stream(), deflateEnd);
- strm->zalloc = Z_NULL;
- strm->zfree = Z_NULL;
- strm->opaque = Z_NULL;
- strm->avail_in = 0;
- strm->next_in = nullptr;
- int ret = deflateInit2(strm.get(), level, method, window_bits, mem_level, strategy);
+ z_stream strm;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
+ strm.opaque = Z_NULL;
+ strm.avail_in = 0;
+ strm.next_in = nullptr;
+ int ret = deflateInit2(&strm, level, method, window_bits, mem_level, strategy);
if (ret != Z_OK) {
LOG(ERROR) << "Failed to init uncompressed data deflation: " << ret;
return false;
@@ -76,18 +76,19 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
size_t actual_target_length = 0;
size_t total_written = 0;
static constexpr size_t buffer_size = 32768;
- auto compression_sink = [&](const uint8_t* data, size_t len) -> size_t {
+ auto compression_sink = [&strm, &actual_target_length, &expected_target_length, &total_written,
+ &ret, &ctx, &sink](const uint8_t* data, size_t len) -> size_t {
// The input patch length for an update never exceeds INT_MAX.
- strm->avail_in = len;
- strm->next_in = data;
+ strm.avail_in = len;
+ strm.next_in = data;
do {
std::vector<uint8_t> buffer(buffer_size);
- strm->avail_out = buffer_size;
- strm->next_out = buffer.data();
+ strm.avail_out = buffer_size;
+ strm.next_out = buffer.data();
if (actual_target_length + len < expected_target_length) {
- ret = deflate(strm.get(), Z_NO_FLUSH);
+ ret = deflate(&strm, Z_NO_FLUSH);
} else {
- ret = deflate(strm.get(), Z_FINISH);
+ ret = deflate(&strm, Z_FINISH);
}
if (ret != Z_OK && ret != Z_STREAM_END) {
LOG(ERROR) << "Failed to deflate stream: " << ret;
@@ -95,20 +96,24 @@ static bool ApplyBSDiffPatchAndStreamOutput(const uint8_t* src_data, size_t src_
return 0;
}
- size_t have = buffer_size - strm->avail_out;
+ size_t have = buffer_size - strm.avail_out;
total_written += have;
if (sink(buffer.data(), have) != have) {
LOG(ERROR) << "Failed to write " << have << " compressed bytes to output.";
return 0;
}
if (ctx) SHA1_Update(ctx, buffer.data(), have);
- } while ((strm->avail_in != 0 || strm->avail_out == 0) && ret != Z_STREAM_END);
+ } while ((strm.avail_in != 0 || strm.avail_out == 0) && ret != Z_STREAM_END);
actual_target_length += len;
return len;
};
- if (ApplyBSDiffPatch(src_data, src_len, patch, patch_offset, compression_sink, nullptr) != 0) {
+ int bspatch_result =
+ ApplyBSDiffPatch(src_data, src_len, patch, patch_offset, compression_sink, nullptr);
+ deflateEnd(&strm);
+
+ if (bspatch_result != 0) {
return false;
}
diff --git a/applypatch/include/applypatch/imgdiff_image.h b/applypatch/include/applypatch/imgdiff_image.h
index 3d29547cb..00a84f3a9 100644
--- a/applypatch/include/applypatch/imgdiff_image.h
+++ b/applypatch/include/applypatch/imgdiff_image.h
@@ -24,7 +24,7 @@
#include <string>
#include <vector>
-#include <bsdiff.h>
+#include <bsdiff/bsdiff.h>
#include <ziparchive/zip_archive.h>
#include <zlib.h>
@@ -98,7 +98,8 @@ class ImageChunk {
* repeatedly, pass nullptr if not needed.
*/
static bool MakePatch(const ImageChunk& tgt, const ImageChunk& src,
- std::vector<uint8_t>* patch_data, saidx_t** bsdiff_cache);
+ std::vector<uint8_t>* patch_data,
+ bsdiff::SuffixArrayIndexInterface** bsdiff_cache);
private:
const uint8_t* GetRawData() const;
diff --git a/minui/Android.mk b/minui/Android.mk
index 546ba2fe5..ae1552b1b 100644
--- a/minui/Android.mk
+++ b/minui/Android.mk
@@ -28,7 +28,7 @@ LOCAL_SRC_FILES := \
LOCAL_WHOLE_STATIC_LIBRARIES := \
libadf \
- libdrm_platform \
+ libdrm \
libsync_recovery
LOCAL_STATIC_LIBRARIES := \
diff --git a/tests/Android.mk b/tests/Android.mk
index b0f71a832..8ebb60308 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -208,6 +208,7 @@ LOCAL_STATIC_LIBRARIES := \
libutils \
libbase \
libcrypto \
+ libbrotli \
libbz \
libdivsufsort64 \
libdivsufsort \
diff --git a/tests/common/test_constants.h b/tests/common/test_constants.h
index f6b6922a4..514818e0a 100644
--- a/tests/common/test_constants.h
+++ b/tests/common/test_constants.h
@@ -19,6 +19,8 @@
#include <stdlib.h>
+#include <string>
+
// Zip entries in ziptest_valid.zip.
static const std::string kATxtContents("abcdefghabcdefgh\n");
static const std::string kBTxtContents("abcdefgh\n");
@@ -30,10 +32,14 @@ static const std::string kATxtSha1Sum("32c96a03dc8cd20097940f351bca6261ee5a1643"
// echo -n -e "abcdefgh\n" | sha1sum
static const std::string kBTxtSha1Sum("e414af7161c9554089f4106d6f1797ef14a73666");
-static const char* data_root = getenv("ANDROID_DATA");
-
static std::string from_testdata_base(const std::string& fname) {
- return std::string(data_root) + "/nativetest/recovery/testdata/" + fname;
+#ifdef __ANDROID__
+ static std::string data_root = getenv("ANDROID_DATA");
+#else
+ static std::string data_root = std::string(getenv("ANDROID_PRODUCT_OUT")) + "/data";
+#endif
+
+ return data_root + "/nativetest/recovery/testdata/" + fname;
}
#endif // _OTA_TEST_CONSTANTS_H
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index bf591dae4..6de804e06 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -32,6 +32,8 @@
#include <gtest/gtest.h>
#include <ziparchive/zip_writer.h>
+#include "common/test_constants.h"
+
using android::base::get_unaligned;
// Sanity check for the given imgdiff patch header.
@@ -148,7 +150,7 @@ TEST(ImgdiffTest, image_mode_smoke) {
TEST(ImgdiffTest, zip_mode_smoke_store) {
// Construct src and tgt zip files.
TemporaryFile src_file;
- FILE* src_file_ptr = fdopen(src_file.fd, "wb");
+ FILE* src_file_ptr = fdopen(src_file.release(), "wb");
ZipWriter src_writer(src_file_ptr);
ASSERT_EQ(0, src_writer.StartEntry("file1.txt", 0)); // Store mode.
const std::string src_content("abcdefg");
@@ -158,7 +160,7 @@ TEST(ImgdiffTest, zip_mode_smoke_store) {
ASSERT_EQ(0, fclose(src_file_ptr));
TemporaryFile tgt_file;
- FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
+ FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
ZipWriter tgt_writer(tgt_file_ptr);
ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", 0)); // Store mode.
const std::string tgt_content("abcdefgxyz");
@@ -197,7 +199,7 @@ TEST(ImgdiffTest, zip_mode_smoke_store) {
TEST(ImgdiffTest, zip_mode_smoke_compressed) {
// Construct src and tgt zip files.
TemporaryFile src_file;
- FILE* src_file_ptr = fdopen(src_file.fd, "wb");
+ FILE* src_file_ptr = fdopen(src_file.release(), "wb");
ZipWriter src_writer(src_file_ptr);
ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
const std::string src_content("abcdefg");
@@ -207,7 +209,7 @@ TEST(ImgdiffTest, zip_mode_smoke_compressed) {
ASSERT_EQ(0, fclose(src_file_ptr));
TemporaryFile tgt_file;
- FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
+ FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
ZipWriter tgt_writer(tgt_file_ptr);
ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
const std::string tgt_content("abcdefgxyz");
@@ -246,7 +248,7 @@ TEST(ImgdiffTest, zip_mode_smoke_compressed) {
TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
// Construct src and tgt zip files.
TemporaryFile src_file;
- FILE* src_file_ptr = fdopen(src_file.fd, "wb");
+ FILE* src_file_ptr = fdopen(src_file.release(), "wb");
ZipWriter src_writer(src_file_ptr);
ASSERT_EQ(0, src_writer.StartEntry("file1.txt", ZipWriter::kCompress));
const std::string src_content("abcdefg");
@@ -256,7 +258,7 @@ TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
ASSERT_EQ(0, fclose(src_file_ptr));
TemporaryFile tgt_file;
- FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
+ FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
ZipWriter tgt_writer(tgt_file_ptr);
ASSERT_EQ(0, tgt_writer.StartEntry("file1.txt", ZipWriter::kCompress));
const std::string tgt_content("abcdefgxyz");
@@ -761,7 +763,7 @@ TEST(ImgdiffTest, zip_mode_store_large_apk) {
// 3 blocks 'a' 12 blocks 'd' (exceeds limit)
// 3 blocks 'e'
TemporaryFile tgt_file;
- FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
+ FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
ZipWriter tgt_writer(tgt_file_ptr);
construct_store_entry(
{ { "a", 3, 'a' }, { "b", 3, 'b' }, { "c", 8, 'c' }, { "d", 12, 'd' }, { "e", 3, 'e' } },
@@ -770,7 +772,7 @@ TEST(ImgdiffTest, zip_mode_store_large_apk) {
ASSERT_EQ(0, fclose(tgt_file_ptr));
TemporaryFile src_file;
- FILE* src_file_ptr = fdopen(src_file.fd, "wb");
+ FILE* src_file_ptr = fdopen(src_file.release(), "wb");
ZipWriter src_writer(src_file_ptr);
construct_store_entry({ { "d", 12, 'd' }, { "c", 8, 'c' }, { "b", 3, 'b' }, { "a", 3, 'a' } },
&src_writer);
@@ -792,49 +794,26 @@ TEST(ImgdiffTest, zip_mode_store_large_apk) {
std::string tgt;
ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
- // Expect 4 pieces of patch.(Rougly 3'a',3'b'; 8'c'; 10'd'; 2'd'3'e')
+ // Expect 4 pieces of patch. (Roughly 3'a',3'b'; 8'c'; 10'd'; 2'd'3'e')
GenerateAndCheckSplitTarget(debug_dir.path, 4, tgt);
}
TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
- // Generate 50 blocks of random data.
- std::string random_data;
- random_data.reserve(4096 * 50);
- generate_n(back_inserter(random_data), 4096 * 50, []() { return rand() % 256; });
-
- // Construct src and tgt zip files with limit = 10 blocks.
+ // Src and tgt zip files are constructed as follows.
// src tgt
// 22 blocks, "d" 4 blocks, "a"
// 5 blocks, "b" 4 blocks, "b"
- // 3 blocks, "a" 7 blocks, "c" (exceeds limit)
- // 8 blocks, "c" 20 blocks, "d" (exceeds limit)
- // 1 block, "f" 2 blocks, "e"
- TemporaryFile tgt_file;
- FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
- ZipWriter tgt_writer(tgt_file_ptr);
-
- construct_deflate_entry(
- { { "a", 0, 4 }, { "b", 5, 4 }, { "c", 12, 8 }, { "d", 21, 20 }, { "e", 45, 2 },
- { "f", 48, 1 } }, &tgt_writer, random_data);
-
- ASSERT_EQ(0, tgt_writer.Finish());
- ASSERT_EQ(0, fclose(tgt_file_ptr));
-
- TemporaryFile src_file;
- FILE* src_file_ptr = fdopen(src_file.fd, "wb");
- ZipWriter src_writer(src_file_ptr);
-
- construct_deflate_entry(
- { { "d", 21, 22 }, { "b", 5, 5 }, { "a", 0, 3 }, { "g", 9, 1 }, { "c", 11, 8 },
- { "f", 45, 1 } }, &src_writer, random_data);
-
- ASSERT_EQ(0, src_writer.Finish());
- ASSERT_EQ(0, fclose(src_file_ptr));
+ // 3 blocks, "a" 8 blocks, "c" (exceeds limit)
+ // 1 block, "g" 20 blocks, "d" (exceeds limit)
+ // 8 blocks, "c" 2 blocks, "e"
+ // 1 block, "f" 1 block , "f"
+ std::string tgt_path = from_testdata_base("deflate_tgt.zip");
+ std::string src_path = from_testdata_base("deflate_src.zip");
ZipModeImage src_image(true, 10 * 4096);
ZipModeImage tgt_image(false, 10 * 4096);
- ASSERT_TRUE(src_image.Initialize(src_file.path));
- ASSERT_TRUE(tgt_image.Initialize(tgt_file.path));
+ ASSERT_TRUE(src_image.Initialize(src_path));
+ ASSERT_TRUE(tgt_image.Initialize(tgt_path));
ASSERT_TRUE(ZipModeImage::CheckAndProcessChunks(&tgt_image, &src_image));
src_image.DumpChunks();
@@ -846,11 +825,12 @@ TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
ZipModeImage::SplitZipModeImageWithLimit(tgt_image, src_image, &split_tgt_images,
&split_src_images, &split_src_ranges);
- // src_piece 1: a 3 blocks, b 5 blocks
- // src_piece 2: c 8 blocks
- // src_piece 3: d-0 10 block
- // src_piece 4: d-1 10 blocks
- // src_piece 5: e 1 block, CD
+ // Expected split images with limit = 10 blocks.
+ // src_piece 0: a 3 blocks, b 5 blocks
+ // src_piece 1: c 8 blocks
+ // src_piece 2: d-0 10 block
+ // src_piece 3: d-1 10 blocks
+ // src_piece 4: e 1 block, CD
ASSERT_EQ(split_tgt_images.size(), split_src_images.size());
ASSERT_EQ(static_cast<size_t>(5), split_tgt_images.size());
@@ -883,24 +863,21 @@ TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
ASSERT_EQ("2", android::base::Trim(info_list[0]));
ASSERT_EQ("5", android::base::Trim(info_list[1]));
- std::vector<size_t> patch_size;
+ std::string tgt;
+ ASSERT_TRUE(android::base::ReadFileToString(tgt_path, &tgt));
+ ASSERT_EQ(static_cast<size_t>(160385), tgt.size());
+ std::vector<std::string> tgt_file_ranges = {
+ "36864 2,22,31", "32768 2,31,40", "40960 2,0,11", "40960 2,11,21", "8833 4,21,22,40,41",
+ };
+
for (size_t i = 0; i < 5; i++) {
- struct stat st = {};
+ struct stat st;
std::string path = android::base::StringPrintf("%s/patch-%zu", debug_dir.path, i);
ASSERT_EQ(0, stat(path.c_str(), &st));
- patch_size.push_back(st.st_size);
+ ASSERT_EQ(std::to_string(st.st_size) + " " + tgt_file_ranges[i],
+ android::base::Trim(info_list[i + 2]));
}
- ASSERT_EQ(std::to_string(patch_size[0]) + " 36864 2,22,31", android::base::Trim(info_list[2]));
- ASSERT_EQ(std::to_string(patch_size[1]) + " 32768 2,31,40", android::base::Trim(info_list[3]));
- ASSERT_EQ(std::to_string(patch_size[2]) + " 40960 2,0,11", android::base::Trim(info_list[4]));
- ASSERT_EQ(std::to_string(patch_size[3]) + " 40960 2,11,21", android::base::Trim(info_list[5]));
- ASSERT_EQ(std::to_string(patch_size[4]) + " 8833 4,21,22,40,41",
- android::base::Trim(info_list[6]));
-
- std::string tgt;
- ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
-
GenerateAndCheckSplitTarget(debug_dir.path, 5, tgt);
}
@@ -911,7 +888,7 @@ TEST(ImgdiffTest, zip_mode_no_match_source) {
generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
TemporaryFile tgt_file;
- FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
+ FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
ZipWriter tgt_writer(tgt_file_ptr);
construct_deflate_entry({ { "a", 0, 4 }, { "b", 5, 5 }, { "c", 11, 5 } }, &tgt_writer,
@@ -922,7 +899,7 @@ TEST(ImgdiffTest, zip_mode_no_match_source) {
// We don't have a matching source entry.
TemporaryFile src_file;
- FILE* src_file_ptr = fdopen(src_file.fd, "wb");
+ FILE* src_file_ptr = fdopen(src_file.release(), "wb");
ZipWriter src_writer(src_file_ptr);
construct_store_entry({ { "d", 1, 'd' } }, &src_writer);
ASSERT_EQ(0, src_writer.Finish());
@@ -954,7 +931,7 @@ TEST(ImgdiffTest, zip_mode_large_enough_limit) {
generate_n(back_inserter(random_data), 4096 * 20, []() { return rand() % 256; });
TemporaryFile tgt_file;
- FILE* tgt_file_ptr = fdopen(tgt_file.fd, "wb");
+ FILE* tgt_file_ptr = fdopen(tgt_file.release(), "wb");
ZipWriter tgt_writer(tgt_file_ptr);
construct_deflate_entry({ { "a", 0, 10 }, { "b", 10, 5 } }, &tgt_writer, random_data);
@@ -964,7 +941,7 @@ TEST(ImgdiffTest, zip_mode_large_enough_limit) {
// Construct 10 blocks of source.
TemporaryFile src_file;
- FILE* src_file_ptr = fdopen(src_file.fd, "wb");
+ FILE* src_file_ptr = fdopen(src_file.release(), "wb");
ZipWriter src_writer(src_file_ptr);
construct_deflate_entry({ { "a", 1, 10 } }, &src_writer, random_data);
ASSERT_EQ(0, src_writer.Finish());
@@ -985,6 +962,6 @@ TEST(ImgdiffTest, zip_mode_large_enough_limit) {
std::string tgt;
ASSERT_TRUE(android::base::ReadFileToString(tgt_file.path, &tgt));
- // Expect 1 pieces of patch since limit is larger than the zip file size.
+ // Expect 1 piece of patch since limit is larger than the zip file size.
GenerateAndCheckSplitTarget(debug_dir.path, 1, tgt);
}
diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp
index 7bb496066..d19d788e4 100644
--- a/tests/component/install_test.cpp
+++ b/tests/component/install_test.cpp
@@ -37,7 +37,7 @@
TEST(InstallTest, verify_package_compatibility_no_entry) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
// The archive must have something to be opened correctly.
ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
@@ -54,7 +54,7 @@ TEST(InstallTest, verify_package_compatibility_no_entry) {
TEST(InstallTest, verify_package_compatibility_invalid_entry) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
ASSERT_EQ(0, writer.StartEntry("compatibility.zip", 0));
ASSERT_EQ(0, writer.FinishEntry());
@@ -70,7 +70,7 @@ TEST(InstallTest, verify_package_compatibility_invalid_entry) {
TEST(InstallTest, read_metadata_from_package_smoke) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
ASSERT_EQ(0, writer.StartEntry("META-INF/com/android/metadata", kCompressStored));
const std::string content("abcdefg");
@@ -87,7 +87,7 @@ TEST(InstallTest, read_metadata_from_package_smoke) {
CloseArchive(zip);
TemporaryFile temp_file2;
- FILE* zip_file2 = fdopen(temp_file2.fd, "w");
+ FILE* zip_file2 = fdopen(temp_file2.release(), "w");
ZipWriter writer2(zip_file2);
ASSERT_EQ(0, writer2.StartEntry("META-INF/com/android/metadata", kCompressDeflated));
ASSERT_EQ(0, writer2.WriteBytes(content.data(), content.size()));
@@ -104,7 +104,7 @@ TEST(InstallTest, read_metadata_from_package_smoke) {
TEST(InstallTest, read_metadata_from_package_no_entry) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
ASSERT_EQ(0, writer.StartEntry("dummy_entry", kCompressStored));
ASSERT_EQ(0, writer.FinishEntry());
@@ -120,7 +120,7 @@ TEST(InstallTest, read_metadata_from_package_no_entry) {
TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) {
TemporaryFile compatibility_zip_file;
- FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w");
+ FILE* compatibility_zip = fdopen(compatibility_zip_file.release(), "w");
ZipWriter compatibility_zip_writer(compatibility_zip);
ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
std::string malformed_xml = "malformed";
@@ -130,7 +130,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_malformed_xml) {
ASSERT_EQ(0, fclose(compatibility_zip));
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
std::string compatibility_zip_content;
@@ -165,7 +165,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml
ASSERT_TRUE(
android::base::ReadFileToString(system_manifest_xml_path, &system_manifest_xml_content));
TemporaryFile compatibility_zip_file;
- FILE* compatibility_zip = fdopen(compatibility_zip_file.fd, "w");
+ FILE* compatibility_zip = fdopen(compatibility_zip_file.release(), "w");
ZipWriter compatibility_zip_writer(compatibility_zip);
ASSERT_EQ(0, compatibility_zip_writer.StartEntry("system_manifest.xml", kCompressDeflated));
ASSERT_EQ(0, compatibility_zip_writer.WriteBytes(system_manifest_xml_content.data(),
@@ -175,7 +175,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml
ASSERT_EQ(0, fclose(compatibility_zip));
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
ASSERT_EQ(0, writer.StartEntry("compatibility.zip", kCompressStored));
std::string compatibility_zip_content;
@@ -202,7 +202,7 @@ TEST(InstallTest, verify_package_compatibility_with_libvintf_system_manifest_xml
#ifdef AB_OTA_UPDATER
static void VerifyAbUpdateBinaryCommand(const std::string& serialno, bool success = true) {
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
ASSERT_EQ(0, writer.FinishEntry());
@@ -258,7 +258,7 @@ TEST(InstallTest, update_binary_command_smoke) {
VerifyAbUpdateBinaryCommand({});
#else
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
static constexpr const char* UPDATE_BINARY_NAME = "META-INF/com/google/android/update-binary";
ASSERT_EQ(0, writer.StartEntry(UPDATE_BINARY_NAME, kCompressStored));
@@ -303,7 +303,7 @@ TEST(InstallTest, update_binary_command_smoke) {
TEST(InstallTest, update_binary_command_invalid) {
#ifdef AB_OTA_UPDATER
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
// Missing payload_properties.txt.
ASSERT_EQ(0, writer.StartEntry("payload.bin", kCompressStored));
@@ -334,7 +334,7 @@ TEST(InstallTest, update_binary_command_invalid) {
CloseArchive(zip);
#else
TemporaryFile temp_file;
- FILE* zip_file = fdopen(temp_file.fd, "w");
+ FILE* zip_file = fdopen(temp_file.release(), "w");
ZipWriter writer(zip_file);
// The archive must have something to be opened correctly.
ASSERT_EQ(0, writer.StartEntry("dummy_entry", 0));
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index e6aec4ad6..d9d01d427 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -23,6 +23,7 @@
#include <algorithm>
#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include <android-base/file.h>
@@ -32,7 +33,7 @@
#include <android-base/test_utils.h>
#include <bootloader_message/bootloader_message.h>
#include <brotli/encode.h>
-#include <bsdiff.h>
+#include <bsdiff/bsdiff.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_archive.h>
#include <ziparchive/zip_writer.h>
@@ -74,6 +75,23 @@ static void expect(const char* expected, const char* expr_str, CauseCode cause_c
ASSERT_EQ(cause_code, state.cause_code);
}
+static void BuildUpdatePackage(const std::unordered_map<std::string, std::string>& entries,
+ int fd) {
+ FILE* zip_file_ptr = fdopen(fd, "wb");
+ ZipWriter zip_writer(zip_file_ptr);
+
+ for (const auto& entry : entries) {
+ ASSERT_EQ(0, zip_writer.StartEntry(entry.first.c_str(), 0));
+ if (!entry.second.empty()) {
+ ASSERT_EQ(0, zip_writer.WriteBytes(entry.second.data(), entry.second.size()));
+ }
+ ASSERT_EQ(0, zip_writer.FinishEntry());
+ }
+
+ ASSERT_EQ(0, zip_writer.Finish());
+ ASSERT_EQ(0, fclose(zip_file_ptr));
+}
+
static std::string get_sha1(const std::string& content) {
uint8_t digest[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const uint8_t*>(content.c_str()), content.size(), digest);
@@ -420,30 +438,19 @@ TEST_F(UpdaterTest, show_progress) {
ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
}
-TEST_F(UpdaterTest, block_image_update) {
- // Create a zip file with new_data and patch_data.
- TemporaryFile zip_file;
- FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
- ZipWriter zip_writer(zip_file_ptr);
-
- // Add a dummy new data.
- ASSERT_EQ(0, zip_writer.StartEntry("new_data", 0));
- ASSERT_EQ(0, zip_writer.FinishEntry());
-
- // Generate and add the patch data.
+TEST_F(UpdaterTest, block_image_update_patch_data) {
std::string src_content = std::string(4096, 'a') + std::string(4096, 'c');
std::string tgt_content = std::string(4096, 'b') + std::string(4096, 'd');
+
+ // Generate the patch data.
TemporaryFile patch_file;
ASSERT_EQ(0, bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(src_content.data()),
src_content.size(), reinterpret_cast<const uint8_t*>(tgt_content.data()),
tgt_content.size(), patch_file.path, nullptr));
std::string patch_content;
ASSERT_TRUE(android::base::ReadFileToString(patch_file.path, &patch_content));
- ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
- ASSERT_EQ(0, zip_writer.WriteBytes(patch_content.data(), patch_content.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- // Add two transfer lists. The first one contains a bsdiff; and we expect the update to succeed.
+ // Create the transfer list that contains a bsdiff.
std::string src_hash = get_sha1(src_content);
std::string tgt_hash = get_sha1(tgt_content);
std::vector<std::string> transfer_list = {
@@ -456,27 +463,16 @@ TEST_F(UpdaterTest, block_image_update) {
src_hash.c_str(), tgt_hash.c_str(), src_hash.c_str()),
"free " + src_hash,
};
- ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0));
- std::string commands = android::base::Join(transfer_list, '\n');
- ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- // Stash and free some blocks, then fail the 2nd update intentionally.
- std::vector<std::string> fail_transfer_list = {
- "4",
- "2",
- "0",
- "2",
- "stash " + tgt_hash + " 2,0,2",
- "free " + tgt_hash,
- "fail",
+ std::unordered_map<std::string, std::string> entries = {
+ { "new_data", "" },
+ { "patch_data", patch_content },
+ { "transfer_list", android::base::Join(transfer_list, '\n') },
};
- ASSERT_EQ(0, zip_writer.StartEntry("fail_transfer_list", 0));
- std::string fail_commands = android::base::Join(fail_transfer_list, '\n');
- ASSERT_EQ(0, zip_writer.WriteBytes(fail_commands.data(), fail_commands.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- ASSERT_EQ(0, zip_writer.Finish());
- ASSERT_EQ(0, fclose(zip_file_ptr));
+
+ // Build the update package.
+ TemporaryFile zip_file;
+ BuildUpdatePackage(entries, zip_file.release());
MemMapping map;
ASSERT_TRUE(map.MapFile(zip_file.path));
@@ -491,7 +487,7 @@ TEST_F(UpdaterTest, block_image_update) {
updater_info.package_zip_addr = map.addr;
updater_info.package_zip_len = map.length;
- // Execute the commands in the 1st transfer list.
+ // Execute the commands in the transfer list.
TemporaryFile update_file;
ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
std::string script = "block_image_update(\"" + std::string(update_file.path) +
@@ -502,44 +498,98 @@ TEST_F(UpdaterTest, block_image_update) {
ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
ASSERT_EQ(tgt_hash, get_sha1(updated_content));
- // Expect the 2nd update to fail, but expect the stashed blocks to be freed.
- script = "block_image_update(\"" + std::string(update_file.path) +
- R"(", package_extract_file("fail_transfer_list"), "new_data", "patch_data"))";
+ ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
+ CloseArchive(handle);
+}
+
+TEST_F(UpdaterTest, block_image_update_fail) {
+ std::string src_content(4096 * 2, 'e');
+ std::string src_hash = get_sha1(src_content);
+ // Stash and free some blocks, then fail the update intentionally.
+ std::vector<std::string> transfer_list = {
+ "4", "2", "0", "2", "stash " + src_hash + " 2,0,2", "free " + src_hash, "fail",
+ };
+
+ // Add a new data of 10 bytes to test the deadlock.
+ std::unordered_map<std::string, std::string> entries = {
+ { "new_data", std::string(10, 0) },
+ { "patch_data", "" },
+ { "transfer_list", android::base::Join(transfer_list, '\n') },
+ };
+
+ // Build the update package.
+ TemporaryFile zip_file;
+ BuildUpdatePackage(entries, zip_file.release());
+
+ MemMapping map;
+ ASSERT_TRUE(map.MapFile(zip_file.path));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
+
+ // Set up the handler, command_pipe, patch offset & length.
+ UpdaterInfo updater_info;
+ updater_info.package_zip = handle;
+ TemporaryFile temp_pipe;
+ updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
+ updater_info.package_zip_addr = map.addr;
+ updater_info.package_zip_len = map.length;
+
+ TemporaryFile update_file;
+ ASSERT_TRUE(android::base::WriteStringToFile(src_content, update_file.path));
+ // Expect the stashed blocks to be freed.
+ std::string script = "block_image_update(\"" + std::string(update_file.path) +
+ R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
expect("", script.c_str(), kNoCause, &updater_info);
// Updater generates the stash name based on the input file name.
std::string name_digest = get_sha1(update_file.path);
std::string stash_base = "/cache/recovery/" + name_digest;
ASSERT_EQ(0, access(stash_base.c_str(), F_OK));
- ASSERT_EQ(-1, access((stash_base + tgt_hash).c_str(), F_OK));
+ ASSERT_EQ(-1, access((stash_base + src_hash).c_str(), F_OK));
ASSERT_EQ(0, rmdir(stash_base.c_str()));
ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
CloseArchive(handle);
}
-TEST_F(UpdaterTest, new_data_short_write) {
- // Create a zip file with new_data.
+TEST_F(UpdaterTest, new_data_over_write) {
+ std::vector<std::string> transfer_list = {
+ "4", "1", "0", "0", "new 2,0,1",
+ };
+
+ // Write 4096 + 100 bytes of new data.
+ std::unordered_map<std::string, std::string> entries = {
+ { "new_data", std::string(4196, 0) },
+ { "patch_data", "" },
+ { "transfer_list", android::base::Join(transfer_list, '\n') },
+ };
+
+ // Build the update package.
TemporaryFile zip_file;
- FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
- ZipWriter zip_writer(zip_file_ptr);
+ BuildUpdatePackage(entries, zip_file.release());
+
+ MemMapping map;
+ ASSERT_TRUE(map.MapFile(zip_file.path));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFromMemory(map.addr, map.length, zip_file.path, &handle));
- // Add the empty new data.
- ASSERT_EQ(0, zip_writer.StartEntry("empty_new_data", 0));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- // Add the short written new data.
- ASSERT_EQ(0, zip_writer.StartEntry("short_new_data", 0));
- std::string new_data_short = std::string(10, 'a');
- ASSERT_EQ(0, zip_writer.WriteBytes(new_data_short.data(), new_data_short.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- // Add the data of exactly one block.
- ASSERT_EQ(0, zip_writer.StartEntry("exact_new_data", 0));
- std::string new_data_exact = std::string(4096, 'a');
- ASSERT_EQ(0, zip_writer.WriteBytes(new_data_exact.data(), new_data_exact.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- // Add a dummy patch data.
- ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
- ASSERT_EQ(0, zip_writer.FinishEntry());
+ // Set up the handler, command_pipe, patch offset & length.
+ UpdaterInfo updater_info;
+ updater_info.package_zip = handle;
+ TemporaryFile temp_pipe;
+ updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
+ updater_info.package_zip_addr = map.addr;
+ updater_info.package_zip_len = map.length;
+ TemporaryFile update_file;
+ std::string script = "block_image_update(\"" + std::string(update_file.path) +
+ R"(", package_extract_file("transfer_list"), "new_data", "patch_data"))";
+ expect("t", script.c_str(), kNoCause, &updater_info);
+
+ ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
+ CloseArchive(handle);
+}
+
+TEST_F(UpdaterTest, new_data_short_write) {
std::vector<std::string> transfer_list = {
"4",
"1",
@@ -547,12 +597,17 @@ TEST_F(UpdaterTest, new_data_short_write) {
"0",
"new 2,0,1",
};
- ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0));
- std::string commands = android::base::Join(transfer_list, '\n');
- ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- ASSERT_EQ(0, zip_writer.Finish());
- ASSERT_EQ(0, fclose(zip_file_ptr));
+
+ std::unordered_map<std::string, std::string> entries = {
+ { "empty_new_data", "" },
+ { "short_new_data", std::string(10, 'a') },
+ { "exact_new_data", std::string(4096, 'a') },
+ { "patch_data", "" },
+ { "transfer_list", android::base::Join(transfer_list, '\n') },
+ };
+
+ TemporaryFile zip_file;
+ BuildUpdatePackage(entries, zip_file.release());
MemMapping map;
ASSERT_TRUE(map.MapFile(zip_file.path));
@@ -587,14 +642,6 @@ TEST_F(UpdaterTest, new_data_short_write) {
}
TEST_F(UpdaterTest, brotli_new_data) {
- // Create a zip file with new_data.
- TemporaryFile zip_file;
- FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
- ZipWriter zip_writer(zip_file_ptr);
-
- // Add a brotli compressed new data entry.
- ASSERT_EQ(0, zip_writer.StartEntry("new.dat.br", 0));
-
auto generator = []() { return rand() % 128; };
// Generate 100 blocks of random data.
std::string brotli_new_data;
@@ -602,16 +649,12 @@ TEST_F(UpdaterTest, brotli_new_data) {
generate_n(back_inserter(brotli_new_data), 4096 * 100, generator);
size_t encoded_size = BrotliEncoderMaxCompressedSize(brotli_new_data.size());
- std::vector<uint8_t> encoded_data(encoded_size);
+ std::string encoded_data(encoded_size, 0);
ASSERT_TRUE(BrotliEncoderCompress(
BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, brotli_new_data.size(),
- reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size, encoded_data.data()));
-
- ASSERT_EQ(0, zip_writer.WriteBytes(encoded_data.data(), encoded_size));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- // Add a dummy patch data.
- ASSERT_EQ(0, zip_writer.StartEntry("patch_data", 0));
- ASSERT_EQ(0, zip_writer.FinishEntry());
+ reinterpret_cast<const uint8_t*>(brotli_new_data.data()), &encoded_size,
+ reinterpret_cast<uint8_t*>(const_cast<char*>(encoded_data.data()))));
+ encoded_data.resize(encoded_size);
// Write a few small chunks of new data, then a large chunk, and finally a few small chunks.
// This helps us to catch potential short writes.
@@ -627,12 +670,15 @@ TEST_F(UpdaterTest, brotli_new_data) {
"new 2,98,99",
"new 2,99,100",
};
- ASSERT_EQ(0, zip_writer.StartEntry("transfer_list", 0));
- std::string commands = android::base::Join(transfer_list, '\n');
- ASSERT_EQ(0, zip_writer.WriteBytes(commands.data(), commands.size()));
- ASSERT_EQ(0, zip_writer.FinishEntry());
- ASSERT_EQ(0, zip_writer.Finish());
- ASSERT_EQ(0, fclose(zip_file_ptr));
+
+ std::unordered_map<std::string, std::string> entries = {
+ { "new.dat.br", std::move(encoded_data) },
+ { "patch_data", "" },
+ { "transfer_list", android::base::Join(transfer_list, '\n') },
+ };
+
+ TemporaryFile zip_file;
+ BuildUpdatePackage(entries, zip_file.release());
MemMapping map;
ASSERT_TRUE(map.MapFile(zip_file.path));
diff --git a/tests/testdata/deflate_src.zip b/tests/testdata/deflate_src.zip
new file mode 100644
index 000000000..bdb2b3216
--- /dev/null
+++ b/tests/testdata/deflate_src.zip
Binary files differ
diff --git a/tests/testdata/deflate_tgt.zip b/tests/testdata/deflate_tgt.zip
new file mode 100644
index 000000000..2a21760ec
--- /dev/null
+++ b/tests/testdata/deflate_tgt.zip
Binary files differ
diff --git a/tools/recovery_l10n/res/values-hi/strings.xml b/tools/recovery_l10n/res/values-hi/strings.xml
index a8a876ee4..65d003352 100644
--- a/tools/recovery_l10n/res/values-hi/strings.xml
+++ b/tools/recovery_l10n/res/values-hi/strings.xml
@@ -3,7 +3,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recovery_installing" msgid="2013591905463558223">"सिस्टम अपडेट इंस्टॉल किया जा रहा है"</string>
<string name="recovery_erasing" msgid="7334826894904037088">"मिटाया जा रहा है"</string>
- <string name="recovery_no_command" msgid="4465476568623024327">"कोई आदेश नहीं"</string>
+ <string name="recovery_no_command" msgid="4465476568623024327">"कोई निर्देश नहीं मिला"</string>
<string name="recovery_error" msgid="5748178989622716736">"गड़बड़ी!"</string>
<string name="recovery_installing_security" msgid="9184031299717114342">"सुरक्षा अपडेट इंस्टॉल किया जा रहा है"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-mr/strings.xml b/tools/recovery_l10n/res/values-mr/strings.xml
index 8cf86f773..5f820336f 100644
--- a/tools/recovery_l10n/res/values-mr/strings.xml
+++ b/tools/recovery_l10n/res/values-mr/strings.xml
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="2013591905463558223">"सिस्टम अद्यतन स्थापित करीत आहे"</string>
+ <string name="recovery_installing" msgid="2013591905463558223">"सिस्टम अपडेट इंस्टॉल करत आहे"</string>
<string name="recovery_erasing" msgid="7334826894904037088">"मिटवत आहे"</string>
- <string name="recovery_no_command" msgid="4465476568623024327">"कोणताही आदेश नाही"</string>
- <string name="recovery_error" msgid="5748178989622716736">"त्रुटी!"</string>
- <string name="recovery_installing_security" msgid="9184031299717114342">"सुरक्षा अद्यतन स्थापित करीत आहे"</string>
+ <string name="recovery_no_command" msgid="4465476568623024327">"कोणतीही कमांड नाही"</string>
+ <string name="recovery_error" msgid="5748178989622716736">"एरर!"</string>
+ <string name="recovery_installing_security" msgid="9184031299717114342">"सुरक्षा अपडेट इंस्टॉल करत आहे"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-pa/strings.xml b/tools/recovery_l10n/res/values-pa/strings.xml
index 8564c9c36..27972d117 100644
--- a/tools/recovery_l10n/res/values-pa/strings.xml
+++ b/tools/recovery_l10n/res/values-pa/strings.xml
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="recovery_installing" msgid="2013591905463558223">"ਸਿਸਟਮ ਅੱਪਡੇਟ ਸਥਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+ <string name="recovery_installing" msgid="2013591905463558223">"ਸਿਸਟਮ ਅੱਪਡੇਟ ਸਥਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<string name="recovery_erasing" msgid="7334826894904037088">"ਮਿਟਾਈ ਜਾ ਰਹੀ ਹੈ"</string>
- <string name="recovery_no_command" msgid="4465476568623024327">"ਕੋਈ ਕਮਾਂਡ ਨਹੀਂ"</string>
+ <string name="recovery_no_command" msgid="4465476568623024327">"ਕੋਈ ਆਦੇਸ਼ ਨਹੀਂ"</string>
<string name="recovery_error" msgid="5748178989622716736">"ਅਸ਼ੁੱਧੀ!"</string>
- <string name="recovery_installing_security" msgid="9184031299717114342">"ਸੁਰੱਖਿਆ ਅੱਪਡੇਟ ਸਥਾਪਤ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ"</string>
+ <string name="recovery_installing_security" msgid="9184031299717114342">"ਸੁਰੱਖਿਆ ਅੱਪਡੇਟ ਸਥਾਪਤ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
</resources>
diff --git a/tools/recovery_l10n/res/values-te/strings.xml b/tools/recovery_l10n/res/values-te/strings.xml
index cfb02c915..e35c82bc4 100644
--- a/tools/recovery_l10n/res/values-te/strings.xml
+++ b/tools/recovery_l10n/res/values-te/strings.xml
@@ -4,6 +4,6 @@
<string name="recovery_installing" msgid="2013591905463558223">"సిస్టమ్ నవీకరణను ఇన్‍స్టాల్ చేస్తోంది"</string>
<string name="recovery_erasing" msgid="7334826894904037088">"డేటాను తొలగిస్తోంది"</string>
<string name="recovery_no_command" msgid="4465476568623024327">"ఆదేశం లేదు"</string>
- <string name="recovery_error" msgid="5748178989622716736">"లోపం సంభవించింది!"</string>
+ <string name="recovery_error" msgid="5748178989622716736">"ఎర్రర్ సంభవించింది!"</string>
<string name="recovery_installing_security" msgid="9184031299717114342">"భద్రతా నవీకరణను ఇన్‌స్టాల్ చేస్తోంది"</string>
</resources>
diff --git a/update_verifier/update_verifier.cpp b/update_verifier/update_verifier.cpp
index faebbede0..ba7b7aec4 100644
--- a/update_verifier/update_verifier.cpp
+++ b/update_verifier/update_verifier.cpp
@@ -137,11 +137,12 @@ static bool read_blocks(const std::string& partition, const std::string& range_s
LOG(ERROR) << "Error in parsing range string.";
return false;
}
+ range_count /= 2;
std::vector<std::future<bool>> threads;
size_t thread_num = std::thread::hardware_concurrency() ?: 4;
- thread_num = std::min(thread_num, range_count / 2);
- size_t group_range_count = range_count / thread_num;
+ thread_num = std::min(thread_num, range_count);
+ size_t group_range_count = (range_count + thread_num - 1) / thread_num;
for (size_t t = 0; t < thread_num; t++) {
auto thread_func = [t, group_range_count, &dm_block_device, &ranges, &partition]() {
@@ -154,7 +155,8 @@ static bool read_blocks(const std::string& partition, const std::string& range_s
return false;
}
- for (size_t i = 1 + group_range_count * t; i < group_range_count * (t + 1) + 1; i += 2) {
+ for (size_t i = group_range_count * 2 * t + 1;
+ i < std::min(group_range_count * 2 * (t + 1) + 1, ranges.size()); i += 2) {
unsigned int range_start, range_end;
bool parse_status = android::base::ParseUint(ranges[i], &range_start);
parse_status = parse_status && android::base::ParseUint(ranges[i + 1], &range_end);
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index ce3cea4f3..6c7b3efcf 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -281,6 +281,11 @@ static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
// Wait for nti->writer to be non-null, indicating some of this data is wanted.
pthread_mutex_lock(&nti->mu);
while (nti->writer == nullptr) {
+ // End the new data receiver if we encounter an error when performing block image update.
+ if (!nti->receiver_available) {
+ pthread_mutex_unlock(&nti->mu);
+ return false;
+ }
pthread_cond_wait(&nti->cv, &nti->mu);
}
pthread_mutex_unlock(&nti->mu);
@@ -316,6 +321,11 @@ static bool receive_brotli_new_data(const uint8_t* data, size_t size, void* cook
// Wait for nti->writer to be non-null, indicating some of this data is wanted.
pthread_mutex_lock(&nti->mu);
while (nti->writer == nullptr) {
+ // End the receiver if we encounter an error when performing block image update.
+ if (!nti->receiver_available) {
+ pthread_mutex_unlock(&nti->mu);
+ return false;
+ }
pthread_cond_wait(&nti->cv, &nti->mu);
}
pthread_mutex_unlock(&nti->mu);
@@ -1591,29 +1601,44 @@ static Value* PerformBlockImageUpdate(const char* name, State* state,
}
}
+ rc = 0;
+
+pbiudone:
if (params.canwrite) {
- pthread_join(params.thread, nullptr);
+ pthread_mutex_lock(&params.nti.mu);
+ if (params.nti.receiver_available) {
+ LOG(WARNING) << "new data receiver is still available after executing all commands.";
+ }
+ params.nti.receiver_available = false;
+ pthread_cond_broadcast(&params.nti.cv);
+ pthread_mutex_unlock(&params.nti.mu);
+ int ret = pthread_join(params.thread, nullptr);
+ if (ret != 0) {
+ LOG(WARNING) << "pthread join returned with " << strerror(ret);
+ }
- LOG(INFO) << "wrote " << params.written << " blocks; expected " << total_blocks;
- LOG(INFO) << "stashed " << params.stashed << " blocks";
- LOG(INFO) << "max alloc needed was " << params.buffer.size();
+ if (rc == 0) {
+ LOG(INFO) << "wrote " << params.written << " blocks; expected " << total_blocks;
+ LOG(INFO) << "stashed " << params.stashed << " blocks";
+ LOG(INFO) << "max alloc needed was " << params.buffer.size();
- const char* partition = strrchr(blockdev_filename->data.c_str(), '/');
- if (partition != nullptr && *(partition + 1) != 0) {
- fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1, params.written * BLOCKSIZE);
- fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1, params.stashed * BLOCKSIZE);
- fflush(cmd_pipe);
+ const char* partition = strrchr(blockdev_filename->data.c_str(), '/');
+ if (partition != nullptr && *(partition + 1) != 0) {
+ fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1, params.written * BLOCKSIZE);
+ fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1, params.stashed * BLOCKSIZE);
+ fflush(cmd_pipe);
+ }
+ // Delete stash only after successfully completing the update, as it may contain blocks needed
+ // to complete the update later.
+ DeleteStash(params.stashbase);
}
- // Delete stash only after successfully completing the update, as it may contain blocks needed
- // to complete the update later.
- DeleteStash(params.stashbase);
- } else {
+
+ pthread_mutex_destroy(&params.nti.mu);
+ pthread_cond_destroy(&params.nti.cv);
+ } else if (rc == 0) {
LOG(INFO) << "verified partition contents; update may be resumed";
}
- rc = 0;
-
-pbiudone:
if (ota_fsync(params.fd) == -1) {
failure_type = kFsyncFailure;
PLOG(ERROR) << "fsync failed";