summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format1
-rw-r--r--applypatch/imgdiff.cpp189
-rw-r--r--applypatch/include/applypatch/imgdiff_image.h6
-rw-r--r--common.h5
-rw-r--r--device.cpp44
-rw-r--r--device.h1
-rw-r--r--install.cpp2
-rw-r--r--minui/include/minui/minui.h4
-rw-r--r--minui/resources.cpp35
-rw-r--r--recovery-persist.rc2
-rw-r--r--recovery-refresh.rc2
-rw-r--r--recovery.cpp11
-rw-r--r--res-hdpi/images/erasing_text.pngbin50184 -> 51214 bytes
-rw-r--r--res-hdpi/images/error_text.pngbin35856 -> 36610 bytes
-rw-r--r--res-hdpi/images/installing_security_text.pngbin113078 -> 115058 bytes
-rw-r--r--res-hdpi/images/installing_text.pngbin104002 -> 105531 bytes
-rw-r--r--res-hdpi/images/no_command_text.pngbin61417 -> 62331 bytes
-rw-r--r--res-mdpi/images/erasing_text.pngbin29660 -> 30027 bytes
-rw-r--r--res-mdpi/images/error_text.pngbin21123 -> 21546 bytes
-rw-r--r--res-mdpi/images/installing_security_text.pngbin69603 -> 70491 bytes
-rw-r--r--res-mdpi/images/installing_text.pngbin61281 -> 62100 bytes
-rw-r--r--res-mdpi/images/no_command_text.pngbin34366 -> 34772 bytes
-rw-r--r--res-xhdpi/images/erasing_text.pngbin73097 -> 74450 bytes
-rw-r--r--res-xhdpi/images/error_text.pngbin52180 -> 53331 bytes
-rw-r--r--res-xhdpi/images/installing_security_text.pngbin197146 -> 201207 bytes
-rw-r--r--res-xhdpi/images/installing_text.pngbin175660 -> 178087 bytes
-rw-r--r--res-xhdpi/images/no_command_text.pngbin86619 -> 88037 bytes
-rw-r--r--res-xxhdpi/images/erasing_text.pngbin121637 -> 123362 bytes
-rw-r--r--res-xxhdpi/images/error_text.pngbin84961 -> 86841 bytes
-rw-r--r--res-xxhdpi/images/installing_security_text.pngbin447228 -> 453013 bytes
-rw-r--r--res-xxhdpi/images/installing_text.pngbin416000 -> 420313 bytes
-rw-r--r--res-xxhdpi/images/no_command_text.pngbin243226 -> 247462 bytes
-rw-r--r--res-xxxhdpi/images/erasing_text.pngbin263646 -> 267640 bytes
-rw-r--r--res-xxxhdpi/images/error_text.pngbin178458 -> 181450 bytes
-rw-r--r--res-xxxhdpi/images/installing_security_text.pngbin610223 -> 618212 bytes
-rw-r--r--res-xxxhdpi/images/installing_text.pngbin567987 -> 574440 bytes
-rw-r--r--res-xxxhdpi/images/no_command_text.pngbin331473 -> 336495 bytes
-rw-r--r--roots.cpp21
-rw-r--r--screen_ui.cpp77
-rw-r--r--screen_ui.h8
-rw-r--r--tests/component/imgdiff_test.cpp51
-rw-r--r--tests/component/updater_test.cpp22
42 files changed, 375 insertions, 106 deletions
diff --git a/.clang-format b/.clang-format
index 532278864..0e0f4d143 100644
--- a/.clang-format
+++ b/.clang-format
@@ -10,6 +10,5 @@ IndentWidth: 2
PointerAlignment: Left
TabWidth: 2
UseTab: Never
-PenaltyExcessCharacter: 32
Cpp11BracedListStyle: false
diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp
index 2eb618fbf..c887a854d 100644
--- a/applypatch/imgdiff.cpp
+++ b/applypatch/imgdiff.cpp
@@ -15,53 +15,44 @@
*/
/*
- * This program constructs binary patches for images -- such as boot.img
- * and recovery.img -- that consist primarily of large chunks of gzipped
- * data interspersed with uncompressed data. Doing a naive bsdiff of
- * these files is not useful because small changes in the data lead to
- * large changes in the compressed bitstream; bsdiff patches of gzipped
- * data are typically as large as the data itself.
+ * This program constructs binary patches for images -- such as boot.img and recovery.img -- that
+ * consist primarily of large chunks of gzipped data interspersed with uncompressed data. Doing a
+ * naive bsdiff of these files is not useful because small changes in the data lead to large
+ * changes in the compressed bitstream; bsdiff patches of gzipped data are typically as large as
+ * the data itself.
*
- * To patch these usefully, we break the source and target images up into
- * chunks of two types: "normal" and "gzip". Normal chunks are simply
- * patched using a plain bsdiff. Gzip chunks are first expanded, then a
- * bsdiff is applied to the uncompressed data, then the patched data is
- * gzipped using the same encoder parameters. Patched chunks are
- * concatenated together to create the output file; the output image
- * should be *exactly* the same series of bytes as the target image used
- * originally to generate the patch.
+ * To patch these usefully, we break the source and target images up into chunks of two types:
+ * "normal" and "gzip". Normal chunks are simply patched using a plain bsdiff. Gzip chunks are
+ * first expanded, then a bsdiff is applied to the uncompressed data, then the patched data is
+ * gzipped using the same encoder parameters. Patched chunks are concatenated together to create
+ * the output file; the output image should be *exactly* the same series of bytes as the target
+ * image used originally to generate the patch.
*
- * To work well with this tool, the gzipped sections of the target
- * image must have been generated using the same deflate encoder that
- * is available in applypatch, namely, the one in the zlib library.
- * In practice this means that images should be compressed using the
- * "minigzip" tool included in the zlib distribution, not the GNU gzip
- * program.
+ * To work well with this tool, the gzipped sections of the target image must have been generated
+ * using the same deflate encoder that is available in applypatch, namely, the one in the zlib
+ * library. In practice this means that images should be compressed using the "minigzip" tool
+ * included in the zlib distribution, not the GNU gzip program.
*
- * An "imgdiff" patch consists of a header describing the chunk structure
- * of the file and any encoding parameters needed for the gzipped
- * chunks, followed by N bsdiff patches, one per chunk.
+ * An "imgdiff" patch consists of a header describing the chunk structure of the file and any
+ * encoding parameters needed for the gzipped chunks, followed by N bsdiff patches, one per chunk.
*
- * For a diff to be generated, the source and target images must have the
- * same "chunk" structure: that is, the same number of gzipped and normal
- * chunks in the same order. Android boot and recovery images currently
- * consist of five chunks: a small normal header, a gzipped kernel, a
- * small normal section, a gzipped ramdisk, and finally a small normal
- * footer.
+ * For a diff to be generated, the source and target must be in well-formed zip archive format;
+ * or they are image files with the same "chunk" structure: that is, the same number of gzipped and
+ * normal chunks in the same order. Android boot and recovery images currently consist of five
+ * chunks: a small normal header, a gzipped kernel, a small normal section, a gzipped ramdisk, and
+ * finally a small normal footer.
*
- * Caveats: we locate gzipped sections within the source and target
- * images by searching for the byte sequence 1f8b0800: 1f8b is the gzip
- * magic number; 08 specifies the "deflate" encoding [the only encoding
- * supported by the gzip standard]; and 00 is the flags byte. We do not
- * currently support any extra header fields (which would be indicated by
- * a nonzero flags byte). We also don't handle the case when that byte
- * sequence appears spuriously in the file. (Note that it would have to
- * occur spuriously within a normal chunk to be a problem.)
+ * Caveats: we locate gzipped sections within the source and target images by searching for the
+ * byte sequence 1f8b0800: 1f8b is the gzip magic number; 08 specifies the "deflate" encoding
+ * [the only encoding supported by the gzip standard]; and 00 is the flags byte. We do not
+ * currently support any extra header fields (which would be indicated by a nonzero flags byte).
+ * We also don't handle the case when that byte sequence appears spuriously in the file. (Note
+ * that it would have to occur spuriously within a normal chunk to be a problem.)
*
*
* The imgdiff patch header looks like this:
*
- * "IMGDIFF1" (8) [magic number and version]
+ * "IMGDIFF2" (8) [magic number and version]
* chunk count (4)
* for each chunk:
* chunk type (4) [CHUNK_{NORMAL, GZIP, DEFLATE, RAW}]
@@ -98,27 +89,55 @@
* target len (4)
* data (target len)
*
- * All integers are little-endian. "source start" and "source len"
- * specify the section of the input image that comprises this chunk,
- * including the gzip header and footer for gzip chunks. "source
- * expanded len" is the size of the uncompressed source data. "target
- * expected len" is the size of the uncompressed data after applying
- * the bsdiff patch. The next five parameters specify the zlib
- * parameters to be used when compressing the patched data, and the
- * next three specify the header and footer to be wrapped around the
- * compressed data to create the output chunk (so that header contents
- * like the timestamp are recreated exactly).
+ * All integers are little-endian. "source start" and "source len" specify the section of the
+ * input image that comprises this chunk, including the gzip header and footer for gzip chunks.
+ * "source expanded len" is the size of the uncompressed source data. "target expected len" is the
+ * size of the uncompressed data after applying the bsdiff patch. The next five parameters
+ * specify the zlib parameters to be used when compressing the patched data, and the next three
+ * specify the header and footer to be wrapped around the compressed data to create the output
+ * chunk (so that header contents like the timestamp are recreated exactly).
*
- * After the header there are 'chunk count' bsdiff patches; the offset
- * of each from the beginning of the file is specified in the header.
+ * After the header there are 'chunk count' bsdiff patches; the offset of each from the beginning
+ * of the file is specified in the header.
*
- * This tool can take an optional file of "bonus data". This is an
- * extra file of data that is appended to chunk #1 after it is
- * compressed (it must be a CHUNK_DEFLATE chunk). The same file must
- * be available (and passed to applypatch with -b) when applying the
- * patch. This is used to reduce the size of recovery-from-boot
- * patches by combining the boot image with recovery ramdisk
+ * This tool can take an optional file of "bonus data". This is an extra file of data that is
+ * appended to chunk #1 after it is compressed (it must be a CHUNK_DEFLATE chunk). The same file
+ * must be available (and passed to applypatch with -b) when applying the patch. This is used to
+ * reduce the size of recovery-from-boot patches by combining the boot image with recovery ramdisk
* information that is stored on the system partition.
+ *
+ * When generating the patch between two zip files, this tool has an option "--block-limit" to
+ * split the large source/target files into several pair of pieces, with each piece has at most
+ * *limit* blocks. When this option is used, we also need to output the split info into the file
+ * path specified by "--split-info".
+ *
+ * Format of split info file:
+ * 2 [version of imgdiff]
+ * n [count of split pieces]
+ * <patch_size>, <tgt_size>, <src_range> [size and ranges for split piece#1]
+ * ...
+ * <patch_size>, <tgt_size>, <src_range> [size and ranges for split piece#n]
+ *
+ * To split a pair of large zip files, we walk through the chunks in target zip and search by its
+ * entry_name in the source zip. If the entry_name is non-empty and a matching entry in source
+ * is found, we'll add the source entry to the current split source image; otherwise we'll skip
+ * this chunk and later do bsdiff between all the skipped trunks and the whole split source image.
+ * We move on to the next pair of pieces if the size of the split source image reaches the block
+ * limit.
+ *
+ * After the split, the target pieces are continuous and block aligned, while the source pieces
+ * are mutually exclusive. Some of the source blocks may not be used if there's no matching
+ * entry_name in the target; as a result, they won't be included in any of these split source
+ * images. Then we will generate patches accordingly between each split image pairs; in particular,
+ * the unmatched trunks in the split target will diff against the entire split source image.
+ *
+ * For example:
+ * Input: [src_image, tgt_image]
+ * Split: [src-0, tgt-0; src-1, tgt-1, src-2, tgt-2]
+ * Diff: [ patch-0; patch-1; patch-2]
+ *
+ * Patch: [(src-0, patch-0) = tgt-0; (src-1, patch-1) = tgt-1; (src-2, patch-2) = tgt-2]
+ * Concatenate: [tgt-0 + tgt-1 + tgt-2 = tgt_image]
*/
#include "applypatch/imgdiff.h"
@@ -151,6 +170,11 @@
using android::base::get_unaligned;
+static constexpr size_t VERSION = 2;
+
+// We assume the header "IMGDIFF#" is 8 bytes.
+static_assert(VERSION <= 9, "VERSION occupies more than one byte.");
+
static constexpr size_t BLOCK_SIZE = 4096;
static constexpr size_t BUFFER_SIZE = 0x8000;
@@ -224,6 +248,7 @@ static const struct option OPTIONS[] = {
{ "bonus-file", required_argument, nullptr, 'b' },
{ "block-limit", required_argument, nullptr, 0 },
{ "debug-dir", required_argument, nullptr, 0 },
+ { "split-info", required_argument, nullptr, 0 },
{ nullptr, 0, nullptr, 0 },
};
@@ -497,6 +522,13 @@ size_t PatchChunk::WriteHeaderToFd(int fd, size_t offset) const {
}
}
+size_t PatchChunk::PatchSize() const {
+ if (type_ == CHUNK_RAW) {
+ return GetHeaderSize();
+ }
+ return GetHeaderSize() + data_.size();
+}
+
// Write the contents of |patch_chunks| to |patch_fd|.
bool PatchChunk::WritePatchDataToFd(const std::vector<PatchChunk>& patch_chunks, int patch_fd) {
// Figure out how big the imgdiff file header is going to be, so that we can correctly compute
@@ -509,8 +541,8 @@ bool PatchChunk::WritePatchDataToFd(const std::vector<PatchChunk>& patch_chunks,
size_t offset = total_header_size;
// Write out the headers.
- if (!android::base::WriteStringToFd("IMGDIFF2", patch_fd)) {
- printf("failed to write \"IMGDIFF2\": %s\n", strerror(errno));
+ if (!android::base::WriteStringToFd("IMGDIFF" + std::to_string(VERSION), patch_fd)) {
+ printf("failed to write \"IMGDIFF%zu\": %s\n", VERSION, strerror(errno));
return false;
}
@@ -1107,7 +1139,9 @@ bool ZipModeImage::GeneratePatches(const ZipModeImage& tgt_image, const ZipModeI
bool ZipModeImage::GeneratePatches(const std::vector<ZipModeImage>& split_tgt_images,
const std::vector<ZipModeImage>& split_src_images,
const std::vector<SortedRangeSet>& split_src_ranges,
- const std::string& patch_name, const std::string& debug_dir) {
+ const std::string& patch_name,
+ const std::string& split_info_file,
+ const std::string& debug_dir) {
printf("Construct patches for %zu split images...\n", split_tgt_images.size());
android::base::unique_fd patch_fd(
@@ -1117,6 +1151,7 @@ bool ZipModeImage::GeneratePatches(const std::vector<ZipModeImage>& split_tgt_im
return false;
}
+ std::vector<std::string> split_info_list;
for (size_t i = 0; i < split_tgt_images.size(); i++) {
std::vector<PatchChunk> patch_chunks;
if (!ZipModeImage::GeneratePatchesInternal(split_tgt_images[i], split_src_images[i],
@@ -1125,14 +1160,23 @@ bool ZipModeImage::GeneratePatches(const std::vector<ZipModeImage>& split_tgt_im
return false;
}
+ size_t total_patch_size = 12;
for (auto& p : patch_chunks) {
p.UpdateSourceOffset(split_src_ranges[i]);
+ total_patch_size += p.PatchSize();
}
if (!PatchChunk::WritePatchDataToFd(patch_chunks, patch_fd)) {
return false;
}
+ size_t split_tgt_size = split_tgt_images[i].chunks_.back().GetStartOffset() +
+ split_tgt_images[i].chunks_.back().GetRawDataLength() -
+ split_tgt_images[i].chunks_.front().GetStartOffset();
+ std::string split_info = android::base::StringPrintf(
+ "%zu %zu %s", total_patch_size, split_tgt_size, split_src_ranges[i].ToString().c_str());
+ split_info_list.push_back(split_info);
+
// Write the split source & patch into the debug directory.
if (!debug_dir.empty()) {
std::string src_name = android::base::StringPrintf("%s/src-%zu", debug_dir.c_str(), i);
@@ -1161,6 +1205,21 @@ bool ZipModeImage::GeneratePatches(const std::vector<ZipModeImage>& split_tgt_im
}
}
}
+
+ // Store the split in the following format:
+ // Line 0: imgdiff version#
+ // Line 1: number of pieces
+ // Line 2: patch_size_1 tgt_size_1 src_range_1
+ // ...
+ // Line n+1: patch_size_n tgt_size_n src_range_n
+ std::string split_info_string = android::base::StringPrintf(
+ "%zu\n%zu\n", VERSION, split_info_list.size()) + android::base::Join(split_info_list, '\n');
+ if (!android::base::WriteStringToFile(split_info_string, split_info_file)) {
+ printf("failed to write split info to \"%s\": %s\n", split_info_file.c_str(),
+ strerror(errno));
+ return false;
+ }
+
return true;
}
@@ -1396,6 +1455,7 @@ int imgdiff(int argc, const char** argv) {
bool zip_mode = false;
std::vector<uint8_t> bonus_data;
size_t blocks_limit = 0;
+ std::string split_info_file;
std::string debug_dir;
int opt;
@@ -1432,6 +1492,8 @@ int imgdiff(int argc, const char** argv) {
if (name == "block-limit" && !android::base::ParseUint(optarg, &blocks_limit)) {
printf("failed to parse size blocks_limit: %s\n", optarg);
return 1;
+ } else if (name == "split-info") {
+ split_info_file = optarg;
} else if (name == "debug-dir") {
debug_dir = optarg;
}
@@ -1451,6 +1513,8 @@ int imgdiff(int argc, const char** argv) {
" --block-limit, For large zips, split the src and tgt based on the block limit;\n"
" and generate patches between each pair of pieces. Concatenate these\n"
" patches together and output them into <patch-file>.\n"
+ " --split-info, Output the split information (patch_size, tgt_size, src_ranges);\n"
+ " zip mode with block-limit only.\n"
" --debug_dir, Debug directory to put the split srcs and patches, zip mode only.\n");
return 2;
}
@@ -1476,6 +1540,11 @@ int imgdiff(int argc, const char** argv) {
// Compute bsdiff patches for each chunk's data (the uncompressed data, in the case of
// deflate chunks).
if (blocks_limit > 0) {
+ if (split_info_file.empty()) {
+ printf("split-info path cannot be empty when generating patches with a block-limit.\n");
+ return 1;
+ }
+
std::vector<ZipModeImage> split_tgt_images;
std::vector<ZipModeImage> split_src_images;
std::vector<SortedRangeSet> split_src_ranges;
@@ -1483,7 +1552,7 @@ int imgdiff(int argc, const char** argv) {
&split_src_images, &split_src_ranges);
if (!ZipModeImage::GeneratePatches(split_tgt_images, split_src_images, split_src_ranges,
- argv[optind + 2], debug_dir)) {
+ argv[optind + 2], split_info_file, debug_dir)) {
return 1;
}
diff --git a/applypatch/include/applypatch/imgdiff_image.h b/applypatch/include/applypatch/imgdiff_image.h
index 9fb844b24..491043dc1 100644
--- a/applypatch/include/applypatch/imgdiff_image.h
+++ b/applypatch/include/applypatch/imgdiff_image.h
@@ -132,6 +132,9 @@ class PatchChunk {
// Update the source start with the new offset within the source range.
void UpdateSourceOffset(const SortedRangeSet& src_range);
+ // Return the total size (header + data) of the patch.
+ size_t PatchSize() const;
+
static bool WritePatchDataToFd(const std::vector<PatchChunk>& patch_chunks, int patch_fd);
private:
@@ -241,7 +244,8 @@ class ZipModeImage : public Image {
static bool GeneratePatches(const std::vector<ZipModeImage>& split_tgt_images,
const std::vector<ZipModeImage>& split_src_images,
const std::vector<SortedRangeSet>& split_src_ranges,
- const std::string& patch_name, const std::string& debug_dir);
+ const std::string& patch_name, const std::string& split_info_file,
+ const std::string& debug_dir);
// Split the tgt chunks and src chunks based on the size limit.
static bool SplitZipModeImageWithLimit(const ZipModeImage& tgt_image,
diff --git a/common.h b/common.h
index 62fb1324b..8b336f806 100644
--- a/common.h
+++ b/common.h
@@ -22,8 +22,9 @@
#include <string>
-#define STRINGIFY(x) #x
-#define EXPAND(x) STRINGIFY(x)
+// Not using the command-line defined macro here because this header could be included by
+// device-specific recovery libraries. We static assert the value consistency in recovery.cpp.
+static constexpr int kRecoveryApiVersion = 3;
class RecoveryUI;
diff --git a/device.cpp b/device.cpp
index 61501869e..f881daff6 100644
--- a/device.cpp
+++ b/device.cpp
@@ -17,34 +17,36 @@
#include "device.h"
static const char* MENU_ITEMS[] = {
- "Reboot system now",
- "Reboot to bootloader",
- "Apply update from ADB",
- "Apply update from SD card",
- "Wipe data/factory reset",
+ "Reboot system now",
+ "Reboot to bootloader",
+ "Apply update from ADB",
+ "Apply update from SD card",
+ "Wipe data/factory reset",
#ifndef AB_OTA_UPDATER
- "Wipe cache partition",
+ "Wipe cache partition",
#endif // !AB_OTA_UPDATER
- "Mount /system",
- "View recovery logs",
- "Run graphics test",
- "Power off",
- NULL,
+ "Mount /system",
+ "View recovery logs",
+ "Run graphics test",
+ "Run locale test",
+ "Power off",
+ nullptr,
};
static const Device::BuiltinAction MENU_ACTIONS[] = {
- Device::REBOOT,
- Device::REBOOT_BOOTLOADER,
- Device::APPLY_ADB_SIDELOAD,
- Device::APPLY_SDCARD,
- Device::WIPE_DATA,
+ Device::REBOOT,
+ Device::REBOOT_BOOTLOADER,
+ Device::APPLY_ADB_SIDELOAD,
+ Device::APPLY_SDCARD,
+ Device::WIPE_DATA,
#ifndef AB_OTA_UPDATER
- Device::WIPE_CACHE,
+ Device::WIPE_CACHE,
#endif // !AB_OTA_UPDATER
- Device::MOUNT_SYSTEM,
- Device::VIEW_RECOVERY_LOGS,
- Device::RUN_GRAPHICS_TEST,
- Device::SHUTDOWN,
+ Device::MOUNT_SYSTEM,
+ Device::VIEW_RECOVERY_LOGS,
+ Device::RUN_GRAPHICS_TEST,
+ Device::RUN_LOCALE_TEST,
+ Device::SHUTDOWN,
};
static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
diff --git a/device.h b/device.h
index 639e2bf57..74745b36c 100644
--- a/device.h
+++ b/device.h
@@ -66,6 +66,7 @@ class Device {
VIEW_RECOVERY_LOGS = 9,
MOUNT_SYSTEM = 10,
RUN_GRAPHICS_TEST = 11,
+ RUN_LOCALE_TEST = 12,
};
// Return the list of menu items (an array of strings, NULL-terminated). The menu_position passed
diff --git a/install.cpp b/install.cpp
index 586dbbe2c..507161c2e 100644
--- a/install.cpp
+++ b/install.cpp
@@ -290,7 +290,7 @@ int update_binary_command(const std::string& package, ZipArchiveHandle zip,
*cmd = {
binary_path,
- EXPAND(RECOVERY_API_VERSION), // defined in Android.mk
+ std::to_string(kRecoveryApiVersion),
std::to_string(status_fd),
package,
};
diff --git a/minui/include/minui/minui.h b/minui/include/minui/minui.h
index 017ddde75..27e603136 100644
--- a/minui/include/minui/minui.h
+++ b/minui/include/minui/minui.h
@@ -21,6 +21,7 @@
#include <functional>
#include <string>
+#include <vector>
//
// Graphics.
@@ -129,6 +130,9 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface);
int res_create_localized_alpha_surface(const char* name, const char* locale,
GRSurface** pSurface);
+// Return a list of locale strings embedded in |png_name|. Return a empty list in case of failure.
+std::vector<std::string> get_locales_in_png(const std::string& png_name);
+
// Free a surface allocated by any of the res_create_*_surface()
// functions.
void res_free_surface(GRSurface* surface);
diff --git a/minui/resources.cpp b/minui/resources.cpp
index 8f8d36d27..756f29d21 100644
--- a/minui/resources.cpp
+++ b/minui/resources.cpp
@@ -396,6 +396,41 @@ bool matches_locale(const std::string& prefix, const std::string& locale) {
return std::regex_match(locale, loc_regex);
}
+std::vector<std::string> get_locales_in_png(const std::string& png_name) {
+ png_structp png_ptr = nullptr;
+ png_infop info_ptr = nullptr;
+ png_uint_32 width, height;
+ png_byte channels;
+
+ int status = open_png(png_name.c_str(), &png_ptr, &info_ptr, &width, &height, &channels);
+ if (status < 0) {
+ printf("Failed to open %s\n", png_name.c_str());
+ return {};
+ }
+ if (channels != 1) {
+ printf("Expect input png to have 1 data channel, this file has %d\n", channels);
+ png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
+ return {};
+ }
+
+ std::vector<std::string> result;
+ std::vector<unsigned char> row(width);
+ for (png_uint_32 y = 0; y < height; ++y) {
+ png_read_row(png_ptr, row.data(), nullptr);
+ int h = (row[3] << 8) | row[2];
+ std::string loc(reinterpret_cast<char*>(&row[5]));
+ if (!loc.empty()) {
+ result.push_back(loc);
+ }
+ for (int i = 0; i < h; ++i, ++y) {
+ png_read_row(png_ptr, row.data(), NULL);
+ }
+ }
+
+ png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
+ return result;
+}
+
int res_create_localized_alpha_surface(const char* name,
const char* locale,
GRSurface** pSurface) {
diff --git a/recovery-persist.rc b/recovery-persist.rc
index 6761627d5..135a3c33d 100644
--- a/recovery-persist.rc
+++ b/recovery-persist.rc
@@ -1,3 +1,3 @@
on post-fs-data
mkdir /data/misc/recovery 0770 system log
- exec - system log -- /system/bin/recovery-persist
+ exec_background - system log -- /system/bin/recovery-persist
diff --git a/recovery-refresh.rc b/recovery-refresh.rc
index 14b05cca4..9fefc819b 100644
--- a/recovery-refresh.rc
+++ b/recovery-refresh.rc
@@ -1,2 +1,2 @@
on post-fs
- exec - system log -- /system/bin/recovery-refresh
+ exec_background - system log -- /system/bin/recovery-refresh
diff --git a/recovery.cpp b/recovery.cpp
index 6f62ff17c..076b4492e 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -125,6 +125,10 @@ static const int BATTERY_WITH_CHARGER_OK_PERCENTAGE = 15;
static constexpr const char* RECOVERY_WIPE = "/etc/recovery.wipe";
static constexpr const char* DEFAULT_LOCALE = "en-US";
+// We define RECOVERY_API_VERSION in Android.mk, which will be picked up by build system and packed
+// into target_files.zip. Assert the version defined in code and in Android.mk are consistent.
+static_assert(kRecoveryApiVersion == RECOVERY_API_VERSION, "Mismatching recovery API versions.");
+
static std::string locale;
static bool has_cache = false;
@@ -1187,6 +1191,11 @@ static Device::BuiltinAction prompt_and_wait(Device* device, int status) {
run_graphics_test();
break;
+ case Device::RUN_LOCALE_TEST: {
+ ScreenRecoveryUI* screen_ui = static_cast<ScreenRecoveryUI*>(ui);
+ screen_ui->CheckBackgroundTextImages(locale);
+ break;
+ }
case Device::MOUNT_SYSTEM:
// For a system image built with the root directory (i.e. system_root_image == "true"), we
// mount it to /system_root, and symlink /system to /system_root/system to make adb shell
@@ -1498,7 +1507,7 @@ int main(int argc, char **argv) {
property_list(print_property, NULL);
printf("\n");
- ui->Print("Supported API: %d\n", RECOVERY_API_VERSION);
+ ui->Print("Supported API: %d\n", kRecoveryApiVersion);
int status = INSTALL_SUCCESS;
diff --git a/res-hdpi/images/erasing_text.png b/res-hdpi/images/erasing_text.png
index 0982544d2..34c56a966 100644
--- a/res-hdpi/images/erasing_text.png
+++ b/res-hdpi/images/erasing_text.png
Binary files differ
diff --git a/res-hdpi/images/error_text.png b/res-hdpi/images/error_text.png
index 3a06f6eb1..2a96053da 100644
--- a/res-hdpi/images/error_text.png
+++ b/res-hdpi/images/error_text.png
Binary files differ
diff --git a/res-hdpi/images/installing_security_text.png b/res-hdpi/images/installing_security_text.png
index b1acd2336..97e1f11b3 100644
--- a/res-hdpi/images/installing_security_text.png
+++ b/res-hdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-hdpi/images/installing_text.png b/res-hdpi/images/installing_text.png
index f0f5d8b6c..1d591eb8b 100644
--- a/res-hdpi/images/installing_text.png
+++ b/res-hdpi/images/installing_text.png
Binary files differ
diff --git a/res-hdpi/images/no_command_text.png b/res-hdpi/images/no_command_text.png
index def503678..977fcfaff 100644
--- a/res-hdpi/images/no_command_text.png
+++ b/res-hdpi/images/no_command_text.png
Binary files differ
diff --git a/res-mdpi/images/erasing_text.png b/res-mdpi/images/erasing_text.png
index 82b4461ba..dcd0ea656 100644
--- a/res-mdpi/images/erasing_text.png
+++ b/res-mdpi/images/erasing_text.png
Binary files differ
diff --git a/res-mdpi/images/error_text.png b/res-mdpi/images/error_text.png
index adb45131f..2152dad83 100644
--- a/res-mdpi/images/error_text.png
+++ b/res-mdpi/images/error_text.png
Binary files differ
diff --git a/res-mdpi/images/installing_security_text.png b/res-mdpi/images/installing_security_text.png
index 54e556448..d1ac4cad6 100644
--- a/res-mdpi/images/installing_security_text.png
+++ b/res-mdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-mdpi/images/installing_text.png b/res-mdpi/images/installing_text.png
index d42331820..c9b6d7185 100644
--- a/res-mdpi/images/installing_text.png
+++ b/res-mdpi/images/installing_text.png
Binary files differ
diff --git a/res-mdpi/images/no_command_text.png b/res-mdpi/images/no_command_text.png
index cd77ff457..f77ad1325 100644
--- a/res-mdpi/images/no_command_text.png
+++ b/res-mdpi/images/no_command_text.png
Binary files differ
diff --git a/res-xhdpi/images/erasing_text.png b/res-xhdpi/images/erasing_text.png
index 333edbe27..e22b27479 100644
--- a/res-xhdpi/images/erasing_text.png
+++ b/res-xhdpi/images/erasing_text.png
Binary files differ
diff --git a/res-xhdpi/images/error_text.png b/res-xhdpi/images/error_text.png
index e26258438..e4c27e1fc 100644
--- a/res-xhdpi/images/error_text.png
+++ b/res-xhdpi/images/error_text.png
Binary files differ
diff --git a/res-xhdpi/images/installing_security_text.png b/res-xhdpi/images/installing_security_text.png
index e0f0f3ea7..7ba12b667 100644
--- a/res-xhdpi/images/installing_security_text.png
+++ b/res-xhdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-xhdpi/images/installing_text.png b/res-xhdpi/images/installing_text.png
index a7e67f512..567988e7f 100644
--- a/res-xhdpi/images/installing_text.png
+++ b/res-xhdpi/images/installing_text.png
Binary files differ
diff --git a/res-xhdpi/images/no_command_text.png b/res-xhdpi/images/no_command_text.png
index 13aef7b71..a682abbef 100644
--- a/res-xhdpi/images/no_command_text.png
+++ b/res-xhdpi/images/no_command_text.png
Binary files differ
diff --git a/res-xxhdpi/images/erasing_text.png b/res-xxhdpi/images/erasing_text.png
index 80e7c475e..6cc953b6d 100644
--- a/res-xxhdpi/images/erasing_text.png
+++ b/res-xxhdpi/images/erasing_text.png
Binary files differ
diff --git a/res-xxhdpi/images/error_text.png b/res-xxhdpi/images/error_text.png
index 32a1965b8..0d5cea843 100644
--- a/res-xxhdpi/images/error_text.png
+++ b/res-xxhdpi/images/error_text.png
Binary files differ
diff --git a/res-xxhdpi/images/installing_security_text.png b/res-xxhdpi/images/installing_security_text.png
index c53c9ac21..5d105986a 100644
--- a/res-xxhdpi/images/installing_security_text.png
+++ b/res-xxhdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-xxhdpi/images/installing_text.png b/res-xxhdpi/images/installing_text.png
index 38b18d20d..6e94fa28b 100644
--- a/res-xxhdpi/images/installing_text.png
+++ b/res-xxhdpi/images/installing_text.png
Binary files differ
diff --git a/res-xxhdpi/images/no_command_text.png b/res-xxhdpi/images/no_command_text.png
index a0666d8dc..40ab484d9 100644
--- a/res-xxhdpi/images/no_command_text.png
+++ b/res-xxhdpi/images/no_command_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/erasing_text.png b/res-xxxhdpi/images/erasing_text.png
index 4f7b37b51..cc730992b 100644
--- a/res-xxxhdpi/images/erasing_text.png
+++ b/res-xxxhdpi/images/erasing_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/error_text.png b/res-xxxhdpi/images/error_text.png
index 052bf2142..fea3cfc95 100644
--- a/res-xxxhdpi/images/error_text.png
+++ b/res-xxxhdpi/images/error_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/installing_security_text.png b/res-xxxhdpi/images/installing_security_text.png
index a9e739b17..ed77d0889 100644
--- a/res-xxxhdpi/images/installing_security_text.png
+++ b/res-xxxhdpi/images/installing_security_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/installing_text.png b/res-xxxhdpi/images/installing_text.png
index 2d1948677..965910648 100644
--- a/res-xxxhdpi/images/installing_text.png
+++ b/res-xxxhdpi/images/installing_text.png
Binary files differ
diff --git a/res-xxxhdpi/images/no_command_text.png b/res-xxxhdpi/images/no_command_text.png
index ee0c23865..4e6f3639d 100644
--- a/res-xxxhdpi/images/no_command_text.png
+++ b/res-xxxhdpi/images/no_command_text.png
Binary files differ
diff --git a/roots.cpp b/roots.cpp
index 26602a710..7d7d1bdc7 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -69,8 +69,27 @@ void load_volume_table() {
printf("\n");
}
+// Finds the volume specified by the given path. fs_mgr_get_entry_for_mount_point() does exact match
+// only, so it attempts the prefixes recursively (e.g. "/cache/recovery/last_log",
+// "/cache/recovery", "/cache", "/" for a given path of "/cache/recovery/last_log") and returns the
+// first match or nullptr.
Volume* volume_for_path(const char* path) {
- return fs_mgr_get_entry_for_mount_point(fstab, path);
+ if (path == nullptr || path[0] == '\0') return nullptr;
+ std::string str(path);
+ while (true) {
+ Volume* result = fs_mgr_get_entry_for_mount_point(fstab, str.c_str());
+ if (result != nullptr || str == "/") {
+ return result;
+ }
+ size_t slash = str.find_last_of('/');
+ if (slash == std::string::npos) return nullptr;
+ if (slash == 0) {
+ str = "/";
+ } else {
+ str = str.substr(0, slash);
+ }
+ }
+ return nullptr;
}
// Mount the volume specified by path at the given mount_point.
diff --git a/screen_ui.cpp b/screen_ui.cpp
index d65d656bd..bc5c5c31f 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -31,7 +31,9 @@
#include <time.h>
#include <unistd.h>
+#include <memory>
#include <string>
+#include <unordered_map>
#include <vector>
#include <android-base/logging.h>
@@ -258,6 +260,81 @@ void ScreenRecoveryUI::SetColor(UIElement e) const {
}
}
+void ScreenRecoveryUI::SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries,
+ size_t sel) {
+ SetLocale(locales_entries[sel]);
+ std::vector<std::string> text_name = { "erasing_text", "error_text", "installing_text",
+ "installing_security_text", "no_command_text" };
+ std::unordered_map<std::string, std::unique_ptr<GRSurface, decltype(&free)>> surfaces;
+ for (const auto& name : text_name) {
+ GRSurface* text_image = nullptr;
+ LoadLocalizedBitmap(name.c_str(), &text_image);
+ if (!text_image) {
+ Print("Failed to load %s\n", name.c_str());
+ return;
+ }
+ surfaces.emplace(name, std::unique_ptr<GRSurface, decltype(&free)>(text_image, &free));
+ }
+
+ pthread_mutex_lock(&updateMutex);
+ gr_color(0, 0, 0, 255);
+ gr_clear();
+
+ int text_y = kMarginHeight;
+ int text_x = kMarginWidth;
+ int line_spacing = gr_sys_font()->char_height; // Put some extra space between images.
+ // Write the header and descriptive texts.
+ SetColor(INFO);
+ std::string header = "Show background text image";
+ text_y += DrawTextLine(text_x, text_y, header.c_str(), true);
+ std::string locale_selection = android::base::StringPrintf(
+ "Current locale: %s, %zu/%zu", locales_entries[sel].c_str(), sel, locales_entries.size());
+ const char* instruction[] = { locale_selection.c_str(),
+ "Use volume up/down to switch locales and power to exit.",
+ nullptr };
+ text_y += DrawWrappedTextLines(text_x, text_y, instruction);
+
+ // Iterate through the text images and display them in order for the current locale.
+ for (const auto& p : surfaces) {
+ text_y += line_spacing;
+ SetColor(LOG);
+ text_y += DrawTextLine(text_x, text_y, p.first.c_str(), false);
+ gr_color(255, 255, 255, 255);
+ gr_texticon(text_x, text_y, p.second.get());
+ text_y += gr_get_height(p.second.get());
+ }
+ // Update the whole screen.
+ gr_flip();
+ pthread_mutex_unlock(&updateMutex);
+}
+
+void ScreenRecoveryUI::CheckBackgroundTextImages(const std::string& saved_locale) {
+ // Load a list of locales embedded in one of the resource files.
+ std::vector<std::string> locales_entries = get_locales_in_png("installing_text");
+ if (locales_entries.empty()) {
+ Print("Failed to load locales from the resource files\n");
+ return;
+ }
+ size_t selected = 0;
+ SelectAndShowBackgroundText(locales_entries, selected);
+
+ FlushKeys();
+ while (true) {
+ int key = WaitKey();
+ if (key == KEY_POWER || key == KEY_ENTER) {
+ break;
+ } else if (key == KEY_UP || key == KEY_VOLUMEUP) {
+ selected = (selected == 0) ? locales_entries.size() - 1 : selected - 1;
+ SelectAndShowBackgroundText(locales_entries, selected);
+ } else if (key == KEY_DOWN || key == KEY_VOLUMEDOWN) {
+ selected = (selected == locales_entries.size() - 1) ? 0 : selected + 1;
+ SelectAndShowBackgroundText(locales_entries, selected);
+ }
+ }
+
+ SetLocale(saved_locale);
+}
+
int ScreenRecoveryUI::DrawHorizontalRule(int y) const {
gr_fill(0, y + 4, gr_fb_width(), y + 6);
return 8;
diff --git a/screen_ui.h b/screen_ui.h
index eaac2a6e8..3a28a09de 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -80,6 +80,10 @@ class ScreenRecoveryUI : public RecoveryUI {
void SetColor(UIElement e) const;
+ // Check the background text image. Use volume up/down button to cycle through the locales
+ // embedded in the png file, and power button to go back to recovery main menu.
+ void CheckBackgroundTextImages(const std::string& saved_locale);
+
protected:
// The margin that we don't want to use for showing texts (e.g. round screen, or screen with
// rounded corners).
@@ -199,6 +203,10 @@ class ScreenRecoveryUI : public RecoveryUI {
private:
void SetLocale(const std::string&);
+
+ // Display the background texts for "erasing", "error", "no_command" and "installing" for the
+ // selected locale.
+ void SelectAndShowBackgroundText(const std::vector<std::string>& locales_entries, size_t sel);
};
#endif // RECOVERY_UI_H
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index 3163a57cf..161d58d45 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -778,10 +778,13 @@ TEST(ImgdiffTest, zip_mode_store_large_apk) {
// Compute patch.
TemporaryFile patch_file;
+ TemporaryFile split_info_file;
TemporaryDir debug_dir;
+ std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
+ std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
std::vector<const char*> args = {
- "imgdiff", "-z", "--block-limit=10", android::base::StringPrintf(
- "--debug-dir=%s", debug_dir.path).c_str(), src_file.path, tgt_file.path, patch_file.path,
+ "imgdiff", "-z", "--block-limit=10", split_info_arg.c_str(), debug_dir_arg.c_str(),
+ src_file.path, tgt_file.path, patch_file.path,
};
ASSERT_EQ(0, imgdiff(args.size(), args.data()));
@@ -863,14 +866,40 @@ TEST(ImgdiffTest, zip_mode_deflate_large_apk) {
// Compute patch.
TemporaryFile patch_file;
+ TemporaryFile split_info_file;
TemporaryDir debug_dir;
ASSERT_TRUE(ZipModeImage::GeneratePatches(split_tgt_images, split_src_images, split_src_ranges,
- patch_file.path, debug_dir.path));
+ patch_file.path, split_info_file.path, debug_dir.path));
+
+ // Verify the content of split info.
+ // Expect 5 pieces of patch. ["a","b"; "c"; "d-0"; "d-1"; "e"]
+ std::string split_info_string;
+ android::base::ReadFileToString(split_info_file.path, &split_info_string);
+ std::vector<std::string> info_list =
+ android::base::Split(android::base::Trim(split_info_string), "\n");
+
+ ASSERT_EQ(static_cast<size_t>(7), info_list.size());
+ ASSERT_EQ("2", android::base::Trim(info_list[0]));
+ ASSERT_EQ("5", android::base::Trim(info_list[1]));
+
+ std::vector<size_t> patch_size;
+ for (size_t i = 0; i < 5; i++) {
+ 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(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));
- // Expect 5 pieces of patch. ["a","b"; "c"; "d-0"; "d-1"; "e"]
GenerateAndCheckSplitTarget(debug_dir.path, 5, tgt);
}
@@ -900,10 +929,13 @@ TEST(ImgdiffTest, zip_mode_no_match_source) {
// Compute patch.
TemporaryFile patch_file;
+ TemporaryFile split_info_file;
TemporaryDir debug_dir;
+ std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
+ std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
std::vector<const char*> args = {
- "imgdiff", "-z", "--block-limit=10", android::base::StringPrintf(
- "--debug-dir=%s", debug_dir.path).c_str(), src_file.path, tgt_file.path, patch_file.path,
+ "imgdiff", "-z", "--block-limit=10", debug_dir_arg.c_str(), split_info_arg.c_str(),
+ src_file.path, tgt_file.path, patch_file.path,
};
ASSERT_EQ(0, imgdiff(args.size(), args.data()));
@@ -939,10 +971,13 @@ TEST(ImgdiffTest, zip_mode_large_enough_limit) {
// Compute patch with a limit of 20 blocks.
TemporaryFile patch_file;
+ TemporaryFile split_info_file;
TemporaryDir debug_dir;
+ std::string split_info_arg = android::base::StringPrintf("--split-info=%s", split_info_file.path);
+ std::string debug_dir_arg = android::base::StringPrintf("--debug-dir=%s", debug_dir.path);
std::vector<const char*> args = {
- "imgdiff", "-z", "--block-limit=20", android::base::StringPrintf(
- "--debug-dir=%s", debug_dir.path).c_str(), src_file.path, tgt_file.path, patch_file.path,
+ "imgdiff", "-z", "--block-limit=20", split_info_arg.c_str(), debug_dir_arg.c_str(),
+ src_file.path, tgt_file.path, patch_file.path,
};
ASSERT_EQ(0, imgdiff(args.size(), args.data()));
diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp
index 6c341c111..2a0575a31 100644
--- a/tests/component/updater_test.cpp
+++ b/tests/component/updater_test.cpp
@@ -383,7 +383,7 @@ TEST_F(UpdaterTest, set_progress) {
TemporaryFile tf;
UpdaterInfo updater_info;
- updater_info.cmd_pipe = fdopen(tf.fd, "w");
+ updater_info.cmd_pipe = fdopen(tf.release(), "w");
expect(".52", "set_progress(\".52\")", kNoCause, &updater_info);
fflush(updater_info.cmd_pipe);
@@ -392,6 +392,7 @@ TEST_F(UpdaterTest, set_progress) {
ASSERT_EQ(android::base::StringPrintf("set_progress %f\n", .52), cmd);
// recovery-updater protocol expects 2 tokens ("set_progress <frac>").
ASSERT_EQ(2U, android::base::Split(cmd, " ").size());
+ ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
}
TEST_F(UpdaterTest, show_progress) {
@@ -407,7 +408,7 @@ TEST_F(UpdaterTest, show_progress) {
TemporaryFile tf;
UpdaterInfo updater_info;
- updater_info.cmd_pipe = fdopen(tf.fd, "w");
+ updater_info.cmd_pipe = fdopen(tf.release(), "w");
expect(".52", "show_progress(\".52\", \"10\")", kNoCause, &updater_info);
fflush(updater_info.cmd_pipe);
@@ -416,12 +417,13 @@ TEST_F(UpdaterTest, show_progress) {
ASSERT_EQ(android::base::StringPrintf("progress %f %d\n", .52, 10), cmd);
// recovery-updater protocol expects 3 tokens ("progress <frac> <secs>").
ASSERT_EQ(3U, android::base::Split(cmd, " ").size());
+ 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.fd, "wb");
+ FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
ZipWriter zip_writer(zip_file_ptr);
// Add a dummy new data.
@@ -485,7 +487,7 @@ TEST_F(UpdaterTest, block_image_update) {
UpdaterInfo updater_info;
updater_info.package_zip = handle;
TemporaryFile temp_pipe;
- updater_info.cmd_pipe = fopen(temp_pipe.path, "wbe");
+ updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
updater_info.package_zip_addr = map.addr;
updater_info.package_zip_len = map.length;
@@ -518,7 +520,7 @@ TEST_F(UpdaterTest, block_image_update) {
TEST_F(UpdaterTest, new_data_short_write) {
// Create a zip file with new_data.
TemporaryFile zip_file;
- FILE* zip_file_ptr = fdopen(zip_file.fd, "wb");
+ FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
ZipWriter zip_writer(zip_file_ptr);
// Add the empty new data.
@@ -561,7 +563,7 @@ TEST_F(UpdaterTest, new_data_short_write) {
UpdaterInfo updater_info;
updater_info.package_zip = handle;
TemporaryFile temp_pipe;
- updater_info.cmd_pipe = fopen(temp_pipe.path, "wbe");
+ updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wbe");
updater_info.package_zip_addr = map.addr;
updater_info.package_zip_len = map.length;
@@ -579,13 +581,15 @@ TEST_F(UpdaterTest, new_data_short_write) {
std::string script_exact_data = "block_image_update(\"" + std::string(update_file.path) +
R"(", package_extract_file("transfer_list"), "exact_new_data", "patch_data"))";
expect("t", script_exact_data.c_str(), kNoCause, &updater_info);
+
+ ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
CloseArchive(handle);
}
TEST_F(UpdaterTest, brotli_new_data) {
// Create a zip file with new_data.
TemporaryFile zip_file;
- FILE* zip_file_ptr = fdopen(zip_file.fd, "wb");
+ FILE* zip_file_ptr = fdopen(zip_file.release(), "wb");
ZipWriter zip_writer(zip_file_ptr);
// Add a brotli compressed new data entry.
@@ -639,7 +643,7 @@ TEST_F(UpdaterTest, brotli_new_data) {
UpdaterInfo updater_info;
updater_info.package_zip = handle;
TemporaryFile temp_pipe;
- updater_info.cmd_pipe = fopen(temp_pipe.path, "wb");
+ updater_info.cmd_pipe = fdopen(temp_pipe.release(), "wb");
updater_info.package_zip_addr = map.addr;
updater_info.package_zip_len = map.length;
@@ -653,5 +657,7 @@ TEST_F(UpdaterTest, brotli_new_data) {
std::string updated_content;
ASSERT_TRUE(android::base::ReadFileToString(update_file.path, &updated_content));
ASSERT_EQ(brotli_new_data, updated_content);
+
+ ASSERT_EQ(0, fclose(updater_info.cmd_pipe));
CloseArchive(handle);
}