Merge "Load kernel modules in parallel"
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 85adbea..a5e2413 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1825,9 +1825,9 @@
TEST_F(CrasherTest, unreadable_elf) {
int intercept_result;
unique_fd output_fd;
- StartProcess([]() {
+ std::string tmp_so_name;
+ StartProcess([&tmp_so_name]() {
TemporaryDir td;
- std::string tmp_so_name;
if (!CopySharedLibrary(td.path, &tmp_so_name)) {
_exit(1);
}
@@ -1857,6 +1857,8 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_MATCH(result, R"(NOTE: Function names and BuildId information is missing )");
+ std::string match_str = "NOTE: " + tmp_so_name;
+ ASSERT_MATCH(result, match_str);
}
TEST(tombstoned, proto) {
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 3e31bb7..bee4a67 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -35,6 +35,7 @@
#include <memory>
#include <optional>
+#include <set>
#include <string>
#include <async_safe/log.h>
@@ -419,18 +420,29 @@
return;
}
- if (unwinder->elf_from_memory_not_file()) {
+ unwinder->SetDisplayBuildID(true);
+ std::set<std::string> unreadable_elf_files;
+ for (const auto& frame : unwinder->frames()) {
+ BacktraceFrame* f = thread.add_current_backtrace();
+ fill_in_backtrace_frame(f, frame);
+ if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
+ unreadable_elf_files.emplace(frame.map_info->name());
+ }
+ }
+
+ if (!unreadable_elf_files.empty()) {
+ auto unreadable_elf_files_proto = thread.mutable_unreadable_elf_files();
auto backtrace_note = thread.mutable_backtrace_note();
*backtrace_note->Add() =
"Function names and BuildId information is missing for some frames due";
*backtrace_note->Add() = "to unreadable libraries. For unwinds of apps, only shared libraries";
*backtrace_note->Add() = "found under the lib/ directory are readable.";
*backtrace_note->Add() = "On this device, run setenforce 0 to make the libraries readable.";
- }
- unwinder->SetDisplayBuildID(true);
- for (const auto& frame : unwinder->frames()) {
- BacktraceFrame* f = thread.add_current_backtrace();
- fill_in_backtrace_frame(f, frame);
+ *backtrace_note->Add() = "Unreadable libraries:";
+ for (auto& name : unreadable_elf_files) {
+ *backtrace_note->Add() = " " + name;
+ *unreadable_elf_files_proto->Add() = name;
+ }
}
}
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 543a67c..ecd98a4 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -28,6 +28,7 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <set>
#include <string>
#include <android-base/properties.h>
@@ -483,7 +484,16 @@
}
void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
- if (unwinder->elf_from_memory_not_file()) {
+ std::set<std::string> unreadable_elf_files;
+ unwinder->SetDisplayBuildID(true);
+ for (const auto& frame : unwinder->frames()) {
+ if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
+ unreadable_elf_files.emplace(frame.map_info->name());
+ }
+ }
+
+ // Put the preamble ahead of the backtrace.
+ if (!unreadable_elf_files.empty()) {
_LOG(log, logtype::BACKTRACE,
"%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix);
_LOG(log, logtype::BACKTRACE,
@@ -493,10 +503,13 @@
_LOG(log, logtype::BACKTRACE,
"%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix);
#endif
+ _LOG(log, logtype::BACKTRACE, "%sNOTE: Unreadable libraries:\n", prefix);
+ for (auto& name : unreadable_elf_files) {
+ _LOG(log, logtype::BACKTRACE, "%sNOTE: %s\n", prefix, name.c_str());
+ }
}
- unwinder->SetDisplayBuildID(true);
- for (size_t i = 0; i < unwinder->NumFrames(); i++) {
- _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
+ for (const auto& frame : unwinder->frames()) {
+ _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(frame).c_str());
}
}
diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto
index 40a942e..a0f2f82 100644
--- a/debuggerd/proto/tombstone.proto
+++ b/debuggerd/proto/tombstone.proto
@@ -123,12 +123,13 @@
string name = 2;
repeated Register registers = 3;
repeated string backtrace_note = 7;
+ repeated string unreadable_elf_files = 9;
repeated BacktraceFrame current_backtrace = 4;
repeated MemoryDump memory_dump = 5;
int64 tagged_addr_ctrl = 6;
int64 pac_enabled_keys = 8;
- reserved 9 to 999;
+ reserved 10 to 999;
}
message BacktraceFrame {
diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy
index 4e8fdf9..8241f0e 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -25,7 +25,7 @@
rt_sigprocmask: 1
rt_sigaction: 1
rt_tgsigqueueinfo: 1
-prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS || arg0 == PR_GET_TAGGED_ADDR_CTRL || arg0 == PR_PAC_GET_ENABLED_KEYS
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS || arg0 == 56 || arg0 == 61
madvise: 1
mprotect: arg2 in 0x1|0x2
munmap: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
index 4eb996e..0cb8e08 100644
--- a/debuggerd/seccomp_policy/crash_dump.policy.def
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -34,7 +34,15 @@
rt_sigaction: 1
rt_tgsigqueueinfo: 1
+// this is referenced from mainline modules running on Q devices, where not all
+// of the constants used here are defined in headers, so minijail rejects them.
+// we define them here to avoid those errors.
+ // constants introduced in R
#define PR_SET_VMA 0x53564d41
+#define PR_GET_TAGGED_ADDR_CTRL 56
+ // constants introduced in S
+#define PR_PAC_GET_ENABLED_KEYS 61
+
#if defined(__aarch64__)
// PR_PAC_RESET_KEYS happens on aarch64 in pthread_create path.
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == PR_SET_VMA || arg0 == PR_PAC_RESET_KEYS || arg0 == PR_GET_TAGGED_ADDR_CTRL || arg0 == PR_PAC_GET_ENABLED_KEYS
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 143e980..b8b9262 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -287,11 +287,16 @@
entry->fs_mgr_flags.avb = true;
entry->vbmeta_partition = arg;
} else if (StartsWith(flag, "keydirectory=")) {
- // The metadata flag is followed by an = and the directory for the keys.
+ // The keydirectory flag enables metadata encryption. It is
+ // followed by an = and the directory containing the metadata
+ // encryption key.
entry->metadata_key_dir = arg;
} else if (StartsWith(flag, "metadata_encryption=")) {
- // Specify the cipher and flags to use for metadata encryption
- entry->metadata_encryption = arg;
+ // The metadata_encryption flag specifies the cipher and flags to
+ // use for metadata encryption, if the defaults aren't sufficient.
+ // It doesn't actually enable metadata encryption; that is done by
+ // "keydirectory".
+ entry->metadata_encryption_options = arg;
} else if (StartsWith(flag, "sysfs_path=")) {
// The path to trigger device gc by idle-maint of vold.
entry->sysfs_path = arg;
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index b831d12..f26fb24 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -38,7 +38,7 @@
std::string fs_options;
std::string fs_checkpoint_opts;
std::string metadata_key_dir;
- std::string metadata_encryption;
+ std::string metadata_encryption_options;
off64_t length = 0;
std::string label;
int partnum = -1;
diff --git a/fs_mgr/liblp/TEST_MAPPING b/fs_mgr/liblp/TEST_MAPPING
index 04bcbda..875ccb0 100644
--- a/fs_mgr/liblp/TEST_MAPPING
+++ b/fs_mgr/liblp/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name": "liblp_test"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "liblp_test"
+ }
]
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 04d228d..36abf71 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2411,8 +2411,15 @@
// fit in super, but not |prd|.
constexpr uint64_t partition_size = 3788_KiB;
SetSize(sys_, partition_size);
+ SetSize(vnd_, partition_size);
+ SetSize(prd_, 18_MiB);
- AddOperationForPartitions({sys_});
+ // Make sure |prd| does not fit in super at all. On VABC, this means we
+ // fake an extra large COW for |vnd| to fill up super.
+ vnd_->set_estimate_cow_size(30_MiB);
+ prd_->set_estimate_cow_size(30_MiB);
+
+ AddOperationForPartitions();
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
@@ -2422,8 +2429,25 @@
GTEST_SKIP() << "Test does not apply to userspace snapshots";
}
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
+ // Test that partitions prioritize using space in super.
+ auto tgt = MetadataBuilder::New(*opener_, "super", 1);
+ ASSERT_NE(tgt, nullptr);
+ ASSERT_NE(nullptr, tgt->FindPartition("sys_b-cow"));
+ ASSERT_NE(nullptr, tgt->FindPartition("vnd_b-cow"));
+ ASSERT_EQ(nullptr, tgt->FindPartition("prd_b-cow"));
+
+ // Write some data to target partitions.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(WriteSnapshotAndHash(name));
+ }
+
+ // Assert that source partitions aren't affected.
+ for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name));
+ }
+
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
ASSERT_TRUE(UnmapAll());
class DmStatusFailure final : public DeviceMapperWrapper {
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
index 0b88567..c31772b 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
@@ -223,8 +223,6 @@
int main(int argc, char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
- LOG(INFO) << "snapuserd daemon about to start";
-
android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
if (!daemon.StartDaemon(argc, argv)) {
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 1dbee75..6c881c0 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -943,7 +943,7 @@
ASSERT_LE(1U, fstab.size());
auto entry = fstab.begin();
- EXPECT_EQ("adiantum", entry->metadata_encryption);
+ EXPECT_EQ("adiantum", entry->metadata_encryption_options);
}
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_MetadataEncryption_WrappedKey) {
@@ -960,8 +960,8 @@
ASSERT_LE(1U, fstab.size());
auto entry = fstab.begin();
- EXPECT_EQ("aes-256-xts:wrappedkey_v0", entry->metadata_encryption);
- auto parts = android::base::Split(entry->metadata_encryption, ":");
+ EXPECT_EQ("aes-256-xts:wrappedkey_v0", entry->metadata_encryption_options);
+ auto parts = android::base::Split(entry->metadata_encryption_options, ":");
EXPECT_EQ(2U, parts.size());
EXPECT_EQ("aes-256-xts", parts[0]);
EXPECT_EQ("wrappedkey_v0", parts[1]);
diff --git a/healthd/TEST_MAPPING b/healthd/TEST_MAPPING
index 5893d10..17e363d 100644
--- a/healthd/TEST_MAPPING
+++ b/healthd/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name": "libhealthd_charger_test"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "libhealthd_charger_test"
+ }
]
}
diff --git a/init/README.md b/init/README.md
index c82dbfb..13c6ebd 100644
--- a/init/README.md
+++ b/init/README.md
@@ -804,13 +804,18 @@
`init.svc.<name>`
> State of a named service ("stopped", "stopping", "running", "restarting")
-`dev.mnt.blk.<mount_point>`
+`dev.mnt.dev.<mount_point>`, `dev.mnt.blk.<mount_point>`, `dev.mnt.rootdisk.<mount_point>`
> Block device base name associated with a *mount_point*.
The *mount_point* has / replaced by . and if referencing the root mount point
- "/", it will use "/root", specifically `dev.mnt.blk.root`.
- Meant for references to `/sys/device/block/${dev.mnt.blk.<mount_point>}/` and
- `/sys/fs/ext4/${dev.mnt.blk.<mount_point>}/` to tune the block device
- characteristics in a device agnostic manner.
+ "/", it will use "/root".
+ `dev.mnt.dev.<mount_point>` indicates a block device attached to filesystems.
+ (e.g., dm-N or sdaN/mmcblk0pN to access `/sys/fs/ext4/${dev.mnt.dev.<mount_point>}/`)
+
+ `dev.mnt.blk.<mount_point>` indicates the disk partition to the above block device.
+ (e.g., sdaN / mmcblk0pN to access `/sys/class/block/${dev.mnt.blk.<mount_point>}/`)
+
+ `dev.mnt.rootdisk.<mount_point>` indicates the root disk to contain the above disk partition.
+ (e.g., sda / mmcblk0 to access `/sys/class/block/${dev.mnt.rootdisk.<mount_point>}/queue`)
Init responds to properties that begin with `ctl.`. These properties take the format of
`ctl.[<target>_]<command>` and the _value_ of the system property is used as a parameter. The
diff --git a/init/TEST_MAPPING b/init/TEST_MAPPING
index 03b9eaa..fa1627c 100644
--- a/init/TEST_MAPPING
+++ b/init/TEST_MAPPING
@@ -9,5 +9,16 @@
{
"name": "MicrodroidHostTestCases"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "CtsInitTestCases"
+ },
+ {
+ "name": "init_kill_services_test"
+ },
+ {
+ "name": "MicrodroidHostTestCases"
+ }
]
}
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index e259fe5..13ee37d 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -27,6 +27,7 @@
#include <sys/utsname.h>
#include <unistd.h>
+#include <chrono>
#include <filesystem>
#include <string>
#include <vector>
@@ -107,6 +108,39 @@
cmdline.find("androidboot.force_normal_boot=1") != std::string::npos;
}
+static void Copy(const char* src, const char* dst) {
+ if (link(src, dst) == 0) {
+ LOG(INFO) << "hard linking " << src << " to " << dst << " succeeded";
+ return;
+ }
+ PLOG(FATAL) << "hard linking " << src << " to " << dst << " failed, falling back to copy.";
+}
+
+// Move e2fsck before switching root, so that it is available at the same path
+// after switching root.
+void PrepareSwitchRoot() {
+ constexpr const char* src = "/system/bin/snapuserd";
+ constexpr const char* dst = "/first_stage_ramdisk/system/bin/snapuserd";
+
+ if (access(dst, X_OK) == 0) {
+ LOG(INFO) << dst << " already exists and it can be executed";
+ return;
+ }
+
+ if (access(src, F_OK) != 0) {
+ PLOG(INFO) << "Not moving " << src << " because it cannot be accessed";
+ return;
+ }
+
+ auto dst_dir = android::base::Dirname(dst);
+ std::error_code ec;
+ if (access(dst_dir.c_str(), F_OK) != 0) {
+ if (!fs::create_directories(dst_dir, ec)) {
+ LOG(FATAL) << "Cannot create " << dst_dir << ": " << ec.message();
+ }
+ }
+ Copy(src, dst);
+}
} // namespace
std::string GetModuleLoadList(bool recovery, const std::string& dir_path) {
@@ -307,12 +341,11 @@
<< module_elapse_time.count() << " ms";
}
-
bool created_devices = false;
if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
if (!IsRecoveryMode()) {
created_devices = DoCreateDevices();
- if (!created_devices){
+ if (!created_devices) {
LOG(ERROR) << "Failed to create device nodes early";
}
}
@@ -355,10 +388,11 @@
if (ForceNormalBoot(cmdline, bootconfig)) {
mkdir("/first_stage_ramdisk", 0755);
+ PrepareSwitchRoot();
// SwitchRoot() must be called with a mount point as the target, so we bind mount the
// target directory to itself here.
if (mount("/first_stage_ramdisk", "/first_stage_ramdisk", nullptr, MS_BIND, nullptr) != 0) {
- LOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
+ PLOG(FATAL) << "Could not bind mount /first_stage_ramdisk to itself";
}
SwitchRoot("/first_stage_ramdisk");
}
diff --git a/init/init.cpp b/init/init.cpp
index 9616805..5a0b3a6 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,7 +33,6 @@
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
-#include <filesystem>
#include <functional>
#include <map>
#include <memory>
@@ -47,7 +46,6 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
-#include <android-base/scopeguard.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <backtrace/Backtrace.h>
@@ -580,12 +578,29 @@
HandlePowerctlMessage("shutdown,container");
}
+static constexpr std::chrono::milliseconds kDiagnosticTimeout = 10s;
+
static void HandleSignalFd() {
signalfd_siginfo siginfo;
- ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
- if (bytes_read != sizeof(siginfo)) {
- PLOG(ERROR) << "Failed to read siginfo from signal_fd";
- return;
+ auto started = std::chrono::steady_clock::now();
+ for (;;) {
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
+ if (bytes_read < 0 && errno == EAGAIN) {
+ auto now = std::chrono::steady_clock::now();
+ std::chrono::duration<double> waited = now - started;
+ if (waited >= kDiagnosticTimeout) {
+ LOG(ERROR) << "epoll() woke us up, but we waited with no SIGCHLD!";
+ started = now;
+ }
+
+ std::this_thread::sleep_for(100ms);
+ continue;
+ }
+ if (bytes_read != sizeof(siginfo)) {
+ PLOG(ERROR) << "Failed to read siginfo from signal_fd";
+ return;
+ }
+ break;
}
switch (siginfo.ssi_signo) {
@@ -641,7 +656,7 @@
LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
}
- signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
+ signal_fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
if (signal_fd == -1) {
PLOG(FATAL) << "failed to create signalfd";
}
@@ -776,82 +791,6 @@
return {};
}
-static bool SystemReadSmokeTest() {
- std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
- android::base::unique_fd fd(open(dev.c_str(), O_RDONLY));
- if (fd < 0) {
- PLOG(ERROR) << "open " << dev << " failed, will not diangose snapuserd hangs";
- return false;
- }
-
- for (size_t i = 1; i <= 100; i++) {
- // Skip around the partition a bit.
- size_t offset = i * 4096 * 512;
-
- char b;
- ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), &b, 1, offset));
- if (n < 0) {
- PLOG(ERROR) << "snapuserd smoke test read failed";
- return false;
- }
- }
- return true;
-}
-
-static void DiagnoseSnapuserdHang(pid_t pid) {
- bool succeeded = false;
-
- std::mutex m;
- std::condition_variable cv;
-
- // Enforce an ordering between this and the thread startup, by taking the
- // lock before we lanuch the thread.
- std::unique_lock<std::mutex> cv_lock(m);
-
- std::thread t([&]() -> void {
- std::lock_guard<std::mutex> lock(m);
- succeeded = SystemReadSmokeTest();
- cv.notify_all();
- });
-
- auto join = android::base::make_scope_guard([&]() -> void {
- // If the smoke test is hung, then this will too. We expect the device to
- // automatically reboot once the watchdog kicks in.
- t.join();
- });
-
- auto now = std::chrono::system_clock::now();
- auto deadline = now + 10s;
- auto status = cv.wait_until(cv_lock, deadline);
- if (status == std::cv_status::timeout) {
- LOG(ERROR) << "snapuserd smoke test timed out";
- } else if (!succeeded) {
- LOG(ERROR) << "snapuserd smoke test failed";
- }
-
- if (succeeded) {
- LOG(INFO) << "snapuserd smoke test succeeded";
- return;
- }
-
- while (true) {
- LOG(ERROR) << "snapuserd problem detected, printing open fds";
-
- std::error_code ec;
- std::string proc_dir = "/proc/" + std::to_string(pid) + "/fd";
- for (const auto& entry : std::filesystem::directory_iterator(proc_dir)) {
- std::string target;
- if (android::base::Readlink(entry.path(), &target)) {
- LOG(ERROR) << "snapuserd opened: " << target;
- } else {
- LOG(ERROR) << "snapuserd opened: " << entry.path();
- }
- }
-
- std::this_thread::sleep_for(10s);
- }
-}
-
int SecondStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
@@ -865,11 +804,6 @@
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
- if (auto pid = GetSnapuserdFirstStagePid()) {
- std::thread t(DiagnoseSnapuserdHang, *pid);
- t.detach();
- }
-
// Update $PATH in the case the second stage init is newer than first stage init, where it is
// first set.
if (setenv("PATH", _PATH_DEFPATH, 1) != 0) {
@@ -1021,7 +955,7 @@
setpriority(PRIO_PROCESS, 0, 0);
while (true) {
// By default, sleep until something happens.
- auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
+ auto epoll_timeout = std::optional<std::chrono::milliseconds>{kDiagnosticTimeout};
auto shutdown_command = shutdown_state.CheckShutdown();
if (shutdown_command) {
@@ -1061,6 +995,13 @@
for (const auto& function : *pending_functions) {
(*function)();
}
+ } else if (Service::is_exec_service_running()) {
+ std::chrono::duration<double> waited =
+ std::chrono::steady_clock::now() - Service::exec_service_started();
+ if (waited >= kDiagnosticTimeout) {
+ LOG(ERROR) << "Exec service is hung? Waited " << waited.count()
+ << " without SIGCHLD";
+ }
}
if (!IsShuttingDown()) {
HandleControlMessages();
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index f0d8d45..227ce2f 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <algorithm>
+#include <filesystem>
#include <string>
#include <utility>
#include <vector>
@@ -32,6 +33,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <fs_mgr.h>
#include <fstab/fstab.h>
@@ -39,6 +41,9 @@
#include "epoll.h"
+using android::base::Basename;
+using android::base::StringPrintf;
+
namespace android {
namespace init {
@@ -67,41 +72,82 @@
return MountHandlerEntry(fields[0], fields[1], fields[2]);
}
+// return sda25 for dm-4, sda25 for sda25, or mmcblk0p24 for mmcblk0p24
+std::string GetDiskPart(std::string blockdev) {
+ if (blockdev.find('/') != std::string::npos) return {};
+
+ while (android::base::StartsWith(blockdev, "dm-")) {
+ auto& dm = dm::DeviceMapper::Instance();
+ std::optional<std::string> parent = dm.GetParentBlockDeviceByPath("/dev/block/" + blockdev);
+ if (parent) {
+ blockdev = android::base::Basename(*parent);
+ } else {
+ return {};
+ }
+ }
+ return blockdev;
+}
+
+// return sda for sda25, or mmcblk0 for mmcblk0p24
+std::string GetRootDisk(std::string blockdev) {
+ if (blockdev.empty()) return {};
+ if (blockdev.find('/') != std::string::npos) return {};
+
+ std::error_code ec;
+ for (const auto& entry : std::filesystem::directory_iterator("/sys/block", ec)) {
+ const std::string path = entry.path().string();
+ if (std::filesystem::exists(StringPrintf("%s/%s", path.c_str(), blockdev.c_str()))) {
+ return Basename(path);
+ }
+ }
+ return {};
+}
+
void SetMountProperty(const MountHandlerEntry& entry, bool add) {
static constexpr char devblock[] = "/dev/block/";
if (!android::base::StartsWith(entry.blk_device, devblock)) return;
- std::string value;
+ auto target = entry.blk_device.substr(strlen(devblock));
+ std::string diskpart, rootdisk;
if (add) {
- value = entry.blk_device.substr(strlen(devblock));
- if (android::base::StartsWith(value, "sd")) {
- // All sd partitions inherit their queue characteristics
- // from the whole device reference. Strip partition number.
- auto it = std::find_if(value.begin(), value.end(), [](char c) { return isdigit(c); });
- if (it != value.end()) value.erase(it, value.end());
- }
- auto queue = "/sys/block/" + value + "/queue";
+ diskpart = GetDiskPart(target);
+ rootdisk = GetRootDisk(diskpart);
+
struct stat sb;
- if (stat(queue.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
- if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) value = "";
+ if (stat(entry.mount_point.c_str(), &sb) || !S_ISDIR(sb.st_mode)) rootdisk = "";
// Clear the noise associated with loopback and APEX.
- if (android::base::StartsWith(value, "loop")) value = "";
- if (android::base::StartsWith(entry.mount_point, "/apex/")) value = "";
+ if (android::base::StartsWith(target, "loop")) rootdisk = "";
+ if (android::base::StartsWith(entry.mount_point, "/apex/")) rootdisk = "";
}
auto mount_prop = entry.mount_point;
if (mount_prop == "/") mount_prop = "/root";
std::replace(mount_prop.begin(), mount_prop.end(), '/', '.');
auto blk_mount_prop = "dev.mnt.blk" + mount_prop;
auto dev_mount_prop = "dev.mnt.dev" + mount_prop;
- // Set property even if its value does not change to trigger 'on property:'
+ auto rootdisk_mount_prop = "dev.mnt.rootdisk" + mount_prop;
+ // Set property even if its rootdisk does not change to trigger 'on property:'
// handling, except for clearing non-existent or already clear property.
// Goal is reduction of empty properties and associated triggers.
- if (value.empty() && android::base::GetProperty(blk_mount_prop, "").empty()) return;
- android::base::SetProperty(blk_mount_prop, value);
- if (!value.empty()) {
- android::base::SetProperty(dev_mount_prop, entry.blk_device.substr(strlen(devblock)));
- } else {
+ if (rootdisk.empty() && android::base::GetProperty(blk_mount_prop, "").empty()) return;
+
+ if (rootdisk.empty()) {
+ android::base::SetProperty(blk_mount_prop, "");
android::base::SetProperty(dev_mount_prop, "");
+ android::base::SetProperty(rootdisk_mount_prop, "");
+ return;
}
+
+ // 1. dm-N
+ // dev.mnt.dev.data = dm-N
+ // dev.mnt.blk.data = sdaN or mmcblk0pN
+ // dev.mnt.rootdisk.data = sda or mmcblk0
+ //
+ // 2. sdaN or mmcblk0pN
+ // dev.mnt.dev.data = sdaN or mmcblk0pN
+ // dev.mnt.blk.data = sdaN or mmcblk0pN
+ // dev.mnt.rootdisk.data = sda or mmcblk0
+ android::base::SetProperty(dev_mount_prop, target);
+ android::base::SetProperty(blk_mount_prop, diskpart);
+ android::base::SetProperty(rootdisk_mount_prop, rootdisk);
}
} // namespace
diff --git a/init/selinux.cpp b/init/selinux.cpp
index c89c5ab..be8c554 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -762,6 +762,7 @@
void SelinuxRestoreContext() {
LOG(INFO) << "Running restorecon...";
selinux_android_restorecon("/dev", 0);
+ selinux_android_restorecon("/dev/console", 0);
selinux_android_restorecon("/dev/kmsg", 0);
if constexpr (WORLD_WRITABLE_KMSG) {
selinux_android_restorecon("/dev/kmsg_debug", 0);
diff --git a/init/service.cpp b/init/service.cpp
index 8a9cc0a..2ebf87e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -127,6 +127,7 @@
unsigned long Service::next_start_order_ = 1;
bool Service::is_exec_service_running_ = false;
+std::chrono::time_point<std::chrono::steady_clock> Service::exec_service_started_;
Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
const std::vector<std::string>& args, bool from_apex)
@@ -388,6 +389,7 @@
flags_ |= SVC_EXEC;
is_exec_service_running_ = true;
+ exec_service_started_ = std::chrono::steady_clock::now();
LOG(INFO) << "SVC_EXEC service '" << name_ << "' pid " << pid_ << " (uid " << proc_attr_.uid
<< " gid " << proc_attr_.gid << "+" << proc_attr_.supp_gids.size() << " context "
diff --git a/init/service.h b/init/service.h
index 3f12aa2..d233cbf 100644
--- a/init/service.h
+++ b/init/service.h
@@ -102,6 +102,9 @@
size_t CheckAllCommands() const { return onrestart_.CheckAllCommands(); }
static bool is_exec_service_running() { return is_exec_service_running_; }
+ static std::chrono::time_point<std::chrono::steady_clock> exec_service_started() {
+ return exec_service_started_;
+ }
const std::string& name() const { return name_; }
const std::set<std::string>& classnames() const { return classnames_; }
@@ -154,6 +157,8 @@
static unsigned long next_start_order_;
static bool is_exec_service_running_;
+ static std::chrono::time_point<std::chrono::steady_clock> exec_service_started_;
+ static pid_t exec_service_pid_;
std::string name_;
std::set<std::string> classnames_;
diff --git a/init/switch_root.cpp b/init/switch_root.cpp
index 575b67f..86fad80 100644
--- a/init/switch_root.cpp
+++ b/init/switch_root.cpp
@@ -78,7 +78,8 @@
auto new_mount_path = new_root + mount_path;
mkdir(new_mount_path.c_str(), 0755);
if (mount(mount_path.c_str(), new_mount_path.c_str(), nullptr, MS_MOVE, nullptr) != 0) {
- PLOG(FATAL) << "Unable to move mount at '" << mount_path << "'";
+ PLOG(FATAL) << "Unable to move mount at '" << mount_path << "' to "
+ << "'" << new_mount_path << "'";
}
}
diff --git a/libcutils/TEST_MAPPING b/libcutils/TEST_MAPPING
index e512ab7..cca7d93 100644
--- a/libcutils/TEST_MAPPING
+++ b/libcutils/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name": "libcutils_test"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "libcutils_test"
+ }
]
}
diff --git a/libcutils/trace-container.cpp b/libcutils/trace-container.cpp
index ef7c72d..f3fdda4 100644
--- a/libcutils/trace-container.cpp
+++ b/libcutils/trace-container.cpp
@@ -131,29 +131,41 @@
// Write trace events to container trace file. Note that we need to amend tid and time information
// here comparing to normal ftrace, where those informations are added by kernel.
-#define WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value) { \
+#define WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, \
+ track_name, name, value) { \
char buf[CONTAINER_ATRACE_MESSAGE_LENGTH]; \
+ const char* track_name_sep = track_name[0] != '\0' ? "|" : ""; \
int pid = getpid(); \
int tid = gettid(); \
uint64_t ts = gettime(CLOCK_MONOTONIC); \
uint64_t tts = gettime(CLOCK_THREAD_CPUTIME_ID); \
int len = snprintf( \
buf, sizeof(buf), \
- ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s" value_format, \
- pid, tid, ts, tts, name, value); \
+ ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s%s%s" value_format, \
+ pid, tid, ts, tts, track_name, track_name_sep, name, value); \
if (len >= (int) sizeof(buf)) { \
int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
/* Truncate the name to make the message fit. */ \
if (name_len > 0) { \
- ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
len = snprintf( \
- buf, sizeof(buf), \
- ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%.*s" value_format, \
- pid, tid, ts, tts, name_len, name, value); \
+ buf, sizeof(buf), \
+ ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%s%s%.*s" value_format, \
+ pid, tid, ts, tts, track_name, track_name_sep, name_len, name, value); \
} else { \
- /* Data is still too long. Drop it. */ \
- ALOGW("Data is too long in %s: %s\n", __FUNCTION__, name); \
- len = 0; \
+ int track_name_len = 0; \
+ if (track_name[0] != '\0') { \
+ track_name_len = strlen(track_name) - (len - strlen(name) - sizeof(buf)) - 2; \
+ } \
+ if (track_name_len <= 0){ \
+ /* Data is still too long. Drop it. */ \
+ len = 0; \
+ } else { \
+ /* Truncate the trackName and name to make the message fit. */ \
+ len = snprintf( \
+ buf, sizeof(buf), \
+ ph "|%d|%d|%" PRIu64 "|%" PRIu64 sep_before_name "%.*s|%.1s" value_format, \
+ pid, tid, ts, tts, track_name_len, track_name, name, value); \
+ } \
} \
} \
if (len > 0) { \
@@ -161,10 +173,10 @@
} \
}
-#define WRITE_MSG_IN_CONTAINER(ph, sep_before_name, value_format, name, value) { \
+#define WRITE_MSG_IN_CONTAINER(ph, sep_before_name, value_format, track_name, name, value) { \
pthread_rwlock_rdlock(&atrace_container_sock_rwlock); \
if (atrace_container_sock_fd != -1) { \
- WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, name, value); \
+ WRITE_MSG_IN_CONTAINER_LOCKED(ph, sep_before_name, value_format, track_name, name, value); \
} \
pthread_rwlock_unlock(&atrace_container_sock_rwlock); \
}
@@ -172,93 +184,93 @@
void atrace_begin_body(const char* name)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("B", "|", "%s", name, "");
+ WRITE_MSG_IN_CONTAINER("B", "|", "%s", "", name, "");
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("B|%d|", "%s", name, "");
+ WRITE_MSG("B|%d|", "%s", "", name, "");
}
void atrace_end_body()
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("E", "", "%s", "", "");
+ WRITE_MSG_IN_CONTAINER("E", "", "%s", "", "", "");
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("E|%d", "%s", "", "");
+ WRITE_MSG("E|%d", "%s", "", "", "");
}
void atrace_async_begin_body(const char* name, int32_t cookie)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("S", "|", "|%d", name, cookie);
+ WRITE_MSG_IN_CONTAINER("S", "|", "|%d", "", name, cookie);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
+ WRITE_MSG("S|%d|", "|%" PRId32, "", name, cookie);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("F", "|", "|%d", name, cookie);
+ WRITE_MSG_IN_CONTAINER("F", "|", "|%d", "", name, cookie);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
+ WRITE_MSG("F|%d|", "|%" PRId32, "", name, cookie);
}
void atrace_instant_body(const char* name) {
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("I", "|", "%s", name, "");
+ WRITE_MSG_IN_CONTAINER("I", "|", "%s", "", name, "");
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("I|%d|", "%s", name, "");
+ WRITE_MSG("I|%d|", "%s", "", name, "");
}
-void atrace_instant_for_track_body(const char* trackName, const char* name) {
+void atrace_instant_for_track_body(const char* track_name, const char* name) {
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("N", "|", "|%s", trackName, name);
+ WRITE_MSG_IN_CONTAINER("N", "|", "%s", track_name, name, "");
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("N|%d|", "|%s", name, trackName);
+ WRITE_MSG("N|%d|", "%s", track_name, name, "");
}
void atrace_int_body(const char* name, int32_t value)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId32, name, value);
+ WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId32, "", name, value);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("C|%d|", "|%" PRId32, name, value);
+ WRITE_MSG("C|%d|", "|%" PRId32, "", name, value);
}
void atrace_int64_body(const char* name, int64_t value)
{
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId64, name, value);
+ WRITE_MSG_IN_CONTAINER("C", "|", "|%" PRId64, "", name, value);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("C|%d|", "|%" PRId64, name, value);
+ WRITE_MSG("C|%d|", "|%" PRId64, "", name, value);
}
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 25c86f4..8bdeac5 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -71,38 +71,38 @@
void atrace_begin_body(const char* name)
{
- WRITE_MSG("B|%d|", "%s", name, "");
+ WRITE_MSG("B|%d|", "%s", "", name, "");
}
void atrace_end_body()
{
- WRITE_MSG("E|%d", "%s", "", "");
+ WRITE_MSG("E|%d", "%s", "", "", "");
}
void atrace_async_begin_body(const char* name, int32_t cookie)
{
- WRITE_MSG("S|%d|", "|%" PRId32, name, cookie);
+ WRITE_MSG("S|%d|", "|%" PRId32, "", name, cookie);
}
void atrace_async_end_body(const char* name, int32_t cookie)
{
- WRITE_MSG("F|%d|", "|%" PRId32, name, cookie);
+ WRITE_MSG("F|%d|", "|%" PRId32, "", name, cookie);
}
void atrace_instant_body(const char* name) {
- WRITE_MSG("I|%d|", "%s", name, "");
+ WRITE_MSG("I|%d|", "%s", "", name, "");
}
-void atrace_instant_for_track_body(const char* trackName, const char* name) {
- WRITE_MSG("N|%d|", "|%s", trackName, name);
+void atrace_instant_for_track_body(const char* track_name, const char* name) {
+ WRITE_MSG("N|%d|", "%s", track_name, name, "");
}
void atrace_int_body(const char* name, int32_t value)
{
- WRITE_MSG("C|%d|", "|%" PRId32, name, value);
+ WRITE_MSG("C|%d|", "|%" PRId32, "", name, value);
}
void atrace_int64_body(const char* name, int64_t value)
{
- WRITE_MSG("C|%d|", "|%" PRId64, name, value);
+ WRITE_MSG("C|%d|", "|%" PRId64, "", name, value);
}
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index 3b459e0..94945ec 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -185,21 +185,36 @@
}
}
-#define WRITE_MSG(format_begin, format_end, name, value) { \
+#define WRITE_MSG(format_begin, format_end, track_name, name, value) { \
char buf[ATRACE_MESSAGE_LENGTH] __attribute__((uninitialized)); \
+ const char* track_name_sep = track_name[0] != '\0' ? "|" : ""; \
int pid = getpid(); \
- int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
- name, value); \
+ int len = snprintf(buf, sizeof(buf), format_begin "%s%s%s" format_end, pid, \
+ track_name, track_name_sep, name, value); \
if (len >= (int) sizeof(buf)) { \
- /* Given the sizeof(buf), and all of the current format buffers, \
- * it is impossible for name_len to be < 0 if len >= sizeof(buf). */ \
int name_len = strlen(name) - (len - sizeof(buf)) - 1; \
/* Truncate the name to make the message fit. */ \
- ALOGW("Truncated name in %s: %s\n", __FUNCTION__, name); \
- len = snprintf(buf, sizeof(buf), format_begin "%.*s" format_end, pid, \
- name_len, name, value); \
+ if (name_len > 0) { \
+ len = snprintf(buf, sizeof(buf), format_begin "%s%s%.*s" format_end, pid, \
+ track_name, track_name_sep, name_len, name, value); \
+ } else { \
+ int track_name_len = 0; \
+ if (track_name[0] != '\0') { \
+ track_name_len = strlen(track_name) - (len - strlen(name) - sizeof(buf)) - 2; \
+ } \
+ if (track_name_len <= 0) { \
+ /* Data is still too long. Drop it. */ \
+ len = 0; \
+ } else { \
+ /* Truncate the trackName and name to make the message fit */ \
+ len = snprintf(buf, sizeof(buf), format_begin "%.*s|%.1s" format_end, pid, \
+ track_name_len, track_name, name, value); \
+ } \
+ } \
} \
- write(atrace_marker_fd, buf, len); \
+ if (len > 0) { \
+ write(atrace_marker_fd, buf, len); \
+ } \
}
#endif // __TRACE_DEV_INC
diff --git a/libcutils/trace-dev_test.cpp b/libcutils/trace-dev_test.cpp
index ff6d202..29a5590 100644
--- a/libcutils/trace-dev_test.cpp
+++ b/libcutils/trace-dev_test.cpp
@@ -255,43 +255,100 @@
ASSERT_STREQ(expected.c_str(), actual.c_str());
}
-TEST_F(TraceDevTest, atrace_instant_for_track_body_exact) {
- const int nameSize = 5;
+TEST_F(TraceDevTest, atrace_instant_for_track_body_exact_track_name) {
+ const int name_size = 5;
std::string expected = android::base::StringPrintf("N|%d|", getpid());
- std::string trackName = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - nameSize);
- atrace_instant_for_track_body(trackName.c_str(), "name");
+ std::string track_name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - name_size);
+ atrace_instant_for_track_body(track_name.c_str(), "name");
ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
std::string actual;
ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- expected += trackName + "|name";
+ expected += track_name + "|name";
ASSERT_STREQ(expected.c_str(), actual.c_str());
- // Add a single character and verify we get the exact same value as before.
+ // Add a single character and verify name truncation
ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
- trackName += '*';
- atrace_instant_for_track_body(trackName.c_str(), "name");
+ track_name += '*';
+ expected = android::base::StringPrintf("N|%d|", getpid());
+ expected += track_name + "|nam";
+ atrace_instant_for_track_body(track_name.c_str(), "name");
EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
ASSERT_STREQ(expected.c_str(), actual.c_str());
}
-TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated) {
- const int nameSize = 5;
+TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated_track_name) {
std::string expected = android::base::StringPrintf("N|%d|", getpid());
- std::string trackName = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_instant_for_track_body(trackName.c_str(), "name");
+ std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+ atrace_instant_for_track_body(track_name.c_str(), "name");
ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
std::string actual;
ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1 - nameSize;
- expected += android::base::StringPrintf("%.*s|name", expected_len, trackName.c_str());
+ int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 3;
+ expected += android::base::StringPrintf("%.*s|n", expected_len, track_name.c_str());
+ ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_for_track_body_exact_name) {
+ const int track_name_size = 11;
+ std::string expected = android::base::StringPrintf("N|%d|", getpid());
+ std::string name = MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - track_name_size);
+ atrace_instant_for_track_body("track_name", name.c_str());
+
+ ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+ ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+ std::string actual;
+ ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+ expected += "track_name|" + name;
+ ASSERT_STREQ(expected.c_str(), actual.c_str());
+
+ // Add a single character and verify we get the same value as before.
+ ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+ name += '*';
+ atrace_instant_for_track_body("track_name", name.c_str());
+ EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+ ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+ ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+ ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated_name) {
+ std::string expected = android::base::StringPrintf("N|%d|track_name|", getpid());
+ std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+ atrace_instant_for_track_body("track_name", name.c_str());
+
+ ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+ ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+ std::string actual;
+ ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+ int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 1;
+ expected += android::base::StringPrintf("%.*s", expected_len, name.c_str());
+ ASSERT_STREQ(expected.c_str(), actual.c_str());
+}
+
+TEST_F(TraceDevTest, atrace_instant_for_track_body_truncated_both) {
+ std::string expected = android::base::StringPrintf("N|%d|", getpid());
+ std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+ std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
+ atrace_instant_for_track_body(track_name.c_str(), name.c_str());
+
+ ASSERT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
+ ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
+
+ std::string actual;
+ ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
+ int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 3;
+ expected +=
+ android::base::StringPrintf("%.*s|%.1s", expected_len, track_name.c_str(), name.c_str());
ASSERT_STREQ(expected.c_str(), actual.c_str());
}
diff --git a/libmodprobe/TEST_MAPPING b/libmodprobe/TEST_MAPPING
index 526b1e4..888593e 100644
--- a/libmodprobe/TEST_MAPPING
+++ b/libmodprobe/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name": "libmodprobe_tests"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "libmodprobe_tests"
+ }
]
}
diff --git a/libpackagelistparser/TEST_MAPPING b/libpackagelistparser/TEST_MAPPING
index 51773f9..d69a7fb 100644
--- a/libpackagelistparser/TEST_MAPPING
+++ b/libpackagelistparser/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name": "libpackagelistparser_test"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "libpackagelistparser_test"
+ }
]
}
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index c68552d..7b0e0d3 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -73,3 +73,29 @@
],
min_sdk_version: "29",
}
+
+cc_test {
+ name: "task_profiles_test",
+ host_supported: true,
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wexit-time-destructors",
+ "-Wno-unused-parameter",
+ ],
+ srcs: [
+ "task_profiles_test.cpp",
+ ],
+ header_libs: [
+ "libcutils_headers",
+ "libprocessgroup_headers",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcgrouprc",
+ "libprocessgroup",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+}
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 76d5e13..96b5537 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -442,8 +442,8 @@
struct stat cgroup_stat;
mode_t cgroup_mode = 0750;
- gid_t cgroup_uid = AID_SYSTEM;
- uid_t cgroup_gid = AID_SYSTEM;
+ uid_t cgroup_uid = AID_SYSTEM;
+ gid_t cgroup_gid = AID_SYSTEM;
int ret = 0;
if (stat(cgroup.c_str(), &cgroup_stat) == 1) {
diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json
index 0634220..3e4393d 100644
--- a/libprocessgroup/profiles/cgroups.json
+++ b/libprocessgroup/profiles/cgroups.json
@@ -3,7 +3,7 @@
{
"Controller": "blkio",
"Path": "/dev/blkio",
- "Mode": "0755",
+ "Mode": "0775",
"UID": "system",
"GID": "system"
},
@@ -32,16 +32,13 @@
],
"Cgroups2": {
"Path": "/sys/fs/cgroup",
- "Mode": "0755",
+ "Mode": "0775",
"UID": "system",
"GID": "system",
"Controllers": [
{
"Controller": "freezer",
- "Path": ".",
- "Mode": "0755",
- "UID": "system",
- "GID": "system"
+ "Path": "."
}
]
}
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index b668dcb..7e03964 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -16,14 +16,21 @@
"File": "top-app/cpus"
},
{
+ "Name": "MemStats",
+ "Controller": "memory",
+ "File": "memory.stat"
+ },
+ {
"Name": "MemLimit",
"Controller": "memory",
- "File": "memory.limit_in_bytes"
+ "File": "memory.limit_in_bytes",
+ "FileV2": "memory.max"
},
{
"Name": "MemSoftLimit",
"Controller": "memory",
- "File": "memory.soft_limit_in_bytes"
+ "File": "memory.soft_limit_in_bytes",
+ "FileV2": "memory.low"
},
{
"Name": "MemSwappiness",
@@ -31,6 +38,26 @@
"File": "memory.swappiness"
},
{
+ "Name": "MemUsage",
+ "Controller": "memory",
+ "File": "memory.usage_in_bytes"
+ },
+ {
+ "Name": "MemAndSwapUsage",
+ "Controller": "memory",
+ "File": "memory.memsw.usage_in_bytes"
+ },
+ {
+ "Name": "MemPressureLevel",
+ "Controller": "memory",
+ "File": "memory.pressure_level"
+ },
+ {
+ "Name": "MemCgroupEventControl",
+ "Controller": "memory",
+ "File": "cgroup.event_control"
+ },
+ {
"Name": "UClampMin",
"Controller": "cpu",
"File": "cpu.uclamp.min"
diff --git a/libprocessgroup/profiles/task_profiles.proto b/libprocessgroup/profiles/task_profiles.proto
index 1de4395..ebcd9b5 100644
--- a/libprocessgroup/profiles/task_profiles.proto
+++ b/libprocessgroup/profiles/task_profiles.proto
@@ -25,11 +25,13 @@
repeated AggregateProfiles aggregateprofiles = 3 [json_name = "AggregateProfiles"];
}
-// Next: 4
+// Next: 6
message Attribute {
string name = 1 [json_name = "Name"];
string controller = 2 [json_name = "Controller"];
string file = 3 [json_name = "File"];
+ string filev2 = 4 [json_name = "FileV2"];
+ string optional = 5 [json_name = "Optional"];
}
// Next: 3
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index dc7c368..78a316a 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -129,11 +129,12 @@
return true;
}
+ const std::string& file_name =
+ controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_;
if (subgroup.empty()) {
- *path = StringPrintf("%s/%s", controller()->path(), file_name_.c_str());
+ *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str());
} else {
- *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(),
- file_name_.c_str());
+ *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str());
}
return true;
}
@@ -206,6 +207,14 @@
}
if (!WriteStringToFile(value_, path)) {
+ if (errno == ENOENT) {
+ if (optional_) {
+ return true;
+ } else {
+ LOG(ERROR) << "No such cgroup attribute: " << path;
+ return false;
+ }
+ }
PLOG(ERROR) << "Failed to write '" << value_ << "' to " << path;
return false;
}
@@ -625,12 +634,19 @@
std::string name = attr[i]["Name"].asString();
std::string controller_name = attr[i]["Controller"].asString();
std::string file_attr = attr[i]["File"].asString();
+ std::string file_v2_attr = attr[i]["FileV2"].asString();
+
+ if (!file_v2_attr.empty() && file_attr.empty()) {
+ LOG(ERROR) << "Attribute " << name << " has FileV2 but no File property";
+ return false;
+ }
auto controller = cg_map.FindController(controller_name);
if (controller.HasValue()) {
auto iter = attributes_.find(name);
if (iter == attributes_.end()) {
- attributes_[name] = std::make_unique<ProfileAttribute>(controller, file_attr);
+ attributes_[name] =
+ std::make_unique<ProfileAttribute>(controller, file_attr, file_v2_attr);
} else {
iter->second->Reset(controller, file_attr);
}
@@ -675,11 +691,12 @@
} else if (action_name == "SetAttribute") {
std::string attr_name = params_val["Name"].asString();
std::string attr_value = params_val["Value"].asString();
+ bool optional = strcmp(params_val["Optional"].asString().c_str(), "true") == 0;
auto iter = attributes_.find(attr_name);
if (iter != attributes_.end()) {
- profile->Add(
- std::make_unique<SetAttributeAction>(iter->second.get(), attr_value));
+ profile->Add(std::make_unique<SetAttributeAction>(iter->second.get(),
+ attr_value, optional));
} else {
LOG(WARNING) << "SetAttribute: unknown attribute: " << attr_name;
}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 9ee3781..df08f65 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -37,8 +37,12 @@
class ProfileAttribute : public IProfileAttribute {
public:
- ProfileAttribute(const CgroupController& controller, const std::string& file_name)
- : controller_(controller), file_name_(file_name) {}
+ // Cgroup attributes may have different names in the v1 and v2 hierarchies. If `file_v2_name` is
+ // not empty, `file_name` is the name for the v1 hierarchy and `file_v2_name` is the name for
+ // the v2 hierarchy. If `file_v2_name` is empty, `file_name` is used for both hierarchies.
+ ProfileAttribute(const CgroupController& controller, const std::string& file_name,
+ const std::string& file_v2_name)
+ : controller_(controller), file_name_(file_name), file_v2_name_(file_v2_name) {}
~ProfileAttribute() = default;
const CgroupController* controller() const override { return &controller_; }
@@ -50,6 +54,7 @@
private:
CgroupController controller_;
std::string file_name_;
+ std::string file_v2_name_;
};
// Abstract profile element
@@ -102,8 +107,8 @@
// Set attribute profile element
class SetAttributeAction : public ProfileAction {
public:
- SetAttributeAction(const IProfileAttribute* attribute, const std::string& value)
- : attribute_(attribute), value_(value) {}
+ SetAttributeAction(const IProfileAttribute* attribute, const std::string& value, bool optional)
+ : attribute_(attribute), value_(value), optional_(optional) {}
const char* Name() const override { return "SetAttribute"; }
bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
@@ -112,6 +117,7 @@
private:
const IProfileAttribute* attribute_;
std::string value_;
+ bool optional_;
};
// Set cgroup profile element
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
new file mode 100644
index 0000000..09ac44c
--- /dev/null
+++ b/libprocessgroup/task_profiles_test.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "task_profiles.h"
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <mntent.h>
+#include <processgroup/processgroup.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <fstream>
+
+using ::android::base::ERROR;
+using ::android::base::LogFunction;
+using ::android::base::LogId;
+using ::android::base::LogSeverity;
+using ::android::base::SetLogger;
+using ::android::base::VERBOSE;
+using ::testing::TestWithParam;
+using ::testing::Values;
+
+namespace {
+
+bool IsCgroupV2Mounted() {
+ std::unique_ptr<FILE, int (*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
+ if (!mnts) {
+ LOG(ERROR) << "Failed to open /proc/mounts";
+ return false;
+ }
+ struct mntent* mnt;
+ while ((mnt = getmntent(mnts.get()))) {
+ if (strcmp(mnt->mnt_fsname, "cgroup2") == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+class ScopedLogCapturer {
+ public:
+ struct log_args {
+ LogId log_buffer_id;
+ LogSeverity severity;
+ std::string tag;
+ std::string file;
+ unsigned int line;
+ std::string message;
+ };
+
+ // Constructor. Installs a new logger and saves the currently active logger.
+ ScopedLogCapturer() {
+ saved_severity_ = SetMinimumLogSeverity(android::base::VERBOSE);
+ saved_logger_ = SetLogger([this](LogId log_buffer_id, LogSeverity severity, const char* tag,
+ const char* file, unsigned int line, const char* message) {
+ if (saved_logger_) {
+ saved_logger_(log_buffer_id, severity, tag, file, line, message);
+ }
+ log_.emplace_back(log_args{.log_buffer_id = log_buffer_id,
+ .severity = severity,
+ .tag = tag,
+ .file = file,
+ .line = line,
+ .message = message});
+ });
+ }
+ // Destructor. Restores the original logger and log level.
+ ~ScopedLogCapturer() {
+ SetLogger(std::move(saved_logger_));
+ SetMinimumLogSeverity(saved_severity_);
+ }
+ ScopedLogCapturer(const ScopedLogCapturer&) = delete;
+ ScopedLogCapturer& operator=(const ScopedLogCapturer&) = delete;
+ // Returns the logged lines.
+ const std::vector<log_args>& Log() const { return log_; }
+
+ private:
+ LogSeverity saved_severity_;
+ LogFunction saved_logger_;
+ std::vector<log_args> log_;
+};
+
+// cgroup attribute at the top level of the cgroup hierarchy.
+class ProfileAttributeMock : public IProfileAttribute {
+ public:
+ ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {}
+ ~ProfileAttributeMock() override = default;
+ void Reset(const CgroupController& controller, const std::string& file_name) override {
+ CHECK(false);
+ }
+ const CgroupController* controller() const override {
+ CHECK(false);
+ return {};
+ }
+ const std::string& file_name() const override { return file_name_; }
+ bool GetPathForTask(int tid, std::string* path) const override {
+#ifdef __ANDROID__
+ CHECK(CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, path));
+ CHECK_GT(path->length(), 0);
+ if (path->rbegin()[0] != '/') {
+ *path += "/";
+ }
+#else
+ // Not Android.
+ *path = "/sys/fs/cgroup/";
+#endif
+ *path += file_name_;
+ return true;
+ };
+
+ private:
+ const std::string file_name_;
+};
+
+struct TestParam {
+ const char* attr_name;
+ const char* attr_value;
+ bool optional_attr;
+ bool result;
+ LogSeverity log_severity;
+ const char* log_prefix;
+ const char* log_suffix;
+};
+
+class SetAttributeFixture : public TestWithParam<TestParam> {
+ public:
+ ~SetAttributeFixture() = default;
+};
+
+TEST_P(SetAttributeFixture, SetAttribute) {
+ // Treehugger runs host tests inside a container without cgroupv2 support.
+ if (!IsCgroupV2Mounted()) {
+ GTEST_SKIP();
+ return;
+ }
+ const TestParam params = GetParam();
+ ScopedLogCapturer captured_log;
+ ProfileAttributeMock pa(params.attr_name);
+ SetAttributeAction a(&pa, params.attr_value, params.optional_attr);
+ EXPECT_EQ(a.ExecuteForProcess(getuid(), getpid()), params.result);
+ auto log = captured_log.Log();
+ if (params.log_prefix || params.log_suffix) {
+ ASSERT_EQ(log.size(), 1);
+ EXPECT_EQ(log[0].severity, params.log_severity);
+ if (params.log_prefix) {
+ EXPECT_EQ(log[0].message.find(params.log_prefix), 0);
+ }
+ if (params.log_suffix) {
+ EXPECT_NE(log[0].message.find(params.log_suffix), std::string::npos);
+ }
+ } else {
+ ASSERT_EQ(log.size(), 0);
+ }
+}
+
+// Test the four combinations of optional_attr {false, true} and cgroup attribute { does not exist,
+// exists }.
+INSTANTIATE_TEST_SUITE_P(
+ SetAttributeTestSuite, SetAttributeFixture,
+ Values(
+ // Test that attempting to write into a non-existing cgroup attribute fails and also
+ // that an error message is logged.
+ TestParam{.attr_name = "no-such-attribute",
+ .attr_value = ".",
+ .optional_attr = false,
+ .result = false,
+ .log_severity = ERROR,
+ .log_prefix = "No such cgroup attribute"},
+ // Test that attempting to write into an optional non-existing cgroup attribute
+ // results in the return value 'true' and also that no messages are logged.
+ TestParam{.attr_name = "no-such-attribute",
+ .attr_value = ".",
+ .optional_attr = true,
+ .result = true},
+ // Test that attempting to write an invalid value into an existing optional cgroup
+ // attribute fails and also that it causes an error
+ // message to be logged.
+ TestParam{.attr_name = "cgroup.procs",
+ .attr_value = "-1",
+ .optional_attr = true,
+ .result = false,
+ .log_severity = ERROR,
+ .log_prefix = "Failed to write",
+ .log_suffix = geteuid() == 0 ? "Invalid argument" : "Permission denied"},
+ // Test that attempting to write into an existing optional read-only cgroup
+ // attribute fails and also that it causes an error message to be logged.
+ TestParam{
+ .attr_name = "cgroup.controllers",
+ .attr_value = ".",
+ .optional_attr = false,
+ .result = false,
+ .log_severity = ERROR,
+ .log_prefix = "Failed to write",
+ .log_suffix = geteuid() == 0 ? "Invalid argument" : "Permission denied"}));
+
+} // namespace
diff --git a/libstats/pull_lazy/TEST_MAPPING b/libstats/pull_lazy/TEST_MAPPING
index 89b8c2a..92f1e6a 100644
--- a/libstats/pull_lazy/TEST_MAPPING
+++ b/libstats/pull_lazy/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name" : "libstatspull_lazy_test"
}
+ ],
+ "hwasan-postsubmit" : [
+ {
+ "name" : "libstatspull_lazy_test"
+ }
]
}
\ No newline at end of file
diff --git a/libstats/socket_lazy/TEST_MAPPING b/libstats/socket_lazy/TEST_MAPPING
index 13afc00..b182660 100644
--- a/libstats/socket_lazy/TEST_MAPPING
+++ b/libstats/socket_lazy/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name" : "libstatssocket_lazy_test"
}
+ ],
+ "hwasan-postsubmit" : [
+ {
+ "name" : "libstatssocket_lazy_test"
+ }
]
}
\ No newline at end of file
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index 0518927..4ddac3d 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -50,12 +50,7 @@
// log all reference counting operations
#define PRINT_REFS 0
-// Continue after logging a stack trace if ~RefBase discovers that reference
-// count has never been incremented. Normally we conspicuously crash in that
-// case.
-#define DEBUG_REFBASE_DESTRUCTION 1
-
-#if !defined(_WIN32) && !defined(__APPLE__)
+#if defined(__linux__)
// CallStack is only supported on linux type platforms.
#define CALLSTACK_ENABLED 1
#else
@@ -751,17 +746,19 @@
}
} else if (mRefs->mStrong.load(std::memory_order_relaxed) == INITIAL_STRONG_VALUE) {
// We never acquired a strong reference on this object.
-#if DEBUG_REFBASE_DESTRUCTION
- // Treating this as fatal is prone to causing boot loops. For debugging, it's
- // better to treat as non-fatal.
- ALOGD("RefBase: Explicit destruction, weak count = %d (in %p)", mRefs->mWeak.load(), this);
+
+ // TODO: make this fatal, but too much code in Android manages RefBase with
+ // new/delete manually (or using other mechanisms such as std::make_unique).
+ // However, this is dangerous because it's also common for code to use the
+ // sp<T>(T*) constructor, assuming that if the object is around, it is already
+ // owned by an sp<>.
+ ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this "
+ "object.",
+ mRefs->mWeak.load(), this);
#if CALLSTACK_ENABLED
CallStack::logStack(LOG_TAG);
#endif
-#else
- LOG_ALWAYS_FATAL("RefBase: Explicit destruction, weak count = %d", mRefs->mWeak.load());
-#endif
}
// For debugging purposes, clear mRefs. Ineffective against outstanding wp's.
const_cast<weakref_impl*&>(mRefs) = nullptr;
diff --git a/libutils/include/utils/Compat.h b/libutils/include/utils/Compat.h
index 6002567..3221899 100644
--- a/libutils/include/utils/Compat.h
+++ b/libutils/include/utils/Compat.h
@@ -71,19 +71,17 @@
#define CONSTEXPR
#endif
-/*
- * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
- * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
- * not already defined, then define it here.
- */
+/* TEMP_FAILURE_RETRY is not available on macOS, but still useful there. */
#ifndef TEMP_FAILURE_RETRY
/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) ({ \
- typeof (exp) _rc; \
- do { \
- _rc = (exp); \
- } while (_rc == -1 && errno == EINTR); \
- _rc; })
+#define TEMP_FAILURE_RETRY(exp) \
+ ({ \
+ __typeof__(exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; \
+ })
#endif
#if defined(_WIN32)
diff --git a/libutils/include/utils/Errors.h b/libutils/include/utils/Errors.h
index d14d223..22fb36d 100644
--- a/libutils/include/utils/Errors.h
+++ b/libutils/include/utils/Errors.h
@@ -34,15 +34,13 @@
* All error codes are negative values.
*/
-// Win32 #defines NO_ERROR as well. It has the same value, so there's no
-// real conflict, though it's a bit awkward.
-#ifdef _WIN32
-# undef NO_ERROR
-#endif
-
enum {
OK = 0, // Preferred constant for checking success.
+#ifndef NO_ERROR
+ // Win32 #defines NO_ERROR as well. It has the same value, so there's no
+ // real conflict, though it's a bit awkward.
NO_ERROR = OK, // Deprecated synonym for `OK`. Prefer `OK` because it doesn't conflict with Windows.
+#endif
UNKNOWN_ERROR = (-2147483647-1), // INT32_MIN value
@@ -76,10 +74,4 @@
// Human readable name of error
std::string statusToString(status_t status);
-// Restore define; enumeration is in "android" namespace, so the value defined
-// there won't work for Win32 code in a different namespace.
-#ifdef _WIN32
-# define NO_ERROR 0L
-#endif
-
} // namespace android
diff --git a/property_service/TEST_MAPPING b/property_service/TEST_MAPPING
index fcdc86a..20f6c84 100644
--- a/property_service/TEST_MAPPING
+++ b/property_service/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name": "propertyinfoserializer_tests"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "propertyinfoserializer_tests"
+ }
]
}
diff --git a/rootdir/etc/TEST_MAPPING b/rootdir/etc/TEST_MAPPING
index e4d3d5e..1c7b716 100644
--- a/rootdir/etc/TEST_MAPPING
+++ b/rootdir/etc/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name": "CtsBionicTestCases"
}
+ ],
+ "hwasan-postsubmit": [
+ {
+ "name": "CtsBionicTestCases"
+ }
]
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c4c9eca..7ad1c3c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -1008,12 +1008,6 @@
# module, delete if not.
exec - system system -- /system/bin/tzdatacheck /apex/com.android.tzdata/etc/tz /data/misc/zoneinfo
- # If there is no post-fs-data action in the init.<device>.rc file, you
- # must uncomment this line, otherwise encrypted filesystems
- # won't work.
- # Set indication (checked by vold) that we have finished this action
- #setprop vold.post_fs_data_done 1
-
# sys.memfd_use set to false by default, which keeps it disabled
# until it is confirmed that apps and vendor processes don't make
# IOCTLs on ashmem fds any more.
@@ -1085,9 +1079,11 @@
mkdir /dev/sys/fs/by-name 0755 system system
symlink /sys/fs/f2fs/${dev.mnt.dev.data} /dev/sys/fs/by-name/userdata
- # to access dm-<num> sysfs
+ # dev.mnt.dev.data=dm-N, dev.mnt.blk.data=sdaN/mmcblk0pN, dev.mnt.rootdisk.data=sda/mmcblk0, or
+ # dev.mnt.dev.data=sdaN/mmcblk0pN, dev.mnt.blk.data=sdaN/mmcblk0pN, dev.mnt.rootdisk.data=sda/mmcblk0
mkdir /dev/sys/block/by-name 0755 system system
- symlink /sys/devices/virtual/block/${dev.mnt.dev.data} /dev/sys/block/by-name/userdata
+ symlink /sys/class/block/${dev.mnt.dev.data} /dev/sys/block/by-name/userdata
+ symlink /sys/class/block/${dev.mnt.rootdisk.data} /dev/sys/block/by-name/rootdisk
# F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs,
# to avoid power consumption when system becomes mostly idle. Be careful
@@ -1099,8 +1095,9 @@
# limit discard size to 128MB in order to avoid long IO latency
# for filesystem tuning first (dm or sda)
- # Note that, if dm-<num> is used, sda/mmcblk0 should be tuned in vendor/init.rc
+ # this requires enabling selinux entry for sda/mmcblk0 in vendor side
write /dev/sys/block/by-name/userdata/queue/discard_max_bytes 134217728
+ write /dev/sys/block/by-name/rootdisk/queue/discard_max_bytes 134217728
# Permissions for System Server and daemons.
chown system system /sys/power/autosleep
diff --git a/trusty/keymaster/keymint/TEST_MAPPING b/trusty/keymaster/keymint/TEST_MAPPING
index 2400ccd..ae24fb4 100644
--- a/trusty/keymaster/keymint/TEST_MAPPING
+++ b/trusty/keymaster/keymint/TEST_MAPPING
@@ -3,5 +3,10 @@
{
"name" : "vts_treble_vintf_framework_test"
}
+ ],
+ "hwasan-postsubmit" : [
+ {
+ "name" : "vts_treble_vintf_framework_test"
+ }
]
}
\ No newline at end of file
diff --git a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
index df6b0f8..e2f376c 100644
--- a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
+++ b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
@@ -342,6 +342,19 @@
return 0;
}
+static int provision_ids(void) {
+ keymaster::SetAttestationIdsRequest req(4 /* ver */);
+ keymaster::EmptyKeymasterResponse rsp(4 /* ver */);
+
+ req.brand.Reinitialize("trusty", 6);
+ req.device.Reinitialize("trusty", 6);
+ req.product.Reinitialize("trusty", 6);
+ req.manufacturer.Reinitialize("trusty", 6);
+ req.model.Reinitialize("trusty", 6);
+
+ return trusty_keymaster_send(KM_SET_ATTESTATION_IDS, req, &rsp);
+}
+
int main(int argc, char** argv) {
int ret = 0;
@@ -353,10 +366,22 @@
ret = trusty_keymaster_connect();
if (ret) {
fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
- } else {
- ret = parse_xml_file(argv[optind]);
- trusty_keymaster_disconnect();
+ return EXIT_FAILURE;
}
- return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ ret = parse_xml_file(argv[optind]);
+ if (ret) {
+ fprintf(stderr, "parse_xml_file failed %d\n", ret);
+ trusty_keymaster_disconnect();
+ return EXIT_FAILURE;
+ }
+
+ ret = provision_ids();
+ if (ret) {
+ fprintf(stderr, "provision_ids failed %d\n", ret);
+ trusty_keymaster_disconnect();
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
}
diff --git a/trusty/libtrusty/include/trusty/ipc.h b/trusty/libtrusty/include/trusty/ipc.h
index 1fa6fe4..04e84c6 100644
--- a/trusty/libtrusty/include/trusty/ipc.h
+++ b/trusty/libtrusty/include/trusty/ipc.h
@@ -23,15 +23,19 @@
/**
* enum transfer_kind - How to send an fd to Trusty
- * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it will
- * be mapped as nonsecure. Suitable for shared memory. The paired
- * fd must be a "memfd".
- * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will be
- * transitioned to "Secure" memory if Trusty is in TrustZone.
- * This transfer kind is suitable for donating video buffers or
- * other similar resources. The paired fd may need to come from a
- * platform-specific allocator for memory that may be
- * transitioned to "Secure".
+ * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it
+ * will be mapped as nonsecure. Suitable for shared memory.
+ * The paired fd must be a "dma_buf".
+ * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will
+ * be transitioned to "Secure" memory if Trusty is in
+ * TrustZone. This transfer kind is suitable for donating
+ * video buffers or other similar resources. The paired fd
+ * may need to come from a platform-specific allocator for
+ * memory that may be transitioned to "Secure".
+ * @TRUSTY_SEND_SECURE: Send memory that is already "Secure". Memory will be
+ * accessible only to Trusty. The paired fd may need to
+ * come from a platform-specific allocator that returns
+ * "Secure" buffers.
*
* Describes how the user would like the resource in question to be sent to
* Trusty. Options may be valid only for certain kinds of fds.
@@ -39,6 +43,7 @@
enum transfer_kind {
TRUSTY_SHARE = 0,
TRUSTY_LEND = 1,
+ TRUSTY_SEND_SECURE = 2,
};
/**