Merge "fastboot: Fix "fastboot gsi"."
diff --git a/adb/Android.bp b/adb/Android.bp
index 8199fff..3813578 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -156,8 +156,6 @@
"client/usb_libusb.cpp",
"client/usb_dispatch.cpp",
"client/transport_mdns.cpp",
- "client/fastdeploy.cpp",
- "client/fastdeploycallbacks.cpp",
],
generated_headers: ["platform_tools_version"],
@@ -192,9 +190,6 @@
"libdiagnose_usb",
"libmdnssd",
"libusb",
- "libandroidfw",
- "libziparchive",
- "libz",
"libutils",
"liblog",
"libcutils",
@@ -280,9 +275,6 @@
"liblog",
"libmdnssd",
"libusb",
- "libandroidfw",
- "libziparchive",
- "libz",
"libutils",
"liblog",
"libcutils",
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index d56a25f..2bf2924 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -36,7 +36,9 @@
#include "commandline.h"
#include "fastdeploy.h"
+#if defined(ENABLE_FASTDEPLOY)
static constexpr int kFastDeployMinApi = 24;
+#endif
static bool can_use_feature(const char* feature) {
FeatureSet features;
@@ -130,10 +132,12 @@
*buf = '\0';
}
+#if defined(ENABLE_FASTDEPLOY)
static int delete_device_patch_file(const char* apkPath) {
std::string patchDevicePath = get_patch_path(apkPath);
return delete_device_file(patchDevicePath);
}
+#endif
static int install_app_streamed(int argc, const char** argv, bool use_fastdeploy,
bool use_localagent) {
@@ -159,6 +163,7 @@
}
if (use_fastdeploy == true) {
+#if defined(ENABLE_FASTDEPLOY)
TemporaryFile metadataTmpFile;
std::string patchTmpFilePath;
{
@@ -179,6 +184,9 @@
adb_unlink(patchTmpFilePath.c_str());
delete_device_patch_file(file);
return 0;
+#else
+ error_exit("fastdeploy is disabled");
+#endif
} else {
struct stat sb;
if (stat(file, &sb) == -1) {
@@ -252,6 +260,7 @@
"/data/local/tmp/" + android::base::Basename(argv[last_apk]);
if (use_fastdeploy == true) {
+#if defined(ENABLE_FASTDEPLOY)
TemporaryFile metadataTmpFile;
TemporaryFile patchTmpFile;
@@ -261,6 +270,9 @@
create_patch(apk_file[0], metadataTmpFile.path, patchTmpFile.path);
apply_patch_on_device(apk_file[0], patchTmpFile.path, apk_dest.c_str());
+#else
+ error_exit("fastdeploy is disabled");
+#endif
} else {
if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
}
@@ -270,7 +282,9 @@
cleanup_apk:
if (use_fastdeploy == true) {
+#if defined(ENABLE_FASTDEPLOY)
delete_device_patch_file(apk_file[0]);
+#endif
}
delete_device_file(apk_dest);
return result;
@@ -334,12 +348,14 @@
error_exit("Attempting to use streaming install on unsupported device");
}
+#if defined(ENABLE_FASTDEPLOY)
if (use_fastdeploy == true && get_device_api_level() < kFastDeployMinApi) {
printf("Fast Deploy is only compatible with devices of API version %d or higher, "
"ignoring.\n",
kFastDeployMinApi);
use_fastdeploy = false;
}
+#endif
std::vector<const char*> passthrough_argv;
for (int i = 0; i < argc; i++) {
@@ -353,12 +369,16 @@
}
if (use_fastdeploy == true) {
+#if defined(ENABLE_FASTDEPLOY)
fastdeploy_set_local_agent(use_localagent);
update_agent(agent_update_strategy);
// The last argument must be the APK file
const char* file = passthrough_argv.back();
use_fastdeploy = find_package(file);
+#else
+ error_exit("fastdeploy is disabled");
+#endif
}
switch (installMode) {
@@ -530,6 +550,10 @@
std::string multi_package_cmd =
android::base::StringPrintf("%s install-create --multi-package", install_cmd.c_str());
+ for (int i = 1; i < first_package; i++) {
+ multi_package_cmd += " " + escape_arg(argv[i]);
+ }
+
if (apex_found) {
multi_package_cmd += " --staged";
}
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 56b5cd8..9e1760d 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -25,6 +25,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -209,6 +210,22 @@
return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
}
+static bool is_mountpoint(const std::string& path, pid_t tid) {
+ const std::string mountinfo_path = "/proc/" + std::to_string(tid) + "/mountinfo";
+ std::string mountinfo;
+ if (!android::base::ReadFileToString(mountinfo_path, &mountinfo)) {
+ PLOG(ERROR) << "Failed to open " << mountinfo_path;
+ return false;
+ }
+ std::vector<std::string> lines = android::base::Split(mountinfo, "\n");
+ return std::find_if(lines.begin(), lines.end(), [&path](const auto& line) {
+ auto tokens = android::base::Split(line, " ");
+ // line format is ...
+ // mountid parentmountid major:minor sourcepath targetpath option ...
+ return tokens.size() >= 4 && tokens[4] == path;
+ }) != lines.end();
+}
+
// Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
#pragma GCC poison SendFail
@@ -415,6 +432,18 @@
struct stat st;
bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) ||
(S_ISLNK(st.st_mode) && !S_ISLNK(mode));
+
+ // If the path is a file that is a mount point, don't unlink it, but instead
+ // truncate to zero. If unlinked, existing mounts on the path is all
+ // unmounted
+ if (S_ISREG(st.st_mode) && is_mountpoint(path, getpid())) {
+ do_unlink = false;
+ if (truncate(path.c_str(), 0) == -1) {
+ SendSyncFail(s, "truncate to zero failed");
+ return false;
+ }
+ }
+
if (do_unlink) {
adb_unlink(path.c_str());
}
@@ -546,7 +575,64 @@
return true;
}
+#if defined(__ANDROID__)
+class FileSyncPreparer {
+ public:
+ FileSyncPreparer() : saved_ns_fd_(-1), rooted_(getuid() == 0) {
+ const std::string namespace_path = "/proc/" + std::to_string(gettid()) + "/ns/mnt";
+ const int ns_fd = adb_open(namespace_path.c_str(), O_RDONLY | O_CLOEXEC);
+ if (ns_fd == -1) {
+ if (rooted_) PLOG(ERROR) << "Failed to save mount namespace";
+ return;
+ }
+ saved_ns_fd_.reset(ns_fd);
+
+ // Note: this is for the current thread only
+ if (unshare(CLONE_NEWNS) != 0) {
+ if (rooted_) PLOG(ERROR) << "Failed to clone mount namespace";
+ return;
+ }
+
+ // Set the propagation type of / to private so that unmount below is
+ // not propagated to other mount namespaces.
+ if (mount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) {
+ if (rooted_) PLOG(ERROR) << "Could not change propagation type of / to MS_PRIVATE";
+ return;
+ }
+
+ // unmount /bionic which is bind-mount to itself by init. Under /bionic,
+ // there are other bind mounts for the bionic files. By unmounting this,
+ // we unmount them all thus revealing the raw file system that is the
+ // same as the local file system seen by the adb client.
+ if (umount2("/bionic", MNT_DETACH) == -1 && errno != ENOENT) {
+ if (rooted_) PLOG(ERROR) << "Could not unmount /bionic to reveal raw filesystem";
+ return;
+ }
+ }
+
+ ~FileSyncPreparer() {
+ if (saved_ns_fd_.get() != -1) {
+ // In fact, this is not strictly required because this thread for file
+ // sync service will be destroyed after the current transfer is all
+ // done. However, let's restore the ns in case the same thread is
+ // reused by multiple transfers in the future refactoring.
+ if (setns(saved_ns_fd_, CLONE_NEWNS) == -1) {
+ PLOG(ERROR) << "Failed to restore saved mount namespace";
+ }
+ }
+ }
+
+ private:
+ unique_fd saved_ns_fd_;
+ bool rooted_;
+};
+#endif
+
void file_sync_service(unique_fd fd) {
+#if defined(__ANDROID__)
+ FileSyncPreparer preparer;
+#endif
+
std::vector<char> buffer(SYNC_DATA_MAX);
while (handle_sync_command(fd.get(), buffer)) {
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index b26c691..c36f1b6 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -230,6 +230,23 @@
android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd.c_str());
}
+static void try_unmount_bionic(int fd) {
+ static constexpr const char* kBionic = "/bionic";
+ struct statfs buf;
+ if (statfs(kBionic, &buf) == -1) {
+ WriteFdFmt(fd, "statfs of the %s mount failed: %s.\n", kBionic, strerror(errno));
+ return;
+ }
+ if (buf.f_flags & ST_RDONLY) {
+ // /bionic is on a read-only partition; can happen for
+ // non-system-as-root-devices. Don' try to unmount.
+ return;
+ }
+ // Success/Fail of the actual remount will be reported by the function.
+ remount_partition(fd, kBionic);
+ return;
+}
+
void remount_service(unique_fd fd, const std::string& cmd) {
bool user_requested_reboot = cmd == "-R";
@@ -323,6 +340,8 @@
return;
}
+ try_unmount_bionic(fd.get());
+
if (!success) {
WriteFdExactly(fd.get(), "remount failed\n");
} else {
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index e096560..fa3738d 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -33,6 +33,8 @@
#include <list>
#include <mutex>
#include <unordered_map>
+#include <utility>
+#include <variant>
#include <vector>
#include <android-base/chrono_utils.h>
@@ -121,13 +123,8 @@
state.c_str());
}
-void fdevent_install(fdevent* fde, int fd, fd_func func, void* arg) {
- check_main_thread();
- CHECK_GE(fd, 0);
- memset(fde, 0, sizeof(fdevent));
-}
-
-fdevent* fdevent_create(int fd, fd_func func, void* arg) {
+template <typename F>
+static fdevent* fdevent_create_impl(int fd, F func, void* arg) {
check_main_thread();
CHECK_GE(fd, 0);
@@ -150,6 +147,14 @@
return fde;
}
+fdevent* fdevent_create(int fd, fd_func func, void* arg) {
+ return fdevent_create_impl(fd, func, arg);
+}
+
+fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
+ return fdevent_create_impl(fd, func, arg);
+}
+
unique_fd fdevent_release(fdevent* fde) {
check_main_thread();
if (!fde) {
@@ -290,13 +295,27 @@
}
}
+template <class T>
+struct always_false : std::false_type {};
+
static void fdevent_call_fdfunc(fdevent* fde) {
unsigned events = fde->events;
fde->events = 0;
CHECK(fde->state & FDE_PENDING);
fde->state &= (~FDE_PENDING);
D("fdevent_call_fdfunc %s", dump_fde(fde).c_str());
- fde->func(fde->fd.get(), events, fde->arg);
+ std::visit(
+ [&](auto&& f) {
+ using F = std::decay_t<decltype(f)>;
+ if constexpr (std::is_same_v<fd_func, F>) {
+ f(fde->fd.get(), events, fde->arg);
+ } else if constexpr (std::is_same_v<fd_func2, F>) {
+ f(fde, events, fde->arg);
+ } else {
+ static_assert(always_false<F>::value, "non-exhaustive visitor");
+ }
+ },
+ fde->func);
}
static void fdevent_run_flush() EXCLUDES(run_queue_mutex) {
diff --git a/adb/fdevent.h b/adb/fdevent.h
index df2339a..70e0a96 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -21,6 +21,7 @@
#include <stdint.h> /* for int64_t */
#include <functional>
+#include <variant>
#include "adb_unique_fd.h"
@@ -30,6 +31,7 @@
#define FDE_ERROR 0x0004
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+typedef void (*fd_func2)(struct fdevent* fde, unsigned events, void* userdata);
struct fdevent {
uint64_t id;
@@ -40,15 +42,14 @@
uint16_t state = 0;
uint16_t events = 0;
- fd_func func = nullptr;
+ std::variant<fd_func, fd_func2> func;
void* arg = nullptr;
};
-/* Allocate and initialize a new fdevent object
- * Note: use FD_TIMER as 'fd' to create a fd-less object
- * (used to implement timers).
-*/
+// Allocate and initialize a new fdevent object
+// TODO: Switch these to unique_fd.
fdevent *fdevent_create(int fd, fd_func func, void *arg);
+fdevent* fdevent_create(int fd, fd_func2 func, void* arg);
// Deallocate an fdevent object that was created by fdevent_create.
void fdevent_destroy(fdevent *fde);
@@ -56,16 +57,14 @@
// fdevent_destroy, except releasing the file descriptor previously owned by the fdevent.
unique_fd fdevent_release(fdevent* fde);
-/* Change which events should cause notifications
-*/
+// Change which events should cause notifications
void fdevent_set(fdevent *fde, unsigned events);
void fdevent_add(fdevent *fde, unsigned events);
void fdevent_del(fdevent *fde, unsigned events);
void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms);
-/* loop forever, handling events.
-*/
+// Loop forever, handling events.
void fdevent_loop();
void check_main_thread();
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index 816134f..a9746bb 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -30,10 +30,16 @@
class FdHandler {
public:
- FdHandler(int read_fd, int write_fd) : read_fd_(read_fd), write_fd_(write_fd) {
- read_fde_ = fdevent_create(read_fd_, FdEventCallback, this);
+ FdHandler(int read_fd, int write_fd, bool use_new_callback)
+ : read_fd_(read_fd), write_fd_(write_fd) {
+ if (use_new_callback) {
+ read_fde_ = fdevent_create(read_fd_, FdEventNewCallback, this);
+ write_fde_ = fdevent_create(write_fd_, FdEventNewCallback, this);
+ } else {
+ read_fde_ = fdevent_create(read_fd_, FdEventCallback, this);
+ write_fde_ = fdevent_create(write_fd_, FdEventCallback, this);
+ }
fdevent_add(read_fde_, FDE_READ);
- write_fde_ = fdevent_create(write_fd_, FdEventCallback, this);
}
~FdHandler() {
@@ -64,6 +70,29 @@
}
}
+ static void FdEventNewCallback(fdevent* fde, unsigned events, void* userdata) {
+ int fd = fde->fd.get();
+ FdHandler* handler = reinterpret_cast<FdHandler*>(userdata);
+ ASSERT_EQ(0u, (events & ~(FDE_READ | FDE_WRITE))) << "unexpected events: " << events;
+ if (events & FDE_READ) {
+ ASSERT_EQ(fd, handler->read_fd_);
+ char c;
+ ASSERT_EQ(1, adb_read(fd, &c, 1));
+ handler->queue_.push(c);
+ fdevent_add(handler->write_fde_, FDE_WRITE);
+ }
+ if (events & FDE_WRITE) {
+ ASSERT_EQ(fd, handler->write_fd_);
+ ASSERT_FALSE(handler->queue_.empty());
+ char c = handler->queue_.front();
+ handler->queue_.pop();
+ ASSERT_EQ(1, adb_write(fd, &c, 1));
+ if (handler->queue_.empty()) {
+ fdevent_del(handler->write_fde_, FDE_WRITE);
+ }
+ }
+ }
+
private:
const int read_fd_;
const int write_fd_;
@@ -84,56 +113,60 @@
}
TEST_F(FdeventTest, smoke) {
- const size_t PIPE_COUNT = 10;
- const size_t MESSAGE_LOOP_COUNT = 100;
- const std::string MESSAGE = "fdevent_test";
- int fd_pair1[2];
- int fd_pair2[2];
- ASSERT_EQ(0, adb_socketpair(fd_pair1));
- ASSERT_EQ(0, adb_socketpair(fd_pair2));
- ThreadArg thread_arg;
- thread_arg.first_read_fd = fd_pair1[0];
- thread_arg.last_write_fd = fd_pair2[1];
- thread_arg.middle_pipe_count = PIPE_COUNT;
- int writer = fd_pair1[1];
- int reader = fd_pair2[0];
+ for (bool use_new_callback : {true, false}) {
+ fdevent_reset();
+ const size_t PIPE_COUNT = 10;
+ const size_t MESSAGE_LOOP_COUNT = 100;
+ const std::string MESSAGE = "fdevent_test";
+ int fd_pair1[2];
+ int fd_pair2[2];
+ ASSERT_EQ(0, adb_socketpair(fd_pair1));
+ ASSERT_EQ(0, adb_socketpair(fd_pair2));
+ ThreadArg thread_arg;
+ thread_arg.first_read_fd = fd_pair1[0];
+ thread_arg.last_write_fd = fd_pair2[1];
+ thread_arg.middle_pipe_count = PIPE_COUNT;
+ int writer = fd_pair1[1];
+ int reader = fd_pair2[0];
- PrepareThread();
+ PrepareThread();
- std::vector<std::unique_ptr<FdHandler>> fd_handlers;
- fdevent_run_on_main_thread([&thread_arg, &fd_handlers]() {
- std::vector<int> read_fds;
- std::vector<int> write_fds;
+ std::vector<std::unique_ptr<FdHandler>> fd_handlers;
+ fdevent_run_on_main_thread([&thread_arg, &fd_handlers, use_new_callback]() {
+ std::vector<int> read_fds;
+ std::vector<int> write_fds;
- read_fds.push_back(thread_arg.first_read_fd);
- for (size_t i = 0; i < thread_arg.middle_pipe_count; ++i) {
- int fds[2];
- ASSERT_EQ(0, adb_socketpair(fds));
- read_fds.push_back(fds[0]);
- write_fds.push_back(fds[1]);
+ read_fds.push_back(thread_arg.first_read_fd);
+ for (size_t i = 0; i < thread_arg.middle_pipe_count; ++i) {
+ int fds[2];
+ ASSERT_EQ(0, adb_socketpair(fds));
+ read_fds.push_back(fds[0]);
+ write_fds.push_back(fds[1]);
+ }
+ write_fds.push_back(thread_arg.last_write_fd);
+
+ for (size_t i = 0; i < read_fds.size(); ++i) {
+ fd_handlers.push_back(
+ std::make_unique<FdHandler>(read_fds[i], write_fds[i], use_new_callback));
+ }
+ });
+ WaitForFdeventLoop();
+
+ for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
+ std::string read_buffer = MESSAGE;
+ std::string write_buffer(MESSAGE.size(), 'a');
+ ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size()));
+ ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size()));
+ ASSERT_EQ(read_buffer, write_buffer);
}
- write_fds.push_back(thread_arg.last_write_fd);
- for (size_t i = 0; i < read_fds.size(); ++i) {
- fd_handlers.push_back(std::make_unique<FdHandler>(read_fds[i], write_fds[i]));
- }
- });
- WaitForFdeventLoop();
+ fdevent_run_on_main_thread([&fd_handlers]() { fd_handlers.clear(); });
+ WaitForFdeventLoop();
- for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
- std::string read_buffer = MESSAGE;
- std::string write_buffer(MESSAGE.size(), 'a');
- ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size()));
- ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size()));
- ASSERT_EQ(read_buffer, write_buffer);
+ TerminateThread();
+ ASSERT_EQ(0, adb_close(writer));
+ ASSERT_EQ(0, adb_close(reader));
}
-
- fdevent_run_on_main_thread([&fd_handlers]() { fd_handlers.clear(); });
- WaitForFdeventLoop();
-
- TerminateThread();
- ASSERT_EQ(0, adb_close(writer));
- ASSERT_EQ(0, adb_close(reader));
}
struct InvalidFdArg {
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 2c890b4..83213e9 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -17,10 +17,10 @@
#pragma once
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
#if !defined(_WIN32)
-#include <dirent.h>
#include <sys/socket.h>
#endif
@@ -114,6 +114,8 @@
private:
void reset(int new_value, void* previous_tag) {
+ int previous_errno = errno;
+
if (fd_ != -1) {
close(fd_, this);
}
@@ -122,6 +124,8 @@
if (new_value != -1) {
tag(new_value, previous_tag, this);
}
+
+ errno = previous_errno;
}
int fd_ = -1;
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 10f52f4..4a53a33 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -114,7 +114,6 @@
"libasync_safe",
"libbase",
"libdebuggerd",
- "libbacktrace",
"libunwindstack",
"libdexfile", // libunwindstack dependency
"libdexfile_external", // libunwindstack dependency
@@ -124,7 +123,6 @@
],
target: {
recovery: {
- cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
exclude_static_libs: [
"libartbase",
"libdexfile",
@@ -164,7 +162,6 @@
srcs: [
"libdebuggerd/backtrace.cpp",
- "libdebuggerd/elf_utils.cpp",
"libdebuggerd/open_files_list.cpp",
"libdebuggerd/tombstone.cpp",
"libdebuggerd/utility.cpp",
@@ -177,7 +174,6 @@
include_dirs: ["bionic/libc"],
static_libs: [
- "libbacktrace",
"libdexfile_external", // libunwindstack dependency
"libdexfile_support", // libunwindstack dependency
"libunwindstack",
@@ -223,7 +219,6 @@
},
shared_libs: [
- "libbacktrace",
"libbase",
"libcutils",
"libdebuggerd_client",
@@ -291,7 +286,6 @@
],
shared_libs: [
- "libbacktrace",
"libbase",
"liblog",
"libprocinfo",
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index d79d20b..82ba0a1 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -48,7 +48,12 @@
#define ATRACE_TAG ATRACE_TAG_BIONIC
#include <utils/Trace.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
#include "libdebuggerd/backtrace.h"
#include "libdebuggerd/tombstone.h"
@@ -63,8 +68,6 @@
using android::base::unique_fd;
using android::base::StringPrintf;
-using unwindstack::Regs;
-
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
struct stat st;
std::string task_path = StringPrintf("task/%d", tid);
@@ -287,7 +290,8 @@
case 1:
*abort_msg_address = crash_info->data.v1.abort_msg_address;
*siginfo = crash_info->data.v1.siginfo;
- regs->reset(Regs::CreateFromUcontext(Regs::CurrentArch(), &crash_info->data.v1.ucontext));
+ regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
+ &crash_info->data.v1.ucontext));
break;
default:
@@ -469,7 +473,7 @@
info.siginfo = &siginfo;
info.signo = info.siginfo->si_signo;
} else {
- info.registers.reset(Regs::RemoteGet(thread));
+ info.registers.reset(unwindstack::Regs::RemoteGet(thread));
if (!info.registers) {
PLOG(WARNING) << "failed to fetch registers for thread " << thread;
ptrace(PTRACE_DETACH, thread, 0, 0);
@@ -562,30 +566,25 @@
}
// TODO: Use seccomp to lock ourselves down.
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(vm_pid, false));
- if (!map) {
- LOG(FATAL) << "failed to create backtrace map";
- }
-
- std::shared_ptr<unwindstack::Memory> process_memory = map->GetProcessMemory();
- if (!process_memory) {
- LOG(FATAL) << "failed to get unwindstack::Memory handle";
+ unwindstack::UnwinderFromPid unwinder(256, vm_pid);
+ if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+ LOG(FATAL) << "Failed to init unwinder object.";
}
std::string amfd_data;
if (backtrace) {
ATRACE_NAME("dump_backtrace");
- dump_backtrace(std::move(g_output_fd), map.get(), thread_info, g_target_thread);
+ dump_backtrace(std::move(g_output_fd), &unwinder, thread_info, g_target_thread);
} else {
{
ATRACE_NAME("fdsan table dump");
- populate_fdsan_table(&open_files, process_memory, fdsan_table_address);
+ populate_fdsan_table(&open_files, unwinder.GetProcessMemory(), fdsan_table_address);
}
{
ATRACE_NAME("engrave_tombstone");
- engrave_tombstone(std::move(g_output_fd), map.get(), process_memory.get(), thread_info,
- g_target_thread, abort_msg_address, &open_files, &amfd_data);
+ engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread,
+ abort_msg_address, &open_files, &amfd_data);
}
}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 15c0265..bbec612 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,9 +42,12 @@
#include <android-base/file.h>
#include <android-base/unique_fd.h>
#include <async_safe/log.h>
-#include <backtrace/BacktraceMap.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
#include "debuggerd/handler.h"
#include "handler/fallback.h"
@@ -55,7 +58,6 @@
#include "libdebuggerd/tombstone.h"
using android::base::unique_fd;
-using unwindstack::Regs;
extern "C" bool __linker_enable_fallback_allocator();
extern "C" void __linker_disable_fallback_allocator();
@@ -73,17 +75,22 @@
}
{
- std::unique_ptr<Regs> regs;
+ std::unique_ptr<unwindstack::Regs> regs;
ThreadInfo thread;
thread.pid = getpid();
thread.tid = gettid();
thread.thread_name = get_thread_name(gettid());
- thread.registers.reset(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
+ unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
+ thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
// TODO: Create this once and store it in a global?
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
- dump_backtrace_thread(output_fd, map.get(), thread);
+ unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
+ if (unwinder.Init(arch)) {
+ dump_backtrace_thread(output_fd, &unwinder, thread);
+ } else {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
+ }
}
__linker_disable_fallback_allocator();
}
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index f0a01f4..753ebcb 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -35,8 +35,8 @@
#include <string>
#include <android-base/unique_fd.h>
-#include <backtrace/Backtrace.h>
#include <log/log.h>
+#include <unwindstack/Unwinder.h>
#include "libdebuggerd/types.h"
#include "libdebuggerd/utility.h"
@@ -59,25 +59,27 @@
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
-void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread) {
+void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+ const ThreadInfo& thread) {
log_t log;
log.tfd = output_fd;
log.amfd_data = nullptr;
_LOG(&log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread.thread_name.c_str(), thread.tid);
- std::vector<backtrace_frame_data_t> frames;
- if (!Backtrace::Unwind(thread.registers.get(), map, &frames, 0, nullptr)) {
+ unwinder->SetRegs(thread.registers.get());
+ unwinder->Unwind();
+ if (unwinder->NumFrames() == 0) {
_LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid);
return;
}
- for (auto& frame : frames) {
- _LOG(&log, logtype::BACKTRACE, " %s\n", Backtrace::FormatFrameData(&frame).c_str());
+ for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+ _LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str());
}
}
-void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread) {
log_t log;
log.tfd = output_fd.get();
@@ -91,10 +93,10 @@
dump_process_header(&log, target->second.pid, target->second.process_name.c_str());
- dump_backtrace_thread(output_fd.get(), map, target->second);
+ dump_backtrace_thread(output_fd.get(), unwinder, target->second);
for (const auto& [tid, info] : thread_info) {
if (tid != target_thread) {
- dump_backtrace_thread(output_fd.get(), map, info);
+ dump_backtrace_thread(output_fd.get(), unwinder, info);
}
}
diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp
deleted file mode 100644
index d7afc0b..0000000
--- a/debuggerd/libdebuggerd/elf_utils.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#define LOG_TAG "DEBUG"
-
-#include "libdebuggerd/elf_utils.h"
-
-#include <elf.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <unwindstack/Memory.h>
-
-#define NOTE_ALIGN(size) (((size) + 3) & ~3)
-
-template <typename HdrType, typename PhdrType, typename NhdrType>
-static bool get_build_id(unwindstack::Memory* memory, uintptr_t base_addr, uint8_t* e_ident,
- std::string* build_id) {
- HdrType hdr;
-
- memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);
-
- // First read the rest of the header.
- if (memory->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
- sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
- return false;
- }
-
- for (size_t i = 0; i < hdr.e_phnum; i++) {
- PhdrType phdr;
- if (memory->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
- reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
- return false;
- }
- // Looking for the .note.gnu.build-id note.
- if (phdr.p_type == PT_NOTE) {
- size_t hdr_size = phdr.p_filesz;
- uintptr_t addr = base_addr + phdr.p_offset;
- while (hdr_size >= sizeof(NhdrType)) {
- NhdrType nhdr;
- if (memory->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
- return false;
- }
- addr += sizeof(nhdr);
- if (nhdr.n_type == NT_GNU_BUILD_ID) {
- // Skip the name (which is the owner and should be "GNU").
- addr += NOTE_ALIGN(nhdr.n_namesz);
- uint8_t build_id_data[160];
- if (nhdr.n_descsz > sizeof(build_id_data)) {
- ALOGE("Possible corrupted note, desc size value is too large: %u",
- nhdr.n_descsz);
- return false;
- }
- if (memory->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
- return false;
- }
-
- build_id->clear();
- for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
- *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
- }
-
- return true;
- } else {
- // Move past the extra note data.
- hdr_size -= sizeof(nhdr);
- size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
- addr += skip_bytes;
- if (hdr_size < skip_bytes) {
- break;
- }
- hdr_size -= skip_bytes;
- }
- }
- }
- }
- return false;
-}
-
-bool elf_get_build_id(unwindstack::Memory* memory, uintptr_t addr, std::string* build_id) {
- // Read and verify the elf magic number first.
- uint8_t e_ident[EI_NIDENT];
- if (memory->Read(addr, e_ident, SELFMAG) != SELFMAG) {
- return false;
- }
-
- if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
- return false;
- }
-
- // Read the rest of EI_NIDENT.
- if (memory->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
- return false;
- }
-
- if (e_ident[EI_CLASS] == ELFCLASS32) {
- return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(memory, addr, e_ident, build_id);
- } else if (e_ident[EI_CLASS] == ELFCLASS64) {
- return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(memory, addr, e_ident, build_id);
- }
-
- return false;
-}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
index 119e59b..c20d090 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
@@ -28,15 +28,19 @@
#include "types.h"
#include "utility.h"
-class BacktraceMap;
+// Forward delcaration
+namespace unwindstack {
+class Unwinder;
+}
// Dumps a backtrace using a format similar to what Dalvik uses so that the result
// can be intermixed in a bug report.
-void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread);
void dump_backtrace_header(int output_fd);
-void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread);
+void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+ const ThreadInfo& thread);
void dump_backtrace_footer(int output_fd);
#endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index be90d0f..7133f77 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -29,7 +29,13 @@
#include "open_files_list.h"
#include "types.h"
-class BacktraceMap;
+// Forward declarations
+namespace unwindstack {
+class Unwinder;
+}
+
+// The maximum number of frames to save when unwinding.
+constexpr size_t kMaxFrames = 256;
/* Create and open a tombstone file for writing.
* Returns a writable file descriptor, or -1 with errno set appropriately.
@@ -38,16 +44,15 @@
int open_tombstone(std::string* path);
/* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
- pid_t pid, pid_t tid, const std::string& process_name,
- const std::map<pid_t, std::string>& threads, uint64_t abort_msg_address,
- std::string* amfd_data);
+void engrave_tombstone(int tombstone_fd, unwindstack::Unwinder* unwinder,
+ const OpenFilesList* open_files, pid_t pid, pid_t tid,
+ const std::string& process_name, const std::map<pid_t, std::string>& threads,
+ uint64_t abort_msg_address, std::string* amfd_data);
void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
ucontext_t* ucontext);
-void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map,
- unwindstack::Memory* process_memory,
+void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
uint64_t abort_msg_address, OpenFilesList* open_files,
std::string* amfd_data);
diff --git a/debuggerd/libdebuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h
deleted file mode 100644
index e7dbed7..0000000
--- a/debuggerd/libdebuggerd/test/BacktraceMock.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2015 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 _DEBUGGERD_TEST_BACKTRACE_MOCK_H
-#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
-
-#include <backtrace/BacktraceMap.h>
-
-class BacktraceMapMock : public BacktraceMap {
- public:
- BacktraceMapMock() : BacktraceMap(0) {}
- virtual ~BacktraceMapMock() {}
-
- void AddMap(backtrace_map_t& map) {
- maps_.push_back(map);
- }
-};
-
-#endif // _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/libdebuggerd/test/UnwinderMock.h b/debuggerd/libdebuggerd/test/UnwinderMock.h
new file mode 100644
index 0000000..023a578
--- /dev/null
+++ b/debuggerd/libdebuggerd/test/UnwinderMock.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#pragma once
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Unwinder.h>
+
+class UnwinderMock : public unwindstack::Unwinder {
+ public:
+ UnwinderMock() : Unwinder(128, new unwindstack::Maps, nullptr) {}
+ virtual ~UnwinderMock() { delete GetMaps(); }
+
+ void MockAddMap(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, std::string name,
+ uint64_t load_bias) {
+ GetMaps()->Add(start, end, offset, flags, name, load_bias);
+ }
+
+ void MockSetBuildID(uint64_t offset, const std::string& build_id) {
+ unwindstack::MapInfo* map_info = GetMaps()->Find(offset);
+ if (map_info != nullptr) {
+ std::string* new_build_id = new std::string(build_id);
+ map_info->build_id = reinterpret_cast<uintptr_t>(new_build_id);
+ }
+ }
+};
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index d24c887..eed5bd3 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -26,26 +26,16 @@
#include "libdebuggerd/utility.h"
-#include "BacktraceMock.h"
-#include "elf_fake.h"
+#include "UnwinderMock.h"
#include "host_signal_fixup.h"
#include "log_fake.h"
#include "tombstone.cpp"
-void dump_registers(log_t*, pid_t) {
-}
-
-void dump_memory_and_code(log_t*, Backtrace*) {
-}
-
-void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
-}
-
class TombstoneTest : public ::testing::Test {
protected:
virtual void SetUp() {
- map_mock_.reset(new BacktraceMapMock());
+ unwinder_mock_.reset(new UnwinderMock());
char tmp_file[256];
const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
@@ -71,7 +61,6 @@
log_.should_retrieve_logcat = false;
resetLogs();
- elf_set_fake_build_id("");
}
virtual void TearDown() {
@@ -80,24 +69,20 @@
}
}
- std::unique_ptr<BacktraceMapMock> map_mock_;
+ std::unique_ptr<UnwinderMock> unwinder_mock_;
log_t log_;
std::string amfd_data_;
};
TEST_F(TombstoneTest, single_map) {
- backtrace_map_t map;
#if defined(__LP64__)
- map.start = 0x123456789abcd000UL;
- map.end = 0x123456789abdf000UL;
+ unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0);
#else
- map.start = 0x1234000;
- map.end = 0x1235000;
+ unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0);
#endif
- map_mock_->AddMap(map);
- dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+ dump_all_maps(&log_, unwinder_mock_.get(), 0);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -119,20 +104,25 @@
}
TEST_F(TombstoneTest, single_map_elf_build_id) {
- backtrace_map_t map;
+ uint64_t build_id_offset;
#if defined(__LP64__)
- map.start = 0x123456789abcd000UL;
- map.end = 0x123456789abdf000UL;
+ build_id_offset = 0x123456789abcd000UL;
+ unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ,
+ "/system/lib/libfake.so", 0);
#else
- map.start = 0x1234000;
- map.end = 0x1235000;
+ build_id_offset = 0x1234000;
+ unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0);
#endif
- map.flags = PROT_READ;
- map.name = "/system/lib/libfake.so";
- map_mock_->AddMap(map);
- elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
- dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+ unwinder_mock_->MockSetBuildID(
+ build_id_offset,
+ std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef),
+ static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56),
+ static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab),
+ static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12),
+ static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78),
+ static_cast<char>(0x90)});
+ dump_all_maps(&log_, unwinder_mock_.get(), 0);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -153,83 +143,15 @@
ASSERT_STREQ("", getFakeLogPrint().c_str());
}
-// Even though build id is present, it should not be printed in either of
-// these cases.
-TEST_F(TombstoneTest, single_map_no_build_id) {
- backtrace_map_t map;
-#if defined(__LP64__)
- map.start = 0x123456789abcd000UL;
- map.end = 0x123456789abdf000UL;
-#else
- map.start = 0x1234000;
- map.end = 0x1235000;
-#endif
- map.flags = PROT_WRITE;
- map_mock_->AddMap(map);
-
- map.name = "/system/lib/libfake.so";
- map_mock_->AddMap(map);
-
- elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
- dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
-
- std::string tombstone_contents;
- ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
- ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory map (2 entries):\n"
-#if defined(__LP64__)
-" 12345678'9abcd000-12345678'9abdefff -w- 0 12000\n"
-" 12345678'9abcd000-12345678'9abdefff -w- 0 12000 /system/lib/libfake.so\n";
-#else
-" 01234000-01234fff -w- 0 1000\n"
-" 01234000-01234fff -w- 0 1000 /system/lib/libfake.so\n";
-#endif
- ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
-
- ASSERT_STREQ("", amfd_data_.c_str());
-
- // Verify that the log buf is empty, and no error messages.
- ASSERT_STREQ("", getFakeLogBuf().c_str());
- ASSERT_STREQ("", getFakeLogPrint().c_str());
-}
-
TEST_F(TombstoneTest, multiple_maps) {
- backtrace_map_t map;
+ unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0);
+ unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0);
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
- map.start = 0xa234000;
- map.end = 0xa235000;
- map_mock_->AddMap(map);
-
- map.start = 0xa334000;
- map.end = 0xa335000;
- map.offset = 0xf000;
- map.flags = PROT_READ;
- map_mock_->AddMap(map);
-
- map.start = 0xa434000;
- map.end = 0xa435000;
- map.offset = 0x1000;
- map.load_bias = 0xd000;
- map.flags = PROT_WRITE;
- map_mock_->AddMap(map);
-
- map.start = 0xa534000;
- map.end = 0xa535000;
- map.offset = 0x3000;
- map.load_bias = 0x2000;
- map.flags = PROT_EXEC;
- map_mock_->AddMap(map);
-
- map.start = 0xa634000;
- map.end = 0xa635000;
- map.offset = 0;
- map.load_bias = 0;
- map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
- map.name = "/system/lib/fake.so";
- map_mock_->AddMap(map);
-
- dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+ dump_all_maps(&log_, unwinder_mock_.get(), 0);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -259,31 +181,12 @@
}
TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
- backtrace_map_t map;
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
- map.start = 0xa434000;
- map.end = 0xa435000;
- map.offset = 0x1000;
- map.load_bias = 0xd000;
- map.flags = PROT_WRITE;
- map_mock_->AddMap(map);
-
- map.start = 0xa534000;
- map.end = 0xa535000;
- map.offset = 0x3000;
- map.load_bias = 0x2000;
- map.flags = PROT_EXEC;
- map_mock_->AddMap(map);
-
- map.start = 0xa634000;
- map.end = 0xa635000;
- map.offset = 0;
- map.load_bias = 0;
- map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
- map.name = "/system/lib/fake.so";
- map_mock_->AddMap(map);
-
- dump_all_maps(&log_, map_mock_.get(), nullptr, 0x1000);
+ dump_all_maps(&log_, unwinder_mock_.get(), 0x1000);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -311,31 +214,12 @@
}
TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
- backtrace_map_t map;
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
- map.start = 0xa434000;
- map.end = 0xa435000;
- map.offset = 0x1000;
- map.load_bias = 0xd000;
- map.flags = PROT_WRITE;
- map_mock_->AddMap(map);
-
- map.start = 0xa534000;
- map.end = 0xa535000;
- map.offset = 0x3000;
- map.load_bias = 0x2000;
- map.flags = PROT_EXEC;
- map_mock_->AddMap(map);
-
- map.start = 0xa634000;
- map.end = 0xa635000;
- map.offset = 0;
- map.load_bias = 0;
- map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
- map.name = "/system/lib/fake.so";
- map_mock_->AddMap(map);
-
- dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa533000);
+ dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -363,31 +247,12 @@
}
TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
- backtrace_map_t map;
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
- map.start = 0xa434000;
- map.end = 0xa435000;
- map.offset = 0x1000;
- map.load_bias = 0xd000;
- map.flags = PROT_WRITE;
- map_mock_->AddMap(map);
-
- map.start = 0xa534000;
- map.end = 0xa535000;
- map.offset = 0x3000;
- map.load_bias = 0x2000;
- map.flags = PROT_EXEC;
- map_mock_->AddMap(map);
-
- map.start = 0xa634000;
- map.end = 0xa635000;
- map.offset = 0;
- map.load_bias = 0;
- map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
- map.name = "/system/lib/fake.so";
- map_mock_->AddMap(map);
-
- dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa534040);
+ dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -413,36 +278,17 @@
}
TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
- backtrace_map_t map;
-
- map.start = 0xa434000;
- map.end = 0xa435000;
- map.offset = 0x1000;
- map.load_bias = 0xd000;
- map.flags = PROT_WRITE;
- map_mock_->AddMap(map);
-
- map.start = 0xa534000;
- map.end = 0xa535000;
- map.offset = 0x3000;
- map.load_bias = 0x2000;
- map.flags = PROT_EXEC;
- map_mock_->AddMap(map);
-
- map.start = 0xa634000;
- map.end = 0xa635000;
- map.offset = 0;
- map.load_bias = 0;
- map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
- map.name = "/system/lib/fake.so";
- map_mock_->AddMap(map);
+ unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+ unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+ unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/system/lib/fake.so", 0);
#if defined(__LP64__)
uint64_t addr = 0x12345a534040UL;
#else
uint64_t addr = 0xf534040UL;
#endif
- dump_all_maps(&log_, map_mock_.get(), nullptr, addr);
+ dump_all_maps(&log_, unwinder_mock_.get(), addr);
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -502,3 +348,467 @@
dump_timestamp(&log_, 0);
ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
}
+
+class MemoryPattern : public unwindstack::Memory {
+ public:
+ MemoryPattern() = default;
+ virtual ~MemoryPattern() = default;
+
+ size_t Read(uint64_t, void* dst, size_t size) override {
+ uint8_t* data = reinterpret_cast<uint8_t*>(dst);
+ for (size_t i = 0; i < size; i++) {
+ data[i] = (i % 0xff);
+ }
+ return size;
+ }
+};
+
+TEST_F(TombstoneTest, dump_stack_single_frame) {
+ std::vector<unwindstack::FrameData> frames;
+ unwindstack::Maps maps;
+ MemoryPattern memory;
+
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+ dump_stack(&log_, frames, &maps, &memory);
+
+ std::string contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+ std::string expected =
+#if defined(__LP64__)
+ " 0000000000001f80 0706050403020100\n"
+ " 0000000000001f88 0f0e0d0c0b0a0908\n"
+ " 0000000000001f90 1716151413121110\n"
+ " 0000000000001f98 1f1e1d1c1b1a1918\n"
+ " 0000000000001fa0 2726252423222120\n"
+ " 0000000000001fa8 2f2e2d2c2b2a2928\n"
+ " 0000000000001fb0 3736353433323130\n"
+ " 0000000000001fb8 3f3e3d3c3b3a3938\n"
+ " 0000000000001fc0 4746454443424140\n"
+ " 0000000000001fc8 4f4e4d4c4b4a4948\n"
+ " 0000000000001fd0 5756555453525150\n"
+ " 0000000000001fd8 5f5e5d5c5b5a5958\n"
+ " 0000000000001fe0 6766656463626160\n"
+ " 0000000000001fe8 6f6e6d6c6b6a6968\n"
+ " 0000000000001ff0 7776757473727170\n"
+ " 0000000000001ff8 7f7e7d7c7b7a7978\n"
+ " #00 0000000000002000 0706050403020100\n"
+ " 0000000000002008 0f0e0d0c0b0a0908\n"
+ " 0000000000002010 1716151413121110\n"
+ " 0000000000002018 1f1e1d1c1b1a1918\n"
+ " 0000000000002020 2726252423222120\n"
+ " 0000000000002028 2f2e2d2c2b2a2928\n"
+ " 0000000000002030 3736353433323130\n"
+ " 0000000000002038 3f3e3d3c3b3a3938\n"
+ " 0000000000002040 4746454443424140\n"
+ " 0000000000002048 4f4e4d4c4b4a4948\n"
+ " 0000000000002050 5756555453525150\n"
+ " 0000000000002058 5f5e5d5c5b5a5958\n"
+ " 0000000000002060 6766656463626160\n"
+ " 0000000000002068 6f6e6d6c6b6a6968\n"
+ " 0000000000002070 7776757473727170\n"
+ " 0000000000002078 7f7e7d7c7b7a7978\n";
+#else
+ " 00001fc0 03020100\n"
+ " 00001fc4 07060504\n"
+ " 00001fc8 0b0a0908\n"
+ " 00001fcc 0f0e0d0c\n"
+ " 00001fd0 13121110\n"
+ " 00001fd4 17161514\n"
+ " 00001fd8 1b1a1918\n"
+ " 00001fdc 1f1e1d1c\n"
+ " 00001fe0 23222120\n"
+ " 00001fe4 27262524\n"
+ " 00001fe8 2b2a2928\n"
+ " 00001fec 2f2e2d2c\n"
+ " 00001ff0 33323130\n"
+ " 00001ff4 37363534\n"
+ " 00001ff8 3b3a3938\n"
+ " 00001ffc 3f3e3d3c\n"
+ " #00 00002000 03020100\n"
+ " 00002004 07060504\n"
+ " 00002008 0b0a0908\n"
+ " 0000200c 0f0e0d0c\n"
+ " 00002010 13121110\n"
+ " 00002014 17161514\n"
+ " 00002018 1b1a1918\n"
+ " 0000201c 1f1e1d1c\n"
+ " 00002020 23222120\n"
+ " 00002024 27262524\n"
+ " 00002028 2b2a2928\n"
+ " 0000202c 2f2e2d2c\n"
+ " 00002030 33323130\n"
+ " 00002034 37363534\n"
+ " 00002038 3b3a3938\n"
+ " 0000203c 3f3e3d3c\n";
+#endif
+ EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames_same_sp) {
+ std::vector<unwindstack::FrameData> frames;
+ unwindstack::Maps maps;
+ MemoryPattern memory;
+
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2000});
+ dump_stack(&log_, frames, &maps, &memory);
+
+ std::string contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+ std::string expected =
+#if defined(__LP64__)
+ " 0000000000001f80 0706050403020100\n"
+ " 0000000000001f88 0f0e0d0c0b0a0908\n"
+ " 0000000000001f90 1716151413121110\n"
+ " 0000000000001f98 1f1e1d1c1b1a1918\n"
+ " 0000000000001fa0 2726252423222120\n"
+ " 0000000000001fa8 2f2e2d2c2b2a2928\n"
+ " 0000000000001fb0 3736353433323130\n"
+ " 0000000000001fb8 3f3e3d3c3b3a3938\n"
+ " 0000000000001fc0 4746454443424140\n"
+ " 0000000000001fc8 4f4e4d4c4b4a4948\n"
+ " 0000000000001fd0 5756555453525150\n"
+ " 0000000000001fd8 5f5e5d5c5b5a5958\n"
+ " 0000000000001fe0 6766656463626160\n"
+ " 0000000000001fe8 6f6e6d6c6b6a6968\n"
+ " 0000000000001ff0 7776757473727170\n"
+ " 0000000000001ff8 7f7e7d7c7b7a7978\n"
+ " #00 0000000000002000 0706050403020100\n"
+ " ................ ................\n"
+ " #01 0000000000002000 0706050403020100\n"
+ " 0000000000002008 0f0e0d0c0b0a0908\n"
+ " 0000000000002010 1716151413121110\n"
+ " 0000000000002018 1f1e1d1c1b1a1918\n"
+ " 0000000000002020 2726252423222120\n"
+ " 0000000000002028 2f2e2d2c2b2a2928\n"
+ " 0000000000002030 3736353433323130\n"
+ " 0000000000002038 3f3e3d3c3b3a3938\n"
+ " 0000000000002040 4746454443424140\n"
+ " 0000000000002048 4f4e4d4c4b4a4948\n"
+ " 0000000000002050 5756555453525150\n"
+ " 0000000000002058 5f5e5d5c5b5a5958\n"
+ " 0000000000002060 6766656463626160\n"
+ " 0000000000002068 6f6e6d6c6b6a6968\n"
+ " 0000000000002070 7776757473727170\n"
+ " 0000000000002078 7f7e7d7c7b7a7978\n";
+#else
+ " 00001fc0 03020100\n"
+ " 00001fc4 07060504\n"
+ " 00001fc8 0b0a0908\n"
+ " 00001fcc 0f0e0d0c\n"
+ " 00001fd0 13121110\n"
+ " 00001fd4 17161514\n"
+ " 00001fd8 1b1a1918\n"
+ " 00001fdc 1f1e1d1c\n"
+ " 00001fe0 23222120\n"
+ " 00001fe4 27262524\n"
+ " 00001fe8 2b2a2928\n"
+ " 00001fec 2f2e2d2c\n"
+ " 00001ff0 33323130\n"
+ " 00001ff4 37363534\n"
+ " 00001ff8 3b3a3938\n"
+ " 00001ffc 3f3e3d3c\n"
+ " #00 00002000 03020100\n"
+ " ........ ........\n"
+ " #01 00002000 03020100\n"
+ " 00002004 07060504\n"
+ " 00002008 0b0a0908\n"
+ " 0000200c 0f0e0d0c\n"
+ " 00002010 13121110\n"
+ " 00002014 17161514\n"
+ " 00002018 1b1a1918\n"
+ " 0000201c 1f1e1d1c\n"
+ " 00002020 23222120\n"
+ " 00002024 27262524\n"
+ " 00002028 2b2a2928\n"
+ " 0000202c 2f2e2d2c\n"
+ " 00002030 33323130\n"
+ " 00002034 37363534\n"
+ " 00002038 3b3a3938\n"
+ " 0000203c 3f3e3d3c\n";
+#endif
+ EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames) {
+ std::vector<unwindstack::FrameData> frames;
+ unwindstack::Maps maps;
+ MemoryPattern memory;
+
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2100});
+ dump_stack(&log_, frames, &maps, &memory);
+
+ std::string contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+ std::string expected =
+#if defined(__LP64__)
+ " 0000000000001f80 0706050403020100\n"
+ " 0000000000001f88 0f0e0d0c0b0a0908\n"
+ " 0000000000001f90 1716151413121110\n"
+ " 0000000000001f98 1f1e1d1c1b1a1918\n"
+ " 0000000000001fa0 2726252423222120\n"
+ " 0000000000001fa8 2f2e2d2c2b2a2928\n"
+ " 0000000000001fb0 3736353433323130\n"
+ " 0000000000001fb8 3f3e3d3c3b3a3938\n"
+ " 0000000000001fc0 4746454443424140\n"
+ " 0000000000001fc8 4f4e4d4c4b4a4948\n"
+ " 0000000000001fd0 5756555453525150\n"
+ " 0000000000001fd8 5f5e5d5c5b5a5958\n"
+ " 0000000000001fe0 6766656463626160\n"
+ " 0000000000001fe8 6f6e6d6c6b6a6968\n"
+ " 0000000000001ff0 7776757473727170\n"
+ " 0000000000001ff8 7f7e7d7c7b7a7978\n"
+ " #00 0000000000002000 0706050403020100\n"
+ " 0000000000002008 0f0e0d0c0b0a0908\n"
+ " #01 0000000000002010 0706050403020100\n"
+ " 0000000000002018 0f0e0d0c0b0a0908\n"
+ " 0000000000002020 1716151413121110\n"
+ " 0000000000002028 1f1e1d1c1b1a1918\n"
+ " 0000000000002030 2726252423222120\n"
+ " 0000000000002038 2f2e2d2c2b2a2928\n"
+ " 0000000000002040 3736353433323130\n"
+ " 0000000000002048 3f3e3d3c3b3a3938\n"
+ " 0000000000002050 4746454443424140\n"
+ " 0000000000002058 4f4e4d4c4b4a4948\n"
+ " 0000000000002060 5756555453525150\n"
+ " 0000000000002068 5f5e5d5c5b5a5958\n"
+ " 0000000000002070 6766656463626160\n"
+ " 0000000000002078 6f6e6d6c6b6a6968\n"
+ " 0000000000002080 7776757473727170\n"
+ " 0000000000002088 7f7e7d7c7b7a7978\n"
+ " ................ ................\n"
+ " #02 0000000000002100 0706050403020100\n"
+ " 0000000000002108 0f0e0d0c0b0a0908\n"
+ " 0000000000002110 1716151413121110\n"
+ " 0000000000002118 1f1e1d1c1b1a1918\n"
+ " 0000000000002120 2726252423222120\n"
+ " 0000000000002128 2f2e2d2c2b2a2928\n"
+ " 0000000000002130 3736353433323130\n"
+ " 0000000000002138 3f3e3d3c3b3a3938\n"
+ " 0000000000002140 4746454443424140\n"
+ " 0000000000002148 4f4e4d4c4b4a4948\n"
+ " 0000000000002150 5756555453525150\n"
+ " 0000000000002158 5f5e5d5c5b5a5958\n"
+ " 0000000000002160 6766656463626160\n"
+ " 0000000000002168 6f6e6d6c6b6a6968\n"
+ " 0000000000002170 7776757473727170\n"
+ " 0000000000002178 7f7e7d7c7b7a7978\n";
+#else
+ " 00001fc0 03020100\n"
+ " 00001fc4 07060504\n"
+ " 00001fc8 0b0a0908\n"
+ " 00001fcc 0f0e0d0c\n"
+ " 00001fd0 13121110\n"
+ " 00001fd4 17161514\n"
+ " 00001fd8 1b1a1918\n"
+ " 00001fdc 1f1e1d1c\n"
+ " 00001fe0 23222120\n"
+ " 00001fe4 27262524\n"
+ " 00001fe8 2b2a2928\n"
+ " 00001fec 2f2e2d2c\n"
+ " 00001ff0 33323130\n"
+ " 00001ff4 37363534\n"
+ " 00001ff8 3b3a3938\n"
+ " 00001ffc 3f3e3d3c\n"
+ " #00 00002000 03020100\n"
+ " 00002004 07060504\n"
+ " 00002008 0b0a0908\n"
+ " 0000200c 0f0e0d0c\n"
+ " #01 00002010 03020100\n"
+ " 00002014 07060504\n"
+ " 00002018 0b0a0908\n"
+ " 0000201c 0f0e0d0c\n"
+ " 00002020 13121110\n"
+ " 00002024 17161514\n"
+ " 00002028 1b1a1918\n"
+ " 0000202c 1f1e1d1c\n"
+ " 00002030 23222120\n"
+ " 00002034 27262524\n"
+ " 00002038 2b2a2928\n"
+ " 0000203c 2f2e2d2c\n"
+ " 00002040 33323130\n"
+ " 00002044 37363534\n"
+ " 00002048 3b3a3938\n"
+ " 0000204c 3f3e3d3c\n"
+ " ........ ........\n"
+ " #02 00002100 03020100\n"
+ " 00002104 07060504\n"
+ " 00002108 0b0a0908\n"
+ " 0000210c 0f0e0d0c\n"
+ " 00002110 13121110\n"
+ " 00002114 17161514\n"
+ " 00002118 1b1a1918\n"
+ " 0000211c 1f1e1d1c\n"
+ " 00002120 23222120\n"
+ " 00002124 27262524\n"
+ " 00002128 2b2a2928\n"
+ " 0000212c 2f2e2d2c\n"
+ " 00002130 33323130\n"
+ " 00002134 37363534\n"
+ " 00002138 3b3a3938\n"
+ " 0000213c 3f3e3d3c\n";
+#endif
+ EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames_disjoint_frames) {
+ std::vector<unwindstack::FrameData> frames;
+ unwindstack::Maps maps;
+ MemoryPattern memory;
+
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1000});
+ frames.push_back(
+ unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1030});
+ dump_stack(&log_, frames, &maps, &memory);
+
+ std::string contents;
+ ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+ ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+ std::string expected =
+#if defined(__LP64__)
+ " 0000000000001f80 0706050403020100\n"
+ " 0000000000001f88 0f0e0d0c0b0a0908\n"
+ " 0000000000001f90 1716151413121110\n"
+ " 0000000000001f98 1f1e1d1c1b1a1918\n"
+ " 0000000000001fa0 2726252423222120\n"
+ " 0000000000001fa8 2f2e2d2c2b2a2928\n"
+ " 0000000000001fb0 3736353433323130\n"
+ " 0000000000001fb8 3f3e3d3c3b3a3938\n"
+ " 0000000000001fc0 4746454443424140\n"
+ " 0000000000001fc8 4f4e4d4c4b4a4948\n"
+ " 0000000000001fd0 5756555453525150\n"
+ " 0000000000001fd8 5f5e5d5c5b5a5958\n"
+ " 0000000000001fe0 6766656463626160\n"
+ " 0000000000001fe8 6f6e6d6c6b6a6968\n"
+ " 0000000000001ff0 7776757473727170\n"
+ " 0000000000001ff8 7f7e7d7c7b7a7978\n"
+ " #00 0000000000002000 0706050403020100\n"
+ " 0000000000002008 0f0e0d0c0b0a0908\n"
+ " #01 0000000000002010 0706050403020100\n"
+ " 0000000000002018 0f0e0d0c0b0a0908\n"
+ " 0000000000002020 1716151413121110\n"
+ " 0000000000002028 1f1e1d1c1b1a1918\n"
+ " 0000000000002030 2726252423222120\n"
+ " 0000000000002038 2f2e2d2c2b2a2928\n"
+ " 0000000000002040 3736353433323130\n"
+ " 0000000000002048 3f3e3d3c3b3a3938\n"
+ " 0000000000002050 4746454443424140\n"
+ " 0000000000002058 4f4e4d4c4b4a4948\n"
+ " 0000000000002060 5756555453525150\n"
+ " 0000000000002068 5f5e5d5c5b5a5958\n"
+ " 0000000000002070 6766656463626160\n"
+ " 0000000000002078 6f6e6d6c6b6a6968\n"
+ " 0000000000002080 7776757473727170\n"
+ " 0000000000002088 7f7e7d7c7b7a7978\n"
+ " ................ ................\n"
+ " #02 0000000000001000 0706050403020100\n"
+ " 0000000000001008 0f0e0d0c0b0a0908\n"
+ " 0000000000001010 1716151413121110\n"
+ " 0000000000001018 1f1e1d1c1b1a1918\n"
+ " 0000000000001020 2726252423222120\n"
+ " 0000000000001028 2f2e2d2c2b2a2928\n"
+ " #03 0000000000001030 0706050403020100\n"
+ " 0000000000001038 0f0e0d0c0b0a0908\n"
+ " 0000000000001040 1716151413121110\n"
+ " 0000000000001048 1f1e1d1c1b1a1918\n"
+ " 0000000000001050 2726252423222120\n"
+ " 0000000000001058 2f2e2d2c2b2a2928\n"
+ " 0000000000001060 3736353433323130\n"
+ " 0000000000001068 3f3e3d3c3b3a3938\n"
+ " 0000000000001070 4746454443424140\n"
+ " 0000000000001078 4f4e4d4c4b4a4948\n"
+ " 0000000000001080 5756555453525150\n"
+ " 0000000000001088 5f5e5d5c5b5a5958\n"
+ " 0000000000001090 6766656463626160\n"
+ " 0000000000001098 6f6e6d6c6b6a6968\n"
+ " 00000000000010a0 7776757473727170\n"
+ " 00000000000010a8 7f7e7d7c7b7a7978\n";
+#else
+ " 00001fc0 03020100\n"
+ " 00001fc4 07060504\n"
+ " 00001fc8 0b0a0908\n"
+ " 00001fcc 0f0e0d0c\n"
+ " 00001fd0 13121110\n"
+ " 00001fd4 17161514\n"
+ " 00001fd8 1b1a1918\n"
+ " 00001fdc 1f1e1d1c\n"
+ " 00001fe0 23222120\n"
+ " 00001fe4 27262524\n"
+ " 00001fe8 2b2a2928\n"
+ " 00001fec 2f2e2d2c\n"
+ " 00001ff0 33323130\n"
+ " 00001ff4 37363534\n"
+ " 00001ff8 3b3a3938\n"
+ " 00001ffc 3f3e3d3c\n"
+ " #00 00002000 03020100\n"
+ " 00002004 07060504\n"
+ " 00002008 0b0a0908\n"
+ " 0000200c 0f0e0d0c\n"
+ " #01 00002010 03020100\n"
+ " 00002014 07060504\n"
+ " 00002018 0b0a0908\n"
+ " 0000201c 0f0e0d0c\n"
+ " 00002020 13121110\n"
+ " 00002024 17161514\n"
+ " 00002028 1b1a1918\n"
+ " 0000202c 1f1e1d1c\n"
+ " 00002030 23222120\n"
+ " 00002034 27262524\n"
+ " 00002038 2b2a2928\n"
+ " 0000203c 2f2e2d2c\n"
+ " 00002040 33323130\n"
+ " 00002044 37363534\n"
+ " 00002048 3b3a3938\n"
+ " 0000204c 3f3e3d3c\n"
+ " ........ ........\n"
+ " #02 00001000 03020100\n"
+ " 00001004 07060504\n"
+ " 00001008 0b0a0908\n"
+ " 0000100c 0f0e0d0c\n"
+ " 00001010 13121110\n"
+ " 00001014 17161514\n"
+ " 00001018 1b1a1918\n"
+ " 0000101c 1f1e1d1c\n"
+ " 00001020 23222120\n"
+ " 00001024 27262524\n"
+ " 00001028 2b2a2928\n"
+ " 0000102c 2f2e2d2c\n"
+ " #03 00001030 03020100\n"
+ " 00001034 07060504\n"
+ " 00001038 0b0a0908\n"
+ " 0000103c 0f0e0d0c\n"
+ " 00001040 13121110\n"
+ " 00001044 17161514\n"
+ " 00001048 1b1a1918\n"
+ " 0000104c 1f1e1d1c\n"
+ " 00001050 23222120\n"
+ " 00001054 27262524\n"
+ " 00001058 2b2a2928\n"
+ " 0000105c 2f2e2d2c\n"
+ " 00001060 33323130\n"
+ " 00001064 37363534\n"
+ " 00001068 3b3a3938\n"
+ " 0000106c 3f3e3d3c\n";
+#endif
+ EXPECT_EQ(expected, contents);
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index b20014f..8798ad3 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -41,19 +41,20 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/log.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
#include <log/log.h>
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
// Needed to get DEBUGGER_SIGNAL.
#include "debuggerd/handler.h"
#include "libdebuggerd/backtrace.h"
-#include "libdebuggerd/elf_utils.h"
#include "libdebuggerd/open_files_list.h"
#include "libdebuggerd/utility.h"
@@ -62,9 +63,6 @@
using android::base::StringPrintf;
using android::base::unique_fd;
-using unwindstack::Memory;
-using unwindstack::Regs;
-
using namespace std::literals::string_literals;
#define STACK_WORDS 16
@@ -87,7 +85,7 @@
_LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
}
-static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps) {
std::string cause;
if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -104,12 +102,9 @@
cause = "call to kuser_cmpxchg64";
}
} else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
- for (auto it = map->begin(); it != map->end(); ++it) {
- const backtrace_map_t* entry = *it;
- if (si->si_addr >= reinterpret_cast<void*>(entry->start) &&
- si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) {
- cause = "execute-only (no-read) memory access error; likely due to data in .text.";
- }
+ unwindstack::MapInfo* map_info = maps->Find(reinterpret_cast<uint64_t>(si->si_addr));
+ if (map_info != nullptr && map_info->flags == PROT_EXEC) {
+ cause = "execute-only (no-read) memory access error; likely due to data in .text.";
}
} else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
@@ -119,7 +114,8 @@
if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
}
-static void dump_signal_info(log_t* log, const ThreadInfo& thread_info, Memory* process_memory) {
+static void dump_signal_info(log_t* log, const ThreadInfo& thread_info,
+ unwindstack::Memory* process_memory) {
char addr_desc[64]; // ", fault addr 0x1234"
if (signal_has_si_addr(thread_info.siginfo)) {
void* addr = thread_info.siginfo->si_addr;
@@ -156,14 +152,14 @@
thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
}
-static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
+static void dump_stack_segment(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
uint64_t* sp, size_t words, int label) {
// Read the data all at once.
word_t stack_data[words];
// TODO: Do we need to word align this for crashes caused by a misaligned sp?
// The process_vm_readv implementation of Memory should handle this appropriately?
- size_t bytes_read = process_memory->Read(*sp, stack_data, sizeof(word_t) * words);
+ size_t bytes_read = memory->Read(*sp, stack_data, sizeof(word_t) * words);
words = bytes_read / sizeof(word_t);
std::string line;
for (size_t i = 0; i < words; i++) {
@@ -176,17 +172,15 @@
}
line += StringPrintf("%" PRIPTR " %" PRIPTR, *sp, static_cast<uint64_t>(stack_data[i]));
- backtrace_map_t map;
- backtrace_map->FillIn(stack_data[i], &map);
- std::string map_name{map.Name()};
- if (BacktraceMap::IsValid(map) && !map_name.empty()) {
- line += " " + map_name;
- uint64_t offset = 0;
- std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset);
- if (!func_name.empty()) {
+ unwindstack::MapInfo* map_info = maps->Find(stack_data[i]);
+ if (map_info != nullptr && !map_info->name.empty()) {
+ line += " " + map_info->name;
+ std::string func_name;
+ uint64_t func_offset = 0;
+ if (map_info->GetFunctionName(stack_data[i], &func_name, &func_offset)) {
line += " (" + func_name;
- if (offset) {
- line += StringPrintf("+%" PRIu64, offset);
+ if (func_offset) {
+ line += StringPrintf("+%" PRIu64, func_offset);
}
line += ')';
}
@@ -197,12 +191,11 @@
}
}
-static void dump_stack(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
- std::vector<backtrace_frame_data_t>& frames) {
+static void dump_stack(log_t* log, const std::vector<unwindstack::FrameData>& frames,
+ unwindstack::Maps* maps, unwindstack::Memory* memory) {
size_t first = 0, last;
for (size_t i = 0; i < frames.size(); i++) {
- const backtrace_frame_data_t& frame = frames[i];
- if (frame.sp) {
+ if (frames[i].sp) {
if (!first) {
first = i+1;
}
@@ -217,29 +210,44 @@
// Dump a few words before the first frame.
uint64_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
- dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, -1);
+ dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, -1);
+
+#if defined(__LP64__)
+ static constexpr const char delimiter[] = " ................ ................\n";
+#else
+ static constexpr const char delimiter[] = " ........ ........\n";
+#endif
// Dump a few words from all successive frames.
- // Only log the first 3 frames, put the rest in the tombstone.
for (size_t i = first; i <= last; i++) {
- const backtrace_frame_data_t* frame = &frames[i];
+ auto* frame = &frames[i];
if (sp != frame->sp) {
- _LOG(log, logtype::STACK, " ........ ........\n");
+ _LOG(log, logtype::STACK, delimiter);
sp = frame->sp;
}
- if (i == last) {
- dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, i);
- if (sp < frame->sp + frame->stack_size) {
- _LOG(log, logtype::STACK, " ........ ........\n");
- }
- } else {
- size_t words = frame->stack_size / sizeof(word_t);
- if (words == 0) {
- words = 1;
- } else if (words > STACK_WORDS) {
+ if (i != last) {
+ // Print stack data up to the stack from the next frame.
+ size_t words;
+ uint64_t next_sp = frames[i + 1].sp;
+ if (next_sp < sp) {
+ // The next frame is probably using a completely different stack,
+ // so dump the max from this stack.
words = STACK_WORDS;
+ } else {
+ words = (next_sp - sp) / sizeof(word_t);
+ if (words == 0) {
+ // The sp is the same as the next frame, print at least
+ // one line for this frame.
+ words = 1;
+ } else if (words > STACK_WORDS) {
+ words = STACK_WORDS;
+ }
}
- dump_stack_segment(log, backtrace_map, process_memory, &sp, words, i);
+ dump_stack_segment(log, maps, memory, &sp, words, i);
+ } else {
+ // Print some number of words past the last stack frame since we
+ // don't know how large the stack is.
+ dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, i);
}
}
}
@@ -256,7 +264,7 @@
return addr_str;
}
-static void dump_abort_message(log_t* log, Memory* process_memory, uint64_t address) {
+static void dump_abort_message(log_t* log, unwindstack::Memory* process_memory, uint64_t address) {
if (address == 0) {
return;
}
@@ -285,16 +293,16 @@
_LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]);
}
-static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
+static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t addr) {
bool print_fault_address_marker = addr;
- ScopedBacktraceMapIteratorLock lock(map);
+ unwindstack::Maps* maps = unwinder->GetMaps();
_LOG(log, logtype::MAPS,
"\n"
"memory map (%zu entr%s):",
- map->size(), map->size() == 1 ? "y" : "ies");
+ maps->Total(), maps->Total() == 1 ? "y" : "ies");
if (print_fault_address_marker) {
- if (map->begin() != map->end() && addr < (*map->begin())->start) {
+ if (maps->Total() != 0 && addr < maps->Get(0)->start) {
_LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
get_addr_string(addr).c_str());
print_fault_address_marker = false;
@@ -305,51 +313,54 @@
_LOG(log, logtype::MAPS, "\n");
}
+ std::shared_ptr<unwindstack::Memory>& process_memory = unwinder->GetProcessMemory();
+
std::string line;
- for (auto it = map->begin(); it != map->end(); ++it) {
- const backtrace_map_t* entry = *it;
+ for (unwindstack::MapInfo* map_info : *maps) {
line = " ";
if (print_fault_address_marker) {
- if (addr < entry->start) {
+ if (addr < map_info->start) {
_LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
get_addr_string(addr).c_str());
print_fault_address_marker = false;
- } else if (addr >= entry->start && addr < entry->end) {
+ } else if (addr >= map_info->start && addr < map_info->end) {
line = "--->";
print_fault_address_marker = false;
}
}
- line += get_addr_string(entry->start) + '-' + get_addr_string(entry->end - 1) + ' ';
- if (entry->flags & PROT_READ) {
+ line += get_addr_string(map_info->start) + '-' + get_addr_string(map_info->end - 1) + ' ';
+ if (map_info->flags & PROT_READ) {
line += 'r';
} else {
line += '-';
}
- if (entry->flags & PROT_WRITE) {
+ if (map_info->flags & PROT_WRITE) {
line += 'w';
} else {
line += '-';
}
- if (entry->flags & PROT_EXEC) {
+ if (map_info->flags & PROT_EXEC) {
line += 'x';
} else {
line += '-';
}
- line += StringPrintf(" %8" PRIx64 " %8" PRIx64, entry->offset, entry->end - entry->start);
+ line += StringPrintf(" %8" PRIx64 " %8" PRIx64, map_info->offset,
+ map_info->end - map_info->start);
bool space_needed = true;
- if (entry->name.length() > 0) {
+ if (!map_info->name.empty()) {
space_needed = false;
- line += " " + entry->name;
- std::string build_id;
- if ((entry->flags & PROT_READ) && elf_get_build_id(process_memory, entry->start, &build_id)) {
+ line += " " + map_info->name;
+ std::string build_id = map_info->GetPrintableBuildID();
+ if (!build_id.empty()) {
line += " (BuildId: " + build_id + ")";
}
}
- if (entry->load_bias != 0) {
+ uint64_t load_bias = map_info->GetLoadBias(process_memory);
+ if (load_bias != 0) {
if (space_needed) {
line += ' ';
}
- line += StringPrintf(" (load bias 0x%" PRIx64 ")", entry->load_bias);
+ line += StringPrintf(" (load bias 0x%" PRIx64 ")", load_bias);
}
_LOG(log, logtype::MAPS, "%s\n", line.c_str());
}
@@ -359,9 +370,9 @@
}
}
-void dump_backtrace(log_t* log, std::vector<backtrace_frame_data_t>& frames, const char* prefix) {
- for (auto& frame : frames) {
- _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, Backtrace::FormatFrameData(&frame).c_str());
+void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+ for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+ _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
}
}
@@ -377,7 +388,7 @@
_LOG(log, logtype::REGISTERS, " %s\n", output.c_str());
}
-void dump_registers(log_t* log, Regs* regs) {
+void dump_registers(log_t* log, unwindstack::Regs* regs) {
// Split lr/sp/pc into their own special row.
static constexpr size_t column_count = 4;
std::vector<std::pair<std::string, uint64_t>> current_row;
@@ -416,23 +427,22 @@
print_register_row(log, special_row);
}
-void dump_memory_and_code(log_t* log, BacktraceMap* map, Memory* memory, Regs* regs) {
- regs->IterateRegisters([log, map, memory](const char* reg_name, uint64_t reg_value) {
+void dump_memory_and_code(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
+ unwindstack::Regs* regs) {
+ regs->IterateRegisters([log, maps, memory](const char* reg_name, uint64_t reg_value) {
std::string label{"memory near "s + reg_name};
- if (map) {
- backtrace_map_t map_info;
- map->FillIn(reg_value, &map_info);
- std::string map_name{map_info.Name()};
- if (!map_name.empty()) label += " (" + map_info.Name() + ")";
+ if (maps) {
+ unwindstack::MapInfo* map_info = maps->Find(reg_value);
+ if (map_info != nullptr && !map_info->name.empty()) {
+ label += " (" + map_info->name + ")";
+ }
}
dump_memory(log, memory, reg_value, label);
});
}
-static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory,
- const ThreadInfo& thread_info, uint64_t abort_msg_address,
- bool primary_thread) {
- UNUSED(process_memory);
+static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info,
+ uint64_t abort_msg_address, bool primary_thread) {
log->current_tid = thread_info.tid;
if (!primary_thread) {
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
@@ -440,41 +450,41 @@
dump_thread_info(log, thread_info);
if (thread_info.siginfo) {
- dump_signal_info(log, thread_info, process_memory);
- dump_probable_cause(log, thread_info.siginfo, map);
+ dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
+ dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps());
}
if (primary_thread) {
- dump_abort_message(log, process_memory, abort_msg_address);
+ dump_abort_message(log, unwinder->GetProcessMemory().get(), abort_msg_address);
}
dump_registers(log, thread_info.registers.get());
// Unwind will mutate the registers, so make a copy first.
- std::unique_ptr<Regs> regs_copy(thread_info.registers->Clone());
- std::vector<backtrace_frame_data_t> frames;
- if (!Backtrace::Unwind(regs_copy.get(), map, &frames, 0, nullptr)) {
+ std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
+ unwinder->SetRegs(regs_copy.get());
+ unwinder->Unwind();
+ if (unwinder->NumFrames() == 0) {
_LOG(log, logtype::THREAD, "Failed to unwind");
- return false;
- }
-
- if (!frames.empty()) {
+ } else {
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
- dump_backtrace(log, frames, " ");
+ dump_backtrace(log, unwinder, " ");
_LOG(log, logtype::STACK, "\nstack:\n");
- dump_stack(log, map, process_memory, frames);
+ dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());
}
if (primary_thread) {
- dump_memory_and_code(log, map, process_memory, thread_info.registers.get());
- if (map) {
+ unwindstack::Maps* maps = unwinder->GetMaps();
+ dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
+ thread_info.registers.get());
+ if (maps != nullptr) {
uint64_t addr = 0;
siginfo_t* si = thread_info.siginfo;
if (signal_has_si_addr(si)) {
addr = reinterpret_cast<uint64_t>(si->si_addr);
}
- dump_all_maps(log, map, process_memory, addr);
+ dump_all_maps(log, unwinder, addr);
}
}
@@ -625,7 +635,8 @@
read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
- std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
+ std::unique_ptr<unwindstack::Regs> regs(
+ unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
std::map<pid_t, ThreadInfo> threads;
threads[gettid()] = ThreadInfo{
@@ -637,18 +648,16 @@
.siginfo = siginfo,
};
- std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid(), false));
- if (!backtrace_map) {
- ALOGE("failed to create backtrace map");
- _exit(1);
+ unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
+ if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+ LOG(FATAL) << "Failed to init unwinder object.";
}
- std::shared_ptr<Memory> process_memory = backtrace_map->GetProcessMemory();
- engrave_tombstone(unique_fd(dup(tombstone_fd)), backtrace_map.get(), process_memory.get(),
- threads, tid, abort_msg_address, nullptr, nullptr);
+ engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, abort_msg_address,
+ nullptr, nullptr);
}
-void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_memory,
+void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
uint64_t abort_msg_address, OpenFilesList* open_files,
std::string* amfd_data) {
@@ -669,7 +678,7 @@
if (it == threads.end()) {
LOG(FATAL) << "failed to find target thread";
}
- dump_thread(&log, map, process_memory, it->second, abort_msg_address, true);
+ dump_thread(&log, unwinder, it->second, abort_msg_address, true);
if (want_logs) {
dump_logs(&log, it->second.pid, 50);
@@ -680,7 +689,7 @@
continue;
}
- dump_thread(&log, map, process_memory, thread_info, 0, false);
+ dump_thread(&log, unwinder, thread_info, 0, false);
}
if (open_files) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 26ce3b2..943a071 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -998,9 +998,7 @@
if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
return false;
}
- auto it = std::find_if(fstab.begin(), fstab.end(),
- [&](const auto& entry) { return entry.mount_point == mount_point; });
- return it != fstab.end();
+ return GetEntryForMountPoint(&fstab, mount_point) != nullptr;
}
// When multiple fstab records share the same mount_point, it will try to mount each
@@ -1090,6 +1088,13 @@
// Skips mounting the device.
continue;
}
+ } else if (!current_entry.avb_key.empty()) {
+ if (AvbHandle::SetUpStandaloneAvbHashtree(¤t_entry) == AvbHashtreeResult::kFail) {
+ LERROR << "Failed to set up AVB on standalone partition: "
+ << current_entry.mount_point << ", skipping!";
+ // Skips mounting the device.
+ continue;
+ }
} else if ((current_entry.fs_mgr_flags.verify)) {
int rc = fs_mgr_setup_verity(¤t_entry, true);
if (__android_log_is_debuggable() &&
@@ -1326,6 +1331,13 @@
// Skips mounting the device.
continue;
}
+ } else if (!fstab_entry.avb_key.empty()) {
+ if (AvbHandle::SetUpStandaloneAvbHashtree(&fstab_entry) == AvbHashtreeResult::kFail) {
+ LERROR << "Failed to set up AVB on standalone partition: "
+ << fstab_entry.mount_point << ", skipping!";
+ // Skips mounting the device.
+ continue;
+ }
} else if (fstab_entry.fs_mgr_flags.verify) {
int rc = fs_mgr_setup_verity(&fstab_entry, true);
if (__android_log_is_debuggable() &&
@@ -1384,6 +1396,15 @@
needs_checkpoint);
}
+int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point) {
+ return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1);
+}
+
+int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
+ bool needs_checkpoint) {
+ return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_checkpoint);
+}
+
/*
* mount a tmpfs filesystem at the given point.
* return 0 on success, non-zero on failure.
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0482f6c..de3aac1 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -338,6 +338,8 @@
} else if (StartsWith(flag, "zram_backing_dev_path=")) {
entry->fs_mgr_flags.zram_backing_dev_path = true;
entry->zram_backing_dev_path = arg;
+ } else if (StartsWith(flag, "avb_key=")) {
+ entry->avb_key = arg;
} else {
LWARNING << "Warning: unknown flag: " << flag;
}
@@ -787,10 +789,8 @@
free(fstab);
}
-/*
- * Returns the fstab_rec* whose mount_point is path.
- * Returns nullptr if not found.
- */
+// Returns the fstab_rec* whose mount_point is path.
+// Returns nullptr if not found.
struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path) {
if (!fstab) {
return nullptr;
@@ -803,6 +803,20 @@
return nullptr;
}
+FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
+ if (fstab == nullptr) {
+ return nullptr;
+ }
+
+ for (auto& entry : *fstab) {
+ if (entry.mount_point == path) {
+ return &entry;
+ }
+ }
+
+ return nullptr;
+}
+
std::set<std::string> fs_mgr_get_boot_devices() {
// First check the kernel commandline, then try the device tree otherwise
std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
@@ -965,12 +979,15 @@
}
FstabEntry BuildGsiSystemFstabEntry() {
+ // .logical_partition_name is required to look up AVB Hashtree descriptors.
FstabEntry system = {
.blk_device = "system_gsi",
.mount_point = "/system",
.fs_type = "ext4",
.flags = MS_RDONLY,
.fs_options = "barrier=1",
+ .avb_key = "/gsi.avbpubkey",
+ .logical_partition_name = "system"
};
system.fs_mgr_flags.wait = true;
system.fs_mgr_flags.logical = true;
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 2c4299a..c7d2cb9 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -564,9 +564,8 @@
if (std::find(verity.begin(), verity.end(), "system") != verity.end()) return mounts;
// confirm that fstab is missing system
- if (std::find_if(fstab->begin(), fstab->end(), [](const auto& entry) {
- return entry.mount_point == "/" || entry.mount_point == "/system ";
- }) != fstab->end()) {
+ if (GetEntryForMountPoint(fstab, "/") != nullptr ||
+ GetEntryForMountPoint(fstab, "/system") != nullptr) {
return mounts;
}
@@ -847,9 +846,7 @@
std::vector<std::string> fs_mgr_overlayfs_required_devices(Fstab* fstab) {
if (fs_mgr_overlayfs_invalid()) return {};
- if (std::find_if(fstab->begin(), fstab->end(), [](const auto& entry) {
- return entry.mount_point == kScratchMountPoint;
- }) != fstab->end()) {
+ if (GetEntryForMountPoint(fstab, kScratchMountPoint) != nullptr) {
return {};
}
@@ -889,9 +886,7 @@
if (overlay_mount_point == kScratchMountPoint) {
if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
} else {
- if (std::find_if(fstab.begin(), fstab.end(), [&overlay_mount_point](const auto& entry) {
- return entry.mount_point == overlay_mount_point;
- }) == fstab.end()) {
+ if (GetEntryForMountPoint(&fstab, overlay_mount_point) == nullptr) {
continue;
}
}
diff --git a/fs_mgr/fs_mgr_roots.cpp b/fs_mgr/fs_mgr_roots.cpp
index 32a5d21..58ef9b6 100644
--- a/fs_mgr/fs_mgr_roots.cpp
+++ b/fs_mgr/fs_mgr_roots.cpp
@@ -37,9 +37,8 @@
if (path.empty()) return nullptr;
std::string str(path);
while (true) {
- auto it = std::find_if(fstab->begin(), fstab->end(),
- [&str](const auto& entry) { return entry.mount_point == str; });
- if (it != fstab->end()) return &*it;
+ auto entry = GetEntryForMountPoint(fstab, str);
+ if (entry != nullptr) return entry;
if (str == "/") break;
auto slash = str.find_last_of('/');
if (slash == std::string::npos) break;
@@ -65,10 +64,8 @@
return MountState::ERROR;
}
- auto mv = std::find_if(
- mounted_fstab.begin(), mounted_fstab.end(),
- [&mount_point](const auto& entry) { return entry.mount_point == mount_point; });
- if (mv != mounted_fstab.end()) {
+ auto mv = GetEntryForMountPoint(&mounted_fstab, mount_point);
+ if (mv != nullptr) {
return MountState::MOUNTED;
}
return MountState::NOT_MOUNTED;
@@ -178,9 +175,8 @@
return "";
}
- auto it = std::find_if(fstab.begin(), fstab.end(),
- [](const auto& entry) { return entry.mount_point == kSystemRoot; });
- if (it == fstab.end()) {
+ auto entry = GetEntryForMountPoint(&fstab, kSystemRoot);
+ if (entry == nullptr) {
return "/";
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 1685e50..2934363 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -65,9 +65,11 @@
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
#define FS_MGR_DOMNT_SUCCESS 0
-
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
+ bool needs_checkpoint);
+int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
+int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
bool need_cp);
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point = "");
int fs_mgr_do_mount_one(fstab_rec* rec);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 100e076..549ff68 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -116,6 +116,7 @@
std::string zram_loopback_path;
uint64_t zram_loopback_size = 512 * 1024 * 1024; // 512MB by default;
std::string zram_backing_dev_path;
+ std::string avb_key;
// TODO: Remove this union once fstab_rec is deprecated. It only serves as a
// convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
@@ -184,6 +185,8 @@
bool ReadFstabFromDt(Fstab* fstab, bool log = true);
bool ReadDefaultFstab(Fstab* fstab);
+FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
+
// Temporary conversion functions.
FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec);
Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab);
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index c6a9e0b..a4614d0 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -299,24 +299,25 @@
// private methods of DeviceMapper
bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
std::vector<TargetInfo>* table) {
- char buffer[4096];
- struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer);
+ std::vector<char> buffer;
+ struct dm_ioctl* io = nullptr;
- InitIo(io, name);
- io->data_size = sizeof(buffer);
- io->data_start = sizeof(*io);
- io->flags = flags;
- if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
- PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
- return false;
- }
- if (io->flags & DM_BUFFER_FULL_FLAG) {
- PLOG(ERROR) << "DM_TABLE_STATUS result for " << name << " was too large";
- return false;
+ for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
+ io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
+
+ InitIo(io, name);
+ io->data_size = buffer.size();
+ io->data_start = sizeof(*io);
+ io->flags = flags;
+ if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
+ PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
+ return false;
+ }
+ if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
}
uint32_t cursor = io->data_start;
- uint32_t data_end = std::min(io->data_size, uint32_t(sizeof(buffer)));
+ uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
for (uint32_t i = 0; i < io->target_count; i++) {
if (cursor + sizeof(struct dm_target_spec) > data_end) {
break;
@@ -324,14 +325,14 @@
// After each dm_target_spec is a status string. spec->next is an
// offset from |io->data_start|, and we clamp it to the size of our
// buffer.
- struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(buffer + cursor);
+ struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
uint32_t data_offset = cursor + sizeof(dm_target_spec);
uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
std::string data;
if (next_cursor > data_offset) {
// Note: we use c_str() to eliminate any extra trailing 0s.
- data = std::string(buffer + data_offset, next_cursor - data_offset).c_str();
+ data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
}
table->emplace_back(*spec, data);
cursor = next_cursor;
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
index 6ccdb57..b9b75f8 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp
@@ -374,14 +374,6 @@
return IsFilePinned(fd, file_path, sfs.f_type);
}
-static void LogExtent(uint32_t num, const struct fiemap_extent& ext) {
- LOG(INFO) << "Extent #" << num;
- LOG(INFO) << " fe_logical: " << ext.fe_logical;
- LOG(INFO) << " fe_physical: " << ext.fe_physical;
- LOG(INFO) << " fe_length: " << ext.fe_length;
- LOG(INFO) << " fe_flags: 0x" << std::hex << ext.fe_flags;
-}
-
static bool ReadFiemap(int file_fd, const std::string& file_path,
std::vector<struct fiemap_extent>* extents) {
uint64_t fiemap_size =
@@ -473,7 +465,7 @@
}
::android::base::unique_fd bdev_fd(
- TEMP_FAILURE_RETRY(open(bdev_path.c_str(), O_RDWR | O_CLOEXEC)));
+ TEMP_FAILURE_RETRY(open(bdev_path.c_str(), O_RDONLY | O_CLOEXEC)));
if (bdev_fd < 0) {
PLOG(ERROR) << "Failed to open block device: " << bdev_path;
cleanup(file_path, create);
@@ -530,7 +522,6 @@
fmap->file_path_ = abs_path;
fmap->bdev_path_ = bdev_path;
fmap->file_fd_ = std::move(file_fd);
- fmap->bdev_fd_ = std::move(bdev_fd);
fmap->file_size_ = file_size;
fmap->bdev_size_ = bdevsz;
fmap->fs_type_ = fs_type;
@@ -541,120 +532,9 @@
return fmap;
}
-bool FiemapWriter::Flush() const {
- if (fsync(bdev_fd_)) {
- PLOG(ERROR) << "Failed to flush " << bdev_path_ << " with fsync";
- return false;
- }
- return true;
-}
-
-// TODO: Test with fs block_size > bdev block_size
-bool FiemapWriter::Write(off64_t off, uint8_t* buffer, uint64_t size) {
- if (!size || size > file_size_) {
- LOG(ERROR) << "Failed write: size " << size << " is invalid for file's size " << file_size_;
- return false;
- }
-
- if (off + size > file_size_) {
- LOG(ERROR) << "Failed write: Invalid offset " << off << " or size " << size
- << " for file size " << file_size_;
- return false;
- }
-
- if ((off & (block_size_ - 1)) || (size & (block_size_ - 1))) {
- LOG(ERROR) << "Failed write: Unaligned offset " << off << " or size " << size
- << " for block size " << block_size_;
- return false;
- }
-
- if (!IsFilePinned(file_fd_, file_path_, fs_type_)) {
- LOG(ERROR) << "Failed write: file " << file_path_ << " is not pinned";
- return false;
- }
-
- // find extents that must be written to and then write one at a time.
- uint32_t num_extent = 1;
- uint32_t buffer_offset = 0;
- for (auto& extent : extents_) {
- uint64_t e_start = extent.fe_logical;
- uint64_t e_end = extent.fe_logical + extent.fe_length;
- // Do we write in this extent ?
- if (off >= e_start && off < e_end) {
- uint64_t written = WriteExtent(extent, buffer + buffer_offset, off, size);
- if (written == 0) {
- return false;
- }
-
- buffer_offset += written;
- off += written;
- size -= written;
-
- // Paranoid check to make sure we are done with this extent now
- if (size && (off >= e_start && off < e_end)) {
- LOG(ERROR) << "Failed to write extent fully";
- LogExtent(num_extent, extent);
- return false;
- }
-
- if (size == 0) {
- // done
- break;
- }
- }
- num_extent++;
- }
-
- return true;
-}
-
bool FiemapWriter::Read(off64_t off, uint8_t* buffer, uint64_t size) {
return false;
}
-// private helpers
-
-// WriteExtent() Returns the total number of bytes written. It will always be multiple of
-// block_size_. 0 is returned in one of the two cases.
-// 1. Any write failed between logical_off & logical_off + length.
-// 2. The logical_offset + length doesn't overlap with the extent passed.
-// The function can either partially for fully write the extent depending on the
-// logical_off + length. It is expected that alignment checks for size and offset are
-// performed before calling into this function.
-uint64_t FiemapWriter::WriteExtent(const struct fiemap_extent& ext, uint8_t* buffer,
- off64_t logical_off, uint64_t length) {
- uint64_t e_start = ext.fe_logical;
- uint64_t e_end = ext.fe_logical + ext.fe_length;
- if (logical_off < e_start || logical_off >= e_end) {
- LOG(ERROR) << "Failed write extent, invalid offset " << logical_off << " and size "
- << length;
- LogExtent(0, ext);
- return 0;
- }
-
- off64_t bdev_offset = ext.fe_physical + (logical_off - e_start);
- if (bdev_offset >= bdev_size_) {
- LOG(ERROR) << "Failed write extent, invalid block # " << bdev_offset << " for block device "
- << bdev_path_ << " of size " << bdev_size_ << " bytes";
- return 0;
- }
- if (TEMP_FAILURE_RETRY(lseek64(bdev_fd_, bdev_offset, SEEK_SET)) == -1) {
- PLOG(ERROR) << "Failed write extent, seek offset for " << bdev_path_ << " offset "
- << bdev_offset;
- return 0;
- }
-
- // Determine how much we want to write at once.
- uint64_t logical_end = logical_off + length;
- uint64_t write_size = (e_end <= logical_end) ? (e_end - logical_off) : length;
- if (!android::base::WriteFully(bdev_fd_, buffer, write_size)) {
- PLOG(ERROR) << "Failed write extent, write " << bdev_path_ << " at " << bdev_offset
- << " size " << write_size;
- return 0;
- }
-
- return write_size;
-}
-
} // namespace fiemap_writer
} // namespace android
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index 3d20ff3..41fa959 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -138,36 +138,31 @@
EXPECT_GT(fptr->extents().size(), 0);
}
-TEST_F(FiemapWriterTest, CheckWriteError) {
- FiemapUniquePtr fptr = FiemapWriter::Open(testfile, testfile_size);
- ASSERT_NE(fptr, nullptr);
-
- // prepare buffer for writing the pattern - 0xa0
- uint64_t blocksize = fptr->block_size();
- auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, blocksize), free);
- ASSERT_NE(buffer, nullptr);
- memset(buffer.get(), 0xa0, blocksize);
-
- uint8_t* p = static_cast<uint8_t*>(buffer.get());
- for (off64_t off = 0; off < testfile_size; off += blocksize) {
- ASSERT_TRUE(fptr->Write(off, p, blocksize));
- }
-
- EXPECT_TRUE(fptr->Flush());
-}
-
class TestExistingFile : public ::testing::Test {
protected:
void SetUp() override {
std::string exec_dir = ::android::base::GetExecutableDirectory();
- std::string unaligned_file = exec_dir + "/testdata/unaligned_file";
- std::string file_4k = exec_dir + "/testdata/file_4k";
- std::string file_32k = exec_dir + "/testdata/file_32k";
- fptr_unaligned = FiemapWriter::Open(unaligned_file, 4097, false);
- fptr_4k = FiemapWriter::Open(file_4k, 4096, false);
- fptr_32k = FiemapWriter::Open(file_32k, 32768, false);
+ unaligned_file_ = exec_dir + "/testdata/unaligned_file";
+ file_4k_ = exec_dir + "/testdata/file_4k";
+ file_32k_ = exec_dir + "/testdata/file_32k";
+
+ CleanupFiles();
+ fptr_unaligned = FiemapWriter::Open(unaligned_file_, 4097);
+ fptr_4k = FiemapWriter::Open(file_4k_, 4096);
+ fptr_32k = FiemapWriter::Open(file_32k_, 32768);
}
+ void TearDown() { CleanupFiles(); }
+
+ void CleanupFiles() {
+ unlink(unaligned_file_.c_str());
+ unlink(file_4k_.c_str());
+ unlink(file_32k_.c_str());
+ }
+
+ std::string unaligned_file_;
+ std::string file_4k_;
+ std::string file_32k_;
FiemapUniquePtr fptr_unaligned;
FiemapUniquePtr fptr_4k;
FiemapUniquePtr fptr_32k;
@@ -184,33 +179,6 @@
EXPECT_GT(fptr_32k->extents().size(), 0);
}
-TEST_F(TestExistingFile, CheckWriteError) {
- ASSERT_NE(fptr_4k, nullptr);
- // prepare buffer for writing the pattern - 0xa0
- uint64_t blocksize = fptr_4k->block_size();
- auto buff_4k = std::unique_ptr<void, decltype(&free)>(calloc(1, blocksize), free);
- ASSERT_NE(buff_4k, nullptr);
- memset(buff_4k.get(), 0xa0, blocksize);
-
- uint8_t* p = static_cast<uint8_t*>(buff_4k.get());
- for (off64_t off = 0; off < 4096; off += blocksize) {
- ASSERT_TRUE(fptr_4k->Write(off, p, blocksize));
- }
- EXPECT_TRUE(fptr_4k->Flush());
-
- ASSERT_NE(fptr_32k, nullptr);
- // prepare buffer for writing the pattern - 0xa0
- blocksize = fptr_32k->block_size();
- auto buff_32k = std::unique_ptr<void, decltype(&free)>(calloc(1, blocksize), free);
- ASSERT_NE(buff_32k, nullptr);
- memset(buff_32k.get(), 0xa0, blocksize);
- p = static_cast<uint8_t*>(buff_32k.get());
- for (off64_t off = 0; off < 4096; off += blocksize) {
- ASSERT_TRUE(fptr_32k->Write(off, p, blocksize));
- }
- EXPECT_TRUE(fptr_32k->Flush());
-}
-
class VerifyBlockWritesExt4 : public ::testing::Test {
// 2GB Filesystem and 4k block size by default
static constexpr uint64_t block_size = 4096;
@@ -253,46 +221,6 @@
std::string fs_path;
};
-TEST_F(VerifyBlockWritesExt4, CheckWrites) {
- EXPECT_EQ(access(fs_path.c_str(), F_OK), 0);
-
- std::string file_path = mntpoint + "/testfile";
- uint64_t file_size = 100 * 1024 * 1024;
- auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, getpagesize()), free);
- ASSERT_NE(buffer, nullptr);
- memset(buffer.get(), 0xa0, getpagesize());
- {
- // scoped fiemap writer
- FiemapUniquePtr fptr = FiemapWriter::Open(file_path, file_size);
- ASSERT_NE(fptr, nullptr);
- uint8_t* p = static_cast<uint8_t*>(buffer.get());
- for (off64_t off = 0; off < file_size / getpagesize(); off += getpagesize()) {
- ASSERT_TRUE(fptr->Write(off, p, getpagesize()));
- }
- EXPECT_TRUE(fptr->Flush());
- }
- // unmount file system here to make sure we invalidated all page cache and
- // remount the filesystem again for verification
- ASSERT_EQ(umount(mntpoint.c_str()), 0);
-
- LoopDevice loop_dev(fs_path);
- ASSERT_TRUE(loop_dev.valid());
- ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "ext4", 0, nullptr), 0)
- << "failed to mount: " << loop_dev.device() << " on " << mntpoint << ": "
- << strerror(errno);
-
- ::android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_SYNC));
- ASSERT_NE(fd, -1);
- auto filebuf = std::unique_ptr<void, decltype(&free)>(calloc(1, getpagesize()), free);
- ASSERT_NE(filebuf, nullptr);
- for (off64_t off = 0; off < file_size / getpagesize(); off += getpagesize()) {
- memset(filebuf.get(), 0x00, getpagesize());
- ASSERT_EQ(pread64(fd, filebuf.get(), getpagesize(), off), getpagesize());
- ASSERT_EQ(memcmp(filebuf.get(), buffer.get(), getpagesize()), 0)
- << "Invalid pattern at offset: " << off << " size " << getpagesize();
- }
-}
-
class VerifyBlockWritesF2fs : public ::testing::Test {
// 2GB Filesystem and 4k block size by default
static constexpr uint64_t block_size = 4096;
@@ -335,46 +263,6 @@
std::string fs_path;
};
-TEST_F(VerifyBlockWritesF2fs, CheckWrites) {
- EXPECT_EQ(access(fs_path.c_str(), F_OK), 0);
-
- std::string file_path = mntpoint + "/testfile";
- uint64_t file_size = 100 * 1024 * 1024;
- auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, getpagesize()), free);
- ASSERT_NE(buffer, nullptr);
- memset(buffer.get(), 0xa0, getpagesize());
- {
- // scoped fiemap writer
- FiemapUniquePtr fptr = FiemapWriter::Open(file_path, file_size);
- ASSERT_NE(fptr, nullptr);
- uint8_t* p = static_cast<uint8_t*>(buffer.get());
- for (off64_t off = 0; off < file_size / getpagesize(); off += getpagesize()) {
- ASSERT_TRUE(fptr->Write(off, p, getpagesize()));
- }
- EXPECT_TRUE(fptr->Flush());
- }
- // unmount file system here to make sure we invalidated all page cache and
- // remount the filesystem again for verification
- ASSERT_EQ(umount(mntpoint.c_str()), 0);
-
- LoopDevice loop_dev(fs_path);
- ASSERT_TRUE(loop_dev.valid());
- ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint.c_str(), "f2fs", 0, nullptr), 0)
- << "failed to mount: " << loop_dev.device() << " on " << mntpoint << ": "
- << strerror(errno);
-
- ::android::base::unique_fd fd(open(file_path.c_str(), O_RDONLY | O_SYNC));
- ASSERT_NE(fd, -1);
- auto filebuf = std::unique_ptr<void, decltype(&free)>(calloc(1, getpagesize()), free);
- ASSERT_NE(filebuf, nullptr);
- for (off64_t off = 0; off < file_size / getpagesize(); off += getpagesize()) {
- memset(filebuf.get(), 0x00, getpagesize());
- ASSERT_EQ(pread64(fd, filebuf.get(), getpagesize(), off), getpagesize());
- ASSERT_EQ(memcmp(filebuf.get(), buffer.get(), getpagesize()), 0)
- << "Invalid pattern at offset: " << off << " size " << getpagesize();
- }
-}
-
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
if (argc <= 1) {
diff --git a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
index a0085cf..edbae77 100644
--- a/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
+++ b/fs_mgr/libfiemap_writer/include/libfiemap_writer/fiemap_writer.h
@@ -57,15 +57,6 @@
// FiemapWriter::Open).
static bool HasPinnedExtents(const std::string& file_path);
- // Syncs block device writes.
- bool Flush() const;
-
- // Writes the file by using its FIEMAP and performing i/o on the raw block device.
- // The return value is success / failure. This will happen in particular if the
- // kernel write returns errors, extents are not writeable or more importantly, if the 'size' is
- // not aligned to the block device's block size.
- bool Write(off64_t off, uint8_t* buffer, uint64_t size);
-
// The counter part of Write(). It is an error for the offset to be unaligned with
// the block device's block size.
// In case of error, the contents of buffer MUST be discarded.
@@ -93,7 +84,6 @@
// File descriptors for the file and block device
::android::base::unique_fd file_fd_;
- ::android::base::unique_fd bdev_fd_;
// Size in bytes of the file this class is writing
uint64_t file_size_;
@@ -112,9 +102,6 @@
std::vector<struct fiemap_extent> extents_;
FiemapWriter() = default;
-
- uint64_t WriteExtent(const struct fiemap_extent& ext, uint8_t* buffer, off64_t logical_off,
- uint64_t length);
};
} // namespace fiemap_writer
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index f57c9d6..945087f 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -27,6 +27,7 @@
#include "util.h"
+using android::base::Basename;
using android::base::StartsWith;
using android::base::unique_fd;
@@ -61,7 +62,7 @@
// class VBMetaData
// ----------------
std::unique_ptr<AvbVBMetaImageHeader> VBMetaData::GetVBMetaHeader(bool update_vbmeta_size) {
- auto vbmeta_header(std::make_unique<AvbVBMetaImageHeader>());
+ auto vbmeta_header = std::make_unique<AvbVBMetaImageHeader>();
if (!vbmeta_header) return nullptr;
@@ -136,7 +137,7 @@
}
table.set_readonly(true);
- const std::string mount_point(basename(fstab_entry->mount_point.c_str()));
+ const std::string mount_point(Basename(fstab_entry->mount_point));
android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
if (!dm.CreateDevice(mount_point, table)) {
LERROR << "Couldn't create verity device!";
@@ -163,12 +164,12 @@
return true;
}
-bool GetHashtreeDescriptor(const std::string& partition_name,
- const std::vector<VBMetaData>& vbmeta_images,
- AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt,
- std::string* out_digest) {
+std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
+ std::string* out_salt, std::string* out_digest) {
bool found = false;
const uint8_t* desc_partition_name;
+ auto hashtree_desc = std::make_unique<AvbHashtreeDescriptor>();
for (const auto& vbmeta : vbmeta_images) {
size_t num_descriptors;
@@ -189,15 +190,15 @@
desc_partition_name =
(const uint8_t*)descriptors[n] + sizeof(AvbHashtreeDescriptor);
if (!avb_hashtree_descriptor_validate_and_byteswap(
- (AvbHashtreeDescriptor*)descriptors[n], out_hashtree_desc)) {
+ (AvbHashtreeDescriptor*)descriptors[n], hashtree_desc.get())) {
continue;
}
- if (out_hashtree_desc->partition_name_len != partition_name.length()) {
+ if (hashtree_desc->partition_name_len != partition_name.length()) {
continue;
}
// Notes that desc_partition_name is not NUL-terminated.
std::string hashtree_partition_name((const char*)desc_partition_name,
- out_hashtree_desc->partition_name_len);
+ hashtree_desc->partition_name_len);
if (hashtree_partition_name == partition_name) {
found = true;
}
@@ -209,16 +210,43 @@
if (!found) {
LERROR << "Partition descriptor not found: " << partition_name.c_str();
+ return nullptr;
+ }
+
+ const uint8_t* desc_salt = desc_partition_name + hashtree_desc->partition_name_len;
+ *out_salt = BytesToHex(desc_salt, hashtree_desc->salt_len);
+
+ const uint8_t* desc_digest = desc_salt + hashtree_desc->salt_len;
+ *out_digest = BytesToHex(desc_digest, hashtree_desc->root_digest_len);
+
+ return hashtree_desc;
+}
+
+bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev,
+ const std::vector<VBMetaData>& vbmeta_images,
+ const std::string& ab_suffix,
+ const std::string& ab_other_suffix) {
+ // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
+ // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
+ std::string partition_name = DeriveAvbPartitionName(*fstab_entry, ab_suffix, ab_other_suffix);
+
+ if (partition_name.empty()) {
+ LERROR << "partition name is empty, cannot lookup AVB descriptors";
return false;
}
- const uint8_t* desc_salt = desc_partition_name + out_hashtree_desc->partition_name_len;
- *out_salt = BytesToHex(desc_salt, out_hashtree_desc->salt_len);
+ std::string salt;
+ std::string root_digest;
+ std::unique_ptr<AvbHashtreeDescriptor> hashtree_descriptor =
+ GetHashtreeDescriptor(partition_name, vbmeta_images, &salt, &root_digest);
+ if (!hashtree_descriptor) {
+ return false;
+ }
- const uint8_t* desc_digest = desc_salt + out_hashtree_desc->salt_len;
- *out_digest = BytesToHex(desc_digest, out_hashtree_desc->root_digest_len);
-
- return true;
+ // Converts HASHTREE descriptor to verity table to load into kernel.
+ // When success, the new device path will be returned, e.g., /dev/block/dm-2.
+ return HashtreeDmVeritySetup(fstab_entry, *hashtree_descriptor, salt, root_digest,
+ wait_for_verity_dev);
}
// Converts a AVB partition_name (without A/B suffix) to a device partition name.
@@ -244,6 +272,38 @@
return sanitized_partition_name + append_suffix;
}
+// Converts fstab_entry.blk_device (with ab_suffix) to a AVB partition name.
+// e.g., "/dev/block/by-name/system_a", slot_select => "system",
+// "/dev/block/by-name/system_b", slot_select_other => "system_other".
+//
+// Or for a logical partition (with ab_suffix):
+// e.g., "system_a", slot_select => "system",
+// "system_b", slot_select_other => "system_other".
+std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix,
+ const std::string& ab_other_suffix) {
+ std::string partition_name;
+ if (fstab_entry.fs_mgr_flags.logical) {
+ partition_name = fstab_entry.logical_partition_name;
+ } else {
+ partition_name = Basename(fstab_entry.blk_device);
+ }
+
+ if (fstab_entry.fs_mgr_flags.slot_select) {
+ auto found = partition_name.rfind(ab_suffix);
+ if (found != std::string::npos) {
+ partition_name.erase(found); // converts system_a => system
+ }
+ } else if (fstab_entry.fs_mgr_flags.slot_select_other) {
+ auto found = partition_name.rfind(ab_other_suffix);
+ if (found != std::string::npos) {
+ partition_name.erase(found); // converts system_b => system
+ }
+ partition_name += "_other"; // converts system => system_other
+ }
+
+ return partition_name;
+}
+
off64_t GetTotalSize(int fd) {
off64_t saved_current = lseek64(fd, 0, SEEK_CUR);
if (saved_current == -1) {
@@ -268,19 +328,19 @@
std::unique_ptr<AvbFooter> GetAvbFooter(int fd) {
std::array<uint8_t, AVB_FOOTER_SIZE> footer_buf;
- auto footer(std::make_unique<AvbFooter>());
+ auto footer = std::make_unique<AvbFooter>();
off64_t footer_offset = GetTotalSize(fd) - AVB_FOOTER_SIZE;
ssize_t num_read =
TEMP_FAILURE_RETRY(pread64(fd, footer_buf.data(), AVB_FOOTER_SIZE, footer_offset));
if (num_read < 0 || num_read != AVB_FOOTER_SIZE) {
- PERROR << "Failed to read AVB footer";
+ PERROR << "Failed to read AVB footer at offset: " << footer_offset;
return nullptr;
}
if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_buf.data(), footer.get())) {
- PERROR << "AVB footer verification failed.";
+ PERROR << "AVB footer verification failed at offset " << footer_offset;
return nullptr;
}
@@ -432,24 +492,22 @@
return chain_partitions;
}
-VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
- const std::string& partition_name, const std::string& ab_suffix,
- const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
- bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
- std::function<std::string(const std::string&)> device_path_constructor,
- bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images) {
+// Loads the vbmeta from a given path.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
+ const std::string& image_path, const std::string& partition_name,
+ const std::string& expected_public_key_blob, bool allow_verification_error,
+ bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled,
+ VBMetaVerifyResult* out_verify_result) {
// Ensures the device path (might be a symlink created by init) is ready to access.
- auto device_path = device_path_constructor(
- AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix));
- if (!WaitForFile(device_path, 1s)) {
- PERROR << "No such partition: " << device_path;
- return VBMetaVerifyResult::kError;
+ if (!WaitForFile(image_path, 1s)) {
+ PERROR << "No such path: " << image_path;
+ return nullptr;
}
- unique_fd fd(TEMP_FAILURE_RETRY(open(device_path.c_str(), O_RDONLY | O_CLOEXEC)));
+ unique_fd fd(TEMP_FAILURE_RETRY(open(image_path.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
- PERROR << "Failed to open: " << device_path;
- return VBMetaVerifyResult::kError;
+ PERROR << "Failed to open: " << image_path;
+ return nullptr;
}
VBMetaVerifyResult verify_result;
@@ -457,53 +515,84 @@
VerifyVBMetaData(fd, partition_name, expected_public_key_blob, &verify_result);
if (!vbmeta) {
LERROR << partition_name << ": Failed to load vbmeta, result: " << verify_result;
- return VBMetaVerifyResult::kError;
+ return nullptr;
}
+ vbmeta->set_vbmeta_path(image_path);
if (!allow_verification_error && verify_result == VBMetaVerifyResult::kErrorVerification) {
LERROR << partition_name << ": allow verification error is not allowed";
- return VBMetaVerifyResult::kError;
+ return nullptr;
}
std::unique_ptr<AvbVBMetaImageHeader> vbmeta_header =
vbmeta->GetVBMetaHeader(true /* update_vbmeta_size */);
if (!vbmeta_header) {
LERROR << partition_name << ": Failed to get vbmeta header";
- return VBMetaVerifyResult::kError;
+ return nullptr;
}
if (rollback_protection && RollbackDetected(partition_name, vbmeta_header->rollback_index)) {
- return VBMetaVerifyResult::kError;
+ return nullptr;
}
// vbmeta flags can only be set by the top-level vbmeta image.
if (is_chained_vbmeta && vbmeta_header->flags != 0) {
LERROR << partition_name << ": chained vbmeta image has non-zero flags";
- return VBMetaVerifyResult::kError;
+ return nullptr;
}
+ // Checks if verification has been disabled by setting a bit in the image.
+ if (out_verification_disabled) {
+ if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
+ LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name;
+ *out_verification_disabled = true;
+ } else {
+ *out_verification_disabled = false;
+ }
+ }
+
+ if (out_verify_result) {
+ *out_verify_result = verify_result;
+ }
+
+ return vbmeta;
+}
+
+VBMetaVerifyResult LoadAndVerifyVbmetaByPartition(
+ const std::string& partition_name, const std::string& ab_suffix,
+ const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
+ bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
+ std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta,
+ std::vector<VBMetaData>* out_vbmeta_images) {
+ auto image_path = device_path_constructor(
+ AvbPartitionToDevicePatition(partition_name, ab_suffix, ab_other_suffix));
+
+ bool verification_disabled = false;
+ VBMetaVerifyResult verify_result;
+ auto vbmeta = LoadAndVerifyVbmetaByPath(
+ image_path, partition_name, expected_public_key_blob, allow_verification_error,
+ rollback_protection, is_chained_vbmeta, &verification_disabled, &verify_result);
+
+ if (!vbmeta) {
+ return VBMetaVerifyResult::kError;
+ }
if (out_vbmeta_images) {
out_vbmeta_images->emplace_back(std::move(*vbmeta));
}
- // If verification has been disabled by setting a bit in the image, we're done.
- if (vbmeta_header->flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED) {
- LWARNING << "VERIFICATION_DISABLED bit is set for partition: " << partition_name;
- return verify_result;
- }
-
- if (load_chained_vbmeta) {
+ // Only loads chained vbmeta if AVB verification is NOT disabled.
+ if (!verification_disabled && load_chained_vbmeta) {
bool fatal_error = false;
auto chain_partitions = GetChainPartitionInfo(*out_vbmeta_images->rbegin(), &fatal_error);
if (fatal_error) {
return VBMetaVerifyResult::kError;
}
for (auto& chain : chain_partitions) {
- auto sub_ret = LoadAndVerifyVbmetaImpl(
- chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob,
- allow_verification_error, load_chained_vbmeta, rollback_protection,
- device_path_constructor, true, /* is_chained_vbmeta */
- out_vbmeta_images);
+ auto sub_ret = LoadAndVerifyVbmetaByPartition(
+ chain.partition_name, ab_suffix, ab_other_suffix, chain.public_key_blob,
+ allow_verification_error, load_chained_vbmeta, rollback_protection,
+ device_path_constructor, true, /* is_chained_vbmeta */
+ out_vbmeta_images);
if (sub_ret != VBMetaVerifyResult::kSuccess) {
verify_result = sub_ret; // might be 'ERROR' or 'ERROR VERIFICATION'.
if (verify_result == VBMetaVerifyResult::kError) {
diff --git a/fs_mgr/libfs_avb/avb_util.h b/fs_mgr/libfs_avb/avb_util.h
index babbfef..14918f2 100644
--- a/fs_mgr/libfs_avb/avb_util.h
+++ b/fs_mgr/libfs_avb/avb_util.h
@@ -46,10 +46,9 @@
};
// AvbHashtreeDescriptor to dm-verity table setup.
-bool GetHashtreeDescriptor(const std::string& partition_name,
- const std::vector<VBMetaData>& vbmeta_images,
- AvbHashtreeDescriptor* out_hashtree_desc, std::string* out_salt,
- std::string* out_digest);
+std::unique_ptr<AvbHashtreeDescriptor> GetHashtreeDescriptor(
+ const std::string& partition_name, const std::vector<VBMetaData>& vbmeta_images,
+ std::string* out_salt, std::string* out_digest);
bool ConstructVerityTable(const AvbHashtreeDescriptor& hashtree_desc, const std::string& salt,
const std::string& root_digest, const std::string& blk_device,
@@ -59,11 +58,20 @@
const std::string& salt, const std::string& root_digest,
bool wait_for_verity_dev);
-// Maps AVB partition name to a device partition name.
+// Searches a Avb hashtree descriptor in vbmeta_images for fstab_entry, to enable dm-verity.
+bool LoadAvbHashtreeToEnableVerity(FstabEntry* fstab_entry, bool wait_for_verity_dev,
+ const std::vector<VBMetaData>& vbmeta_images,
+ const std::string& ab_suffix, const std::string& ab_other_suffix);
+
+// Converts AVB partition name to a device partition name.
std::string AvbPartitionToDevicePatition(const std::string& avb_partition_name,
const std::string& ab_suffix,
const std::string& ab_other_suffix);
+// Converts by-name symlink to AVB partition name.
+std::string DeriveAvbPartitionName(const FstabEntry& fstab_entry, const std::string& ab_suffix,
+ const std::string& ab_other_suffix);
+
// AvbFooter and AvbMetaImage maninpulations.
off64_t GetTotalSize(int fd);
@@ -84,12 +92,22 @@
// Extracts chain partition info.
std::vector<ChainInfo> GetChainPartitionInfo(const VBMetaData& vbmeta, bool* fatal_error);
-VBMetaVerifyResult LoadAndVerifyVbmetaImpl(
- const std::string& partition_name, const std::string& ab_suffix,
- const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
- bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
- std::function<std::string(const std::string&)> device_path_constructor,
- bool is_chained_vbmeta, std::vector<VBMetaData>* out_vbmeta_images);
+// Loads the single vbmeta from a given path.
+std::unique_ptr<VBMetaData> LoadAndVerifyVbmetaByPath(
+ const std::string& image_path, const std::string& partition_name,
+ const std::string& expected_public_key_blob, bool allow_verification_error,
+ bool rollback_protection, bool is_chained_vbmeta, bool* out_verification_disabled,
+ VBMetaVerifyResult* out_verify_result);
+
+// Loads the top-level vbmeta and all its chained vbmeta images.
+// The actual device path is constructed at runtime by:
+// partition_name, ab_suffix, ab_other_suffix, and device_path_constructor.
+VBMetaVerifyResult LoadAndVerifyVbmetaByPartition(
+ const std::string& partition_name, const std::string& ab_suffix,
+ const std::string& ab_other_suffix, const std::string& expected_public_key_blob,
+ bool allow_verification_error, bool load_chained_vbmeta, bool rollback_protection,
+ std::function<std::string(const std::string&)> device_path_constructor, bool is_chained_vbmeta,
+ std::vector<VBMetaData>* out_vbmeta_images);
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 9f8ad53..a1ae4e7 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -233,10 +233,10 @@
auto device_path = custom_device_path ? custom_device_path : android_by_name_symlink;
- auto verify_result = LoadAndVerifyVbmetaImpl(
- partition_name, ab_suffix, ab_other_suffix, expected_key_blob, allow_verification_error,
- load_chained_vbmeta, rollback_protection, device_path, false,
- /* is_chained_vbmeta */ &avb_handle->vbmeta_images_);
+ auto verify_result = LoadAndVerifyVbmetaByPartition(
+ partition_name, ab_suffix, ab_other_suffix, expected_key_blob, allow_verification_error,
+ load_chained_vbmeta, rollback_protection, device_path, false,
+ /* is_chained_vbmeta */ &avb_handle->vbmeta_images_);
switch (verify_result) {
case VBMetaVerifyResult::kSuccess:
avb_handle->status_ = AvbHandleStatus::kSuccess;
@@ -245,10 +245,16 @@
avb_handle->status_ = AvbHandleStatus::kVerificationError;
break;
default:
- LERROR << "LoadAndVerifyVbmetaImpl failed, result: " << verify_result;
+ LERROR << "LoadAndVerifyVbmetaByPartition failed, result: " << verify_result;
return nullptr;
}
+ // Sanity check here because we have to use vbmeta_images_[0] below.
+ if (avb_handle->vbmeta_images_.size() < 1) {
+ LERROR << "LoadAndVerifyVbmetaByPartition failed, no vbmeta loaded";
+ return nullptr;
+ }
+
// Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
avb_handle->avb_version_ = StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
@@ -377,6 +383,55 @@
return avb_handle;
}
+AvbHashtreeResult AvbHandle::SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
+ bool wait_for_verity_dev) {
+ if (fstab_entry->avb_key.empty()) {
+ LERROR << "avb_key=/path/to/key is missing for " << fstab_entry->mount_point;
+ return AvbHashtreeResult::kFail;
+ }
+
+ // Binds allow_verification_error and rollback_protection to device unlock state.
+ bool allow_verification_error = IsDeviceUnlocked();
+ bool rollback_protection = !allow_verification_error;
+
+ std::string expected_key_blob;
+ if (!ReadFileToString(fstab_entry->avb_key, &expected_key_blob)) {
+ if (!allow_verification_error) {
+ LERROR << "Failed to load avb_key: " << fstab_entry->avb_key
+ << " for mount point: " << fstab_entry->mount_point;
+ return AvbHashtreeResult::kFail;
+ }
+ LWARNING << "Allowing no expected key blob when verification error is permitted";
+ expected_key_blob.clear();
+ }
+
+ bool verification_disabled = false;
+ std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
+ fstab_entry->blk_device, "" /* partition_name, no need for a standalone path */,
+ expected_key_blob, allow_verification_error, rollback_protection,
+ false /* not is_chained_vbmeta */, &verification_disabled, nullptr /* out_verify_result */);
+
+ if (!vbmeta) {
+ LERROR << "Failed to load vbmeta: " << fstab_entry->blk_device;
+ return AvbHashtreeResult::kFail;
+ }
+
+ if (verification_disabled) {
+ LINFO << "AVB verification disabled on: " << fstab_entry->mount_point;
+ return AvbHashtreeResult::kDisabled;
+ }
+
+ // Puts the vbmeta into a vector, for LoadAvbHashtreeToEnableVerity() to use.
+ std::vector<VBMetaData> vbmeta_images;
+ vbmeta_images.emplace_back(std::move(*vbmeta));
+ if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images,
+ fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix())) {
+ return AvbHashtreeResult::kFail;
+ }
+
+ return AvbHashtreeResult::kSuccess;
+}
+
AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev) {
if (!fstab_entry || status_ == AvbHandleStatus::kUninitialized || vbmeta_images_.size() < 1) {
return AvbHashtreeResult::kFail;
@@ -388,33 +443,8 @@
return AvbHashtreeResult::kDisabled;
}
- // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
- // to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
- std::string partition_name;
- if (fstab_entry->fs_mgr_flags.logical) {
- partition_name = fstab_entry->logical_partition_name;
- } else {
- partition_name = Basename(fstab_entry->blk_device);
- }
-
- if (fstab_entry->fs_mgr_flags.slot_select) {
- auto ab_suffix = partition_name.rfind(fs_mgr_get_slot_suffix());
- if (ab_suffix != std::string::npos) {
- partition_name.erase(ab_suffix);
- }
- }
-
- AvbHashtreeDescriptor hashtree_descriptor;
- std::string salt;
- std::string root_digest;
- if (!GetHashtreeDescriptor(partition_name, vbmeta_images_, &hashtree_descriptor, &salt,
- &root_digest)) {
- return AvbHashtreeResult::kFail;
- }
-
- // Converts HASHTREE descriptor to verity_table_params.
- if (!HashtreeDmVeritySetup(fstab_entry, hashtree_descriptor, salt, root_digest,
- wait_for_verity_dev)) {
+ if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images_,
+ fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix())) {
return AvbHashtreeResult::kFail;
}
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 7af3c7e..d4e3a6e 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -81,8 +81,15 @@
// true to update vbmeta_size_ to the actual size with valid content.
std::unique_ptr<AvbVBMetaImageHeader> GetVBMetaHeader(bool update_vbmeta_size = false);
+ // Sets the vbmeta_path where we load the vbmeta data. Could be a partition or a file.
+ // e.g.,
+ // - /dev/block/by-name/system_a
+ // - /path/to/system_other.img.
+ void set_vbmeta_path(std::string vbmeta_path) { vbmeta_path_ = std::move(vbmeta_path); }
+
// Get methods for each data member.
const std::string& partition() const { return partition_name_; }
+ const std::string& vbmeta_path() const { return vbmeta_path_; }
uint8_t* data() const { return vbmeta_ptr_.get(); }
const size_t& size() const { return vbmeta_size_; }
@@ -93,6 +100,7 @@
std::unique_ptr<uint8_t[]> vbmeta_ptr_;
size_t vbmeta_size_;
std::string partition_name_;
+ std::string vbmeta_path_;
};
class FsManagerAvbOps;
@@ -160,6 +168,10 @@
// - kDisabled: hashtree is disabled.
AvbHashtreeResult SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev);
+ // Similar to above, but loads the offline vbmeta from the end of fstab_entry->blk_device.
+ static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
+ bool wait_for_verity_dev = true);
+
const std::string& avb_version() const { return avb_version_; }
const VBMetaInfo& vbmeta_info() const { return vbmeta_info_; }
AvbHandleStatus status() const { return status_; }
diff --git a/fs_mgr/libfs_avb/tests/avb_util_test.cpp b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
index 26b3294..23faffc 100644
--- a/fs_mgr/libfs_avb/tests/avb_util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
@@ -14,20 +14,25 @@
* limitations under the License.
*/
+#include <endian.h>
+
#include <android-base/unique_fd.h>
#include <base/files/file_util.h>
#include <base/rand_util.h>
#include <base/strings/string_util.h>
+#include <libavb/libavb.h>
#include "avb_util.h"
#include "fs_avb_test_util.h"
// Target classes or functions to test:
using android::fs_mgr::AvbPartitionToDevicePatition;
+using android::fs_mgr::DeriveAvbPartitionName;
using android::fs_mgr::GetAvbFooter;
using android::fs_mgr::GetChainPartitionInfo;
using android::fs_mgr::GetTotalSize;
-using android::fs_mgr::LoadAndVerifyVbmetaImpl;
+using android::fs_mgr::LoadAndVerifyVbmetaByPartition;
+using android::fs_mgr::LoadAndVerifyVbmetaByPath;
using android::fs_mgr::VBMetaData;
using android::fs_mgr::VBMetaVerifyResult;
using android::fs_mgr::VerifyPublicKeyBlob;
@@ -52,8 +57,34 @@
// Loads the content of avb_image_path and comparies it with the content of vbmeta.
bool CompareVBMeta(const base::FilePath& avb_image_path, const VBMetaData& expected_vbmeta);
+
+ // Sets the flas in vbmeta header, the image_path could be a vbmeta.img or a system.img.
+ void SetVBMetaFlags(const base::FilePath& image_path, uint32_t flags);
};
+void AvbUtilTest::SetVBMetaFlags(const base::FilePath& image_path, uint32_t flags) {
+ if (!base::PathExists(image_path)) return;
+
+ std::string image_file_name = image_path.RemoveExtension().BaseName().value();
+ bool is_vbmeta_partition =
+ base::StartsWith(image_file_name, "vbmeta", base::CompareCase::INSENSITIVE_ASCII);
+
+ android::base::unique_fd fd(open(image_path.value().c_str(), O_RDWR | O_CLOEXEC));
+ EXPECT_TRUE(fd > 0);
+
+ uint64_t vbmeta_offset = 0; // for vbmeta.img
+ if (!is_vbmeta_partition) {
+ std::unique_ptr<AvbFooter> footer = GetAvbFooter(fd);
+ EXPECT_NE(nullptr, footer);
+ vbmeta_offset = footer->vbmeta_offset;
+ }
+
+ auto flags_offset = vbmeta_offset + offsetof(AvbVBMetaImageHeader, flags);
+ uint32_t flags_data = htobe32(flags);
+ EXPECT_EQ(flags_offset, lseek64(fd, flags_offset, SEEK_SET));
+ EXPECT_EQ(sizeof flags_data, write(fd, &flags_data, sizeof flags_data));
+}
+
TEST_F(AvbUtilTest, AvbPartitionToDevicePatition) {
EXPECT_EQ("system", AvbPartitionToDevicePatition("system", "", ""));
EXPECT_EQ("system", AvbPartitionToDevicePatition("system", "", "_b"));
@@ -65,6 +96,63 @@
EXPECT_EQ("system_b", AvbPartitionToDevicePatition("system_other", "_a", "_b"));
}
+TEST_F(AvbUtilTest, DeriveAvbPartitionName) {
+ // The fstab_entry to test.
+ FstabEntry fstab_entry = {
+ .blk_device = "/dev/block/dm-1", // a dm-linear device (logical)
+ .mount_point = "/system",
+ .fs_type = "ext4",
+ .logical_partition_name = "system",
+ };
+
+ // Logical partitions.
+ // non-A/B
+ fstab_entry.fs_mgr_flags.logical = true;
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_dont_care"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "", ""));
+ // Active slot.
+ fstab_entry.fs_mgr_flags.slot_select = true;
+ fstab_entry.logical_partition_name = "system_a";
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_dont_care"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", ""));
+ EXPECT_EQ("system_a", DeriveAvbPartitionName(fstab_entry, "_wont_erase_a", "_dont_care"));
+ // The other slot.
+ fstab_entry.fs_mgr_flags.slot_select = false;
+ fstab_entry.fs_mgr_flags.slot_select_other = true;
+ fstab_entry.logical_partition_name = "system_b";
+ EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_b"));
+ EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
+ EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "", "_b"));
+ EXPECT_EQ("system_b_other", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_wont_erase_b"));
+
+ // Non-logical partitions.
+ // non-A/B.
+ fstab_entry.fs_mgr_flags.logical = false;
+ fstab_entry.fs_mgr_flags.slot_select = false;
+ fstab_entry.fs_mgr_flags.slot_select_other = false;
+ fstab_entry.blk_device = "/dev/block/by-name/system";
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_dont_care", "_dont_care"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "", ""));
+ // Active slot _a.
+ fstab_entry.fs_mgr_flags.slot_select = true;
+ fstab_entry.blk_device = "/dev/block/by-name/system_a";
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_dont_care"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
+ EXPECT_EQ("system", DeriveAvbPartitionName(fstab_entry, "_a", ""));
+ EXPECT_EQ("system_a", DeriveAvbPartitionName(fstab_entry, "_wont_erase_a", "_dont_care"));
+ // Inactive slot _b.
+ fstab_entry.fs_mgr_flags.slot_select = false;
+ fstab_entry.fs_mgr_flags.slot_select_other = true;
+ fstab_entry.blk_device = "/dev/block/by-name/system_b";
+ EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "dont_care", "_b"));
+ EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "_a", "_b"));
+ EXPECT_EQ("system_other", DeriveAvbPartitionName(fstab_entry, "", "_b"));
+ EXPECT_EQ("system_b_other", DeriveAvbPartitionName(fstab_entry, "dont_care", "_wont_erase_b"));
+}
+
TEST_F(AvbUtilTest, GetFdTotalSize) {
// Generates a raw test.img via BaseFsAvbTest.
const size_t image_size = 5 * 1024 * 1024;
@@ -751,7 +839,213 @@
EXPECT_EQ(false, fatal_error);
}
-TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImpl) {
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPath) {
+ // Generates a raw system_other.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
+
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
+ 20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ std::string expected_key_blob_4096;
+ EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
+
+ bool verification_disabled;
+ VBMetaVerifyResult verify_result;
+ std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ false /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, &verification_disabled, &verify_result);
+
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess, verify_result);
+ EXPECT_EQ(false, verification_disabled);
+
+ EXPECT_EQ(2112UL, vbmeta->size());
+ EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
+ EXPECT_EQ("system_other", vbmeta->partition());
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPathErrorVerification) {
+ // Generates a raw system_other.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
+
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
+ 20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ std::string expected_key_blob_4096;
+ EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
+
+ // Modifies the auxiliary data of system_other.img
+ auto fd = OpenUniqueReadFd(system_path);
+ auto system_footer = GetAvbFooter(fd);
+ auto system_vbmeta = ExtractAndLoadVBMetaData(system_path, "system_other-vbmeta.img");
+ auto system_header = system_vbmeta.GetVBMetaHeader(true /* update_vbmeta_size */);
+ size_t header_block_offset = 0;
+ size_t authentication_block_offset = header_block_offset + sizeof(AvbVBMetaImageHeader);
+ size_t auxiliary_block_offset =
+ authentication_block_offset + system_header->authentication_data_block_size;
+
+ // Modifies the hash.
+ ModifyFile(
+ system_path,
+ (system_footer->vbmeta_offset + authentication_block_offset + system_header->hash_offset),
+ system_header->hash_size);
+
+ VBMetaVerifyResult verify_result;
+ // Not allow verification error.
+ std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ false /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, nullptr /* verification_disabled */, &verify_result);
+ EXPECT_EQ(nullptr, vbmeta);
+
+ // Allow verification error.
+ vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ true /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, nullptr /* verification_disabled */, &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
+
+ EXPECT_EQ(2112UL, vbmeta->size());
+ EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
+ EXPECT_EQ("system_other", vbmeta->partition());
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+
+ // Modifies the auxiliary data block.
+ ModifyFile(system_path, system_footer->vbmeta_offset + auxiliary_block_offset,
+ system_header->auxiliary_data_block_size);
+
+ // Not allow verification error.
+ vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ false /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, nullptr /* verification_disabled */, &verify_result);
+ EXPECT_EQ(nullptr, vbmeta);
+
+ // Allow verification error.
+ vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ true /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, nullptr /* verification_disabled */, &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPathUnexpectedPublicKey) {
+ // Generates a raw system_other.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
+
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
+ 20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ std::string expected_key_blob_4096;
+ EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
+ std::string unexpected_key_blob_2048;
+ EXPECT_TRUE(base::ReadFileToString(rsa2048_public_key, &unexpected_key_blob_2048));
+
+ // Uses the correct expected public key.
+ VBMetaVerifyResult verify_result;
+ std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ false /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, nullptr /* verification_disabled */, &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_EQ(verify_result, VBMetaVerifyResult::kSuccess);
+ EXPECT_EQ(2112UL, vbmeta->size());
+ EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
+ EXPECT_EQ("system_other", vbmeta->partition());
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+
+ // Uses the wrong expected public key with allow_verification_error set to false.
+ vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", unexpected_key_blob_2048,
+ false /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, nullptr /* verification_disabled */, &verify_result);
+ EXPECT_EQ(nullptr, vbmeta);
+
+ // Uses the wrong expected public key with allow_verification_error set to true.
+ vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", unexpected_key_blob_2048,
+ true /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, nullptr /* verification_disabled */, &verify_result);
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_EQ(verify_result, VBMetaVerifyResult::kErrorVerification);
+ EXPECT_EQ(2112UL, vbmeta->size());
+ EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
+ EXPECT_EQ("system_other", vbmeta->partition());
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPathVerificationDisabled) {
+ // Generates a raw system_other.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system_other.img", system_image_size);
+
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system_other", system_partition_size, "SHA512_RSA4096",
+ 20, data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+
+ std::string expected_key_blob_4096;
+ EXPECT_TRUE(base::ReadFileToString(rsa4096_public_key, &expected_key_blob_4096));
+
+ // Sets disabled flag and expect the returned verification_disabled is true.
+ SetVBMetaFlags(system_path, AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+ bool verification_disabled;
+ VBMetaVerifyResult verify_result;
+ std::unique_ptr<VBMetaData> vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ true /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, &verification_disabled, &verify_result);
+
+ EXPECT_NE(nullptr, vbmeta);
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification, verify_result);
+ EXPECT_EQ(true, verification_disabled); // should be true.
+
+ EXPECT_EQ(2112UL, vbmeta->size());
+ EXPECT_EQ(system_path.value(), vbmeta->vbmeta_path());
+ EXPECT_EQ("system_other", vbmeta->partition());
+ EXPECT_TRUE(CompareVBMeta(system_path, *vbmeta));
+
+ // Since the vbmeta flags is modified, vbmeta will be nullptr
+ // if verification error isn't allowed.
+ vbmeta = LoadAndVerifyVbmetaByPath(
+ system_path.value(), "system_other", expected_key_blob_4096,
+ false /* allow_verification_error */, false /* rollback_protection */,
+ false /* is_chained_vbmeta */, &verification_disabled, &verify_result);
+ EXPECT_EQ(nullptr, vbmeta);
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartition) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
@@ -795,18 +1089,18 @@
EXPECT_EQ("6f4bf815a651aa35ec7102a88b7906b91aef284bc5e20d0bf527c7d460da3266",
CalcVBMetaDigest("vbmeta.img", "sha256"));
- // Starts to test LoadAndVerifyVbmetaImpl.
+ // Starts to test LoadAndVerifyVbmetaByPartition.
std::vector<VBMetaData> vbmeta_images;
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- "" /* expected_public_key_blob*/, false /* allow_verification_error */,
- true /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot, vbmeta_system and system
// Binary comparison for each vbmeta image.
@@ -818,17 +1112,17 @@
// Skip loading chained vbmeta images.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- "" /* expected_public_key_blob*/, false /* allow_verification_error */,
- false /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Only vbmeta is loaded.
EXPECT_EQ(1UL, vbmeta_images.size());
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
}
-TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImplWithSuffixes) {
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionWithSuffixes) {
// Tests the following chained partitions.
// vbmeta_a.img
// |--> boot_b.img (boot_other)
@@ -874,18 +1168,18 @@
{"vbmeta_system_other", 2, rsa4096_public_key}},
"--internal_release_string \"unit test\"");
- // Starts to test LoadAndVerifyVbmetaImpl with ab_suffix and ab_other_suffix.
+ // Starts to test LoadAndVerifyVbmetaByPartition with ab_suffix and ab_other_suffix.
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
std::vector<VBMetaData> vbmeta_images;
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
- "" /* expected_public_key_blob*/, false /* allow_verification_error */,
- true /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot_other, vbmeta_system_other and system
// Binary comparison for each vbmeta image.
@@ -897,26 +1191,26 @@
// Skips loading chained vbmeta images.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
- "" /* expected_public_key_blob*/, false /* allow_verification_error */,
- false /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "_a" /* ab_suffix */, "_b" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Only vbmeta is loaded.
EXPECT_EQ(1UL, vbmeta_images.size());
EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
// Using an invalid suffix for 'other' slot, checks it returns error.
EXPECT_EQ(VBMetaVerifyResult::kError,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "_a" /* ab_suffix */,
- "_invalid_suffix" /* other_suffix */, "" /* expected_public_key_blob*/,
- false /* allow_verification_error */, true /* load_chained_vbmeta */,
- true /* rollback_protection */, vbmeta_image_path,
- false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "_a" /* ab_suffix */,
+ "_invalid_suffix" /* other_suffix */, "" /* expected_public_key_blob*/,
+ false /* allow_verification_error */, true /* load_chained_vbmeta */,
+ true /* rollback_protection */, vbmeta_image_path, false /* is_chained_vbmeta*/,
+ &vbmeta_images));
}
-TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImplErrorVerification) {
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionErrorVerification) {
// Generates a raw boot.img
const size_t boot_image_size = 5 * 1024 * 1024;
const size_t boot_partition_size = 10 * 1024 * 1024;
@@ -964,27 +1258,27 @@
// Modifies the hash.
ModifyFile(vbmeta_path, authentication_block_offset + header->hash_offset, header->hash_size);
- // Starts to test LoadAndVerifyVbmetaImpl.
+ // Starts to test LoadAndVerifyVbmetaByPartition.
std::vector<VBMetaData> vbmeta_images;
auto vbmeta_image_path = [this](const std::string& partition_name) {
return test_dir_.Append(partition_name + ".img").value();
};
EXPECT_EQ(VBMetaVerifyResult::kError,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- "" /* expected_public_key_blob*/, false /* allow_verification_error */,
- true /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
// Stops to load vbmeta because the top-level vbmeta has verification error.
EXPECT_EQ(0UL, vbmeta_images.size());
// Tries again with verification error allowed.
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "", /* other_suffix */
- "" /* expected_public_key_blob*/, true /* allow_verification_error */,
- true /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "", /* other_suffix */
+ "" /* expected_public_key_blob*/, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
EXPECT_EQ(3UL, vbmeta_images.size()); // vbmeta, boot, and system
// Binary comparison for each vbmeta image.
@@ -1008,11 +1302,11 @@
system_header->auxiliary_data_block_size);
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kError,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- "" /* expected_public_key_blob*/, false /* allow_verification_error */,
- true /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
// 'vbmeta', 'boot' but no 'system', because of verification error.
EXPECT_EQ(2UL, vbmeta_images.size());
// Binary comparison for the loaded 'vbmeta' and 'boot'.
@@ -1020,20 +1314,113 @@
EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
// Resets the modification of the auxiliary data.
- ModifyFile(vbmeta_path, 0 /* offset */, -1 /* length */);
+ ModifyFile(system_path, 0 /* offset */, -1 /* length */);
// Sets the vbmeta header flags on a chained partition, which introduces an error.
ModifyFile(system_path, system_footer->vbmeta_offset + offsetof(AvbVBMetaImageHeader, flags),
sizeof(uint32_t));
EXPECT_EQ(VBMetaVerifyResult::kError,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- "" /* expected_public_key_blob*/, true /* allow_verification_error */,
- true /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
}
-TEST_F(AvbUtilTest, LoadAndVerifyVbmetaImplUnexpectedPublicKey) {
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionVerificationDisabled) {
+ // Generates a raw boot.img
+ const size_t boot_image_size = 5 * 1024 * 1024;
+ const size_t boot_partition_size = 10 * 1024 * 1024;
+ base::FilePath boot_path = GenerateImage("boot.img", boot_image_size);
+
+ // Adds AVB Hash Footer.
+ AddAvbFooter(boot_path, "hash", "boot", boot_partition_size, "SHA256_RSA2048", 10,
+ data_dir_.Append("testkey_rsa2048.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates a raw system.img, use a smaller size to speed-up unit test.
+ const size_t system_image_size = 10 * 1024 * 1024;
+ const size_t system_partition_size = 15 * 1024 * 1024;
+ base::FilePath system_path = GenerateImage("system.img", system_image_size);
+ // Adds AVB Hashtree Footer.
+ AddAvbFooter(system_path, "hashtree", "system", system_partition_size, "SHA512_RSA4096", 20,
+ data_dir_.Append("testkey_rsa4096.pem"), "d00df00d",
+ "--internal_release_string \"unit test\"");
+
+ // Generates chain partition descriptors.
+ base::FilePath rsa2048_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
+ base::FilePath rsa4096_public_key =
+ ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa4096.pem"));
+ // Makes a vbmeta_system.img including the 'system' chained descriptor.
+ auto vbmeta_system_path = GenerateVBMetaImage(
+ "vbmeta_system.img", "SHA256_RSA4096", 0, data_dir_.Append("testkey_rsa4096.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"system", 3, rsa4096_public_key}}, /* chain_partitions */
+ "--internal_release_string \"unit test\"");
+
+ // Makes a vbmeta image includeing 'boot' and 'vbmeta_system' chained descriptors.
+ auto vbmeta_path = GenerateVBMetaImage("vbmeta.img", "SHA256_RSA8192", 0,
+ data_dir_.Append("testkey_rsa8192.pem"),
+ {}, /* include_descriptor_image_paths */
+ {{"boot", 1, rsa2048_public_key}, /* chain_partitions */
+ {"vbmeta_system", 2, rsa4096_public_key}},
+ "--internal_release_string \"unit test\"");
+
+ // Calculates the digest of all chained partitions, to ensure the chained is formed properly.
+ EXPECT_EQ("6f4bf815a651aa35ec7102a88b7906b91aef284bc5e20d0bf527c7d460da3266",
+ CalcVBMetaDigest("vbmeta.img", "sha256"));
+
+ // Starts to test LoadAndVerifyVbmetaByPartition.
+ std::vector<VBMetaData> vbmeta_images;
+ auto vbmeta_image_path = [this](const std::string& partition_name) {
+ return test_dir_.Append(partition_name + ".img").value();
+ };
+
+ EXPECT_EQ(VBMetaVerifyResult::kSuccess,
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, false /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
+
+ EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot, vbmeta_system and system
+ // Binary comparison for each vbmeta image.
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+ EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
+ EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
+ EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
+
+ // Sets VERIFICATION_DISABLED to the top-level vbmeta.img
+ SetVBMetaFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+ vbmeta_images.clear();
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
+ EXPECT_EQ(1UL, vbmeta_images.size()); // Only vbmeta is loaded
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+
+ // HASHTREE_DISABLED still loads the chained vbmeta.
+ SetVBMetaFlags(vbmeta_path, AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+ vbmeta_images.clear();
+ EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ "" /* expected_public_key_blob*/, true /* allow_verification_error */,
+ true /* load_chained_vbmeta */, true /* rollback_protection */, vbmeta_image_path,
+ false /* is_chained_vbmeta*/, &vbmeta_images));
+ EXPECT_EQ(4UL, vbmeta_images.size()); // vbmeta, boot, vbmeta_system and system
+ // Binary comparison for each vbmeta image.
+ EXPECT_TRUE(CompareVBMeta(vbmeta_path, vbmeta_images[0]));
+ EXPECT_TRUE(CompareVBMeta(boot_path, vbmeta_images[1]));
+ EXPECT_TRUE(CompareVBMeta(vbmeta_system_path, vbmeta_images[2]));
+ EXPECT_TRUE(CompareVBMeta(system_path, vbmeta_images[3]));
+}
+
+TEST_F(AvbUtilTest, LoadAndVerifyVbmetaByPartitionUnexpectedPublicKey) {
// Generates chain partition descriptors.
base::FilePath rsa2048_public_key =
ExtractPublicKeyAvb(data_dir_.Append("testkey_rsa2048.pem"));
@@ -1060,29 +1447,29 @@
std::vector<VBMetaData> vbmeta_images;
// Uses the correct expected public key.
EXPECT_EQ(VBMetaVerifyResult::kSuccess,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- expected_key_blob_8192, true /* allow_verification_error */,
- false /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ expected_key_blob_8192, true /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Uses the wrong expected public key with allow_verification_error set to true.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kErrorVerification,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- expected_key_blob_4096, true /* allow_verification_error */,
- false /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ expected_key_blob_4096, true /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
// Uses the wrong expected public key with allow_verification_error set to false.
vbmeta_images.clear();
EXPECT_EQ(VBMetaVerifyResult::kError,
- LoadAndVerifyVbmetaImpl(
- "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
- expected_key_blob_4096, false /* allow_verification_error */,
- false /* load_chained_vbmeta */, true /* rollback_protection */,
- vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
+ LoadAndVerifyVbmetaByPartition(
+ "vbmeta" /* partition_name */, "" /* ab_suffix */, "" /* other_suffix */,
+ expected_key_blob_4096, false /* allow_verification_error */,
+ false /* load_chained_vbmeta */, true /* rollback_protection */,
+ vbmeta_image_path, false /* is_chained_vbmeta*/, &vbmeta_images));
}
} // namespace fs_avb_host_test
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index ede0122..4d9bc61 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -569,6 +569,18 @@
die "vendor hello"
check_eq "${A}" "${B}" /vendor before reboot
+# download libc.so, append some gargage, push back, and check if the file is updated.
+tempdir="`mktemp -d`"
+cleanup() {
+ rm -rf ${tempdir}
+}
+adb pull /system/lib/bootstrap/libc.so ${tempdir} || die "pull libc.so from device"
+garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`"
+echo ${garbage} >> ${tempdir}/libc.so
+adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so || die "push libc.so to device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || die "pull libc.so from device"
+diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
+
echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2
adb_reboot &&
@@ -607,6 +619,14 @@
check_eq "${A}" "${B}" vendor after reboot
echo "${GREEN}[ OK ]${NORMAL} /vendor content remains after reboot" >&2
+# check if the updated libc.so is persistent after reboot
+adb_root &&
+ adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice ||
+ die "pull libc.so from device"
+diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
+rm -r ${tempdir}
+echo "${GREEN}[ OK ]${NORMAL} /system/lib/bootstrap/libc.so content remains after reboot" >&2
+
echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 3b6ff9b..63661f0 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -27,6 +27,7 @@
#include <android-base/unique_fd.h>
#include <libdm/dm.h>
+#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
@@ -50,6 +51,7 @@
static int Usage(void) {
std::cerr << "usage: dmctl <command> [command options]" << std::endl;
+ std::cerr << " dmctl -f file" << std::endl;
std::cerr << "commands:" << std::endl;
std::cerr << " create <dm-name> [-ro] <targets...>" << std::endl;
std::cerr << " delete <dm-name>" << std::endl;
@@ -58,6 +60,8 @@
std::cerr << " table <dm-name>" << std::endl;
std::cerr << " help" << std::endl;
std::cerr << std::endl;
+ std::cerr << "-f file reads command and all parameters from named file" << std::endl;
+ std::cerr << std::endl;
std::cerr << "Target syntax:" << std::endl;
std::cerr << " <target_type> <start_sector> <num_sectors> [target_data]" << std::endl;
return -EINVAL;
@@ -340,12 +344,40 @@
// clang-format on
};
+static bool ReadFile(const char* filename, std::vector<std::string>* args,
+ std::vector<char*>* arg_ptrs) {
+ std::ifstream file(filename);
+ if (!file) return false;
+
+ std::string arg;
+ while (file >> arg) args->push_back(arg);
+
+ for (auto const& i : *args) arg_ptrs->push_back(const_cast<char*>(i.c_str()));
+ return true;
+}
+
int main(int argc, char** argv) {
android::base::InitLogging(argv, &android::base::StderrLogger);
if (argc < 2) {
return Usage();
}
+ std::vector<std::string> args;
+ std::vector<char*> arg_ptrs;
+ if (std::string("-f") == argv[1]) {
+ if (argc != 3) {
+ return Usage();
+ }
+
+ args.push_back(argv[0]);
+ if (!ReadFile(argv[2], &args, &arg_ptrs)) {
+ return Usage();
+ }
+
+ argc = arg_ptrs.size();
+ argv = &arg_ptrs[0];
+ }
+
for (const auto& cmd : cmdmap) {
if (cmd.first == argv[1]) {
return cmd.second(argc - 2, argv + 2);
diff --git a/healthd/OWNERS b/healthd/OWNERS
index 00df08a..d3f8758 100644
--- a/healthd/OWNERS
+++ b/healthd/OWNERS
@@ -1,2 +1,2 @@
elsk@google.com
-toddpoynor@google.com
+hridya@google.com
diff --git a/init/Android.bp b/init/Android.bp
index 9f5d17d..67688f2 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -110,6 +110,7 @@
"init.cpp",
"keychords.cpp",
"modalias_handler.cpp",
+ "mount_namespace.cpp",
"parser.cpp",
"persistent_properties.cpp",
"persistent_properties.proto",
@@ -166,6 +167,7 @@
exclude_shared_libs: ["libbinder", "libutils"],
},
},
+ ldflags: ["-Wl,--rpath,/system/${LIB}/bootstrap"],
}
// Tests
diff --git a/init/Android.mk b/init/Android.mk
index 69c63e1..59d7f11 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -47,6 +47,7 @@
first_stage_init.cpp \
first_stage_main.cpp \
first_stage_mount.cpp \
+ mount_namespace.cpp \
reboot_utils.cpp \
selinux.cpp \
switch_root.cpp \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 169edbe..b41b035 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -63,6 +63,7 @@
#include "action_manager.h"
#include "bootchart.h"
#include "init.h"
+#include "mount_namespace.h"
#include "parser.h"
#include "property_service.h"
#include "reboot.h"
@@ -1098,6 +1099,14 @@
}
}
+static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
+ if (SwitchToDefaultMountNamespace()) {
+ return Success();
+ } else {
+ return Error() << "Failed to setup runtime bionic";
+ }
+}
+
// Builtin-function-map start
const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1145,6 +1154,7 @@
{"rmdir", {1, 1, {true, do_rmdir}}},
{"setprop", {2, 2, {true, do_setprop}}},
{"setrlimit", {3, 3, {false, do_setrlimit}}},
+ {"setup_runtime_bionic", {0, 0, {false, do_setup_runtime_bionic}}},
{"start", {1, 1, {false, do_start}}},
{"stop", {1, 1, {false, do_stop}}},
{"swapon_all", {1, 1, {false, do_swapon_all}}},
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 153b857..79536e4 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -136,10 +136,6 @@
return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
}
-static bool IsRecoveryMode() {
- return access("/system/bin/recovery", F_OK) == 0;
-}
-
static Fstab ReadFirstStageFstab() {
Fstab fstab;
if (!ReadFstabFromDt(&fstab)) {
@@ -683,22 +679,31 @@
}
bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
+ AvbHashtreeResult hashtree_result;
+
if (fstab_entry->fs_mgr_flags.avb) {
if (!InitAvbHandle()) return false;
- AvbHashtreeResult hashtree_result =
+ hashtree_result =
avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
- switch (hashtree_result) {
- case AvbHashtreeResult::kDisabled:
- return true; // Returns true to mount the partition.
- case AvbHashtreeResult::kSuccess:
- // The exact block device name (fstab_rec->blk_device) is changed to
- // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
- // first stage.
- return InitMappedDevice(fstab_entry->blk_device);
- default:
- return false;
- }
+ } else if (!fstab_entry->avb_key.empty()) {
+ hashtree_result =
+ AvbHandle::SetUpStandaloneAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
+ } else {
+ return true; // No need AVB, returns true to mount the partition directly.
}
+
+ switch (hashtree_result) {
+ case AvbHashtreeResult::kDisabled:
+ return true; // Returns true to mount the partition.
+ case AvbHashtreeResult::kSuccess:
+ // The exact block device name (fstab_rec->blk_device) is changed to
+ // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
+ // first stage.
+ return InitMappedDevice(fstab_entry->blk_device);
+ default:
+ return false;
+ }
+
return true; // Returns true to mount the partition.
}
diff --git a/init/init.cpp b/init/init.cpp
index d360fdd..4f4a15f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -54,6 +54,7 @@
#include "first_stage_mount.h"
#include "import_parser.h"
#include "keychords.h"
+#include "mount_namespace.h"
#include "property_service.h"
#include "reboot.h"
#include "reboot_utils.h"
@@ -666,6 +667,10 @@
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
+ if (!SetupMountNamespaces()) {
+ PLOG(FATAL) << "SetupMountNamespaces failed";
+ }
+
subcontexts = InitializeSubcontexts();
ActionManager& am = ActionManager::GetInstance();
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
new file mode 100644
index 0000000..413fe8f
--- /dev/null
+++ b/init/mount_namespace.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2019 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 "mount_namespace.h"
+
+#include <sys/mount.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+
+#include "util.h"
+
+namespace android {
+namespace init {
+namespace {
+
+static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker";
+static constexpr const char* kBootstrapLinkerPath = "/system/bin/bootstrap/linker";
+static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
+
+static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/";
+static constexpr const char* kBootstrapBionicLibsDir = "/system/lib/bootstrap/";
+static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
+
+static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64";
+static constexpr const char* kBootstrapLinkerPath64 = "/system/bin/bootstrap/linker64";
+static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
+
+static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/";
+static constexpr const char* kBootstrapBionicLibsDir64 = "/system/lib64/bootstrap/";
+static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
+
+static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
+
+static bool BindMount(const std::string& source, const std::string& mount_point,
+ bool recursive = false) {
+ unsigned long mountflags = MS_BIND;
+ if (recursive) {
+ mountflags |= MS_REC;
+ }
+ if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+ PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point;
+ return false;
+ }
+ return true;
+}
+
+static bool MakeShared(const std::string& mount_point, bool recursive = false) {
+ unsigned long mountflags = MS_SHARED;
+ if (recursive) {
+ mountflags |= MS_REC;
+ }
+ if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+ PLOG(ERROR) << "Failed to change propagation type to shared";
+ return false;
+ }
+ return true;
+}
+
+static bool MakePrivate(const std::string& mount_point, bool recursive = false) {
+ unsigned long mountflags = MS_PRIVATE;
+ if (recursive) {
+ mountflags |= MS_REC;
+ }
+ if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+ PLOG(ERROR) << "Failed to change propagation type to private";
+ return false;
+ }
+ return true;
+}
+
+static int OpenMountNamespace() {
+ int fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ PLOG(ERROR) << "Cannot open fd for current mount namespace";
+ }
+ return fd;
+}
+
+static std::string GetMountNamespaceId() {
+ std::string ret;
+ if (!android::base::Readlink("/proc/self/ns/mnt", &ret)) {
+ PLOG(ERROR) << "Failed to read namespace ID";
+ return "";
+ }
+ return ret;
+}
+
+static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source,
+ const std::string& linker_mount_point,
+ const std::string& lib_mount_dir) {
+ if (access(linker_source.c_str(), F_OK) != 0) {
+ PLOG(INFO) << linker_source << " does not exist. skipping mounting bionic there.";
+ // This can happen for 64-bit bionic in 32-bit only device.
+ // It is okay to skip mounting the 64-bit bionic.
+ return true;
+ }
+ if (!BindMount(linker_source, linker_mount_point)) {
+ return false;
+ }
+ if (!MakePrivate(linker_mount_point)) {
+ return false;
+ }
+ for (const auto& libname : kBionicLibFileNames) {
+ std::string mount_point = lib_mount_dir + libname;
+ std::string source = lib_dir_source + libname;
+ if (!BindMount(source, mount_point)) {
+ return false;
+ }
+ if (!MakePrivate(mount_point)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool IsBionicUpdatable() {
+ static bool result = android::base::GetBoolProperty("ro.apex.IsBionicUpdatable", false);
+ return result;
+}
+
+static android::base::unique_fd bootstrap_ns_fd;
+static android::base::unique_fd default_ns_fd;
+
+static std::string bootstrap_ns_id;
+static std::string default_ns_id;
+
+} // namespace
+
+bool SetupMountNamespaces() {
+ // Set the propagation type of / as shared so that any mounting event (e.g.
+ // /data) is by default visible to all processes. When private mounting is
+ // needed for /foo/bar, then we will make /foo/bar as a mount point (by
+ // bind-mounting by to itself) and set the propagation type of the mount
+ // point to private.
+ if (!MakeShared("/", true /*recursive*/)) return false;
+
+ // Since different files (bootstrap or runtime APEX) should be mounted to
+ // the same mount point paths (e.g. /bionic/bin/linker, /bionic/lib/libc.so,
+ // etc.) across the two mount namespaces, we create a private mount point at
+ // /bionic so that a mount event for the bootstrap bionic in the mount
+ // namespace for pre-apexd processes is not propagated to the other mount
+ // namespace for post-apexd process, and vice versa.
+ //
+ // Other mount points other than /bionic, however, are all still shared.
+ if (!BindMount("/bionic", "/bionic", true /*recursive*/)) return false;
+ if (!MakePrivate("/bionic")) return false;
+
+ // Bind-mount bootstrap bionic.
+ if (!BindMountBionic(kBootstrapLinkerPath, kBootstrapBionicLibsDir, kLinkerMountPoint,
+ kBionicLibsMountPointDir))
+ return false;
+ if (!BindMountBionic(kBootstrapLinkerPath64, kBootstrapBionicLibsDir64, kLinkerMountPoint64,
+ kBionicLibsMountPointDir64))
+ return false;
+
+ bootstrap_ns_fd.reset(OpenMountNamespace());
+ bootstrap_ns_id = GetMountNamespaceId();
+
+ // When bionic is updatable via the runtime APEX, we create separate mount
+ // namespaces for processes that are started before and after the APEX is
+ // activated by apexd. In the namespace for pre-apexd processes, the bionic
+ // from the /system partition (that we call bootstrap bionic) is
+ // bind-mounted. In the namespace for post-apexd processes, the bionic from
+ // the runtime APEX is bind-mounted.
+ bool success = true;
+ if (IsBionicUpdatable() && !IsRecoveryMode()) {
+ // Creating a new namespace by cloning, saving, and switching back to
+ // the original namespace.
+ if (unshare(CLONE_NEWNS) == -1) {
+ PLOG(ERROR) << "Cannot create mount namespace";
+ return false;
+ }
+ default_ns_fd.reset(OpenMountNamespace());
+ default_ns_id = GetMountNamespaceId();
+
+ // By this unmount, the bootstrap bionic are not mounted in the default
+ // mount namespace.
+ if (umount2("/bionic", MNT_DETACH) == -1) {
+ PLOG(ERROR) << "Cannot unmount /bionic";
+ // Don't return here. We have to switch back to the bootstrap
+ // namespace.
+ success = false;
+ }
+
+ if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
+ PLOG(ERROR) << "Cannot switch back to bootstrap mount namespace";
+ return false;
+ }
+ } else {
+ // Otherwise, default == bootstrap
+ default_ns_fd.reset(OpenMountNamespace());
+ default_ns_id = GetMountNamespaceId();
+ }
+
+ LOG(INFO) << "SetupMountNamespaces done";
+ return success;
+}
+
+bool SwitchToDefaultMountNamespace() {
+ if (IsRecoveryMode()) {
+ // we don't have multiple namespaces in recovery mode
+ return true;
+ }
+ if (default_ns_id != GetMountNamespaceId()) {
+ if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
+ PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
+ return false;
+ }
+ }
+
+ // Bind-mount bionic from the runtime APEX since it is now available. Note
+ // that in case of IsBionicUpdatable() == false, these mounts are over the
+ // existing existing bind mounts for the bootstrap bionic, which effectively
+ // becomes hidden.
+ if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint,
+ kBionicLibsMountPointDir))
+ return false;
+ if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64,
+ kBionicLibsMountPointDir64))
+ return false;
+
+ LOG(INFO) << "Switched to default mount namespace";
+ return true;
+}
+
+bool SwitchToBootstrapMountNamespaceIfNeeded() {
+ if (IsRecoveryMode()) {
+ // we don't have multiple namespaces in recovery mode
+ return true;
+ }
+ if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
+ IsBionicUpdatable()) {
+ if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
+ PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace init
+} // namespace android
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h b/init/mount_namespace.h
similarity index 65%
rename from debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
rename to init/mount_namespace.h
index 5d0d924..c41a449 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
+++ b/init/mount_namespace.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -14,16 +14,14 @@
* limitations under the License.
*/
-#ifndef _DEBUGGERD_ELF_UTILS_H
-#define _DEBUGGERD_ELF_UTILS_H
+#pragma once
-#include <stdint.h>
-#include <string>
+namespace android {
+namespace init {
-namespace unwindstack {
-class Memory;
-}
+bool SetupMountNamespaces();
+bool SwitchToDefaultMountNamespace();
+bool SwitchToBootstrapMountNamespaceIfNeeded();
-bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string*);
-
-#endif // _DEBUGGERD_ELF_UTILS_H
+} // namespace init
+} // namespace android
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 3199d45..91b7ddd 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -49,8 +49,6 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <bootimg.h>
-#include <fs_mgr.h>
#include <property_info_parser/property_info_parser.h>
#include <property_info_serializer/property_info_serializer.h>
#include <selinux/android.h>
@@ -79,8 +77,6 @@
using android::properties::PropertyInfoAreaFile;
using android::properties::PropertyInfoEntry;
-#define RECOVERY_MOUNT_POINT "/recovery"
-
namespace android {
namespace init {
@@ -732,37 +728,6 @@
property_set("ro.persistent_properties.ready", "true");
}
-void load_recovery_id_prop() {
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
- if (!fstab) {
- PLOG(ERROR) << "unable to read default fstab";
- return;
- }
-
- fstab_rec* rec = fs_mgr_get_entry_for_mount_point(fstab.get(), RECOVERY_MOUNT_POINT);
- if (rec == NULL) {
- LOG(ERROR) << "/recovery not specified in fstab";
- return;
- }
-
- int fd = open(rec->blk_device, O_RDONLY | O_CLOEXEC);
- if (fd == -1) {
- PLOG(ERROR) << "error opening block device " << rec->blk_device;
- return;
- }
-
- boot_img_hdr hdr;
- if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
- std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
- property_set("ro.recovery_id", hex);
- } else {
- PLOG(ERROR) << "error reading /recovery";
- }
-
- close(fd);
-}
-
void property_load_boot_defaults() {
// TODO(b/117892318): merge prop.default and build.prop files into one
// TODO(b/122864654): read the prop files from all partitions and then
@@ -783,7 +748,6 @@
load_properties_from_file("/odm/build.prop", NULL);
load_properties_from_file("/vendor/build.prop", NULL);
load_properties_from_file("/factory/factory.prop", "ro.*");
- load_recovery_id_prop();
update_sys_usb_config();
}
diff --git a/init/service.cpp b/init/service.cpp
index 272809f..a6eb7f7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -50,6 +50,7 @@
#include <sys/system_properties.h>
#include "init.h"
+#include "mount_namespace.h"
#include "property_service.h"
#include "selinux.h"
#else
@@ -207,6 +208,11 @@
return execv(c_strings[0], c_strings.data()) == 0;
}
+static bool IsRuntimeApexReady() {
+ struct stat buf;
+ return stat("/apex/com.android.runtime/", &buf) == 0;
+}
+
unsigned long Service::next_start_order_ = 1;
bool Service::is_exec_service_running_ = false;
@@ -929,6 +935,14 @@
scon = *result;
}
+ if (!IsRuntimeApexReady() && !pre_apexd_) {
+ // If this service is started before the runtime APEX gets available,
+ // mark it as pre-apexd one. Note that this marking is permanent. So
+ // for example, if the service is re-launched (e.g., due to crash),
+ // it is still recognized as pre-apexd... for consistency.
+ pre_apexd_ = true;
+ }
+
LOG(INFO) << "starting service '" << name_ << "'...";
pid_t pid = -1;
@@ -945,6 +959,15 @@
LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
}
+#if defined(__ANDROID__)
+ if (pre_apexd_) {
+ if (!SwitchToBootstrapMountNamespaceIfNeeded()) {
+ LOG(FATAL) << "Service '" << name_ << "' could not enter "
+ << "into the bootstrap mount namespace";
+ }
+ }
+#endif
+
if (namespace_flags_ & CLONE_NEWNS) {
if (auto result = SetUpMountNamespace(); !result) {
LOG(FATAL) << "Service '" << name_
diff --git a/init/service.h b/init/service.h
index 56e75b0..c29723a 100644
--- a/init/service.h
+++ b/init/service.h
@@ -242,6 +242,8 @@
std::vector<std::string> args_;
std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
+
+ bool pre_apexd_ = false;
};
class ServiceList {
diff --git a/init/util.cpp b/init/util.cpp
index 3781141..29d7a76 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -34,7 +34,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
@@ -269,16 +268,6 @@
}
/*
- * Writes hex_len hex characters (1/2 byte) to hex from bytes.
- */
-std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
- std::string hex("0x");
- for (size_t i = 0; i < bytes_len; i++)
- android::base::StringAppendF(&hex, "%02x", bytes[i]);
- return hex;
-}
-
-/*
* Returns true is pathname is a directory
*/
bool is_dir(const char* pathname) {
@@ -452,5 +441,9 @@
android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function));
}
+bool IsRecoveryMode() {
+ return access("/system/bin/recovery", F_OK) == 0;
+}
+
} // namespace init
} // namespace android
diff --git a/init/util.h b/init/util.h
index 53f4547..2232a0f 100644
--- a/init/util.h
+++ b/init/util.h
@@ -51,7 +51,6 @@
void import_kernel_cmdline(bool in_qemu,
const std::function<void(const std::string&, const std::string&, bool)>&);
bool make_dir(const std::string& path, mode_t mode);
-std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
bool is_dir(const char* pathname);
bool expand_props(const std::string& src, std::string* dst);
@@ -65,7 +64,7 @@
bool IsLegalPropertyName(const std::string& name);
void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function);
-
+bool IsRecoveryMode();
} // namespace init
} // namespace android
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 03edfb5..63c3793 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -134,6 +134,7 @@
#define AID_IORAPD 1071 /* input/output readahead and pin daemon */
#define AID_GPU_SERVICE 1072 /* GPU service daemon */
#define AID_NETWORK_STACK 1073 /* network stack service */
+#define AID_GSID 1074 /* GSI service daemon */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index b388e95..e816926 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -16,3 +16,16 @@
srcs: ["keyutils_test.cpp"],
test_suites: ["device-tests"],
}
+
+cc_binary {
+ name: "mini-keyctl",
+ srcs: ["mini_keyctl.cpp"],
+
+ shared_libs: [
+ "libbase",
+ "libkeyutils",
+ "liblog",
+ ],
+
+ cflags: ["-Werror", "-Wall", "-Wextra"],
+}
diff --git a/libkeyutils/include/keyutils.h b/libkeyutils/include/keyutils.h
index 585767d..c508f27 100644
--- a/libkeyutils/include/keyutils.h
+++ b/libkeyutils/include/keyutils.h
@@ -51,6 +51,10 @@
long keyctl_unlink(key_serial_t key, key_serial_t keyring);
+long keyctl_restrict_keyring(key_serial_t keyring, const char* type, const char* restriction);
+
+long keyctl_get_security(key_serial_t key, char* buffer, size_t buflen);
+
__END_DECLS
#endif
diff --git a/libkeyutils/keyutils.cpp b/libkeyutils/keyutils.cpp
index 58a2a17..8f63f70 100644
--- a/libkeyutils/keyutils.cpp
+++ b/libkeyutils/keyutils.cpp
@@ -69,3 +69,11 @@
long keyctl_unlink(key_serial_t key, key_serial_t keyring) {
return keyctl(KEYCTL_UNLINK, key, keyring);
}
+
+long keyctl_restrict_keyring(key_serial_t keyring, const char* type, const char* restriction) {
+ return keyctl(KEYCTL_RESTRICT_KEYRING, keyring, type, restriction);
+}
+
+long keyctl_get_security(key_serial_t id, char* buffer, size_t buflen) {
+ return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen);
+}
diff --git a/libkeyutils/mini_keyctl.cpp b/libkeyutils/mini_keyctl.cpp
new file mode 100644
index 0000000..abc8f82
--- /dev/null
+++ b/libkeyutils/mini_keyctl.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/*
+ * A tool loads keys to keyring.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <keyutils.h>
+
+static constexpr int kMaxCertSize = 4096;
+
+// Add all the certs from directory path to keyring with keyring_id. Returns the number of keys
+// added.
+int AddKeys(const std::string& path, const key_serial_t keyring_id, const std::string& keyring_desc,
+ int start_index) {
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(path.c_str()), closedir);
+ if (!dir) {
+ PLOG(WARNING) << "Failed to open directory " << path;
+ return 0;
+ }
+ int keys_added = 0;
+ struct dirent* dp;
+ while ((dp = readdir(dir.get())) != NULL) {
+ if (dp->d_type != DT_REG) {
+ continue;
+ }
+ std::string cert_path = path + "/" + dp->d_name;
+ std::string cert_buf;
+ if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) {
+ LOG(ERROR) << "Failed to read " << cert_path;
+ continue;
+ }
+
+ if (cert_buf.size() > kMaxCertSize) {
+ LOG(ERROR) << "Certficate size too large: " << cert_path;
+ continue;
+ }
+
+ // Add key to keyring.
+ int key_desc_index = keys_added + start_index;
+ std::string key_desc = keyring_desc + "-key" + std::to_string(key_desc_index);
+ key_serial_t key =
+ add_key("asymmetric", key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id);
+ if (key < 0) {
+ PLOG(ERROR) << "Failed to add key to keyring: " << cert_path;
+ continue;
+ }
+ keys_added++;
+ }
+ return keys_added;
+}
+
+std::vector<std::string> SplitBySpace(const std::string& s) {
+ std::istringstream iss(s);
+ return std::vector<std::string>{std::istream_iterator<std::string>{iss},
+ std::istream_iterator<std::string>{}};
+}
+
+// Find the keyring id. Because request_key(2) syscall is not available or the key is
+// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
+// information in the descritption section depending on the key type, only the first word in the
+// keyring description is used for searching.
+bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
+ if (!keyring_id) {
+ LOG(ERROR) << "keyring_id is null";
+ return false;
+ }
+
+ // Only keys allowed by SELinux rules will be shown here.
+ std::ifstream proc_keys_file("/proc/keys");
+ if (!proc_keys_file.is_open()) {
+ PLOG(ERROR) << "Failed to open /proc/keys";
+ return false;
+ }
+
+ std::string line;
+ while (getline(proc_keys_file, line)) {
+ std::vector<std::string> tokens = SplitBySpace(line);
+ if (tokens.size() < 9) {
+ continue;
+ }
+ std::string key_id = tokens[0];
+ std::string key_type = tokens[7];
+ // The key description may contain space.
+ std::string key_desc_prefix = tokens[8];
+ // The prefix has a ":" at the end
+ std::string key_desc_pattern = keyring_desc + ":";
+ if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
+ continue;
+ }
+ *keyring_id = std::stoi(key_id, nullptr, 16);
+ return true;
+ }
+ return false;
+}
+
+static void Usage(int exit_code) {
+ fprintf(stderr, "usage: mini-keyctl -c PATHS -s DESCRIPTION\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "-c, --cert_dirs the certificate locations, separated by comma\n");
+ fprintf(stderr, "-k, --keyring the keyring description\n");
+ _exit(exit_code);
+}
+
+int main(int argc, char** argv) {
+ if (argc < 5) Usage(1);
+
+ std::string arg_cert_dirs;
+ std::string arg_keyring_desc;
+
+ for (int i = 1; i < argc; i++) {
+ std::string option = argv[i];
+ if (option == "-c" || option == "--cert_dirs") {
+ if (i + 1 < argc) arg_cert_dirs = argv[++i];
+ } else if (option == "-k" || option == "--keyring") {
+ if (i + 1 < argc) arg_keyring_desc = argv[++i];
+ }
+ }
+
+ if (arg_cert_dirs.empty() || arg_keyring_desc.empty()) {
+ LOG(ERROR) << "Missing cert_dirs or keyring desc";
+ Usage(1);
+ }
+
+ // Get the keyring id
+ key_serial_t key_ring_id;
+ if (!GetKeyringId(arg_keyring_desc, &key_ring_id)) {
+ PLOG(ERROR) << "Can't find keyring with " << arg_keyring_desc;
+ return 1;
+ }
+
+ std::vector<std::string> cert_dirs = android::base::Split(arg_cert_dirs, ",");
+ int start_index = 0;
+ for (const auto& cert_dir : cert_dirs) {
+ int keys_added = AddKeys(cert_dir, key_ring_id, arg_keyring_desc, start_index);
+ start_index += keys_added;
+ }
+
+ // Prevent new keys to be added.
+ if (!android::base::GetBoolProperty("ro.debuggable", false) &&
+ keyctl_restrict_keyring(key_ring_id, nullptr, nullptr) < 0) {
+ PLOG(ERROR) << "Failed to restrict key ring " << arg_keyring_desc;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/liblog/tests/AndroidTest.xml b/liblog/tests/AndroidTest.xml
index bee0497..c167478 100644
--- a/liblog/tests/AndroidTest.xml
+++ b/liblog/tests/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="systems" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsLiblogTestCases->/data/local/tmp/CtsLiblogTestCases" />
diff --git a/libmeminfo/Android.bp b/libmeminfo/Android.bp
index 3e191ad..fc022bd 100644
--- a/libmeminfo/Android.bp
+++ b/libmeminfo/Android.bp
@@ -46,7 +46,6 @@
static_libs: [
"libmeminfo",
- "libpagemap",
"libbase",
"liblog",
],
diff --git a/libmeminfo/libdmabufinfo/dmabufinfo.cpp b/libmeminfo/libdmabufinfo/dmabufinfo.cpp
index 41ecc51..b4ad667 100644
--- a/libmeminfo/libdmabufinfo/dmabufinfo.cpp
+++ b/libmeminfo/libdmabufinfo/dmabufinfo.cpp
@@ -119,9 +119,23 @@
return false;
}
- DmaBuffer& buf =
+ uint64_t inode = sb.st_ino;
+ auto buf = std::find_if(dmabufs->begin(), dmabufs->end(),
+ [&inode](const DmaBuffer& dbuf) { return dbuf.inode() == inode; });
+ if (buf != dmabufs->end()) {
+ if (buf->name() == "" || buf->name() == "<unknown>")
+ buf->SetName(name);
+ if (buf->exporter() == "" || buf->exporter() == "<unknown>")
+ buf->SetExporter(exporter);
+ if (buf->count() == 0)
+ buf->SetCount(count);
+ buf->AddFdRef(pid);
+ return true;
+ }
+
+ DmaBuffer& db =
dmabufs->emplace_back(sb.st_ino, sb.st_blocks * 512, count, exporter, name);
- buf.AddFdRef(pid);
+ db.AddFdRef(pid);
}
return true;
@@ -225,6 +239,10 @@
bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
dmabufs->clear();
+ return AppendDmaBufInfo(pid, dmabufs);
+}
+
+bool AppendDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs) {
if (!ReadDmaBufFdRefs(pid, dmabufs)) {
LOG(ERROR) << "Failed to read dmabuf fd references";
return false;
diff --git a/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp b/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
index aa5f16c..95aa2c7 100644
--- a/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
+++ b/libmeminfo/libdmabufinfo/dmabufinfo_test.cpp
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include <unordered_map>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -61,18 +62,16 @@
#define EXPECT_PID_IN_FDREFS(_bufptr, _pid, _expect) \
do { \
- const std::vector<pid_t>& _fdrefs = _bufptr->fdrefs(); \
- auto _ref = std::find_if(_fdrefs.begin(), _fdrefs.end(), \
- [&](const pid_t& p) { return p == _pid; }); \
- EXPECT_EQ((_ref == _fdrefs.end()), _expect); \
+ const std::unordered_map<pid_t, int>& _fdrefs = _bufptr->fdrefs(); \
+ auto _ref = _fdrefs.find(_pid); \
+ EXPECT_EQ((_ref != _fdrefs.end()), _expect); \
} while (0)
#define EXPECT_PID_IN_MAPREFS(_bufptr, _pid, _expect) \
do { \
- const std::vector<pid_t>& _maprefs = _bufptr->maprefs(); \
- auto _ref = std::find_if(_maprefs.begin(), _maprefs.end(), \
- [&](const pid_t& p) { return p == _pid; }); \
- EXPECT_EQ((_ref == _maprefs.end()), _expect); \
+ const std::unordered_map<pid_t, int>& _maprefs = _bufptr->maprefs(); \
+ auto _ref = _maprefs.find(_pid); \
+ EXPECT_EQ((_ref != _maprefs.end()), _expect); \
} while (0)
TEST(DmaBufInfoParser, TestReadDmaBufInfo) {
diff --git a/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h b/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
index 29ce4d0..74eff3c 100644
--- a/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
+++ b/libmeminfo/libdmabufinfo/include/dmabufinfo/dmabufinfo.h
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include <unordered_map>
namespace android {
namespace dmabufinfo {
@@ -33,20 +34,27 @@
~DmaBuffer() = default;
// Adds one file descriptor reference for the given pid
- void AddFdRef(pid_t pid) { fdrefs_.emplace_back(pid); }
+ void AddFdRef(pid_t pid) {
+ AddRefToPidMap(pid, &fdrefs_);
+ }
// Adds one map reference for the given pid
- void AddMapRef(pid_t pid) { maprefs_.emplace_back(pid); }
+ void AddMapRef(pid_t pid) {
+ AddRefToPidMap(pid, &maprefs_);
+ }
// Getters for each property
uint64_t size() { return size_; }
- const std::vector<pid_t>& fdrefs() const { return fdrefs_; }
- const std::vector<pid_t>& maprefs() const { return maprefs_; }
+ const std::unordered_map<pid_t, int>& fdrefs() const { return fdrefs_; }
+ const std::unordered_map<pid_t, int>& maprefs() const { return maprefs_; }
ino_t inode() const { return inode_; }
uint64_t total_refs() const { return fdrefs_.size() + maprefs_.size(); }
uint64_t count() const { return count_; };
const std::string& name() const { return name_; }
const std::string& exporter() const { return exporter_; }
+ void SetName(const std::string& name) { name_ = name; }
+ void SetExporter(const std::string& exporter) { exporter_ = exporter; }
+ void SetCount(uint64_t count) { count_ = count; }
private:
ino_t inode_;
@@ -54,20 +62,37 @@
uint64_t count_;
std::string exporter_;
std::string name_;
- std::vector<pid_t> fdrefs_;
- std::vector<pid_t> maprefs_;
+ std::unordered_map<pid_t, int> fdrefs_;
+ std::unordered_map<pid_t, int> maprefs_;
+ void AddRefToPidMap(pid_t pid, std::unordered_map<pid_t, int>* map) {
+ // The first time we find a ref, we set the ref count to 1
+ // otherwise, increment the existing ref count
+ auto [it, inserted] = map->insert(std::make_pair(pid, 1));
+ if (!inserted)
+ it->second++;
+ }
};
// Read and return current dma buf objects from
// DEBUGFS/dma_buf/bufinfo. The references to each dma buffer are not
// populated here and will return an empty vector.
+//
// Returns false if something went wrong with the function, true otherwise.
bool ReadDmaBufInfo(std::vector<DmaBuffer>* dmabufs,
const std::string& path = "/sys/kernel/debug/dma_buf/bufinfo");
+
// Read and return dmabuf objects for a given process without the help
// of DEBUGFS
+//
+// Returns false if something went wrong with the function, true otherwise.
bool ReadDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);
+// Append dmabuf objects for a given process without the help
+// of DEBUGFS to an existing vector
+//
+// Returns false if something went wrong with the function, true otherwise.
+bool AppendDmaBufInfo(pid_t pid, std::vector<DmaBuffer>* dmabufs);
+
} // namespace dmabufinfo
} // namespace android
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index ccc40d1..5451ca3 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -26,7 +26,6 @@
#include <meminfo/pageacct.h>
#include <meminfo/procmeminfo.h>
#include <meminfo/sysmeminfo.h>
-#include <pagemap/pagemap.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -37,239 +36,12 @@
pid_t pid = -1;
-class ValidateProcMemInfo : public ::testing::Test {
- protected:
- void SetUp() override {
- ASSERT_EQ(0, pm_kernel_create(&ker));
- ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
- proc_mem = new ProcMemInfo(pid);
- ASSERT_NE(proc_mem, nullptr);
- }
-
- void TearDown() override {
- delete proc_mem;
- pm_process_destroy(proc);
- pm_kernel_destroy(ker);
- }
-
- pm_kernel_t* ker;
- pm_process_t* proc;
- ProcMemInfo* proc_mem;
-};
-
-TEST_F(ValidateProcMemInfo, TestMapsSize) {
- const std::vector<Vma>& maps = proc_mem->Maps();
- ASSERT_FALSE(maps.empty()) << "Process " << getpid() << " maps are empty";
-}
-
-TEST_F(ValidateProcMemInfo, TestMapsEquality) {
- const std::vector<Vma>& maps = proc_mem->Maps();
- ASSERT_EQ(proc->num_maps, maps.size());
-
- for (size_t i = 0; i < maps.size(); ++i) {
- EXPECT_EQ(proc->maps[i]->start, maps[i].start);
- EXPECT_EQ(proc->maps[i]->end, maps[i].end);
- EXPECT_EQ(proc->maps[i]->offset, maps[i].offset);
- EXPECT_EQ(std::string(proc->maps[i]->name), maps[i].name);
- }
-}
-
-TEST_F(ValidateProcMemInfo, TestMaps) {
- const std::vector<Vma>& maps = proc_mem->Maps();
- ASSERT_FALSE(maps.empty());
- ASSERT_EQ(proc->num_maps, maps.size());
-
- pm_memusage_t map_usage, proc_usage;
- pm_memusage_zero(&map_usage);
- pm_memusage_zero(&proc_usage);
- for (size_t i = 0; i < maps.size(); i++) {
- ASSERT_EQ(0, pm_map_usage(proc->maps[i], &map_usage));
- EXPECT_EQ(map_usage.vss, maps[i].usage.vss) << "VSS mismatch for map: " << maps[i].name;
- EXPECT_EQ(map_usage.rss, maps[i].usage.rss) << "RSS mismatch for map: " << maps[i].name;
- EXPECT_EQ(map_usage.pss, maps[i].usage.pss) << "PSS mismatch for map: " << maps[i].name;
- EXPECT_EQ(map_usage.uss, maps[i].usage.uss) << "USS mismatch for map: " << maps[i].name;
- pm_memusage_add(&proc_usage, &map_usage);
- }
-
- EXPECT_EQ(proc_usage.vss, proc_mem->Usage().vss);
- EXPECT_EQ(proc_usage.rss, proc_mem->Usage().rss);
- EXPECT_EQ(proc_usage.pss, proc_mem->Usage().pss);
- EXPECT_EQ(proc_usage.uss, proc_mem->Usage().uss);
-}
-
-TEST_F(ValidateProcMemInfo, TestSwapUsage) {
- const std::vector<Vma>& maps = proc_mem->Maps();
- ASSERT_FALSE(maps.empty());
- ASSERT_EQ(proc->num_maps, maps.size());
-
- pm_memusage_t map_usage, proc_usage;
- pm_memusage_zero(&map_usage);
- pm_memusage_zero(&proc_usage);
- for (size_t i = 0; i < maps.size(); i++) {
- ASSERT_EQ(0, pm_map_usage(proc->maps[i], &map_usage));
- EXPECT_EQ(map_usage.swap, maps[i].usage.swap) << "SWAP mismatch for map: " << maps[i].name;
- pm_memusage_add(&proc_usage, &map_usage);
- }
-
- EXPECT_EQ(proc_usage.swap, proc_mem->Usage().swap);
-}
-
-TEST_F(ValidateProcMemInfo, TestSwapOffsets) {
- const MemUsage& proc_usage = proc_mem->Usage();
- const std::vector<uint16_t>& swap_offsets = proc_mem->SwapOffsets();
-
- EXPECT_EQ(proc_usage.swap / getpagesize(), swap_offsets.size());
-}
-
-TEST_F(ValidateProcMemInfo, TestPageMap) {
- std::vector<uint64_t> pagemap;
-
- auto vma_callback = [&](const Vma& vma) {
- uint64_t* pmap_out;
- size_t len;
- ASSERT_EQ(0, pm_process_pagemap_range(proc, vma.start, vma.end, &pmap_out, &len));
- ASSERT_TRUE(proc_mem->PageMap(vma, &pagemap));
-
- EXPECT_EQ(len, ((vma.end - vma.start) / getpagesize()));
- for (size_t i = 0; i < len; i++) {
- EXPECT_EQ(pmap_out[i], pagemap[i]);
- }
- };
- ASSERT_TRUE(proc_mem->ForEachVma(vma_callback));
-}
-
-class ValidateProcMemInfoWss : public ::testing::Test {
- protected:
- void SetUp() override {
- ASSERT_EQ(0, pm_kernel_create(&ker));
- ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
- proc_mem = new ProcMemInfo(pid, true);
- ASSERT_NE(proc_mem, nullptr);
- }
-
- void TearDown() override {
- delete proc_mem;
- pm_process_destroy(proc);
- pm_kernel_destroy(ker);
- }
-
- pm_kernel_t* ker;
- pm_process_t* proc;
- ProcMemInfo* proc_mem;
-};
-
-TEST_F(ValidateProcMemInfoWss, TestWorkingTestReset) {
+TEST(ProcMemInfo, TestWorkingTestReset) {
// Expect reset to succeed
EXPECT_TRUE(ProcMemInfo::ResetWorkingSet(pid));
}
-TEST_F(ValidateProcMemInfoWss, TestWssEquality) {
- // Read wss using libpagemap
- pm_memusage_t wss_pagemap;
- EXPECT_EQ(0, pm_process_workingset(proc, &wss_pagemap, 0));
-
- // Read wss using libmeminfo
- MemUsage wss = proc_mem->Wss();
-
- // compare
- EXPECT_EQ(wss_pagemap.rss, wss.rss);
- EXPECT_EQ(wss_pagemap.pss, wss.pss);
- EXPECT_EQ(wss_pagemap.uss, wss.uss);
-}
-
-class ValidatePageAcct : public ::testing::Test {
- protected:
- void SetUp() override {
- ASSERT_EQ(0, pm_kernel_create(&ker));
- ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
- }
-
- void TearDown() override {
- pm_process_destroy(proc);
- pm_kernel_destroy(ker);
- }
-
- pm_kernel_t* ker;
- pm_process_t* proc;
-};
-
-TEST_F(ValidatePageAcct, TestPageFlags) {
- PageAcct& pi = PageAcct::Instance();
- pi.InitPageAcct(false);
-
- uint64_t* pagemap;
- size_t num_pages;
- for (size_t i = 0; i < proc->num_maps; i++) {
- ASSERT_EQ(0, pm_map_pagemap(proc->maps[i], &pagemap, &num_pages));
- for (size_t j = 0; j < num_pages; j++) {
- if (!PM_PAGEMAP_PRESENT(pagemap[j])) continue;
-
- uint64_t pfn = PM_PAGEMAP_PFN(pagemap[j]);
- uint64_t page_flags_pagemap, page_flags_meminfo;
-
- ASSERT_EQ(0, pm_kernel_flags(ker, pfn, &page_flags_pagemap));
- ASSERT_TRUE(pi.PageFlags(pfn, &page_flags_meminfo));
- // check if page flags equal
- EXPECT_EQ(page_flags_pagemap, page_flags_meminfo);
- }
- free(pagemap);
- }
-}
-
-TEST_F(ValidatePageAcct, TestPageCounts) {
- PageAcct& pi = PageAcct::Instance();
- pi.InitPageAcct(false);
-
- uint64_t* pagemap;
- size_t num_pages;
- for (size_t i = 0; i < proc->num_maps; i++) {
- ASSERT_EQ(0, pm_map_pagemap(proc->maps[i], &pagemap, &num_pages));
- for (size_t j = 0; j < num_pages; j++) {
- uint64_t pfn = PM_PAGEMAP_PFN(pagemap[j]);
- uint64_t map_count_pagemap, map_count_meminfo;
-
- ASSERT_EQ(0, pm_kernel_count(ker, pfn, &map_count_pagemap));
- ASSERT_TRUE(pi.PageMapCount(pfn, &map_count_meminfo));
- // check if map counts are equal
- EXPECT_EQ(map_count_pagemap, map_count_meminfo);
- }
- free(pagemap);
- }
-}
-
-TEST_F(ValidatePageAcct, TestPageIdle) {
- // skip the test if idle page tracking isn't enabled
- if (pm_kernel_init_page_idle(ker) != 0) {
- return;
- }
-
- PageAcct& pi = PageAcct::Instance();
- ASSERT_TRUE(pi.InitPageAcct(true));
-
- uint64_t* pagemap;
- size_t num_pages;
- for (size_t i = 0; i < proc->num_maps; i++) {
- ASSERT_EQ(0, pm_map_pagemap(proc->maps[i], &pagemap, &num_pages));
- for (size_t j = 0; j < num_pages; j++) {
- if (!PM_PAGEMAP_PRESENT(pagemap[j])) continue;
- uint64_t pfn = PM_PAGEMAP_PFN(pagemap[j]);
-
- ASSERT_EQ(0, pm_kernel_mark_page_idle(ker, &pfn, 1));
- int idle_status_pagemap = pm_kernel_get_page_idle(ker, pfn);
- int idle_status_meminfo = pi.IsPageIdle(pfn);
- EXPECT_EQ(idle_status_pagemap, idle_status_meminfo);
- }
- free(pagemap);
- }
-}
-
-TEST(TestProcMemInfo, MapsEmpty) {
- ProcMemInfo proc_mem(pid);
- const std::vector<Vma>& maps = proc_mem.Maps();
- EXPECT_GT(maps.size(), 0);
-}
-
-TEST(TestProcMemInfo, UsageEmpty) {
+TEST(ProcMemInfo, UsageEmpty) {
// If we created the object for getting working set,
// the usage must be empty
ProcMemInfo proc_mem(pid, true);
@@ -281,7 +53,14 @@
EXPECT_EQ(usage.swap, 0);
}
-TEST(TestProcMemInfo, WssEmpty) {
+TEST(ProcMemInfo, MapsNotEmpty) {
+ // Make sure the process maps are never empty
+ ProcMemInfo proc_mem(pid);
+ const std::vector<Vma>& maps = proc_mem.Maps();
+ EXPECT_FALSE(maps.empty());
+}
+
+TEST(ProcMemInfo, WssEmpty) {
// If we created the object for getting usage,
// the working set must be empty
ProcMemInfo proc_mem(pid, false);
@@ -293,7 +72,7 @@
EXPECT_EQ(wss.swap, 0);
}
-TEST(TestProcMemInfo, SwapOffsetsEmpty) {
+TEST(ProcMemInfo, SwapOffsetsEmpty) {
// If we created the object for getting working set,
// the swap offsets must be empty
ProcMemInfo proc_mem(pid, true);
@@ -301,7 +80,10 @@
EXPECT_EQ(swap_offsets.size(), 0);
}
-TEST(TestProcMemInfo, IsSmapsSupportedTest) {
+TEST(ProcMemInfo, IsSmapsSupportedTest) {
+ // Get any pid and check if /proc/<pid>/smaps_rollup exists using the API.
+ // The API must return the appropriate value regardless of the after it succeeds
+ // once.
std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid);
bool supported = IsSmapsRollupSupported(pid);
EXPECT_EQ(!access(path.c_str(), F_OK | R_OK), supported);
@@ -310,7 +92,8 @@
EXPECT_EQ(supported, IsSmapsRollupSupported(-1));
}
-TEST(TestProcMemInfo, SmapsOrRollupTest) {
+TEST(ProcMemInfo, SmapsOrRollupTest) {
+ // Make sure we can parse 'smaps_rollup' correctly
std::string rollup =
R"rollup(12c00000-7fe859e000 ---p 00000000 00:00 0 [rollup]
Rss: 331908 kB
@@ -342,8 +125,8 @@
EXPECT_EQ(stats.swap_pss, 442);
}
-TEST(TestProcMemInfo, SmapsOrRollupSmapsTest) {
- // This is a made up smaps for the test
+TEST(ProcMemInfo, SmapsOrRollupSmapsTest) {
+ // Make sure /proc/<pid>/smaps is parsed correctly
std::string smaps =
R"smaps(12c00000-13440000 rw-p 00000000 00:00 0 [anon:dalvik-main space (region space)]
Name: [anon:dalvik-main space (region space)]
@@ -382,8 +165,9 @@
EXPECT_EQ(stats.swap_pss, 70);
}
-TEST(TestProcMemInfo, SmapsOrRollupPssRollupTest) {
- // This is a made up smaps for the test
+TEST(ProcMemInfo, SmapsOrRollupPssRollupTest) {
+ // Make sure /proc/<pid>/smaps is parsed correctly
+ // to get the PSS
std::string smaps =
R"smaps(12c00000-13440000 rw-p 00000000 00:00 0 [anon:dalvik-main space (region space)]
Name: [anon:dalvik-main space (region space)]
@@ -417,7 +201,8 @@
EXPECT_EQ(pss, 2652);
}
-TEST(TestProcMemInfo, SmapsOrRollupPssSmapsTest) {
+TEST(ProcMemInfo, SmapsOrRollupPssSmapsTest) {
+ // Correctly parse smaps file to gather pss
std::string exec_dir = ::android::base::GetExecutableDirectory();
std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
@@ -426,7 +211,8 @@
EXPECT_EQ(pss, 19119);
}
-TEST(TestProcMemInfo, ForEachVmaFromFileTest) {
+TEST(ProcMemInfo, ForEachVmaFromFileTest) {
+ // Parse smaps file correctly to make callbacks for each virtual memory area (vma)
std::string exec_dir = ::android::base::GetExecutableDirectory();
std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
ProcMemInfo proc_mem(pid);
@@ -519,13 +305,14 @@
EXPECT_EQ(vmas[5].usage.swap_pss, 0);
}
-TEST(TestProcMemInfo, SmapsReturnTest) {
+TEST(ProcMemInfo, SmapsReturnTest) {
+ // Make sure Smaps() is never empty for any process
ProcMemInfo proc_mem(pid);
auto vmas = proc_mem.Smaps();
EXPECT_FALSE(vmas.empty());
}
-TEST(TestProcMemInfo, SmapsTest) {
+TEST(ProcMemInfo, SmapsTest) {
std::string exec_dir = ::android::base::GetExecutableDirectory();
std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str());
ProcMemInfo proc_mem(pid);
@@ -616,56 +403,7 @@
EXPECT_EQ(vmas[5].usage.swap_pss, 0);
}
-TEST(ValidateProcMemInfoFlags, TestPageFlags1) {
- // Create proc object using libpagemap
- pm_kernel_t* ker;
- ASSERT_EQ(0, pm_kernel_create(&ker));
- pm_process_t* proc;
- ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
-
- // count swapbacked pages using libpagemap
- pm_memusage_t proc_usage;
- pm_memusage_zero(&proc_usage);
- ASSERT_EQ(0, pm_process_usage_flags(proc, &proc_usage, (1 << KPF_SWAPBACKED),
- (1 << KPF_SWAPBACKED)));
-
- // Create ProcMemInfo that counts swapbacked pages
- ProcMemInfo proc_mem(pid, false, (1 << KPF_SWAPBACKED), (1 << KPF_SWAPBACKED));
-
- EXPECT_EQ(proc_usage.vss, proc_mem.Usage().vss);
- EXPECT_EQ(proc_usage.rss, proc_mem.Usage().rss);
- EXPECT_EQ(proc_usage.pss, proc_mem.Usage().pss);
- EXPECT_EQ(proc_usage.uss, proc_mem.Usage().uss);
-
- pm_process_destroy(proc);
- pm_kernel_destroy(ker);
-}
-
-TEST(ValidateProcMemInfoFlags, TestPageFlags2) {
- // Create proc object using libpagemap
- pm_kernel_t* ker;
- ASSERT_EQ(0, pm_kernel_create(&ker));
- pm_process_t* proc;
- ASSERT_EQ(0, pm_process_create(ker, pid, &proc));
-
- // count non-swapbacked pages using libpagemap
- pm_memusage_t proc_usage;
- pm_memusage_zero(&proc_usage);
- ASSERT_EQ(0, pm_process_usage_flags(proc, &proc_usage, (1 << KPF_SWAPBACKED), 0));
-
- // Create ProcMemInfo that counts non-swapbacked pages
- ProcMemInfo proc_mem(pid, false, 0, (1 << KPF_SWAPBACKED));
-
- EXPECT_EQ(proc_usage.vss, proc_mem.Usage().vss);
- EXPECT_EQ(proc_usage.rss, proc_mem.Usage().rss);
- EXPECT_EQ(proc_usage.pss, proc_mem.Usage().pss);
- EXPECT_EQ(proc_usage.uss, proc_mem.Usage().uss);
-
- pm_process_destroy(proc);
- pm_kernel_destroy(ker);
-}
-
-TEST(SysMemInfoParser, TestSysMemInfoFile) {
+TEST(SysMemInfo, TestSysMemInfoFile) {
std::string meminfo = R"meminfo(MemTotal: 3019740 kB
MemFree: 1809728 kB
MemAvailable: 2546560 kB
@@ -733,7 +471,7 @@
EXPECT_EQ(mi.mem_kernel_stack_kb(), 4880);
}
-TEST(SysMemInfoParser, TestEmptyFile) {
+TEST(SysMemInfo, TestEmptyFile) {
TemporaryFile tf;
std::string empty_string = "";
ASSERT_TRUE(tf.fd != -1);
@@ -744,7 +482,7 @@
EXPECT_EQ(mi.mem_total_kb(), 0);
}
-TEST(SysMemInfoParser, TestZramTotal) {
+TEST(SysMemInfo, TestZramTotal) {
std::string exec_dir = ::android::base::GetExecutableDirectory();
SysMemInfo mi;
@@ -774,7 +512,7 @@
MEMINFO_COUNT
};
-TEST(SysMemInfoParser, TestZramWithTags) {
+TEST(SysMemInfo, TestZramWithTags) {
std::string meminfo = R"meminfo(MemTotal: 3019740 kB
MemFree: 1809728 kB
MemAvailable: 2546560 kB
@@ -849,7 +587,7 @@
EXPECT_EQ(mem[MEMINFO_KERNEL_STACK], 4880);
}
-TEST(SysMemInfoParser, TestVmallocInfoNoMemory) {
+TEST(SysMemInfo, TestVmallocInfoNoMemory) {
std::string vmallocinfo =
R"vmallocinfo(0x0000000000000000-0x0000000000000000 69632 of_iomap+0x78/0xb0 phys=17a00000 ioremap
0x0000000000000000-0x0000000000000000 8192 of_iomap+0x78/0xb0 phys=b220000 ioremap
@@ -864,7 +602,7 @@
EXPECT_EQ(ReadVmallocInfo(file), 0);
}
-TEST(SysMemInfoParser, TestVmallocInfoKernel) {
+TEST(SysMemInfo, TestVmallocInfoKernel) {
std::string vmallocinfo =
R"vmallocinfo(0x0000000000000000-0x0000000000000000 8192 drm_property_create_blob+0x44/0xec pages=1 vmalloc)vmallocinfo";
@@ -876,7 +614,7 @@
EXPECT_EQ(ReadVmallocInfo(file), getpagesize());
}
-TEST(SysMemInfoParser, TestVmallocInfoModule) {
+TEST(SysMemInfo, TestVmallocInfoModule) {
std::string vmallocinfo =
R"vmallocinfo(0x0000000000000000-0x0000000000000000 28672 pktlog_alloc_buf+0xc4/0x15c [wlan] pages=6 vmalloc)vmallocinfo";
@@ -888,7 +626,7 @@
EXPECT_EQ(ReadVmallocInfo(file), 6 * getpagesize());
}
-TEST(SysMemInfoParser, TestVmallocInfoAll) {
+TEST(SysMemInfo, TestVmallocInfoAll) {
std::string vmallocinfo =
R"vmallocinfo(0x0000000000000000-0x0000000000000000 69632 of_iomap+0x78/0xb0 phys=17a00000 ioremap
0x0000000000000000-0x0000000000000000 8192 of_iomap+0x78/0xb0 phys=b220000 ioremap
@@ -907,11 +645,7 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- if (argc <= 1) {
- cerr << "Pid of a permanently sleeping process must be provided." << endl;
- exit(EXIT_FAILURE);
- }
::android::base::InitLogging(argv, android::base::StderrLogger);
- pid = std::stoi(std::string(argv[1]));
+ pid = getpid();
return RUN_ALL_TESTS();
}
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 2802d36..1ec21e9 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -23,6 +23,10 @@
"llndk.libraries.txt",
"vndksp.libraries.txt",
],
+ stubs: {
+ symbol_file: "libnativeloader.map.txt",
+ versions: ["1"],
+ },
}
cc_library_headers {
diff --git a/libnetutils/Android.bp b/libnetutils/Android.bp
index 1d43775..268496f 100644
--- a/libnetutils/Android.bp
+++ b/libnetutils/Android.bp
@@ -6,6 +6,7 @@
},
srcs: [
+ "checksum.c",
"dhcpclient.c",
"dhcpmsg.c",
"ifc_utils.c",
diff --git a/libnetutils/checksum.c b/libnetutils/checksum.c
new file mode 100644
index 0000000..74b5fdd
--- /dev/null
+++ b/libnetutils/checksum.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011 Daniel Drown
+ *
+ * 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.
+ *
+ * checksum.c - ipv4/ipv6 checksum calculation
+ */
+#include <netinet/icmp6.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include "netutils/checksum.h"
+
+/* function: ip_checksum_add
+ * adds data to a checksum. only known to work on little-endian hosts
+ * current - the current checksum (or 0 to start a new checksum)
+ * data - the data to add to the checksum
+ * len - length of data
+ */
+uint32_t ip_checksum_add(uint32_t current, const void* data, int len) {
+ uint32_t checksum = current;
+ int left = len;
+ const uint16_t* data_16 = data;
+
+ while (left > 1) {
+ checksum += *data_16;
+ data_16++;
+ left -= 2;
+ }
+ if (left) {
+ checksum += *(uint8_t*)data_16;
+ }
+
+ return checksum;
+}
+
+/* function: ip_checksum_fold
+ * folds a 32-bit partial checksum into 16 bits
+ * temp_sum - sum from ip_checksum_add
+ * returns: the folded checksum in network byte order
+ */
+uint16_t ip_checksum_fold(uint32_t temp_sum) {
+ while (temp_sum > 0xffff) {
+ temp_sum = (temp_sum >> 16) + (temp_sum & 0xFFFF);
+ }
+ return temp_sum;
+}
+
+/* function: ip_checksum_finish
+ * folds and closes the checksum
+ * temp_sum - sum from ip_checksum_add
+ * returns: a header checksum value in network byte order
+ */
+uint16_t ip_checksum_finish(uint32_t temp_sum) {
+ return ~ip_checksum_fold(temp_sum);
+}
+
+/* function: ip_checksum
+ * combined ip_checksum_add and ip_checksum_finish
+ * data - data to checksum
+ * len - length of data
+ */
+uint16_t ip_checksum(const void* data, int len) {
+ // TODO: consider starting from 0xffff so the checksum of a buffer entirely consisting of zeros
+ // is correctly calculated as 0.
+ uint32_t temp_sum;
+
+ temp_sum = ip_checksum_add(0, data, len);
+ return ip_checksum_finish(temp_sum);
+}
+
+/* function: ipv6_pseudo_header_checksum
+ * calculate the pseudo header checksum for use in tcp/udp/icmp headers
+ * ip6 - the ipv6 header
+ * len - the transport length (transport header + payload)
+ * protocol - the transport layer protocol, can be different from ip6->ip6_nxt for fragments
+ */
+uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, uint8_t protocol) {
+ uint32_t checksum_len = htonl(len);
+ uint32_t checksum_next = htonl(protocol);
+
+ uint32_t current = 0;
+
+ current = ip_checksum_add(current, &(ip6->ip6_src), sizeof(struct in6_addr));
+ current = ip_checksum_add(current, &(ip6->ip6_dst), sizeof(struct in6_addr));
+ current = ip_checksum_add(current, &checksum_len, sizeof(checksum_len));
+ current = ip_checksum_add(current, &checksum_next, sizeof(checksum_next));
+
+ return current;
+}
+
+/* function: ipv4_pseudo_header_checksum
+ * calculate the pseudo header checksum for use in tcp/udp headers
+ * ip - the ipv4 header
+ * len - the transport length (transport header + payload)
+ */
+uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len) {
+ uint16_t temp_protocol, temp_length;
+
+ temp_protocol = htons(ip->protocol);
+ temp_length = htons(len);
+
+ uint32_t current = 0;
+
+ current = ip_checksum_add(current, &(ip->saddr), sizeof(uint32_t));
+ current = ip_checksum_add(current, &(ip->daddr), sizeof(uint32_t));
+ current = ip_checksum_add(current, &temp_protocol, sizeof(uint16_t));
+ current = ip_checksum_add(current, &temp_length, sizeof(uint16_t));
+
+ return current;
+}
+
+/* function: ip_checksum_adjust
+ * calculates a new checksum given a previous checksum and the old and new pseudo-header checksums
+ * checksum - the header checksum in the original packet in network byte order
+ * old_hdr_sum - the pseudo-header checksum of the original packet
+ * new_hdr_sum - the pseudo-header checksum of the translated packet
+ * returns: the new header checksum in network byte order
+ */
+uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum) {
+ // Algorithm suggested in RFC 1624.
+ // http://tools.ietf.org/html/rfc1624#section-3
+ checksum = ~checksum;
+ uint16_t folded_sum = ip_checksum_fold(checksum + new_hdr_sum);
+ uint16_t folded_old = ip_checksum_fold(old_hdr_sum);
+ if (folded_sum > folded_old) {
+ return ~(folded_sum - folded_old);
+ } else {
+ return ~(folded_sum - folded_old - 1); // end-around borrow
+ }
+}
diff --git a/libnetutils/include/netutils/checksum.h b/libnetutils/include/netutils/checksum.h
new file mode 100644
index 0000000..868217c
--- /dev/null
+++ b/libnetutils/include/netutils/checksum.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011 Daniel Drown
+ *
+ * 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.
+ *
+ * checksum.h - checksum functions
+ */
+#ifndef __CHECKSUM_H__
+#define __CHECKSUM_H__
+
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <stdint.h>
+
+uint32_t ip_checksum_add(uint32_t current, const void* data, int len);
+uint16_t ip_checksum_finish(uint32_t temp_sum);
+uint16_t ip_checksum(const void* data, int len);
+
+uint32_t ipv6_pseudo_header_checksum(const struct ip6_hdr* ip6, uint32_t len, uint8_t protocol);
+uint32_t ipv4_pseudo_header_checksum(const struct iphdr* ip, uint16_t len);
+
+uint16_t ip_checksum_adjust(uint16_t checksum, uint32_t old_hdr_sum, uint32_t new_hdr_sum);
+
+#endif /* __CHECKSUM_H__ */
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 9e6bcd4..89a6a79 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -320,7 +320,8 @@
}
std::string printable_build_id;
for (const char& c : raw_build_id) {
- printable_build_id += android::base::StringPrintf("%02x", c);
+ // Use %hhx to avoid sign extension on abis that have signed chars.
+ printable_build_id += android::base::StringPrintf("%02hhx", c);
}
return printable_build_id;
}
diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
index ea9befc..16451d1 100644
--- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
+++ b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
@@ -78,6 +78,17 @@
EXPECT_EQ("46414b455f4255494c445f4944", map_info_->GetPrintableBuildID());
}
+TEST_F(MapInfoGetBuildIDTest, from_elf_no_sign_extension) {
+ map_info_->elf.reset(elf_container_.release());
+
+ std::string build_id = {static_cast<char>(0xfa), static_cast<char>(0xab), static_cast<char>(0x12),
+ static_cast<char>(0x02)};
+ elf_interface_->FakeSetBuildID(build_id);
+
+ EXPECT_EQ("\xFA\xAB\x12\x2", map_info_->GetBuildID());
+ EXPECT_EQ("faab1202", map_info_->GetPrintableBuildID());
+}
+
void MapInfoGetBuildIDTest::MultipleThreadTest(std::string expected_build_id) {
static constexpr size_t kNumConcurrentThreads = 100;
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 3f5b88b..19982d8 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -44,10 +44,10 @@
}
printf("ARM Unwind Information:\n");
+ uint64_t load_bias = elf->GetLoadBias();
for (const auto& entry : interface->pt_loads()) {
- uint64_t load_bias = entry.second.table_offset;
printf(" PC Range 0x%" PRIx64 " - 0x%" PRIx64 "\n", entry.second.offset + load_bias,
- entry.second.table_size + load_bias);
+ entry.second.offset + entry.second.table_size + load_bias);
for (auto pc : *interface) {
std::string name;
printf(" PC 0x%" PRIx64, pc + load_bias);
diff --git a/lmkd/libpsi/Android.bp b/lmkd/libpsi/Android.bp
new file mode 100644
index 0000000..8a97094
--- /dev/null
+++ b/lmkd/libpsi/Android.bp
@@ -0,0 +1,22 @@
+cc_library_headers {
+ name: "libpsi_headers",
+ export_include_dirs: ["include"],
+}
+
+cc_library {
+ name: "libpsi",
+ srcs: ["psi.c"],
+ shared_libs: [
+ "liblog"
+ ],
+ header_libs: [
+ "libpsi_headers",
+ ],
+ export_header_lib_headers: [
+ "libpsi_headers",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/lmkd/libpsi/OWNERS b/lmkd/libpsi/OWNERS
new file mode 100644
index 0000000..b15bb48
--- /dev/null
+++ b/lmkd/libpsi/OWNERS
@@ -0,0 +1 @@
+surenb@google.com
diff --git a/lmkd/libpsi/include/psi/psi.h b/lmkd/libpsi/include/psi/psi.h
new file mode 100644
index 0000000..cd49e8b
--- /dev/null
+++ b/lmkd/libpsi/include/psi/psi.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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 __ANDROID_PSI_H__
+#define __ANDROID_PSI_H__
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+__BEGIN_DECLS
+
+enum psi_stall_type {
+ PSI_SOME,
+ PSI_FULL,
+ PSI_TYPE_COUNT
+};
+
+/*
+ * Initializes psi monitor.
+ * stall_type, threshold_us and window_us are monitor parameters
+ * When successful, the function returns file descriptor that can
+ * be used with poll/epoll syscalls to wait for EPOLLPRI events.
+ * When unsuccessful, the function returns -1 and errno is set
+ * appropriately.
+ */
+int init_psi_monitor(enum psi_stall_type stall_type,
+ int threshold_us, int window_us);
+
+/*
+ * Registers psi monitor file descriptor fd on the epoll instance
+ * referred to by the file descriptor epollfd.
+ * data parameter will be associated with event's epoll_data.ptr
+ * member.
+ */
+int register_psi_monitor(int epollfd, int fd, void* data);
+
+/*
+ * Unregisters psi monitor file descriptor fd from the epoll instance
+ * referred to by the file descriptor epollfd.
+ */
+int unregister_psi_monitor(int epollfd, int fd);
+
+/*
+ * Destroys psi monitor.
+ * fd is the file descriptor returned by psi monitor initialization
+ * routine.
+ * Note that if user process exits without calling this routine
+ * kernel will destroy the monitor as its lifetime is linked to
+ * the file descriptor.
+ */
+void destroy_psi_monitor(int fd);
+
+__END_DECLS
+
+#endif // __ANDROID_PSI_H__
diff --git a/lmkd/libpsi/psi.c b/lmkd/libpsi/psi.c
new file mode 100644
index 0000000..f4d5d18
--- /dev/null
+++ b/lmkd/libpsi/psi.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define LOG_TAG "libpsi"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/epoll.h>
+
+#include <log/log.h>
+#include "psi/psi.h"
+
+#define PSI_MON_FILE_MEMORY "/proc/pressure/memory"
+
+static const char* stall_type_name[] = {
+ "some",
+ "full",
+};
+
+int init_psi_monitor(enum psi_stall_type stall_type,
+ int threshold_us, int window_us) {
+ int fd;
+ int res;
+ char buf[256];
+
+ fd = TEMP_FAILURE_RETRY(open(PSI_MON_FILE_MEMORY, O_WRONLY | O_CLOEXEC));
+ if (fd < 0) {
+ ALOGE("No kernel psi monitor support (errno=%d)", errno);
+ return -1;
+ }
+
+ switch (stall_type) {
+ case (PSI_SOME):
+ case (PSI_FULL):
+ res = snprintf(buf, sizeof(buf), "%s %d %d",
+ stall_type_name[stall_type], threshold_us, window_us);
+ break;
+ default:
+ ALOGE("Invalid psi stall type: %d", stall_type);
+ errno = EINVAL;
+ goto err;
+ }
+
+ if (res >= (ssize_t)sizeof(buf)) {
+ ALOGE("%s line overflow for psi stall type '%s'",
+ PSI_MON_FILE_MEMORY, stall_type_name[stall_type]);
+ errno = EINVAL;
+ goto err;
+ }
+
+ res = TEMP_FAILURE_RETRY(write(fd, buf, strlen(buf) + 1));
+ if (res < 0) {
+ ALOGE("%s write failed for psi stall type '%s'; errno=%d",
+ PSI_MON_FILE_MEMORY, stall_type_name[stall_type], errno);
+ goto err;
+ }
+
+ return fd;
+
+err:
+ close(fd);
+ return -1;
+}
+
+int register_psi_monitor(int epollfd, int fd, void* data) {
+ int res;
+ struct epoll_event epev;
+
+ epev.events = EPOLLPRI;
+ epev.data.ptr = data;
+ res = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &epev);
+ if (res < 0) {
+ ALOGE("epoll_ctl for psi monitor failed; errno=%d", errno);
+ }
+ return res;
+}
+
+int unregister_psi_monitor(int epollfd, int fd) {
+ return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
+}
+
+void destroy_psi_monitor(int fd) {
+ if (fd >= 0) {
+ close(fd);
+ }
+}
diff --git a/logd/tests/AndroidTest.xml b/logd/tests/AndroidTest.xml
index 1e71a73..9a18edb 100644
--- a/logd/tests/AndroidTest.xml
+++ b/logd/tests/AndroidTest.xml
@@ -17,6 +17,7 @@
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="systems" />
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsLogdTestCases->/data/local/tmp/CtsLogdTestCases" />
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index a416825..a854e93 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -38,6 +38,12 @@
additional.namespaces = runtime,conscrypt,media,resolv
# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# If a shared library or an executable requests a shared library that
+# cannot be loaded into the default namespace, the dynamic linker tries
+# to load the shared library from the runtime namespace.And then, if the
+# shared library cannot be loaded from the runtime namespace either, the
+# dynamic linker tries to load the shared library from the resolv namespace.
+# Finally, if all attempts fail, the dynamic linker returns an error.
namespace.default.links = runtime,resolv
namespace.default.asan.links = runtime,resolv
# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
@@ -49,6 +55,9 @@
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
+# When libnetd_resolv.so can't be found in the default namespace, search for it
+# in the resolv namespace. Don't allow any other libraries from the resolv namespace
+# to be loaded in the default namespace.
namespace.default.link.resolv.shared_libs = libnetd_resolv.so
###############################################################################
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index d0e84df..a617418 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -73,6 +73,8 @@
namespace.default.permitted.paths += /%PRODUCT_SERVICES%/priv-app
namespace.default.permitted.paths += /data
namespace.default.permitted.paths += /mnt/expand
+namespace.default.permitted.paths += /bionic/${LIB}
+namespace.default.permitted.paths += /system/${LIB}/bootstrap
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
@@ -104,8 +106,16 @@
namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/app
namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
namespace.default.asan.permitted.paths += /mnt/expand
+namespace.default.asan.permitted.paths += /bionic/${LIB}
+namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# If a shared library or an executable requests a shared library that
+# cannot be loaded into the default namespace, the dynamic linker tries
+# to load the shared library from the runtime namespace.And then, if the
+# shared library cannot be loaded from the runtime namespace either, the
+# dynamic linker tries to load the shared library from the resolv namespace.
+# Finally, if all attempts fail, the dynamic linker returns an error.
namespace.default.links = runtime,resolv
# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
# libart.
@@ -116,6 +126,9 @@
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
+# When libnetd_resolv.so can't be found in the default namespace, search for it
+# in the resolv namespace. Don't allow any other libraries from the resolv namespace
+# to be loaded in the default namespace.
namespace.default.link.resolv.shared_libs = libnetd_resolv.so
###############################################################################
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index c97baeb..ae486ea 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -57,6 +57,12 @@
# Keep in sync with the platform namespace in the com.android.runtime APEX
# ld.config.txt.
+# If a shared library or an executable requests a shared library that
+# cannot be loaded into the default namespace, the dynamic linker tries
+# to load the shared library from the runtime namespace.And then, if the
+# shared library cannot be loaded from the runtime namespace either, the
+# dynamic linker tries to load the shared library from the resolv namespace.
+# Finally, if all attempts fail, the dynamic linker returns an error.
namespace.default.links = runtime,resolv
# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
# libart.
@@ -67,6 +73,9 @@
namespace.default.link.runtime.shared_libs += libnativehelper.so
namespace.default.link.runtime.shared_libs += libnativeloader.so
+# When libnetd_resolv.so can't be found in the default namespace, search for it
+# in the resolv namespace. Don't allow any other libraries from the resolv namespace
+# to be loaded in the default namespace.
namespace.default.link.resolv.shared_libs = libnetd_resolv.so
###############################################################################
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d081666..4a19e39 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -12,6 +12,12 @@
import /init.${ro.zygote}.rc
on early-init
+ # Mount shared so changes propagate into child namespaces
+ # Do this before other processes are started from init. Otherwise,
+ # processes launched while the propagation type of / is 'private'
+ # won't get mount events from others.
+ mount rootfs rootfs / shared rec
+
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
@@ -346,8 +352,6 @@
# Once everything is setup, no need to modify /.
# The bind+remount combination allows this to work in containers.
mount rootfs rootfs / remount bind ro nodev
- # Mount shared so changes propagate into child namespaces
- mount rootfs rootfs / shared rec
# Mount default storage into root namespace
mount none /mnt/runtime/default /storage bind rec
mount none none /storage slave rec
@@ -583,6 +587,14 @@
# Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
+ # Wait for apexd to finish activating APEXes before starting more processes.
+ # This certainly reduces the parallelism but is required to make as many processes
+ # as possible to use the bionic libs from the runtime APEX. This takes less than 50ms
+ # so the impact on the booting time is not significant.
+ wait_for_prop apexd.status ready
+ setup_runtime_bionic
+ parse_apex_configs
+
# If there is no post-fs-data action in the init.<device>.rc file, you
# must uncomment this line, otherwise encrypted filesystems
# won't work.
@@ -804,6 +816,3 @@
service flash_recovery /system/bin/install-recovery.sh
class main
oneshot
-
-on property:apexd.status=ready
- parse_apex_configs