Merge "Added libinit_headers to Android.bp"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ad0231d..5c7d847 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -293,6 +293,13 @@
"libdebuggerd/test/utility_test.cpp",
],
+ product_variables: {
+ malloc_not_svelte: {
+ srcs: ["libdebuggerd/test/scudo_test.cpp"],
+ header_libs: ["scudo_headers"],
+ },
+ },
+
target: {
android: {
srcs: [
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 967b942..e3ea455 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -51,12 +51,9 @@
#define ATRACE_TAG ATRACE_TAG_BIONIC
#include <utils/Trace.h>
-#include <unwindstack/DexFiles.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
+#include <unwindstack/AndroidUnwinder.h>
+#include <unwindstack/Error.h>
#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
#include "libdebuggerd/backtrace.h"
#include "libdebuggerd/tombstone.h"
@@ -623,9 +620,12 @@
}
// TODO: Use seccomp to lock ourselves down.
- unwindstack::UnwinderFromPid unwinder(256, vm_pid, unwindstack::Regs::CurrentArch());
- if (!unwinder.Init()) {
- LOG(FATAL) << "Failed to init unwinder object.";
+
+ unwindstack::AndroidRemoteUnwinder unwinder(vm_pid, unwindstack::Regs::CurrentArch());
+ unwindstack::ErrorData error_data;
+ if (!unwinder.Initialize(error_data)) {
+ LOG(FATAL) << "Failed to initialize unwinder object: "
+ << unwindstack::GetErrorCodeString(error_data.code);
}
std::string amfd_data;
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index f4ba347..ed90ab4 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1463,6 +1463,60 @@
ASSERT_BACKTRACE_FRAME(result, "bar");
}
+TEST_F(CrasherTest, seccomp_tombstone_thread_abort) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ static const auto dump_type = kDebuggerdTombstone;
+ StartProcess(
+ []() {
+ std::thread abort_thread([] { abort(); });
+ abort_thread.join();
+ },
+ &seccomp_fork);
+
+ StartIntercept(&output_fd, dump_type);
+ FinishCrasher();
+ AssertDeath(SIGABRT);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "abort");
+}
+
+TEST_F(CrasherTest, seccomp_tombstone_multiple_threads_abort) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ static const auto dump_type = kDebuggerdTombstone;
+ StartProcess(
+ []() {
+ std::thread a(foo);
+ std::thread b(bar);
+
+ std::this_thread::sleep_for(100ms);
+
+ std::thread abort_thread([] { abort(); });
+ abort_thread.join();
+ },
+ &seccomp_fork);
+
+ StartIntercept(&output_fd, dump_type);
+ FinishCrasher();
+ AssertDeath(SIGABRT);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "abort");
+ ASSERT_BACKTRACE_FRAME(result, "foo");
+ ASSERT_BACKTRACE_FRAME(result, "bar");
+ ASSERT_BACKTRACE_FRAME(result, "main");
+}
+
TEST_F(CrasherTest, seccomp_backtrace) {
int intercept_result;
unique_fd output_fd;
@@ -1493,6 +1547,40 @@
ASSERT_BACKTRACE_FRAME(result, "bar");
}
+TEST_F(CrasherTest, seccomp_backtrace_from_thread) {
+ int intercept_result;
+ unique_fd output_fd;
+
+ static const auto dump_type = kDebuggerdNativeBacktrace;
+ StartProcess(
+ []() {
+ std::thread a(foo);
+ std::thread b(bar);
+
+ std::this_thread::sleep_for(100ms);
+
+ std::thread raise_thread([] {
+ raise_debugger_signal(dump_type);
+ _exit(0);
+ });
+ raise_thread.join();
+ },
+ &seccomp_fork);
+
+ StartIntercept(&output_fd, dump_type);
+ FinishCrasher();
+ AssertDeath(0);
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
+ ASSERT_BACKTRACE_FRAME(result, "foo");
+ ASSERT_BACKTRACE_FRAME(result, "bar");
+ ASSERT_BACKTRACE_FRAME(result, "main");
+}
+
TEST_F(CrasherTest, seccomp_crash_logcat) {
StartProcess([]() { abort(); }, &seccomp_fork);
FinishCrasher();
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index c8b25ae..4721391 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -31,12 +31,9 @@
#include <android-base/unique_fd.h>
#include <async_safe/log.h>
#include <bionic/reserved_signals.h>
-#include <unwindstack/DexFiles.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Maps.h>
+#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
#include "debuggerd/handler.h"
#include "handler/fallback.h"
@@ -75,11 +72,11 @@
// Do not use the thread cache here because it will call pthread_key_create
// which doesn't work in linker code. See b/189803009.
- // Use a normal cached object because the process is stopped, and there
+ // Use a normal cached object because the thread is stopped, and there
// is no chance of data changing between reads.
auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
// TODO: Create this once and store it in a global?
- unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid(), process_memory);
+ unwindstack::AndroidLocalUnwinder unwinder(process_memory);
dump_backtrace_thread(output_fd, &unwinder, thread);
}
__linker_disable_fallback_allocator();
@@ -213,7 +210,10 @@
// Send a signal to all of our siblings, asking them to dump their stack.
pid_t current_tid = gettid();
- if (!iterate_tids(current_tid, [&output_fd](pid_t tid) {
+ if (!iterate_tids(current_tid, [&output_fd, ¤t_tid](pid_t tid) {
+ if (current_tid == tid) {
+ return;
+ }
// Use a pipe, to be able to detect situations where the thread gracefully exits before
// receiving our signal.
unique_fd pipe_read, pipe_write;
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index fd91038..3ff9710 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -37,6 +37,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <log/log.h>
+#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Unwinder.h>
#include "libdebuggerd/types.h"
@@ -57,7 +58,7 @@
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
-void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+void dump_backtrace_thread(int output_fd, unwindstack::AndroidUnwinder* unwinder,
const ThreadInfo& thread) {
log_t log;
log.tfd = output_fd;
@@ -65,21 +66,17 @@
_LOG(&log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread.thread_name.c_str(), thread.tid);
- unwinder->SetRegs(thread.registers.get());
- unwinder->Unwind();
- if (unwinder->NumFrames() == 0) {
- _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d\n", thread.tid);
- if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
- _LOG(&log, logtype::THREAD, " Error code: %s\n", unwinder->LastErrorCodeString());
- _LOG(&log, logtype::THREAD, " Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
- }
+ unwindstack::AndroidUnwinderData data;
+ if (!unwinder->Unwind(thread.registers.get(), data)) {
+ _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d: Error %s\n", thread.tid,
+ data.GetErrorString().c_str());
return;
}
- log_backtrace(&log, unwinder, " ");
+ log_backtrace(&log, unwinder, data, " ");
}
-void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::AndroidUnwinder* unwinder,
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread) {
log_t log;
log.tfd = output_fd.get();
diff --git a/debuggerd/libdebuggerd/gwp_asan.cpp b/debuggerd/libdebuggerd/gwp_asan.cpp
index 3d96627..d8f74e0 100644
--- a/debuggerd/libdebuggerd/gwp_asan.cpp
+++ b/debuggerd/libdebuggerd/gwp_asan.cpp
@@ -21,9 +21,8 @@
#include "gwp_asan/common.h"
#include "gwp_asan/crash_handler.h"
-#include <unwindstack/Maps.h>
+#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
#include <unwindstack/Unwinder.h>
#include "tombstone.pb.h"
@@ -106,7 +105,8 @@
constexpr size_t kMaxTraceLength = gwp_asan::AllocationMetadata::kMaxTraceLengthToCollect;
-void GwpAsanCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const {
+void GwpAsanCrashData::AddCauseProtos(Tombstone* tombstone,
+ unwindstack::AndroidUnwinder* unwinder) const {
if (!CrashIsMine()) {
ALOGE("Internal Error: AddCauseProtos() on a non-GWP-ASan crash.");
return;
@@ -140,7 +140,6 @@
heap_object->set_address(__gwp_asan_get_allocation_address(responsible_allocation_));
heap_object->set_size(__gwp_asan_get_allocation_size(responsible_allocation_));
- unwinder->SetDisplayBuildID(true);
std::unique_ptr<uintptr_t[]> frames(new uintptr_t[kMaxTraceLength]);
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
index c20d090..531afea 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
@@ -30,16 +30,16 @@
// Forward delcaration
namespace unwindstack {
-class Unwinder;
+class AndroidUnwinder;
}
// Dumps a backtrace using a format similar to what Dalvik uses so that the result
// can be intermixed in a bug report.
-void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::AndroidUnwinder* unwinder,
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread);
void dump_backtrace_header(int output_fd);
-void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+void dump_backtrace_thread(int output_fd, unwindstack::AndroidUnwinder* unwinder,
const ThreadInfo& thread);
void dump_backtrace_footer(int output_fd);
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
index a979370..0429643 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/gwp_asan.h
@@ -26,9 +26,15 @@
#include "types.h"
#include "utility.h"
+// Forward delcarations
class Cause;
class Tombstone;
+namespace unwindstack {
+class AndroidUnwinder;
+class Memory;
+} // namespace unwindstack
+
class GwpAsanCrashData {
public:
GwpAsanCrashData() = delete;
@@ -52,7 +58,7 @@
// allocator crash state.
uintptr_t GetFaultAddress() const;
- void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
+ void AddCauseProtos(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder) const;
protected:
// Is GWP-ASan responsible for this crash.
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
index 172ffe9..68bfd5b 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
@@ -23,23 +23,30 @@
#include "scudo/interface.h"
+// Forward delcarations
class Cause;
class Tombstone;
+namespace unwindstack {
+class AndroidUnwinder;
+class Memory;
+} // namespace unwindstack
+
class ScudoCrashData {
public:
- ScudoCrashData() = delete;
+ ScudoCrashData() = default;
~ScudoCrashData() = default;
- ScudoCrashData(unwindstack::Memory* process_memory, const ProcessInfo& process_info);
+
+ bool SetErrorInfo(unwindstack::Memory* process_memory, const ProcessInfo& process_info);
bool CrashIsMine() const;
- void AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const;
+ void AddCauseProtos(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder) const;
private:
scudo_error_info error_info_ = {};
uintptr_t untagged_fault_addr_;
void FillInCause(Cause* cause, const scudo_error_report* report,
- unwindstack::Unwinder* unwinder) const;
+ unwindstack::AndroidUnwinder* unwinder) const;
};
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index 7bf1688..be999e0 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -37,7 +37,7 @@
namespace unwindstack {
struct FrameData;
-class Unwinder;
+class AndroidUnwinder;
}
// The maximum number of frames to save when unwinding.
@@ -51,7 +51,7 @@
/* Creates a tombstone file and writes the crash dump to it. */
void engrave_tombstone(android::base::unique_fd output_fd, android::base::unique_fd proto_fd,
- unwindstack::Unwinder* unwinder,
+ unwindstack::AndroidUnwinder* unwinder,
const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
const ProcessInfo& process_info, OpenFilesList* open_files,
std::string* amfd_data);
@@ -59,7 +59,7 @@
void engrave_tombstone_ucontext(int tombstone_fd, int proto_fd, uint64_t abort_msg_address,
siginfo_t* siginfo, ucontext_t* ucontext);
-void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
+void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
const ProcessInfo& process_info, const OpenFilesList* open_files);
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 63e142f..25b03af 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -73,11 +73,13 @@
void _VLOG(log_t* log, logtype ltype, const char* fmt, va_list ap);
namespace unwindstack {
-class Unwinder;
+class AndroidUnwinder;
class Memory;
+struct AndroidUnwinderData;
}
-void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix);
+void log_backtrace(log_t* log, unwindstack::AndroidUnwinder* unwinder,
+ unwindstack::AndroidUnwinderData& data, const char* prefix);
ssize_t dump_memory(void* out, size_t len, uint8_t* tags, size_t tags_len, uint64_t* addr,
unwindstack::Memory* memory);
diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp
index a4836d7..9483e59 100644
--- a/debuggerd/libdebuggerd/scudo.cpp
+++ b/debuggerd/libdebuggerd/scudo.cpp
@@ -14,65 +14,108 @@
* limitations under the License.
*/
+#include <stdint.h>
+#include <unistd.h>
+
+#include <vector>
+
#include "libdebuggerd/scudo.h"
#include "libdebuggerd/tombstone.h"
+#include "unwindstack/AndroidUnwinder.h"
#include "unwindstack/Memory.h"
-#include "unwindstack/Unwinder.h"
#include <android-base/macros.h>
#include <bionic/macros.h>
#include "tombstone.pb.h"
-std::unique_ptr<char[]> AllocAndReadFully(unwindstack::Memory* process_memory, uint64_t addr,
- size_t size) {
- auto buf = std::make_unique<char[]>(size);
- if (!process_memory->ReadFully(addr, buf.get(), size)) {
- return std::unique_ptr<char[]>();
- }
- return buf;
-}
-
-ScudoCrashData::ScudoCrashData(unwindstack::Memory* process_memory,
- const ProcessInfo& process_info) {
+bool ScudoCrashData::SetErrorInfo(unwindstack::Memory* process_memory,
+ const ProcessInfo& process_info) {
if (!process_info.has_fault_address) {
- return;
+ return false;
}
- auto stack_depot = AllocAndReadFully(process_memory, process_info.scudo_stack_depot,
- __scudo_get_stack_depot_size());
- auto region_info = AllocAndReadFully(process_memory, process_info.scudo_region_info,
- __scudo_get_region_info_size());
- auto ring_buffer = AllocAndReadFully(process_memory, process_info.scudo_ring_buffer,
- __scudo_get_ring_buffer_size());
+ std::vector<char> stack_depot(__scudo_get_stack_depot_size());
+ if (!process_memory->ReadFully(process_info.scudo_stack_depot, stack_depot.data(),
+ stack_depot.size())) {
+ return false;
+ }
+ std::vector<char> region_info(__scudo_get_region_info_size());
+ if (!process_memory->ReadFully(process_info.scudo_region_info, region_info.data(),
+ region_info.size())) {
+ return false;
+ }
+ std::vector<char> ring_buffer(__scudo_get_ring_buffer_size());
+ if (!process_memory->ReadFully(process_info.scudo_ring_buffer, ring_buffer.data(),
+ ring_buffer.size())) {
+ return false;
+ }
+
+ uintptr_t page_size = getpagesize();
untagged_fault_addr_ = process_info.untagged_fault_address;
- uintptr_t fault_page = untagged_fault_addr_ & ~(PAGE_SIZE - 1);
+ uintptr_t fault_page = untagged_fault_addr_ & ~(page_size - 1);
- uintptr_t memory_begin = fault_page - PAGE_SIZE * 16;
- if (memory_begin > fault_page) {
- return;
+ // Attempt to get 16 pages before the fault page and 16 pages after.
+ constexpr size_t kExtraPages = 16;
+ std::vector<char> memory(page_size * (kExtraPages * 2 + 1));
+
+ // Read faulting page first.
+ size_t memory_index = kExtraPages;
+ if (!process_memory->ReadFully(fault_page, &memory[memory_index * page_size], page_size)) {
+ return false;
}
- uintptr_t memory_end = fault_page + PAGE_SIZE * 16;
- if (memory_end < fault_page) {
- return;
+ // Attempt to read the pages after the fault page, stop as soon as we
+ // fail to read.
+ uintptr_t read_addr = fault_page;
+ if (!__builtin_add_overflow(fault_page, page_size, &read_addr)) {
+ memory_index++;
+ for (size_t i = 0; i < kExtraPages; i++, memory_index++) {
+ if (!process_memory->ReadFully(read_addr, &memory[memory_index * page_size], page_size)) {
+ break;
+ }
+ if (__builtin_add_overflow(read_addr, page_size, &read_addr)) {
+ break;
+ }
+ }
+ }
+ uintptr_t memory_end = read_addr;
+
+ // Attempt to read the pages before the fault page, stop as soon as we
+ // fail to read.
+ memory_index = kExtraPages;
+ if (fault_page > 0) {
+ read_addr = fault_page - page_size;
+ for (size_t i = 0; i < kExtraPages; i++, memory_index--) {
+ if (!process_memory->ReadFully(read_addr, &memory[(memory_index - 1) * page_size],
+ page_size)) {
+ break;
+ }
+ if (read_addr == 0) {
+ memory_index--;
+ break;
+ }
+ read_addr -= page_size;
+ }
+ }
+ size_t start_memory_index = memory_index;
+ uintptr_t memory_begin = fault_page - (kExtraPages - memory_index) * page_size;
+
+ std::vector<long> memory_tags((memory_end - memory_begin) / kTagGranuleSize);
+ read_addr = memory_begin;
+ for (size_t i = 0; i < memory_tags.size(); i++) {
+ memory_tags[i] = process_memory->ReadTag(read_addr);
+ read_addr += kTagGranuleSize;
}
- auto memory = std::make_unique<char[]>(memory_end - memory_begin);
- for (auto i = memory_begin; i != memory_end; i += PAGE_SIZE) {
- process_memory->ReadFully(i, memory.get() + i - memory_begin, PAGE_SIZE);
- }
+ __scudo_get_error_info(
+ &error_info_, process_info.maybe_tagged_fault_address, stack_depot.data(), region_info.data(),
+ ring_buffer.data(), &memory[start_memory_index * page_size],
+ reinterpret_cast<const char*>(memory_tags.data()), memory_begin, memory_end - memory_begin);
- auto memory_tags = std::make_unique<char[]>((memory_end - memory_begin) / kTagGranuleSize);
- for (auto i = memory_begin; i != memory_end; i += kTagGranuleSize) {
- memory_tags[(i - memory_begin) / kTagGranuleSize] = process_memory->ReadTag(i);
- }
-
- __scudo_get_error_info(&error_info_, process_info.maybe_tagged_fault_address, stack_depot.get(),
- region_info.get(), ring_buffer.get(), memory.get(), memory_tags.get(),
- memory_begin, memory_end - memory_begin);
+ return true;
}
bool ScudoCrashData::CrashIsMine() const {
@@ -80,7 +123,7 @@
}
void ScudoCrashData::FillInCause(Cause* cause, const scudo_error_report* report,
- unwindstack::Unwinder* unwinder) const {
+ unwindstack::AndroidUnwinder* unwinder) const {
MemoryError* memory_error = cause->mutable_memory_error();
HeapObject* heap_object = memory_error->mutable_heap();
@@ -102,7 +145,6 @@
heap_object->set_address(report->allocation_address);
heap_object->set_size(report->allocation_size);
- unwinder->SetDisplayBuildID(true);
heap_object->set_allocation_tid(report->allocation_tid);
for (size_t i = 0; i < arraysize(report->allocation_trace) && report->allocation_trace[i]; ++i) {
@@ -123,7 +165,8 @@
set_human_readable_cause(cause, untagged_fault_addr_);
}
-void ScudoCrashData::AddCauseProtos(Tombstone* tombstone, unwindstack::Unwinder* unwinder) const {
+void ScudoCrashData::AddCauseProtos(Tombstone* tombstone,
+ unwindstack::AndroidUnwinder* unwinder) const {
size_t report_num = 0;
while (report_num < sizeof(error_info_.reports) / sizeof(error_info_.reports[0]) &&
error_info_.reports[report_num].error_type != UNKNOWN) {
diff --git a/debuggerd/libdebuggerd/test/scudo_test.cpp b/debuggerd/libdebuggerd/test/scudo_test.cpp
new file mode 100644
index 0000000..d8fc6a7
--- /dev/null
+++ b/debuggerd/libdebuggerd/test/scudo_test.cpp
@@ -0,0 +1,233 @@
+/*
+ * 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 <stdlib.h>
+#include <unistd.h>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "libdebuggerd/scudo.h"
+#include "libdebuggerd/types.h"
+#include "unwindstack/Memory.h"
+
+#include "log_fake.h"
+
+#include <inttypes.h>
+
+// This needs to match the kExtraPages from ScudoCrashData::SetErrorInfo.
+constexpr uint64_t kMaxPages = 16;
+
+class MemoryAlwaysZero : public unwindstack::Memory {
+ public:
+ MemoryAlwaysZero() = default;
+ virtual ~MemoryAlwaysZero() = default;
+
+ size_t Read(uint64_t addr, void* buffer, size_t size) override {
+ if (test_unreadable_addrs_.count(addr) != 0) {
+ return 0;
+ }
+ test_read_addrs_.insert(addr);
+ memset(buffer, 0, size);
+ return size;
+ }
+
+ void TestAddUnreadableAddress(uint64_t addr) { test_unreadable_addrs_.insert(addr); }
+
+ void TestClearAddresses() {
+ test_read_addrs_.clear();
+ test_unreadable_addrs_.clear();
+ }
+
+ std::set<uint64_t>& test_read_addrs() { return test_read_addrs_; }
+
+ private:
+ std::set<uint64_t> test_unreadable_addrs_;
+
+ std::set<uint64_t> test_read_addrs_;
+};
+
+TEST(ScudoTest, no_fault_address) {
+ MemoryAlwaysZero process_memory;
+ ProcessInfo info;
+ info.has_fault_address = false;
+ info.untagged_fault_address = 0x5000;
+ info.scudo_stack_depot = 0x1000;
+ info.scudo_region_info = 0x2000;
+ info.scudo_ring_buffer = 0x3000;
+
+ ScudoCrashData crash;
+ ASSERT_FALSE(crash.SetErrorInfo(&process_memory, info));
+
+ info.has_fault_address = true;
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+}
+
+TEST(ScudoTest, scudo_data_read_check) {
+ MemoryAlwaysZero process_memory;
+ ProcessInfo info;
+ info.has_fault_address = true;
+ info.untagged_fault_address = 0x5000;
+ info.scudo_stack_depot = 0x1000;
+ info.scudo_region_info = 0x2000;
+ info.scudo_ring_buffer = 0x3000;
+
+ ScudoCrashData crash;
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+
+ // Stack Depot unreadable
+ process_memory.TestClearAddresses();
+ process_memory.TestAddUnreadableAddress(0x1000);
+ ASSERT_FALSE(crash.SetErrorInfo(&process_memory, info));
+
+ // The Region Info doesn't exist for 32 bit.
+#if defined(__LP64__)
+ // Region Info unreadable
+ process_memory.TestClearAddresses();
+ process_memory.TestAddUnreadableAddress(0x2000);
+ ASSERT_FALSE(crash.SetErrorInfo(&process_memory, info));
+#endif
+
+ // Ring Buffer unreadable
+ process_memory.TestClearAddresses();
+ process_memory.TestAddUnreadableAddress(0x3000);
+ ASSERT_FALSE(crash.SetErrorInfo(&process_memory, info));
+
+ // Verify that with all scudo data readable, the error info works.
+ process_memory.TestClearAddresses();
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+}
+
+TEST(ScudoTest, fault_page_unreadable) {
+ MemoryAlwaysZero process_memory;
+ ProcessInfo info;
+ info.has_fault_address = true;
+ info.untagged_fault_address = 0x5124;
+ info.scudo_stack_depot = 0x1000;
+ info.scudo_region_info = 0x2000;
+ info.scudo_ring_buffer = 0x3000;
+
+ ScudoCrashData crash;
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+
+ uint64_t fault_page = info.untagged_fault_address & ~(getpagesize() - 1);
+ process_memory.TestAddUnreadableAddress(fault_page);
+ ASSERT_FALSE(crash.SetErrorInfo(&process_memory, info));
+}
+
+TEST(ScudoTest, pages_before_fault_unreadable) {
+ MemoryAlwaysZero process_memory;
+ ProcessInfo info;
+ info.has_fault_address = true;
+ info.untagged_fault_address = 0x15124;
+ info.scudo_stack_depot = 0x1000;
+ info.scudo_region_info = 0x2000;
+ info.scudo_ring_buffer = 0x3000;
+
+ ScudoCrashData crash;
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+
+ uint64_t page_size = getpagesize();
+ uint64_t fault_page = info.untagged_fault_address & ~(page_size - 1);
+
+ std::vector<uint64_t> expected_reads = {0x1000, 0x2000, 0x3000};
+ for (size_t i = 0; i <= kMaxPages; i++) {
+ expected_reads.emplace_back(fault_page + i * page_size);
+ }
+
+ // Loop through and make pages before the fault page unreadable.
+ for (size_t i = 1; i <= kMaxPages + 1; i++) {
+ process_memory.TestClearAddresses();
+ uint64_t unreadable_addr = fault_page - i * page_size;
+ SCOPED_TRACE(testing::Message()
+ << "Failed at unreadable address 0x" << std::hex << unreadable_addr);
+ process_memory.TestAddUnreadableAddress(unreadable_addr);
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+ ASSERT_THAT(process_memory.test_read_addrs(),
+ testing::UnorderedElementsAreArray(expected_reads));
+ // Need to add the previous unreadable_addr to the list of expected addresses.
+ expected_reads.emplace_back(unreadable_addr);
+ }
+}
+
+TEST(ScudoTest, pages_after_fault_unreadable) {
+ MemoryAlwaysZero process_memory;
+ ProcessInfo info;
+ info.has_fault_address = true;
+ info.untagged_fault_address = 0x15124;
+ info.scudo_stack_depot = 0x1000;
+ info.scudo_region_info = 0x2000;
+ info.scudo_ring_buffer = 0x3000;
+
+ ScudoCrashData crash;
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+
+ uint64_t page_size = getpagesize();
+ uint64_t fault_page = info.untagged_fault_address & ~(page_size - 1);
+
+ std::vector<uint64_t> expected_reads = {0x1000, 0x2000, 0x3000};
+ for (size_t i = 0; i <= kMaxPages; i++) {
+ expected_reads.emplace_back(fault_page - i * page_size);
+ }
+
+ // Loop through and make pages after the fault page unreadable.
+ for (size_t i = 1; i <= kMaxPages + 1; i++) {
+ process_memory.TestClearAddresses();
+ uint64_t unreadable_addr = fault_page + i * page_size;
+ SCOPED_TRACE(testing::Message()
+ << "Failed at unreadable address 0x" << std::hex << unreadable_addr);
+ process_memory.TestAddUnreadableAddress(unreadable_addr);
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+ ASSERT_THAT(process_memory.test_read_addrs(),
+ testing::UnorderedElementsAreArray(expected_reads));
+ // Need to add the previous unreadable_addr to the list of expected addresses.
+ expected_reads.emplace_back(unreadable_addr);
+ }
+}
+
+// Make sure that if the fault address is low, you won't underflow.
+TEST(ScudoTest, fault_address_low) {
+ MemoryAlwaysZero process_memory;
+ ProcessInfo info;
+ info.has_fault_address = true;
+ info.scudo_stack_depot = 0x21000;
+ info.scudo_region_info = 0x22000;
+ info.scudo_ring_buffer = 0x23000;
+
+ ScudoCrashData crash;
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+
+ uint64_t page_size = getpagesize();
+ for (size_t i = 0; i < kMaxPages + 1; i++) {
+ process_memory.TestClearAddresses();
+ info.untagged_fault_address = 0x124 + i * getpagesize();
+ SCOPED_TRACE(testing::Message()
+ << "Failed with fault address 0x" << std::hex << info.untagged_fault_address);
+ ASSERT_TRUE(crash.SetErrorInfo(&process_memory, info));
+ std::vector<uint64_t> expected_reads = {0x21000, 0x22000, 0x23000};
+ uint64_t fault_page = info.untagged_fault_address & ~(page_size - 1);
+ expected_reads.emplace_back(fault_page);
+ for (size_t j = 1; j <= kMaxPages; j++) {
+ expected_reads.emplace_back(fault_page + j * page_size);
+ }
+ while (fault_page != 0) {
+ fault_page -= page_size;
+ expected_reads.emplace_back(fault_page);
+ }
+ ASSERT_THAT(process_memory.test_read_addrs(),
+ testing::UnorderedElementsAreArray(expected_reads));
+ }
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index eda7182..e5b4d74 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -36,9 +36,9 @@
#include <async_safe/log.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
-#include <unwindstack/Memory.h>
+#include <unwindstack/AndroidUnwinder.h>
+#include <unwindstack/Error.h>
#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
#include "libdebuggerd/backtrace.h"
#include "libdebuggerd/open_files_list.h"
@@ -55,15 +55,15 @@
siginfo_t* siginfo, ucontext_t* ucontext) {
pid_t uid = getuid();
pid_t pid = getpid();
- pid_t tid = gettid();
+ pid_t target_tid = gettid();
log_t log;
- log.current_tid = tid;
- log.crashed_tid = tid;
+ log.current_tid = target_tid;
+ log.crashed_tid = target_tid;
log.tfd = tombstone_fd;
log.amfd_data = nullptr;
- std::string thread_name = get_thread_name(tid);
+ std::string thread_name = get_thread_name(target_tid);
std::vector<std::string> command_line = get_command_line(pid);
std::unique_ptr<unwindstack::Regs> regs(
@@ -73,50 +73,57 @@
android::base::ReadFileToString("/proc/self/attr/current", &selinux_label);
std::map<pid_t, ThreadInfo> threads;
- threads[tid] = ThreadInfo{
- .registers = std::move(regs), .uid = uid, .tid = tid, .thread_name = std::move(thread_name),
- .pid = pid, .command_line = std::move(command_line), .selinux_label = std::move(selinux_label),
- .siginfo = siginfo,
+ threads[target_tid] = ThreadInfo {
+ .registers = std::move(regs), .uid = uid, .tid = target_tid,
+ .thread_name = std::move(thread_name), .pid = pid, .command_line = std::move(command_line),
+ .selinux_label = std::move(selinux_label), .siginfo = siginfo,
#if defined(__aarch64__)
// Only supported on aarch64 for now.
.tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
.pac_enabled_keys = prctl(PR_PAC_GET_ENABLED_KEYS, 0, 0, 0, 0),
#endif
};
- if (pid == tid) {
- const ThreadInfo& thread = threads[pid];
- if (!iterate_tids(pid, [&threads, &thread](pid_t tid) {
- threads[tid] = ThreadInfo{
- .uid = thread.uid,
- .tid = tid,
- .pid = thread.pid,
- .command_line = thread.command_line,
- .thread_name = get_thread_name(tid),
- .tagged_addr_ctrl = thread.tagged_addr_ctrl,
- .pac_enabled_keys = thread.pac_enabled_keys,
- };
- })) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to open /proc/%d/task: %s", pid,
- strerror(errno));
- }
+ const ThreadInfo& thread = threads[pid];
+ if (!iterate_tids(pid, [&threads, &thread, &target_tid](pid_t tid) {
+ if (target_tid == tid) {
+ return;
+ }
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Adding thread %d", tid);
+ threads[tid] = ThreadInfo{
+ .uid = thread.uid,
+ .tid = tid,
+ .pid = thread.pid,
+ .command_line = thread.command_line,
+ .thread_name = get_thread_name(tid),
+ .tagged_addr_ctrl = thread.tagged_addr_ctrl,
+ .pac_enabled_keys = thread.pac_enabled_keys,
+ };
+ })) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to open /proc/%d/task: %s", pid,
+ strerror(errno));
}
- auto process_memory =
- unwindstack::Memory::CreateProcessMemoryCached(getpid());
- unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch(), nullptr,
- process_memory);
- if (!unwinder.Init()) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to init unwinder object");
+ // Do not use the thread cache here because it will call pthread_key_create
+ // which doesn't work in linker code. See b/189803009.
+ // Use a normal cached object because the thread is stopped, and there
+ // is no chance of data changing between reads.
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+ unwindstack::AndroidLocalUnwinder unwinder(process_memory);
+ unwindstack::ErrorData error;
+ if (!unwinder.Initialize(error)) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to init unwinder object: %s",
+ unwindstack::GetErrorCodeString(error.code));
return;
}
ProcessInfo process_info;
process_info.abort_msg_address = abort_msg_address;
- engrave_tombstone(unique_fd(dup(tombstone_fd)), unique_fd(dup(proto_fd)), &unwinder, threads, tid,
- process_info, nullptr, nullptr);
+ engrave_tombstone(unique_fd(dup(tombstone_fd)), unique_fd(dup(proto_fd)), &unwinder, threads,
+ target_tid, process_info, nullptr, nullptr);
}
-void engrave_tombstone(unique_fd output_fd, unique_fd proto_fd, unwindstack::Unwinder* unwinder,
+void engrave_tombstone(unique_fd output_fd, unique_fd proto_fd,
+ unwindstack::AndroidUnwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
const ProcessInfo& process_info, OpenFilesList* open_files,
std::string* amfd_data) {
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index bee4a67..6e1ce8f 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -56,10 +56,11 @@
#include <private/android_filesystem_config.h>
#include <procinfo/process.h>
+#include <unwindstack/AndroidUnwinder.h>
+#include <unwindstack/Error.h>
+#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
#include "libdebuggerd/open_files_list.h"
#include "libdebuggerd/utility.h"
@@ -189,11 +190,12 @@
error_type_str, diff, byte_suffix, location_str, heap_object.size(), heap_object.address()));
}
-static void dump_probable_cause(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
+static void dump_probable_cause(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
const ProcessInfo& process_info, const ThreadInfo& main_thread) {
#if defined(USE_SCUDO)
- ScudoCrashData scudo_crash_data(unwinder->GetProcessMemory().get(), process_info);
- if (scudo_crash_data.CrashIsMine()) {
+ ScudoCrashData scudo_crash_data;
+ if (scudo_crash_data.SetErrorInfo(unwinder->GetProcessMemory().get(), process_info) &&
+ scudo_crash_data.CrashIsMine()) {
scudo_crash_data.AddCauseProtos(tombstone, unwinder);
return;
}
@@ -245,9 +247,9 @@
}
}
-static void dump_abort_message(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
+static void dump_abort_message(Tombstone* tombstone,
+ std::shared_ptr<unwindstack::Memory>& process_memory,
const ProcessInfo& process_info) {
- std::shared_ptr<unwindstack::Memory> process_memory = unwinder->GetProcessMemory();
uintptr_t address = process_info.abort_msg_address;
if (address == 0) {
return;
@@ -348,7 +350,7 @@
f->set_build_id(frame.map_info->GetPrintableBuildID());
}
-static void dump_registers(unwindstack::Unwinder* unwinder,
+static void dump_registers(unwindstack::AndroidUnwinder* unwinder,
const std::unique_ptr<unwindstack::Regs>& regs, Thread& thread,
bool memory_dump) {
if (regs == nullptr) {
@@ -402,27 +404,9 @@
});
}
-static void log_unwinder_error(unwindstack::Unwinder* unwinder) {
- if (unwinder->LastErrorCode() == unwindstack::ERROR_NONE) {
- return;
- }
-
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error code: %s",
- unwinder->LastErrorCodeString());
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, " error address: 0x%" PRIx64,
- unwinder->LastErrorAddress());
-}
-
-static void dump_thread_backtrace(unwindstack::Unwinder* unwinder, Thread& thread) {
- if (unwinder->NumFrames() == 0) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "failed to unwind");
- log_unwinder_error(unwinder);
- return;
- }
-
- unwinder->SetDisplayBuildID(true);
+static void dump_thread_backtrace(std::vector<unwindstack::FrameData>& frames, Thread& thread) {
std::set<std::string> unreadable_elf_files;
- for (const auto& frame : unwinder->frames()) {
+ for (const auto& frame : frames) {
BacktraceFrame* f = thread.add_current_backtrace();
fill_in_backtrace_frame(f, frame);
if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
@@ -446,7 +430,7 @@
}
}
-static void dump_thread(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
+static void dump_thread(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
const ThreadInfo& thread_info, bool memory_dump = false) {
Thread thread;
@@ -455,36 +439,29 @@
thread.set_tagged_addr_ctrl(thread_info.tagged_addr_ctrl);
thread.set_pac_enabled_keys(thread_info.pac_enabled_keys);
- if (thread_info.pid == getpid() && thread_info.pid != thread_info.tid) {
- // Fallback path for non-main thread, doing unwind from running process.
- unwindstack::ThreadUnwinder thread_unwinder(kMaxFrames, unwinder->GetMaps());
- if (!thread_unwinder.Init()) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
- "Unable to initialize ThreadUnwinder object.");
- log_unwinder_error(&thread_unwinder);
- return;
- }
-
- std::unique_ptr<unwindstack::Regs> initial_regs;
- thread_unwinder.UnwindWithSignal(BIONIC_SIGNAL_BACKTRACE, thread_info.tid, &initial_regs);
- dump_registers(&thread_unwinder, initial_regs, thread, memory_dump);
- dump_thread_backtrace(&thread_unwinder, thread);
+ unwindstack::AndroidUnwinderData data;
+ // Indicate we want a copy of the initial registers.
+ data.saved_initial_regs = std::make_optional<std::unique_ptr<unwindstack::Regs>>();
+ bool unwind_ret;
+ if (thread_info.registers != nullptr) {
+ unwind_ret = unwinder->Unwind(thread_info.registers.get(), data);
} else {
- dump_registers(unwinder, thread_info.registers, thread, memory_dump);
- std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
- unwinder->SetRegs(regs_copy.get());
- unwinder->Unwind();
- dump_thread_backtrace(unwinder, thread);
+ unwind_ret = unwinder->Unwind(thread_info.tid, data);
}
+ if (!unwind_ret) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Unwind failed for tid %d: Error %s",
+ thread_info.tid, data.GetErrorString().c_str());
+ } else {
+ dump_thread_backtrace(data.frames, thread);
+ }
+ dump_registers(unwinder, *data.saved_initial_regs, thread, memory_dump);
auto& threads = *tombstone->mutable_threads();
threads[thread_info.tid] = thread;
}
-static void dump_mappings(Tombstone* tombstone, unwindstack::Unwinder* unwinder) {
- unwindstack::Maps* maps = unwinder->GetMaps();
- std::shared_ptr<unwindstack::Memory> process_memory = unwinder->GetProcessMemory();
-
+static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps,
+ std::shared_ptr<unwindstack::Memory>& process_memory) {
for (const auto& map_info : *maps) {
auto* map = tombstone->add_memory_mappings();
map->set_begin_address(map_info->start());
@@ -593,7 +570,8 @@
}
static void dump_tags_around_fault_addr(Signal* signal, const Tombstone& tombstone,
- unwindstack::Unwinder* unwinder, uintptr_t fault_addr) {
+ std::shared_ptr<unwindstack::Memory>& process_memory,
+ uintptr_t fault_addr) {
if (tombstone.arch() != Architecture::ARM64) return;
fault_addr = untag_address(fault_addr);
@@ -604,8 +582,6 @@
// a valid address for us to dump tags from.
if (fault_addr < kBytesToRead / 2) return;
- unwindstack::Memory* memory = unwinder->GetProcessMemory().get();
-
constexpr uintptr_t kRowStartMask = ~(kNumTagColumns * kTagGranuleSize - 1);
size_t start_address = (fault_addr & kRowStartMask) - kBytesToRead / 2;
MemoryDump tag_dump;
@@ -614,7 +590,7 @@
// Attempt to read the first tag. If reading fails, this likely indicates the
// lowest touched page is inaccessible or not marked with PROT_MTE.
// Fast-forward over pages until one has tags, or we exhaust the search range.
- while (memory->ReadTag(start_address) < 0) {
+ while (process_memory->ReadTag(start_address) < 0) {
size_t page_size = sysconf(_SC_PAGE_SIZE);
size_t bytes_to_next_page = page_size - (start_address % page_size);
if (bytes_to_next_page >= granules_to_read * kTagGranuleSize) return;
@@ -626,7 +602,7 @@
std::string* mte_tags = tag_dump.mutable_arm_mte_metadata()->mutable_memory_tags();
for (size_t i = 0; i < granules_to_read; ++i) {
- long tag = memory->ReadTag(start_address + i * kTagGranuleSize);
+ long tag = process_memory->ReadTag(start_address + i * kTagGranuleSize);
if (tag < 0) break;
mte_tags->push_back(static_cast<uint8_t>(tag));
}
@@ -636,7 +612,7 @@
}
}
-void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::Unwinder* unwinder,
+void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
const ProcessInfo& process_info, const OpenFilesList* open_files) {
Tombstone result;
@@ -691,12 +667,12 @@
sig.set_has_fault_address(true);
uintptr_t fault_addr = process_info.maybe_tagged_fault_address;
sig.set_fault_address(fault_addr);
- dump_tags_around_fault_addr(&sig, result, unwinder, fault_addr);
+ dump_tags_around_fault_addr(&sig, result, unwinder->GetProcessMemory(), fault_addr);
}
*result.mutable_signal_info() = sig;
- dump_abort_message(&result, unwinder, process_info);
+ dump_abort_message(&result, unwinder->GetProcessMemory(), process_info);
// Dump the main thread, but save the memory around the registers.
dump_thread(&result, unwinder, main_thread, /* memory_dump */ true);
@@ -709,7 +685,7 @@
dump_probable_cause(&result, unwinder, process_info, main_thread);
- dump_mappings(&result, unwinder);
+ dump_mappings(&result, unwinder->GetMaps(), unwinder->GetProcessMemory());
// Only dump logs on debuggable devices.
if (android::base::GetBoolProperty("ro.debuggable", false)) {
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index ecd98a4..74a1423 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -39,6 +39,7 @@
#include <bionic/reserved_signals.h>
#include <debuggerd/handler.h>
#include <log/log.h>
+#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Unwinder.h>
@@ -483,10 +484,10 @@
return describe_end(value, desc);
}
-void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+void log_backtrace(log_t* log, unwindstack::AndroidUnwinder* unwinder,
+ unwindstack::AndroidUnwinderData& data, const char* prefix) {
std::set<std::string> unreadable_elf_files;
- unwinder->SetDisplayBuildID(true);
- for (const auto& frame : unwinder->frames()) {
+ for (const auto& frame : data.frames) {
if (frame.map_info != nullptr && frame.map_info->ElfFileNotReadable()) {
unreadable_elf_files.emplace(frame.map_info->name());
}
@@ -509,7 +510,7 @@
}
}
- for (const auto& frame : unwinder->frames()) {
+ for (const auto& frame : data.frames) {
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(frame).c_str());
}
}
diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp
index 5c6abc9..df033df 100644
--- a/debuggerd/util.cpp
+++ b/debuggerd/util.cpp
@@ -90,9 +90,7 @@
if (tid == 0) {
continue;
}
- if (pid != tid) {
- callback(tid);
- }
+ callback(tid);
}
return true;
}
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 9ae2c37..5c07eb0 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -130,12 +130,10 @@
"-Werror",
"-Wvla",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
+ "-Wthread-safety",
],
rtti: true,
- clang_cflags: [
- "-Wthread-safety",
- ],
}
cc_binary {
@@ -215,7 +213,7 @@
"-Werror",
"-Wunreachable-code",
"-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
- "-D_FILE_OFFSET_BITS=64"
+ "-D_FILE_OFFSET_BITS=64",
],
target: {
@@ -411,7 +409,7 @@
":fastboot_test_vendor_ramdisk_replace",
":fastboot_test_vendor_boot_v3",
":fastboot_test_vendor_boot_v4_without_frag",
- ":fastboot_test_vendor_boot_v4_with_frag"
+ ":fastboot_test_vendor_boot_v4_with_frag",
],
}
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index b9f6c97..0f3a208 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -254,6 +254,7 @@
return device->WriteStatus(FastbootResult::FAIL, ret.message);
}
+ device->WriteInfo(ret.message);
return device->WriteStatus(FastbootResult::OKAY, ret.message);
}
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 06ffe0f..05186a2 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -121,7 +121,12 @@
int WriteCallback(void* priv, const void* data, size_t len) {
PartitionHandle* handle = reinterpret_cast<PartitionHandle*>(priv);
if (!data) {
- return lseek64(handle->fd(), len, SEEK_CUR) >= 0 ? 0 : -errno;
+ if (lseek64(handle->fd(), len, SEEK_CUR) < 0) {
+ int rv = -errno;
+ PLOG(ERROR) << "lseek failed";
+ return rv;
+ }
+ return 0;
}
return FlashRawDataChunk(handle, reinterpret_cast<const char*>(data), len);
}
@@ -131,6 +136,7 @@
downloaded_data.size(), true, false);
if (!file) {
// Invalid sparse format
+ LOG(ERROR) << "Unable to open sparse data for flashing";
return -EINVAL;
}
return sparse_file_callback(file, false, false, WriteCallback, reinterpret_cast<void*>(handle));
@@ -175,10 +181,13 @@
std::vector<char> data = std::move(device->download_data());
if (data.size() == 0) {
+ LOG(ERROR) << "Cannot flash empty data vector";
return -EINVAL;
}
uint64_t block_device_size = get_block_device_size(handle.fd());
if (data.size() > block_device_size) {
+ LOG(ERROR) << "Cannot flash " << data.size() << " bytes to block device of size "
+ << block_device_size;
return -EOVERFLOW;
} else if (data.size() < block_device_size &&
(partition_name == "boot" || partition_name == "boot_a" ||
diff --git a/fastboot/device/main.cpp b/fastboot/device/main.cpp
index df9c900..08c9358 100644
--- a/fastboot/device/main.cpp
+++ b/fastboot/device/main.cpp
@@ -14,13 +14,30 @@
* limitations under the License.
*/
+#include <stdarg.h>
+
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <sparse/sparse.h>
#include "fastboot_device.h"
+static void LogSparseVerboseMessage(const char* fmt, ...) {
+ std::string message;
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&message, fmt, ap);
+ va_end(ap);
+
+ LOG(ERROR) << "libsparse message: " << message;
+}
+
int main(int /*argc*/, char* argv[]) {
android::base::InitLogging(argv, &android::base::KernelLogger);
+ sparse_print_verbose = LogSparseVerboseMessage;
+
while (true) {
FastbootDevice device;
device.ExecuteCommands();
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index 159c314..2031170 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -9,6 +9,7 @@
cc_test_host {
name: "fuzzy_fastboot",
+ isolated: false,
compile_multilib: "first",
srcs: [
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6863894..7c7979b 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -124,8 +124,8 @@
FS_STAT_RO_MOUNT_FAILED = 0x0040,
FS_STAT_RO_UNMOUNT_FAILED = 0x0080,
FS_STAT_FULL_MOUNT_FAILED = 0x0100,
- FS_STAT_E2FSCK_FAILED = 0x0200,
- FS_STAT_E2FSCK_FS_FIXED = 0x0400,
+ FS_STAT_FSCK_FAILED = 0x0200,
+ FS_STAT_FSCK_FS_FIXED = 0x0400,
FS_STAT_INVALID_MAGIC = 0x0800,
FS_STAT_TOGGLE_QUOTAS_FAILED = 0x10000,
FS_STAT_SET_RESERVED_BLOCKS_FAILED = 0x20000,
@@ -136,7 +136,6 @@
};
static void log_fs_stat(const std::string& blk_device, int fs_stat) {
- if ((fs_stat & FS_STAT_IS_EXT4) == 0) return; // only log ext4
std::string msg =
android::base::StringPrintf("\nfs_stat,%s,0x%x\n", blk_device.c_str(), fs_stat);
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(FSCK_LOG_FILE, O_WRONLY | O_CLOEXEC |
@@ -166,7 +165,7 @@
return fs_stat &
(FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED | FS_STAT_FULL_MOUNT_FAILED |
- FS_STAT_E2FSCK_FAILED | FS_STAT_TOGGLE_QUOTAS_FAILED |
+ FS_STAT_FSCK_FAILED | FS_STAT_TOGGLE_QUOTAS_FAILED |
FS_STAT_SET_RESERVED_BLOCKS_FAILED | FS_STAT_ENABLE_ENCRYPTION_FAILED);
}
@@ -255,10 +254,10 @@
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
LERROR << "Failed trying to run " << E2FSCK_BIN;
- *fs_stat |= FS_STAT_E2FSCK_FAILED;
+ *fs_stat |= FS_STAT_FSCK_FAILED;
} else if (status != 0) {
LINFO << "e2fsck returned status 0x" << std::hex << status;
- *fs_stat |= FS_STAT_E2FSCK_FS_FIXED;
+ *fs_stat |= FS_STAT_FSCK_FS_FIXED;
}
}
} else if (is_f2fs(fs_type)) {
@@ -267,20 +266,30 @@
const char* f2fs_fsck_forced_argv[] = {
F2FS_FSCK_BIN, "-f", "-c", "10000", "--debug-cache", blk_device.c_str()};
- if (should_force_check(*fs_stat)) {
- LINFO << "Running " << F2FS_FSCK_BIN << " -f -c 10000 --debug-cache "
- << realpath(blk_device);
- ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
- &status, false, LOG_KLOG | LOG_FILE, false, nullptr);
+ if (access(F2FS_FSCK_BIN, X_OK)) {
+ LINFO << "Not running " << F2FS_FSCK_BIN << " on " << realpath(blk_device)
+ << " (executable not in system image)";
} else {
- LINFO << "Running " << F2FS_FSCK_BIN << " -a -c 10000 --debug-cache "
- << realpath(blk_device);
- ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, false,
- LOG_KLOG | LOG_FILE, false, nullptr);
- }
- if (ret < 0) {
- /* No need to check for error in fork, we can't really handle it now */
- LERROR << "Failed trying to run " << F2FS_FSCK_BIN;
+ if (should_force_check(*fs_stat)) {
+ LINFO << "Running " << F2FS_FSCK_BIN << " -f -c 10000 --debug-cache "
+ << realpath(blk_device);
+ ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
+ &status, false, LOG_KLOG | LOG_FILE, false,
+ FSCK_LOG_FILE);
+ } else {
+ LINFO << "Running " << F2FS_FSCK_BIN << " -a -c 10000 --debug-cache "
+ << realpath(blk_device);
+ ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status,
+ false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
+ }
+ if (ret < 0) {
+ /* No need to check for error in fork, we can't really handle it now */
+ LERROR << "Failed trying to run " << F2FS_FSCK_BIN;
+ *fs_stat |= FS_STAT_FSCK_FAILED;
+ } else if (status != 0) {
+ LINFO << F2FS_FSCK_BIN << " returned status 0x" << std::hex << status;
+ *fs_stat |= FS_STAT_FSCK_FS_FIXED;
+ }
}
}
android::base::SetProperty("ro.boottime.init.fsck." + Basename(target),
@@ -840,8 +849,10 @@
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(source);
}
- android::base::SetProperty("ro.boottime.init.mount." + Basename(target),
- std::to_string(t.duration().count()));
+ if (ret == 0) {
+ android::base::SetProperty("ro.boottime.init.mount." + Basename(target),
+ std::to_string(t.duration().count()));
+ }
errno = save_errno;
return ret;
}
@@ -1911,6 +1922,7 @@
while (retry_count-- > 0) {
if (!__mount(n_blk_device, mount_point, fstab_entry)) {
fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
+ log_fs_stat(fstab_entry.blk_device, fs_stat);
return FS_MGR_DOMNT_SUCCESS;
} else {
if (retry_count <= 0) break; // run check_fs only once
diff --git a/fs_mgr/liblp/TEST_MAPPING b/fs_mgr/liblp/TEST_MAPPING
index 875ccb0..cf0d22b 100644
--- a/fs_mgr/liblp/TEST_MAPPING
+++ b/fs_mgr/liblp/TEST_MAPPING
@@ -4,7 +4,7 @@
"name": "liblp_test"
}
],
- "hwasan-postsubmit": [
+ "hwasan-presubmit": [
{
"name": "liblp_test"
}
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 5daa84d..6ee8d4a 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -235,4 +235,13 @@
// The source fingerprint at the time the OTA was downloaded.
string source_build_fingerprint = 10;
+
+ // Whether this update attempt uses userspace snapshots.
+ bool userspace_snapshots_used = 11;
+
+ // Whether this update attempt uses XOR compression.
+ bool xor_compression_used = 12;
+
+ // Whether this update attempt used io_uring.
+ bool iouring_used = 13;
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 8e6bbd9..f4d5c72 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -171,11 +171,11 @@
std::optional<uint64_t> last_label_;
std::shared_ptr<std::vector<CowOperation>> ops_;
std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- uint64_t merge_op_start_;
+ uint64_t merge_op_start_{};
std::shared_ptr<std::unordered_map<uint32_t, int>> block_map_;
- uint64_t num_total_data_ops_;
- uint64_t num_ordered_ops_to_merge_;
- bool has_seq_ops_;
+ uint64_t num_total_data_ops_{};
+ uint64_t num_ordered_ops_to_merge_{};
+ bool has_seq_ops_{};
std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc_;
ReaderFlags reader_flag_;
};
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index ba62330..d458b87 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -62,6 +62,7 @@
MOCK_METHOD(std::unique_ptr<AutoDevice>, EnsureMetadataMounted, (), (override));
MOCK_METHOD(ISnapshotMergeStats*, GetSnapshotMergeStatsInstance, (), (override));
MOCK_METHOD(std::string, ReadSourceBuildFingerprint, (), (override));
+ MOCK_METHOD(void, SetMergeStatsFeatures, (ISnapshotMergeStats*), (override));
};
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
index 3d384cc..8280f2e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_merge_stats.h
@@ -28,10 +28,7 @@
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_state, (android::snapshot::UpdateState), (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(void, set_merge_failure_code, (MergeFailureCode), (override));
@@ -45,6 +42,7 @@
MOCK_METHOD(MergeFailureCode, merge_failure_code, (), (override));
MOCK_METHOD(std::unique_ptr<Result>, Finish, (), (override));
MOCK_METHOD(bool, WriteState, (), (override));
+ MOCK_METHOD(SnapshotMergeReport*, report, (), (override));
using ISnapshotMergeStats::Result;
// Return nullptr if any failure.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 11da568..5fe5280 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -134,6 +134,9 @@
// may need to be merged before wiping.
virtual bool FinishedSnapshotWrites(bool wipe) = 0;
+ // Set feature flags on an ISnapshotMergeStats object.
+ virtual void SetMergeStatsFeatures(ISnapshotMergeStats* stats) = 0;
+
// Update an ISnapshotMergeStats object with statistics about COW usage.
// This should be called before the merge begins as otherwise snapshots
// may be deleted.
@@ -378,6 +381,7 @@
bool MapAllSnapshots(const std::chrono::milliseconds& timeout_ms = {}) override;
bool UnmapAllSnapshots() override;
std::string ReadSourceBuildFingerprint() override;
+ void SetMergeStatsFeatures(ISnapshotMergeStats* stats) override;
// We can't use WaitForFile during first-stage init, because ueventd is not
// running and therefore will not automatically create symlinks. Instead,
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
index 8c2fec7..8a70400 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h
@@ -28,10 +28,7 @@
virtual ~ISnapshotMergeStats() = default;
// Called when merge starts or resumes.
virtual bool Start() = 0;
- virtual void set_state(android::snapshot::UpdateState state, bool using_compression) = 0;
- virtual void set_cow_file_size(uint64_t cow_file_size) = 0;
- virtual void set_total_cow_size_bytes(uint64_t bytes) = 0;
- virtual void set_estimated_cow_size_bytes(uint64_t bytes) = 0;
+ virtual void set_state(android::snapshot::UpdateState state) = 0;
virtual void set_boot_complete_time_ms(uint32_t ms) = 0;
virtual void set_boot_complete_to_merge_start_time_ms(uint32_t ms) = 0;
virtual void set_merge_failure_code(MergeFailureCode code) = 0;
@@ -55,6 +52,9 @@
// Return nullptr if any failure.
virtual std::unique_ptr<Result> Finish() = 0;
+ // Return the underlying implementation.
+ virtual SnapshotMergeReport* report() = 0;
+
// Write out the current state. This should be called when data might be lost that
// cannot be recovered (eg the COW sizes).
virtual bool WriteState() = 0;
@@ -67,11 +67,8 @@
// ISnapshotMergeStats overrides
bool Start() override;
- void set_state(android::snapshot::UpdateState state, bool using_compression) override;
- void set_cow_file_size(uint64_t cow_file_size) override;
+ void set_state(android::snapshot::UpdateState state) override;
uint64_t cow_file_size() override;
- void set_total_cow_size_bytes(uint64_t bytes) override;
- void set_estimated_cow_size_bytes(uint64_t bytes) override;
uint64_t total_cow_size_bytes() override;
uint64_t estimated_cow_size_bytes() override;
void set_boot_complete_time_ms(uint32_t ms) override;
@@ -85,6 +82,9 @@
std::unique_ptr<Result> Finish() override;
bool WriteState() override;
+ // Access the underlying report before it is finished.
+ SnapshotMergeReport* report() override { return &report_; }
+
private:
bool ReadState();
bool DeleteState();
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 318e525..171c7c6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -59,6 +59,7 @@
bool MapAllSnapshots(const std::chrono::milliseconds& timeout_ms) override;
bool UnmapAllSnapshots() override;
std::string ReadSourceBuildFingerprint() override;
+ void SetMergeStatsFeatures(ISnapshotMergeStats* stats) override;
};
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index a83f535..e6db491 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -4150,9 +4150,20 @@
estimated_cow_size += status.estimated_cow_size();
}
- stats->set_cow_file_size(cow_file_size);
- stats->set_total_cow_size_bytes(total_cow_size);
- stats->set_estimated_cow_size_bytes(estimated_cow_size);
+ stats->report()->set_cow_file_size(cow_file_size);
+ stats->report()->set_total_cow_size_bytes(total_cow_size);
+ stats->report()->set_estimated_cow_size_bytes(estimated_cow_size);
+}
+
+void SnapshotManager::SetMergeStatsFeatures(ISnapshotMergeStats* stats) {
+ auto lock = LockExclusive();
+ if (!lock) return;
+
+ SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get());
+ stats->report()->set_iouring_used(update_status.io_uring_enabled());
+ stats->report()->set_userspace_snapshots_used(update_status.userspace_snapshots());
+ stats->report()->set_xor_compression_used(
+ android::base::GetBoolProperty("ro.virtual_ab.compression.xor.enabled", false));
}
bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp
index 712eafb..9b6eb2c 100644
--- a/fs_mgr/libsnapshot/snapshot_stats.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stats.cpp
@@ -84,27 +84,14 @@
return WriteState();
}
-void SnapshotMergeStats::set_state(android::snapshot::UpdateState state, bool using_compression) {
+void SnapshotMergeStats::set_state(android::snapshot::UpdateState state) {
report_.set_state(state);
- report_.set_compression_enabled(using_compression);
-}
-
-void SnapshotMergeStats::set_cow_file_size(uint64_t cow_file_size) {
- report_.set_cow_file_size(cow_file_size);
}
uint64_t SnapshotMergeStats::cow_file_size() {
return report_.cow_file_size();
}
-void SnapshotMergeStats::set_total_cow_size_bytes(uint64_t bytes) {
- report_.set_total_cow_size_bytes(bytes);
-}
-
-void SnapshotMergeStats::set_estimated_cow_size_bytes(uint64_t bytes) {
- report_.set_estimated_cow_size_bytes(bytes);
-}
-
uint64_t SnapshotMergeStats::total_cow_size_bytes() {
return report_.total_cow_size_bytes();
}
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 4af5367..84e2226 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -128,12 +128,9 @@
class SnapshotMergeStatsStub : public ISnapshotMergeStats {
bool Start() override { return false; }
- void set_state(android::snapshot::UpdateState, bool) override {}
- void set_cow_file_size(uint64_t) override {}
+ void set_state(android::snapshot::UpdateState) override {}
uint64_t cow_file_size() override { return 0; }
std::unique_ptr<Result> Finish() override { return nullptr; }
- void set_total_cow_size_bytes(uint64_t) override {}
- void set_estimated_cow_size_bytes(uint64_t) override {}
uint64_t total_cow_size_bytes() override { return 0; }
uint64_t estimated_cow_size_bytes() override { return 0; }
void set_boot_complete_time_ms(uint32_t) override {}
@@ -145,6 +142,10 @@
void set_source_build_fingerprint(const std::string&) override {}
std::string source_build_fingerprint() override { return {}; }
bool WriteState() override { return false; }
+ SnapshotMergeReport* report() override { return &report_; }
+
+ private:
+ SnapshotMergeReport report_;
};
ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
@@ -183,4 +184,8 @@
return {};
}
+void SnapshotManagerStub::SetMergeStatsFeatures(ISnapshotMergeStats*) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+}
+
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index bc2bceb..fbc8c30 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -72,7 +72,7 @@
cflags: [
"-Wall",
- "-Werror"
+ "-Werror",
],
static_libs: [
@@ -89,14 +89,7 @@
"liburing",
],
include_dirs: ["bionic/libc/kernel"],
-}
-
-cc_binary {
- name: "snapuserd",
- defaults: ["snapuserd_defaults"],
- init_rc: [
- "snapuserd.rc",
- ],
+ system_shared_libs: [],
// snapuserd is started during early boot by first-stage init. At that
// point, /system is mounted using the "dm-user" device-mapper kernel
@@ -105,16 +98,40 @@
// faults for its code pages.
static_executable: true,
- system_shared_libs: [],
- ramdisk_available: true,
- vendor_ramdisk_available: true,
- recovery_available: true,
-
// Snapuserd segfaults with ThinLTO
// http://b/208565717
lto: {
never: true,
- }
+ },
+}
+
+cc_binary {
+ name: "snapuserd",
+ defaults: ["snapuserd_defaults"],
+ init_rc: [
+ "snapuserd.rc",
+ ],
+ ramdisk_available: false,
+ vendor_ramdisk_available: true,
+ recovery_available: true,
+}
+
+// This target will install to /system/bin/snapuserd_ramdisk
+// It will also create a symblink on /system/bin/snapuserd that point to
+// /system/bin/snapuserd_ramdisk .
+// This way, init can check if generic ramdisk copy exists.
+cc_binary {
+ name: "snapuserd_ramdisk",
+ defaults: ["snapuserd_defaults"],
+ init_rc: [
+ "snapuserd.rc",
+ ],
+ // This target is specifically for generic ramdisk, therefore we set
+ // vendor_ramdisk_available to false.
+ ramdisk_available: true,
+ vendor_ramdisk_available: false,
+ ramdisk: true,
+ symlinks: ["snapuserd"],
}
cc_test {
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp
index 9ddc963..577b09d 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp
@@ -505,7 +505,7 @@
// We don't care if the ACK is received.
code[0] = 'a';
- if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL) < 0)) {
+ if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL)) < 0) {
PLOG(ERROR) << "Failed to send ACK to proxy";
return false;
}
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
index 82b2b25..9827662 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -637,7 +637,7 @@
// We don't care if the ACK is received.
code[0] = 'a';
- if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL) < 0)) {
+ if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL)) < 0) {
PLOG(ERROR) << "Failed to send ACK to proxy";
return false;
}
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index b5fac53..aac2cfd 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -47,6 +47,8 @@
std::string fs;
ASSERT_TRUE(android::base::ReadFileToString("/proc/filesystems", &fs));
EXPECT_THAT(fs, ::testing::HasSubstr("\terofs\n"));
+
+ ASSERT_EQ(access("/sys/fs/erofs", F_OK), 0);
}
TEST(fs, PartitionTypes) {
@@ -94,7 +96,13 @@
}
if (entry.flags & MS_RDONLY) {
- EXPECT_EQ(entry.fs_type, "erofs") << entry.mount_point;
+ std::vector<std::string> allowed = {"erofs", "ext4"};
+ if (vsr_level == __ANDROID_API_T__) {
+ allowed.emplace_back("f2fs");
+ }
+
+ EXPECT_NE(std::find(allowed.begin(), allowed.end(), entry.fs_type), allowed.end())
+ << entry.mount_point;
} else {
EXPECT_NE(entry.fs_type, "ext4") << entry.mount_point;
}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 9fe85d4..e305a86 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -308,30 +308,7 @@
// If timeout and battery level is still not ready, draw unknown battery
}
- if (healthd_draw_ == nullptr) {
- std::optional<bool> out_screen_on = configuration_->ChargerShouldKeepScreenOn();
- if (out_screen_on.has_value()) {
- if (!*out_screen_on) {
- LOGV("[%" PRId64 "] leave screen off\n", now);
- batt_anim_.run = false;
- next_screen_transition_ = -1;
- if (configuration_->ChargerIsOnline()) {
- RequestEnableSuspend();
- }
- return;
- }
- }
-
- healthd_draw_ = HealthdDraw::Create(&batt_anim_);
- if (healthd_draw_ == nullptr) return;
-
-#if !defined(__ANDROID_VNDK__)
- if (android::sysprop::ChargerProperties::disable_init_blank().value_or(false)) {
- healthd_draw_->blank_screen(true, static_cast<int>(drm_));
- screen_blanked_ = true;
- }
-#endif
- }
+ if (healthd_draw_ == nullptr) return;
/* animation is over, blank screen and leave */
if (batt_anim_.num_cycles > 0 && batt_anim_.cur_cycle == batt_anim_.num_cycles) {
@@ -736,6 +713,33 @@
}
}
+void Charger::InitHealthdDraw() {
+ if (healthd_draw_ == nullptr) {
+ std::optional<bool> out_screen_on = configuration_->ChargerShouldKeepScreenOn();
+ if (out_screen_on.has_value()) {
+ if (!*out_screen_on) {
+ LOGV("[%" PRId64 "] leave screen off\n", curr_time_ms());
+ batt_anim_.run = false;
+ next_screen_transition_ = -1;
+ if (configuration_->ChargerIsOnline()) {
+ RequestEnableSuspend();
+ }
+ return;
+ }
+ }
+
+ healthd_draw_ = HealthdDraw::Create(&batt_anim_);
+ if (healthd_draw_ == nullptr) return;
+
+#if !defined(__ANDROID_VNDK__)
+ if (android::sysprop::ChargerProperties::disable_init_blank().value_or(false)) {
+ healthd_draw_->blank_screen(true, static_cast<int>(drm_));
+ screen_blanked_ = true;
+ }
+#endif
+ }
+}
+
void Charger::OnInit(struct healthd_config* config) {
int ret;
int i;
@@ -753,6 +757,7 @@
}
InitAnimation();
+ InitHealthdDraw();
ret = CreateDisplaySurface(batt_anim_.fail_file, &surf_unknown_);
if (ret < 0) {
diff --git a/healthd/include_charger/charger/healthd_mode_charger.h b/healthd/include_charger/charger/healthd_mode_charger.h
index 28e1fb5..82e4ddf 100644
--- a/healthd/include_charger/charger/healthd_mode_charger.h
+++ b/healthd/include_charger/charger/healthd_mode_charger.h
@@ -104,6 +104,7 @@
void HandleInputState(int64_t now);
void HandlePowerSupplyState(int64_t now);
int InputCallback(int fd, unsigned int epevents);
+ void InitHealthdDraw();
void InitAnimation();
int RequestEnableSuspend();
int RequestDisableSuspend();
diff --git a/init/Android.bp b/init/Android.bp
index fc60659..b4bc170 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -178,7 +178,6 @@
"update_metadata-protos",
],
shared_libs: [
- "libbacktrace",
"libbase",
"libbootloader_message",
"libcrypto",
@@ -195,6 +194,7 @@
"libprocessgroup",
"libprocessgroup_setup",
"libselinux",
+ "libunwindstack",
"libutils",
"libziparchive",
],
@@ -358,7 +358,6 @@
"libgsi",
"liblzma",
"libunwindstack_no_dex",
- "libbacktrace_no_dex",
"libmodprobe",
"libext2_uuid",
"libprotobuf-cpp-lite",
diff --git a/init/README.md b/init/README.md
index 13c6ebd..fed81db 100644
--- a/init/README.md
+++ b/init/README.md
@@ -606,8 +606,12 @@
group. If not provided, the directory is created with permissions 755 and
owned by the root user and root group. If provided, the mode, owner and group
will be updated if the directory exists already.
+ If the directory does not exist, it will receive the security context from
+ the current SELinux policy or its parent if not specified in the policy. If
+ the directory exists, its security context will not be changed (even if
+ different from the policy).
- > _action_ can be one of:
+ > _action_ can be one of:
* `None`: take no encryption action; directory will be encrypted if parent is.
* `Require`: encrypt directory, abort boot process if encryption fails
* `Attempt`: try to set an encryption policy, but continue if it fails
diff --git a/init/action.h b/init/action.h
index 1534bf9..eddc384 100644
--- a/init/action.h
+++ b/init/action.h
@@ -22,6 +22,8 @@
#include <variant>
#include <vector>
+#include <android-base/strings.h>
+
#include "builtins.h"
#include "keyword_map.h"
#include "result.h"
@@ -79,6 +81,7 @@
static void set_function_map(const BuiltinFunctionMap* function_map) {
function_map_ = function_map;
}
+ bool IsFromApex() const { return base::StartsWith(filename_, "/apex/"); }
private:
void ExecuteCommand(const Command& command) const;
diff --git a/init/action_manager.h b/init/action_manager.h
index b6f93d9..2746a7c 100644
--- a/init/action_manager.h
+++ b/init/action_manager.h
@@ -37,6 +37,10 @@
size_t CheckAllCommands();
void AddAction(std::unique_ptr<Action> action);
+ template <class UnaryPredicate>
+ void RemoveActionIf(UnaryPredicate predicate) {
+ actions_.erase(std::remove_if(actions_.begin(), actions_.end(), predicate), actions_.end());
+ }
void QueueEventTrigger(const std::string& trigger);
void QueuePropertyChange(const std::string& name, const std::string& value);
void QueueAllPropertyActions();
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index 52f6a1f..49fe24a 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -142,6 +142,14 @@
action_subcontext = subcontext_;
}
+ // We support 'on' for only Vendor APEXes from /{vendor, odm}.
+ // It is to prevent mainline modules from using 'on' triggers because events/properties are
+ // not stable for mainline modules.
+ // Note that this relies on Subcontext::PathMatchesSubcontext() to identify Vendor APEXes.
+ if (StartsWith(filename, "/apex/") && !action_subcontext) {
+ return Error() << "ParseSection() failed: 'on' is supported for only Vendor APEXes.";
+ }
+
std::string event_trigger;
std::map<std::string, std::string> property_triggers;
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 01db4f5..9e1d93c 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1288,7 +1288,8 @@
return Error() << "glob pattern '" << glob_pattern << "' failed";
}
std::vector<std::string> configs;
- Parser parser = CreateServiceOnlyParser(ServiceList::GetInstance(), true);
+ Parser parser =
+ CreateApexConfigParser(ActionManager::GetInstance(), ServiceList::GetInstance());
for (size_t i = 0; i < glob_result.gl_pathc; i++) {
std::string path = glob_result.gl_pathv[i];
// Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index d050ed7..202a86a 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -119,19 +119,14 @@
// Move snapuserd 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";
+ static constexpr const auto& snapuserd = "/system/bin/snapuserd";
+ static constexpr const auto& snapuserd_ramdisk = "/system/bin/snapuserd_ramdisk";
+ static constexpr const auto& 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) {
@@ -139,7 +134,18 @@
LOG(FATAL) << "Cannot create " << dst_dir << ": " << ec.message();
}
}
- Copy(src, dst);
+
+ // prefer the generic ramdisk copy of snapuserd, because that's on system side of treble
+ // boundary, and therefore is more likely to be updated along with the Android platform.
+ // The vendor ramdisk copy might be under vendor freeze, or vendor might choose not to update
+ // it.
+ if (access(snapuserd_ramdisk, F_OK) == 0) {
+ LOG(INFO) << "Using generic ramdisk copy of snapuserd " << snapuserd_ramdisk;
+ Copy(snapuserd_ramdisk, dst);
+ } else if (access(snapuserd, F_OK) == 0) {
+ LOG(INFO) << "Using vendor ramdisk copy of snapuserd " << snapuserd;
+ Copy(snapuserd, dst);
+ }
}
} // namespace
diff --git a/init/init.cpp b/init/init.cpp
index 038f172..4955bc5 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -48,7 +48,6 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <backtrace/Backtrace.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr_vendor_overlay.h>
#include <keyutils.h>
@@ -58,6 +57,7 @@
#include <processgroup/processgroup.h>
#include <processgroup/setup.h>
#include <selinux/android.h>
+#include <unwindstack/AndroidUnwinder.h>
#include "action_parser.h"
#include "builtins.h"
@@ -85,6 +85,10 @@
#include "system/core/init/property_service.pb.h"
#include "util.h"
+#ifndef RECOVERY
+#include "com_android_apex.h"
+#endif // RECOVERY
+
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -253,12 +257,14 @@
} shutdown_state;
static void UnwindMainThreadStack() {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 1));
- if (!backtrace->Unwind(0)) {
- LOG(ERROR) << __FUNCTION__ << "sys.powerctl: Failed to unwind callstack.";
+ unwindstack::AndroidLocalUnwinder unwinder;
+ unwindstack::AndroidUnwinderData data;
+ if (!unwinder.Unwind(data)) {
+ LOG(ERROR) << __FUNCTION__
+ << "sys.powerctl: Failed to unwind callstack: " << data.GetErrorString();
}
- for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- LOG(ERROR) << "sys.powerctl: " << backtrace->FormatFrameData(i);
+ for (const auto& frame : data.frames) {
+ LOG(ERROR) << "sys.powerctl: " << unwinder.FormatFrame(frame);
}
}
@@ -291,13 +297,59 @@
return parser;
}
-// parser that only accepts new services
-Parser CreateServiceOnlyParser(ServiceList& service_list, bool from_apex) {
- Parser parser;
+#ifndef RECOVERY
+template <typename T>
+struct LibXmlErrorHandler {
+ T handler_;
+ template <typename Handler>
+ LibXmlErrorHandler(Handler&& handler) : handler_(std::move(handler)) {
+ xmlSetGenericErrorFunc(nullptr, &ErrorHandler);
+ }
+ ~LibXmlErrorHandler() { xmlSetGenericErrorFunc(nullptr, nullptr); }
+ static void ErrorHandler(void*, const char* msg, ...) {
+ va_list args;
+ va_start(args, msg);
+ char* formatted;
+ if (vasprintf(&formatted, msg, args) >= 0) {
+ LOG(ERROR) << formatted;
+ }
+ free(formatted);
+ va_end(args);
+ }
+};
- parser.AddSectionParser(
- "service", std::make_unique<ServiceParser>(&service_list, GetSubcontext(), std::nullopt,
- from_apex));
+template <typename Handler>
+LibXmlErrorHandler(Handler&&) -> LibXmlErrorHandler<Handler>;
+#endif // RECOVERY
+
+// Returns a Parser that accepts scripts from APEX modules. It supports `service` and `on`.
+Parser CreateApexConfigParser(ActionManager& action_manager, ServiceList& service_list) {
+ Parser parser;
+ auto subcontext = GetSubcontext();
+#ifndef RECOVERY
+ if (subcontext) {
+ const auto apex_info_list_file = "/apex/apex-info-list.xml";
+ auto error_handler = LibXmlErrorHandler([&](const auto& error_message) {
+ LOG(ERROR) << "Failed to read " << apex_info_list_file << ":" << error_message;
+ });
+ const auto apex_info_list = com::android::apex::readApexInfoList(apex_info_list_file);
+ if (apex_info_list.has_value()) {
+ std::vector<std::string> subcontext_apexes;
+ for (const auto& info : apex_info_list->getApexInfo()) {
+ if (info.hasPreinstalledModulePath() &&
+ subcontext->PathMatchesSubcontext(info.getPreinstalledModulePath())) {
+ subcontext_apexes.push_back(info.getModuleName());
+ }
+ }
+ subcontext->SetApexList(std::move(subcontext_apexes));
+ }
+ }
+#endif // RECOVERY
+ parser.AddSectionParser("service",
+ std::make_unique<ServiceParser>(&service_list, subcontext, std::nullopt,
+ /*from_apex=*/true));
+ parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontext));
+
return parser;
}
diff --git a/init/init.h b/init/init.h
index 4f686cb..5220535 100644
--- a/init/init.h
+++ b/init/init.h
@@ -29,7 +29,7 @@
namespace init {
Parser CreateParser(ActionManager& action_manager, ServiceList& service_list);
-Parser CreateServiceOnlyParser(ServiceList& service_list, bool from_apex);
+Parser CreateApexConfigParser(ActionManager& action_manager, ServiceList& service_list);
bool start_waiting_for_property(const char *name, const char *value);
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 8550ec8..0dc6ff6 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -42,34 +42,34 @@
using ActionManagerCommand = std::function<void(ActionManager&)>;
void TestInit(const std::string& init_script_file, const BuiltinFunctionMap& test_function_map,
- const std::vector<ActionManagerCommand>& commands, ServiceList* service_list) {
- ActionManager am;
-
+ const std::vector<ActionManagerCommand>& commands, ActionManager* action_manager,
+ ServiceList* service_list) {
Action::set_function_map(&test_function_map);
Parser parser;
parser.AddSectionParser("service",
std::make_unique<ServiceParser>(service_list, nullptr, std::nullopt));
- parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
+ parser.AddSectionParser("on", std::make_unique<ActionParser>(action_manager, nullptr));
parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
ASSERT_TRUE(parser.ParseConfig(init_script_file));
for (const auto& command : commands) {
- command(am);
+ command(*action_manager);
}
- while (am.HasMoreCommands()) {
- am.ExecuteOneCommand();
+ while (action_manager->HasMoreCommands()) {
+ action_manager->ExecuteOneCommand();
}
}
void TestInitText(const std::string& init_script, const BuiltinFunctionMap& test_function_map,
- const std::vector<ActionManagerCommand>& commands, ServiceList* service_list) {
+ const std::vector<ActionManagerCommand>& commands, ActionManager* action_manager,
+ ServiceList* service_list) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFd(init_script, tf.fd));
- TestInit(tf.path, test_function_map, commands, service_list);
+ TestInit(tf.path, test_function_map, commands, action_manager, service_list);
}
TEST(init, SimpleEventTrigger) {
@@ -91,8 +91,9 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
+ ActionManager action_manager;
ServiceList service_list;
- TestInitText(init_script, test_function_map, commands, &service_list);
+ TestInitText(init_script, test_function_map, commands, &action_manager, &service_list);
EXPECT_TRUE(expect_true);
}
@@ -154,8 +155,10 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
+ ActionManager action_manager;
ServiceList service_list;
- TestInitText(init_script, test_function_map, commands, &service_list);
+ TestInitText(init_script, test_function_map, commands, &action_manager, &service_list);
+ EXPECT_EQ(3, num_executed);
}
TEST(init, OverrideService) {
@@ -169,8 +172,9 @@
)init";
+ ActionManager action_manager;
ServiceList service_list;
- TestInitText(init_script, BuiltinFunctionMap(), {}, &service_list);
+ TestInitText(init_script, BuiltinFunctionMap(), {}, &action_manager, &service_list);
ASSERT_EQ(1, std::distance(service_list.begin(), service_list.end()));
auto service = service_list.begin()->get();
@@ -236,13 +240,100 @@
ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
std::vector<ActionManagerCommand> commands{trigger_boot};
+ ActionManager action_manager;
ServiceList service_list;
-
- TestInit(start.path, test_function_map, commands, &service_list);
+ TestInit(start.path, test_function_map, commands, &action_manager, &service_list);
EXPECT_EQ(6, num_executed);
}
+BuiltinFunctionMap GetTestFunctionMapForLazyLoad(int& num_executed, ActionManager& action_manager) {
+ auto execute_command = [&num_executed](const BuiltinArguments& args) {
+ EXPECT_EQ(2U, args.size());
+ EXPECT_EQ(++num_executed, std::stoi(args[1]));
+ return Result<void>{};
+ };
+ auto load_command = [&action_manager](const BuiltinArguments& args) -> Result<void> {
+ EXPECT_EQ(2U, args.size());
+ Parser parser;
+ parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, nullptr));
+ if (!parser.ParseConfig(args[1])) {
+ return Error() << "Failed to load";
+ }
+ return Result<void>{};
+ };
+ auto trigger_command = [&action_manager](const BuiltinArguments& args) {
+ EXPECT_EQ(2U, args.size());
+ LOG(INFO) << "Queue event trigger: " << args[1];
+ action_manager.QueueEventTrigger(args[1]);
+ return Result<void>{};
+ };
+ BuiltinFunctionMap test_function_map = {
+ {"execute", {1, 1, {false, execute_command}}},
+ {"load", {1, 1, {false, load_command}}},
+ {"trigger", {1, 1, {false, trigger_command}}},
+ };
+ return test_function_map;
+}
+
+TEST(init, LazilyLoadedActionsCantBeTriggeredByTheSameTrigger) {
+ // "start" script loads "lazy" script. Even though "lazy" scripts
+ // defines "on boot" action, it's not executed by the current "boot"
+ // event because it's already processed.
+ TemporaryFile lazy;
+ ASSERT_TRUE(lazy.fd != -1);
+ ASSERT_TRUE(android::base::WriteStringToFd("on boot\nexecute 2", lazy.fd));
+
+ TemporaryFile start;
+ // clang-format off
+ std::string start_script = "on boot\n"
+ "load " + std::string(lazy.path) + "\n"
+ "execute 1";
+ // clang-format on
+ ASSERT_TRUE(android::base::WriteStringToFd(start_script, start.fd));
+
+ int num_executed = 0;
+ ActionManager action_manager;
+ ServiceList service_list;
+ BuiltinFunctionMap test_function_map =
+ GetTestFunctionMapForLazyLoad(num_executed, action_manager);
+
+ ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
+ std::vector<ActionManagerCommand> commands{trigger_boot};
+ TestInit(start.path, test_function_map, commands, &action_manager, &service_list);
+
+ EXPECT_EQ(1, num_executed);
+}
+
+TEST(init, LazilyLoadedActionsCanBeTriggeredByTheNextTrigger) {
+ // "start" script loads "lazy" script and then triggers "next" event
+ // which executes "on next" action loaded by the previous command.
+ TemporaryFile lazy;
+ ASSERT_TRUE(lazy.fd != -1);
+ ASSERT_TRUE(android::base::WriteStringToFd("on next\nexecute 2", lazy.fd));
+
+ TemporaryFile start;
+ // clang-format off
+ std::string start_script = "on boot\n"
+ "load " + std::string(lazy.path) + "\n"
+ "execute 1\n"
+ "trigger next";
+ // clang-format on
+ ASSERT_TRUE(android::base::WriteStringToFd(start_script, start.fd));
+
+ int num_executed = 0;
+ ActionManager action_manager;
+ ServiceList service_list;
+ BuiltinFunctionMap test_function_map =
+ GetTestFunctionMapForLazyLoad(num_executed, action_manager);
+
+ ActionManagerCommand trigger_boot = [](ActionManager& am) { am.QueueEventTrigger("boot"); };
+ std::vector<ActionManagerCommand> commands{trigger_boot};
+ TestInit(start.path, test_function_map, commands, &action_manager, &service_list);
+
+ EXPECT_EQ(2, num_executed);
+}
+
TEST(init, RejectsCriticalAndOneshotService) {
if (GetIntProperty("ro.product.first_api_level", 10000) < 30) {
GTEST_SKIP() << "Test only valid for devices launching with R or later";
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 9f7c215..a1f6e04 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -54,6 +54,7 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
+#include <android-base/result.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <property_info_parser/property_info_parser.h>
@@ -76,9 +77,12 @@
using namespace std::literals;
+using android::base::ErrnoError;
+using android::base::Error;
using android::base::GetProperty;
using android::base::ParseInt;
using android::base::ReadFileToString;
+using android::base::Result;
using android::base::Split;
using android::base::StartsWith;
using android::base::StringPrintf;
@@ -629,8 +633,8 @@
return result;
}
-static bool load_properties_from_file(const char*, const char*,
- std::map<std::string, std::string>*);
+static Result<void> load_properties_from_file(const char*, const char*,
+ std::map<std::string, std::string>*);
/*
* Filter is used to decide which properties to load: NULL loads all keys,
@@ -691,7 +695,10 @@
continue;
}
- load_properties_from_file(expanded_filename->c_str(), key, properties);
+ if (auto res = load_properties_from_file(expanded_filename->c_str(), key, properties);
+ !res.ok()) {
+ LOG(WARNING) << res.error();
+ }
} else {
value = strchr(key, '=');
if (!value) continue;
@@ -738,20 +745,19 @@
// Filter is used to decide which properties to load: NULL loads all keys,
// "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
-static bool load_properties_from_file(const char* filename, const char* filter,
- std::map<std::string, std::string>* properties) {
+static Result<void> load_properties_from_file(const char* filename, const char* filter,
+ std::map<std::string, std::string>* properties) {
Timer t;
auto file_contents = ReadFile(filename);
if (!file_contents.ok()) {
- PLOG(WARNING) << "Couldn't load property file '" << filename
- << "': " << file_contents.error();
- return false;
+ return Error() << "Couldn't load property file '" << filename
+ << "': " << file_contents.error();
}
file_contents->push_back('\n');
LoadProperties(file_contents->data(), filter, filename, properties);
LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
- return true;
+ return {};
}
static void LoadPropertiesFromSecondStageRes(std::map<std::string, std::string>* properties) {
@@ -760,7 +766,9 @@
CHECK(errno == ENOENT) << "Cannot access " << prop << ": " << strerror(errno);
return;
}
- load_properties_from_file(prop.c_str(), nullptr, properties);
+ if (auto res = load_properties_from_file(prop.c_str(), nullptr, properties); !res.ok()) {
+ LOG(WARNING) << res.error();
+ }
}
// persist.sys.usb.config values can't be combined on build-time when property
@@ -1058,7 +1066,10 @@
std::map<std::string, std::string> properties;
if (IsRecoveryMode()) {
- load_properties_from_file("/prop.default", nullptr, &properties);
+ if (auto res = load_properties_from_file("/prop.default", nullptr, &properties);
+ !res.ok()) {
+ LOG(ERROR) << res.error();
+ }
}
// /<part>/etc/build.prop is the canonical location of the build-time properties since S.
@@ -1067,7 +1078,7 @@
const auto load_properties_from_partition = [&properties](const std::string& partition,
int support_legacy_path_until) {
auto path = "/" + partition + "/etc/build.prop";
- if (load_properties_from_file(path.c_str(), nullptr, &properties)) {
+ if (load_properties_from_file(path.c_str(), nullptr, &properties).ok()) {
return;
}
// To read ro.<partition>.build.version.sdk, temporarily load the legacy paths into a
@@ -1105,7 +1116,13 @@
// Order matters here. The more the partition is specific to a product, the higher its
// precedence is.
LoadPropertiesFromSecondStageRes(&properties);
- load_properties_from_file("/system/build.prop", nullptr, &properties);
+
+ // system should have build.prop, unlike the other partitions
+ if (auto res = load_properties_from_file("/system/build.prop", nullptr, &properties);
+ !res.ok()) {
+ LOG(WARNING) << res.error();
+ }
+
load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
load_properties_from_file("/system_dlkm/etc/build.prop", nullptr, &properties);
// TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
@@ -1121,7 +1138,10 @@
if (access(kDebugRamdiskProp, R_OK) == 0) {
LOG(INFO) << "Loading " << kDebugRamdiskProp;
- load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
+ if (auto res = load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
+ !res.ok()) {
+ LOG(WARNING) << res.error();
+ }
}
for (const auto& [name, value] : properties) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 41cf748..4e4bfd8 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -892,7 +892,16 @@
sub_reason = "ns_switch";
return Error() << "Failed to switch to bootstrap namespace";
}
- // Remove services that were defined in an APEX.
+ ActionManager::GetInstance().RemoveActionIf([](const auto& action) -> bool {
+ if (action->IsFromApex()) {
+ std::string trigger_name = action->BuildTriggersString();
+ LOG(INFO) << "Removing action (" << trigger_name << ") from (" << action->filename()
+ << ":" << action->line() << ")";
+ return true;
+ }
+ return false;
+ });
+ // Remove services that were defined in an APEX
ServiceList::GetInstance().RemoveServiceIf([](const std::unique_ptr<Service>& s) -> bool {
if (s->is_from_apex()) {
LOG(INFO) << "Removing service '" << s->name() << "' because it's defined in an APEX";
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index b3fa9fd..f8e1de0 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -26,8 +26,8 @@
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include <backtrace/Backtrace.h>
#include <cutils/android_reboot.h>
+#include <unwindstack/AndroidUnwinder.h>
#include "capabilities.h"
#include "reboot_utils.h"
@@ -157,13 +157,13 @@
// In the parent, let's try to get a backtrace then shutdown.
LOG(ERROR) << __FUNCTION__ << ": signal " << signal_number;
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- if (!backtrace->Unwind(0)) {
- LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack.";
+ unwindstack::AndroidLocalUnwinder unwinder;
+ unwindstack::AndroidUnwinderData data;
+ if (!unwinder.Unwind(data)) {
+ LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack: " << data.GetErrorString();
}
- for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- LOG(ERROR) << backtrace->FormatFrameData(i);
+ for (const auto& frame : data.frames) {
+ LOG(ERROR) << unwinder.FormatFrame(frame);
}
if (init_fatal_panic) {
LOG(ERROR) << __FUNCTION__ << ": Trigger crash";
diff --git a/init/service.cpp b/init/service.cpp
index 077477a..01dd685 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -288,6 +288,10 @@
if (flags_ & SVC_EXEC) UnSetExec();
+ if (name_ == "zygote" || name_ == "zygote64") {
+ removeAllEmptyProcessGroups();
+ }
+
if (flags_ & SVC_TEMPORARY) return;
pid_ = 0;
@@ -541,6 +545,10 @@
if ((flags_ & SVC_ONESHOT) && disabled) {
flags_ |= SVC_RESTART;
}
+
+ LOG(INFO) << "service '" << name_
+ << "' requested start, but it is already running (flags: " << flags_ << ")";
+
// It is not an error to try to start a service that is already running.
reboot_on_failure.Disable();
return {};
diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp
index 5deaf31..5c821b0 100644
--- a/init/snapuserd_transition.cpp
+++ b/init/snapuserd_transition.cpp
@@ -29,6 +29,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
@@ -40,6 +41,7 @@
#include <snapuserd/snapuserd_client.h>
#include "block_dev_initializer.h"
+#include "lmkd_service.h"
#include "service_utils.h"
#include "util.h"
@@ -320,6 +322,14 @@
LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
+ // Since daemon is not started as a service, we have
+ // to explicitly set the OOM score to default which is unkillable
+ std::string oom_str = std::to_string(DEFAULT_OOM_SCORE_ADJUST);
+ std::string oom_file = android::base::StringPrintf("/proc/%d/oom_score_adj", pid);
+ if (!android::base::WriteStringToFile(oom_str, oom_file)) {
+ PLOG(ERROR) << "couldn't write oom_score_adj to snapuserd daemon with pid: " << pid;
+ }
+
if (!TestSnapuserdIsReady()) {
PLOG(FATAL) << "snapuserd daemon failed to launch";
} else {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 7aa4a9d..bb3967e 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -250,7 +250,14 @@
Fork();
}
-bool Subcontext::PathMatchesSubcontext(const std::string& path) {
+bool Subcontext::PathMatchesSubcontext(const std::string& path) const {
+ static const std::string kApexDir = "/apex/";
+ if (StartsWith(path, kApexDir)) {
+ auto begin = kApexDir.size();
+ auto end = path.find('/', begin);
+ auto apex_name = path.substr(begin, end - begin);
+ return std::find(apex_list_.begin(), apex_list_.end(), apex_name) != apex_list_.end();
+ }
for (const auto& prefix : path_prefixes_) {
if (StartsWith(path, prefix)) {
return true;
@@ -259,6 +266,10 @@
return false;
}
+void Subcontext::SetApexList(std::vector<std::string>&& apex_list) {
+ apex_list_ = std::move(apex_list);
+}
+
Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
if (auto result = SendMessage(socket_, subcontext_command); !result.ok()) {
Restart();
diff --git a/init/subcontext.h b/init/subcontext.h
index cb4138e..8acc032 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -46,7 +46,8 @@
Result<void> Execute(const std::vector<std::string>& args);
Result<std::vector<std::string>> ExpandArgs(const std::vector<std::string>& args);
void Restart();
- bool PathMatchesSubcontext(const std::string& path);
+ bool PathMatchesSubcontext(const std::string& path) const;
+ void SetApexList(std::vector<std::string>&& apex_list);
const std::string& context() const { return context_; }
pid_t pid() const { return pid_; }
@@ -56,6 +57,7 @@
Result<SubcontextReply> TransmitMessage(const SubcontextCommand& subcontext_command);
std::vector<std::string> path_prefixes_;
+ std::vector<std::string> apex_list_;
std::string context_;
pid_t pid_;
android::base::unique_fd socket_;
diff --git a/init/util.cpp b/init/util.cpp
index d1e518b..1801d17 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -61,6 +61,8 @@
const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");
+const std::string kDataDirPrefix("/data/");
+
void (*trigger_shutdown)(const std::string& command) = nullptr;
// DecodeUid() - decodes and returns the given string, which can be either the
@@ -458,58 +460,34 @@
return {};
}
-static FscryptAction FscryptInferAction(const std::string& dir) {
- const std::string prefix = "/data/";
-
- if (!android::base::StartsWith(dir, prefix)) {
- return FscryptAction::kNone;
- }
-
- // Special-case /data/media/obb per b/64566063
- if (dir == "/data/media/obb") {
- // Try to set policy on this directory, but if it is non-empty this may fail.
- return FscryptAction::kAttempt;
- }
-
- // Only set policy on first level /data directories
- // To make this less restrictive, consider using a policy file.
- // However this is overkill for as long as the policy is simply
- // to apply a global policy to all /data folders created via makedir
- if (dir.find_first_of('/', prefix.size()) != std::string::npos) {
- return FscryptAction::kNone;
- }
-
- // Special case various directories that must not be encrypted,
- // often because their subdirectories must be encrypted.
- // This isn't a nice way to do this, see b/26641735
- std::vector<std::string> directories_to_exclude = {
- "lost+found", "system_ce", "system_de", "misc_ce", "misc_de",
- "vendor_ce", "vendor_de", "media", "data", "user",
- "user_de", "apex", "preloads", "app-staging", "gsi",
- };
- for (const auto& d : directories_to_exclude) {
- if ((prefix + d) == dir) {
- return FscryptAction::kNone;
+// Remove unnecessary slashes so that any later checks (e.g., the check for
+// whether the path is a top-level directory in /data) don't get confused.
+std::string CleanDirPath(const std::string& path) {
+ std::string result;
+ result.reserve(path.length());
+ // Collapse duplicate slashes, e.g. //data//foo// => /data/foo/
+ for (char c : path) {
+ if (c != '/' || result.empty() || result.back() != '/') {
+ result += c;
}
}
- // Empty these directories if policy setting fails.
- std::vector<std::string> wipe_on_failure = {
- "rollback", "rollback-observer", // b/139193659
- };
- for (const auto& d : wipe_on_failure) {
- if ((prefix + d) == dir) {
- return FscryptAction::kDeleteIfNecessary;
- }
+ // Remove trailing slash, e.g. /data/foo/ => /data/foo
+ if (result.length() > 1 && result.back() == '/') {
+ result.pop_back();
}
- return FscryptAction::kRequire;
+ return result;
}
Result<MkdirOptions> ParseMkdir(const std::vector<std::string>& args) {
+ std::string path = CleanDirPath(args[1]);
+ const bool is_toplevel_data_dir =
+ StartsWith(path, kDataDirPrefix) &&
+ path.find_first_of('/', kDataDirPrefix.size()) == std::string::npos;
+ FscryptAction fscrypt_action =
+ is_toplevel_data_dir ? FscryptAction::kRequire : FscryptAction::kNone;
mode_t mode = 0755;
Result<uid_t> uid = -1;
Result<gid_t> gid = -1;
- FscryptAction fscrypt_inferred_action = FscryptInferAction(args[1]);
- FscryptAction fscrypt_action = fscrypt_inferred_action;
std::string ref_option = "ref";
bool set_option_encryption = false;
bool set_option_key = false;
@@ -574,24 +552,17 @@
if (set_option_key && fscrypt_action == FscryptAction::kNone) {
return Error() << "Key option set but encryption action is none";
}
- const std::string prefix = "/data/";
- if (StartsWith(args[1], prefix) &&
- args[1].find_first_of('/', prefix.size()) == std::string::npos) {
+ if (is_toplevel_data_dir) {
if (!set_option_encryption) {
- LOG(WARNING) << "Top-level directory needs encryption action, eg mkdir " << args[1]
+ LOG(WARNING) << "Top-level directory needs encryption action, eg mkdir " << path
<< " <mode> <uid> <gid> encryption=Require";
}
if (fscrypt_action == FscryptAction::kNone) {
- LOG(INFO) << "Not setting encryption policy on: " << args[1];
+ LOG(INFO) << "Not setting encryption policy on: " << path;
}
}
- if (fscrypt_action != fscrypt_inferred_action) {
- LOG(WARNING) << "Inferred action different from explicit one, expected "
- << static_cast<int>(fscrypt_inferred_action) << " but got "
- << static_cast<int>(fscrypt_action);
- }
- return MkdirOptions{args[1], mode, *uid, *gid, fscrypt_action, ref_option};
+ return MkdirOptions{path, mode, *uid, *gid, fscrypt_action, ref_option};
}
Result<MountAllOptions> ParseMountAll(const std::vector<std::string>& args) {
diff --git a/init/util.h b/init/util.h
index bf53675..47d4ff5 100644
--- a/init/util.h
+++ b/init/util.h
@@ -69,6 +69,7 @@
bool IsLegalPropertyName(const std::string& name);
Result<void> IsLegalPropertyValue(const std::string& name, const std::string& value);
+std::string CleanDirPath(const std::string& path);
struct MkdirOptions {
std::string target;
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 565e7d4..e8144c3 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -170,5 +170,18 @@
EXPECT_TRUE(is_dir(path1.c_str()));
}
+TEST(util, CleanDirPath) {
+ EXPECT_EQ("", CleanDirPath(""));
+ EXPECT_EQ("/", CleanDirPath("/"));
+ EXPECT_EQ("/", CleanDirPath("//"));
+ EXPECT_EQ("/foo", CleanDirPath("/foo"));
+ EXPECT_EQ("/foo", CleanDirPath("//foo"));
+ EXPECT_EQ("/foo", CleanDirPath("/foo/"));
+ EXPECT_EQ("/foo/bar", CleanDirPath("/foo/bar"));
+ EXPECT_EQ("/foo/bar", CleanDirPath("/foo/bar/"));
+ EXPECT_EQ("/foo/bar", CleanDirPath("/foo/bar////"));
+ EXPECT_EQ("/foo/bar", CleanDirPath("//foo//bar"));
+}
+
} // namespace init
} // namespace android
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index 98ae0d4..3867f34 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -214,6 +214,7 @@
* provided, which is the name of the row where this async event should be
* recorded. The track name, name, and cookie used to begin an event must be
* used to end it.
+ * The cookie here must be unique on the track_name level, not the name level.
*/
#define ATRACE_ASYNC_FOR_TRACK_BEGIN(track_name, name, cookie) \
atrace_async_for_track_begin(ATRACE_TAG, track_name, name, cookie)
@@ -229,13 +230,13 @@
* Trace the end of an asynchronous event.
* This should correspond to a previous ATRACE_ASYNC_FOR_TRACK_BEGIN.
*/
-#define ATRACE_ASYNC_FOR_TRACK_END(track_name, name, cookie) \
- atrace_async_for_track_end(ATRACE_TAG, track_name, name, cookie)
+#define ATRACE_ASYNC_FOR_TRACK_END(track_name, cookie) \
+ atrace_async_for_track_end(ATRACE_TAG, track_name, cookie)
static inline void atrace_async_for_track_end(uint64_t tag, const char* track_name,
- const char* name, int32_t cookie) {
+ int32_t cookie) {
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
- void atrace_async_for_track_end_body(const char*, const char*, int32_t);
- atrace_async_for_track_end_body(track_name, name, cookie);
+ void atrace_async_for_track_end_body(const char*, int32_t);
+ atrace_async_for_track_end_body(track_name, cookie);
}
}
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 8bb8652..bdb8075 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -137,6 +137,7 @@
#define AID_JC_STRONGBOX 1088 /* Javacard Strongbox HAL - to manage omapi ARA rules */
#define AID_JC_IDENTITYCRED 1089 /* Javacard Identity Cred HAL - to manage omapi ARA rules */
#define AID_SDK_SANDBOX 1090 /* SDK sandbox virtual UID */
+#define AID_SECURITY_LOG_WRITER 1091 /* write to security log */
/* 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/trace-container.cpp b/libcutils/trace-container.cpp
index 8901e4a..eae6155 100644
--- a/libcutils/trace-container.cpp
+++ b/libcutils/trace-container.cpp
@@ -231,24 +231,24 @@
void atrace_async_for_track_begin_body(const char* track_name, const char* name, int32_t cookie) {
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("T", "|", "|%d", track_name, name, cookie);
+ WRITE_MSG_IN_CONTAINER("G", "|", "|%d", track_name, name, cookie);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("T|%d|", "|%" PRId32, track_name, name, cookie);
+ WRITE_MSG("G|%d|", "|%" PRId32, track_name, name, cookie);
}
-void atrace_async_for_track_end_body(const char* track_name, const char* name, int32_t cookie) {
+void atrace_async_for_track_end_body(const char* track_name, int32_t cookie) {
if (CC_LIKELY(atrace_use_container_sock)) {
- WRITE_MSG_IN_CONTAINER("U", "|", "|%d", track_name, name, cookie);
+ WRITE_MSG_IN_CONTAINER("H", "|", "|%d", "", track_name, cookie);
return;
}
if (atrace_marker_fd < 0) return;
- WRITE_MSG("U|%d|", "|%" PRId32, track_name, name, cookie);
+ WRITE_MSG("H|%d|", "|%" PRId32, "", track_name, cookie);
}
void atrace_instant_body(const char* name) {
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index eacc8ee..1827e32 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -90,11 +90,11 @@
}
void atrace_async_for_track_begin_body(const char* track_name, const char* name, int32_t cookie) {
- WRITE_MSG("T|%d|", "|%" PRId32, track_name, name, cookie);
+ WRITE_MSG("G|%d|", "|%" PRId32, track_name, name, cookie);
}
-void atrace_async_for_track_end_body(const char* track_name, const char* name, int32_t cookie) {
- WRITE_MSG("U|%d|", "|%" PRId32, track_name, name, cookie);
+void atrace_async_for_track_end_body(const char* track_name, int32_t cookie) {
+ WRITE_MSG("H|%d|", "|%" PRId32, "", track_name, cookie);
}
void atrace_instant_body(const char* name) {
diff --git a/libcutils/trace-dev_test.cpp b/libcutils/trace-dev_test.cpp
index 841674a..3dea5ff 100644
--- a/libcutils/trace-dev_test.cpp
+++ b/libcutils/trace-dev_test.cpp
@@ -202,13 +202,13 @@
std::string actual;
ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- std::string expected = android::base::StringPrintf("T|%d|fake_track|fake_name|12345", getpid());
+ std::string expected = android::base::StringPrintf("G|%d|fake_track|fake_name|12345", getpid());
ASSERT_STREQ(expected.c_str(), actual.c_str());
}
TEST_F(TraceDevTest, atrace_async_for_track_begin_body_exact_track_name) {
const int name_size = 5;
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
+ std::string expected = android::base::StringPrintf("G|%d|", getpid());
std::string track_name =
MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - name_size - 6);
atrace_async_for_track_begin_body(track_name.c_str(), "name", 12345);
@@ -224,7 +224,7 @@
// Add a single character and verify name truncation
ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
track_name += '*';
- expected = android::base::StringPrintf("T|%d|", getpid());
+ expected = android::base::StringPrintf("G|%d|", getpid());
expected += track_name + "|nam|12345";
atrace_async_for_track_begin_body(track_name.c_str(), "name", 12345);
EXPECT_EQ(ATRACE_MESSAGE_LENGTH - 1, lseek(atrace_marker_fd, 0, SEEK_CUR));
@@ -234,7 +234,7 @@
}
TEST_F(TraceDevTest, atrace_async_for_track_begin_body_truncated_track_name) {
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
+ std::string expected = android::base::StringPrintf("G|%d|", getpid());
std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
atrace_async_for_track_begin_body(track_name.c_str(), "name", 12345);
@@ -250,7 +250,7 @@
TEST_F(TraceDevTest, atrace_async_for_track_begin_body_exact_name) {
const int track_name_size = 11;
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
+ std::string expected = android::base::StringPrintf("G|%d|", getpid());
std::string name =
MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - track_name_size - 6);
atrace_async_for_track_begin_body("track_name", name.c_str(), 12345);
@@ -274,7 +274,7 @@
}
TEST_F(TraceDevTest, atrace_async_for_track_begin_body_truncated_name) {
- std::string expected = android::base::StringPrintf("T|%d|track_name|", getpid());
+ std::string expected = android::base::StringPrintf("G|%d|track_name|", getpid());
std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
atrace_async_for_track_begin_body("track_name", name.c_str(), 12345);
@@ -289,7 +289,7 @@
}
TEST_F(TraceDevTest, atrace_async_for_track_begin_body_truncated_both) {
- std::string expected = android::base::StringPrintf("T|%d|", getpid());
+ std::string expected = android::base::StringPrintf("G|%d|", getpid());
std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
atrace_async_for_track_begin_body(track_name.c_str(), name.c_str(), 12345);
@@ -306,112 +306,52 @@
}
TEST_F(TraceDevTest, atrace_async_for_track_end_body_normal) {
- atrace_async_for_track_end_body("fake_track", "fake_name", 12345);
+ atrace_async_for_track_end_body("fake_track", 12345);
ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
std::string actual;
ASSERT_TRUE(android::base::ReadFdToString(atrace_marker_fd, &actual));
- std::string expected = android::base::StringPrintf("U|%d|fake_track|fake_name|12345", getpid());
+ std::string expected = android::base::StringPrintf("H|%d|fake_track|12345", getpid());
ASSERT_STREQ(expected.c_str(), actual.c_str());
}
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_exact_track_name) {
- const int name_size = 5;
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
+TEST_F(TraceDevTest, atrace_async_for_track_end_body_exact) {
+ std::string expected = android::base::StringPrintf("H|%d|", getpid());
std::string track_name =
- MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - name_size - 6);
- atrace_async_for_track_end_body(track_name.c_str(), "name", 12345);
+ MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 7);
+ atrace_async_for_track_end_body(track_name.c_str(), 12345);
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|12345";
+ expected += track_name + "|12345";
ASSERT_STREQ(expected.c_str(), actual.c_str());
- // Add a single character and verify name truncation
+ // Add a single character and verify we get the exact same value as before.
ASSERT_EQ(0, lseek(atrace_marker_fd, 0, SEEK_SET));
track_name += '*';
- expected = android::base::StringPrintf("U|%d|", getpid());
- expected += track_name + "|nam|12345";
- atrace_async_for_track_end_body(track_name.c_str(), "name", 12345);
+ atrace_async_for_track_end_body(track_name.c_str(), 12345);
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_async_for_track_end_body_truncated_track_name) {
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
+TEST_F(TraceDevTest, atrace_async_for_track_end_body_truncated) {
+ std::string expected = android::base::StringPrintf("H|%d|", getpid());
std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_end_body(track_name.c_str(), "name", 12345);
+ atrace_async_for_track_end_body(track_name.c_str(), 12345);
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() - 9;
- expected += android::base::StringPrintf("%.*s|n|12345", expected_len, track_name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_exact_name) {
- const int track_name_size = 11;
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
- std::string name =
- MakeName(ATRACE_MESSAGE_LENGTH - expected.length() - 1 - track_name_size - 6);
- atrace_async_for_track_end_body("track_name", name.c_str(), 12345);
-
- 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 + "|12345";
- 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_async_for_track_end_body("track_name", name.c_str(), 12345);
- 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_async_for_track_end_body_truncated_name) {
- std::string expected = android::base::StringPrintf("U|%d|track_name|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_end_body("track_name", name.c_str(), 12345);
-
- 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 - 6;
- expected += android::base::StringPrintf("%.*s|12345", expected_len, name.c_str());
- ASSERT_STREQ(expected.c_str(), actual.c_str());
-}
-
-TEST_F(TraceDevTest, atrace_async_for_track_end_body_truncated_both) {
- std::string expected = android::base::StringPrintf("U|%d|", getpid());
- std::string name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- std::string track_name = MakeName(2 * ATRACE_MESSAGE_LENGTH);
- atrace_async_for_track_end_body(track_name.c_str(), name.c_str(), 12345);
-
- 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 - 6;
- expected += android::base::StringPrintf("%.*s|%.1s|12345", expected_len, track_name.c_str(),
- name.c_str());
+ int expected_len = ATRACE_MESSAGE_LENGTH - expected.length() - 7;
+ expected += android::base::StringPrintf("%.*s|12345", expected_len, track_name.c_str());
ASSERT_STREQ(expected.c_str(), actual.c_str());
}
diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp
index c2a379b..e9f58c3 100644
--- a/libcutils/trace-host.cpp
+++ b/libcutils/trace-host.cpp
@@ -30,8 +30,7 @@
void atrace_async_end_body(const char* /*name*/, int32_t /*cookie*/) {}
void atrace_async_for_track_begin_body(const char* /*track_name*/, const char* /*name*/,
int32_t /*cookie*/) {}
-void atrace_async_for_track_end_body(const char* /*track_name*/, const char* /*name*/,
- int32_t /*cookie*/) {}
+void atrace_async_for_track_end_body(const char* /*track_name*/, int32_t /*cookie*/) {}
void atrace_instant_body(const char* /*name*/) {}
void atrace_instant_for_track_body(const char* /*track_name*/, const char* /*name*/) {}
void atrace_int_body(const char* /*name*/, int32_t /*value*/) {}
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index c5badc9..39b9f3f 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -67,6 +67,7 @@
bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes);
void removeAllProcessGroups(void);
+void removeAllEmptyProcessGroups(void);
// Provides the path for an attribute in a specific process group
// Returns false in case of error, true in case of success
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index e3a80e9..267e62c 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -200,7 +200,7 @@
return ret;
}
-static bool RemoveUidProcessGroups(const std::string& uid_path) {
+static bool RemoveUidProcessGroups(const std::string& uid_path, bool empty_only) {
std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path.c_str()), closedir);
bool empty = true;
if (uid != NULL) {
@@ -215,6 +215,21 @@
}
auto path = StringPrintf("%s/%s", uid_path.c_str(), dir->d_name);
+ if (empty_only) {
+ struct stat st;
+ auto procs_file = StringPrintf("%s/%s", path.c_str(),
+ PROCESSGROUP_CGROUP_PROCS_FILE);
+ if (stat(procs_file.c_str(), &st) == -1) {
+ PLOG(ERROR) << "Failed to get stats for " << procs_file;
+ continue;
+ }
+ if (st.st_size > 0) {
+ // skip non-empty groups
+ LOG(VERBOSE) << "Skipping non-empty group " << path;
+ empty = false;
+ continue;
+ }
+ }
LOG(VERBOSE) << "Removing " << path;
if (rmdir(path.c_str()) == -1) {
if (errno != EBUSY) {
@@ -227,9 +242,7 @@
return empty;
}
-void removeAllProcessGroups() {
- LOG(VERBOSE) << "removeAllProcessGroups()";
-
+void removeAllProcessGroupsInternal(bool empty_only) {
std::vector<std::string> cgroups;
std::string path, memcg_apps_path;
@@ -256,7 +269,7 @@
}
auto path = StringPrintf("%s/%s", cgroup_root_path.c_str(), dir->d_name);
- if (!RemoveUidProcessGroups(path)) {
+ if (!RemoveUidProcessGroups(path, empty_only)) {
LOG(VERBOSE) << "Skip removing " << path;
continue;
}
@@ -269,6 +282,16 @@
}
}
+void removeAllProcessGroups() {
+ LOG(VERBOSE) << "removeAllProcessGroups()";
+ removeAllProcessGroupsInternal(false);
+}
+
+void removeAllEmptyProcessGroups() {
+ LOG(VERBOSE) << "removeAllEmptyProcessGroups()";
+ removeAllProcessGroupsInternal(true);
+}
+
/**
* Process groups are primarily created by the Zygote, meaning that uid/pid groups are created by
* the user root. Ownership for the newly created cgroup and all of its files must thus be
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index f5533c2..8589a8d 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -224,19 +224,6 @@
]
},
{
- "Name": "VMCompilationPerformance",
- "Actions": [
- {
- "Name": "JoinCgroup",
- "Params":
- {
- "Controller": "cpu",
- "Path": "system"
- }
- }
- ]
- },
- {
"Name": "CpuPolicySpread",
"Actions": [
{
@@ -660,6 +647,10 @@
"Profiles": [ "ServicePerformance", "LowIoPriority", "TimerSlackNormal" ]
},
{
+ "Name": "SCHED_SP_COMPUTE",
+ "Profiles": [ "HighPerformance", "ProcessCapacityHigh", "LowIoPriority", "TimerSlackNormal" ]
+ },
+ {
"Name": "SCHED_SP_RT_APP",
"Profiles": [ "RealtimePerformance", "MaxIoPriority", "TimerSlackNormal" ]
},
diff --git a/libsparse/img2simg.cpp b/libsparse/img2simg.cpp
index 3e24cc0..51580f7 100644
--- a/libsparse/img2simg.cpp
+++ b/libsparse/img2simg.cpp
@@ -38,24 +38,41 @@
#endif
void usage() {
- fprintf(stderr, "Usage: img2simg <raw_image_file> <sparse_image_file> [<block_size>]\n");
+ fprintf(stderr, "Usage: img2simg [-s] <raw_image_file> <sparse_image_file> [<block_size>]\n");
}
int main(int argc, char* argv[]) {
+ char *arg_in;
+ char *arg_out;
+ enum sparse_read_mode mode = SPARSE_READ_MODE_NORMAL;
+ int extra;
int in;
+ int opt;
int out;
int ret;
struct sparse_file* s;
unsigned int block_size = 4096;
off64_t len;
- if (argc < 3 || argc > 4) {
+ while ((opt = getopt(argc, argv, "s")) != -1) {
+ switch (opt) {
+ case 's':
+ mode = SPARSE_READ_MODE_HOLE;
+ break;
+ default:
+ usage();
+ exit(-1);
+ }
+ }
+
+ extra = argc - optind;
+ if (extra < 2 || extra > 3) {
usage();
exit(-1);
}
- if (argc == 4) {
- block_size = atoi(argv[3]);
+ if (extra == 3) {
+ block_size = atoi(argv[optind + 2]);
}
if (block_size < 1024 || block_size % 4 != 0) {
@@ -63,22 +80,24 @@
exit(-1);
}
- if (strcmp(argv[1], "-") == 0) {
+ arg_in = argv[optind];
+ if (strcmp(arg_in, "-") == 0) {
in = STDIN_FILENO;
} else {
- in = open(argv[1], O_RDONLY | O_BINARY);
+ in = open(arg_in, O_RDONLY | O_BINARY);
if (in < 0) {
- fprintf(stderr, "Cannot open input file %s\n", argv[1]);
+ fprintf(stderr, "Cannot open input file %s\n", arg_in);
exit(-1);
}
}
- if (strcmp(argv[2], "-") == 0) {
+ arg_out = argv[optind + 1];
+ if (strcmp(arg_out, "-") == 0) {
out = STDOUT_FILENO;
} else {
- out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
+ out = open(arg_out, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
if (out < 0) {
- fprintf(stderr, "Cannot open output file %s\n", argv[2]);
+ fprintf(stderr, "Cannot open output file %s\n", arg_out);
exit(-1);
}
}
@@ -93,7 +112,7 @@
}
sparse_file_verbose(s);
- ret = sparse_file_read(s, in, SPARSE_READ_MODE_NORMAL, false);
+ ret = sparse_file_read(s, in, mode, false);
if (ret) {
fprintf(stderr, "Failed to read file\n");
exit(-1);
diff --git a/libsparse/sparse_fuzzer.cpp b/libsparse/sparse_fuzzer.cpp
index 235d15d..663c812 100644
--- a/libsparse/sparse_fuzzer.cpp
+++ b/libsparse/sparse_fuzzer.cpp
@@ -23,5 +23,7 @@
if (!file) {
return 0;
}
- return sparse_file_callback(file, false, false, WriteCallback, nullptr);
+ int32_t result = sparse_file_callback(file, false, false, WriteCallback, nullptr);
+ sparse_file_destroy(file);
+ return result;
}
diff --git a/libsparse/sparse_read.cpp b/libsparse/sparse_read.cpp
index 028b6be..44f7557 100644
--- a/libsparse/sparse_read.cpp
+++ b/libsparse/sparse_read.cpp
@@ -670,7 +670,7 @@
int64_t len;
int ret;
- s = sparse_file_import(fd, verbose, crc);
+ s = sparse_file_import(fd, false, crc);
if (s) {
return s;
}
@@ -686,6 +686,9 @@
if (!s) {
return nullptr;
}
+ if (verbose) {
+ sparse_file_verbose(s);
+ }
ret = sparse_file_read_normal(s, fd);
if (ret < 0) {
diff --git a/libstats/socket_lazy/TEST_MAPPING b/libstats/socket_lazy/TEST_MAPPING
index b182660..03506cd 100644
--- a/libstats/socket_lazy/TEST_MAPPING
+++ b/libstats/socket_lazy/TEST_MAPPING
@@ -4,7 +4,7 @@
"name" : "libstatssocket_lazy_test"
}
],
- "hwasan-postsubmit" : [
+ "hwasan-presubmit" : [
{
"name" : "libstatssocket_lazy_test"
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 1b29285..f663671 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -44,14 +44,6 @@
export_include_dirs: ["include"],
target: {
- android: {
- header_libs: ["libbacktrace_headers"],
- export_header_lib_headers: ["libbacktrace_headers"],
- },
- host_linux: {
- header_libs: ["libbacktrace_headers"],
- export_header_lib_headers: ["libbacktrace_headers"],
- },
linux_bionic: {
enabled: true,
},
@@ -196,7 +188,7 @@
shared_libs: [
"libutils",
- "libbacktrace",
+ "libunwindstack",
],
target: {
diff --git a/libutils/CallStack.cpp b/libutils/CallStack.cpp
index fe6f33d..f19ba6a 100644
--- a/libutils/CallStack.cpp
+++ b/libutils/CallStack.cpp
@@ -20,7 +20,7 @@
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <backtrace/Backtrace.h>
+#include <unwindstack/AndroidUnwinder.h>
#define CALLSTACK_WEAK // Don't generate weak definitions.
#include <utils/CallStack.h>
@@ -39,14 +39,25 @@
}
void CallStack::update(int32_t ignoreDepth, pid_t tid) {
+ if (ignoreDepth < 0) {
+ ignoreDepth = 0;
+ }
+
mFrameLines.clear();
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
- if (!backtrace->Unwind(ignoreDepth)) {
- ALOGW("%s: Failed to unwind callstack.", __FUNCTION__);
+ unwindstack::AndroidLocalUnwinder unwinder;
+ unwindstack::AndroidUnwinderData data;
+ std::optional<pid_t> tid_val;
+ if (tid != -1) {
+ *tid_val = tid;
}
- for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- mFrameLines.push_back(String8(backtrace->FormatFrameData(i).c_str()));
+ if (!unwinder.Unwind(tid_val, data)) {
+ ALOGW("%s: Failed to unwind callstack: %s", __FUNCTION__, data.GetErrorString().c_str());
+ }
+ for (size_t i = ignoreDepth; i < data.frames.size(); i++) {
+ auto& frame = data.frames[i];
+ frame.num -= ignoreDepth;
+ mFrameLines.push_back(String8(unwinder.FormatFrame(frame).c_str()));
}
}
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index c97a19b..d951b8b 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -279,14 +279,12 @@
ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
{
- ALOG_ASSERT((index+count)<=size(),
- "[%p] remove: index=%d, count=%d, size=%d",
- this, (int)index, (int)count, (int)size());
-
- if ((index+count) > size())
- return BAD_VALUE;
- _shrink(index, count);
- return index;
+ size_t end;
+ LOG_ALWAYS_FATAL_IF(__builtin_add_overflow(index, count, &end), "overflow: index=%zu count=%zu",
+ index, count);
+ if (end > size()) return BAD_VALUE;
+ _shrink(index, count);
+ return index;
}
void VectorImpl::finish_vector()
diff --git a/libutils/Vector_test.cpp b/libutils/Vector_test.cpp
index 5336c40..6d90eaa 100644
--- a/libutils/Vector_test.cpp
+++ b/libutils/Vector_test.cpp
@@ -136,4 +136,13 @@
}
}
+TEST_F(VectorTest, removeItemsAt_overflow) {
+ android::Vector<int> v;
+ for (int i = 0; i < 666; i++) v.add(i);
+
+ ASSERT_DEATH(v.removeItemsAt(SIZE_MAX, 666), "overflow");
+ ASSERT_DEATH(v.removeItemsAt(666, SIZE_MAX), "overflow");
+ ASSERT_DEATH(v.removeItemsAt(SIZE_MAX, SIZE_MAX), "overflow");
+}
+
} // namespace android
diff --git a/libutils/include/utils/CallStack.h b/libutils/include/utils/CallStack.h
index 7a4a345..fe4d4f5 100644
--- a/libutils/include/utils/CallStack.h
+++ b/libutils/include/utils/CallStack.h
@@ -20,7 +20,6 @@
#include <memory>
#include <android/log.h>
-#include <backtrace/backtrace_constants.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -59,7 +58,7 @@
// Immediately collect the stack traces for the specified thread.
// The default is to dump the stack of the current call.
- void update(int32_t ignoreDepth = 1, pid_t tid = BACKTRACE_CURRENT_THREAD);
+ void update(int32_t ignoreDepth = 1, pid_t tid = -1);
// Dump a stack trace to the log using the supplied logtag.
void log(const char* logtag,
diff --git a/libutils/include/utils/Thread.h b/libutils/include/utils/Thread.h
index fc67656..5cf6b47 100644
--- a/libutils/include/utils/Thread.h
+++ b/libutils/include/utils/Thread.h
@@ -42,7 +42,9 @@
{
public:
// Create a Thread object, but doesn't create or start the associated
- // thread. See the run() method.
+ // thread. See the run() method. This object must be used with RefBase/sp,
+ // like any other RefBase object, because they are conventionally promoted
+ // from bare pointers (Thread::run is particularly problematic here).
explicit Thread(bool canCallJava = true);
virtual ~Thread();
diff --git a/property_service/TEST_MAPPING b/property_service/TEST_MAPPING
index 20f6c84..7b02b51 100644
--- a/property_service/TEST_MAPPING
+++ b/property_service/TEST_MAPPING
@@ -4,7 +4,7 @@
"name": "propertyinfoserializer_tests"
}
],
- "hwasan-postsubmit": [
+ "hwasan-presubmit": [
{
"name": "propertyinfoserializer_tests"
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index aae28dc..70a3736 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -86,6 +86,10 @@
mkdir /dev/sys/fs 0755 system system
mkdir /dev/sys/block 0755 system system
+ # Create location for fs_mgr to store abbreviated output from filesystem
+ # checker programs.
+ mkdir /dev/fscklogs 0770 root system
+
# Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610
on early-init && property:ro.product.cpu.abilist32=*
exec_start boringssl_self_test32
@@ -97,22 +101,18 @@
exec_start boringssl_self_test_apex64
service boringssl_self_test32 /system/bin/boringssl_self_test32
- setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
service boringssl_self_test64 /system/bin/boringssl_self_test64
- setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32
- setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64
- setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
reboot_on_failure reboot,boringssl-self-check-failed
stdio_to_kmsg
@@ -447,10 +447,6 @@
mount bpf bpf /sys/fs/bpf nodev noexec nosuid
- # Create location for fs_mgr to store abbreviated output from filesystem
- # checker programs.
- mkdir /dev/fscklogs 0770 root system
-
# pstore/ramoops previous console log
mount pstore pstore /sys/fs/pstore nodev noexec nosuid
chown system log /sys/fs/pstore
@@ -538,6 +534,10 @@
# /data, which in turn can only be loaded when system properties are present.
trigger post-fs-data
+ # APEXes are ready to use. apex-ready is a public trigger similar to apexd.status=ready which
+ # is a system-private property.
+ trigger apex-ready
+
# Should be before netd, but after apex, properties and logging is available.
trigger load_bpf_programs
@@ -688,8 +688,6 @@
copy /data/system/entropy.dat /dev/urandom
mkdir /data/vendor 0771 root root encryption=Require
- mkdir /data/vendor_ce 0771 root root encryption=None
- mkdir /data/vendor_de 0771 root root encryption=None
mkdir /data/vendor/hardware 0771 root root
# Start tombstoned early to be able to store tombstones.
@@ -738,6 +736,13 @@
# To handle userspace reboots as well as devices that use FDE, make sure
# that apexd is started cleanly here (set apexd.status="") and that it is
# restarted if it's already running.
+ #
+ # /data/apex uses encryption=None because direct I/O support is needed on
+ # APEX files, but some devices don't support direct I/O on encrypted files.
+ # Also, APEXes are public information, similar to the system image.
+ # /data/apex/decompressed and /data/apex/ota_reserved override this setting;
+ # they are encrypted so that files in them can be hard-linked into
+ # /data/rollback which is encrypted.
mkdir /data/apex 0755 root system encryption=None
mkdir /data/apex/active 0755 root system
mkdir /data/apex/backup 0700 root system
@@ -828,19 +833,20 @@
# directory used for odsign metrics
mkdir /data/misc/odsign/metrics 0770 root system
- # Directory for VirtualizationService temporary image files. Always create
- # a fresh new empty directory to remove any stale files from the previous
- # boot.
- rmdir /data/misc/virtualizationservice
- mkdir /data/misc/virtualizationservice 0700 system system
+ # Directory for VirtualizationService temporary image files.
+ # Delete any stale files owned by the old virtualizationservice uid (b/230056726).
+ chmod 0770 /data/misc/virtualizationservice
+ exec - virtualizationservice system -- /bin/rm -rf /data/misc/virtualizationservice
+ mkdir /data/misc/virtualizationservice 0770 system system
+ # /data/preloads uses encryption=None because it only contains preloaded
+ # files that are public information, similar to the system image.
mkdir /data/preloads 0775 system system encryption=None
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
mkdir /data/local/tmp 0771 shell shell
mkdir /data/local/traces 0777 shell shell
- mkdir /data/data 0771 system system encryption=None
mkdir /data/app-private 0771 system system encryption=Require
mkdir /data/app-ephemeral 0771 system system encryption=Require
mkdir /data/app-asec 0700 root root encryption=Require
@@ -878,7 +884,10 @@
chown system system /data/resource-cache
chmod 0771 /data/resource-cache
- # create the lost+found directories, so as to enforce our permissions
+ # Ensure that lost+found exists and has the correct permissions. Linux
+ # filesystems expect this directory to exist; it's where the fsck tool puts
+ # any recovered files that weren't present in any directory. It must be
+ # unencrypted, as fsck must be able to write to it.
mkdir /data/lost+found 0770 root root encryption=None
# create directory for DRM plug-ins - give drm the read/write access to
@@ -906,21 +915,26 @@
mkdir /data/system/heapdump 0700 system system
mkdir /data/system/users 0775 system system
- mkdir /data/system_de 0770 system system encryption=None
- mkdir /data/system_ce 0770 system system encryption=None
-
- mkdir /data/misc_de 01771 system misc encryption=None
+ # Create the parent directories of the user CE and DE storage directories.
+ # These parent directories must use encryption=None, since each of their
+ # subdirectories uses a different encryption policy (a per-user one), and
+ # encryption policies apply recursively. These directories should never
+ # contain any subdirectories other than the per-user ones. /data/media/obb
+ # is an exception that exists for legacy reasons.
+ mkdir /data/media 0770 media_rw media_rw encryption=None
mkdir /data/misc_ce 01771 system misc encryption=None
-
+ mkdir /data/misc_de 01771 system misc encryption=None
+ mkdir /data/system_ce 0770 system system encryption=None
+ mkdir /data/system_de 0770 system system encryption=None
mkdir /data/user 0711 system system encryption=None
mkdir /data/user_de 0711 system system encryption=None
+ mkdir /data/vendor_ce 0771 root root encryption=None
+ mkdir /data/vendor_de 0771 root root encryption=None
- # Unlink /data/user/0 if we previously symlink it to /data/data
- rm /data/user/0
-
- # Bind mount /data/user/0 to /data/data
- mkdir /data/user/0 0700 system system encryption=None
- mount none /data/data /data/user/0 bind rec
+ # Set the casefold flag on /data/media. For upgrades, a restorecon can be
+ # needed first to relabel the directory from media_rw_data_file.
+ restorecon /data/media
+ exec - media_rw media_rw -- /system/bin/chattr +F /data/media
# A tmpfs directory, which will contain all apps CE DE data directory that
# bind mount from the original source.
@@ -933,8 +947,10 @@
mkdir /data_mirror/data_ce/null 0700 root root
mkdir /data_mirror/data_de/null 0700 root root
- # Bind mount CE and DE data directory to mirror's default volume directory
- mount none /data/user /data_mirror/data_ce/null bind rec
+ # Bind mount CE and DE data directory to mirror's default volume directory.
+ # The 'slave' option (MS_SLAVE) is needed to cause the later bind mount of
+ # /data/data onto /data/user/0 to propagate to /data_mirror/data_ce/null/0.
+ mount none /data/user /data_mirror/data_ce/null bind rec slave
mount none /data/user_de /data_mirror/data_de/null bind rec
# Create mirror directory for jit profiles
@@ -967,13 +983,8 @@
wait_for_prop apexd.status activated
perform_apex_config
- # 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
- mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
-
# Create directories for boot animation.
- mkdir /data/bootanim 0755 system system encryption=None
+ mkdir /data/bootanim 0755 system system encryption=DeleteIfNecessary
exec_start derive_sdk
@@ -1099,6 +1110,9 @@
write /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time 50
write /dev/sys/fs/by-name/userdata/iostat_enable 1
+ # set readahead multiplier for POSIX_FADV_SEQUENTIAL files
+ write /dev/sys/fs/by-name/userdata/seq_file_ra_mul 16
+
# limit discard size to 128MB in order to avoid long IO latency
# for filesystem tuning first (dm or sda)
# this requires enabling selinux entry for sda/mmcblk0 in vendor side
@@ -1132,10 +1146,6 @@
chown system system /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/io_is_busy
- # Assume SMP uses shared cpufreq policy for all CPUs
- chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
- chmod 0660 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
-
chown system system /sys/class/leds/vibrator/trigger
chown system system /sys/class/leds/vibrator/activate
chown system system /sys/class/leds/vibrator/brightness
@@ -1303,6 +1313,7 @@
on userspace-reboot-resume
trigger userspace-reboot-fs-remount
trigger post-fs-data
+ trigger apex-ready
trigger zygote-start
trigger early-boot
trigger boot
diff --git a/set-verity-state/Android.bp b/set-verity-state/Android.bp
index 2f0cb10..f0df350 100644
--- a/set-verity-state/Android.bp
+++ b/set-verity-state/Android.bp
@@ -22,6 +22,17 @@
],
cflags: ["-Werror"],
+ cppflags: [
+ "-DALLOW_DISABLE_VERITY=0",
+ ],
+ product_variables: {
+ debuggable: {
+ cppflags: [
+ "-UALLOW_DISABLE_VERITY",
+ "-DALLOW_DISABLE_VERITY=1",
+ ],
+ },
+ },
symlinks: [
"enable-verity",
"disable-verity",
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 8cc8b59..cefef6e 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -333,7 +333,7 @@
first_write = false;
}
- if (benchmark_size) {
+ if (benchmark_size && benchmark_time_ns) {
int perf = benchmark_size * 1000000LLU / benchmark_time_ns;
storage_info->update_perf_history(perf, system_clock::now());
}
diff --git a/trusty/keymaster/keymint/TEST_MAPPING b/trusty/keymaster/keymint/TEST_MAPPING
index ae24fb4..6671355 100644
--- a/trusty/keymaster/keymint/TEST_MAPPING
+++ b/trusty/keymaster/keymint/TEST_MAPPING
@@ -4,7 +4,7 @@
"name" : "vts_treble_vintf_framework_test"
}
],
- "hwasan-postsubmit" : [
+ "hwasan-presubmit" : [
{
"name" : "vts_treble_vintf_framework_test"
}
diff --git a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
index 9440724..78e765e 100644
--- a/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
+++ b/trusty/keymaster/keymint/TrustyKeyMintOperation.cpp
@@ -52,11 +52,15 @@
}
ScopedAStatus TrustyKeyMintOperation::updateAad(
- const vector<uint8_t>& input, const optional<HardwareAuthToken>& /* authToken */,
+ const vector<uint8_t>& input, const optional<HardwareAuthToken>& authToken,
const optional<TimeStampToken>& /* timestampToken */) {
UpdateOperationRequest request(impl_->message_version());
request.op_handle = opHandle_;
request.additional_params.push_back(TAG_ASSOCIATED_DATA, input.data(), input.size());
+ if (authToken) {
+ auto tokenAsVec(authToken2AidlVec(*authToken));
+ request.additional_params.push_back(TAG_AUTH_TOKEN, tokenAsVec.data(), tokenAsVec.size());
+ }
UpdateOperationResponse response(impl_->message_version());
impl_->UpdateOperation(request, &response);
diff --git a/trusty/utils/acvp/acvp_ipc.h b/trusty/utils/acvp/acvp_ipc.h
index 8b48ae3..300e05a 100644
--- a/trusty/utils/acvp/acvp_ipc.h
+++ b/trusty/utils/acvp/acvp_ipc.h
@@ -27,7 +27,7 @@
/*
* Maximum number of arguments
*/
-#define ACVP_MAX_NUM_ARGUMENTS 8
+#define ACVP_MAX_NUM_ARGUMENTS 9
/*
* Maximum length of an algorithm name