diff options
-rw-r--r-- | minadbd/Android.mk | 1 | ||||
-rw-r--r-- | minadbd/AndroidTest.xml | 26 | ||||
-rw-r--r-- | tests/Android.mk | 6 | ||||
-rw-r--r-- | tests/AndroidTest.xml | 31 | ||||
-rw-r--r-- | update_verifier/Android.mk | 2 | ||||
-rw-r--r-- | update_verifier/update_verifier.rc | 11 | ||||
-rw-r--r-- | updater/blockimg.cpp | 313 | ||||
-rw-r--r-- | updater/install.cpp | 16 |
8 files changed, 229 insertions, 177 deletions
diff --git a/minadbd/Android.mk b/minadbd/Android.mk index 7eef13ee0..de0b0c890 100644 --- a/minadbd/Android.mk +++ b/minadbd/Android.mk @@ -29,6 +29,7 @@ include $(CLEAR_VARS) LOCAL_CLANG := true LOCAL_MODULE := minadbd_test +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_SRC_FILES := fuse_adb_provider_test.cpp LOCAL_CFLAGS := $(minadbd_cflags) LOCAL_C_INCLUDES := $(LOCAL_PATH) system/core/adb diff --git a/minadbd/AndroidTest.xml b/minadbd/AndroidTest.xml new file mode 100644 index 000000000..7ea235b7c --- /dev/null +++ b/minadbd/AndroidTest.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<configuration description="Config for minadbd_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="minadbd_test->/data/local/tmp/minadbd_test" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="minadbd_test" /> + </test> +</configuration>
\ No newline at end of file diff --git a/tests/Android.mk b/tests/Android.mk index ff6e14c9b..80eae8f37 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -20,7 +20,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_CFLAGS := -Werror LOCAL_MODULE := recovery_unit_test -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_STATIC_LIBRARIES := \ libverifier \ libminui \ @@ -45,10 +45,8 @@ include $(BUILD_NATIVE_TEST) # Manual tests include $(CLEAR_VARS) -LOCAL_CLANG := true LOCAL_CFLAGS := -Werror LOCAL_MODULE := recovery_manual_test -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_STATIC_LIBRARIES := \ libminui \ libbase @@ -85,8 +83,8 @@ LOCAL_CFLAGS := \ -Werror \ -D_FILE_OFFSET_BITS=64 -LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := recovery_component_test +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_C_INCLUDES := bootable/recovery LOCAL_SRC_FILES := \ component/applypatch_test.cpp \ diff --git a/tests/AndroidTest.xml b/tests/AndroidTest.xml new file mode 100644 index 000000000..3999aa57d --- /dev/null +++ b/tests/AndroidTest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<configuration description="Config for recovery_component_test and recovery_unit_test"> + <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> + <option name="cleanup" value="true" /> + <option name="push" value="recovery_component_test->/data/local/tmp/recovery_component_test" /> + <option name="push" value="recovery_unit_test->/data/local/tmp/recovery_unit_test" /> + </target_preparer> + <option name="test-suite-tag" value="apct" /> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="recovery_component_test" /> + </test> + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="recovery_unit_test" /> + </test> +</configuration> diff --git a/update_verifier/Android.mk b/update_verifier/Android.mk index c1051a54a..1acd5eca0 100644 --- a/update_verifier/Android.mk +++ b/update_verifier/Android.mk @@ -32,6 +32,8 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_CFLAGS := -Werror LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. +LOCAL_INIT_RC := update_verifier.rc + ifeq ($(PRODUCTS.$(INTERNAL_PRODUCT).PRODUCT_SUPPORTS_VERITY),true) LOCAL_CFLAGS += -DPRODUCT_SUPPORTS_VERITY=1 endif diff --git a/update_verifier/update_verifier.rc b/update_verifier/update_verifier.rc new file mode 100644 index 000000000..fc8a64dee --- /dev/null +++ b/update_verifier/update_verifier.rc @@ -0,0 +1,11 @@ +service update_verifier_nonencrypted /system/bin/update_verifier nonencrypted + user root + class cache + priority -20 + ioprio rt 1 + +service update_verifier /system/bin/update_verifier ${vold.decrypt} + user root + class cache + priority -20 + ioprio rt 1
\ No newline at end of file diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 8c0f885a1..a1a5773d4 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -18,6 +18,7 @@ #include <errno.h> #include <dirent.h> #include <fcntl.h> +#include <inttypes.h> #include <linux/fs.h> #include <pthread.h> #include <stdarg.h> @@ -231,125 +232,135 @@ static void allocate(size_t size, std::vector<uint8_t>& buffer) { buffer.resize(size); } -struct RangeSinkState { - explicit RangeSinkState(RangeSet& rs) : tgt(rs) { }; - - int fd; - const RangeSet& tgt; - size_t p_block; - size_t p_remain; -}; +/** + * RangeSinkWriter reads data from the given FD, and writes them to the destination specified by the + * given RangeSet. + */ +class RangeSinkWriter { + public: + RangeSinkWriter(int fd, const RangeSet& tgt) + : fd_(fd), tgt_(tgt), next_range_(0), current_range_left_(0) { + CHECK_NE(tgt.count, static_cast<size_t>(0)); + }; -static size_t RangeSinkWrite(const uint8_t* data, size_t size, RangeSinkState* rss) { - if (rss->p_remain == 0) { - LOG(ERROR) << "range sink write overrun"; - return 0; + bool Finished() const { + return next_range_ == tgt_.count && current_range_left_ == 0; } - size_t written = 0; - while (size > 0) { - size_t write_now = size; - - if (rss->p_remain < write_now) { - write_now = rss->p_remain; - } - - if (write_all(rss->fd, data, write_now) == -1) { - break; + size_t Write(const uint8_t* data, size_t size) { + if (Finished()) { + LOG(ERROR) << "range sink write overrun; can't write " << size << " bytes"; + return 0; } - data += write_now; - size -= write_now; - - rss->p_remain -= write_now; - written += write_now; - - if (rss->p_remain == 0) { - // Move to the next block. - ++rss->p_block; - if (rss->p_block < rss->tgt.count) { - rss->p_remain = - (rss->tgt.pos[rss->p_block * 2 + 1] - rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE; - - off64_t offset = static_cast<off64_t>(rss->tgt.pos[rss->p_block * 2]) * BLOCKSIZE; - if (!discard_blocks(rss->fd, offset, rss->p_remain)) { + size_t written = 0; + while (size > 0) { + // Move to the next range as needed. + if (current_range_left_ == 0) { + if (next_range_ < tgt_.count) { + off64_t offset = static_cast<off64_t>(tgt_.pos[next_range_ * 2]) * BLOCKSIZE; + current_range_left_ = + (tgt_.pos[next_range_ * 2 + 1] - tgt_.pos[next_range_ * 2]) * BLOCKSIZE; + next_range_++; + if (!discard_blocks(fd_, offset, current_range_left_)) { + break; + } + + if (!check_lseek(fd_, offset, SEEK_SET)) { + break; + } + } else { + // We can't write any more; return how many bytes have been written so far. break; } + } - if (!check_lseek(rss->fd, offset, SEEK_SET)) { - break; - } + size_t write_now = size; + if (current_range_left_ < write_now) { + write_now = current_range_left_; + } - } else { - // We can't write any more; return how many bytes have been written so far. + if (write_all(fd_, data, write_now) == -1) { break; } + + data += write_now; + size -= write_now; + + current_range_left_ -= write_now; + written += write_now; } - } - return written; -} + return written; + } -// All of the data for all the 'new' transfers is contained in one -// file in the update package, concatenated together in the order in -// which transfers.list will need it. We want to stream it out of the -// archive (it's compressed) without writing it to a temp file, but we -// can't write each section until it's that transfer's turn to go. -// -// To achieve this, we expand the new data from the archive in a -// background thread, and block that threads 'receive uncompressed -// data' function until the main thread has reached a point where we -// want some new data to be written. We signal the background thread -// with the destination for the data and block the main thread, -// waiting for the background thread to complete writing that section. -// Then it signals the main thread to wake up and goes back to -// blocking waiting for a transfer. -// -// NewThreadInfo is the struct used to pass information back and forth -// between the two threads. When the main thread wants some data -// written, it sets rss to the destination location and signals the -// condition. When the background thread is done writing, it clears -// rss and signals the condition again. + private: + // The input data. + int fd_; + // The destination for the data. + const RangeSet& tgt_; + // The next range that we should write to. + size_t next_range_; + // The number of bytes to write before moving to the next range. + size_t current_range_left_; +}; +/** + * All of the data for all the 'new' transfers is contained in one file in the update package, + * concatenated together in the order in which transfers.list will need it. We want to stream it out + * of the archive (it's compressed) without writing it to a temp file, but we can't write each + * section until it's that transfer's turn to go. + * + * To achieve this, we expand the new data from the archive in a background thread, and block that + * threads 'receive uncompressed data' function until the main thread has reached a point where we + * want some new data to be written. We signal the background thread with the destination for the + * data and block the main thread, waiting for the background thread to complete writing that + * section. Then it signals the main thread to wake up and goes back to blocking waiting for a + * transfer. + * + * NewThreadInfo is the struct used to pass information back and forth between the two threads. When + * the main thread wants some data written, it sets writer to the destination location and signals + * the condition. When the background thread is done writing, it clears writer and signals the + * condition again. + */ struct NewThreadInfo { - ZipArchiveHandle za; - ZipEntry entry; + ZipArchiveHandle za; + ZipEntry entry; - RangeSinkState* rss; + RangeSinkWriter* writer; - pthread_mutex_t mu; - pthread_cond_t cv; + pthread_mutex_t mu; + pthread_cond_t cv; }; static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) { - NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie); + NewThreadInfo* nti = static_cast<NewThreadInfo*>(cookie); - while (size > 0) { - // Wait for nti->rss to be non-null, indicating some of this - // data is wanted. - pthread_mutex_lock(&nti->mu); - while (nti->rss == nullptr) { - pthread_cond_wait(&nti->cv, &nti->mu); - } - pthread_mutex_unlock(&nti->mu); + while (size > 0) { + // Wait for nti->writer to be non-null, indicating some of this data is wanted. + pthread_mutex_lock(&nti->mu); + while (nti->writer == nullptr) { + pthread_cond_wait(&nti->cv, &nti->mu); + } + pthread_mutex_unlock(&nti->mu); - // At this point nti->rss is set, and we own it. The main - // thread is waiting for it to disappear from nti. - size_t written = RangeSinkWrite(data, size, nti->rss); - data += written; - size -= written; + // At this point nti->writer is set, and we own it. The main thread is waiting for it to + // disappear from nti. + size_t written = nti->writer->Write(data, size); + data += written; + size -= written; - if (nti->rss->p_block == nti->rss->tgt.count) { - // we have written all the bytes desired by this rss. + if (nti->writer->Finished()) { + // We have written all the bytes desired by this writer. - pthread_mutex_lock(&nti->mu); - nti->rss = nullptr; - pthread_cond_broadcast(&nti->cv); - pthread_mutex_unlock(&nti->mu); - } + pthread_mutex_lock(&nti->mu); + nti->writer = nullptr; + pthread_cond_broadcast(&nti->cv); + pthread_mutex_unlock(&nti->mu); } + } - return true; + return true; } static void* unzip_new_data(void* cookie) { @@ -380,28 +391,26 @@ static int ReadBlocks(const RangeSet& src, std::vector<uint8_t>& buffer, int fd) } static int WriteBlocks(const RangeSet& tgt, const std::vector<uint8_t>& buffer, int fd) { - const uint8_t* data = buffer.data(); - - size_t p = 0; - for (size_t i = 0; i < tgt.count; ++i) { - off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE; - size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE; - if (!discard_blocks(fd, offset, size)) { - return -1; - } - - if (!check_lseek(fd, offset, SEEK_SET)) { - return -1; - } + size_t written = 0; + for (size_t i = 0; i < tgt.count; ++i) { + off64_t offset = static_cast<off64_t>(tgt.pos[i * 2]) * BLOCKSIZE; + size_t size = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * BLOCKSIZE; + if (!discard_blocks(fd, offset, size)) { + return -1; + } - if (write_all(fd, data + p, size) == -1) { - return -1; - } + if (!check_lseek(fd, offset, SEEK_SET)) { + return -1; + } - p += size; + if (write_all(fd, buffer.data() + written, size) == -1) { + return -1; } - return 0; + written += size; + } + + return 0; } // Parameters for transfer list command functions @@ -1214,45 +1223,31 @@ static int PerformCommandZero(CommandParameters& params) { } static int PerformCommandNew(CommandParameters& params) { + if (params.cpos >= params.tokens.size()) { + LOG(ERROR) << "missing target blocks for new"; + return -1; + } - if (params.cpos >= params.tokens.size()) { - LOG(ERROR) << "missing target blocks for new"; - return -1; - } - - RangeSet tgt = parse_range(params.tokens[params.cpos++]); - - if (params.canwrite) { - LOG(INFO) << " writing " << tgt.size << " blocks of new data"; - - RangeSinkState rss(tgt); - rss.fd = params.fd; - rss.p_block = 0; - rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE; - - off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE; - if (!discard_blocks(params.fd, offset, tgt.size * BLOCKSIZE)) { - return -1; - } - - if (!check_lseek(params.fd, offset, SEEK_SET)) { - return -1; - } + RangeSet tgt = parse_range(params.tokens[params.cpos++]); - pthread_mutex_lock(¶ms.nti.mu); - params.nti.rss = &rss; - pthread_cond_broadcast(¶ms.nti.cv); + if (params.canwrite) { + LOG(INFO) << " writing " << tgt.size << " blocks of new data"; - while (params.nti.rss) { - pthread_cond_wait(¶ms.nti.cv, ¶ms.nti.mu); - } + RangeSinkWriter writer(params.fd, tgt); + pthread_mutex_lock(¶ms.nti.mu); + params.nti.writer = &writer; + pthread_cond_broadcast(¶ms.nti.cv); - pthread_mutex_unlock(¶ms.nti.mu); + while (params.nti.writer != nullptr) { + pthread_cond_wait(¶ms.nti.cv, ¶ms.nti.mu); } - params.written += tgt.size; + pthread_mutex_unlock(¶ms.nti.mu); + } - return 0; + params.written += tgt.size; + + return 0; } static int PerformCommandDiff(CommandParameters& params) { @@ -1295,40 +1290,28 @@ static int PerformCommandDiff(CommandParameters& params) { LOG(INFO) << "patching " << blocks << " blocks to " << tgt.size; Value patch_value( VAL_BLOB, std::string(reinterpret_cast<const char*>(params.patch_start + offset), len)); - RangeSinkState rss(tgt); - rss.fd = params.fd; - rss.p_block = 0; - rss.p_remain = (tgt.pos[1] - tgt.pos[0]) * BLOCKSIZE; - - off64_t offset = static_cast<off64_t>(tgt.pos[0]) * BLOCKSIZE; - if (!discard_blocks(params.fd, offset, rss.p_remain)) { - return -1; - } - - if (!check_lseek(params.fd, offset, SEEK_SET)) { - return -1; - } + RangeSinkWriter writer(params.fd, tgt); if (params.cmdname[0] == 'i') { // imgdiff - if (ApplyImagePatch( - params.buffer.data(), blocks * BLOCKSIZE, &patch_value, - std::bind(&RangeSinkWrite, std::placeholders::_1, std::placeholders::_2, &rss), - nullptr, nullptr) != 0) { + if (ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, + std::bind(&RangeSinkWriter::Write, &writer, std::placeholders::_1, + std::placeholders::_2), + nullptr, nullptr) != 0) { LOG(ERROR) << "Failed to apply image patch."; return -1; } } else { - if (ApplyBSDiffPatch( - params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0, - std::bind(&RangeSinkWrite, std::placeholders::_1, std::placeholders::_2, &rss), - nullptr) != 0) { + if (ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0, + std::bind(&RangeSinkWriter::Write, &writer, std::placeholders::_1, + std::placeholders::_2), + nullptr) != 0) { LOG(ERROR) << "Failed to apply bsdiff patch."; return -1; } } // We expect the output of the patcher to fill the tgt ranges exactly. - if (rss.p_block != tgt.count || rss.p_remain != 0) { + if (!writer.Finished()) { LOG(ERROR) << "range sink underrun?"; } } else { @@ -1831,7 +1814,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, uint16_t mount_count = *reinterpret_cast<uint16_t*>(&block0_buffer[0x400+0x34]); if (mount_count > 0) { - uiPrintf(state, "Device was remounted R/W %d times\n", mount_count); + uiPrintf(state, "Device was remounted R/W %" PRIu16 " times", mount_count); uiPrintf(state, "Last remount happened on %s", ctime(&mount_time)); } diff --git a/updater/install.cpp b/updater/install.cpp index f91f3fc9f..857d7f1e0 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -181,8 +181,8 @@ Value* MountFn(const char* name, State* state, const std::vector<std::unique_ptr if (mount(location.c_str(), mount_point.c_str(), fs_type.c_str(), MS_NOATIME | MS_NODEV | MS_NODIRATIME, mount_options.c_str()) < 0) { - uiPrintf(state, "%s: failed to mount %s at %s: %s\n", name, location.c_str(), - mount_point.c_str(), strerror(errno)); + uiPrintf(state, "%s: Failed to mount %s at %s: %s", name, location.c_str(), mount_point.c_str(), + strerror(errno)); return StringValue(""); } @@ -231,12 +231,12 @@ Value* UnmountFn(const char* name, State* state, const std::vector<std::unique_p scan_mounted_volumes(); MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str()); if (vol == nullptr) { - uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point.c_str()); + uiPrintf(state, "Failed to unmount %s: No such volume", mount_point.c_str()); return nullptr; } else { int ret = unmount_mounted_volume(vol); if (ret != 0) { - uiPrintf(state, "unmount of %s failed (%d): %s\n", mount_point.c_str(), ret, strerror(errno)); + uiPrintf(state, "Failed to unmount %s: %s", mount_point.c_str(), strerror(errno)); } } @@ -699,15 +699,15 @@ Value* ApplyPatchCheckFn(const char* name, State* state, const std::vector<std:: return StringValue(result == 0 ? "t" : ""); } -// This is the updater side handler for ui_print() in edify script. Contents -// will be sent over to the recovery side for on-screen display. +// This is the updater side handler for ui_print() in edify script. Contents will be sent over to +// the recovery side for on-screen display. Value* UIPrintFn(const char* name, State* state, const std::vector<std::unique_ptr<Expr>>& argv) { std::vector<std::string> args; if (!ReadArgs(state, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); } - std::string buffer = android::base::Join(args, "") + "\n"; + std::string buffer = android::base::Join(args, ""); uiPrint(state, buffer); return StringValue(buffer); } |