Merge "Chmod for existing nodes which mode not the same as ueventd.rc"
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 5a9d4f2..ed90ab4 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -113,8 +113,14 @@
// Enable GWP-ASan at the start of this process. GWP-ASan is enabled using
// process sampling, so we need to ensure we force GWP-ASan on.
__attribute__((constructor)) static void enable_gwp_asan() {
- bool force = true;
- android_mallopt(M_INITIALIZE_GWP_ASAN, &force, sizeof(force));
+ android_mallopt_gwp_asan_options_t opts;
+ // No, we're not an app, but let's turn ourselves on without sampling.
+ // Technically, if someone's using the *.default_app sysprops, they'll adjust
+ // our settings, but I don't think this will be common on a device that's
+ // running debuggerd_tests.
+ opts.desire = android_mallopt_gwp_asan_options_t::Action::TURN_ON_FOR_APP;
+ opts.program_name = "";
+ android_mallopt(M_INITIALIZE_GWP_ASAN, &opts, sizeof(android_mallopt_gwp_asan_options_t));
}
static void tombstoned_intercept(pid_t target_pid, unique_fd* intercept_fd, unique_fd* output_fd,
@@ -1457,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;
@@ -1487,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 4c1f9eb..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"
@@ -73,14 +70,13 @@
thread.registers.reset(
unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
- // TODO: Create this once and store it in a global?
- unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
// 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());
- unwinder.SetProcessMemory(process_memory);
+ // TODO: Create this once and store it in a global?
+ unwindstack::AndroidLocalUnwinder unwinder(process_memory);
dump_backtrace_thread(output_fd, &unwinder, thread);
}
__linker_disable_fallback_allocator();
@@ -214,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 b2077ba..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"
@@ -43,10 +42,13 @@
static const gwp_asan::AllocationMetadata* retrieve_gwp_asan_metadata(
unwindstack::Memory* process_memory, const gwp_asan::AllocatorState& state,
uintptr_t metadata_addr) {
- if (state.MaxSimultaneousAllocations > 1024) {
+ // 1 million GWP-ASan slots would take 4.1GiB of space. Thankfully, copying
+ // the metadata for that amount of slots is only 532MiB, and this really will
+ // only be used with some ridiculous torture-tests.
+ if (state.MaxSimultaneousAllocations > 1000000) {
ALOGE(
"Error when retrieving GWP-ASan metadata, MSA from state (%zu) "
- "exceeds maximum allowed (1024).",
+ "exceeds maximum allowed (1,000,000).",
state.MaxSimultaneousAllocations);
return nullptr;
}
@@ -103,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;
@@ -137,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 14caaf6..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));
}
- unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
- auto process_memory =
- unwindstack::Memory::CreateProcessMemoryCached(getpid());
- unwinder.SetProcessMemory(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/fastboot.bash b/fastboot/fastboot.bash
index e9bf9e9..911071a 100644
--- a/fastboot/fastboot.bash
+++ b/fastboot/fastboot.bash
@@ -109,7 +109,7 @@
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ $i -eq $COMP_CWORD ]]; then
- partitions="boot bootloader dtbo init_boot modem odm odm_dlkm oem product pvmfw radio recovery system system_dlkm vbmeta vendor vendor_dlkm"
+ partitions="boot bootloader dtbo init_boot modem odm odm_dlkm oem product pvmfw radio recovery system system_dlkm vbmeta vendor vendor_dlkm vendor_kernel_boot"
COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
else
_fastboot_util_complete_local_file "${cur}" '!*.img'
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 39d86f9..79c3ac7 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -186,6 +186,11 @@
"vendor_dlkm.img", "vendor_dlkm.sig",
"vendor_dlkm",
true, ImageType::Normal },
+ { "vendor_kernel_boot",
+ "vendor_kernel_boot.img",
+ "vendor_kernel_boot.sig",
+ "vendor_kernel_boot",
+ true, ImageType::BootCritical },
{ nullptr, "vendor_other.img", "vendor.sig", "vendor", true, ImageType::Normal },
// clang-format on
};
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/fastboot/vendor_boot_img_utils.cpp b/fastboot/vendor_boot_img_utils.cpp
index 9e09abb..9f05253 100644
--- a/fastboot/vendor_boot_img_utils.cpp
+++ b/fastboot/vendor_boot_img_utils.cpp
@@ -152,6 +152,9 @@
if (memcmp(hdr->magic, VENDOR_BOOT_MAGIC, VENDOR_BOOT_MAGIC_SIZE) != 0) {
return Errorf("Vendor boot image magic mismatch");
}
+ if (hdr->page_size == 0) {
+ return Errorf("Page size cannot be zero");
+ }
if (hdr->header_version < version) {
return Errorf("Require vendor boot header V{} but is V{}", version, hdr->header_version);
}
@@ -199,6 +202,7 @@
}
// round |value| up to a multiple of |page_size|.
+// aware that this can be integer overflow if value is too large
inline uint32_t round_up(uint32_t value, uint32_t page_size) {
return (value + page_size - 1) / page_size * page_size;
}
@@ -311,7 +315,13 @@
const uint32_t r = round_up(hdr->vendor_ramdisk_table_size, hdr->page_size);
const uint32_t s = round_up(hdr->bootconfig_size, hdr->page_size);
- if (hdr->vendor_ramdisk_table_entry_num == std::numeric_limits<uint32_t>::max()) {
+ uint64_t total_size = (uint64_t)o + p + q + r + s;
+ if (total_size > vendor_boot.size()) {
+ return Errorf("Vendor boot image size is too small, overflow");
+ }
+
+ if ((uint64_t)hdr->vendor_ramdisk_table_entry_num * sizeof(vendor_ramdisk_table_entry_v4) >
+ (uint64_t)o + p + q + r) {
return Errorf("Too many vendor ramdisk entries in table, overflow");
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6863894..c12a672 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;
}
@@ -1474,7 +1485,7 @@
if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.blk_device,
attempted_entry.mount_point, wiped ? "true" : "false",
- attempted_entry.fs_type},
+ attempted_entry.fs_type, attempted_entry.zoned_device},
nullptr)) {
LERROR << "Encryption failed";
set_type_property(encryptable);
@@ -1514,7 +1525,7 @@
if (!call_vdc({"cryptfs", "encryptFstab", current_entry.blk_device,
current_entry.mount_point, "true" /* shouldFormat */,
- current_entry.fs_type},
+ current_entry.fs_type, current_entry.zoned_device},
nullptr)) {
LERROR << "Encryption failed";
} else {
@@ -1539,7 +1550,7 @@
if (mount_errno != EBUSY && mount_errno != EACCES &&
should_use_metadata_encryption(attempted_entry)) {
if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.blk_device,
- attempted_entry.mount_point},
+ attempted_entry.mount_point, attempted_entry.zoned_device},
nullptr)) {
++error_count;
} else if (current_entry.mount_point == "/data") {
@@ -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/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 6f59ed3..7385f79 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -117,7 +117,7 @@
}
static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs_projid,
- bool needs_casefold, bool fs_compress) {
+ bool needs_casefold, bool fs_compress, const std::string& zoned_device) {
if (!dev_sz) {
int rc = get_dev_sz(fs_blkdev, &dev_sz);
if (rc) {
@@ -146,8 +146,15 @@
args.push_back("-O");
args.push_back("extra_attr");
}
- args.push_back(fs_blkdev.c_str());
- args.push_back(size_str.c_str());
+ if (!zoned_device.empty()) {
+ args.push_back("-c");
+ args.push_back(zoned_device.c_str());
+ args.push_back("-m");
+ args.push_back(fs_blkdev.c_str());
+ } else {
+ args.push_back(fs_blkdev.c_str());
+ args.push_back(size_str.c_str());
+ }
return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, false, nullptr);
}
@@ -164,7 +171,7 @@
if (entry.fs_type == "f2fs") {
return format_f2fs(entry.blk_device, entry.length, needs_projid, needs_casefold,
- entry.fs_mgr_flags.fs_compress);
+ entry.fs_mgr_flags.fs_compress, entry.zoned_device);
} else if (entry.fs_type == "ext4") {
return format_ext4(entry.blk_device, entry.mount_point, needs_projid,
entry.fs_mgr_flags.ext_meta_csum);
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 8c719c8..06368b8 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -304,6 +304,14 @@
if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
}
+ } else if (StartsWith(flag, "zoned_device=")) {
+ std::string zoned;
+ if (ReadFileToString("/sys/class/block/" + arg + "/queue/zoned", &zoned) &&
+ android::base::StartsWith(zoned, "host-managed")) {
+ entry->zoned_device = "/dev/block/" + arg;
+ } else {
+ LWARNING << "Warning: cannot find the zoned device: " << arg;
+ }
} else {
LWARNING << "Warning: unknown flag: " << flag;
}
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index f26fb24..8f200a8 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -31,6 +31,7 @@
struct FstabEntry {
std::string blk_device;
+ std::string zoned_device;
std::string logical_partition_name;
std::string mount_point;
std::string fs_type;
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/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 72827eb..1759cf9 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <android-base/properties.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
@@ -31,6 +32,7 @@
using ::testing::ElementsAre;
using ::testing::NiceMock;
using ::testing::Return;
+using android::base::GetProperty;
class Environment : public ::testing::Environment {
public:
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index e67fb33..d123304 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -20,7 +20,10 @@
#include <sys/syscall.h>
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/unique_fd.h>
+#include <fs_mgr.h>
+#include <fstab/fstab.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
@@ -38,6 +41,7 @@
using ::testing::_;
using ::testing::Return;
using unique_fd = android::base::unique_fd;
+using android::base::GetProperty;
// Our tests assume a 128KiB disk with two 512 byte metadata slots.
static const size_t kDiskSize = 131072;
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..57c599c 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -47,6 +47,7 @@
"libbase",
"liblog",
],
+ export_include_dirs: ["include"],
ramdisk_available: true,
}
@@ -68,11 +69,12 @@
"user-space-merge/snapuserd_readahead.cpp",
"user-space-merge/snapuserd_transitions.cpp",
"user-space-merge/snapuserd_server.cpp",
+ "user-space-merge/snapuserd_verify.cpp",
],
cflags: [
"-Wall",
- "-Werror"
+ "-Werror",
],
static_libs: [
@@ -88,16 +90,14 @@
"libext4_utils",
"liburing",
],
- include_dirs: ["bionic/libc/kernel"],
-}
-cc_binary {
- name: "snapuserd",
- defaults: ["snapuserd_defaults"],
- init_rc: [
- "snapuserd.rc",
+ header_libs: [
+ "libstorage_literals_headers",
],
+ include_dirs: ["bionic/libc/kernel"],
+ 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
// module. dm-user routes all I/O to userspace to be handled by
@@ -105,16 +105,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/include/snapuserd/snapuserd_client.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h
index cebda1c..9a69d58 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_client.h
@@ -89,6 +89,10 @@
// Return the status of the snapshot
std::string QuerySnapshotStatus(const std::string& misc_name);
+
+ // Check the update verification status - invoked by update_verifier during
+ // boot
+ bool QueryUpdateVerification();
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
index 7b1c7a3..e08cf9b 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp
@@ -269,5 +269,15 @@
return Receivemsg();
}
+bool SnapuserdClient::QueryUpdateVerification() {
+ std::string msg = "update-verify";
+ if (!Sendmsg(msg)) {
+ LOG(ERROR) << "Failed to send message " << msg << " to snapuserd";
+ return false;
+ }
+ std::string response = Receivemsg();
+ return response == "success";
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 692cb74..afc653f 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -18,6 +18,7 @@
#include <sys/utsname.h>
+#include <android-base/chrono_utils.h>
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/strings.h>
@@ -70,6 +71,9 @@
read_ahead_thread_ = std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_,
GetSharedPtr());
+
+ update_verify_ = std::make_unique<UpdateVerify>(misc_name_);
+
return true;
}
@@ -306,206 +310,6 @@
return ReadMetadata();
}
-void SnapshotHandler::FinalizeIouring() {
- io_uring_queue_exit(ring_.get());
-}
-
-bool SnapshotHandler::InitializeIouring(int io_depth) {
- ring_ = std::make_unique<struct io_uring>();
-
- int ret = io_uring_queue_init(io_depth, ring_.get(), 0);
- if (ret) {
- LOG(ERROR) << "io_uring_queue_init failed with ret: " << ret;
- return false;
- }
-
- LOG(INFO) << "io_uring_queue_init success with io_depth: " << io_depth;
- return true;
-}
-
-bool SnapshotHandler::ReadBlocksAsync(const std::string& dm_block_device,
- const std::string& partition_name, size_t size) {
- // 64k block size with io_depth of 64 is optimal
- // for a single thread. We just need a single thread
- // to read all the blocks from all dynamic partitions.
- size_t io_depth = 64;
- size_t bs = (64 * 1024);
-
- if (!InitializeIouring(io_depth)) {
- return false;
- }
-
- LOG(INFO) << "ReadBlockAsync start "
- << " Block-device: " << dm_block_device << " Partition-name: " << partition_name
- << " Size: " << size;
-
- auto scope_guard = android::base::make_scope_guard([this]() -> void { FinalizeIouring(); });
-
- std::vector<std::unique_ptr<struct iovec>> vecs;
- using AlignedBuf = std::unique_ptr<void, decltype(free)*>;
- std::vector<AlignedBuf> alignedBufVector;
-
- /*
- * TODO: We need aligned memory for DIRECT-IO. However, if we do
- * a DIRECT-IO and verify the blocks then we need to inform
- * update-verifier that block verification has been done and
- * there is no need to repeat the same. We are not there yet
- * as we need to see if there are any boot time improvements doing
- * a DIRECT-IO.
- *
- * Also, we could you the same function post merge for block verification;
- * again, we can do a DIRECT-IO instead of thrashing page-cache and
- * hurting other applications.
- *
- * For now, we will just create aligned buffers but rely on buffered
- * I/O until we have perf numbers to justify DIRECT-IO.
- */
- for (int i = 0; i < io_depth; i++) {
- auto iovec = std::make_unique<struct iovec>();
- vecs.push_back(std::move(iovec));
-
- struct iovec* iovec_ptr = vecs[i].get();
-
- if (posix_memalign(&iovec_ptr->iov_base, BLOCK_SZ, bs)) {
- LOG(ERROR) << "posix_memalign failed";
- return false;
- }
-
- iovec_ptr->iov_len = bs;
- alignedBufVector.push_back(
- std::unique_ptr<void, decltype(free)*>(iovec_ptr->iov_base, free));
- }
-
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
- if (fd.get() == -1) {
- SNAP_PLOG(ERROR) << "File open failed - block-device " << dm_block_device
- << " partition-name: " << partition_name;
- return false;
- }
-
- loff_t offset = 0;
- size_t remain = size;
- size_t read_sz = io_depth * bs;
-
- while (remain > 0) {
- size_t to_read = std::min(remain, read_sz);
- size_t queue_size = to_read / bs;
-
- for (int i = 0; i < queue_size; i++) {
- struct io_uring_sqe* sqe = io_uring_get_sqe(ring_.get());
- if (!sqe) {
- SNAP_LOG(ERROR) << "io_uring_get_sqe() failed";
- return false;
- }
-
- struct iovec* iovec_ptr = vecs[i].get();
-
- io_uring_prep_read(sqe, fd.get(), iovec_ptr->iov_base, iovec_ptr->iov_len, offset);
- sqe->flags |= IOSQE_ASYNC;
- offset += bs;
- }
-
- int ret = io_uring_submit(ring_.get());
- if (ret != queue_size) {
- SNAP_LOG(ERROR) << "submit got: " << ret << " wanted: " << queue_size;
- return false;
- }
-
- for (int i = 0; i < queue_size; i++) {
- struct io_uring_cqe* cqe;
-
- int ret = io_uring_wait_cqe(ring_.get(), &cqe);
- if (ret) {
- SNAP_PLOG(ERROR) << "wait_cqe failed" << ret;
- return false;
- }
-
- if (cqe->res < 0) {
- SNAP_LOG(ERROR) << "io failed with res: " << cqe->res;
- return false;
- }
- io_uring_cqe_seen(ring_.get(), cqe);
- }
-
- remain -= to_read;
- }
-
- LOG(INFO) << "ReadBlockAsync complete: "
- << " Block-device: " << dm_block_device << " Partition-name: " << partition_name
- << " Size: " << size;
- return true;
-}
-
-void SnapshotHandler::ReadBlocksToCache(const std::string& dm_block_device,
- const std::string& partition_name, off_t offset,
- size_t size) {
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
- if (fd.get() == -1) {
- SNAP_PLOG(ERROR) << "Error reading " << dm_block_device
- << " partition-name: " << partition_name;
- return;
- }
-
- size_t remain = size;
- off_t file_offset = offset;
- // We pick 4M I/O size based on the fact that the current
- // update_verifier has a similar I/O size.
- size_t read_sz = 1024 * BLOCK_SZ;
- std::vector<uint8_t> buf(read_sz);
-
- while (remain > 0) {
- size_t to_read = std::min(remain, read_sz);
-
- if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) {
- SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device
- << " at offset: " << file_offset
- << " partition-name: " << partition_name << " total-size: " << size
- << " remain_size: " << remain;
- return;
- }
-
- file_offset += to_read;
- remain -= to_read;
- }
-
- SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device
- << " partition: " << partition_name << " size: " << size
- << " offset: " << offset;
-}
-
-void SnapshotHandler::ReadBlocks(const std::string partition_name,
- const std::string& dm_block_device) {
- SNAP_LOG(DEBUG) << "Reading partition: " << partition_name
- << " Block-Device: " << dm_block_device;
-
- uint64_t dev_sz = 0;
-
- unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd < 0) {
- SNAP_LOG(ERROR) << "Cannot open block device";
- return;
- }
-
- dev_sz = get_block_device_size(fd.get());
- if (!dev_sz) {
- SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device;
- return;
- }
-
- int num_threads = 2;
- size_t num_blocks = dev_sz >> BLOCK_SHIFT;
- size_t num_blocks_per_thread = num_blocks / num_threads;
- size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT;
- off_t offset = 0;
-
- for (int i = 0; i < num_threads; i++) {
- std::async(std::launch::async, &SnapshotHandler::ReadBlocksToCache, this, dm_block_device,
- partition_name, offset, read_sz_per_thread);
-
- offset += read_sz_per_thread;
- }
-}
-
/*
* Entry point to launch threads
*/
@@ -526,42 +330,22 @@
std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get()));
}
- bool second_stage_init = true;
+ bool partition_verification = true;
- // We don't want to read the blocks during first stage init.
+ // We don't want to read the blocks during first stage init or
+ // during post-install phase.
if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) {
- second_stage_init = false;
- }
-
- if (second_stage_init) {
- SNAP_LOG(INFO) << "Reading blocks to cache....";
- auto& dm = DeviceMapper::Instance();
- auto dm_block_devices = dm.FindDmPartitions();
- if (dm_block_devices.empty()) {
- SNAP_LOG(ERROR) << "No dm-enabled block device is found.";
- } else {
- auto parts = android::base::Split(misc_name_, "-");
- std::string partition_name = parts[0];
-
- const char* suffix_b = "_b";
- const char* suffix_a = "_a";
-
- partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1);
- partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1);
-
- if (dm_block_devices.find(partition_name) == dm_block_devices.end()) {
- SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name;
- } else {
- ReadBlocks(partition_name, dm_block_devices.at(partition_name));
- }
- }
- } else {
- SNAP_LOG(INFO) << "Not reading block device into cache";
+ partition_verification = false;
}
std::future<bool> merge_thread =
std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get());
+ // Now that the worker threads are up, scan the partitions.
+ if (partition_verification) {
+ update_verify_->VerifyUpdatePartition();
+ }
+
bool ret = true;
for (auto& t : threads) {
ret = t.get() && ret;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
index 83d40f6..90fba75 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -42,12 +42,14 @@
#include <liburing.h>
#include <snapuserd/snapuserd_buffer.h>
#include <snapuserd/snapuserd_kernel.h>
+#include <storage_literals/storage_literals.h>
namespace android {
namespace snapshot {
using android::base::unique_fd;
using namespace std::chrono_literals;
+using namespace android::storage_literals;
static constexpr size_t PAYLOAD_BUFFER_SZ = (1UL << 20);
static_assert(PAYLOAD_BUFFER_SZ >= BLOCK_SZ);
@@ -165,6 +167,36 @@
std::unique_ptr<struct io_uring> ring_;
};
+class UpdateVerify {
+ public:
+ UpdateVerify(const std::string& misc_name);
+ void VerifyUpdatePartition();
+ bool CheckPartitionVerification();
+
+ private:
+ enum class UpdateVerifyState {
+ VERIFY_UNKNOWN,
+ VERIFY_FAILED,
+ VERIFY_SUCCESS,
+ };
+
+ std::string misc_name_;
+ UpdateVerifyState state_;
+ std::mutex m_lock_;
+ std::condition_variable m_cv_;
+
+ int kMinThreadsToVerify = 1;
+ int kMaxThreadsToVerify = 4;
+ uint64_t kThresholdSize = 512_MiB;
+ uint64_t kBlockSizeVerify = 1_MiB;
+
+ bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
+ void UpdatePartitionVerificationState(UpdateVerifyState state);
+ bool VerifyPartition(const std::string& partition_name, const std::string& dm_block_device);
+ bool VerifyBlocks(const std::string& partition_name, const std::string& dm_block_device,
+ off_t offset, int skip_blocks, uint64_t dev_sz);
+};
+
class Worker {
public:
Worker(const std::string& cow_device, const std::string& backing_device,
@@ -344,24 +376,16 @@
MERGE_GROUP_STATE ProcessMergingBlock(uint64_t new_block, void* buffer);
bool IsIouringSupported();
+ bool CheckPartitionVerification() { return update_verify_->CheckPartitionVerification(); }
private:
bool ReadMetadata();
sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; }
- bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
+ bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
struct BufferState* GetBufferState();
void UpdateMergeCompletionPercentage();
- void ReadBlocks(const std::string partition_name, const std::string& dm_block_device);
- void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name,
- off_t offset, size_t size);
-
- bool InitializeIouring(int io_depth);
- void FinalizeIouring();
- bool ReadBlocksAsync(const std::string& dm_block_device, const std::string& partition_name,
- size_t size);
-
// COW device
std::string cow_device_;
// Source device
@@ -413,6 +437,7 @@
bool scratch_space_ = false;
std::unique_ptr<struct io_uring> ring_;
+ std::unique_ptr<UpdateVerify> update_verify_;
};
} // namespace snapshot
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..b7f7f54 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -55,6 +55,7 @@
if (input == "initiate_merge") return DaemonOps::INITIATE;
if (input == "merge_percent") return DaemonOps::PERCENTAGE;
if (input == "getstatus") return DaemonOps::GETSTATUS;
+ if (input == "update-verify") return DaemonOps::UPDATE_VERIFY;
return DaemonOps::INVALID;
}
@@ -282,6 +283,14 @@
return Sendmsg(fd, merge_status);
}
}
+ case DaemonOps::UPDATE_VERIFY: {
+ std::lock_guard<std::mutex> lock(lock_);
+ if (!UpdateVerification(&lock)) {
+ return Sendmsg(fd, "fail");
+ }
+
+ return Sendmsg(fd, "success");
+ }
default: {
LOG(ERROR) << "Received unknown message type from client";
Sendmsg(fd, "fail");
@@ -637,7 +646,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;
}
@@ -687,5 +696,22 @@
return true;
}
+bool UserSnapshotServer::UpdateVerification(std::lock_guard<std::mutex>* proof_of_lock) {
+ CHECK(proof_of_lock);
+
+ bool status = true;
+ for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
+ auto& th = (*iter)->thread();
+ if (th.joinable() && status) {
+ status = (*iter)->snapuserd()->CheckPartitionVerification() && status;
+ } else {
+ // return immediately if there is a failure
+ return false;
+ }
+ }
+
+ return status;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
index 34e7941..00734a9 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
@@ -46,6 +46,7 @@
INITIATE,
PERCENTAGE,
GETSTATUS,
+ UPDATE_VERIFY,
INVALID,
};
@@ -118,6 +119,8 @@
double GetMergePercentage(std::lock_guard<std::mutex>* proof_of_lock);
void TerminateMergeThreads(std::lock_guard<std::mutex>* proof_of_lock);
+ bool UpdateVerification(std::lock_guard<std::mutex>* proof_of_lock);
+
public:
UserSnapshotServer() { terminating_ = false; }
~UserSnapshotServer();
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp
new file mode 100644
index 0000000..18c1dfc
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp
@@ -0,0 +1,222 @@
+/*
+ * 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 "snapuserd_core.h"
+
+#include <android-base/chrono_utils.h>
+#include <android-base/scopeguard.h>
+#include <android-base/strings.h>
+
+namespace android {
+namespace snapshot {
+
+using namespace android;
+using namespace android::dm;
+using android::base::unique_fd;
+
+UpdateVerify::UpdateVerify(const std::string& misc_name)
+ : misc_name_(misc_name), state_(UpdateVerifyState::VERIFY_UNKNOWN) {}
+
+bool UpdateVerify::CheckPartitionVerification() {
+ auto now = std::chrono::system_clock::now();
+ auto deadline = now + 10s;
+ {
+ std::unique_lock<std::mutex> cv_lock(m_lock_);
+ while (state_ == UpdateVerifyState::VERIFY_UNKNOWN) {
+ auto status = m_cv_.wait_until(cv_lock, deadline);
+ if (status == std::cv_status::timeout) {
+ return false;
+ }
+ }
+ }
+
+ return (state_ == UpdateVerifyState::VERIFY_SUCCESS);
+}
+
+void UpdateVerify::UpdatePartitionVerificationState(UpdateVerifyState state) {
+ {
+ std::lock_guard<std::mutex> lock(m_lock_);
+ state_ = state;
+ }
+ m_cv_.notify_all();
+}
+
+void UpdateVerify::VerifyUpdatePartition() {
+ bool succeeded = false;
+
+ auto scope_guard = android::base::make_scope_guard([this, &succeeded]() -> void {
+ if (!succeeded) {
+ UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_FAILED);
+ }
+ });
+
+ auto& dm = DeviceMapper::Instance();
+ auto dm_block_devices = dm.FindDmPartitions();
+ if (dm_block_devices.empty()) {
+ SNAP_LOG(ERROR) << "No dm-enabled block device is found.";
+ return;
+ }
+
+ const auto parts = android::base::Split(misc_name_, "-");
+ std::string partition_name = parts[0];
+
+ constexpr auto&& suffix_b = "_b";
+ constexpr auto&& suffix_a = "_a";
+
+ partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1);
+ partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1);
+
+ if (dm_block_devices.find(partition_name) == dm_block_devices.end()) {
+ SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name;
+ return;
+ }
+
+ if (!VerifyPartition(partition_name, dm_block_devices.at(partition_name))) {
+ SNAP_LOG(ERROR) << "Partition: " << partition_name
+ << " Block-device: " << dm_block_devices.at(partition_name)
+ << " verification failed";
+ }
+ succeeded = true;
+}
+
+bool UpdateVerify::VerifyBlocks(const std::string& partition_name,
+ const std::string& dm_block_device, off_t offset, int skip_blocks,
+ uint64_t dev_sz) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_DIRECT)));
+ if (fd < 0) {
+ SNAP_LOG(ERROR) << "open failed: " << dm_block_device;
+ return false;
+ }
+
+ loff_t file_offset = offset;
+ const uint64_t read_sz = kBlockSizeVerify;
+
+ void* addr;
+ ssize_t page_size = getpagesize();
+ if (posix_memalign(&addr, page_size, read_sz) < 0) {
+ SNAP_PLOG(ERROR) << "posix_memalign failed "
+ << " page_size: " << page_size << " read_sz: " << read_sz;
+ return false;
+ }
+
+ std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
+
+ uint64_t bytes_read = 0;
+
+ while (true) {
+ size_t to_read = std::min((dev_sz - file_offset), read_sz);
+
+ if (!android::base::ReadFullyAtOffset(fd.get(), buffer.get(), to_read, file_offset)) {
+ SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device
+ << " partition-name: " << partition_name
+ << " at offset: " << file_offset << " read-size: " << to_read
+ << " block-size: " << dev_sz;
+ return false;
+ }
+
+ bytes_read += to_read;
+ file_offset += (skip_blocks * kBlockSizeVerify);
+ if (file_offset >= dev_sz) {
+ break;
+ }
+ }
+
+ SNAP_LOG(DEBUG) << "Verification success with bytes-read: " << bytes_read
+ << " dev_sz: " << dev_sz << " partition_name: " << partition_name;
+
+ return true;
+}
+
+bool UpdateVerify::VerifyPartition(const std::string& partition_name,
+ const std::string& dm_block_device) {
+ android::base::Timer timer;
+
+ SNAP_LOG(INFO) << "VerifyPartition: " << partition_name << " Block-device: " << dm_block_device;
+
+ bool succeeded = false;
+ auto scope_guard = android::base::make_scope_guard([this, &succeeded]() -> void {
+ if (!succeeded) {
+ UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_FAILED);
+ }
+ });
+
+ unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_DIRECT)));
+ if (fd < 0) {
+ SNAP_LOG(ERROR) << "open failed: " << dm_block_device;
+ return false;
+ }
+
+ uint64_t dev_sz = get_block_device_size(fd.get());
+ if (!dev_sz) {
+ SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device;
+ return false;
+ }
+
+ if (!IsBlockAligned(dev_sz)) {
+ SNAP_LOG(ERROR) << "dev_sz: " << dev_sz << " is not block aligned";
+ return false;
+ }
+
+ /*
+ * Not all partitions are of same size. Some partitions are as small as
+ * 100Mb. We can just finish them in a single thread. For bigger partitions
+ * such as product, 4 threads are sufficient enough.
+ *
+ * TODO: With io_uring SQ_POLL support, we can completely cut this
+ * down to just single thread for all partitions and potentially verify all
+ * the partitions with zero syscalls. Additionally, since block layer
+ * supports polling, IO_POLL could be used which will further cut down
+ * latency.
+ */
+ int num_threads = kMinThreadsToVerify;
+ if (dev_sz > kThresholdSize) {
+ num_threads = kMaxThreadsToVerify;
+ }
+
+ std::vector<std::future<bool>> threads;
+ off_t start_offset = 0;
+ const int skip_blocks = num_threads;
+
+ while (num_threads) {
+ threads.emplace_back(std::async(std::launch::async, &UpdateVerify::VerifyBlocks, this,
+ partition_name, dm_block_device, start_offset, skip_blocks,
+ dev_sz));
+ start_offset += kBlockSizeVerify;
+ num_threads -= 1;
+ if (start_offset >= dev_sz) {
+ break;
+ }
+ }
+
+ bool ret = true;
+ for (auto& t : threads) {
+ ret = t.get() && ret;
+ }
+
+ if (ret) {
+ succeeded = true;
+ UpdatePartitionVerificationState(UpdateVerifyState::VERIFY_SUCCESS);
+ SNAP_LOG(INFO) << "Partition: " << partition_name << " Block-device: " << dm_block_device
+ << " Size: " << dev_sz
+ << " verification success. Duration : " << timer.duration().count() << " ms";
+ return true;
+ }
+
+ return false;
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index d82d566..fdc0d8e 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -52,9 +52,9 @@
],
}
-cc_prebuilt_binary {
+sh_binary_host {
name: "adb-remount-test.sh",
- srcs: ["adb-remount-test.sh"],
+ src: "adb-remount-test.sh",
target: {
darwin: {
enabled: false,
@@ -62,11 +62,7 @@
windows: {
enabled: false,
},
- android: {
- enabled: false,
- },
},
- host_supported: true,
}
sh_test {
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 dd67d04..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",
],
@@ -202,6 +202,12 @@
visibility: [":__subpackages__"],
}
+cc_library_headers {
+ name: "libinit_headers",
+ export_include_dirs: ["."],
+ visibility: [":__subpackages__"],
+}
+
cc_library_static {
name: "libinit",
recovery_available: true,
@@ -352,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/bootchart.cpp b/init/bootchart.cpp
index b7db9b6..f46fb09 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -140,6 +140,20 @@
static void bootchart_thread_main() {
LOG(INFO) << "Bootcharting started";
+ // Unshare the mount namespace of this thread so that the init process itself can switch
+ // the mount namespace later while this thread is still running.
+ // Otherwise, setns() call invoked as part of `enter_default_mount_ns` fails with EINVAL.
+ //
+ // Note that after unshare()'ing the mount namespace from the main thread, this thread won't
+ // receive mount/unmount events from the other mount namespace unless the events are happening
+ // from under a sharable mount.
+ //
+ // The bootchart thread is safe to unshare the mount namespace because it only reads from /proc
+ // and write to /data which are not private mounts.
+ if (unshare(CLONE_NEWNS) == -1) {
+ PLOG(ERROR) << "Cannot create mount namespace";
+ return;
+ }
// Open log files.
auto stat_log = fopen_unique("/data/bootchart/proc_stat.log", "we");
if (!stat_log) return;
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/compare-bootcharts.py b/init/compare-bootcharts.py
index 2057b55..009b639 100755
--- a/init/compare-bootcharts.py
+++ b/init/compare-bootcharts.py
@@ -56,24 +56,24 @@
]
jw = jiffy_record['jiffy_to_wallclock']
- print "process: baseline experiment (delta)"
- print " - Unit is ms (a jiffy is %d ms on the system)" % jw
- print "------------------------------------"
+ print("process: baseline experiment (delta)")
+ print(" - Unit is ms (a jiffy is %d ms on the system)" % jw)
+ print("------------------------------------")
for p in processes_of_interest:
# e.g., 32-bit system doesn't have zygote64
if p in process_map1 and p in process_map2:
- print "%s: %d %d (%+d)" % (
+ print("%s: %d %d (%+d)" % (
p, process_map1[p]['start_time'] * jw,
process_map2[p]['start_time'] * jw,
(process_map2[p]['start_time'] -
- process_map1[p]['start_time']) * jw)
+ process_map1[p]['start_time']) * jw))
# Print the last tick for the bootanimation process
- print "bootanimation ends at: %d %d (%+d)" % (
+ print("bootanimation ends at: %d %d (%+d)" % (
process_map1['/system/bin/bootanimation']['last_tick'] * jw,
process_map2['/system/bin/bootanimation']['last_tick'] * jw,
(process_map2['/system/bin/bootanimation']['last_tick'] -
- process_map1['/system/bin/bootanimation']['last_tick']) * jw)
+ process_map1['/system/bin/bootanimation']['last_tick']) * jw))
def parse_proc_file(pathname, process_map, jiffy_record=None):
# Uncompress bootchart.tgz
@@ -83,7 +83,7 @@
f = tf.extractfile('proc_ps.log')
# Break proc_ps into chunks based on timestamps
- blocks = f.read().split('\n\n')
+ blocks = f.read().decode('utf-8').split('\n\n')
for b in blocks:
lines = b.split('\n')
if not lines[0]:
@@ -133,7 +133,7 @@
def main():
if len(sys.argv) != 3:
- print "Usage: %s base_bootchart_dir exp_bootchart_dir" % sys.argv[0]
+ print("Usage: %s base_bootchart_dir exp_bootchart_dir" % sys.argv[0])
sys.exit(1)
process_map1 = {}
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..7e92538 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) {
@@ -1331,6 +1351,11 @@
InitPropertySet(persistent_property_record.name(),
persistent_property_record.value());
}
+ // Apply debug ramdisk special settings after persistent properties are loaded.
+ if (android::base::GetBoolProperty("ro.force.debuggable", false)) {
+ // Always enable usb adb if device is booted with debug ramdisk.
+ update_sys_usb_config();
+ }
InitPropertySet("ro.persistent_properties.ready", "true");
persistent_properties_loaded = true;
break;
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 6aa9912..4e4bfd8 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -18,6 +18,7 @@
#include <dirent.h>
#include <fcntl.h>
+#include <linux/f2fs.h>
#include <linux/fs.h>
#include <linux/loop.h>
#include <mntent.h>
@@ -218,7 +219,7 @@
<< stat;
}
-static bool IsDataMounted() {
+static bool IsDataMounted(const std::string& fstype) {
std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
if (fp == nullptr) {
PLOG(ERROR) << "Failed to open /proc/mounts";
@@ -227,7 +228,7 @@
mntent* mentry;
while ((mentry = getmntent(fp.get())) != nullptr) {
if (mentry->mnt_dir == "/data"s) {
- return true;
+ return fstype == "*" || mentry->mnt_type == fstype;
}
}
return false;
@@ -633,7 +634,7 @@
// If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
// worry about unmounting it.
- if (!IsDataMounted()) {
+ if (!IsDataMounted("*")) {
sync();
RebootSystem(cmd, reboot_target);
abort();
@@ -758,6 +759,16 @@
sem_post(&reboot_semaphore);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
+ if (IsDataMounted("f2fs")) {
+ uint32_t flag = F2FS_GOING_DOWN_FULLSYNC;
+ unique_fd fd(TEMP_FAILURE_RETRY(open("/data", O_RDONLY)));
+ int ret = ioctl(fd, F2FS_IOC_SHUTDOWN, &flag);
+ if (ret) {
+ PLOG(ERROR) << "Shutdown /data: ";
+ } else {
+ LOG(INFO) << "Shutdown /data";
+ }
+ }
RebootSystem(cmd, reboot_target);
abort();
}
@@ -881,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/ueventd.cpp b/init/ueventd.cpp
index c6bf708..586e2cf 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -298,21 +298,31 @@
static UeventdConfiguration GetConfiguration() {
auto hardware = android::base::GetProperty("ro.hardware", "");
- std::vector<std::string> legacy_paths{"/vendor/ueventd.rc", "/odm/ueventd.rc",
- "/ueventd." + hardware + ".rc"};
+
+ struct LegacyPathInfo {
+ std::string legacy_path;
+ std::string preferred;
+ };
+ std::vector<LegacyPathInfo> legacy_paths{
+ {"/vendor/ueventd.rc", "/vendor/etc/ueventd.rc"},
+ {"/odm/ueventd.rc", "/odm/etc/ueventd.rc"},
+ {"/ueventd." + hardware + ".rc", "another ueventd.rc file"}};
std::vector<std::string> canonical{"/system/etc/ueventd.rc"};
if (android::base::GetIntProperty("ro.product.first_api_level", 10000) < __ANDROID_API_T__) {
// TODO: Remove these legacy paths once Android S is no longer supported.
- canonical.insert(canonical.end(), legacy_paths.begin(), legacy_paths.end());
+ for (const auto& info : legacy_paths) {
+ canonical.push_back(info.legacy_path);
+ }
} else {
// Warn if newer device is using legacy paths.
- for (const auto& path : legacy_paths) {
- if (access(path.c_str(), F_OK) == 0) {
+ for (const auto& info : legacy_paths) {
+ if (access(info.legacy_path.c_str(), F_OK) == 0) {
LOG(FATAL_WITHOUT_ABORT)
<< "Legacy ueventd configuration file detected and will not be parsed: "
- << path;
+ << info.legacy_path << ". Please move your configuration to "
+ << info.preferred << " instead.";
}
}
}
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 edda414..51c810e 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -166,7 +166,8 @@
// https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3574427/5/src/linux/android.rs#12
extern "C" bool android_set_process_profiles(uid_t uid, pid_t pid, size_t num_profiles,
const char* profiles[]) {
- std::vector<std::string> profiles_(num_profiles);
+ std::vector<std::string> profiles_;
+ profiles_.reserve(num_profiles);
for (size_t i = 0; i < num_profiles; i++) {
profiles_.emplace_back(profiles[i]);
}
@@ -186,10 +187,6 @@
auto uid_pid_path = ConvertUidPidToPath(cgroup, uid, pid);
auto uid_path = ConvertUidToPath(cgroup, uid);
- if (retries == 0) {
- retries = 1;
- }
-
while (retries--) {
ret = rmdir(uid_pid_path.c_str());
if (!ret || errno != EBUSY) break;
@@ -199,7 +196,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) {
@@ -214,6 +211,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) {
@@ -226,9 +238,7 @@
return empty;
}
-void removeAllProcessGroups() {
- LOG(VERBOSE) << "removeAllProcessGroups()";
-
+void removeAllProcessGroupsInternal(bool empty_only) {
std::vector<std::string> cgroups;
std::string path, memcg_apps_path;
@@ -255,7 +265,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;
}
@@ -268,6 +278,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
@@ -439,12 +459,13 @@
<< " in " << static_cast<int>(ms) << "ms";
}
- int err = RemoveProcessGroup(cgroup, uid, initialPid, retries);
+ // 400 retries correspond to 2 secs max timeout
+ int err = RemoveProcessGroup(cgroup, uid, initialPid, 400);
if (isMemoryCgroupSupported() && UsePerAppMemcg()) {
std::string memcg_apps_path;
if (CgroupGetMemcgAppsPath(&memcg_apps_path) &&
- RemoveProcessGroup(memcg_apps_path.c_str(), uid, initialPid, retries) < 0) {
+ RemoveProcessGroup(memcg_apps_path.c_str(), uid, initialPid, 400) < 0) {
return -1;
}
}
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 7e03964..8589a8d 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -435,7 +435,6 @@
}
]
},
-
{
"Name": "LowIoPriority",
"Actions": [
@@ -648,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/pull_rust/stats_pull.rs b/libstats/pull_rust/stats_pull.rs
index 174125e..09b2623 100644
--- a/libstats/pull_rust/stats_pull.rs
+++ b/libstats/pull_rust/stats_pull.rs
@@ -68,7 +68,7 @@
}
/// Calls AStatsManager_PullAtomMetadata_setAdditiveFields.
- pub fn set_additive_fields(&mut self, additive_fields: &mut Vec<i32>) {
+ pub fn set_additive_fields(&mut self, additive_fields: &mut [i32]) {
// Safety: Metadata::new ensures that self.metadata is a valid object.
unsafe {
AStatsManager_PullAtomMetadata_setAdditiveFields(
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 d39a21c..29b8365 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
@@ -829,15 +834,19 @@
mkdir /data/misc/odsign/metrics 0770 root system
# Directory for VirtualizationService temporary image files.
- mkdir /data/misc/virtualizationservice 0700 system system
+ # 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
@@ -875,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
@@ -903,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.
@@ -930,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
@@ -964,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
@@ -1096,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
@@ -1129,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
@@ -1157,6 +1170,7 @@
chown system system /sys/kernel/ipv4/tcp_rmem_def
chown system system /sys/kernel/ipv4/tcp_rmem_max
chown root radio /proc/cmdline
+ chown root system /proc/bootconfig
# Define default initial receive window size in segments.
setprop net.tcp_def_init_rwnd 60
@@ -1300,6 +1314,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/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp
index cdfbd90..e77940a 100644
--- a/trusty/keymaster/TrustyKeymaster.cpp
+++ b/trusty/keymaster/TrustyKeymaster.cpp
@@ -279,4 +279,10 @@
return response;
}
+GetRootOfTrustResponse TrustyKeymaster::GetRootOfTrust(const GetRootOfTrustRequest& request) {
+ GetRootOfTrustResponse response(message_version());
+ ForwardCommand(KM_GET_ROOT_OF_TRUST, request, &response);
+ return response;
+}
+
} // namespace keymaster
diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
index f80e02f..9f4f39b 100644
--- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
+++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h
@@ -66,6 +66,7 @@
DeviceLockedResponse DeviceLocked(const DeviceLockedRequest& request);
ConfigureVendorPatchlevelResponse ConfigureVendorPatchlevel(
const ConfigureVendorPatchlevelRequest& request);
+ GetRootOfTrustResponse GetRootOfTrust(const GetRootOfTrustRequest& request);
uint32_t message_version() const { return message_version_; }
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index fa475ae..bf0cb70 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -59,6 +59,7 @@
KM_GENERATE_RKP_KEY = (31 << KEYMASTER_REQ_SHIFT),
KM_GENERATE_CSR = (32 << KEYMASTER_REQ_SHIFT),
KM_CONFIGURE_VENDOR_PATCHLEVEL = (33 << KEYMASTER_REQ_SHIFT),
+ KM_GET_ROOT_OF_TRUST = (34 << KEYMASTER_REQ_SHIFT),
// Bootloader/provisioning calls.
KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
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/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
index 44780e8..7d58162 100644
--- a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
+++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp
@@ -325,9 +325,20 @@
return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
}
-ScopedAStatus TrustyKeyMintDevice::getRootOfTrust(const array<uint8_t, 16>& /* challenge */,
- vector<uint8_t>* /* rootOfTrust */) {
- return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED);
+ScopedAStatus TrustyKeyMintDevice::getRootOfTrust(const array<uint8_t, 16>& challenge,
+ vector<uint8_t>* rootOfTrust) {
+ if (!rootOfTrust) {
+ return kmError2ScopedAStatus(KM_ERROR_UNEXPECTED_NULL_POINTER);
+ }
+ keymaster::GetRootOfTrustRequest request(impl_->message_version(),
+ {challenge.begin(), challenge.end()});
+ keymaster::GetRootOfTrustResponse response = impl_->GetRootOfTrust(request);
+ if (response.error != KM_ERROR_OK) {
+ return kmError2ScopedAStatus(response.error);
+ }
+
+ *rootOfTrust = std::move(response.rootOfTrust);
+ return ScopedAStatus::ok();
}
ScopedAStatus TrustyKeyMintDevice::sendRootOfTrust(const vector<uint8_t>& /* rootOfTrust */) {
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/libtrusty-rs/Android.bp b/trusty/libtrusty-rs/Android.bp
index bc1dcf6..4fc162b 100644
--- a/trusty/libtrusty-rs/Android.bp
+++ b/trusty/libtrusty-rs/Android.bp
@@ -19,6 +19,7 @@
rust_library {
name: "libtrusty-rs",
crate_name: "trusty",
+ vendor_available: true,
srcs: [
"src/lib.rs"
],
diff --git a/trusty/metrics/metrics_test.cpp b/trusty/metrics/metrics_test.cpp
index 407ddf2..9897950 100644
--- a/trusty/metrics/metrics_test.cpp
+++ b/trusty/metrics/metrics_test.cpp
@@ -31,7 +31,7 @@
using android::base::unique_fd;
static void TriggerCrash() {
- size_t num_retries = 3;
+ size_t num_retries = 6;
int fd = -1;
for (size_t i = 0; i < num_retries; i++) {
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