diff options
-rw-r--r-- | applypatch/Android.mk | 9 | ||||
-rw-r--r-- | applypatch/imgdiff.cpp | 651 | ||||
-rw-r--r-- | applypatch/include/applypatch/imgdiff_image.h | 247 | ||||
-rw-r--r-- | etc/init.rc | 4 | ||||
-rw-r--r-- | minui/graphics.cpp | 4 | ||||
-rw-r--r-- | rangeset.h (renamed from updater/include/updater/rangeset.h) | 8 | ||||
-rw-r--r-- | recovery.cpp | 18 | ||||
-rw-r--r-- | screen_ui.cpp | 31 | ||||
-rw-r--r-- | screen_ui.h | 3 | ||||
-rw-r--r-- | tests/component/verifier_test.cpp | 17 | ||||
-rw-r--r-- | tests/unit/rangeset_test.cpp | 2 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-az/strings.xml (renamed from tools/recovery_l10n/res/values-az-rAZ/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-b+sr+Latn/strings.xml | 9 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-be/strings.xml | 9 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-bn/strings.xml (renamed from tools/recovery_l10n/res/values-bn-rBD/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-bs/strings.xml | 9 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-et/strings.xml (renamed from tools/recovery_l10n/res/values-et-rEE/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-eu/strings.xml (renamed from tools/recovery_l10n/res/values-eu-rES/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-gl/strings.xml (renamed from tools/recovery_l10n/res/values-gl-rES/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-gu/strings.xml (renamed from tools/recovery_l10n/res/values-gu-rIN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-hy/strings.xml (renamed from tools/recovery_l10n/res/values-hy-rAM/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-is/strings.xml (renamed from tools/recovery_l10n/res/values-is-rIS/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-ka/strings.xml (renamed from tools/recovery_l10n/res/values-ka-rGE/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-kk/strings.xml (renamed from tools/recovery_l10n/res/values-kk-rKZ/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-km/strings.xml (renamed from tools/recovery_l10n/res/values-km-rKH/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-kn/strings.xml (renamed from tools/recovery_l10n/res/values-kn-rIN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-ky/strings.xml (renamed from tools/recovery_l10n/res/values-ky-rKG/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-lo/strings.xml (renamed from tools/recovery_l10n/res/values-lo-rLA/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-mk/strings.xml (renamed from tools/recovery_l10n/res/values-mk-rMK/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-ml/strings.xml (renamed from tools/recovery_l10n/res/values-ml-rIN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-mn/strings.xml (renamed from tools/recovery_l10n/res/values-mn-rMN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-mr/strings.xml (renamed from tools/recovery_l10n/res/values-mr-rIN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-ms/strings.xml (renamed from tools/recovery_l10n/res/values-ms-rMY/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-my/strings.xml (renamed from tools/recovery_l10n/res/values-my-rMM/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-ne/strings.xml (renamed from tools/recovery_l10n/res/values-ne-rNP/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-pa/strings.xml (renamed from tools/recovery_l10n/res/values-pa-rIN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-si/strings.xml (renamed from tools/recovery_l10n/res/values-si-rLK/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-sq/strings.xml (renamed from tools/recovery_l10n/res/values-sq-rAL/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-ta/strings.xml (renamed from tools/recovery_l10n/res/values-ta-rIN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-te/strings.xml (renamed from tools/recovery_l10n/res/values-te-rIN/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-ur/strings.xml (renamed from tools/recovery_l10n/res/values-ur-rPK/strings.xml) | 0 | ||||
-rw-r--r-- | tools/recovery_l10n/res/values-uz/strings.xml (renamed from tools/recovery_l10n/res/values-uz-rUZ/strings.xml) | 0 | ||||
-rw-r--r-- | uncrypt/uncrypt.cpp | 6 | ||||
-rw-r--r-- | update_verifier/update_verifier_main.cpp | 6 | ||||
-rw-r--r-- | updater/blockimg.cpp | 2 | ||||
-rw-r--r-- | updater/updater.cpp | 6 |
46 files changed, 612 insertions, 429 deletions
diff --git a/applypatch/Android.mk b/applypatch/Android.mk index 7aed0a95a..e38207c22 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -151,7 +151,8 @@ LOCAL_CFLAGS := \ LOCAL_STATIC_LIBRARIES := \ $(libimgdiff_static_libraries) LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/include + $(LOCAL_PATH)/include \ + bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include include $(BUILD_STATIC_LIBRARY) @@ -166,7 +167,8 @@ LOCAL_CFLAGS := \ LOCAL_STATIC_LIBRARIES := \ $(libimgdiff_static_libraries) LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/include + $(LOCAL_PATH)/include \ + bootable/recovery LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include include $(BUILD_HOST_STATIC_LIBRARY) @@ -180,4 +182,7 @@ LOCAL_STATIC_LIBRARIES := \ libimgdiff \ $(libimgdiff_static_libraries) \ libbz +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + bootable/recovery include $(BUILD_HOST_EXECUTABLE) diff --git a/applypatch/imgdiff.cpp b/applypatch/imgdiff.cpp index 880265260..59b600713 100644 --- a/applypatch/imgdiff.cpp +++ b/applypatch/imgdiff.cpp @@ -140,11 +140,12 @@ #include <android-base/logging.h> #include <android-base/memory.h> #include <android-base/unique_fd.h> -#include <ziparchive/zip_archive.h> - #include <bsdiff.h> +#include <ziparchive/zip_archive.h> #include <zlib.h> +#include "applypatch/imgdiff_image.h" + using android::base::get_unaligned; static constexpr auto BUFFER_SIZE = 0x8000; @@ -161,107 +162,16 @@ static inline bool Write4(int fd, int32_t value) { return android::base::WriteFully(fd, &value, sizeof(int32_t)); } -class ImageChunk { - public: - static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream. - static constexpr auto MEMLEVEL = 8; // the default value. - static constexpr auto METHOD = Z_DEFLATED; - static constexpr auto STRATEGY = Z_DEFAULT_STRATEGY; - - ImageChunk(int type, size_t start, const std::vector<uint8_t>* file_content, size_t raw_data_len) - : type_(type), - start_(start), - input_file_ptr_(file_content), - raw_data_len_(raw_data_len), - compress_level_(6), - source_start_(0), - source_len_(0), - source_uncompressed_len_(0) { - CHECK(file_content != nullptr) << "input file container can't be nullptr"; - } - - int GetType() const { - return type_; - } - size_t GetRawDataLength() const { - return raw_data_len_; - } - const std::string& GetEntryName() const { - return entry_name_; - } - - // CHUNK_DEFLATE will return the uncompressed data for diff, while other types will simply return - // the raw data. - const uint8_t * DataForPatch() const; - size_t DataLengthForPatch() const; - - void Dump() const { - printf("type: %d, start: %zu, len: %zu, name: %s\n", type_, start_, DataLengthForPatch(), - entry_name_.c_str()); - } - - void SetSourceInfo(const ImageChunk& other); - void SetEntryName(std::string entryname); - void SetUncompressedData(std::vector<uint8_t> data); - bool SetBonusData(const std::vector<uint8_t>& bonus_data); - - bool operator==(const ImageChunk& other) const; - bool operator!=(const ImageChunk& other) const { - return !(*this == other); - } - - size_t GetHeaderSize(size_t patch_size) const; - // Return the offset of the next patch into the patch data. - size_t WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset) const; - - /* - * Cause a gzip chunk to be treated as a normal chunk (ie, as a blob - * of uninterpreted data). The resulting patch will likely be about - * as big as the target file, but it lets us handle the case of images - * where some gzip chunks are reconstructible but others aren't (by - * treating the ones that aren't as normal chunks). - */ - void ChangeDeflateChunkToNormal(); - bool ChangeChunkToRaw(size_t patch_size); - - /* - * Verify that we can reproduce exactly the same compressed data that - * we started with. Sets the level, method, windowBits, memLevel, and - * strategy fields in the chunk to the encoding parameters needed to - * produce the right output. - */ - bool ReconstructDeflateChunk(); - bool IsAdjacentNormal(const ImageChunk& other) const; - void MergeAdjacentNormal(const ImageChunk& other); - - /* - * Compute a bsdiff patch between |this| and the input source chunks. - * Store the result in the patch_data. - * |bsdiff_cache| can be used to cache the suffix array if the same |src| chunk is used - * repeatedly, pass nullptr if not needed. - */ - bool MakePatch(const ImageChunk& src, std::vector<uint8_t>* patch_data, saidx_t** bsdiff_cache); - - private: - int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW - size_t start_; // offset of chunk in the original input file - const std::vector<uint8_t>* input_file_ptr_; // ptr to the full content of original input file - size_t raw_data_len_; - - // --- for CHUNK_DEFLATE chunks only: --- - std::vector<uint8_t> uncompressed_data_; - std::string entry_name_; // used for zip entries - - // deflate encoder parameters - int compress_level_; - - size_t source_start_; - size_t source_len_; - size_t source_uncompressed_len_; - - const uint8_t* GetRawData() const; - bool TryReconstruction(int level); -}; +ImageChunk::ImageChunk(int type, size_t start, const std::vector<uint8_t>* file_content, + size_t raw_data_len, std::string entry_name) + : type_(type), + start_(start), + input_file_ptr_(file_content), + raw_data_len_(raw_data_len), + compress_level_(6), + entry_name_(std::move(entry_name)) { + CHECK(file_content != nullptr) << "input file container can't be nullptr"; +} const uint8_t* ImageChunk::GetRawData() const { CHECK_LE(start_ + raw_data_len_, input_file_ptr_->size()); @@ -290,20 +200,6 @@ bool ImageChunk::operator==(const ImageChunk& other) const { memcmp(GetRawData(), other.GetRawData(), raw_data_len_) == 0); } -void ImageChunk::SetSourceInfo(const ImageChunk& src) { - source_start_ = src.start_; - if (type_ == CHUNK_NORMAL) { - source_len_ = src.raw_data_len_; - } else if (type_ == CHUNK_DEFLATE) { - source_len_ = src.raw_data_len_; - source_uncompressed_len_ = src.uncompressed_data_.size(); - } -} - -void ImageChunk::SetEntryName(std::string entryname) { - entry_name_ = std::move(entryname); -} - void ImageChunk::SetUncompressedData(std::vector<uint8_t> data) { uncompressed_data_ = std::move(data); } @@ -316,18 +212,6 @@ bool ImageChunk::SetBonusData(const std::vector<uint8_t>& bonus_data) { return true; } -// Convert CHUNK_NORMAL & CHUNK_DEFLATE to CHUNK_RAW if the target size is -// smaller. Also take the header size into account during size comparison. -bool ImageChunk::ChangeChunkToRaw(size_t patch_size) { - if (type_ == CHUNK_RAW) { - return true; - } else if (type_ == CHUNK_NORMAL && (raw_data_len_ <= 160 || raw_data_len_ < patch_size)) { - type_ = CHUNK_RAW; - return true; - } - return false; -} - void ImageChunk::ChangeDeflateChunkToNormal() { if (type_ != CHUNK_DEFLATE) return; type_ = CHUNK_NORMAL; @@ -335,61 +219,6 @@ void ImageChunk::ChangeDeflateChunkToNormal() { uncompressed_data_.clear(); } -// Header size: -// header_type 4 bytes -// CHUNK_NORMAL 8*3 = 24 bytes -// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes -// CHUNK_RAW 4 bytes + patch_size -size_t ImageChunk::GetHeaderSize(size_t patch_size) const { - switch (type_) { - case CHUNK_NORMAL: - return 4 + 8 * 3; - case CHUNK_DEFLATE: - return 4 + 8 * 5 + 4 * 5; - case CHUNK_RAW: - return 4 + 4 + patch_size; - default: - CHECK(false) << "unexpected chunk type: " << type_; // Should not reach here. - return 0; - } -} - -size_t ImageChunk::WriteHeaderToFd(int fd, const std::vector<uint8_t>& patch, size_t offset) const { - Write4(fd, type_); - switch (type_) { - case CHUNK_NORMAL: - printf("normal (%10zu, %10zu) %10zu\n", start_, raw_data_len_, patch.size()); - Write8(fd, static_cast<int64_t>(source_start_)); - Write8(fd, static_cast<int64_t>(source_len_)); - Write8(fd, static_cast<int64_t>(offset)); - return offset + patch.size(); - case CHUNK_DEFLATE: - printf("deflate (%10zu, %10zu) %10zu %s\n", start_, raw_data_len_, patch.size(), - entry_name_.c_str()); - Write8(fd, static_cast<int64_t>(source_start_)); - Write8(fd, static_cast<int64_t>(source_len_)); - Write8(fd, static_cast<int64_t>(offset)); - Write8(fd, static_cast<int64_t>(source_uncompressed_len_)); - Write8(fd, static_cast<int64_t>(uncompressed_data_.size())); - Write4(fd, compress_level_); - Write4(fd, METHOD); - Write4(fd, WINDOWBITS); - Write4(fd, MEMLEVEL); - Write4(fd, STRATEGY); - return offset + patch.size(); - case CHUNK_RAW: - printf("raw (%10zu, %10zu)\n", start_, raw_data_len_); - Write4(fd, static_cast<int32_t>(patch.size())); - if (!android::base::WriteFully(fd, patch.data(), patch.size())) { - CHECK(false) << "failed to write " << patch.size() <<" bytes patch"; - } - return offset; - default: - CHECK(false) << "unexpected chunk type: " << type_; - return offset; - } -} - bool ImageChunk::IsAdjacentNormal(const ImageChunk& other) const { if (type_ != CHUNK_NORMAL || other.type_ != CHUNK_NORMAL) { return false; @@ -402,15 +231,8 @@ void ImageChunk::MergeAdjacentNormal(const ImageChunk& other) { raw_data_len_ = raw_data_len_ + other.raw_data_len_; } -bool ImageChunk::MakePatch(const ImageChunk& src, std::vector<uint8_t>* patch_data, - saidx_t** bsdiff_cache) { - if (ChangeChunkToRaw(0)) { - size_t patch_size = DataLengthForPatch(); - patch_data->resize(patch_size); - std::copy(DataForPatch(), DataForPatch() + patch_size, patch_data->begin()); - return true; - } - +bool ImageChunk::MakePatch(const ImageChunk& tgt, const ImageChunk& src, + std::vector<uint8_t>* patch_data, saidx_t** bsdiff_cache) { #if defined(__ANDROID__) char ptemp[] = "/data/local/tmp/imgdiff-patch-XXXXXX"; #else @@ -424,8 +246,8 @@ bool ImageChunk::MakePatch(const ImageChunk& src, std::vector<uint8_t>* patch_da } close(fd); - int r = bsdiff::bsdiff(src.DataForPatch(), src.DataLengthForPatch(), DataForPatch(), - DataLengthForPatch(), ptemp, bsdiff_cache); + int r = bsdiff::bsdiff(src.DataForPatch(), src.DataLengthForPatch(), tgt.DataForPatch(), + tgt.DataLengthForPatch(), ptemp, bsdiff_cache); if (r != 0) { printf("bsdiff() failed: %d\n", r); return false; @@ -443,14 +265,7 @@ bool ImageChunk::MakePatch(const ImageChunk& src, std::vector<uint8_t>* patch_da } size_t sz = static_cast<size_t>(st.st_size); - // Change the chunk type to raw if the patch takes less space that way. - if (ChangeChunkToRaw(sz)) { - unlink(ptemp); - size_t patch_size = DataLengthForPatch(); - patch_data->resize(patch_size); - std::copy(DataForPatch(), DataForPatch() + patch_size, patch_data->begin()); - return true; - } + patch_data->resize(sz); if (!android::base::ReadFully(patch_fd, patch_data->data(), sz)) { printf("failed to read \"%s\" %s\n", ptemp, strerror(errno)); @@ -459,7 +274,6 @@ bool ImageChunk::MakePatch(const ImageChunk& src, std::vector<uint8_t>* patch_da } unlink(ptemp); - SetSourceInfo(src); return true; } @@ -470,8 +284,8 @@ bool ImageChunk::ReconstructDeflateChunk() { return false; } - // We only check two combinations of encoder parameters: level 6 - // (the default) and level 9 (the maximum). + // We only check two combinations of encoder parameters: level 6 (the default) and level 9 + // (the maximum). for (int level = 6; level <= 9; level += 3) { if (TryReconstruction(level)) { compress_level_ = level; @@ -483,10 +297,9 @@ bool ImageChunk::ReconstructDeflateChunk() { } /* - * Takes the uncompressed data stored in the chunk, compresses it - * using the zlib parameters stored in the chunk, and checks that it - * matches exactly the compressed data we started with (also stored in - * the chunk). + * Takes the uncompressed data stored in the chunk, compresses it using the zlib parameters stored + * in the chunk, and checks that it matches exactly the compressed data we started with (also + * stored in the chunk). */ bool ImageChunk::TryReconstruction(int level) { z_stream strm; @@ -529,55 +342,136 @@ bool ImageChunk::TryReconstruction(int level) { return true; } -// Interface for zip_mode and image_mode images. We initialize the image from an input file and -// split the file content into a list of image chunks. -class Image { - public: - explicit Image(bool is_source) : is_source_(is_source) {} - - virtual ~Image() {} - - // Create a list of image chunks from input file. - virtual bool Initialize(const std::string& filename) = 0; +PatchChunk::PatchChunk(const ImageChunk& tgt, const ImageChunk& src, std::vector<uint8_t> data) + : type_(tgt.GetType()), + source_start_(src.GetStartOffset()), + source_len_(src.GetRawDataLength()), + source_uncompressed_len_(src.DataLengthForPatch()), + target_start_(tgt.GetStartOffset()), + target_len_(tgt.GetRawDataLength()), + target_uncompressed_len_(tgt.DataLengthForPatch()), + target_compress_level_(tgt.GetCompressLevel()), + data_(std::move(data)) {} + +// Construct a CHUNK_RAW patch from the target data directly. +PatchChunk::PatchChunk(const ImageChunk& tgt) + : type_(CHUNK_RAW), + source_start_(0), + source_len_(0), + source_uncompressed_len_(0), + target_start_(tgt.GetStartOffset()), + target_len_(tgt.GetRawDataLength()), + target_uncompressed_len_(tgt.DataLengthForPatch()), + target_compress_level_(tgt.GetCompressLevel()), + data_(tgt.DataForPatch(), tgt.DataForPatch() + tgt.DataLengthForPatch()) {} + +// Return true if raw data is smaller than the patch size. +bool PatchChunk::RawDataIsSmaller(const ImageChunk& tgt, size_t patch_size) { + size_t target_len = tgt.GetRawDataLength(); + return (tgt.GetType() == CHUNK_NORMAL && (target_len <= 160 || target_len < patch_size)); +} - // Look for runs of adjacent normal chunks and compress them down into a single chunk. (Such - // runs can be produced when deflate chunks are changed to normal chunks.) - void MergeAdjacentNormalChunks(); +// Header size: +// header_type 4 bytes +// CHUNK_NORMAL 8*3 = 24 bytes +// CHUNK_DEFLATE 8*5 + 4*5 = 60 bytes +// CHUNK_RAW 4 bytes + patch_size +size_t PatchChunk::GetHeaderSize() const { + switch (type_) { + case CHUNK_NORMAL: + return 4 + 8 * 3; + case CHUNK_DEFLATE: + return 4 + 8 * 5 + 4 * 5; + case CHUNK_RAW: + return 4 + 4 + data_.size(); + default: + CHECK(false) << "unexpected chunk type: " << type_; // Should not reach here. + return 0; + } +} - // In zip mode, find the matching deflate source chunk by entry name. Search for normal chunks - // also if |find_normal| is true. - ImageChunk* FindChunkByName(const std::string& name, bool find_normal = false); +// Return the offset of the next patch into the patch data. +size_t PatchChunk::WriteHeaderToFd(int fd, size_t offset) const { + Write4(fd, type_); + switch (type_) { + case CHUNK_NORMAL: + printf("normal (%10zu, %10zu) %10zu\n", target_start_, target_len_, data_.size()); + Write8(fd, static_cast<int64_t>(source_start_)); + Write8(fd, static_cast<int64_t>(source_len_)); + Write8(fd, static_cast<int64_t>(offset)); + return offset + data_.size(); + case CHUNK_DEFLATE: + printf("deflate (%10zu, %10zu) %10zu\n", target_start_, target_len_, data_.size()); + Write8(fd, static_cast<int64_t>(source_start_)); + Write8(fd, static_cast<int64_t>(source_len_)); + Write8(fd, static_cast<int64_t>(offset)); + Write8(fd, static_cast<int64_t>(source_uncompressed_len_)); + Write8(fd, static_cast<int64_t>(target_uncompressed_len_)); + Write4(fd, target_compress_level_); + Write4(fd, ImageChunk::METHOD); + Write4(fd, ImageChunk::WINDOWBITS); + Write4(fd, ImageChunk::MEMLEVEL); + Write4(fd, ImageChunk::STRATEGY); + return offset + data_.size(); + case CHUNK_RAW: + printf("raw (%10zu, %10zu)\n", target_start_, target_len_); + Write4(fd, static_cast<int32_t>(data_.size())); + if (!android::base::WriteFully(fd, data_.data(), data_.size())) { + CHECK(false) << "failed to write " << data_.size() << " bytes patch"; + } + return offset; + default: + CHECK(false) << "unexpected chunk type: " << type_; + return offset; + } +} - // Write the contents of |patch_data| to |patch_fd|. - bool WritePatchDataToFd(const std::vector<std::vector<uint8_t>>& patch_data, int patch_fd) const; +// 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 + // the offset of each bsdiff patch within the file. + size_t total_header_size = 12; + for (const auto& patch : patch_chunks) { + total_header_size += patch.GetHeaderSize(); + } - void DumpChunks() const; + size_t offset = total_header_size; - // Non const iterators to access the stored ImageChunks. - std::vector<ImageChunk>::iterator begin() { - return chunks_.begin(); + // Write out the headers. + if (!android::base::WriteStringToFd("IMGDIFF2", patch_fd)) { + printf("failed to write \"IMGDIFF2\": %s\n", strerror(errno)); + return false; } - std::vector<ImageChunk>::iterator end() { - return chunks_.end(); - } - // Return a pointer to the ith ImageChunk. - ImageChunk* Get(size_t i) { - CHECK_LT(i, chunks_.size()); - return &chunks_[i]; + Write4(patch_fd, static_cast<int32_t>(patch_chunks.size())); + for (size_t i = 0; i < patch_chunks.size(); ++i) { + printf("chunk %zu: ", i); + offset = patch_chunks[i].WriteHeaderToFd(patch_fd, offset); } - size_t NumOfChunks() const { - return chunks_.size(); + // Append each chunk's bsdiff patch, in order. + for (const auto& patch : patch_chunks) { + if (patch.type_ == CHUNK_RAW) { + continue; + } + if (!android::base::WriteFully(patch_fd, patch.data_.data(), patch.data_.size())) { + printf("failed to write %zu bytes patch to patch_fd\n", patch.data_.size()); + return false; + } } - protected: - bool ReadFile(const std::string& filename, std::vector<uint8_t>* file_content); + return true; +} + +ImageChunk& Image::operator[](size_t i) { + CHECK_LT(i, chunks_.size()); + return chunks_[i]; +} - bool is_source_; // True if it's for source chunks. - std::vector<ImageChunk> chunks_; // Internal storage of ImageChunk. - std::vector<uint8_t> file_content_; // Store the whole input file in memory. -}; +const ImageChunk& Image::operator[](size_t i) const { + CHECK_LT(i, chunks_.size()); + return chunks_[i]; +} void Image::MergeAdjacentNormalChunks() { size_t merged_last = 0, cur = 0; @@ -601,54 +495,6 @@ void Image::MergeAdjacentNormalChunks() { } } -ImageChunk* Image::FindChunkByName(const std::string& name, bool find_normal) { - if (name.empty()) { - return nullptr; - } - for (auto& chunk : chunks_) { - if ((chunk.GetType() == CHUNK_DEFLATE || find_normal) && chunk.GetEntryName() == name) { - return &chunk; - } - } - return nullptr; -} - -bool Image::WritePatchDataToFd(const std::vector<std::vector<uint8_t>>& patch_data, - int patch_fd) const { - // Figure out how big the imgdiff file header is going to be, so that we can correctly compute - // the offset of each bsdiff patch within the file. - CHECK_EQ(chunks_.size(), patch_data.size()); - size_t total_header_size = 12; - for (size_t i = 0; i < chunks_.size(); ++i) { - total_header_size += chunks_[i].GetHeaderSize(patch_data[i].size()); - } - - 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)); - return false; - } - Write4(patch_fd, static_cast<int32_t>(chunks_.size())); - for (size_t i = 0; i < chunks_.size(); ++i) { - printf("chunk %zu: ", i); - offset = chunks_[i].WriteHeaderToFd(patch_fd, patch_data[i], offset); - } - - // Append each chunk's bsdiff patch, in order. - for (size_t i = 0; i < chunks_.size(); ++i) { - if (chunks_[i].GetType() != CHUNK_RAW) { - if (!android::base::WriteFully(patch_fd, patch_data[i].data(), patch_data[i].size())) { - printf("failed to write %zu bytes patch for chunk %zu\n", patch_data[i].size(), i); - return false; - } - } - } - - return true; -} - void Image::DumpChunks() const { std::string type = is_source_ ? "source" : "target"; printf("Dumping chunks for %s\n", type.c_str()); @@ -683,39 +529,6 @@ bool Image::ReadFile(const std::string& filename, std::vector<uint8_t>* file_con return true; } -class ZipModeImage : public Image { - public: - explicit ZipModeImage(bool is_source) : Image(is_source) {} - - bool Initialize(const std::string& filename) override; - - const ImageChunk& PseudoSource() const { - CHECK(is_source_); - CHECK(pseudo_source_ != nullptr); - return *pseudo_source_; - } - - // Verify that we can reconstruct the deflate chunks; also change the type to CHUNK_NORMAL if - // src and tgt are identical. - static bool CheckAndProcessChunks(ZipModeImage* tgt_image, ZipModeImage* src_image); - - // Compute the patches against the input image, and write the data into |patch_name|. - static bool GeneratePatches(ZipModeImage* tgt_image, ZipModeImage* src_image, - const std::string& patch_name); - - private: - // Initialize image chunks based on the zip entries. - bool InitializeChunks(const std::string& filename, ZipArchiveHandle handle); - // Add the a zip entry to the list. - bool AddZipEntryToChunks(ZipArchiveHandle handle, const std::string& entry_name, ZipEntry* entry); - // Return the real size of the zip file. (omit the trailing zeros that used for alignment) - bool GetZipFileSize(size_t* input_file_size); - - // The pesudo source chunk for bsdiff if there's no match for the given target chunk. It's in - // fact the whole source file. - std::unique_ptr<ImageChunk> pseudo_source_; -}; - bool ZipModeImage::Initialize(const std::string& filename) { if (!ReadFile(filename, &file_content_)) { return false; @@ -736,9 +549,6 @@ bool ZipModeImage::Initialize(const std::string& filename) { return false; } - if (is_source_) { - pseudo_source_ = std::make_unique<ImageChunk>(CHUNK_NORMAL, 0, &file_content_, zipfile_size); - } if (!InitializeChunks(filename, handle)) { CloseArchive(handle); return false; @@ -834,14 +644,11 @@ bool ZipModeImage::AddZipEntryToChunks(ZipArchiveHandle handle, const std::strin ErrorCodeString(ret)); return false; } - ImageChunk curr(CHUNK_DEFLATE, entry->offset, &file_content_, compressed_len); - curr.SetEntryName(entry_name); + ImageChunk curr(CHUNK_DEFLATE, entry->offset, &file_content_, compressed_len, entry_name); curr.SetUncompressedData(std::move(uncompressed_data)); - chunks_.push_back(curr); + chunks_.push_back(std::move(curr)); } else { - ImageChunk curr(CHUNK_NORMAL, entry->offset, &file_content_, compressed_len); - curr.SetEntryName(entry_name); - chunks_.push_back(curr); + chunks_.emplace_back(CHUNK_NORMAL, entry->offset, &file_content_, compressed_len, entry_name); } return true; @@ -880,6 +687,28 @@ bool ZipModeImage::GetZipFileSize(size_t* input_file_size) { return false; } +ImageChunk ZipModeImage::PseudoSource() const { + CHECK(is_source_); + return ImageChunk(CHUNK_NORMAL, 0, &file_content_, file_content_.size()); +} + +const ImageChunk* ZipModeImage::FindChunkByName(const std::string& name, bool find_normal) const { + if (name.empty()) { + return nullptr; + } + for (auto& chunk : chunks_) { + if ((chunk.GetType() == CHUNK_DEFLATE || find_normal) && chunk.GetEntryName() == name) { + return &chunk; + } + } + return nullptr; +} + +ImageChunk* ZipModeImage::FindChunkByName(const std::string& name, bool find_normal) { + return const_cast<ImageChunk*>( + static_cast<const ZipModeImage*>(this)->FindChunkByName(name, find_normal)); +} + bool ZipModeImage::CheckAndProcessChunks(ZipModeImage* tgt_image, ZipModeImage* src_image) { for (auto& tgt_chunk : *tgt_image) { if (tgt_chunk.GetType() != CHUNK_DEFLATE) { @@ -907,40 +736,55 @@ bool ZipModeImage::CheckAndProcessChunks(ZipModeImage* tgt_image, ZipModeImage* } } - return true; -} - -bool ZipModeImage::GeneratePatches(ZipModeImage* tgt_image, ZipModeImage* src_image, - const std::string& patch_name) { // For zips, we only need merge normal chunks for the target: deflated chunks are matched via // filename, and normal chunks are patched using the entire source file as the source. tgt_image->MergeAdjacentNormalChunks(); tgt_image->DumpChunks(); - printf("Construct patches for %zu chunks...\n", tgt_image->NumOfChunks()); - std::vector<std::vector<uint8_t>> patch_data(tgt_image->NumOfChunks()); + return true; +} + +bool ZipModeImage::GeneratePatches(const ZipModeImage& tgt_image, const ZipModeImage& src_image, + const std::string& patch_name) { + printf("Construct patches for %zu chunks...\n", tgt_image.NumOfChunks()); + std::vector<PatchChunk> patch_chunks; + patch_chunks.reserve(tgt_image.NumOfChunks()); saidx_t* bsdiff_cache = nullptr; - size_t i = 0; - for (auto& tgt_chunk : *tgt_image) { - ImageChunk* src_chunk = (tgt_chunk.GetType() != CHUNK_DEFLATE) - ? nullptr - : src_image->FindChunkByName(tgt_chunk.GetEntryName()); + for (size_t i = 0; i < tgt_image.NumOfChunks(); i++) { + const auto& tgt_chunk = tgt_image[i]; + + if (PatchChunk::RawDataIsSmaller(tgt_chunk, 0)) { + patch_chunks.emplace_back(tgt_chunk); + continue; + } - const auto& src_ref = (src_chunk == nullptr) ? src_image->PseudoSource() : *src_chunk; + const ImageChunk* src_chunk = (tgt_chunk.GetType() != CHUNK_DEFLATE) + ? nullptr + : 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; - if (!tgt_chunk.MakePatch(src_ref, &patch_data[i], bsdiff_cache_ptr)) { + std::vector<uint8_t> patch_data; + if (!ImageChunk::MakePatch(tgt_chunk, src_ref, &patch_data, bsdiff_cache_ptr)) { printf("Failed to generate patch, name: %s\n", tgt_chunk.GetEntryName().c_str()); return false; } - printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data[i].size(), + printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data.size(), tgt_chunk.GetRawDataLength()); - i++; + + if (PatchChunk::RawDataIsSmaller(tgt_chunk, patch_data.size())) { + patch_chunks.emplace_back(tgt_chunk); + } else { + patch_chunks.emplace_back(tgt_chunk, src_ref, std::move(patch_data)); + } } free(bsdiff_cache); + CHECK_EQ(tgt_image.NumOfChunks(), patch_chunks.size()); + android::base::unique_fd patch_fd( open(patch_name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)); if (patch_fd == -1) { @@ -948,26 +792,9 @@ bool ZipModeImage::GeneratePatches(ZipModeImage* tgt_image, ZipModeImage* src_im return false; } - return tgt_image->WritePatchDataToFd(patch_data, patch_fd); + return PatchChunk::WritePatchDataToFd(patch_chunks, patch_fd); } -class ImageModeImage : public Image { - public: - explicit ImageModeImage(bool is_source) : Image(is_source) {} - - // Initialize the image chunks list by searching the magic numbers in an image file. - bool Initialize(const std::string& filename) override; - - // In Image Mode, verify that the source and target images have the same chunk structure (ie, the - // same sequence of deflate and normal chunks). - static bool CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeImage* src_image); - - // In image mode, generate patches against the given source chunks and bonus_data; write the - // result to |patch_name|. - static bool GeneratePatches(ImageModeImage* tgt_image, ImageModeImage* src_image, - const std::vector<uint8_t>& bonus_data, const std::string& patch_name); -}; - bool ImageModeImage::Initialize(const std::string& filename) { if (!ReadFile(filename, &file_content_)) { return false; @@ -1053,7 +880,7 @@ bool ImageModeImage::Initialize(const std::string& filename) { ImageChunk body(CHUNK_DEFLATE, pos, &file_content_, raw_data_len); uncompressed_data.resize(uncompressed_len); body.SetUncompressedData(std::move(uncompressed_data)); - chunks_.push_back(body); + chunks_.push_back(std::move(body)); pos += raw_data_len; @@ -1083,6 +910,18 @@ bool ImageModeImage::Initialize(const std::string& filename) { return true; } +bool ImageModeImage::SetBonusData(const std::vector<uint8_t>& bonus_data) { + CHECK(is_source_); + if (chunks_.size() < 2 || !chunks_[1].SetBonusData(bonus_data)) { + printf("Failed to set bonus data\n"); + DumpChunks(); + return false; + } + + printf(" using %zu bytes of bonus data\n", bonus_data.size()); + return true; +} + // In Image Mode, verify that the source and target images have the same chunk structure (ie, the // same sequence of deflate and normal chunks). bool ImageModeImage::CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeImage* src_image) { @@ -1097,7 +936,7 @@ bool ImageModeImage::CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeI return false; } for (size_t i = 0; i < tgt_image->NumOfChunks(); ++i) { - if (tgt_image->Get(i)->GetType() != src_image->Get(i)->GetType()) { + if ((*tgt_image)[i].GetType() != (*src_image)[i].GetType()) { printf("source and target don't have same chunk structure! (chunk %zu)\n", i); tgt_image->DumpChunks(); src_image->DumpChunks(); @@ -1106,26 +945,23 @@ bool ImageModeImage::CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeI } for (size_t i = 0; i < tgt_image->NumOfChunks(); ++i) { - auto& tgt_chunk = *tgt_image->Get(i); - auto& src_chunk = *src_image->Get(i); + auto& tgt_chunk = (*tgt_image)[i]; + auto& src_chunk = (*src_image)[i]; if (tgt_chunk.GetType() != CHUNK_DEFLATE) { continue; } - // Confirm that we can recompress the data and get exactly the same bits as are in the - // input target image. - if (!tgt_chunk.ReconstructDeflateChunk()) { - printf("failed to reconstruct target deflate chunk %zu [%s]; treating as normal\n", i, - tgt_chunk.GetEntryName().c_str()); - tgt_chunk.ChangeDeflateChunkToNormal(); - src_chunk.ChangeDeflateChunkToNormal(); - continue; - } - // If two deflate chunks are identical treat them as normal chunks. if (tgt_chunk == src_chunk) { tgt_chunk.ChangeDeflateChunkToNormal(); src_chunk.ChangeDeflateChunkToNormal(); + } else if (!tgt_chunk.ReconstructDeflateChunk()) { + // We cannot recompress the data and get exactly the same bits as are in the input target + // image, fall back to normal + printf("failed to reconstruct target deflate chunk %zu [%s]; treating as normal\n", i, + tgt_chunk.GetEntryName().c_str()); + tgt_chunk.ChangeDeflateChunkToNormal(); + src_chunk.ChangeDeflateChunkToNormal(); } } @@ -1144,29 +980,39 @@ bool ImageModeImage::CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeI // In image mode, generate patches against the given source chunks and bonus_data; write the // result to |patch_name|. -bool ImageModeImage::GeneratePatches(ImageModeImage* tgt_image, ImageModeImage* src_image, - const std::vector<uint8_t>& bonus_data, +bool ImageModeImage::GeneratePatches(const ImageModeImage& tgt_image, + const ImageModeImage& src_image, const std::string& patch_name) { - printf("Construct patches for %zu chunks...\n", tgt_image->NumOfChunks()); - std::vector<std::vector<uint8_t>> patch_data(tgt_image->NumOfChunks()); + printf("Construct patches for %zu chunks...\n", tgt_image.NumOfChunks()); + std::vector<PatchChunk> patch_chunks; + patch_chunks.reserve(tgt_image.NumOfChunks()); - for (size_t i = 0; i < tgt_image->NumOfChunks(); i++) { - auto& tgt_chunk = *tgt_image->Get(i); - auto& src_chunk = *src_image->Get(i); + for (size_t i = 0; i < tgt_image.NumOfChunks(); i++) { + const auto& tgt_chunk = tgt_image[i]; + const auto& src_chunk = src_image[i]; - if (i == 1 && !bonus_data.empty()) { - printf(" using %zu bytes of bonus data for chunk %zu\n", bonus_data.size(), i); - src_chunk.SetBonusData(bonus_data); + if (PatchChunk::RawDataIsSmaller(tgt_chunk, 0)) { + patch_chunks.emplace_back(tgt_chunk); + continue; } - if (!tgt_chunk.MakePatch(src_chunk, &patch_data[i], nullptr)) { + std::vector<uint8_t> patch_data; + if (!ImageChunk::MakePatch(tgt_chunk, src_chunk, &patch_data, nullptr)) { printf("Failed to generate patch for target chunk %zu: ", i); return false; } - printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data[i].size(), + printf("patch %3zu is %zu bytes (of %zu)\n", i, patch_data.size(), tgt_chunk.GetRawDataLength()); + + if (PatchChunk::RawDataIsSmaller(tgt_chunk, patch_data.size())) { + patch_chunks.emplace_back(tgt_chunk); + } else { + patch_chunks.emplace_back(tgt_chunk, src_chunk, std::move(patch_data)); + } } + CHECK_EQ(tgt_image.NumOfChunks(), patch_chunks.size()); + android::base::unique_fd patch_fd( open(patch_name.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR)); if (patch_fd == -1) { @@ -1174,7 +1020,7 @@ bool ImageModeImage::GeneratePatches(ImageModeImage* tgt_image, ImageModeImage* return false; } - return tgt_image->WritePatchDataToFd(patch_data, patch_fd); + return PatchChunk::WritePatchDataToFd(patch_chunks, patch_fd); } int imgdiff(int argc, const char** argv) { @@ -1236,7 +1082,7 @@ 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 (!ZipModeImage::GeneratePatches(&tgt_image, &src_image, argv[optind + 2])) { + if (!ZipModeImage::GeneratePatches(tgt_image, src_image, argv[optind + 2])) { return 1; } } else { @@ -1253,7 +1099,12 @@ int imgdiff(int argc, const char** argv) { if (!ImageModeImage::CheckAndProcessChunks(&tgt_image, &src_image)) { return 1; } - if (!ImageModeImage::GeneratePatches(&tgt_image, &src_image, bonus_data, argv[optind + 2])) { + + if (!bonus_data.empty() && !src_image.SetBonusData(bonus_data)) { + return 1; + } + + if (!ImageModeImage::GeneratePatches(tgt_image, src_image, argv[optind + 2])) { return 1; } } diff --git a/applypatch/include/applypatch/imgdiff_image.h b/applypatch/include/applypatch/imgdiff_image.h new file mode 100644 index 000000000..221dd5ab5 --- /dev/null +++ b/applypatch/include/applypatch/imgdiff_image.h @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _APPLYPATCH_IMGDIFF_IMAGE_H +#define _APPLYPATCH_IMGDIFF_IMAGE_H + +#include <stddef.h> +#include <stdio.h> +#include <sys/types.h> + +#include <string> +#include <vector> + +#include <bsdiff.h> +#include <ziparchive/zip_archive.h> +#include <zlib.h> + +#include "imgdiff.h" +#include "rangeset.h" + +class ImageChunk { + public: + static constexpr auto WINDOWBITS = -15; // 32kb window; negative to indicate a raw stream. + static constexpr auto MEMLEVEL = 8; // the default value. + static constexpr auto METHOD = Z_DEFLATED; + static constexpr auto STRATEGY = Z_DEFAULT_STRATEGY; + + ImageChunk(int type, size_t start, const std::vector<uint8_t>* file_content, size_t raw_data_len, + std::string entry_name = {}); + + int GetType() const { + return type_; + } + size_t GetRawDataLength() const { + return raw_data_len_; + } + const std::string& GetEntryName() const { + return entry_name_; + } + size_t GetStartOffset() const { + return start_; + } + int GetCompressLevel() const { + return compress_level_; + } + + // CHUNK_DEFLATE will return the uncompressed data for diff, while other types will simply return + // the raw data. + const uint8_t* DataForPatch() const; + size_t DataLengthForPatch() const; + + void Dump() const { + printf("type: %d, start: %zu, len: %zu, name: %s\n", type_, start_, DataLengthForPatch(), + entry_name_.c_str()); + } + + void SetUncompressedData(std::vector<uint8_t> data); + bool SetBonusData(const std::vector<uint8_t>& bonus_data); + + bool operator==(const ImageChunk& other) const; + bool operator!=(const ImageChunk& other) const { + return !(*this == other); + } + + /* + * Cause a gzip chunk to be treated as a normal chunk (ie, as a blob of uninterpreted data). + * The resulting patch will likely be about as big as the target file, but it lets us handle + * the case of images where some gzip chunks are reconstructible but others aren't (by treating + * the ones that aren't as normal chunks). + */ + void ChangeDeflateChunkToNormal(); + + /* + * Verify that we can reproduce exactly the same compressed data that we started with. Sets the + * level, method, windowBits, memLevel, and strategy fields in the chunk to the encoding + * parameters needed to produce the right output. + */ + bool ReconstructDeflateChunk(); + bool IsAdjacentNormal(const ImageChunk& other) const; + void MergeAdjacentNormal(const ImageChunk& other); + + /* + * Compute a bsdiff patch between |src| and |tgt|; Store the result in the patch_data. + * |bsdiff_cache| can be used to cache the suffix array if the same |src| chunk is used + * 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); + + private: + const uint8_t* GetRawData() const; + bool TryReconstruction(int level); + + int type_; // CHUNK_NORMAL, CHUNK_DEFLATE, CHUNK_RAW + size_t start_; // offset of chunk in the original input file + const std::vector<uint8_t>* input_file_ptr_; // ptr to the full content of original input file + size_t raw_data_len_; + + // deflate encoder parameters + int compress_level_; + + // --- for CHUNK_DEFLATE chunks only: --- + std::vector<uint8_t> uncompressed_data_; + std::string entry_name_; // used for zip entries +}; + +// PatchChunk stores the patch data between a source chunk and a target chunk. It also keeps track +// of the metadata of src&tgt chunks (e.g. offset, raw data length, uncompressed data length). +class PatchChunk { + public: + PatchChunk(const ImageChunk& tgt, const ImageChunk& src, std::vector<uint8_t> data); + + // Construct a CHUNK_RAW patch from the target data directly. + explicit PatchChunk(const ImageChunk& tgt); + + // Return true if raw data size is smaller than the patch size. + static bool RawDataIsSmaller(const ImageChunk& tgt, size_t patch_size); + + static bool WritePatchDataToFd(const std::vector<PatchChunk>& patch_chunks, int patch_fd); + + private: + size_t GetHeaderSize() const; + size_t WriteHeaderToFd(int fd, size_t offset) const; + + // The patch chunk type is the same as the target chunk type. The only exception is we change + // the |type_| to CHUNK_RAW if target length is smaller than the patch size. + int type_; + + size_t source_start_; + size_t source_len_; + size_t source_uncompressed_len_; + + size_t target_start_; // offset of the target chunk within the target file + size_t target_len_; + size_t target_uncompressed_len_; + size_t target_compress_level_; // the deflate compression level of the target chunk. + + std::vector<uint8_t> data_; // storage for the patch data +}; + +// Interface for zip_mode and image_mode images. We initialize the image from an input file and +// split the file content into a list of image chunks. +class Image { + public: + explicit Image(bool is_source) : is_source_(is_source) {} + + virtual ~Image() {} + + // Create a list of image chunks from input file. + virtual bool Initialize(const std::string& filename) = 0; + + // Look for runs of adjacent normal chunks and compress them down into a single chunk. (Such + // runs can be produced when deflate chunks are changed to normal chunks.) + void MergeAdjacentNormalChunks(); + + void DumpChunks() const; + + // Non const iterators to access the stored ImageChunks. + std::vector<ImageChunk>::iterator begin() { + return chunks_.begin(); + } + + std::vector<ImageChunk>::iterator end() { + return chunks_.end(); + } + + ImageChunk& operator[](size_t i); + const ImageChunk& operator[](size_t i) const; + + size_t NumOfChunks() const { + return chunks_.size(); + } + + protected: + bool ReadFile(const std::string& filename, std::vector<uint8_t>* file_content); + + bool is_source_; // True if it's for source chunks. + std::vector<ImageChunk> chunks_; // Internal storage of ImageChunk. + std::vector<uint8_t> file_content_; // Store the whole input file in memory. +}; + +class ZipModeImage : public Image { + public: + explicit ZipModeImage(bool is_source) : Image(is_source) {} + + bool Initialize(const std::string& filename) override; + + // The pesudo source chunk for bsdiff if there's no match for the given target chunk. It's in + // fact the whole source file. + ImageChunk PseudoSource() const; + + // Find the matching deflate source chunk by entry name. Search for normal chunks also if + // |find_normal| is true. + ImageChunk* FindChunkByName(const std::string& name, bool find_normal = false); + + const ImageChunk* FindChunkByName(const std::string& name, bool find_normal = false) const; + + // Verify that we can reconstruct the deflate chunks; also change the type to CHUNK_NORMAL if + // src and tgt are identical. + static bool CheckAndProcessChunks(ZipModeImage* tgt_image, ZipModeImage* src_image); + + // Compute the patch between tgt & src images, and write the data into |patch_name|. + static bool GeneratePatches(const ZipModeImage& tgt_image, const ZipModeImage& src_image, + const std::string& patch_name); + + private: + // Initialize image chunks based on the zip entries. + bool InitializeChunks(const std::string& filename, ZipArchiveHandle handle); + // Add the a zip entry to the list. + bool AddZipEntryToChunks(ZipArchiveHandle handle, const std::string& entry_name, ZipEntry* entry); + // Return the real size of the zip file. (omit the trailing zeros that used for alignment) + bool GetZipFileSize(size_t* input_file_size); +}; + +class ImageModeImage : public Image { + public: + explicit ImageModeImage(bool is_source) : Image(is_source) {} + + // Initialize the image chunks list by searching the magic numbers in an image file. + bool Initialize(const std::string& filename) override; + + bool SetBonusData(const std::vector<uint8_t>& bonus_data); + + // In Image Mode, verify that the source and target images have the same chunk structure (ie, the + // same sequence of deflate and normal chunks). + static bool CheckAndProcessChunks(ImageModeImage* tgt_image, ImageModeImage* src_image); + + // In image mode, generate patches against the given source chunks and bonus_data; write the + // result to |patch_name|. + static bool GeneratePatches(const ImageModeImage& tgt_image, const ImageModeImage& src_image, + const std::string& patch_name); +}; + +#endif // _APPLYPATCH_IMGDIFF_IMAGE_H diff --git a/etc/init.rc b/etc/init.rc index 2e3c7a739..d8121cc4e 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -79,9 +79,9 @@ service ueventd /sbin/ueventd critical seclabel u:r:ueventd:s0 -service healthd /sbin/healthd -r +service charger /charger -r critical - seclabel u:r:healthd:s0 + seclabel u:r:charger:s0 service recovery /sbin/recovery seclabel u:r:recovery:s0 diff --git a/minui/graphics.cpp b/minui/graphics.cpp index 3bdc33fd1..3bfce11d8 100644 --- a/minui/graphics.cpp +++ b/minui/graphics.cpp @@ -258,7 +258,7 @@ unsigned int gr_get_height(GRSurface* surface) { } int gr_init_font(const char* name, GRFont** dest) { - GRFont* font = reinterpret_cast<GRFont*>(calloc(1, sizeof(*gr_font))); + GRFont* font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font))); if (font == nullptr) { return -1; } @@ -291,7 +291,7 @@ static void gr_init_font(void) // fall back to the compiled-in font. - gr_font = static_cast<GRFont*>(calloc(sizeof(*gr_font), 1)); + gr_font = static_cast<GRFont*>(calloc(1, sizeof(*gr_font))); gr_font->texture = static_cast<GRSurface*>(malloc(sizeof(*gr_font->texture))); gr_font->texture->width = font.width; gr_font->texture->height = font.height; diff --git a/updater/include/updater/rangeset.h b/rangeset.h index b67c98724..f224a08be 100644 --- a/updater/include/updater/rangeset.h +++ b/rangeset.h @@ -266,13 +266,13 @@ class SortedRangeSet : public RangeSet { new_block_start += (old_block_start - range.first); return (new_block_start * kBlockSize + old_offset % kBlockSize); } else { - CHECK(false) <<"block_start " << old_block_start << " is missing between two ranges: " - << this->ToString(); + CHECK(false) << "block_start " << old_block_start + << " is missing between two ranges: " << this->ToString(); return 0; } } - CHECK(false) <<"block_start " << old_block_start << " exceeds the limit of current RangeSet: " - << this->ToString(); + CHECK(false) << "block_start " << old_block_start + << " exceeds the limit of current RangeSet: " << this->ToString(); return 0; } };
\ No newline at end of file diff --git a/recovery.cpp b/recovery.cpp index 233e56246..6f62ff17c 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -53,6 +53,7 @@ #include <healthd/BatteryMonitor.h> #include <private/android_logger.h> /* private pmsg functions */ #include <private/android_filesystem_config.h> /* for AID_SYSTEM */ +#include <selinux/android.h> #include <selinux/label.h> #include <selinux/selinux.h> #include <ziparchive/zip_archive.h> @@ -757,12 +758,13 @@ static bool wipe_data(Device* device) { } static bool prompt_and_wipe_data(Device* device) { + // Use a single string and let ScreenRecoveryUI handles the wrapping. const char* const headers[] = { - "Can't load Android system. Your data may be corrupt.", - "If you continue to get this message, you may need to", - "perform a factory data reset and erase all user data", + "Can't load Android system. Your data may be corrupt. " + "If you continue to get this message, you may need to " + "perform a factory data reset and erase all user data " "stored on this device.", - NULL + nullptr }; const char* const items[] = { "Try again", @@ -1479,12 +1481,8 @@ int main(int argc, char **argv) { ui->SetBackground(RecoveryUI::NONE); if (show_text) ui->ShowText(true); - struct selinux_opt seopts[] = { - { SELABEL_OPT_PATH, "/file_contexts" } - }; - - sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); - + sehandle = selinux_android_file_context_handle(); + selinux_android_set_sehandle(sehandle); if (!sehandle) { ui->Print("Warning: No file_contexts\n"); } diff --git a/screen_ui.cpp b/screen_ui.cpp index c83a7659e..5c93b6672 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -278,6 +278,34 @@ int ScreenRecoveryUI::DrawTextLines(int x, int y, const char* const* lines) cons return offset; } +int ScreenRecoveryUI::DrawWrappedTextLines(int x, int y, const char* const* lines) const { + int offset = 0; + for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) { + // The line will be wrapped if it exceeds text_cols_. + std::string line(lines[i]); + size_t next_start = 0; + while (next_start < line.size()) { + std::string sub = line.substr(next_start, text_cols_ + 1); + if (sub.size() <= text_cols_) { + next_start += sub.size(); + } else { + // Line too long and must be wrapped to text_cols_ columns. + size_t last_space = sub.find_last_of(" \t\n"); + if (last_space == std::string::npos) { + // No space found, just draw as much as we can + sub.resize(text_cols_); + next_start += text_cols_; + } else { + sub.resize(last_space); + next_start += last_space + 1; + } + } + offset += DrawTextLine(x, y + offset, sub.c_str(), false); + } + } + return offset; +} + static const char* REGULAR_HELP[] = { "Use volume up/down and power.", NULL @@ -316,7 +344,8 @@ void ScreenRecoveryUI::draw_screen_locked() { y += DrawTextLines(x, y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP); SetColor(HEADER); - y += DrawTextLines(x, y, menu_headers_); + // Ignore kMenuIndent, which is not taken into account by text_cols_. + y += DrawWrappedTextLines(kMarginWidth, y, menu_headers_); SetColor(MENU); y += DrawHorizontalRule(y) + 4; diff --git a/screen_ui.h b/screen_ui.h index 1f40164af..62dda7558 100644 --- a/screen_ui.h +++ b/screen_ui.h @@ -187,6 +187,9 @@ class ScreenRecoveryUI : public RecoveryUI { virtual int DrawTextLine(int x, int y, const char* line, bool bold) const; // Draws multiple text lines. Returns the offset it should be moving along Y-axis. int DrawTextLines(int x, int y, const char* const* lines) const; + // Similar to DrawTextLines() to draw multiple text lines, but additionally wraps long lines. + // Returns the offset it should be moving along Y-axis. + int DrawWrappedTextLines(int x, int y, const char* const* lines) const; }; #endif // RECOVERY_UI_H diff --git a/tests/component/verifier_test.cpp b/tests/component/verifier_test.cpp index 5338f05c6..e520f5028 100644 --- a/tests/component/verifier_test.cpp +++ b/tests/component/verifier_test.cpp @@ -33,6 +33,8 @@ #include "otautil/SysUtil.h" #include "verifier.h" +using namespace std::string_literals; + class VerifierTest : public testing::TestWithParam<std::vector<std::string>> { protected: void SetUp() override { @@ -115,6 +117,21 @@ TEST(VerifierTest, load_keys_invalid_keys) { ASSERT_FALSE(load_keys(key_file5.path, certs)); } +TEST(VerifierTest, BadPackage_SignatureStartOutOfBounds) { + std::string testkey_v3; + ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3)); + + TemporaryFile key_file; + ASSERT_TRUE(android::base::WriteStringToFile(testkey_v3, key_file.path)); + std::vector<Certificate> certs; + ASSERT_TRUE(load_keys(key_file.path, certs)); + + // Signature start is 65535 (0xffff) while comment size is 0 (Bug: 31914369). + std::string package = "\x50\x4b\x05\x06"s + std::string(12, '\0') + "\xff\xff\xff\xff\x00\x00"s; + ASSERT_EQ(VERIFY_FAILURE, verify_file(reinterpret_cast<const unsigned char*>(package.data()), + package.size(), certs)); +} + TEST(VerifierTest, BadPackage_AlteredFooter) { std::string testkey_v3; ASSERT_TRUE(android::base::ReadFileToString(from_testdata_base("testkey_v3.txt"), &testkey_v3)); diff --git a/tests/unit/rangeset_test.cpp b/tests/unit/rangeset_test.cpp index 3993cb9ea..15bcec855 100644 --- a/tests/unit/rangeset_test.cpp +++ b/tests/unit/rangeset_test.cpp @@ -21,7 +21,7 @@ #include <gtest/gtest.h> -#include "updater/rangeset.h" +#include "rangeset.h" TEST(RangeSetTest, Parse_smoke) { RangeSet rs = RangeSet::Parse("2,1,10"); diff --git a/tools/recovery_l10n/res/values-az-rAZ/strings.xml b/tools/recovery_l10n/res/values-az/strings.xml index c6765a9ea..c6765a9ea 100644 --- a/tools/recovery_l10n/res/values-az-rAZ/strings.xml +++ b/tools/recovery_l10n/res/values-az/strings.xml diff --git a/tools/recovery_l10n/res/values-b+sr+Latn/strings.xml b/tools/recovery_l10n/res/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000..c2d8f2239 --- /dev/null +++ b/tools/recovery_l10n/res/values-b+sr+Latn/strings.xml @@ -0,0 +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">"Ažuriranje sistema se instalira"</string> + <string name="recovery_erasing" msgid="7334826894904037088">"Briše se"</string> + <string name="recovery_no_command" msgid="4465476568623024327">"Nema komande"</string> + <string name="recovery_error" msgid="5748178989622716736">"Greška!"</string> + <string name="recovery_installing_security" msgid="9184031299717114342">"Instalira se bezbednosno ažuriranje"</string> +</resources> diff --git a/tools/recovery_l10n/res/values-be/strings.xml b/tools/recovery_l10n/res/values-be/strings.xml new file mode 100644 index 000000000..7c0954d31 --- /dev/null +++ b/tools/recovery_l10n/res/values-be/strings.xml @@ -0,0 +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_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> +</resources> diff --git a/tools/recovery_l10n/res/values-bn-rBD/strings.xml b/tools/recovery_l10n/res/values-bn/strings.xml index 0a481faf1..0a481faf1 100644 --- a/tools/recovery_l10n/res/values-bn-rBD/strings.xml +++ b/tools/recovery_l10n/res/values-bn/strings.xml diff --git a/tools/recovery_l10n/res/values-bs/strings.xml b/tools/recovery_l10n/res/values-bs/strings.xml new file mode 100644 index 000000000..412cf0276 --- /dev/null +++ b/tools/recovery_l10n/res/values-bs/strings.xml @@ -0,0 +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">"Ažuriranje sistema…"</string> + <string name="recovery_erasing" msgid="7334826894904037088">"Brisanje u toku"</string> + <string name="recovery_no_command" msgid="4465476568623024327">"Nema komande"</string> + <string name="recovery_error" msgid="5748178989622716736">"Greška!"</string> + <string name="recovery_installing_security" msgid="9184031299717114342">"Instaliranje sigurnosnog ažuriranja…"</string> +</resources> diff --git a/tools/recovery_l10n/res/values-et-rEE/strings.xml b/tools/recovery_l10n/res/values-et/strings.xml index 072a9ef80..072a9ef80 100644 --- a/tools/recovery_l10n/res/values-et-rEE/strings.xml +++ b/tools/recovery_l10n/res/values-et/strings.xml diff --git a/tools/recovery_l10n/res/values-eu-rES/strings.xml b/tools/recovery_l10n/res/values-eu/strings.xml index 5540469d0..5540469d0 100644 --- a/tools/recovery_l10n/res/values-eu-rES/strings.xml +++ b/tools/recovery_l10n/res/values-eu/strings.xml diff --git a/tools/recovery_l10n/res/values-gl-rES/strings.xml b/tools/recovery_l10n/res/values-gl/strings.xml index 42b2016c2..42b2016c2 100644 --- a/tools/recovery_l10n/res/values-gl-rES/strings.xml +++ b/tools/recovery_l10n/res/values-gl/strings.xml diff --git a/tools/recovery_l10n/res/values-gu-rIN/strings.xml b/tools/recovery_l10n/res/values-gu/strings.xml index 2355a0f4f..2355a0f4f 100644 --- a/tools/recovery_l10n/res/values-gu-rIN/strings.xml +++ b/tools/recovery_l10n/res/values-gu/strings.xml diff --git a/tools/recovery_l10n/res/values-hy-rAM/strings.xml b/tools/recovery_l10n/res/values-hy/strings.xml index 9d62bb763..9d62bb763 100644 --- a/tools/recovery_l10n/res/values-hy-rAM/strings.xml +++ b/tools/recovery_l10n/res/values-hy/strings.xml diff --git a/tools/recovery_l10n/res/values-is-rIS/strings.xml b/tools/recovery_l10n/res/values-is/strings.xml index 5065b6522..5065b6522 100644 --- a/tools/recovery_l10n/res/values-is-rIS/strings.xml +++ b/tools/recovery_l10n/res/values-is/strings.xml diff --git a/tools/recovery_l10n/res/values-ka-rGE/strings.xml b/tools/recovery_l10n/res/values-ka/strings.xml index 6a46b3677..6a46b3677 100644 --- a/tools/recovery_l10n/res/values-ka-rGE/strings.xml +++ b/tools/recovery_l10n/res/values-ka/strings.xml diff --git a/tools/recovery_l10n/res/values-kk-rKZ/strings.xml b/tools/recovery_l10n/res/values-kk/strings.xml index a4bd86e66..a4bd86e66 100644 --- a/tools/recovery_l10n/res/values-kk-rKZ/strings.xml +++ b/tools/recovery_l10n/res/values-kk/strings.xml diff --git a/tools/recovery_l10n/res/values-km-rKH/strings.xml b/tools/recovery_l10n/res/values-km/strings.xml index 313c0f457..313c0f457 100644 --- a/tools/recovery_l10n/res/values-km-rKH/strings.xml +++ b/tools/recovery_l10n/res/values-km/strings.xml diff --git a/tools/recovery_l10n/res/values-kn-rIN/strings.xml b/tools/recovery_l10n/res/values-kn/strings.xml index 5bf6260ee..5bf6260ee 100644 --- a/tools/recovery_l10n/res/values-kn-rIN/strings.xml +++ b/tools/recovery_l10n/res/values-kn/strings.xml diff --git a/tools/recovery_l10n/res/values-ky-rKG/strings.xml b/tools/recovery_l10n/res/values-ky/strings.xml index 0a6bd783a..0a6bd783a 100644 --- a/tools/recovery_l10n/res/values-ky-rKG/strings.xml +++ b/tools/recovery_l10n/res/values-ky/strings.xml diff --git a/tools/recovery_l10n/res/values-lo-rLA/strings.xml b/tools/recovery_l10n/res/values-lo/strings.xml index d3dbb3970..d3dbb3970 100644 --- a/tools/recovery_l10n/res/values-lo-rLA/strings.xml +++ b/tools/recovery_l10n/res/values-lo/strings.xml diff --git a/tools/recovery_l10n/res/values-mk-rMK/strings.xml b/tools/recovery_l10n/res/values-mk/strings.xml index 351459730..351459730 100644 --- a/tools/recovery_l10n/res/values-mk-rMK/strings.xml +++ b/tools/recovery_l10n/res/values-mk/strings.xml diff --git a/tools/recovery_l10n/res/values-ml-rIN/strings.xml b/tools/recovery_l10n/res/values-ml/strings.xml index b506e2530..b506e2530 100644 --- a/tools/recovery_l10n/res/values-ml-rIN/strings.xml +++ b/tools/recovery_l10n/res/values-ml/strings.xml diff --git a/tools/recovery_l10n/res/values-mn-rMN/strings.xml b/tools/recovery_l10n/res/values-mn/strings.xml index e3dd2e90e..e3dd2e90e 100644 --- a/tools/recovery_l10n/res/values-mn-rMN/strings.xml +++ b/tools/recovery_l10n/res/values-mn/strings.xml diff --git a/tools/recovery_l10n/res/values-mr-rIN/strings.xml b/tools/recovery_l10n/res/values-mr/strings.xml index 8cf86f773..8cf86f773 100644 --- a/tools/recovery_l10n/res/values-mr-rIN/strings.xml +++ b/tools/recovery_l10n/res/values-mr/strings.xml diff --git a/tools/recovery_l10n/res/values-ms-rMY/strings.xml b/tools/recovery_l10n/res/values-ms/strings.xml index 0e24ac4e1..0e24ac4e1 100644 --- a/tools/recovery_l10n/res/values-ms-rMY/strings.xml +++ b/tools/recovery_l10n/res/values-ms/strings.xml diff --git a/tools/recovery_l10n/res/values-my-rMM/strings.xml b/tools/recovery_l10n/res/values-my/strings.xml index f13752461..f13752461 100644 --- a/tools/recovery_l10n/res/values-my-rMM/strings.xml +++ b/tools/recovery_l10n/res/values-my/strings.xml diff --git a/tools/recovery_l10n/res/values-ne-rNP/strings.xml b/tools/recovery_l10n/res/values-ne/strings.xml index 1880e807b..1880e807b 100644 --- a/tools/recovery_l10n/res/values-ne-rNP/strings.xml +++ b/tools/recovery_l10n/res/values-ne/strings.xml diff --git a/tools/recovery_l10n/res/values-pa-rIN/strings.xml b/tools/recovery_l10n/res/values-pa/strings.xml index 8564c9c36..8564c9c36 100644 --- a/tools/recovery_l10n/res/values-pa-rIN/strings.xml +++ b/tools/recovery_l10n/res/values-pa/strings.xml diff --git a/tools/recovery_l10n/res/values-si-rLK/strings.xml b/tools/recovery_l10n/res/values-si/strings.xml index 456cdc567..456cdc567 100644 --- a/tools/recovery_l10n/res/values-si-rLK/strings.xml +++ b/tools/recovery_l10n/res/values-si/strings.xml diff --git a/tools/recovery_l10n/res/values-sq-rAL/strings.xml b/tools/recovery_l10n/res/values-sq/strings.xml index 1156931fb..1156931fb 100644 --- a/tools/recovery_l10n/res/values-sq-rAL/strings.xml +++ b/tools/recovery_l10n/res/values-sq/strings.xml diff --git a/tools/recovery_l10n/res/values-ta-rIN/strings.xml b/tools/recovery_l10n/res/values-ta/strings.xml index d49186d8d..d49186d8d 100644 --- a/tools/recovery_l10n/res/values-ta-rIN/strings.xml +++ b/tools/recovery_l10n/res/values-ta/strings.xml diff --git a/tools/recovery_l10n/res/values-te-rIN/strings.xml b/tools/recovery_l10n/res/values-te/strings.xml index cfb02c915..cfb02c915 100644 --- a/tools/recovery_l10n/res/values-te-rIN/strings.xml +++ b/tools/recovery_l10n/res/values-te/strings.xml diff --git a/tools/recovery_l10n/res/values-ur-rPK/strings.xml b/tools/recovery_l10n/res/values-ur/strings.xml index 12e32fbc1..12e32fbc1 100644 --- a/tools/recovery_l10n/res/values-ur-rPK/strings.xml +++ b/tools/recovery_l10n/res/values-ur/strings.xml diff --git a/tools/recovery_l10n/res/values-uz-rUZ/strings.xml b/tools/recovery_l10n/res/values-uz/strings.xml index 2c309d646..2c309d646 100644 --- a/tools/recovery_l10n/res/values-uz-rUZ/strings.xml +++ b/tools/recovery_l10n/res/values-uz/strings.xml diff --git a/uncrypt/uncrypt.cpp b/uncrypt/uncrypt.cpp index 35998bcba..7a2ccbc7c 100644 --- a/uncrypt/uncrypt.cpp +++ b/uncrypt/uncrypt.cpp @@ -625,12 +625,12 @@ int main(int argc, char** argv) { } if (action == UNCRYPT_DEBUG) { - LOG(INFO) << "uncrypt called in debug mode, skip socket communication\n"; + LOG(INFO) << "uncrypt called in debug mode, skip socket communication"; bool success = uncrypt_wrapper(input_path, map_file, -1); if (success) { - LOG(INFO) << "uncrypt succeeded\n"; + LOG(INFO) << "uncrypt succeeded"; } else{ - LOG(INFO) << "uncrypt failed\n"; + LOG(INFO) << "uncrypt failed"; } return success ? 0 : 1; } diff --git a/update_verifier/update_verifier_main.cpp b/update_verifier/update_verifier_main.cpp index 46e8bbb59..9dd5a0cc4 100644 --- a/update_verifier/update_verifier_main.cpp +++ b/update_verifier/update_verifier_main.cpp @@ -16,8 +16,14 @@ // See the comments in update_verifier.cpp. +#include <android-base/logging.h> + #include "update_verifier/update_verifier.h" int main(int argc, char** argv) { + // Set up update_verifier logging to be written to kmsg; because we may not have Logd during + // boot time. + android::base::InitLogging(argv, &android::base::KernelLogger); + return update_verifier(argc, argv); } diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index a0b9ad233..fe21dd0eb 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -53,8 +53,8 @@ #include "error_code.h" #include "ota_io.h" #include "print_sha1.h" +#include "rangeset.h" #include "updater/install.h" -#include "updater/rangeset.h" #include "updater/updater.h" // Set this to 0 to interpret 'erase' transfers to mean do a diff --git a/updater/updater.cpp b/updater/updater.cpp index f5ff6df91..1d8fa8e92 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -25,6 +25,7 @@ #include <android-base/logging.h> #include <android-base/strings.h> +#include <selinux/android.h> #include <selinux/label.h> #include <selinux/selinux.h> #include <ziparchive/zip_archive.h> @@ -139,9 +140,8 @@ int main(int argc, char** argv) { return 6; } - struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } }; - - sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + sehandle = selinux_android_file_context_handle(); + selinux_android_set_sehandle(sehandle); if (!sehandle) { fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); |