summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--minadbd/Android.mk1
-rw-r--r--minadbd/AndroidTest.xml26
-rw-r--r--tests/Android.mk6
-rw-r--r--tests/AndroidTest.xml31
-rw-r--r--update_verifier/Android.mk2
-rw-r--r--update_verifier/update_verifier.rc11
-rw-r--r--updater/blockimg.cpp313
-rw-r--r--updater/install.cpp16
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(&params.nti.mu);
- params.nti.rss = &rss;
- pthread_cond_broadcast(&params.nti.cv);
+ if (params.canwrite) {
+ LOG(INFO) << " writing " << tgt.size << " blocks of new data";
- while (params.nti.rss) {
- pthread_cond_wait(&params.nti.cv, &params.nti.mu);
- }
+ RangeSinkWriter writer(params.fd, tgt);
+ pthread_mutex_lock(&params.nti.mu);
+ params.nti.writer = &writer;
+ pthread_cond_broadcast(&params.nti.cv);
- pthread_mutex_unlock(&params.nti.mu);
+ while (params.nti.writer != nullptr) {
+ pthread_cond_wait(&params.nti.cv, &params.nti.mu);
}
- params.written += tgt.size;
+ pthread_mutex_unlock(&params.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);
}