Merge "Load *_compat_cil_file from system_ext as well"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index fb274ec..7b6f6c0 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -238,6 +238,7 @@
"gwp_asan_crash_handler",
"libscudo",
"libtombstone_proto",
+ "libprocinfo",
"libprotobuf-cpp-lite",
],
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 6bfb5f2..530e0e8 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -96,7 +96,7 @@
if (std::string str = data.str(); !str.empty()) {
buffer << "\n----- Waiting Channels: pid " << pid << " at " << get_timestamp() << " -----\n"
- << "Cmd line: " << get_process_name(pid) << "\n";
+ << "Cmd line: " << android::base::Join(get_command_line(pid), " ") << "\n";
buffer << "\n" << str << "\n";
buffer << "----- end " << std::to_string(pid) << " -----\n";
buffer << "\n";
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 04e1e4e..a152740 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -450,9 +450,6 @@
// unwind, do not make this too small. b/62828735
alarm(30 * android::base::HwTimeoutMultiplier());
- // Get the process name (aka cmdline).
- std::string process_name = get_process_name(g_target_thread);
-
// Collect the list of open files.
OpenFilesList open_files;
{
@@ -489,7 +486,6 @@
info.pid = target_process;
info.tid = thread;
info.uid = getuid();
- info.process_name = process_name;
info.thread_name = get_thread_name(thread);
unique_fd attr_fd(openat(target_proc_fd, "attr/current", O_RDONLY | O_CLOEXEC));
@@ -517,6 +513,8 @@
ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info);
info.siginfo = &siginfo;
info.signo = info.siginfo->si_signo;
+
+ info.command_line = get_command_line(g_target_thread);
} else {
info.registers.reset(unwindstack::Regs::RemoteGet(thread));
if (!info.registers) {
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index c543a83..fd91038 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -34,6 +34,7 @@
#include <memory>
#include <string>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <log/log.h>
#include <unwindstack/Unwinder.h>
@@ -42,11 +43,12 @@
#include "libdebuggerd/utility.h"
#include "util.h"
-static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
+static void dump_process_header(log_t* log, pid_t pid,
+ const std::vector<std::string>& command_line) {
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, get_timestamp().c_str());
- if (process_name) {
- _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name);
+ if (!command_line.empty()) {
+ _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", android::base::Join(command_line, " ").c_str());
}
_LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
}
@@ -89,7 +91,7 @@
return;
}
- dump_process_header(&log, target->second.pid, target->second.process_name.c_str());
+ dump_process_header(&log, target->second.pid, target->second.command_line);
dump_backtrace_thread(output_fd.get(), unwinder, target->second);
for (const auto& [tid, info] : thread_info) {
@@ -107,7 +109,7 @@
log.amfd_data = nullptr;
pid_t pid = getpid();
- dump_process_header(&log, pid, get_process_name(pid).c_str());
+ dump_process_header(&log, pid, get_command_line(pid));
}
void dump_backtrace_footer(int output_fd) {
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index dcb52f9..086dc97 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -18,6 +18,7 @@
#include <memory>
#include <string>
+#include <vector>
#include <unwindstack/Regs.h>
@@ -32,13 +33,14 @@
pid_t pid;
- std::string process_name;
+ std::vector<std::string> command_line;
std::string selinux_label;
int signo = 0;
siginfo_t* siginfo = nullptr;
};
+// This struct is written into a pipe from inside the crashing process.
struct ProcessInfo {
uintptr_t abort_msg_address = 0;
uintptr_t fdsan_table_address = 0;
diff --git a/debuggerd/libdebuggerd/test/UnwinderMock.h b/debuggerd/libdebuggerd/test/UnwinderMock.h
index 44a9214..8f84346 100644
--- a/debuggerd/libdebuggerd/test/UnwinderMock.h
+++ b/debuggerd/libdebuggerd/test/UnwinderMock.h
@@ -33,8 +33,7 @@
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 = new_build_id;
+ map_info->SetBuildID(std::string(build_id));
}
}
};
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 79ac122..a14dcb0 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -350,11 +350,11 @@
}
TEST_F(TombstoneTest, dump_thread_info_uid) {
- dump_thread_info(&log_, ThreadInfo{.uid = 1,
- .tid = 3,
- .thread_name = "some_thread",
- .pid = 2,
- .process_name = "some_process"});
+ std::vector<std::string> cmdline = {"some_process"};
+ dump_thread_info(
+ &log_,
+ ThreadInfo{
+ .uid = 1, .tid = 3, .thread_name = "some_thread", .pid = 2, .command_line = cmdline});
std::string expected = "pid: 2, tid: 3, name: some_thread >>> some_process <<<\nuid: 1\n";
ASSERT_STREQ(expected.c_str(), amfd_data_.c_str());
}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 4f75ff1..e0cc662 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -182,8 +182,13 @@
// Don't try to collect logs from the threads that implement the logging system itself.
if (thread_info.uid == AID_LOGD) log->should_retrieve_logcat = false;
+ const char* process_name = "<unknown>";
+ if (!thread_info.command_line.empty()) {
+ process_name = thread_info.command_line[0].c_str();
+ }
+
_LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", thread_info.pid,
- thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
+ thread_info.tid, thread_info.thread_name.c_str(), process_name);
_LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid);
if (thread_info.tagged_addr_ctrl != -1) {
_LOG(log, logtype::HEADER, "tagged_addr_ctrl: %016lx\n", thread_info.tagged_addr_ctrl);
@@ -567,7 +572,7 @@
log.amfd_data = nullptr;
std::string thread_name = get_thread_name(tid);
- std::string process_name = get_process_name(pid);
+ std::vector<std::string> command_line = get_command_line(pid);
std::unique_ptr<unwindstack::Regs> regs(
unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
@@ -582,7 +587,7 @@
.tid = tid,
.thread_name = std::move(thread_name),
.pid = pid,
- .process_name = std::move(process_name),
+ .command_line = std::move(command_line),
.selinux_label = std::move(selinux_label),
.siginfo = siginfo,
};
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 1ab93fe..7657001 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -31,10 +31,12 @@
#include <time.h>
#include <memory>
+#include <optional>
#include <string>
#include <async_safe/log.h>
+#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -47,6 +49,7 @@
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
+#include <procinfo/process.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
@@ -519,6 +522,14 @@
dump_log_file(tombstone, "main", pid);
}
+static std::optional<uint64_t> read_uptime_secs() {
+ std::string uptime;
+ if (!android::base::ReadFileToString("/proc/uptime", &uptime)) {
+ return {};
+ }
+ return strtoll(uptime.c_str(), nullptr, 10);
+}
+
void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
const ProcessInfo& process_info, const OpenFilesList* open_files) {
@@ -529,13 +540,33 @@
result.set_revision(android::base::GetProperty("ro.revision", "unknown"));
result.set_timestamp(get_timestamp());
+ std::optional<uint64_t> system_uptime = read_uptime_secs();
+ if (system_uptime) {
+ android::procinfo::ProcessInfo proc_info;
+ std::string error;
+ if (android::procinfo::GetProcessInfo(target_thread, &proc_info, &error)) {
+ uint64_t starttime = proc_info.starttime / sysconf(_SC_CLK_TCK);
+ result.set_process_uptime(*system_uptime - starttime);
+ } else {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to read process info: %s",
+ error.c_str());
+ }
+ } else {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to read /proc/uptime: %s",
+ strerror(errno));
+ }
+
const ThreadInfo& main_thread = threads.at(target_thread);
result.set_pid(main_thread.pid);
result.set_tid(main_thread.tid);
result.set_uid(main_thread.uid);
result.set_selinux_label(main_thread.selinux_label);
- result.set_process_name(main_thread.process_name);
+ auto cmd_line = result.mutable_command_line();
+ for (const auto& arg : main_thread.command_line) {
+ *cmd_line->Add() = arg;
+ }
+
if (!main_thread.siginfo) {
async_safe_fatal("siginfo missing");
}
diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
index e4dd6df..020b0a5 100644
--- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
@@ -26,6 +26,7 @@
#include <vector>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <async_safe/log.h>
@@ -71,8 +72,13 @@
static void print_thread_header(CallbackType callback, const Tombstone& tombstone,
const Thread& thread, bool should_log) {
+ const char* process_name = "<unknown>";
+ if (!tombstone.command_line().empty()) {
+ process_name = tombstone.command_line()[0].c_str();
+ CB(should_log, "Cmdline: %s", android::base::Join(tombstone.command_line(), " ").c_str());
+ }
CB(should_log, "pid: %d, tid: %d, name: %s >>> %s <<<", tombstone.pid(), thread.id(),
- thread.name().c_str(), tombstone.process_name().c_str());
+ thread.name().c_str(), process_name);
CB(should_log, "uid: %d", tombstone.uid());
if (thread.tagged_addr_ctrl() != -1) {
CB(should_log, "tagged_addr_ctrl: %016" PRIx64, thread.tagged_addr_ctrl());
@@ -360,6 +366,7 @@
CBL("Revision: '%s'", tombstone.revision().c_str());
CBL("ABI: '%s'", abi_string(tombstone));
CBL("Timestamp: %s", tombstone.timestamp().c_str());
+ CBL("Process uptime: %ds", tombstone.process_uptime());
// Process header
const auto& threads = tombstone.threads();
diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto
index 433c406..294e4e5 100644
--- a/debuggerd/proto/tombstone.proto
+++ b/debuggerd/proto/tombstone.proto
@@ -17,7 +17,10 @@
uint32 uid = 7;
string selinux_label = 8;
- string process_name = 9;
+ repeated string command_line = 9;
+
+ // Process uptime in seconds.
+ uint32 process_uptime = 20;
Signal signal_info = 10;
string abort_message = 14;
@@ -28,7 +31,7 @@
repeated LogBuffer log_buffers = 18;
repeated FD open_fds = 19;
- reserved 20 to 999;
+ reserved 21 to 999;
}
enum Architecture {
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index f3bff8c..ce0fd30 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -26,10 +26,31 @@
#include <android-base/strings.h>
#include "protocol.h"
+std::vector<std::string> get_command_line(pid_t pid) {
+ std::vector<std::string> result;
+
+ std::string cmdline;
+ android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), &cmdline);
+
+ auto it = cmdline.cbegin();
+ while (it != cmdline.cend()) {
+ // string::iterator is a wrapped type, not a raw char*.
+ auto terminator = std::find(it, cmdline.cend(), '\0');
+ result.emplace_back(it, terminator);
+ it = std::find_if(terminator, cmdline.cend(), [](char c) { return c != '\0'; });
+ }
+ if (result.empty()) {
+ result.emplace_back("<unknown>");
+ }
+
+ return result;
+}
+
std::string get_process_name(pid_t pid) {
std::string result = "<unknown>";
android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/cmdline", pid), &result);
- return result;
+ // We only want the name, not the whole command line, so truncate at the first NUL.
+ return result.c_str();
}
std::string get_thread_name(pid_t tid) {
diff --git a/debuggerd/util.h b/debuggerd/util.h
index 07e7e99..ec2862a 100644
--- a/debuggerd/util.h
+++ b/debuggerd/util.h
@@ -17,10 +17,12 @@
#pragma once
#include <string>
+#include <vector>
#include <sys/cdefs.h>
#include <sys/types.h>
+std::vector<std::string> get_command_line(pid_t pid);
std::string get_process_name(pid_t pid);
std::string get_thread_name(pid_t tid);
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 3c4269b..ce702a0 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -127,6 +127,7 @@
"-Wextra",
"-Werror",
"-Wvla",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
],
rtti: true,
@@ -182,6 +183,7 @@
],
static_libs: [
+ "libc++fs",
"libgtest_prod",
"libhealthhalutils",
"libsnapshot_cow",
@@ -206,6 +208,8 @@
"-Wextra",
"-Werror",
"-Wunreachable-code",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ "-D_FILE_OFFSET_BITS=64"
],
target: {
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index 2c0989e..d2056aa 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -34,22 +34,22 @@
#include <stdlib.h>
#include <string.h>
-static void bootimg_set_cmdline_v3(boot_img_hdr_v3* h, const std::string& cmdline) {
+static void bootimg_set_cmdline_v3_and_above(boot_img_hdr_v3* h, const std::string& cmdline) {
if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
}
void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline) {
- if (h->header_version == 3) {
- return bootimg_set_cmdline_v3(reinterpret_cast<boot_img_hdr_v3*>(h), cmdline);
+ if (h->header_version >= 3) {
+ return bootimg_set_cmdline_v3_and_above(reinterpret_cast<boot_img_hdr_v3*>(h), cmdline);
}
if (cmdline.size() >= sizeof(h->cmdline)) die("command line too large: %zu", cmdline.size());
strcpy(reinterpret_cast<char*>(h->cmdline), cmdline.c_str());
}
-static boot_img_hdr_v3* mkbootimg_v3(const std::vector<char>& kernel,
- const std::vector<char>& ramdisk, const boot_img_hdr_v2& src,
- std::vector<char>* out) {
+static void mkbootimg_v3_and_above(const std::vector<char>& kernel,
+ const std::vector<char>& ramdisk, const boot_img_hdr_v2& src,
+ std::vector<char>* out) {
#define V3_PAGE_SIZE 4096
const size_t page_mask = V3_PAGE_SIZE - 1;
int64_t kernel_actual = (kernel.size() + page_mask) & (~page_mask);
@@ -65,22 +65,27 @@
hdr->ramdisk_size = ramdisk.size();
hdr->os_version = src.os_version;
hdr->header_size = sizeof(boot_img_hdr_v3);
- hdr->header_version = 3;
+ hdr->header_version = src.header_version;
+
+ if (src.header_version >= 4) {
+ auto hdr_v4 = reinterpret_cast<boot_img_hdr_v4*>(hdr);
+ hdr_v4->signature_size = 0;
+ }
memcpy(hdr->magic + V3_PAGE_SIZE, kernel.data(), kernel.size());
memcpy(hdr->magic + V3_PAGE_SIZE + kernel_actual, ramdisk.data(), ramdisk.size());
-
- return hdr;
}
-boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
- const std::vector<char>& second, const std::vector<char>& dtb,
- size_t base, const boot_img_hdr_v2& src, std::vector<char>* out) {
- if (src.header_version == 3) {
+void mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+ const std::vector<char>& second, const std::vector<char>& dtb, size_t base,
+ const boot_img_hdr_v2& src, std::vector<char>* out) {
+ if (src.header_version >= 3) {
if (!second.empty() || !dtb.empty()) {
- die("Second stage bootloader and dtb not supported in v3 boot image\n");
+ die("Second stage bootloader and dtb not supported in v%d boot image\n",
+ src.header_version);
}
- return reinterpret_cast<boot_img_hdr_v2*>(mkbootimg_v3(kernel, ramdisk, src, out));
+ mkbootimg_v3_and_above(kernel, ramdisk, src, out);
+ return;
}
const size_t page_mask = src.page_size - 1;
@@ -122,5 +127,4 @@
second.size());
memcpy(hdr->magic + hdr->page_size + kernel_actual + ramdisk_actual + second_actual, dtb.data(),
dtb.size());
- return hdr;
}
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index b7cf9bd..0eb003d 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -35,7 +35,8 @@
#include <string>
#include <vector>
-boot_img_hdr_v2* mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
- const std::vector<char>& second, const std::vector<char>& dtb,
- size_t base, const boot_img_hdr_v2& src, std::vector<char>* out);
+void mkbootimg(const std::vector<char>& kernel, const std::vector<char>& ramdisk,
+ const std::vector<char>& second, const std::vector<char>& dtb, size_t base,
+ const boot_img_hdr_v2& src, std::vector<char>* out);
+
void bootimg_set_cmdline(boot_img_hdr_v2* h, const std::string& cmdline);
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index b72f3fe..0a72812 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -392,13 +392,13 @@
struct sockaddr_un addr = {.sun_family = AF_UNIX};
strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
- if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+ if (connect(sock.get(), (struct sockaddr*)&addr, sizeof(addr)) < 0) {
PLOG(ERROR) << "Couldn't connect to recovery";
return false;
}
// Switch to recovery will not update the boot reason since it does not
// require a reboot.
- auto ret = write(sock, &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
+ auto ret = write(sock.get(), &msg_switch_to_recovery, sizeof(msg_switch_to_recovery));
if (ret != sizeof(msg_switch_to_recovery)) {
PLOG(ERROR) << "Couldn't write message to switch to recovery";
return false;
diff --git a/fastboot/device/usb.cpp b/fastboot/device/usb.cpp
index 4bee7b2..4115a6d 100644
--- a/fastboot/device/usb.cpp
+++ b/fastboot/device/usb.cpp
@@ -82,7 +82,7 @@
int orig_len = len;
while (len > 0) {
int write_len = std::min(USB_FFS_BULK_SIZE, len);
- int n = write(h->bulk_in, buf, write_len);
+ int n = write(h->bulk_in.get(), buf, write_len);
if (n < 0) {
D("ERROR: fd = %d, n = %d: %s", h->bulk_in.get(), n, strerror(errno));
return -1;
@@ -103,7 +103,7 @@
unsigned count = 0;
while (len > 0) {
int read_len = std::min(USB_FFS_BULK_SIZE, len);
- int n = read(h->bulk_out, buf, read_len);
+ int n = read(h->bulk_out.get(), buf, read_len);
if (n < 0) {
D("ERROR: fd = %d, n = %d: %s", h->bulk_out.get(), n, strerror(errno));
return -1;
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index f9267e0..07ad902 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -204,12 +204,7 @@
}
bool GetDeviceLockStatus() {
- std::string cmdline;
- // Return lock status true if unable to read kernel command line.
- if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
- return true;
- }
- return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
+ return android::base::GetProperty("ro.boot.verifiedbootstate", "") != "orange";
}
bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e1bf984..e5319a5 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -230,9 +230,9 @@
fprintf(stderr, "(bootloader) %s\n", info.c_str());
}
-static int64_t get_file_size(int fd) {
+static int64_t get_file_size(borrowed_fd fd) {
struct stat sb;
- if (fstat(fd, &sb) == -1) {
+ if (fstat(fd.get(), &sb) == -1) {
die("could not get file size");
}
return sb.st_size;
@@ -411,6 +411,13 @@
" gsi wipe|disable Wipe or disable a GSI installation (fastbootd only).\n"
" wipe-super [SUPER_EMPTY] Wipe the super partition. This will reset it to\n"
" contain an empty set of default dynamic partitions.\n"
+ " create-logical-partition NAME SIZE\n"
+ " Create a logical partition with the given name and\n"
+ " size, in the super partition.\n"
+ " delete-logical-partition NAME\n"
+ " Delete a logical partition with the given name.\n"
+ " resize-logical-partition NAME SIZE\n"
+ " Change the size of the named logical partition.\n"
" snapshot-update cancel On devices that support snapshot-based updates, cancel\n"
" an in-progress update. This may make the device\n"
" unbootable until it is reflashed.\n"
@@ -523,10 +530,12 @@
fprintf(stderr,"creating boot image...\n");
std::vector<char> out;
- boot_img_hdr_v2* boot_image_data = mkbootimg(kernel_data, ramdisk_data, second_stage_data,
- dtb_data, g_base_addr, g_boot_img_hdr, &out);
+ mkbootimg(kernel_data, ramdisk_data, second_stage_data, dtb_data, g_base_addr, g_boot_img_hdr,
+ &out);
- if (!g_cmdline.empty()) bootimg_set_cmdline(boot_image_data, g_cmdline);
+ if (!g_cmdline.empty()) {
+ bootimg_set_cmdline(reinterpret_cast<boot_img_hdr_v2*>(out.data()), g_cmdline);
+ }
fprintf(stderr, "creating boot image - %zu bytes\n", out.size());
return out;
}
@@ -657,12 +666,12 @@
fprintf(stderr, "extracting %s (%" PRIu64 " MB) to disk...", entry_name,
zip_entry.uncompressed_length / 1024 / 1024);
double start = now();
- int error = ExtractEntryToFile(zip, &zip_entry, fd);
+ int error = ExtractEntryToFile(zip, &zip_entry, fd.get());
if (error != 0) {
die("\nfailed to extract '%s': %s", entry_name, ErrorCodeString(error));
}
- if (lseek(fd, 0, SEEK_SET) != 0) {
+ if (lseek(fd.get(), 0, SEEK_SET) != 0) {
die("\nlseek on extracted file '%s' failed: %s", entry_name, strerror(errno));
}
@@ -671,7 +680,7 @@
return fd;
}
-static void CheckRequirement(const std::string& cur_product, const std::string& var,
+static bool CheckRequirement(const std::string& cur_product, const std::string& var,
const std::string& product, bool invert,
const std::vector<std::string>& options) {
Status("Checking '" + var + "'");
@@ -683,7 +692,7 @@
double split = now();
fprintf(stderr, "IGNORE, product is %s required only for %s [%7.3fs]\n",
cur_product.c_str(), product.c_str(), (split - start));
- return;
+ return true;
}
}
@@ -692,7 +701,7 @@
fprintf(stderr, "FAILED\n\n");
fprintf(stderr, "Could not getvar for '%s' (%s)\n\n", var.c_str(),
fb->Error().c_str());
- die("requirements not met!");
+ return false;
}
bool match = false;
@@ -712,7 +721,7 @@
if (match) {
double split = now();
fprintf(stderr, "OKAY [%7.3fs]\n", (split - start));
- return;
+ return true;
}
fprintf(stderr, "FAILED\n\n");
@@ -722,7 +731,7 @@
fprintf(stderr, " or '%s'", it->c_str());
}
fprintf(stderr, ".\n\n");
- die("requirements not met!");
+ return false;
}
bool ParseRequirementLine(const std::string& line, std::string* name, std::string* product,
@@ -786,7 +795,7 @@
}
}
-static void CheckRequirements(const std::string& data) {
+static void CheckRequirements(const std::string& data, bool force_flash) {
std::string cur_product;
if (fb->GetVar("product", &cur_product) != fastboot::SUCCESS) {
fprintf(stderr, "getvar:product FAILED (%s)\n", fb->Error().c_str());
@@ -810,7 +819,14 @@
if (name == "partition-exists") {
HandlePartitionExists(options);
} else {
- CheckRequirement(cur_product, name, product, invert, options);
+ bool met = CheckRequirement(cur_product, name, product, invert, options);
+ if (!met) {
+ if (!force_flash) {
+ die("requirements not met!");
+ } else {
+ fprintf(stderr, "requirements not met! but proceeding due to --force\n");
+ }
+ }
}
}
}
@@ -902,17 +918,18 @@
return false;
}
- if (sparse_file* s = sparse_file_import(fd, false, false)) {
+ if (sparse_file* s = sparse_file_import(fd.get(), false, false)) {
buf->image_size = sparse_file_len(s, false, false);
sparse_file_destroy(s);
} else {
buf->image_size = sz;
}
- lseek(fd, 0, SEEK_SET);
+ lseek(fd.get(), 0, SEEK_SET);
int64_t limit = get_sparse_limit(sz);
+ buf->fd = std::move(fd);
if (limit) {
- sparse_file** s = load_sparse_files(fd, limit);
+ sparse_file** s = load_sparse_files(buf->fd.get(), limit);
if (s == nullptr) {
return false;
}
@@ -921,7 +938,6 @@
} else {
buf->type = FB_BUFFER_FD;
buf->data = nullptr;
- buf->fd = std::move(fd);
buf->sz = sz;
}
@@ -936,7 +952,7 @@
}
struct stat s;
- if (fstat(fd, &s)) {
+ if (fstat(fd.get(), &s)) {
return false;
}
if (!S_ISREG(s.st_mode)) {
@@ -995,7 +1011,7 @@
die("Failed writing to modified vbmeta");
}
buf->fd = std::move(fd);
- lseek(buf->fd, 0, SEEK_SET);
+ lseek(buf->fd.get(), 0, SEEK_SET);
}
static bool has_vbmeta_partition() {
@@ -1005,6 +1021,11 @@
fb->GetVar("partition-type:vbmeta_b", &partition_type) == fastboot::SUCCESS;
}
+static bool is_logical(const std::string& partition) {
+ std::string value;
+ return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
+}
+
static std::string fb_fix_numeric_var(std::string var) {
// Some bootloaders (angler, for example), send spurious leading whitespace.
var = android::base::Trim(var);
@@ -1017,12 +1038,18 @@
static uint64_t get_partition_size(const std::string& partition) {
std::string partition_size_str;
if (fb->GetVar("partition-size:" + partition, &partition_size_str) != fastboot::SUCCESS) {
+ if (!is_logical(partition)) {
+ return 0;
+ }
die("cannot get partition size for %s", partition.c_str());
}
partition_size_str = fb_fix_numeric_var(partition_size_str);
uint64_t partition_size;
if (!android::base::ParseUint(partition_size_str, &partition_size)) {
+ if (!is_logical(partition)) {
+ return 0;
+ }
die("Couldn't parse partition size '%s'.", partition_size_str.c_str());
}
return partition_size;
@@ -1033,16 +1060,6 @@
return;
}
- // If overflows and negative, it should be < buf->sz.
- int64_t partition_size = static_cast<int64_t>(get_partition_size(partition));
-
- if (partition_size == buf->sz) {
- return;
- }
- if (partition_size < buf->sz) {
- die("boot partition is smaller than boot image");
- }
-
std::string data;
if (!android::base::ReadFdToString(buf->fd, &data)) {
die("Failed reading from boot");
@@ -1052,18 +1069,27 @@
if (0 != data.compare(footer_offset, AVB_FOOTER_MAGIC_LEN, AVB_FOOTER_MAGIC)) {
return;
}
+ // If overflows and negative, it should be < buf->sz.
+ int64_t partition_size = static_cast<int64_t>(get_partition_size(partition));
+
+ if (partition_size == buf->sz) {
+ return;
+ }
+ if (partition_size < buf->sz) {
+ die("boot partition is smaller than boot image");
+ }
unique_fd fd(make_temporary_fd("boot rewriting"));
if (!android::base::WriteStringToFd(data, fd)) {
die("Failed writing to modified boot");
}
- lseek(fd, partition_size - AVB_FOOTER_SIZE, SEEK_SET);
+ lseek(fd.get(), partition_size - AVB_FOOTER_SIZE, SEEK_SET);
if (!android::base::WriteStringToFd(data.substr(footer_offset), fd)) {
die("Failed copying AVB footer in boot");
}
buf->fd = std::move(fd);
buf->sz = partition_size;
- lseek(buf->fd, 0, SEEK_SET);
+ lseek(buf->fd.get(), 0, SEEK_SET);
}
static void flash_buf(const std::string& partition, struct fastboot_buffer *buf)
@@ -1248,11 +1274,6 @@
}
}
-static bool is_logical(const std::string& partition) {
- std::string value;
- return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
-}
-
static bool is_retrofit_device() {
std::string value;
if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) {
@@ -1391,13 +1412,15 @@
class ImageSource {
public:
+ virtual ~ImageSource() {};
virtual bool ReadFile(const std::string& name, std::vector<char>* out) const = 0;
virtual unique_fd OpenFile(const std::string& name) const = 0;
};
class FlashAllTool {
public:
- FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe);
+ FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary,
+ bool wipe, bool force_flash);
void Flash();
@@ -1413,16 +1436,19 @@
std::string slot_override_;
bool skip_secondary_;
bool wipe_;
+ bool force_flash_;
std::string secondary_slot_;
std::vector<std::pair<const Image*, std::string>> boot_images_;
std::vector<std::pair<const Image*, std::string>> os_images_;
};
-FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override, bool skip_secondary, bool wipe)
+FlashAllTool::FlashAllTool(const ImageSource& source, const std::string& slot_override,
+ bool skip_secondary, bool wipe, bool force_flash)
: source_(source),
slot_override_(slot_override),
skip_secondary_(skip_secondary),
- wipe_(wipe)
+ wipe_(wipe),
+ force_flash_(force_flash)
{
}
@@ -1470,7 +1496,7 @@
if (!source_.ReadFile("android-info.txt", &contents)) {
die("could not read android-info.txt");
}
- ::CheckRequirements({contents.data(), contents.size()});
+ ::CheckRequirements({contents.data(), contents.size()}, force_flash_);
}
void FlashAllTool::DetermineSecondarySlot() {
@@ -1538,7 +1564,7 @@
}
void FlashAllTool::UpdateSuperPartition() {
- int fd = source_.OpenFile("super_empty.img");
+ unique_fd fd = source_.OpenFile("super_empty.img");
if (fd < 0) {
return;
}
@@ -1590,14 +1616,15 @@
return unzip_to_file(zip_, name.c_str());
}
-static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary) {
+static void do_update(const char* filename, const std::string& slot_override, bool skip_secondary,
+ bool force_flash) {
ZipArchiveHandle zip;
int error = OpenArchive(filename, &zip);
if (error != 0) {
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
- FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false);
+ FlashAllTool tool(ZipImageSource(zip), slot_override, skip_secondary, false, force_flash);
tool.Flash();
CloseArchive(zip);
@@ -1622,8 +1649,9 @@
return unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_BINARY)));
}
-static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) {
- FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe);
+static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe,
+ bool force_flash) {
+ FlashAllTool tool(LocalImageSource(), slot_override, skip_secondary, wipe, force_flash);
tool.Flash();
}
@@ -2171,9 +2199,9 @@
} else if (command == "flashall") {
if (slot_override == "all") {
fprintf(stderr, "Warning: slot set to 'all'. Secondary slots will not be flashed.\n");
- do_flashall(slot_override, true, wants_wipe);
+ do_flashall(slot_override, true, wants_wipe, force_flash);
} else {
- do_flashall(slot_override, skip_secondary, wants_wipe);
+ do_flashall(slot_override, skip_secondary, wants_wipe, force_flash);
}
wants_reboot = true;
} else if (command == "update") {
@@ -2185,7 +2213,7 @@
if (!args.empty()) {
filename = next_arg(&args);
}
- do_update(filename.c_str(), slot_override, skip_secondary || slot_all);
+ do_update(filename.c_str(), slot_override, skip_secondary || slot_all, force_flash);
wants_reboot = true;
} else if (command == FB_CMD_SET_ACTIVE) {
std::string slot = verify_slot(next_arg(&args), false);
@@ -2197,7 +2225,7 @@
if (!load_buf(filename.c_str(), &buf) || buf.type != FB_BUFFER_FD) {
die("cannot load '%s'", filename.c_str());
}
- fb->Download(filename, buf.fd, buf.sz);
+ fb->Download(filename, buf.fd.get(), buf.sz);
} else if (command == "get_staged") {
std::string filename = next_arg(&args);
fb->Upload(filename);
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index 14ee785..99a4873 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -144,7 +144,8 @@
return Flash(partition);
}
-RetCode FastBootDriver::FlashPartition(const std::string& partition, int fd, uint32_t size) {
+RetCode FastBootDriver::FlashPartition(const std::string& partition, android::base::borrowed_fd fd,
+ uint32_t size) {
RetCode ret;
if ((ret = Download(partition, fd, size))) {
return ret;
@@ -182,15 +183,16 @@
return SUCCESS;
}
-RetCode FastBootDriver::Download(const std::string& name, int fd, size_t size,
- std::string* response, std::vector<std::string>* info) {
+RetCode FastBootDriver::Download(const std::string& name, android::base::borrowed_fd fd,
+ size_t size, std::string* response,
+ std::vector<std::string>* info) {
prolog_(StringPrintf("Sending '%s' (%zu KB)", name.c_str(), size / 1024));
auto result = Download(fd, size, response, info);
epilog_(result);
return result;
}
-RetCode FastBootDriver::Download(int fd, size_t size, std::string* response,
+RetCode FastBootDriver::Download(android::base::borrowed_fd fd, size_t size, std::string* response,
std::vector<std::string>* info) {
RetCode ret;
@@ -521,7 +523,7 @@
}
/******************************* PRIVATE **************************************/
-RetCode FastBootDriver::SendBuffer(int fd, size_t size) {
+RetCode FastBootDriver::SendBuffer(android::base::borrowed_fd fd, size_t size) {
static constexpr uint32_t MAX_MAP_SIZE = 512 * 1024 * 1024;
off64_t offset = 0;
uint32_t remaining = size;
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index f1c094f..bccd668 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -77,9 +77,9 @@
RetCode Continue(std::string* response = nullptr, std::vector<std::string>* info = nullptr);
RetCode CreatePartition(const std::string& partition, const std::string& size);
RetCode DeletePartition(const std::string& partition);
- RetCode Download(const std::string& name, int fd, size_t size, std::string* response = nullptr,
- std::vector<std::string>* info = nullptr);
- RetCode Download(int fd, size_t size, std::string* response = nullptr,
+ RetCode Download(const std::string& name, android::base::borrowed_fd fd, size_t size,
+ std::string* response = nullptr, std::vector<std::string>* info = nullptr);
+ RetCode Download(android::base::borrowed_fd fd, size_t size, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
RetCode Download(const std::string& name, const std::vector<char>& buf,
std::string* response = nullptr, std::vector<std::string>* info = nullptr);
@@ -113,7 +113,8 @@
/* HIGHER LEVEL COMMANDS -- Composed of the commands above */
RetCode FlashPartition(const std::string& partition, const std::vector<char>& data);
- RetCode FlashPartition(const std::string& partition, int fd, uint32_t sz);
+ RetCode FlashPartition(const std::string& partition, android::base::borrowed_fd fd,
+ uint32_t sz);
RetCode FlashPartition(const std::string& partition, sparse_file* s, uint32_t sz,
size_t current, size_t total);
@@ -149,7 +150,7 @@
Transport* transport_;
private:
- RetCode SendBuffer(int fd, size_t size);
+ RetCode SendBuffer(android::base::borrowed_fd fd, size_t size);
RetCode SendBuffer(const std::vector<char>& buf);
RetCode SendBuffer(const void* buf, size_t size);
diff --git a/fastboot/testdata/Android.bp b/fastboot/testdata/Android.bp
index 5debf5e..a490fe2 100644
--- a/fastboot/testdata/Android.bp
+++ b/fastboot/testdata/Android.bp
@@ -12,6 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
python_binary_host {
name: "fastboot_gen_rand",
visibility: [":__subpackages__"],
diff --git a/fastboot/vendor_boot_img_utils.cpp b/fastboot/vendor_boot_img_utils.cpp
index 2db20cd..9e09abb 100644
--- a/fastboot/vendor_boot_img_utils.cpp
+++ b/fastboot/vendor_boot_img_utils.cpp
@@ -184,7 +184,7 @@
if (!android::base::WriteStringToFd(data, fd)) {
return ErrnoErrorf("Cannot write new content to {}", what);
}
- if (TEMP_FAILURE_RETRY(ftruncate64(fd.get(), data.size())) == -1) {
+ if (TEMP_FAILURE_RETRY(ftruncate(fd.get(), data.size())) == -1) {
return ErrnoErrorf("Truncating new vendor boot image to 0x{:x} fails", data.size());
}
return {};
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6952cdf..bbbb7e8 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -647,6 +647,46 @@
return sb == cpu_to_le32(F2FS_SUPER_MAGIC);
}
+static void SetReadAheadSize(const std::string& entry_block_device, off64_t size_kb) {
+ std::string block_device;
+ if (!Realpath(entry_block_device, &block_device)) {
+ PERROR << "Failed to realpath " << entry_block_device;
+ return;
+ }
+
+ static constexpr std::string_view kDevBlockPrefix("/dev/block/");
+ if (!android::base::StartsWith(block_device, kDevBlockPrefix)) {
+ LWARNING << block_device << " is not a block device";
+ return;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ while (true) {
+ std::string block_name = block_device;
+ if (android::base::StartsWith(block_device, kDevBlockPrefix)) {
+ block_name = block_device.substr(kDevBlockPrefix.length());
+ }
+ std::string sys_partition =
+ android::base::StringPrintf("/sys/class/block/%s/partition", block_name.c_str());
+ struct stat info;
+ if (lstat(sys_partition.c_str(), &info) == 0) {
+ // it has a partition like "sda12".
+ block_name += "/..";
+ }
+ std::string sys_ra = android::base::StringPrintf("/sys/class/block/%s/queue/read_ahead_kb",
+ block_name.c_str());
+ std::string size = android::base::StringPrintf("%llu", (long long)size_kb);
+ android::base::WriteStringToFile(size, sys_ra.c_str());
+ LINFO << "Set readahead_kb: " << size << " on " << sys_ra;
+
+ auto parent = dm.GetParentBlockDeviceByPath(block_device);
+ if (!parent) {
+ return;
+ }
+ block_device = *parent;
+ }
+}
+
//
// Prepare the filesystem on the given block device to be mounted.
//
@@ -667,6 +707,11 @@
}
mkdir(mount_point.c_str(), 0755);
+ // Don't need to return error, since it's a salt
+ if (entry.readahead_size_kb != -1) {
+ SetReadAheadSize(blk_device, entry.readahead_size_kb);
+ }
+
int fs_stat = 0;
if (is_extfs(entry.fs_type)) {
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0c0862e..42bf356 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -17,6 +17,7 @@
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
+#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -254,6 +255,13 @@
} else {
entry->reserved_size = static_cast<off64_t>(size);
}
+ } else if (StartsWith(flag, "readahead_size_kb=")) {
+ int val;
+ if (ParseInt(arg, &val, 0, 16 * 1024)) {
+ entry->readahead_size_kb = val;
+ } else {
+ LWARNING << "Warning: readahead_size_kb= flag malformed (0 ~ 16MB): " << arg;
+ }
} else if (StartsWith(flag, "eraseblk=")) {
// The erase block size flag is followed by an = and the flash erase block size. Get it,
// check that it is a power of 2 and at least 4096, and return it.
@@ -680,7 +688,7 @@
}
}
-bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
+bool ReadFstabFromFile(const std::string& path, Fstab* fstab_out) {
auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
if (!fstab_file) {
PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
@@ -689,41 +697,51 @@
bool is_proc_mounts = path == "/proc/mounts";
- if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, fstab)) {
+ Fstab fstab;
+ if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, &fstab)) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
return false;
}
- if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
- // This is expected to fail if host is android Q, since Q doesn't
- // support DSU slotting. The DSU "active" indicator file would be
- // non-existent or empty if DSU is enabled within the guest system.
- // In that case, just use the default slot name "dsu".
- std::string dsu_slot;
- if (!android::gsi::GetActiveDsu(&dsu_slot)) {
- PWARNING << __FUNCTION__ << "(): failed to get active dsu slot";
+ if (!is_proc_mounts) {
+ if (!access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
+ // This is expected to fail if host is android Q, since Q doesn't
+ // support DSU slotting. The DSU "active" indicator file would be
+ // non-existent or empty if DSU is enabled within the guest system.
+ // In that case, just use the default slot name "dsu".
+ std::string dsu_slot;
+ if (!android::gsi::GetActiveDsu(&dsu_slot) && errno != ENOENT) {
+ PERROR << __FUNCTION__ << "(): failed to get active DSU slot";
+ return false;
+ }
+ if (dsu_slot.empty()) {
+ dsu_slot = "dsu";
+ LWARNING << __FUNCTION__ << "(): assuming default DSU slot: " << dsu_slot;
+ }
+ // This file is non-existent on Q vendor.
+ std::string lp_names;
+ if (!ReadFileToString(gsi::kGsiLpNamesFile, &lp_names) && errno != ENOENT) {
+ PERROR << __FUNCTION__ << "(): failed to read DSU LP names";
+ return false;
+ }
+ TransformFstabForDsu(&fstab, dsu_slot, Split(lp_names, ","));
+ } else if (errno != ENOENT) {
+ PERROR << __FUNCTION__ << "(): failed to access() DSU booted indicator";
+ return false;
}
- if (dsu_slot.empty()) {
- dsu_slot = "dsu";
- }
-
- std::string lp_names;
- ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
- TransformFstabForDsu(fstab, dsu_slot, Split(lp_names, ","));
}
-#ifndef NO_SKIP_MOUNT
- SkipMountingPartitions(fstab);
-#endif
- EnableMandatoryFlags(fstab);
+ SkipMountingPartitions(&fstab, false /* verbose */);
+ EnableMandatoryFlags(&fstab);
+ *fstab_out = std::move(fstab);
return true;
}
// Returns fstab entries parsed from the device tree if they exist
-bool ReadFstabFromDt(Fstab* fstab, bool log) {
+bool ReadFstabFromDt(Fstab* fstab, bool verbose) {
std::string fstab_buf = ReadFstabFromDt();
if (fstab_buf.empty()) {
- if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
+ if (verbose) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
return false;
}
@@ -731,34 +749,36 @@
fmemopen(static_cast<void*>(const_cast<char*>(fstab_buf.c_str())),
fstab_buf.length(), "r"), fclose);
if (!fstab_file) {
- if (log) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
+ if (verbose) PERROR << __FUNCTION__ << "(): failed to create a file stream for fstab dt";
return false;
}
if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
- if (log) {
+ if (verbose) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
<< fstab_buf;
}
return false;
}
-#ifndef NO_SKIP_MOUNT
- SkipMountingPartitions(fstab);
-#endif
+ SkipMountingPartitions(fstab, verbose);
return true;
}
-#ifndef NO_SKIP_MOUNT
+#ifdef NO_SKIP_MOUNT
+bool SkipMountingPartitions(Fstab*, bool) {
+ return true;
+}
+#else
// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
// device-specific /product and /system_ext. skip_mount.cfg belongs to system_ext partition because
// only common files for all targets can be put into system partition. It is under
// /system/system_ext because GSI is a single system.img that includes the contents of system_ext
// partition and product partition under /system/system_ext and /system/product, respectively.
-bool SkipMountingPartitions(Fstab* fstab) {
- constexpr const char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
+bool SkipMountingPartitions(Fstab* fstab, bool verbose) {
+ static constexpr char kSkipMountConfig[] = "/system/system_ext/etc/init/config/skip_mount.cfg";
std::string skip_config;
auto save_errno = errno;
@@ -767,29 +787,39 @@
return true;
}
- for (const auto& skip_mount_point : Split(skip_config, "\n")) {
- if (skip_mount_point.empty()) {
+ std::vector<std::string> skip_mount_patterns;
+ for (const auto& line : Split(skip_config, "\n")) {
+ if (line.empty() || StartsWith(line, "#")) {
continue;
}
- auto it = std::remove_if(fstab->begin(), fstab->end(),
- [&skip_mount_point](const auto& entry) {
- return entry.mount_point == skip_mount_point;
- });
- if (it == fstab->end()) continue;
- fstab->erase(it, fstab->end());
- LOG(INFO) << "Skip mounting partition: " << skip_mount_point;
+ skip_mount_patterns.push_back(line);
}
+ // Returns false if mount_point matches any of the skip mount patterns, so that the FstabEntry
+ // would be partitioned to the second group.
+ auto glob_pattern_mismatch = [&skip_mount_patterns](const FstabEntry& entry) -> bool {
+ for (const auto& pattern : skip_mount_patterns) {
+ if (!fnmatch(pattern.c_str(), entry.mount_point.c_str(), 0 /* flags */)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ auto remove_from = std::stable_partition(fstab->begin(), fstab->end(), glob_pattern_mismatch);
+ if (verbose) {
+ for (auto it = remove_from; it != fstab->end(); ++it) {
+ LINFO << "Skip mounting mountpoint: " << it->mount_point;
+ }
+ }
+ fstab->erase(remove_from, fstab->end());
return true;
}
#endif
// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {
- Fstab dt_fstab;
- ReadFstabFromDt(&dt_fstab, false);
-
- *fstab = std::move(dt_fstab);
+ fstab->clear();
+ ReadFstabFromDt(fstab, false /* verbose */);
std::string default_fstab_path;
// Use different fstab paths for normal boot and recovery boot, respectively
@@ -800,16 +830,14 @@
}
Fstab default_fstab;
- if (!default_fstab_path.empty()) {
- ReadFstabFromFile(default_fstab_path, &default_fstab);
+ if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
+ for (auto&& entry : default_fstab) {
+ fstab->emplace_back(std::move(entry));
+ }
} else {
LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
- for (auto&& entry : default_fstab) {
- fstab->emplace_back(std::move(entry));
- }
-
return !fstab->empty();
}
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 2d4de09..2704e47 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -47,6 +47,7 @@
int max_comp_streams = 0;
off64_t zram_size = 0;
off64_t reserved_size = 0;
+ off64_t readahead_size_kb = -1;
std::string encryption_options;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
@@ -97,9 +98,9 @@
using Fstab = std::vector<FstabEntry>;
bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
-bool ReadFstabFromDt(Fstab* fstab, bool log = true);
+bool ReadFstabFromDt(Fstab* fstab, bool verbose = true);
bool ReadDefaultFstab(Fstab* fstab);
-bool SkipMountingPartitions(Fstab* fstab);
+bool SkipMountingPartitions(Fstab* fstab, bool verbose = false);
FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
// The Fstab can contain multiple entries for the same mount point with different configurations.
diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
index 50f4f33..7e30509 100644
--- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h
+++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
@@ -198,7 +198,7 @@
~MappedDevice();
- int fd() const { return fd_; }
+ int fd() const { return fd_.get(); }
const std::string& path() const { return path_; }
protected:
diff --git a/fs_mgr/libfs_avb/TEST_MAPPING b/fs_mgr/libfs_avb/TEST_MAPPING
deleted file mode 100644
index b0f36d4..0000000
--- a/fs_mgr/libfs_avb/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "postsubmit": [
- {
- "name": "libfs_avb_test",
- "host": true
- },
- {
- "name": "libfs_avb_internal_test",
- "host": true
- }
- ]
-}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index ea92d25..3cb4123 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -264,6 +264,7 @@
"android.hardware.boot@1.0",
"android.hardware.boot@1.1",
"libbrotli",
+ "libc++fs",
"libfs_mgr",
"libgsi",
"libgmock",
@@ -297,6 +298,7 @@
],
static_libs: [
"libbrotli",
+ "libc++fs",
"libfstab",
"libsnapshot",
"libsnapshot_cow",
@@ -326,6 +328,7 @@
"power_test.cpp",
],
static_libs: [
+ "libc++fs",
"libsnapshot",
"update_metadata-protos",
],
@@ -355,6 +358,7 @@
static_libs: [
"libbase",
"libbrotli",
+ "libc++fs",
"libchrome",
"libcrypto_static",
"libcutils",
@@ -416,7 +420,7 @@
"snapuserd_server.cpp",
"snapuserd.cpp",
"snapuserd_daemon.cpp",
- "snapuserd_worker.cpp",
+ "snapuserd_worker.cpp",
],
cflags: [
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
new file mode 100644
index 0000000..ac2c787
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2021 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 <memory>
+
+#include <gmock/gmock.h>
+#include <libsnapshot/snapshot_stats.h>
+
+namespace android::snapshot {
+
+class MockSnapshotMergeStats final : public ISnapshotMergeStats {
+ public:
+ virtual ~MockSnapshotMergeStats() = default;
+ // Called when merge starts or resumes.
+ MOCK_METHOD(bool, Start, (), (override));
+ MOCK_METHOD(void, set_state, (android::snapshot::UpdateState, bool), (override));
+ MOCK_METHOD(void, set_cow_file_size, (uint64_t), ());
+ MOCK_METHOD(void, set_total_cow_size_bytes, (uint64_t), (override));
+ MOCK_METHOD(void, set_estimated_cow_size_bytes, (uint64_t), (override));
+ MOCK_METHOD(void, set_boot_complete_time_ms, (uint32_t), (override));
+ MOCK_METHOD(void, set_boot_complete_to_merge_start_time_ms, (uint32_t), (override));
+ MOCK_METHOD(uint64_t, cow_file_size, (), (override));
+ MOCK_METHOD(uint64_t, total_cow_size_bytes, (), (override));
+ MOCK_METHOD(uint64_t, estimated_cow_size_bytes, (), (override));
+ MOCK_METHOD(uint32_t, boot_complete_time_ms, (), (override));
+ MOCK_METHOD(uint32_t, boot_complete_to_merge_start_time_ms, (), (override));
+ MOCK_METHOD(std::unique_ptr<Result>, Finish, (), (override));
+
+ using ISnapshotMergeStats::Result;
+ // Return nullptr if any failure.
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 7e74fac..126e1a0 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -493,6 +493,9 @@
// Unmap a COW image device previously mapped with MapCowImage().
bool UnmapCowImage(const std::string& name);
+ // Unmap a COW and remove it from a MetadataBuilder.
+ void UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata);
+
// Unmap and remove all known snapshots.
bool RemoveAllSnapshots(LockedFile* lock);
@@ -738,6 +741,10 @@
// Helper of UpdateUsesCompression
bool UpdateUsesCompression(LockedFile* lock);
+ // Wrapper around libdm, with diagnostics.
+ bool DeleteDeviceIfExists(const std::string& name,
+ const std::chrono::milliseconds& timeout_ms = {});
+
std::string gsid_dir_;
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
index 1dab361..280e857 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -69,6 +69,8 @@
// must ONLY be called if the control device has already been deleted.
bool WaitForDeviceDelete(const std::string& control_device);
+ void CloseConnection() { sockfd_ = {}; }
+
// Detach snapuserd. This shuts down the listener socket, and will cause
// snapuserd to gracefully exit once all handler threads have terminated.
// This should only be used on first-stage instances of snapuserd.
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index bd1e284..c504355 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <sys/unistd.h>
+#include <filesystem>
#include <optional>
#include <thread>
#include <unordered_set>
@@ -587,8 +588,7 @@
bool SnapshotManager::UnmapSnapshot(LockedFile* lock, const std::string& name) {
CHECK(lock);
- auto& dm = DeviceMapper::Instance();
- if (!dm.DeleteDeviceIfExists(name)) {
+ if (!DeleteDeviceIfExists(name)) {
LOG(ERROR) << "Could not delete snapshot device: " << name;
return false;
}
@@ -1252,25 +1252,6 @@
return true;
}
-static bool DeleteDmDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
- auto start = std::chrono::steady_clock::now();
- auto& dm = DeviceMapper::Instance();
- while (true) {
- if (dm.DeleteDeviceIfExists(name)) {
- break;
- }
- auto now = std::chrono::steady_clock::now();
- auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
- if (elapsed >= timeout_ms) {
- LOG(ERROR) << "DeleteDevice timeout: " << name;
- return false;
- }
- std::this_thread::sleep_for(400ms);
- }
-
- return true;
-}
-
bool SnapshotManager::CollapseSnapshotDevice(const std::string& name,
const SnapshotStatus& status) {
auto& dm = DeviceMapper::Instance();
@@ -1326,11 +1307,11 @@
UnmapDmUserDevice(name);
}
auto base_name = GetBaseDeviceName(name);
- if (!dm.DeleteDeviceIfExists(base_name)) {
+ if (!DeleteDeviceIfExists(base_name)) {
LOG(ERROR) << "Unable to delete base device for snapshot: " << base_name;
}
- if (!DeleteDmDevice(GetSourceDeviceName(name), 4000ms)) {
+ if (!DeleteDeviceIfExists(GetSourceDeviceName(name), 4000ms)) {
LOG(ERROR) << "Unable to delete source device for snapshot: " << GetSourceDeviceName(name);
}
@@ -1619,6 +1600,18 @@
// as dm-snapshot (for example, after merge completes).
bool should_unmap = current_slot != Slot::Target;
bool should_delete = ShouldDeleteSnapshot(flashing_status, current_slot, name);
+ if (should_unmap && android::base::EndsWith(name, device_->GetSlotSuffix())) {
+ // Something very unexpected has happened - we want to unmap this
+ // snapshot, but it's on the wrong slot. We can't unmap an active
+ // partition. If this is not really a snapshot, skip the unmap
+ // step.
+ auto& dm = DeviceMapper::Instance();
+ if (dm.GetState(name) == DmDeviceState::INVALID || !IsSnapshotDevice(name)) {
+ LOG(ERROR) << "Detected snapshot " << name << " on " << current_slot << " slot"
+ << " for source partition; removing without unmap.";
+ should_unmap = false;
+ }
+ }
bool partition_ok = true;
if (should_unmap && !UnmapPartitionWithSnapshot(lock, name)) {
@@ -2071,15 +2064,14 @@
return false;
}
- auto& dm = DeviceMapper::Instance();
auto base_name = GetBaseDeviceName(target_partition_name);
- if (!dm.DeleteDeviceIfExists(base_name)) {
+ if (!DeleteDeviceIfExists(base_name)) {
LOG(ERROR) << "Cannot delete base device: " << base_name;
return false;
}
auto source_name = GetSourceDeviceName(target_partition_name);
- if (!dm.DeleteDeviceIfExists(source_name)) {
+ if (!DeleteDeviceIfExists(source_name)) {
LOG(ERROR) << "Cannot delete source device: " << source_name;
return false;
}
@@ -2169,7 +2161,7 @@
return false;
}
- if (!DeleteDmDevice(GetCowName(name), 4000ms)) {
+ if (!DeleteDeviceIfExists(GetCowName(name), 4000ms)) {
LOG(ERROR) << "Cannot unmap: " << GetCowName(name);
return false;
}
@@ -2190,7 +2182,7 @@
return true;
}
- if (!dm.DeleteDeviceIfExists(dm_user_name)) {
+ if (!DeleteDeviceIfExists(dm_user_name)) {
LOG(ERROR) << "Cannot unmap " << dm_user_name;
return false;
}
@@ -2285,6 +2277,17 @@
return false;
}
}
+
+ // Terminate the daemon and release the snapuserd_client_ object.
+ // If we need to re-connect with the daemon, EnsureSnapuserdConnected()
+ // will re-create the object and establish the socket connection.
+ if (snapuserd_client_) {
+ LOG(INFO) << "Shutdown snapuserd daemon";
+ snapuserd_client_->DetachSnapuserd();
+ snapuserd_client_->CloseConnection();
+ snapuserd_client_ = nullptr;
+ }
+
return true;
}
@@ -2570,11 +2573,10 @@
return true;
}
-static void UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata) {
- auto& dm = DeviceMapper::Instance();
+void SnapshotManager::UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata) {
std::vector<std::string> to_delete;
for (auto* existing_cow_partition : current_metadata->ListPartitionsInGroup(kCowGroupName)) {
- if (!dm.DeleteDeviceIfExists(existing_cow_partition->name())) {
+ if (!DeleteDeviceIfExists(existing_cow_partition->name())) {
LOG(WARNING) << existing_cow_partition->name()
<< " cannot be unmapped and its space cannot be reclaimed";
continue;
@@ -3603,5 +3605,71 @@
stats->set_estimated_cow_size_bytes(estimated_cow_size);
}
+bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
+ const std::chrono::milliseconds& timeout_ms) {
+ auto& dm = DeviceMapper::Instance();
+ auto start = std::chrono::steady_clock::now();
+ while (true) {
+ if (dm.DeleteDeviceIfExists(name)) {
+ return true;
+ }
+ auto now = std::chrono::steady_clock::now();
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
+ if (elapsed >= timeout_ms) {
+ break;
+ }
+ std::this_thread::sleep_for(400ms);
+ }
+
+ // Try to diagnose why this failed. First get the actual device path.
+ std::string full_path;
+ if (!dm.GetDmDevicePathByName(name, &full_path)) {
+ LOG(ERROR) << "Unable to diagnose DM_DEV_REMOVE failure.";
+ return false;
+ }
+
+ // Check for child dm-devices.
+ std::string block_name = android::base::Basename(full_path);
+ std::string sysfs_holders = "/sys/class/block/" + block_name + "/holders";
+
+ std::error_code ec;
+ std::filesystem::directory_iterator dir_iter(sysfs_holders, ec);
+ if (auto begin = std::filesystem::begin(dir_iter); begin != std::filesystem::end(dir_iter)) {
+ LOG(ERROR) << "Child device-mapper device still mapped: " << begin->path();
+ return false;
+ }
+
+ // Check for mounted partitions.
+ android::fs_mgr::Fstab fstab;
+ android::fs_mgr::ReadFstabFromFile("/proc/mounts", &fstab);
+ for (const auto& entry : fstab) {
+ if (android::base::Basename(entry.blk_device) == block_name) {
+ LOG(ERROR) << "Partition still mounted: " << entry.mount_point;
+ return false;
+ }
+ }
+
+ // Check for detached mounted partitions.
+ for (const auto& fs : std::filesystem::directory_iterator("/sys/fs", ec)) {
+ std::string fs_type = android::base::Basename(fs.path().c_str());
+ if (!(fs_type == "ext4" || fs_type == "f2fs")) {
+ continue;
+ }
+
+ std::string path = fs.path().c_str() + "/"s + block_name;
+ if (access(path.c_str(), F_OK) == 0) {
+ LOG(ERROR) << "Block device was lazily unmounted and is still in-use: " << full_path
+ << "; possibly open file descriptor or attached loop device.";
+ return false;
+ }
+ }
+
+ LOG(ERROR) << "Device-mapper device " << name << "(" << full_path << ")"
+ << " still in use."
+ << " Probably a file descriptor was leaked or held open, or a loop device is"
+ << " attached.";
+ return false;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 25500b5..8fae00b 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2019,6 +2019,36 @@
// Read bytes back and verify they match the cache.
ASSERT_TRUE(IsPartitionUnchanged("sys_b"));
+
+ ASSERT_TRUE(sm->UnmapAllSnapshots());
+}
+
+TEST_F(SnapshotUpdateTest, CancelOnTargetSlot) {
+ AddOperationForPartitions();
+
+ // Execute the update from B->A.
+ test_device->set_slot_suffix("_b");
+ ASSERT_TRUE(sm->BeginUpdate());
+ ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+ std::string path;
+ ASSERT_TRUE(CreateLogicalPartition(
+ CreateLogicalPartitionParams{
+ .block_device = fake_super,
+ .metadata_slot = 0,
+ .partition_name = "sys_a",
+ .timeout_ms = 1s,
+ .partition_opener = opener_.get(),
+ },
+ &path));
+
+ // Hold sys_a open so it can't be unmapped.
+ unique_fd fd(open(path.c_str(), O_RDONLY));
+
+ // Switch back to "A", make sure we can cancel. Instead of unmapping sys_a
+ // we should simply delete the old snapshots.
+ test_device->set_slot_suffix("_a");
+ ASSERT_TRUE(sm->BeginUpdate());
}
class FlashAfterUpdateTest : public SnapshotUpdateTest,
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index a44de84..5eb2003 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -48,6 +48,17 @@
return SnapshotManager::New()->Dump(std::cout);
}
+bool MapCmdHandler(int, char** argv) {
+ android::base::InitLogging(argv, &android::base::StderrLogger);
+ using namespace std::chrono_literals;
+ return SnapshotManager::New()->MapAllSnapshots(5000ms);
+}
+
+bool UnmapCmdHandler(int, char** argv) {
+ android::base::InitLogging(argv, &android::base::StderrLogger);
+ return SnapshotManager::New()->UnmapAllSnapshots();
+}
+
bool MergeCmdHandler(int /*argc*/, char** argv) {
android::base::InitLogging(argv, &android::base::StderrLogger);
LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
@@ -58,6 +69,8 @@
// clang-format off
{"dump", DumpCmdHandler},
{"merge", MergeCmdHandler},
+ {"map", MapCmdHandler},
+ {"unmap", UnmapCmdHandler},
// clang-format on
};
diff --git a/fs_mgr/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h
index 9335364..87c5528 100644
--- a/fs_mgr/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd.h
@@ -158,6 +158,7 @@
bool CommitMerge(int num_merge_ops);
void CloseFds() { cow_fd_ = {}; }
+ void FreeResources() { worker_threads_.clear(); }
size_t GetMetadataAreaSize() { return vec_.size(); }
void* GetExceptionBuffer(size_t i) { return vec_[i].get(); }
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 167895e..64332d1 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -219,7 +219,13 @@
auto iter = FindHandler(&lock, handler->misc_name());
if (iter == dm_users_.end()) {
// RemoveAndJoinHandler() already removed us from the list, and is
- // now waiting on a join(), so just return.
+ // now waiting on a join(), so just return. Additionally, release
+ // all the resources held by snapuserd object which are shared
+ // by worker threads. This should be done when the last reference
+ // of "handler" is released; but we will explicitly release here
+ // to make sure snapuserd object is freed as it is the biggest
+ // consumer of memory in the daemon.
+ handler->FreeResources();
LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name;
return;
}
diff --git a/fs_mgr/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd_server.h
index e9d575d..6699189 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd_server.h
@@ -49,7 +49,15 @@
public:
explicit DmUserHandler(std::shared_ptr<Snapuserd> snapuserd);
- void FreeResources() { snapuserd_ = nullptr; }
+ void FreeResources() {
+ // Each worker thread holds a reference to snapuserd.
+ // Clear them so that all the resources
+ // held by snapuserd is released
+ if (snapuserd_) {
+ snapuserd_->FreeResources();
+ snapuserd_ = nullptr;
+ }
+ }
const std::shared_ptr<Snapuserd>& snapuserd() const { return snapuserd_; }
std::thread& thread() { return thread_; }
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 5887641..9adb6bd 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -1097,3 +1097,59 @@
ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
<< "/data wasn't mounted from default fstab";
}
+
+TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ std::string fstab_contents = R"fs(
+source none0 swap defaults readahead_size_kb=blah
+source none1 swap defaults readahead_size_kb=128
+source none2 swap defaults readahead_size_kb=5%
+source none3 swap defaults readahead_size_kb=5kb
+source none4 swap defaults readahead_size_kb=16385
+source none5 swap defaults readahead_size_kb=-128
+source none6 swap defaults readahead_size_kb=0
+)fs";
+ ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
+
+ Fstab fstab;
+ EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
+ ASSERT_EQ(7U, fstab.size());
+
+ FstabEntry::FsMgrFlags flags = {};
+
+ auto entry = fstab.begin();
+ EXPECT_EQ("none0", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none1", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(128, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none2", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none3", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none4", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none5", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(-1, entry->readahead_size_kb);
+ entry++;
+
+ EXPECT_EQ("none6", entry->mount_point);
+ EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
+ EXPECT_EQ(0, entry->readahead_size_kb);
+}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a11bb28..3faf430 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -97,7 +97,6 @@
bool MountPartitions();
bool TrySwitchSystemAsRoot();
- bool TrySkipMountingPartitions();
bool IsDmLinearEnabled();
void GetSuperDeviceName(std::set<std::string>* devices);
bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
@@ -534,7 +533,7 @@
bool FirstStageMount::MountPartitions() {
if (!TrySwitchSystemAsRoot()) return false;
- if (!SkipMountingPartitions(&fstab_)) return false;
+ if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false;
for (auto current = fstab_.begin(); current != fstab_.end();) {
// We've already mounted /system above.
diff --git a/init/init.cpp b/init/init.cpp
index 7264b22..a7325ca 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -849,21 +849,6 @@
auto is_installed = android::gsi::IsGsiInstalled() ? "1" : "0";
SetProperty(gsi::kGsiInstalledProp, is_installed);
- /*
- * For debug builds of S launching devices, init mounts debugfs for
- * enabling vendor debug data collection setup at boot time. Init will unmount it on
- * boot-complete after vendor code has performed the required initializations
- * during boot. Dumpstate will then mount debugfs in order to read data
- * from the same using the dumpstate HAL during bugreport creation.
- * Dumpstate will also unmount debugfs after bugreport creation.
- * first_api_level comparison is done here instead
- * of init.rc since init.rc parser does not support >/< operators.
- */
- auto api_level = android::base::GetIntProperty("ro.product.first_api_level", 0);
- bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
- auto mount_debugfs = (is_debuggable && (api_level >= 31)) ? "1" : "0";
- SetProperty("init.mount_debugfs", mount_debugfs);
-
am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups");
am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
am.QueueBuiltinAction(TestPerfEventSelinuxAction, "TestPerfEventSelinux");
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 382f430..c2eb73c 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1165,15 +1165,57 @@
constexpr auto ANDROIDBOOT_PREFIX = "androidboot."sv;
+// emulator specific, should be removed once emulator is migrated to
+// bootconfig, see b/182291166.
+static std::string RemapEmulatorPropertyName(const std::string_view qemu_key) {
+ if (StartsWith(qemu_key, "dalvik."sv) || StartsWith(qemu_key, "opengles."sv) ||
+ StartsWith(qemu_key, "config."sv)) {
+ return std::string(qemu_key);
+ } else if (qemu_key == "uirenderer"sv) {
+ return "debug.hwui.renderer"s;
+ } else if (qemu_key == "media.ccodec"sv) {
+ return "debug.stagefright.ccodec"s;
+ } else {
+ return "qemu."s + std::string(qemu_key);
+ }
+}
+
static void ProcessKernelCmdline() {
ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ constexpr auto qemu_prefix = "qemu."sv;
+
if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
- } else if (StartsWith(key, "qemu."sv)) {
- InitPropertySet("ro.kernel." + key, value);
- } else if (key == "qemu") {
+ } else if (StartsWith(key, qemu_prefix)) {
InitPropertySet("ro.kernel." + key, value); // emulator specific, deprecated
+
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
+ const auto new_name =
+ RemapEmulatorPropertyName(std::string_view(key).substr(qemu_prefix.size()));
+ if (!new_name.empty()) {
+ InitPropertySet("ro.boot." + new_name, value);
+ }
+ } else if (key == "qemu") {
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
InitPropertySet("ro.boot." + key, value);
+ } else if (key == "android.bootanim" && value == "0") {
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
+ InitPropertySet("ro.boot.debug.sf.nobootanimation", "1");
+ } else if (key == "android.checkjni") {
+ // emulator specific, should be retired once emulator migrates to
+ // androidboot.
+ std::string value_bool;
+ if (value == "0") {
+ value_bool = "false";
+ } else if (value == "1") {
+ value_bool = "true";
+ } else {
+ value_bool = value;
+ }
+ InitPropertySet("ro.boot.dalvik.vm.checkjni", value_bool);
}
});
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index b417396..35a96f9 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -667,7 +667,7 @@
extra_fstab.emplace_back(std::move(entry));
}
- SkipMountingPartitions(&extra_fstab);
+ SkipMountingPartitions(&extra_fstab, true /* verbose */);
if (extra_fstab.empty()) {
return;
}
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index cab988b..2221228 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -106,10 +106,10 @@
}
if (std::find_if(external_firmware_handlers->begin(), external_firmware_handlers->end(),
- [&args](const auto& other) { return other.devpath == args[2]; }) !=
+ [&args](const auto& other) { return other.devpath == args[1]; }) !=
external_firmware_handlers->end()) {
return Error() << "found a previous external_firmware_handler with the same devpath, '"
- << args[2] << "'";
+ << args[1] << "'";
}
passwd* pwd = getpwnam(args[2].c_str());
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index b604c53..4e63ba5 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -45,6 +45,13 @@
EXPECT_EQ(expected.attribute_, test.attribute_);
}
+void TestExternalFirmwareHandler(const ExternalFirmwareHandler& expected,
+ const ExternalFirmwareHandler& test) {
+ EXPECT_EQ(expected.devpath, test.devpath) << expected.devpath;
+ EXPECT_EQ(expected.uid, test.uid) << expected.uid;
+ EXPECT_EQ(expected.handler_path, test.handler_path) << expected.handler_path;
+}
+
template <typename T, typename F>
void TestVector(const T& expected, const T& test, F function) {
ASSERT_EQ(expected.size(), test.size());
@@ -67,6 +74,8 @@
TestVector(expected.sysfs_permissions, result.sysfs_permissions, TestSysfsPermissions);
TestVector(expected.dev_permissions, result.dev_permissions, TestPermissions);
EXPECT_EQ(expected.firmware_directories, result.firmware_directories);
+ TestVector(expected.external_firmware_handlers, result.external_firmware_handlers,
+ TestExternalFirmwareHandler);
}
TEST(ueventd_parser, EmptyFile) {
@@ -144,7 +153,7 @@
auto ueventd_file = R"(
external_firmware_handler devpath root handler_path
external_firmware_handler /devices/path/firmware/something001.bin system /vendor/bin/firmware_handler.sh
-external_firmware_handler /devices/path/firmware/something001.bin radio "/vendor/bin/firmware_handler.sh --has --arguments"
+external_firmware_handler /devices/path/firmware/something002.bin radio "/vendor/bin/firmware_handler.sh --has --arguments"
)";
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
@@ -159,7 +168,7 @@
"/vendor/bin/firmware_handler.sh",
},
{
- "/devices/path/firmware/something001.bin",
+ "/devices/path/firmware/something002.bin",
AID_RADIO,
"/vendor/bin/firmware_handler.sh --has --arguments",
},
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 0d9f2c7..0f3763c 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -354,3 +354,17 @@
defaults: ["libcutils_test_static_defaults"],
test_config: "KernelLibcutilsTest.xml",
}
+
+rust_bindgen {
+ name: "libcutils_bindgen",
+ wrapper_src: "rust/cutils.h",
+ crate_name: "cutils_bindgen",
+ source_stem: "bindings",
+ local_include_dirs: ["include"],
+ bindgen_flags: [
+ "--whitelist-function", "multiuser_get_app_id",
+ "--whitelist-function", "multiuser_get_user_id",
+ "--whitelist-function", "multiuser_get_uid",
+ "--whitelist-var", "AID_USER_OFFSET",
+ ],
+}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index d69c038..e9497a8 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -86,7 +86,7 @@
{ 00751, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
- { 00751, AID_ROOT, AID_SHELL, 0, "system/xbin" },
+ { 00750, AID_ROOT, AID_SHELL, 0, "system/xbin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system/apex/*/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system_ext/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system_ext/apex/*/bin" },
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index b4fe2e6..7489281 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -127,6 +127,7 @@
#define AID_EXT_DATA_RW 1078 /* GID for app-private data directories on external storage */
#define AID_EXT_OBB_RW 1079 /* GID for OBB directories on external storage */
#define AID_CONTEXT_HUB 1080 /* GID for access to the Context Hub */
+#define AID_VIRTMANAGER 1081 /* VirtManager 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/libcutils/rust/cutils.h b/libcutils/rust/cutils.h
new file mode 100644
index 0000000..9b78af6
--- /dev/null
+++ b/libcutils/rust/cutils.h
@@ -0,0 +1,4 @@
+#pragma once
+
+#include <cutils/multiuser.h>
+#include <private/android_filesystem_config.h>
diff --git a/libmodprobe/OWNERS b/libmodprobe/OWNERS
index e6b5bba..a6796cb 100644
--- a/libmodprobe/OWNERS
+++ b/libmodprobe/OWNERS
@@ -1 +1,2 @@
-smuckle@google.com
+dvander@google.com
+willmcvicker@google.com
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index baee4f9..c934860 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -24,7 +24,8 @@
class Modprobe {
public:
- Modprobe(const std::vector<std::string>&, const std::string load_file = "modules.load");
+ Modprobe(const std::vector<std::string>&, const std::string load_file = "modules.load",
+ bool use_blocklist = true);
bool LoadListedModules(bool strict = true);
bool LoadWithAliases(const std::string& module_name, bool strict,
@@ -36,7 +37,6 @@
std::vector<std::string>* post_dependencies);
void ResetModuleCount() { module_count_ = 0; }
int GetModuleCount() { return module_count_; }
- void EnableBlocklist(bool enable);
private:
std::string MakeCanonical(const std::string& module_path);
@@ -48,6 +48,7 @@
void AddOption(const std::string& module_name, const std::string& option_name,
const std::string& value);
std::string GetKernelCmdline();
+ bool IsBlocklisted(const std::string& module_name);
bool ParseDepCallback(const std::string& base_path, const std::vector<std::string>& args);
bool ParseAliasCallback(const std::vector<std::string>& args);
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index b3ae937..1a9d364 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -313,7 +313,9 @@
}
}
-Modprobe::Modprobe(const std::vector<std::string>& base_paths, const std::string load_file) {
+Modprobe::Modprobe(const std::vector<std::string>& base_paths, const std::string load_file,
+ bool use_blocklist)
+ : blocklist_enabled(use_blocklist) {
using namespace std::placeholders;
for (const auto& base_path : base_paths) {
@@ -339,10 +341,6 @@
ParseKernelCmdlineOptions();
}
-void Modprobe::EnableBlocklist(bool enable) {
- blocklist_enabled = enable;
-}
-
std::vector<std::string> Modprobe::GetDependencies(const std::string& module) {
auto it = module_deps_.find(module);
if (it == module_deps_.end()) {
@@ -427,10 +425,23 @@
return true;
}
+bool Modprobe::IsBlocklisted(const std::string& module_name) {
+ if (!blocklist_enabled) return false;
+
+ auto canonical_name = MakeCanonical(module_name);
+ auto dependencies = GetDependencies(canonical_name);
+ for (auto dep = dependencies.begin(); dep != dependencies.end(); ++dep) {
+ if (module_blocklist_.count(MakeCanonical(*dep))) return true;
+ }
+
+ return module_blocklist_.count(canonical_name) > 0;
+}
+
bool Modprobe::LoadListedModules(bool strict) {
auto ret = true;
for (const auto& module : module_load_) {
if (!LoadWithAliases(module, true)) {
+ if (IsBlocklisted(module)) continue;
ret = false;
if (strict) break;
}
@@ -440,16 +451,10 @@
bool Modprobe::Remove(const std::string& module_name) {
auto dependencies = GetDependencies(MakeCanonical(module_name));
- if (dependencies.empty()) {
- LOG(ERROR) << "Empty dependencies for module " << module_name;
- return false;
- }
- if (!Rmmod(dependencies[0])) {
- return false;
- }
- for (auto dep = dependencies.begin() + 1; dep != dependencies.end(); ++dep) {
+ for (auto dep = dependencies.begin(); dep != dependencies.end(); ++dep) {
Rmmod(*dep);
}
+ Rmmod(module_name);
return true;
}
diff --git a/libmodprobe/libmodprobe_test.cpp b/libmodprobe/libmodprobe_test.cpp
index d50c10d..f960b61 100644
--- a/libmodprobe/libmodprobe_test.cpp
+++ b/libmodprobe/libmodprobe_test.cpp
@@ -78,6 +78,18 @@
"/test13.ko",
};
+ std::vector<std::string> expected_modules_blocklist_enabled = {
+ "/test1.ko option1=50 option2=60",
+ "/test6.ko",
+ "/test2.ko",
+ "/test5.ko option1=",
+ "/test8.ko",
+ "/test7.ko param1=4",
+ "/test12.ko",
+ "/test11.ko",
+ "/test13.ko",
+ };
+
const std::string modules_dep =
"test1.ko:\n"
"test2.ko:\n"
@@ -146,7 +158,7 @@
*i = dir.path + *i;
}
- Modprobe m({dir.path});
+ Modprobe m({dir.path}, "modules.load", false);
EXPECT_TRUE(m.LoadListedModules());
GTEST_LOG_(INFO) << "Expected modules loaded (in order):";
@@ -176,8 +188,22 @@
EXPECT_TRUE(modules_loaded == expected_after_remove);
- m.EnableBlocklist(true);
+ m = Modprobe({dir.path});
EXPECT_FALSE(m.LoadWithAliases("test4", true));
+ while (modules_loaded.size() > 0) EXPECT_TRUE(m.Remove(modules_loaded.front()));
+ EXPECT_TRUE(m.LoadListedModules());
+
+ GTEST_LOG_(INFO) << "Expected modules loaded after enabling blocklist (in order):";
+ for (auto i = expected_modules_blocklist_enabled.begin();
+ i != expected_modules_blocklist_enabled.end(); ++i) {
+ *i = dir.path + *i;
+ GTEST_LOG_(INFO) << "\"" << *i << "\"";
+ }
+ GTEST_LOG_(INFO) << "Actual modules loaded with blocklist enabled (in order):";
+ for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) {
+ GTEST_LOG_(INFO) << "\"" << *i << "\"";
+ }
+ EXPECT_TRUE(modules_loaded == expected_modules_blocklist_enabled);
}
TEST(libmodprobe, ModuleDepLineWithoutColonIsSkipped) {
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 5b57bdd..bd94621 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -70,11 +70,11 @@
"Name": "Frozen",
"Actions": [
{
- "Name": "JoinCgroup",
+ "Name": "SetAttribute",
"Params":
{
- "Controller": "freezer",
- "Path": ""
+ "Name": "FreezerState",
+ "Value": "1"
}
}
]
@@ -83,11 +83,11 @@
"Name": "Unfrozen",
"Actions": [
{
- "Name": "JoinCgroup",
+ "Name": "SetAttribute",
"Params":
{
- "Controller": "freezer",
- "Path": "../"
+ "Name": "FreezerState",
+ "Value": "0"
}
}
]
@@ -558,32 +558,6 @@
}
]
},
- {
- "Name": "FreezerDisabled",
- "Actions": [
- {
- "Name": "SetAttribute",
- "Params":
- {
- "Name": "FreezerState",
- "Value": "0"
- }
- }
- ]
- },
- {
- "Name": "FreezerEnabled",
- "Actions": [
- {
- "Name": "SetAttribute",
- "Params":
- {
- "Name": "FreezerState",
- "Value": "1"
- }
- }
- ]
- }
],
"AggregateProfiles": [
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index f13a681..db00a49 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -518,10 +518,10 @@
std::string attr_filepath = params_val["FilePath"].asString();
std::string attr_value = params_val["Value"].asString();
if (!attr_filepath.empty() && !attr_value.empty()) {
- const Json::Value& logfailures = params_val["LogFailures"];
- bool attr_logfailures = logfailures.isNull() || logfailures.asBool();
+ std::string attr_logfailures = params_val["LogFailures"].asString();
+ bool logfailures = attr_logfailures.empty() || attr_logfailures == "true";
profile->Add(std::make_unique<WriteFileAction>(attr_filepath, attr_value,
- attr_logfailures));
+ logfailures));
} else if (attr_filepath.empty()) {
LOG(WARNING) << "WriteFile: invalid parameter: "
<< "empty filepath";
diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp
new file mode 100644
index 0000000..354c7b3
--- /dev/null
+++ b/libstats/pull_rust/Android.bp
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2021 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.
+//
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_bindgen {
+ name: "libstatspull_bindgen",
+ wrapper_src: "statslog.h",
+ crate_name: "statspull_bindgen",
+ source_stem: "bindings",
+ bindgen_flags: [
+ "--size_t-is-usize",
+ "--whitelist-function=AStatsEventList_addStatsEvent",
+ "--whitelist-function=AStatsEvent_.*",
+ "--whitelist-function=AStatsManager_.*",
+ "--whitelist-var=AStatsManager_.*",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "libstatspull",
+ "libstatssocket",
+ ],
+ },
+ host: {
+ static_libs: [
+ "libstatspull",
+ "libstatssocket",
+ ],
+ },
+ },
+}
+
+rust_library {
+ name: "libstatspull_rust",
+ crate_name: "statspull_rust",
+ srcs: ["stats_pull.rs"],
+ rustlibs: [
+ "liblazy_static",
+ "liblog_rust",
+ "libstatslog_rust_header",
+ "libstatspull_bindgen",
+ ],
+}
diff --git a/libstats/pull_rust/stats_pull.rs b/libstats/pull_rust/stats_pull.rs
new file mode 100644
index 0000000..174125e
--- /dev/null
+++ b/libstats/pull_rust/stats_pull.rs
@@ -0,0 +1,170 @@
+// Copyright 2021, 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 Rust interface for the StatsD pull API.
+
+use lazy_static::lazy_static;
+use statslog_rust_header::{Atoms, Stat, StatsError};
+use statspull_bindgen::*;
+use std::collections::HashMap;
+use std::convert::TryInto;
+use std::os::raw::c_void;
+use std::sync::Mutex;
+
+/// The return value of callbacks.
+pub type StatsPullResult = Vec<Box<dyn Stat>>;
+
+/// A wrapper for AStatsManager_PullAtomMetadata.
+/// It calls AStatsManager_PullAtomMetadata_release on drop.
+pub struct Metadata {
+ metadata: *mut AStatsManager_PullAtomMetadata,
+}
+
+impl Metadata {
+ /// Calls AStatsManager_PullAtomMetadata_obtain.
+ pub fn new() -> Self {
+ // Safety: We panic if the memory allocation fails.
+ let metadata = unsafe { AStatsManager_PullAtomMetadata_obtain() };
+ if metadata.is_null() {
+ panic!("Cannot obtain pull atom metadata.");
+ } else {
+ Metadata { metadata }
+ }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_setCoolDownMillis.
+ pub fn set_cooldown_millis(&mut self, cooldown_millis: i64) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_setCoolDownMillis(self.metadata, cooldown_millis) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_getCoolDownMillis.
+ pub fn get_cooldown_millis(&self) -> i64 {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_getCoolDownMillis(self.metadata) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_setTimeoutMillis.
+ pub fn set_timeout_millis(&mut self, timeout_millis: i64) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_setTimeoutMillis(self.metadata, timeout_millis) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_getTimeoutMillis.
+ pub fn get_timeout_millis(&self) -> i64 {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_getTimeoutMillis(self.metadata) }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_setAdditiveFields.
+ pub fn set_additive_fields(&mut self, additive_fields: &mut Vec<i32>) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe {
+ AStatsManager_PullAtomMetadata_setAdditiveFields(
+ self.metadata,
+ additive_fields.as_mut_ptr(),
+ additive_fields.len().try_into().expect("Cannot convert length to i32"),
+ )
+ }
+ }
+
+ /// Calls AStatsManager_PullAtomMetadata_getAdditiveFields.
+ pub fn get_additive_fields(&self) -> Vec<i32> {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ // We call getNumAdditiveFields to ensure we pass getAdditiveFields a large enough array.
+ unsafe {
+ let num_fields = AStatsManager_PullAtomMetadata_getNumAdditiveFields(self.metadata)
+ .try_into()
+ .expect("Cannot convert num additive fields to usize");
+ let mut fields = vec![0; num_fields];
+ AStatsManager_PullAtomMetadata_getAdditiveFields(self.metadata, fields.as_mut_ptr());
+ fields
+ }
+ }
+}
+
+impl Drop for Metadata {
+ fn drop(&mut self) {
+ // Safety: Metadata::new ensures that self.metadata is a valid object.
+ unsafe { AStatsManager_PullAtomMetadata_release(self.metadata) }
+ }
+}
+
+impl Default for Metadata {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+lazy_static! {
+ static ref COOKIES: Mutex<HashMap<i32, fn() -> StatsPullResult>> = Mutex::new(HashMap::new());
+}
+
+// Safety: We store our callbacks in the global so they are valid.
+unsafe extern "C" fn callback_wrapper(
+ atom_tag: i32,
+ data: *mut AStatsEventList,
+ _cookie: *mut c_void,
+) -> AStatsManager_PullAtomCallbackReturn {
+ if !data.is_null() {
+ let map = COOKIES.lock().unwrap();
+ let cb = map.get(&atom_tag);
+ match cb {
+ None => log::error!("No callback found for {}", atom_tag),
+ Some(cb) => {
+ let stats = cb();
+ let result = stats
+ .iter()
+ .map(|stat| stat.add_astats_event(&mut *data))
+ .collect::<Result<Vec<()>, StatsError>>();
+ match result {
+ Ok(_) => {
+ return AStatsManager_PULL_SUCCESS as AStatsManager_PullAtomCallbackReturn
+ }
+ _ => log::error!("Error adding astats events: {:?}", result),
+ }
+ }
+ }
+ }
+ AStatsManager_PULL_SKIP as AStatsManager_PullAtomCallbackReturn
+}
+
+/// Rust wrapper for AStatsManager_setPullAtomCallback.
+pub fn set_pull_atom_callback(
+ atom: Atoms,
+ metadata: Option<&Metadata>,
+ callback: fn() -> StatsPullResult,
+) {
+ COOKIES.lock().unwrap().insert(atom as i32, callback);
+ let metadata_raw = match metadata {
+ Some(m) => m.metadata,
+ None => std::ptr::null_mut(),
+ };
+ // Safety: We pass a valid function as the callback.
+ unsafe {
+ AStatsManager_setPullAtomCallback(
+ atom as i32,
+ metadata_raw,
+ Some(callback_wrapper),
+ std::ptr::null_mut(),
+ );
+ }
+}
+
+/// Rust wrapper for AStatsManager_clearPullAtomCallback.
+pub fn clear_pull_atom_callback(atom: Atoms) {
+ COOKIES.lock().unwrap().remove(&(atom as i32));
+ // Safety: No memory allocations.
+ unsafe { AStatsManager_clearPullAtomCallback(atom as i32) }
+}
diff --git a/libstats/pull_rust/statslog.h b/libstats/pull_rust/statslog.h
new file mode 100644
index 0000000..983fb7b
--- /dev/null
+++ b/libstats/pull_rust/statslog.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "stats_pull_atom_callback.h"
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 8e45226..b57e287 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -443,6 +443,20 @@
refs->mBase->onFirstRef();
}
+void RefBase::incStrongRequireStrong(const void* id) const {
+ weakref_impl* const refs = mRefs;
+ refs->incWeak(id);
+
+ refs->addStrongRef(id);
+ const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
+
+ LOG_ALWAYS_FATAL_IF(c <= 0 || c == INITIAL_STRONG_VALUE,
+ "incStrongRequireStrong() called on %p which isn't already owned", refs);
+#if PRINT_REFS
+ ALOGD("incStrong (requiring strong) of %p from %p: cnt=%d\n", this, id, c);
+#endif
+}
+
void RefBase::decStrong(const void* id) const
{
weakref_impl* const refs = mRefs;
@@ -521,6 +535,14 @@
ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
}
+void RefBase::weakref_type::incWeakRequireWeak(const void* id)
+{
+ weakref_impl* const impl = static_cast<weakref_impl*>(this);
+ impl->addWeakRef(id);
+ const int32_t c __unused = impl->mWeak.fetch_add(1,
+ std::memory_order_relaxed);
+ LOG_ALWAYS_FATAL_IF(c <= 0, "incWeakRequireWeak called on %p which has no weak refs", this);
+}
void RefBase::weakref_type::decWeak(const void* id)
{
diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp
index c9b4894..93f9654 100644
--- a/libutils/RefBase_test.cpp
+++ b/libutils/RefBase_test.cpp
@@ -241,6 +241,30 @@
ASSERT_FALSE(wp1 != wp2);
}
+TEST(RefBase, AssertWeakRefExistsSuccess) {
+ bool isDeleted;
+ sp<Foo> foo = sp<Foo>::make(&isDeleted);
+ wp<Foo> weakFoo = foo;
+
+ EXPECT_EQ(weakFoo, wp<Foo>::fromExisting(foo.get()));
+ EXPECT_EQ(weakFoo.unsafe_get(), wp<Foo>::fromExisting(foo.get()).unsafe_get());
+
+ EXPECT_FALSE(isDeleted);
+ foo = nullptr;
+ EXPECT_TRUE(isDeleted);
+}
+
+TEST(RefBase, AssertWeakRefExistsDeath) {
+ // uses some other refcounting method, or none at all
+ bool isDeleted;
+ Foo* foo = new Foo(&isDeleted);
+
+ // can only get a valid wp<> object when you construct it from an sp<>
+ EXPECT_DEATH(wp<Foo>::fromExisting(foo), "");
+
+ delete foo;
+}
+
// Set up a situation in which we race with visit2AndRremove() to delete
// 2 strong references. Bar destructor checks that there are no early
// deletions and prior updates are visible to destructor.
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 70bf5a0..e3e5f11 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -390,28 +390,6 @@
return static_cast<size_t>(*(p - 1));
}
-status_t String16::makeLower()
-{
- const size_t N = size();
- const char16_t* str = string();
- char16_t* edited = nullptr;
- for (size_t i=0; i<N; i++) {
- const char16_t v = str[i];
- if (v >= 'A' && v <= 'Z') {
- if (!edited) {
- SharedBuffer* buf = static_cast<SharedBuffer*>(edit());
- if (!buf) {
- return NO_MEMORY;
- }
- edited = (char16_t*)buf->data();
- mString = str = edited;
- }
- edited[i] = tolower((char)v);
- }
- }
- return OK;
-}
-
status_t String16::replaceAll(char16_t replaceThis, char16_t withThis)
{
const size_t N = size();
diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp
index 63c2800..defa0f5 100644
--- a/libutils/String16_fuzz.cpp
+++ b/libutils/String16_fuzz.cpp
@@ -34,11 +34,6 @@
str1.size();
}),
- // Casing
- ([](FuzzedDataProvider&, android::String16 str1, android::String16) -> void {
- str1.makeLower();
- }),
-
// Comparison
([](FuzzedDataProvider&, android::String16 str1, android::String16 str2) -> void {
str1.startsWith(str2);
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
index 2505f44..c2e9b02 100644
--- a/libutils/String16_test.cpp
+++ b/libutils/String16_test.cpp
@@ -97,13 +97,6 @@
EXPECT_STR16EQ(u" m", tmp);
}
-TEST(String16Test, MakeLower) {
- String16 tmp("Verify Me!");
- tmp.makeLower();
- EXPECT_EQ(10U, tmp.size());
- EXPECT_STR16EQ(u"verify me!", tmp);
-}
-
TEST(String16Test, ReplaceAll) {
String16 tmp("Verify verify Verify");
tmp.replaceAll(u'r', u'!');
@@ -176,14 +169,6 @@
EXPECT_FALSE(tmp.isStaticString());
}
-TEST(String16Test, StaticStringMakeLower) {
- StaticString16 tmp(u"Verify me!");
- tmp.makeLower();
- EXPECT_EQ(10U, tmp.size());
- EXPECT_STR16EQ(u"verify me!", tmp);
- EXPECT_FALSE(tmp.isStaticString());
-}
-
TEST(String16Test, StaticStringReplaceAll) {
StaticString16 tmp(u"Verify verify Verify");
tmp.replaceAll(u'r', u'!');
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 3dc2026..fad130b 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -415,50 +415,28 @@
void String8::toLower()
{
- toLower(0, size());
-}
+ const size_t length = size();
+ if (length == 0) return;
-void String8::toLower(size_t start, size_t length)
-{
- const size_t len = size();
- if (start >= len) {
- return;
- }
- if (start+length > len) {
- length = len-start;
- }
- char* buf = lockBuffer(len);
- buf += start;
- while (length > 0) {
+ char* buf = lockBuffer(length);
+ for (size_t i = length; i > 0; --i) {
*buf = static_cast<char>(tolower(*buf));
buf++;
- length--;
}
- unlockBuffer(len);
+ unlockBuffer(length);
}
void String8::toUpper()
{
- toUpper(0, size());
-}
+ const size_t length = size();
+ if (length == 0) return;
-void String8::toUpper(size_t start, size_t length)
-{
- const size_t len = size();
- if (start >= len) {
- return;
- }
- if (start+length > len) {
- length = len-start;
- }
- char* buf = lockBuffer(len);
- buf += start;
- while (length > 0) {
+ char* buf = lockBuffer(length);
+ for (size_t i = length; i > 0; --i) {
*buf = static_cast<char>(toupper(*buf));
buf++;
- length--;
}
- unlockBuffer(len);
+ unlockBuffer(length);
}
// ---------------------------------------------------------------------------
diff --git a/libutils/StrongPointer_test.cpp b/libutils/StrongPointer_test.cpp
index d37c1de..29f6bd4 100644
--- a/libutils/StrongPointer_test.cpp
+++ b/libutils/StrongPointer_test.cpp
@@ -21,8 +21,8 @@
using namespace android;
-class SPFoo : public LightRefBase<SPFoo> {
-public:
+class SPFoo : virtual public RefBase {
+ public:
explicit SPFoo(bool* deleted_check) : mDeleted(deleted_check) {
*mDeleted = false;
}
@@ -69,3 +69,14 @@
ASSERT_NE(nullptr, foo);
ASSERT_NE(foo, nullptr);
}
+
+TEST(StrongPointer, AssertStrongRefExists) {
+ // uses some other refcounting method, or non at all
+ bool isDeleted;
+ SPFoo* foo = new SPFoo(&isDeleted);
+
+ // can only get a valid sp<> object when you construct it as an sp<> object
+ EXPECT_DEATH(sp<SPFoo>::fromExisting(foo), "");
+
+ delete foo;
+}
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index e7acd17..7148949 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -140,7 +140,9 @@
// count, and accidentally passed to f(sp<T>), a strong pointer to the object
// will be temporarily constructed and destroyed, prematurely deallocating the
// object, and resulting in heap corruption. None of this would be easily
-// visible in the source.
+// visible in the source. See below on
+// ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION for a compile time
+// option which helps avoid this case.
// Extra Features:
@@ -167,6 +169,42 @@
// to THE SAME sp<> or wp<>. In effect, their thread-safety properties are
// exactly like those of T*, NOT atomic<T*>.
+// Safety option: ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION
+//
+// This flag makes the semantics for using a RefBase object with wp<> and sp<>
+// much stricter by disabling implicit conversion from raw pointers to these
+// objects. In order to use this, apply this flag in Android.bp like so:
+//
+// cflags: [
+// "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
+// ],
+//
+// REGARDLESS of whether this flag is on, best usage of sp<> is shown below. If
+// this flag is on, no other usage is possible (directly calling RefBase methods
+// is possible, but seeing code using 'incStrong' instead of 'sp<>', for
+// instance, should already set off big alarm bells. With carefully constructed
+// data structures, it should NEVER be necessary to directly use RefBase
+// methods). Proper RefBase usage:
+//
+// class Foo : virtual public RefBase { ... };
+//
+// // always construct an sp object with sp::make
+// sp<Foo> myFoo = sp<Foo>::make(/*args*/);
+//
+// // if you need a weak pointer, it must be constructed from a strong
+// // pointer
+// wp<Foo> weakFoo = myFoo; // NOT myFoo.get()
+//
+// // If you are inside of a method of Foo and need access to a strong
+// // explicitly call this function. This documents your intention to code
+// // readers, and it will give a runtime error for what otherwise would
+// // be potential double ownership
+// .... Foo::someMethod(...) {
+// // asserts if there is a memory issue
+// sp<Foo> thiz = sp<Foo>::fromExisting(this);
+// }
+//
+
#ifndef ANDROID_REF_BASE_H
#define ANDROID_REF_BASE_H
@@ -244,6 +282,7 @@
{
public:
void incStrong(const void* id) const;
+ void incStrongRequireStrong(const void* id) const;
void decStrong(const void* id) const;
void forceIncStrong(const void* id) const;
@@ -257,6 +296,7 @@
RefBase* refBase() const;
void incWeak(const void* id);
+ void incWeakRequireWeak(const void* id);
void decWeak(const void* id);
// acquires a strong reference if there is already one.
@@ -365,10 +405,24 @@
inline wp() : m_ptr(nullptr), m_refs(nullptr) { }
+ // if nullptr, returns nullptr
+ //
+ // if a weak pointer is already available, this will retrieve it,
+ // otherwise, this will abort
+ static inline wp<T> fromExisting(T* other);
+
+ // for more information about this flag, see above
+#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+ wp(std::nullptr_t) : wp() {}
+#else
wp(T* other); // NOLINT(implicit)
+#endif
wp(const wp<T>& other);
explicit wp(const sp<T>& other);
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> wp(U* other); // NOLINT(implicit)
+#endif
template<typename U> wp(const sp<U>& other); // NOLINT(implicit)
template<typename U> wp(const wp<U>& other); // NOLINT(implicit)
@@ -376,11 +430,15 @@
// Assignment
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
wp& operator = (T* other);
+#endif
wp& operator = (const wp<T>& other);
wp& operator = (const sp<T>& other);
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> wp& operator = (U* other);
+#endif
template<typename U> wp& operator = (const wp<U>& other);
template<typename U> wp& operator = (const sp<U>& other);
@@ -481,12 +539,27 @@
// Note that the above comparison operations go out of their way to provide an ordering consistent
// with ordinary pointer comparison; otherwise they could ignore m_ptr, and just compare m_refs.
+template <typename T>
+wp<T> wp<T>::fromExisting(T* other) {
+ if (!other) return nullptr;
+
+ auto refs = other->getWeakRefs();
+ refs->incWeakRequireWeak(other);
+
+ wp<T> ret;
+ ret.m_ptr = other;
+ ret.m_refs = refs;
+ return ret;
+}
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
wp<T>::wp(T* other)
: m_ptr(other)
{
m_refs = other ? m_refs = other->createWeak(this) : nullptr;
}
+#endif
template<typename T>
wp<T>::wp(const wp<T>& other)
@@ -502,12 +575,14 @@
m_refs = m_ptr ? m_ptr->createWeak(this) : nullptr;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
wp<T>::wp(U* other)
: m_ptr(other)
{
m_refs = other ? other->createWeak(this) : nullptr;
}
+#endif
template<typename T> template<typename U>
wp<T>::wp(const wp<U>& other)
@@ -534,6 +609,7 @@
if (m_ptr) m_refs->decWeak(this);
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
wp<T>& wp<T>::operator = (T* other)
{
@@ -544,6 +620,7 @@
m_refs = newRefs;
return *this;
}
+#endif
template<typename T>
wp<T>& wp<T>::operator = (const wp<T>& other)
@@ -569,6 +646,7 @@
return *this;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (U* other)
{
@@ -579,6 +657,7 @@
m_refs = newRefs;
return *this;
}
+#endif
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const wp<U>& other)
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 1a4b47e..5ce48c6 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -85,8 +85,6 @@
bool contains(const char16_t* chrs) const;
- status_t makeLower();
-
status_t replaceAll(char16_t replaceThis,
char16_t withThis);
diff --git a/libutils/include/utils/String8.h b/libutils/include/utils/String8.h
index 0bcb716..84f14d0 100644
--- a/libutils/include/utils/String8.h
+++ b/libutils/include/utils/String8.h
@@ -130,9 +130,7 @@
bool removeAll(const char* other);
void toLower();
- void toLower(size_t start, size_t numChars);
void toUpper();
- void toUpper(size_t start, size_t numChars);
/*
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 11128f2..dd53b9e 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -32,30 +32,67 @@
public:
inline sp() : m_ptr(nullptr) { }
- // TODO: switch everyone to using this over new, and make RefBase operator
- // new private to that class so that we can avoid RefBase being used with
- // other memory management mechanisms.
+ // The old way of using sp<> was like this. This is bad because it relies
+ // on implicit conversion to sp<>, which we would like to remove (if an
+ // object is being managed some other way, this is double-ownership). We
+ // want to move away from this:
+ //
+ // sp<Foo> foo = new Foo(...); // DO NOT DO THIS
+ //
+ // Instead, prefer to do this:
+ //
+ // sp<Foo> foo = sp<Foo>::make(...); // DO THIS
+ //
+ // Sometimes, in order to use this, when a constructor is marked as private,
+ // you may need to add this to your class:
+ //
+ // friend class sp<Foo>;
template <typename... Args>
static inline sp<T> make(Args&&... args);
+ // if nullptr, returns nullptr
+ //
+ // if a strong pointer is already available, this will retrieve it,
+ // otherwise, this will abort
+ static inline sp<T> fromExisting(T* other);
+
+ // for more information about this macro and correct RefBase usage, see
+ // the comment at the top of utils/RefBase.h
+#if defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
+ sp(std::nullptr_t) : sp() {}
+#else
sp(T* other); // NOLINT(implicit)
+#endif
sp(const sp<T>& other);
sp(sp<T>&& other) noexcept;
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> sp(U* other); // NOLINT(implicit)
+#endif
template<typename U> sp(const sp<U>& other); // NOLINT(implicit)
template<typename U> sp(sp<U>&& other); // NOLINT(implicit)
+ // Cast a strong pointer directly from one type to another. Constructors
+ // allow changing types, but only if they are pointer-compatible. This does
+ // a static_cast internally.
+ template <typename U>
+ static inline sp<T> cast(const sp<U>& other);
+
~sp();
// Assignment
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
sp& operator = (T* other);
+#endif
sp& operator = (const sp<T>& other);
sp& operator=(sp<T>&& other) noexcept;
template<typename U> sp& operator = (const sp<U>& other);
template<typename U> sp& operator = (sp<U>&& other);
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename U> sp& operator = (U* other);
+#endif
//! Special optimization for use by ProcessState (and nobody else).
void force_set(T* other);
@@ -189,6 +226,19 @@
return result;
}
+template <typename T>
+sp<T> sp<T>::fromExisting(T* other) {
+ if (other) {
+ check_not_on_stack(other);
+ other->incStrongRequireStrong(other);
+ sp<T> result;
+ result.m_ptr = other;
+ return result;
+ }
+ return nullptr;
+}
+
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
sp<T>::sp(T* other)
: m_ptr(other) {
@@ -197,6 +247,7 @@
other->incStrong(this);
}
}
+#endif
template<typename T>
sp<T>::sp(const sp<T>& other)
@@ -210,6 +261,7 @@
other.m_ptr = nullptr;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
sp<T>::sp(U* other)
: m_ptr(other) {
@@ -218,6 +270,7 @@
(static_cast<T*>(other))->incStrong(this);
}
}
+#endif
template<typename T> template<typename U>
sp<T>::sp(const sp<U>& other)
@@ -232,6 +285,12 @@
other.m_ptr = nullptr;
}
+template <typename T>
+template <typename U>
+sp<T> sp<T>::cast(const sp<U>& other) {
+ return sp<T>::fromExisting(static_cast<T*>(other.get()));
+}
+
template<typename T>
sp<T>::~sp() {
if (m_ptr)
@@ -260,6 +319,7 @@
return *this;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T>
sp<T>& sp<T>::operator =(T* other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
@@ -272,6 +332,7 @@
m_ptr = other;
return *this;
}
+#endif
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(const sp<U>& other) {
@@ -294,6 +355,7 @@
return *this;
}
+#if !defined(ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION)
template<typename T> template<typename U>
sp<T>& sp<T>::operator =(U* other) {
T* oldPtr(*const_cast<T* volatile*>(&m_ptr));
@@ -303,6 +365,7 @@
m_ptr = other;
return *this;
}
+#endif
template<typename T>
void sp<T>::force_set(T* other) {
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index 83cb6ff..d9f5526 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -1,8 +1,7 @@
{
"requireLibs": [
- // Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
- "libdexfile_external.so",
- "libdexfiled_external.so",
+ "libdexfile.so",
+ "libdexfiled.so",
"libnativebridge.so",
"libnativehelper.so",
"libnativeloader.so",
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ce2dd9e..5a9cc99 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -821,6 +821,9 @@
mkdir /data/ss 0700 system system encryption=Require
mkdir /data/system 0775 system system encryption=Require
+ mkdir /data/system/environ 0700 system system
+ # b/183861600 attempt to fix selinux label before running derive_classpath service
+ restorecon /data/system/environ
mkdir /data/system/dropbox 0700 system system
mkdir /data/system/heapdump 0700 system system
mkdir /data/system/users 0775 system system
@@ -884,10 +887,6 @@
wait_for_prop apexd.status activated
perform_apex_config
- # Export *CLASSPATH variables from /etc/classpath
- # TODO(b/180105615): export from the generated file instead.
- load_exports /etc/classpath
-
# Special-case /data/media/obb per b/64566063
mkdir /data/media 0770 media_rw media_rw encryption=None
exec - media_rw media_rw -- /system/bin/chattr +F /data/media
@@ -900,8 +899,15 @@
# Set SELinux security contexts on upgrade or policy update.
restorecon --recursive --skip-ce /data
+ # Define and export *CLASSPATH variables
+ # Must start before 'odsign', as odsign depends on *CLASSPATH variables
+ exec_start derive_classpath
+ load_exports /data/system/environ/classpath
+ rm /data/system/environ/classpath
+
# Start the on-device signing daemon, and wait for it to finish, to ensure
# ART artifacts are generated if needed.
+ # Must start after 'derive_classpath' to have *CLASSPATH variables set.
start odsign
# Before we can lock keys and proceed to the next boot stage, wait for
@@ -979,7 +985,7 @@
write /proc/sys/vm/dirty_expire_centisecs 200
write /proc/sys/vm/dirty_background_ratio 5
-on property:sys.boot_completed=1 && property:init.mount_debugfs=1
+on property:sys.boot_completed=1 && property:ro.product.enforce_debugfs_restrictions=true
umount /sys/kernel/debug
on boot
@@ -1257,7 +1263,7 @@
on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
setprop sys.init.userspace_reboot.in_progress ""
-on early-init && property:init.mount_debugfs=1
+on early-init && property:ro.product.enforce_debugfs_restrictions=true
mount debugfs debugfs /sys/kernel/debug
chmod 0755 /sys/kernel/debug
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 27b05ec..0730cce 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -19,6 +19,9 @@
updatable
seclabel u:r:adbd:s0
+on property:vendor.sys.usb.adb.disabled=*
+ setprop sys.usb.adb.disabled ${vendor.sys.usb.adb.disabled}
+
# Set default value on sys.usb.configfs early in boot sequence. It will be
# overridden in `on boot` action of init.hardware.rc.
on init
diff --git a/toolbox/OWNERS b/toolbox/OWNERS
index 7529cb9..5e2c581 100644
--- a/toolbox/OWNERS
+++ b/toolbox/OWNERS
@@ -1 +1,2 @@
include platform/system/core:/janitors/OWNERS
+per-file modprobe.c=willmcvicker@google.com,dvander@google.com
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 7df7b71..711586a 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -215,10 +215,7 @@
return EXIT_FAILURE;
}
- Modprobe m(mod_dirs);
- if (blocklist) {
- m.EnableBlocklist(true);
- }
+ Modprobe m(mod_dirs, "modules.load", blocklist);
for (const auto& module : modules) {
switch (mode) {
diff --git a/trusty/apploader/apploader.cpp b/trusty/apploader/apploader.cpp
index 8ab6303..4aca375 100644
--- a/trusty/apploader/apploader.cpp
+++ b/trusty/apploader/apploader.cpp
@@ -96,13 +96,13 @@
unique_fd file_fd(TEMP_FAILURE_RETRY(open(file_name, O_RDONLY)));
if (!file_fd.ok()) {
- fprintf(stderr, "Error opening file '%s': %s\n", file_name, strerror(errno));
+ PLOG(ERROR) << "Error opening file " << file_name;
return {};
}
rc = fstat64(file_fd, &st);
if (rc < 0) {
- fprintf(stderr, "Error calling stat on file '%s': %s\n", file_name, strerror(errno));
+ PLOG(ERROR) << "Error calling stat on file '" << file_name << "'";
return {};
}
@@ -115,14 +115,14 @@
file_page_offset = page_size - file_page_offset;
}
if (__builtin_add_overflow(file_size, file_page_offset, &file_page_size)) {
- fprintf(stderr, "Failed to page-align file size\n");
+ LOG(ERROR) << "Failed to page-align file size";
return {};
}
BufferAllocator alloc;
unique_fd dmabuf_fd(alloc.Alloc(kDmabufSystemHeapName, file_page_size));
if (!dmabuf_fd.ok()) {
- fprintf(stderr, "Error creating dmabuf: %d\n", dmabuf_fd.get());
+ LOG(ERROR) << "Error creating dmabuf: " << dmabuf_fd.get();
return dmabuf_fd;
}
@@ -137,12 +137,12 @@
pread(file_fd, (char*)shm + file_offset, file_size - file_offset, file_offset));
if (num_read < 0) {
- fprintf(stderr, "Error reading package file '%s': %s\n", file_name, strerror(errno));
+ PLOG(ERROR) << "Error reading package file '" << file_name << "'";
break;
}
if (num_read == 0) {
- fprintf(stderr, "Unexpected end of file '%s'\n", file_name);
+ LOG(ERROR) << "Unexpected end of file '" << file_name << "'";
break;
}
@@ -182,17 +182,17 @@
struct apploader_resp resp;
ssize_t rc = read(tipc_fd, &resp, sizeof(resp));
if (rc < 0) {
- fprintf(stderr, "Failed to read response: %zd\n", rc);
+ PLOG(ERROR) << "Failed to read response";
return rc;
}
if (rc < sizeof(resp)) {
- fprintf(stderr, "Not enough data in response: %zd\n", rc);
+ LOG(ERROR) << "Not enough data in response: " << rc;
return -EIO;
}
if (resp.hdr.cmd != (APPLOADER_CMD_LOAD_APPLICATION | APPLOADER_RESP_BIT)) {
- fprintf(stderr, "Invalid command in response: %u\n", resp.hdr.cmd);
+ LOG(ERROR) << "Invalid command in response: " << resp.hdr.cmd;
return -EINVAL;
}
@@ -200,28 +200,28 @@
case APPLOADER_NO_ERROR:
break;
case APPLOADER_ERR_UNKNOWN_CMD:
- fprintf(stderr, "Error: unknown command\n");
+ LOG(ERROR) << "Error: unknown command";
break;
case APPLOADER_ERR_INVALID_CMD:
- fprintf(stderr, "Error: invalid command arguments\n");
+ LOG(ERROR) << "Error: invalid command arguments";
break;
case APPLOADER_ERR_NO_MEMORY:
- fprintf(stderr, "Error: out of Trusty memory\n");
+ LOG(ERROR) << "Error: out of Trusty memory";
break;
case APPLOADER_ERR_VERIFICATION_FAILED:
- fprintf(stderr, "Error: failed to verify the package\n");
+ LOG(ERROR) << "Error: failed to verify the package";
break;
case APPLOADER_ERR_LOADING_FAILED:
- fprintf(stderr, "Error: failed to load the package\n");
+ LOG(ERROR) << "Error: failed to load the package";
break;
case APPLOADER_ERR_ALREADY_EXISTS:
- fprintf(stderr, "Error: application already exists\n");
+ LOG(ERROR) << "Error: application already exists";
break;
case APPLOADER_ERR_INTERNAL:
- fprintf(stderr, "Error: internal apploader error\n");
+ LOG(ERROR) << "Error: internal apploader error";
break;
default:
- fprintf(stderr, "Unrecognized error: %u\n", resp.error);
+ LOG(ERROR) << "Unrecognized error: " << resp.error;
break;
}
@@ -241,14 +241,14 @@
tipc_fd = tipc_connect(dev_name, APPLOADER_PORT);
if (tipc_fd < 0) {
- fprintf(stderr, "Failed to connect to Trusty app loader: %s\n", strerror(-tipc_fd));
+ LOG(ERROR) << "Failed to connect to Trusty app loader: " << strerror(-tipc_fd);
rc = tipc_fd;
goto err_tipc_connect;
}
rc = send_load_message(tipc_fd, package_fd, package_size);
if (rc < 0) {
- fprintf(stderr, "Failed to send package: %zd\n", rc);
+ LOG(ERROR) << "Failed to send package: " << rc;
goto err_send;
}
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 94aedd7..29c6f93 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -914,7 +914,7 @@
}
size_t buf_size = PAGE_SIZE * num_pages;
- dma_buf = DmabufHeapAlloc(allocator, "system", buf_size, 0);
+ dma_buf = DmabufHeapAlloc(allocator, "system", buf_size, 0, 0 /* legacy align */);
if (dma_buf < 0) {
ret = dma_buf;
fprintf(stderr, "Failed to create dma-buf fd of size %zu err (%d)\n", buf_size, ret);