summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--applypatch/applypatch.cpp45
-rw-r--r--applypatch/bspatch.cpp14
-rw-r--r--applypatch/imgpatch.cpp26
-rw-r--r--applypatch/include/applypatch/applypatch.h19
-rw-r--r--applypatch/include/applypatch/imgpatch.h9
-rw-r--r--edify/parser.yy3
-rw-r--r--install.cpp52
-rw-r--r--otautil/Android.mk12
-rw-r--r--otautil/ThermalUtil.cpp80
-rw-r--r--otautil/ThermalUtil.h24
-rw-r--r--tests/component/imgdiff_test.cpp80
-rw-r--r--tests/component/uncrypt_test.cpp185
-rw-r--r--updater/blockimg.cpp511
13 files changed, 574 insertions, 486 deletions
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 7be3fdbde..51bf3932a 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <functional>
#include <memory>
#include <string>
#include <utility>
@@ -42,7 +43,7 @@
#include "print_sha1.h"
static int LoadPartitionContents(const std::string& filename, FileContents* file);
-static ssize_t FileSink(const unsigned char* data, ssize_t len, void* token);
+static size_t FileSink(const unsigned char* data, size_t len, int fd);
static int GenerateTarget(const FileContents& source_file, const std::unique_ptr<Value>& patch,
const std::string& target_filename,
const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data);
@@ -194,8 +195,8 @@ int SaveFileContents(const char* filename, const FileContents* file) {
return -1;
}
- ssize_t bytes_written = FileSink(file->data.data(), file->data.size(), &fd);
- if (bytes_written != static_cast<ssize_t>(file->data.size())) {
+ size_t bytes_written = FileSink(file->data.data(), file->data.size(), fd);
+ if (bytes_written != file->data.size()) {
printf("short write of \"%s\" (%zd bytes of %zu): %s\n", filename, bytes_written,
file->data.size(), strerror(errno));
return -1;
@@ -433,25 +434,17 @@ int ShowLicenses() {
return 0;
}
-ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) {
- int fd = *static_cast<int*>(token);
- ssize_t done = 0;
- ssize_t wrote;
- while (done < len) {
- wrote = TEMP_FAILURE_RETRY(ota_write(fd, data+done, len-done));
- if (wrote == -1) {
- printf("error writing %zd bytes: %s\n", (len-done), strerror(errno));
- return done;
- }
- done += wrote;
+static size_t FileSink(const unsigned char* data, size_t len, int fd) {
+ size_t done = 0;
+ while (done < len) {
+ ssize_t wrote = TEMP_FAILURE_RETRY(ota_write(fd, data + done, len - done));
+ if (wrote == -1) {
+ printf("error writing %zd bytes: %s\n", (len - done), strerror(errno));
+ return done;
}
- return done;
-}
-
-ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
- std::string* s = static_cast<std::string*>(token);
- s->append(reinterpret_cast<const char*>(data), len);
- return len;
+ done += wrote;
+ }
+ return done;
}
// Return the amount of free space (in bytes) on the filesystem
@@ -647,9 +640,11 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
}
// We store the decoded output in memory.
- SinkFn sink = MemorySink;
std::string memory_sink_str; // Don't need to reserve space.
- void* token = &memory_sink_str;
+ SinkFn sink = [&memory_sink_str](const unsigned char* data, size_t len) {
+ memory_sink_str.append(reinterpret_cast<const char*>(data), len);
+ return len;
+ };
SHA_CTX ctx;
SHA1_Init(&ctx);
@@ -657,10 +652,10 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
int result;
if (use_bsdiff) {
result = ApplyBSDiffPatch(source_file.data.data(), source_file.data.size(), patch.get(), 0,
- sink, token, &ctx);
+ sink, &ctx);
} else {
result = ApplyImagePatch(source_file.data.data(), source_file.data.size(), patch.get(), sink,
- token, &ctx, bonus_data);
+ &ctx, bonus_data);
}
if (result != 0) {
diff --git a/applypatch/bspatch.cpp b/applypatch/bspatch.cpp
index 9920c2be1..f75a2c680 100644
--- a/applypatch/bspatch.cpp
+++ b/applypatch/bspatch.cpp
@@ -24,9 +24,9 @@
#include <sys/types.h>
#include <bspatch.h>
+#include <openssl/sha.h>
#include "applypatch/applypatch.h"
-#include "openssl/sha.h"
void ShowBSDiffLicense() {
puts("The bsdiff library used herein is:\n"
@@ -60,10 +60,10 @@ void ShowBSDiffLicense() {
);
}
-int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Value* patch,
- ssize_t patch_offset, SinkFn sink, void* token, SHA_CTX* ctx) {
- auto sha_sink = [&](const uint8_t* data, size_t len) {
- len = sink(data, len, token);
+int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch,
+ size_t patch_offset, SinkFn sink, SHA_CTX* ctx) {
+ auto sha_sink = [&sink, &ctx](const uint8_t* data, size_t len) {
+ len = sink(data, len);
if (ctx) SHA1_Update(ctx, data, len);
return len;
};
@@ -72,8 +72,8 @@ int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size, const Valu
patch->data.size(), sha_sink);
}
-int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size, const Value* patch,
- ssize_t patch_offset, std::vector<unsigned char>* new_data) {
+int ApplyBSDiffPatchMem(const unsigned char* old_data, size_t old_size, const Value* patch,
+ size_t patch_offset, std::vector<unsigned char>* new_data) {
auto vector_sink = [new_data](const uint8_t* data, size_t len) {
new_data->insert(new_data->end(), data, data + len);
return len;
diff --git a/applypatch/imgpatch.cpp b/applypatch/imgpatch.cpp
index adcc61fd6..7d8b7361c 100644
--- a/applypatch/imgpatch.cpp
+++ b/applypatch/imgpatch.cpp
@@ -43,12 +43,11 @@ static inline int32_t Read4(const void *address) {
return android::base::get_unaligned<int32_t>(address);
}
-int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
- const unsigned char* patch_data, ssize_t patch_size,
- SinkFn sink, void* token) {
+int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const unsigned char* patch_data,
+ size_t patch_size, SinkFn sink) {
Value patch(VAL_BLOB, std::string(reinterpret_cast<const char*>(patch_data), patch_size));
- return ApplyImagePatch(old_data, old_size, &patch, sink, token, nullptr, nullptr);
+ return ApplyImagePatch(old_data, old_size, &patch, sink, nullptr, nullptr);
}
/*
@@ -57,8 +56,8 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
* file, and update the SHA context with the output data as well.
* Return 0 on success.
*/
-int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value* patch,
- SinkFn sink, void* token, SHA_CTX* ctx, const Value* bonus_data) {
+int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink,
+ SHA_CTX* ctx, const Value* bonus_data) {
if (patch->data.size() < 12) {
printf("patch too short to contain header\n");
return -1;
@@ -97,11 +96,11 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
size_t src_len = static_cast<size_t>(Read8(normal_header + 8));
size_t patch_offset = static_cast<size_t>(Read8(normal_header + 16));
- if (src_start + src_len > static_cast<size_t>(old_size)) {
+ if (src_start + src_len > old_size) {
printf("source data too short\n");
return -1;
}
- ApplyBSDiffPatch(old_data + src_start, src_len, patch, patch_offset, sink, token, ctx);
+ ApplyBSDiffPatch(old_data + src_start, src_len, patch, patch_offset, sink, ctx);
} else if (type == CHUNK_RAW) {
const char* raw_header = &patch->data[pos];
pos += 4;
@@ -110,15 +109,14 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
return -1;
}
- ssize_t data_len = Read4(raw_header);
+ size_t data_len = static_cast<size_t>(Read4(raw_header));
if (pos + data_len > patch->data.size()) {
printf("failed to read chunk %d raw data\n", i);
return -1;
}
if (ctx) SHA1_Update(ctx, &patch->data[pos], data_len);
- if (sink(reinterpret_cast<const unsigned char*>(&patch->data[pos]), data_len, token) !=
- data_len) {
+ if (sink(reinterpret_cast<const unsigned char*>(&patch->data[pos]), data_len) != data_len) {
printf("failed to write chunk %d raw data\n", i);
return -1;
}
@@ -143,7 +141,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
int memLevel = Read4(deflate_header + 52);
int strategy = Read4(deflate_header + 56);
- if (src_start + src_len > static_cast<size_t>(old_size)) {
+ if (src_start + src_len > old_size) {
printf("source data too short\n");
return -1;
}
@@ -240,9 +238,9 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size, const Value
strm.avail_out = temp_data.size();
strm.next_out = temp_data.data();
ret = deflate(&strm, Z_FINISH);
- ssize_t have = temp_data.size() - strm.avail_out;
+ size_t have = temp_data.size() - strm.avail_out;
- if (sink(temp_data.data(), have, token) != have) {
+ if (sink(temp_data.data(), have) != have) {
printf("failed to write %zd compressed bytes to output\n", have);
return -1;
}
diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h
index 4489decb6..da55432d5 100644
--- a/applypatch/include/applypatch/applypatch.h
+++ b/applypatch/include/applypatch/applypatch.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/stat.h>
+#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -41,7 +42,7 @@ struct FileContents {
// and use it as the source instead.
#define CACHE_TEMP_SOURCE "/cache/saved.file"
-typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*);
+using SinkFn = std::function<size_t(const unsigned char*, size_t)>;
// applypatch.cpp
int ShowLicenses();
@@ -66,18 +67,14 @@ int SaveFileContents(const char* filename, const FileContents* file);
// bspatch.cpp
void ShowBSDiffLicense();
-int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
- const Value* patch, ssize_t patch_offset,
- SinkFn sink, void* token, SHA_CTX* ctx);
-int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
- const Value* patch, ssize_t patch_offset,
- std::vector<unsigned char>* new_data);
+int ApplyBSDiffPatch(const unsigned char* old_data, size_t old_size, const Value* patch,
+ size_t patch_offset, SinkFn sink, SHA_CTX* ctx);
+int ApplyBSDiffPatchMem(const unsigned char* old_data, size_t old_size, const Value* patch,
+ size_t patch_offset, std::vector<unsigned char>* new_data);
// imgpatch.cpp
-int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
- const Value* patch,
- SinkFn sink, void* token, SHA_CTX* ctx,
- const Value* bonus_data);
+int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const Value* patch, SinkFn sink,
+ SHA_CTX* ctx, const Value* bonus_data);
// freecache.cpp
int MakeFreeSpaceOnCache(size_t bytes_needed);
diff --git a/applypatch/include/applypatch/imgpatch.h b/applypatch/include/applypatch/imgpatch.h
index 6549f79f0..07c66094f 100644
--- a/applypatch/include/applypatch/imgpatch.h
+++ b/applypatch/include/applypatch/imgpatch.h
@@ -19,10 +19,11 @@
#include <sys/types.h>
-using SinkFn = ssize_t (*)(const unsigned char*, ssize_t, void*);
+#include <functional>
-int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
- const unsigned char* patch_data, ssize_t patch_size,
- SinkFn sink, void* token);
+using SinkFn = std::function<size_t(const unsigned char*, size_t)>;
+
+int ApplyImagePatch(const unsigned char* old_data, size_t old_size, const unsigned char* patch_data,
+ size_t patch_size, SinkFn sink);
#endif // _APPLYPATCH_IMGPATCH_H
diff --git a/edify/parser.yy b/edify/parser.yy
index 97205fe3b..b1685eb1f 100644
--- a/edify/parser.yy
+++ b/edify/parser.yy
@@ -23,6 +23,8 @@
#include <string>
#include <vector>
+#include <android-base/macros.h>
+
#include "expr.h"
#include "yydefs.h"
#include "parser.h"
@@ -121,6 +123,7 @@ arglist: /* empty */ {
$$->emplace_back($1);
}
| arglist ',' expr {
+ UNUSED($1);
$$->push_back(std::unique_ptr<Expr>($3));
}
;
diff --git a/install.cpp b/install.cpp
index 7cef44a37..0a2fa3ca4 100644
--- a/install.cpp
+++ b/install.cpp
@@ -26,11 +26,15 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <algorithm>
#include <chrono>
+#include <condition_variable>
#include <functional>
#include <limits>
#include <map>
+#include <mutex>
#include <string>
+#include <thread>
#include <vector>
#include <android-base/file.h>
@@ -46,10 +50,13 @@
#include "error_code.h"
#include "minui/minui.h"
#include "otautil/SysUtil.h"
+#include "otautil/ThermalUtil.h"
#include "roots.h"
#include "ui.h"
#include "verifier.h"
+using namespace std::chrono_literals;
+
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
static constexpr const char* AB_OTA_PAYLOAD = "payload.bin";
@@ -63,6 +70,8 @@ static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25;
static constexpr float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
static constexpr float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
+static std::condition_variable finish_log_temperature;
+
// This function parses and returns the build.version.incremental
static int parse_build_number(const std::string& str) {
size_t pos = str.find('=');
@@ -299,9 +308,19 @@ update_binary_command(const char* path, ZipArchiveHandle zip, int retry_count,
}
#endif // !AB_OTA_UPDATER
+static void log_max_temperature(int* max_temperature) {
+ CHECK(max_temperature != nullptr);
+ std::mutex mtx;
+ std::unique_lock<std::mutex> lck(mtx);
+ while (finish_log_temperature.wait_for(lck, 20s) == std::cv_status::timeout) {
+ *max_temperature = std::max(*max_temperature, GetMaxValueFromThermalZone());
+ }
+}
+
// If the package contains an update binary, extract it and run it.
static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_cache,
- std::vector<std::string>& log_buffer, int retry_count) {
+ std::vector<std::string>& log_buffer, int retry_count,
+ int* max_temperature) {
read_source_target_build(zip, log_buffer);
int pipefd[2];
@@ -392,6 +411,8 @@ static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_
}
close(pipefd[1]);
+ std::thread temperature_logger(log_max_temperature, max_temperature);
+
*wipe_cache = false;
bool retry_update = false;
@@ -453,6 +474,10 @@ static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_
int status;
waitpid(pid, &status, 0);
+
+ finish_log_temperature.notify_one();
+ temperature_logger.join();
+
if (retry_update) {
return INSTALL_RETRY;
}
@@ -466,7 +491,7 @@ static int try_update_binary(const char* path, ZipArchiveHandle zip, bool* wipe_
static int
really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
- std::vector<std::string>& log_buffer, int retry_count)
+ std::vector<std::string>& log_buffer, int retry_count, int* max_temperature)
{
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
ui->Print("Finding update package...\n");
@@ -517,7 +542,7 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
ui->Print("Retry attempt: %d\n", retry_count);
}
ui->SetEnableReboot(false);
- int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count);
+ int result = try_update_binary(path, zip, wipe_cache, log_buffer, retry_count, max_temperature);
ui->SetEnableReboot(true);
ui->Print("\n");
@@ -533,13 +558,17 @@ install_package(const char* path, bool* wipe_cache, const char* install_file,
modified_flash = true;
auto start = std::chrono::system_clock::now();
+ int start_temperature = GetMaxValueFromThermalZone();
+ int max_temperature = start_temperature;
+
int result;
std::vector<std::string> log_buffer;
if (setup_install_mounts() != 0) {
LOG(ERROR) << "failed to set up expected mounts for install; aborting";
result = INSTALL_ERROR;
} else {
- result = really_install_package(path, wipe_cache, needs_mount, log_buffer, retry_count);
+ result = really_install_package(path, wipe_cache, needs_mount, log_buffer, retry_count,
+ &max_temperature);
}
// Measure the time spent to apply OTA update in seconds.
@@ -570,8 +599,21 @@ install_package(const char* path, bool* wipe_cache, const char* install_file,
"time_total: " + std::to_string(time_total),
"retry: " + std::to_string(retry_count),
};
+
+ int end_temperature = GetMaxValueFromThermalZone();
+ max_temperature = std::max(end_temperature, max_temperature);
+ if (start_temperature > 0) {
+ log_buffer.push_back("temperature_start: " + std::to_string(start_temperature));
+ }
+ if (end_temperature > 0) {
+ log_buffer.push_back("temperature_end: " + std::to_string(end_temperature));
+ }
+ if (max_temperature > 0) {
+ log_buffer.push_back("temperature_max: " + std::to_string(max_temperature));
+ }
+
std::string log_content = android::base::Join(log_header, "\n") + "\n" +
- android::base::Join(log_buffer, "\n");
+ android::base::Join(log_buffer, "\n") + "\n";
if (!android::base::WriteStringToFile(log_content, install_file)) {
PLOG(ERROR) << "failed to write " << install_file;
}
diff --git a/otautil/Android.mk b/otautil/Android.mk
index e602f19ee..f7ca9a9ee 100644
--- a/otautil/Android.mk
+++ b/otautil/Android.mk
@@ -18,12 +18,16 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
SysUtil.cpp \
DirUtil.cpp \
- ZipUtil.cpp
+ ZipUtil.cpp \
+ ThermalUtil.cpp
-LOCAL_STATIC_LIBRARIES := libselinux libbase
+LOCAL_STATIC_LIBRARIES := \
+ libselinux \
+ libbase
LOCAL_MODULE := libotautil
-
-LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CFLAGS := \
+ -Werror \
+ -Wall
include $(BUILD_STATIC_LIBRARY)
diff --git a/otautil/ThermalUtil.cpp b/otautil/ThermalUtil.cpp
new file mode 100644
index 000000000..13d36432a
--- /dev/null
+++ b/otautil/ThermalUtil.cpp
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+#include "ThermalUtil.h"
+
+#include <dirent.h>
+#include <stdio.h>
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
+static constexpr auto THERMAL_PREFIX = "/sys/class/thermal/";
+
+static int thermal_filter(const dirent* de) {
+ if (android::base::StartsWith(de->d_name, "thermal_zone")) {
+ return 1;
+ }
+ return 0;
+}
+
+static std::vector<std::string> InitThermalPaths() {
+ dirent** namelist;
+ int n = scandir(THERMAL_PREFIX, &namelist, thermal_filter, alphasort);
+ if (n == -1) {
+ PLOG(ERROR) << "Failed to scandir " << THERMAL_PREFIX;
+ return {};
+ }
+ if (n == 0) {
+ LOG(ERROR) << "Failed to find CPU thermal info in " << THERMAL_PREFIX;
+ return {};
+ }
+
+ std::vector<std::string> thermal_paths;
+ while (n--) {
+ thermal_paths.push_back(THERMAL_PREFIX + std::string(namelist[n]->d_name) + "/temp");
+ free(namelist[n]);
+ }
+ free(namelist);
+ return thermal_paths;
+}
+
+int GetMaxValueFromThermalZone() {
+ static std::vector<std::string> thermal_paths = InitThermalPaths();
+ int max_temperature = -1;
+ for (const auto& path : thermal_paths) {
+ std::string content;
+ if (!android::base::ReadFileToString(path, &content)) {
+ PLOG(WARNING) << "Failed to read " << path;
+ continue;
+ }
+
+ int temperature;
+ if (!android::base::ParseInt(android::base::Trim(content), &temperature)) {
+ LOG(WARNING) << "Failed to parse integer in " << content;
+ continue;
+ }
+ max_temperature = std::max(temperature, max_temperature);
+ }
+ LOG(INFO) << "current maximum temperature: " << max_temperature;
+ return max_temperature;
+} \ No newline at end of file
diff --git a/otautil/ThermalUtil.h b/otautil/ThermalUtil.h
new file mode 100644
index 000000000..43ab55940
--- /dev/null
+++ b/otautil/ThermalUtil.h
@@ -0,0 +1,24 @@
+/*
+ * 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 OTAUTIL_THERMALUTIL_H
+#define OTAUTIL_THERMALUTIL_H
+
+// We can find the temperature reported by all sensors in /sys/class/thermal/thermal_zone*/temp.
+// Their values are in millidegree Celsius; and we will log the maximum one.
+int GetMaxValueFromThermalZone();
+
+#endif // OTAUTIL_THERMALUTIL_H
diff --git a/tests/component/imgdiff_test.cpp b/tests/component/imgdiff_test.cpp
index 2f648501c..7d00a3d53 100644
--- a/tests/component/imgdiff_test.cpp
+++ b/tests/component/imgdiff_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <stdio.h>
+
#include <string>
#include <vector>
@@ -27,12 +29,6 @@
using android::base::get_unaligned;
-static ssize_t MemorySink(const unsigned char* data, ssize_t len, void* token) {
- std::string* s = static_cast<std::string*>(token);
- s->append(reinterpret_cast<const char*>(data), len);
- return len;
-}
-
// Sanity check for the given imgdiff patch header.
static void verify_patch_header(const std::string& patch, size_t* num_normal, size_t* num_raw,
size_t* num_deflate) {
@@ -79,6 +75,18 @@ static void verify_patch_header(const std::string& patch, size_t* num_normal, si
if (num_deflate != nullptr) *num_deflate = deflate;
}
+static void verify_patched_image(const std::string& src, const std::string& patch,
+ const std::string& tgt) {
+ std::string patched;
+ ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
+ reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
+ [&patched](const unsigned char* data, size_t len) {
+ patched.append(reinterpret_cast<const char*>(data), len);
+ return len;
+ }));
+ ASSERT_EQ(tgt, patched);
+}
+
TEST(ImgdiffTest, invalid_args) {
// Insufficient inputs.
ASSERT_EQ(2, imgdiff(1, (const char* []){ "imgdiff" }));
@@ -124,11 +132,7 @@ TEST(ImgdiffTest, image_mode_smoke) {
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(1U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, zip_mode_smoke_store) {
@@ -177,11 +181,7 @@ TEST(ImgdiffTest, zip_mode_smoke_store) {
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(1U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, zip_mode_smoke_compressed) {
@@ -230,11 +230,7 @@ TEST(ImgdiffTest, zip_mode_smoke_compressed) {
ASSERT_EQ(1U, num_deflate);
ASSERT_EQ(2U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
@@ -286,11 +282,7 @@ TEST(ImgdiffTest, zip_mode_smoke_trailer_zeros) {
ASSERT_EQ(1U, num_deflate);
ASSERT_EQ(2U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, image_mode_simple) {
@@ -333,11 +325,7 @@ TEST(ImgdiffTest, image_mode_simple) {
ASSERT_EQ(1U, num_deflate);
ASSERT_EQ(2U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, image_mode_different_num_chunks) {
@@ -413,11 +401,7 @@ TEST(ImgdiffTest, image_mode_merge_chunks) {
ASSERT_EQ(1U, num_deflate);
ASSERT_EQ(2U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, image_mode_spurious_magic) {
@@ -454,11 +438,7 @@ TEST(ImgdiffTest, image_mode_spurious_magic) {
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(1U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, image_mode_short_input1) {
@@ -494,11 +474,7 @@ TEST(ImgdiffTest, image_mode_short_input1) {
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(1U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, image_mode_short_input2) {
@@ -534,11 +510,7 @@ TEST(ImgdiffTest, image_mode_short_input2) {
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(1U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
TEST(ImgdiffTest, image_mode_single_entry_long) {
@@ -577,9 +549,5 @@ TEST(ImgdiffTest, image_mode_single_entry_long) {
ASSERT_EQ(0U, num_deflate);
ASSERT_EQ(0U, num_raw);
- std::string patched;
- ASSERT_EQ(0, ApplyImagePatch(reinterpret_cast<const unsigned char*>(src.data()), src.size(),
- reinterpret_cast<const unsigned char*>(patch.data()), patch.size(),
- MemorySink, &patched));
- ASSERT_EQ(tgt, patched);
+ verify_patched_image(src, patch, tgt);
}
diff --git a/tests/component/uncrypt_test.cpp b/tests/component/uncrypt_test.cpp
index 4f2b8164f..5e057e129 100644
--- a/tests/component/uncrypt_test.cpp
+++ b/tests/component/uncrypt_test.cpp
@@ -25,12 +25,15 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <bootloader_message/bootloader_message.h>
#include <gtest/gtest.h>
#include "common/component_test_util.h"
+using namespace std::string_literals;
+
static const std::string UNCRYPT_SOCKET = "/dev/socket/uncrypt";
static const std::string INIT_SVC_SETUP_BCB = "init.svc.setup-bcb";
static const std::string INIT_SVC_CLEAR_BCB = "init.svc.clear-bcb";
@@ -65,128 +68,104 @@ class UncryptTest : public ::testing::Test {
has_misc = parse_misc();
}
- bool has_misc;
-};
-
-TEST_F(UncryptTest, setup_bcb) {
- if (!has_misc) {
- GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
- return;
- }
-
- // Trigger the setup-bcb service.
- ASSERT_TRUE(android::base::SetProperty("ctl.start", "setup-bcb"));
-
- // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected").
- sleep(1);
-
- struct sockaddr_un un = {};
- un.sun_family = AF_UNIX;
- strlcpy(un.sun_path, UNCRYPT_SOCKET.c_str(), sizeof(un.sun_path));
-
- int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- ASSERT_NE(-1, sockfd);
-
- // Connect to the uncrypt socket.
- bool success = false;
- for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
- if (connect(sockfd, reinterpret_cast<struct sockaddr*>(&un), sizeof(struct sockaddr_un)) != 0) {
- success = true;
- break;
+ void SetupOrClearBcb(bool isSetup, const std::string& message,
+ const std::string& message_in_bcb) const {
+ if (!has_misc) {
+ GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
+ return;
}
- sleep(1);
- }
- ASSERT_TRUE(success);
-
- // Send out the BCB message.
- std::string message = "--update_message=abc value";
- std::string message_in_bcb = "recovery\n--update_message=abc value\n";
- int length = static_cast<int>(message.size());
- int length_out = htonl(length);
- ASSERT_TRUE(android::base::WriteFully(sockfd, &length_out, sizeof(int)))
- << "Failed to write length: " << strerror(errno);
- ASSERT_TRUE(android::base::WriteFully(sockfd, message.data(), length))
- << "Failed to write message: " << strerror(errno);
-
- // Check the status code from uncrypt.
- int status;
- ASSERT_TRUE(android::base::ReadFully(sockfd, &status, sizeof(int)));
- ASSERT_EQ(100U, ntohl(status));
- // Ack having received the status code.
- int code = 0;
- ASSERT_TRUE(android::base::WriteFully(sockfd, &code, sizeof(int)));
+ // Trigger the setup-bcb service.
+ ASSERT_TRUE(android::base::SetProperty("ctl.start", isSetup ? "setup-bcb" : "clear-bcb"));
- ASSERT_EQ(0, close(sockfd));
+ // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected").
+ sleep(1);
- ASSERT_TRUE(android::base::SetProperty("ctl.stop", "setup-bcb"));
+ sockaddr_un un = {};
+ un.sun_family = AF_UNIX;
+ strlcpy(un.sun_path, UNCRYPT_SOCKET.c_str(), sizeof(un.sun_path));
- // Verify the message by reading from BCB directly.
- bootloader_message boot;
- std::string err;
- ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
+ int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_NE(-1, sockfd);
- ASSERT_EQ("boot-recovery", std::string(boot.command));
- ASSERT_EQ(message_in_bcb, std::string(boot.recovery));
+ // Connect to the uncrypt socket.
+ bool success = false;
+ for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+ if (connect(sockfd, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)) != 0) {
+ success = true;
+ break;
+ }
+ sleep(1);
+ }
+ ASSERT_TRUE(success);
+
+ if (isSetup) {
+ // Send out the BCB message.
+ int length = static_cast<int>(message.size());
+ int length_out = htonl(length);
+ ASSERT_TRUE(android::base::WriteFully(sockfd, &length_out, sizeof(int)))
+ << "Failed to write length: " << strerror(errno);
+ ASSERT_TRUE(android::base::WriteFully(sockfd, message.data(), length))
+ << "Failed to write message: " << strerror(errno);
+ }
- // The rest of the boot.recovery message should be zero'd out.
- ASSERT_LE(message_in_bcb.size(), sizeof(boot.recovery));
- size_t left = sizeof(boot.recovery) - message_in_bcb.size();
- ASSERT_EQ(std::string(left, '\0'), std::string(&boot.recovery[message_in_bcb.size()], left));
+ // Check the status code from uncrypt.
+ int status;
+ ASSERT_TRUE(android::base::ReadFully(sockfd, &status, sizeof(int)));
+ ASSERT_EQ(100U, ntohl(status));
- // Clear the BCB.
- ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
-}
+ // Ack having received the status code.
+ int code = 0;
+ ASSERT_TRUE(android::base::WriteFully(sockfd, &code, sizeof(int)));
-TEST_F(UncryptTest, clear_bcb) {
- if (!has_misc) {
- GTEST_LOG_(INFO) << "Test skipped due to no /misc partition found on the device.";
- return;
- }
+ ASSERT_EQ(0, close(sockfd));
- // Trigger the clear-bcb service.
- ASSERT_TRUE(android::base::SetProperty("ctl.start", "clear-bcb"));
+ ASSERT_TRUE(android::base::SetProperty("ctl.stop", isSetup ? "setup-bcb" : "clear-bcb"));
- // Test tends to be flaky if proceeding immediately ("Transport endpoint is not connected").
- sleep(1);
+ // Verify the message by reading from BCB directly.
+ bootloader_message boot;
+ std::string err;
+ ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
- struct sockaddr_un un = {};
- un.sun_family = AF_UNIX;
- strlcpy(un.sun_path, UNCRYPT_SOCKET.c_str(), sizeof(un.sun_path));
+ if (isSetup) {
+ ASSERT_EQ("boot-recovery", std::string(boot.command));
+ ASSERT_EQ(message_in_bcb, std::string(boot.recovery));
- int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
- ASSERT_NE(-1, sockfd);
+ // The rest of the boot.recovery message should be zero'd out.
+ ASSERT_LE(message_in_bcb.size(), sizeof(boot.recovery));
+ size_t left = sizeof(boot.recovery) - message_in_bcb.size();
+ ASSERT_EQ(std::string(left, '\0'), std::string(&boot.recovery[message_in_bcb.size()], left));
- // Connect to the uncrypt socket.
- bool success = false;
- for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
- if (connect(sockfd, reinterpret_cast<struct sockaddr*>(&un), sizeof(struct sockaddr_un)) != 0) {
- success = true;
- break;
+ // Clear the BCB.
+ ASSERT_TRUE(clear_bootloader_message(&err)) << "Failed to clear BCB: " << err;
+ } else {
+ // All the bytes should be cleared.
+ ASSERT_EQ(std::string(sizeof(boot), '\0'),
+ std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)));
}
- sleep(1);
}
- ASSERT_TRUE(success);
- // Check the status code from uncrypt.
- int status;
- ASSERT_TRUE(android::base::ReadFully(sockfd, &status, sizeof(int)));
- ASSERT_EQ(100U, ntohl(status));
-
- // Ack having received the status code.
- int code = 0;
- ASSERT_TRUE(android::base::WriteFully(sockfd, &code, sizeof(int)));
+ bool has_misc;
+};
- ASSERT_EQ(0, close(sockfd));
+TEST_F(UncryptTest, setup_bcb) {
+ std::string message = "--update_message=abc value";
+ std::string message_in_bcb = "recovery\n--update_message=abc value\n";
+ SetupOrClearBcb(true, message, message_in_bcb);
+}
- ASSERT_TRUE(android::base::SetProperty("ctl.stop", "clear-bcb"));
+TEST_F(UncryptTest, clear_bcb) {
+ SetupOrClearBcb(false, "", "");
+}
- // Verify the content by reading from BCB directly.
- bootloader_message boot;
- std::string err;
- ASSERT_TRUE(read_bootloader_message(&boot, &err)) << "Failed to read BCB: " << err;
+TEST_F(UncryptTest, setup_bcb_wipe_ab) {
+ TemporaryFile wipe_package;
+ ASSERT_TRUE(android::base::WriteStringToFile(std::string(345, 'a'), wipe_package.path));
- // All the bytes should be cleared.
- ASSERT_EQ(std::string(sizeof(boot), '\0'),
- std::string(reinterpret_cast<const char*>(&boot), sizeof(boot)));
+ // It's expected to store a wipe package in /misc, with the package size passed to recovery.
+ std::string message =
+ "--wipe_ab\n--wipe_package="s + wipe_package.path + "\n--reason=wipePackage"s;
+ std::string message_in_bcb =
+ "recovery\n--wipe_ab\n--wipe_package_size=345\n--reason=wipePackage\n";
+ SetupOrClearBcb(true, message, message_in_bcb);
}
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index c614ccc47..8c0f885a1 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -240,57 +240,54 @@ struct RangeSinkState {
size_t p_remain;
};
-static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) {
- RangeSinkState* rss = reinterpret_cast<RangeSinkState*>(token);
-
- if (rss->p_remain == 0) {
- LOG(ERROR) << "range sink write overrun";
- return 0;
- }
-
- ssize_t written = 0;
- while (size > 0) {
- size_t write_now = size;
-
- if (rss->p_remain < write_now) {
- write_now = rss->p_remain;
- }
+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;
+ }
- if (write_all(rss->fd, data, write_now) == -1) {
- break;
- }
+ size_t written = 0;
+ while (size > 0) {
+ size_t write_now = size;
- data += write_now;
- size -= write_now;
+ if (rss->p_remain < write_now) {
+ write_now = rss->p_remain;
+ }
- rss->p_remain -= write_now;
- written += write_now;
+ if (write_all(rss->fd, data, write_now) == -1) {
+ break;
+ }
- 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;
+ data += write_now;
+ size -= write_now;
- off64_t offset = static_cast<off64_t>(rss->tgt.pos[rss->p_block*2]) * BLOCKSIZE;
- if (!discard_blocks(rss->fd, offset, rss->p_remain)) {
- break;
- }
+ rss->p_remain -= write_now;
+ written += write_now;
- if (!check_lseek(rss->fd, offset, SEEK_SET)) {
- break;
- }
+ 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)) {
+ 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;
}
+
+ } else {
+ // We can't write any more; return how many bytes have been written so far.
+ break;
+ }
}
+ }
- return written;
+ return written;
}
// All of the data for all the 'new' transfers is contained in one
@@ -338,7 +335,7 @@ static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) {
// At this point nti->rss is set, and we own it. The main
// thread is waiting for it to disappear from nti.
- ssize_t written = RangeSinkWrite(data, size, nti->rss);
+ size_t written = RangeSinkWrite(data, size, nti->rss);
data += written;
size -= written;
@@ -696,7 +693,7 @@ static int LoadStash(CommandParameters& params, const std::string& id, bool veri
}
static int WriteStash(const std::string& base, const std::string& id, int blocks,
- std::vector<uint8_t>& buffer, bool checkspace, bool *exists) {
+ std::vector<uint8_t>& buffer, bool checkspace, bool* exists) {
if (base.empty()) {
return -1;
}
@@ -883,96 +880,81 @@ static void MoveRange(std::vector<uint8_t>& dest, const RangeSet& locs,
}
}
-// Do a source/target load for move/bsdiff/imgdiff in version 2.
-// We expect to parse the remainder of the parameter tokens as one of:
-//
-// <tgt_range> <src_block_count> <src_range>
-// (loads data from source image only)
-//
-// <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
-// (loads data from stashes only)
-//
-// <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
-// (loads data from both source image and stashes)
-//
-// On return, params.buffer is filled with the loaded source data (rearranged and combined with
-// stashed data as necessary). buffer may be reallocated if needed to accommodate the source data.
-// *tgt is the target RangeSet. Any stashes required are loaded using LoadStash.
-
-static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
- bool* overlap) {
+/**
+ * We expect to parse the remainder of the parameter tokens as one of:
+ *
+ * <src_block_count> <src_range>
+ * (loads data from source image only)
+ *
+ * <src_block_count> - <[stash_id:stash_range] ...>
+ * (loads data from stashes only)
+ *
+ * <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
+ * (loads data from both source image and stashes)
+ *
+ * On return, params.buffer is filled with the loaded source data (rearranged and combined with
+ * stashed data as necessary). buffer may be reallocated if needed to accommodate the source data.
+ * tgt is the target RangeSet for detecting overlaps. Any stashes required are loaded using
+ * LoadStash.
+ */
+static int LoadSourceBlocks(CommandParameters& params, const RangeSet& tgt, size_t* src_blocks,
+ bool* overlap) {
+ CHECK(src_blocks != nullptr);
+ CHECK(overlap != nullptr);
+
+ // <src_block_count>
+ const std::string& token = params.tokens[params.cpos++];
+ if (!android::base::ParseUint(token, src_blocks)) {
+ LOG(ERROR) << "invalid src_block_count \"" << token << "\"";
+ return -1;
+ }
- // At least it needs to provide three parameters: <tgt_range>,
- // <src_block_count> and "-"/<src_range>.
- if (params.cpos + 2 >= params.tokens.size()) {
- LOG(ERROR) << "invalid parameters";
- return -1;
- }
+ allocate(*src_blocks * BLOCKSIZE, params.buffer);
- // <tgt_range>
- tgt = parse_range(params.tokens[params.cpos++]);
+ // "-" or <src_range> [<src_loc>]
+ if (params.tokens[params.cpos] == "-") {
+ // no source ranges, only stashes
+ params.cpos++;
+ } else {
+ RangeSet src = parse_range(params.tokens[params.cpos++]);
+ *overlap = range_overlaps(src, tgt);
- // <src_block_count>
- const std::string& token = params.tokens[params.cpos++];
- if (!android::base::ParseUint(token.c_str(), &src_blocks)) {
- LOG(ERROR) << "invalid src_block_count \"" << token << "\"";
- return -1;
+ if (ReadBlocks(src, params.buffer, params.fd) == -1) {
+ return -1;
}
- allocate(src_blocks * BLOCKSIZE, params.buffer);
-
- // "-" or <src_range> [<src_loc>]
- if (params.tokens[params.cpos] == "-") {
- // no source ranges, only stashes
- params.cpos++;
- } else {
- RangeSet src = parse_range(params.tokens[params.cpos++]);
- int res = ReadBlocks(src, params.buffer, params.fd);
-
- if (overlap) {
- *overlap = range_overlaps(src, tgt);
- }
-
- if (res == -1) {
- return -1;
- }
-
- if (params.cpos >= params.tokens.size()) {
- // no stashes, only source range
- return 0;
- }
-
- RangeSet locs = parse_range(params.tokens[params.cpos++]);
- MoveRange(params.buffer, locs, params.buffer);
+ if (params.cpos >= params.tokens.size()) {
+ // no stashes, only source range
+ return 0;
}
- // <[stash_id:stash_range]>
- while (params.cpos < params.tokens.size()) {
- // Each word is a an index into the stash table, a colon, and
- // then a rangeset describing where in the source block that
- // stashed data should go.
- std::vector<std::string> tokens = android::base::Split(params.tokens[params.cpos++], ":");
- if (tokens.size() != 2) {
- LOG(ERROR) << "invalid parameter";
- return -1;
- }
-
- std::vector<uint8_t> stash;
- int res = LoadStash(params, tokens[0], false, nullptr, stash, true);
-
- if (res == -1) {
- // These source blocks will fail verification if used later, but we
- // will let the caller decide if this is a fatal failure
- LOG(ERROR) << "failed to load stash " << tokens[0];
- continue;
- }
+ RangeSet locs = parse_range(params.tokens[params.cpos++]);
+ MoveRange(params.buffer, locs, params.buffer);
+ }
- RangeSet locs = parse_range(tokens[1]);
+ // <[stash_id:stash_range]>
+ while (params.cpos < params.tokens.size()) {
+ // Each word is a an index into the stash table, a colon, and then a RangeSet describing where
+ // in the source block that stashed data should go.
+ std::vector<std::string> tokens = android::base::Split(params.tokens[params.cpos++], ":");
+ if (tokens.size() != 2) {
+ LOG(ERROR) << "invalid parameter";
+ return -1;
+ }
- MoveRange(params.buffer, locs, stash);
+ std::vector<uint8_t> stash;
+ if (LoadStash(params, tokens[0], false, nullptr, stash, true) == -1) {
+ // These source blocks will fail verification if used later, but we
+ // will let the caller decide if this is a fatal failure
+ LOG(ERROR) << "failed to load stash " << tokens[0];
+ continue;
}
- return 0;
+ RangeSet locs = parse_range(tokens[1]);
+ MoveRange(params.buffer, locs, stash);
+ }
+
+ return 0;
}
/**
@@ -989,9 +971,8 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
* <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
* (loads data from both source image and stashes)
*
- * Parameters are the same as for LoadSrcTgtVersion2, except for 'onehash', which tells the function
- * whether to expect separate source and targe block hashes, or if they are both the same and only
- * one hash should be expected, and 'isunresumable', which receives a non-zero value if block
+ * 'onehash' tells whether to expect separate source and targe block hashes, or if they are both the
+ * same and only one hash should be expected. params.isunresumable will be set to true if block
* verification fails in a way that the update cannot be resumed anymore.
*
* If the function is unable to load the necessary blocks or their contents don't match the hashes,
@@ -1002,87 +983,100 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t&
*
* If the return value is 0, source blocks have expected content and the command can be performed.
*/
-static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& src_blocks,
- bool onehash, bool& overlap) {
- if (params.cpos >= params.tokens.size()) {
- LOG(ERROR) << "missing source hash";
- return -1;
- }
+static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t* src_blocks,
+ bool onehash, bool* overlap) {
+ CHECK(src_blocks != nullptr);
+ CHECK(overlap != nullptr);
- std::string srchash = params.tokens[params.cpos++];
- std::string tgthash;
+ if (params.cpos >= params.tokens.size()) {
+ LOG(ERROR) << "missing source hash";
+ return -1;
+ }
- if (onehash) {
- tgthash = srchash;
- } else {
- if (params.cpos >= params.tokens.size()) {
- LOG(ERROR) << "missing target hash";
- return -1;
- }
- tgthash = params.tokens[params.cpos++];
- }
+ std::string srchash = params.tokens[params.cpos++];
+ std::string tgthash;
- if (LoadSrcTgtVersion2(params, tgt, src_blocks, &overlap) == -1) {
- return -1;
+ if (onehash) {
+ tgthash = srchash;
+ } else {
+ if (params.cpos >= params.tokens.size()) {
+ LOG(ERROR) << "missing target hash";
+ return -1;
}
+ tgthash = params.tokens[params.cpos++];
+ }
- std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
+ // At least it needs to provide three parameters: <tgt_range>, <src_block_count> and
+ // "-"/<src_range>.
+ if (params.cpos + 2 >= params.tokens.size()) {
+ LOG(ERROR) << "invalid parameters";
+ return -1;
+ }
- if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
- return -1;
- }
+ // <tgt_range>
+ tgt = parse_range(params.tokens[params.cpos++]);
- if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) {
- // Target blocks already have expected content, command should be skipped.
- return 1;
- }
+ std::vector<uint8_t> tgtbuffer(tgt.size * BLOCKSIZE);
+ if (ReadBlocks(tgt, tgtbuffer, params.fd) == -1) {
+ return -1;
+ }
- if (VerifyBlocks(srchash, params.buffer, src_blocks, true) == 0) {
- // If source and target blocks overlap, stash the source blocks so we can
- // resume from possible write errors. In verify mode, we can skip stashing
- // because the source blocks won't be overwritten.
- if (overlap && params.canwrite) {
- LOG(INFO) << "stashing " << src_blocks << " overlapping blocks to " << srchash;
+ // Return now if target blocks already have expected content.
+ if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) {
+ return 1;
+ }
- bool stash_exists = false;
- if (WriteStash(params.stashbase, srchash, src_blocks, params.buffer, true,
- &stash_exists) != 0) {
- LOG(ERROR) << "failed to stash overlapping source blocks";
- return -1;
- }
+ // Load source blocks.
+ if (LoadSourceBlocks(params, tgt, src_blocks, overlap) == -1) {
+ return -1;
+ }
- params.stashed += src_blocks;
- // Can be deleted when the write has completed.
- if (!stash_exists) {
- params.freestash = srchash;
- }
- }
+ if (VerifyBlocks(srchash, params.buffer, *src_blocks, true) == 0) {
+ // If source and target blocks overlap, stash the source blocks so we can
+ // resume from possible write errors. In verify mode, we can skip stashing
+ // because the source blocks won't be overwritten.
+ if (*overlap && params.canwrite) {
+ LOG(INFO) << "stashing " << *src_blocks << " overlapping blocks to " << srchash;
+
+ bool stash_exists = false;
+ if (WriteStash(params.stashbase, srchash, *src_blocks, params.buffer, true,
+ &stash_exists) != 0) {
+ LOG(ERROR) << "failed to stash overlapping source blocks";
+ return -1;
+ }
- // Source blocks have expected content, command can proceed.
- return 0;
+ params.stashed += *src_blocks;
+ // Can be deleted when the write has completed.
+ if (!stash_exists) {
+ params.freestash = srchash;
+ }
}
- if (overlap && LoadStash(params, srchash, true, nullptr, params.buffer, true) == 0) {
- // Overlapping source blocks were previously stashed, command can proceed.
- // We are recovering from an interrupted command, so we don't know if the
- // stash can safely be deleted after this command.
- return 0;
- }
+ // Source blocks have expected content, command can proceed.
+ return 0;
+ }
- // Valid source data not available, update cannot be resumed.
- LOG(ERROR) << "partition has unexpected contents";
- PrintHashForCorruptedSourceBlocks(params, params.buffer);
+ if (*overlap && LoadStash(params, srchash, true, nullptr, params.buffer, true) == 0) {
+ // Overlapping source blocks were previously stashed, command can proceed. We are recovering
+ // from an interrupted command, so we don't know if the stash can safely be deleted after this
+ // command.
+ return 0;
+ }
- params.isunresumable = true;
+ // Valid source data not available, update cannot be resumed.
+ LOG(ERROR) << "partition has unexpected contents";
+ PrintHashForCorruptedSourceBlocks(params, params.buffer);
- return -1;
+ params.isunresumable = true;
+
+ return -1;
}
static int PerformCommandMove(CommandParameters& params) {
size_t blocks = 0;
bool overlap = false;
RangeSet tgt;
- int status = LoadSrcTgtVersion3(params, tgt, blocks, true, overlap);
+ int status = LoadSrcTgtVersion3(params, tgt, &blocks, true, &overlap);
if (status == -1) {
LOG(ERROR) << "failed to read blocks for move";
@@ -1262,92 +1256,95 @@ static int PerformCommandNew(CommandParameters& params) {
}
static int PerformCommandDiff(CommandParameters& params) {
+ // <offset> <length>
+ if (params.cpos + 1 >= params.tokens.size()) {
+ LOG(ERROR) << "missing patch offset or length for " << params.cmdname;
+ return -1;
+ }
- // <offset> <length>
- if (params.cpos + 1 >= params.tokens.size()) {
- LOG(ERROR) << "missing patch offset or length for " << params.cmdname;
- return -1;
- }
+ size_t offset;
+ if (!android::base::ParseUint(params.tokens[params.cpos++], &offset)) {
+ LOG(ERROR) << "invalid patch offset";
+ return -1;
+ }
- size_t offset;
- if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &offset)) {
- LOG(ERROR) << "invalid patch offset";
- return -1;
- }
+ size_t len;
+ if (!android::base::ParseUint(params.tokens[params.cpos++], &len)) {
+ LOG(ERROR) << "invalid patch len";
+ return -1;
+ }
- size_t len;
- if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &len)) {
- LOG(ERROR) << "invalid patch len";
- return -1;
- }
+ RangeSet tgt;
+ size_t blocks = 0;
+ bool overlap = false;
+ int status = LoadSrcTgtVersion3(params, tgt, &blocks, false, &overlap);
- RangeSet tgt;
- size_t blocks = 0;
- bool overlap = false;
- int status = LoadSrcTgtVersion3(params, tgt, blocks, false, overlap);
+ if (status == -1) {
+ LOG(ERROR) << "failed to read blocks for diff";
+ return -1;
+ }
- if (status == -1) {
- LOG(ERROR) << "failed to read blocks for diff";
- return -1;
- }
+ if (status == 0) {
+ params.foundwrites = true;
+ } else if (params.foundwrites) {
+ LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
+ }
+ if (params.canwrite) {
if (status == 0) {
- params.foundwrites = true;
- } else if (params.foundwrites) {
- LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]";
- }
-
- if (params.canwrite) {
- if (status == 0) {
- 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;
- }
+ 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 (params.cmdname[0] == 'i') { // imgdiff
- if (ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
- &RangeSinkWrite, &rss, nullptr, nullptr) != 0) {
- LOG(ERROR) << "Failed to apply image patch.";
- return -1;
- }
- } else {
- if (ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value,
- 0, &RangeSinkWrite, &rss, nullptr) != 0) {
- LOG(ERROR) << "Failed to apply bsdiff patch.";
- return -1;
- }
- }
+ if (!check_lseek(params.fd, offset, SEEK_SET)) {
+ 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) {
- LOG(ERROR) << "range sink underrun?";
- }
- } else {
- LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.size
- << " [" << params.cmdline << "]";
+ 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) {
+ 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) {
+ LOG(ERROR) << "Failed to apply bsdiff patch.";
+ return -1;
+ }
+ }
- if (!params.freestash.empty()) {
- FreeStash(params.stashbase, params.freestash);
- params.freestash.clear();
+ // We expect the output of the patcher to fill the tgt ranges exactly.
+ if (rss.p_block != tgt.count || rss.p_remain != 0) {
+ LOG(ERROR) << "range sink underrun?";
+ }
+ } else {
+ LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.size << " ["
+ << params.cmdline << "]";
}
+ }
- params.written += tgt.size;
+ if (!params.freestash.empty()) {
+ FreeStash(params.stashbase, params.freestash);
+ params.freestash.clear();
+ }
- return 0;
+ params.written += tgt.size;
+
+ return 0;
}
static int PerformCommandErase(CommandParameters& params) {
@@ -1871,7 +1868,7 @@ Value* BlockImageRecoverFn(const char* name, State* state,
LOG(INFO) << filename->data << " image corrupted, attempting to recover...";
// When opened with O_RDWR, libfec rewrites corrupted blocks when they are read
- fec::io fh(filename->data.c_str(), O_RDWR);
+ fec::io fh(filename->data, O_RDWR);
if (!fh) {
ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data.c_str(),