Merge "Revert^2 "Only write appcompat properties if flag is defined"" into main
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 2529516..0c5543e 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -240,11 +240,16 @@
"libdebuggerd/backtrace.cpp",
"libdebuggerd/gwp_asan.cpp",
"libdebuggerd/open_files_list.cpp",
+ "libdebuggerd/scudo.cpp",
"libdebuggerd/tombstone.cpp",
"libdebuggerd/tombstone_proto.cpp",
"libdebuggerd/utility.cpp",
],
+ cflags: [
+ "-DUSE_SCUDO",
+ ],
+
local_include_dirs: ["libdebuggerd/include"],
export_include_dirs: ["libdebuggerd/include"],
@@ -256,6 +261,7 @@
"bionic_libc_platform_headers",
"gwp_asan_headers",
"liblog_headers",
+ "scudo_headers",
],
static_libs: [
@@ -273,6 +279,7 @@
"libtombstone_proto",
"libprocinfo",
"libprotobuf-cpp-lite",
+ "libscudo",
],
target: {
@@ -312,11 +319,9 @@
cflags: ["-DROOT_POSSIBLE"],
},
- malloc_not_svelte: {
- cflags: ["-DUSE_SCUDO"],
- whole_static_libs: ["libscudo"],
- srcs: ["libdebuggerd/scudo.cpp"],
- header_libs: ["scudo_headers"],
+ malloc_low_memory: {
+ cflags: ["-UUSE_SCUDO"],
+ exclude_static_libs: ["libscudo"],
},
},
apex_available: [
@@ -447,6 +452,7 @@
header_libs: [
"bionic_libc_platform_headers",
+ "libnative_bridge_support_accessor_headers",
],
static_libs: [
@@ -456,6 +462,8 @@
"libtombstone_proto",
"libprotobuf-cpp-lite",
+
+ "libnative_bridge_guest_state_accessor",
],
shared_libs: [
@@ -471,6 +479,15 @@
// Required for tests.
required: ["crash_dump.policy"],
+
+ target: {
+ android: {
+ header_libs: [
+ "libnative_bridge_support_accessor_headers", // For dlext_namespaces.h
+ ],
+ shared_libs: ["libdl_android"], // For android_get_exported_namespace implementation
+ },
+ },
}
cc_binary {
diff --git a/debuggerd/TEST_MAPPING b/debuggerd/TEST_MAPPING
index 61d7155..824d20a 100644
--- a/debuggerd/TEST_MAPPING
+++ b/debuggerd/TEST_MAPPING
@@ -4,6 +4,10 @@
"name": "debuggerd_test"
},
{
+ "name": "debuggerd_test",
+ "keywords": ["primary-device"]
+ },
+ {
"name": "libtombstoned_client_rust_test"
},
{
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 203b485..1c1fb8a 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -25,6 +25,7 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <cstdint>
#include <limits>
#include <map>
#include <memory>
@@ -42,6 +43,7 @@
#include <android-base/unique_fd.h>
#include <bionic/macros.h>
#include <bionic/reserved_signals.h>
+#include <bionic/tls_defines.h>
#include <cutils/sockets.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
@@ -52,7 +54,18 @@
#include <unwindstack/AndroidUnwinder.h>
#include <unwindstack/Error.h>
+#include <unwindstack/MachineArm.h>
+#include <unwindstack/MachineArm64.h>
+#include <unwindstack/MachineRiscv64.h>
#include <unwindstack/Regs.h>
+#include <unwindstack/RegsArm.h>
+#include <unwindstack/RegsArm64.h>
+#include <unwindstack/RegsRiscv64.h>
+#include <unwindstack/UserArm.h>
+#include <unwindstack/UserArm64.h>
+#include <unwindstack/UserRiscv64.h>
+
+#include <native_bridge_support/guest_state_accessor/accessor.h>
#include "libdebuggerd/backtrace.h"
#include "libdebuggerd/tombstone.h"
@@ -68,6 +81,10 @@
using android::base::StringPrintf;
using android::base::unique_fd;
+// This stores guest architecture. When the architecture is supported, tombstone file will output
+// guest state information.
+static Architecture g_guest_arch;
+
static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
struct stat st;
std::string task_path = StringPrintf("task/%d", tid);
@@ -286,28 +303,27 @@
*recoverable_crash = false;
if (rc == -1) {
PLOG(FATAL) << "failed to read target ucontext";
- } else {
- ssize_t expected_size = 0;
- switch (crash_info->header.version) {
- case 1:
- case 2:
- case 3:
- expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataStatic);
- break;
+ }
+ ssize_t expected_size = 0;
+ switch (crash_info->header.version) {
+ case 1:
+ case 2:
+ case 3:
+ expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataStatic);
+ break;
- case 4:
- expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataDynamic);
- break;
+ case 4:
+ expected_size = sizeof(CrashInfoHeader) + sizeof(CrashInfoDataDynamic);
+ break;
- default:
- LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version;
- break;
- };
+ default:
+ LOG(FATAL) << "unexpected CrashInfo version: " << crash_info->header.version;
+ break;
+ }
- if (rc < expected_size) {
- LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected "
- << expected_size;
- }
+ if (rc < expected_size) {
+ LOG(FATAL) << "read " << rc << " bytes when reading target crash information, expected "
+ << expected_size;
}
switch (crash_info->header.version) {
@@ -403,6 +419,116 @@
sigaction(SIGPIPE, &action, nullptr);
}
+static bool PtracePeek(int request, pid_t tid, uintptr_t addr, void* data, std::string_view err_msg,
+ uintptr_t* result) {
+ errno = 0;
+ *result = ptrace(request, tid, addr, data);
+ if (errno != 0) {
+ PLOG(ERROR) << err_msg;
+ return false;
+ }
+ return true;
+}
+
+static bool GetGuestRegistersFromCrashedProcess([[maybe_unused]] pid_t tid,
+ NativeBridgeGuestRegs* guest_regs) {
+ auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(tid);
+
+ uintptr_t header_ptr = 0;
+ uintptr_t base = 0;
+#if defined(__x86_64__)
+ if (!PtracePeek(PTRACE_PEEKUSER, tid, offsetof(user_regs_struct, fs_base), nullptr,
+ "failed to read thread register for thread " + std::to_string(tid), &base)) {
+ return false;
+ }
+#elif defined(__aarch64__)
+ // base is implicitly casted to uint64_t.
+ struct iovec pt_iov {
+ .iov_base = &base, .iov_len = sizeof(base),
+ };
+
+ if (ptrace(PTRACE_GETREGSET, tid, NT_ARM_TLS, &pt_iov) != 0) {
+ PLOG(ERROR) << "failed to read thread register for thread " << tid;
+ return false;
+ }
+#elif defined(__riscv)
+ struct user_regs_struct regs;
+ struct iovec pt_iov = {.iov_base = ®s, .iov_len = sizeof(regs)};
+ if (ptrace(PTRACE_GETREGSET, tid, NT_PRSTATUS, &pt_iov) != 0) {
+ PLOG(ERROR) << "failed to read thread register for thread " << tid;
+ return false;
+ }
+ base = reinterpret_cast<uintptr_t>(regs.tp);
+#else
+ // TODO(b/339287219): Add case for Riscv host.
+ return false;
+#endif
+ auto ptr_to_guest_slot = base + TLS_SLOT_NATIVE_BRIDGE_GUEST_STATE * sizeof(uintptr_t);
+ if (!process_memory->ReadFully(ptr_to_guest_slot, &header_ptr, sizeof(uintptr_t))) {
+ PLOG(ERROR) << "failed to get guest state TLS slot content for thread " << tid;
+ return false;
+ }
+
+ NativeBridgeGuestStateHeader header;
+ if (!process_memory->ReadFully(header_ptr, &header, sizeof(NativeBridgeGuestStateHeader))) {
+ PLOG(ERROR) << "failed to get the guest state header for thread " << tid;
+ return false;
+ }
+ if (header.signature != NATIVE_BRIDGE_GUEST_STATE_SIGNATURE) {
+ // Return when ptr points to unmapped memory or no valid guest state.
+ return false;
+ }
+ auto guest_state_data_copy = std::make_unique<unsigned char[]>(header.guest_state_data_size);
+ if (!process_memory->ReadFully(reinterpret_cast<uintptr_t>(header.guest_state_data),
+ guest_state_data_copy.get(), header.guest_state_data_size)) {
+ PLOG(ERROR) << "failed to read the guest state data for thread " << tid;
+ return false;
+ }
+
+ LoadGuestStateRegisters(guest_state_data_copy.get(), header.guest_state_data_size, guest_regs);
+ return true;
+}
+
+static void ReadGuestRegisters([[maybe_unused]] std::unique_ptr<unwindstack::Regs>* regs,
+ pid_t tid) {
+ // TODO: remove [[maybe_unused]], when the ARM32 case is removed from the native bridge support.
+ NativeBridgeGuestRegs guest_regs;
+ if (!GetGuestRegistersFromCrashedProcess(tid, &guest_regs)) {
+ return;
+ }
+
+ switch (guest_regs.guest_arch) {
+#if defined(__LP64__)
+ case NATIVE_BRIDGE_ARCH_ARM64: {
+ unwindstack::arm64_user_regs arm64_user_regs = {};
+ for (size_t i = 0; i < unwindstack::ARM64_REG_R31; i++) {
+ arm64_user_regs.regs[i] = guest_regs.regs_arm64.x[i];
+ }
+ arm64_user_regs.sp = guest_regs.regs_arm64.sp;
+ arm64_user_regs.pc = guest_regs.regs_arm64.ip;
+ regs->reset(unwindstack::RegsArm64::Read(&arm64_user_regs));
+
+ g_guest_arch = Architecture::ARM64;
+ break;
+ }
+ case NATIVE_BRIDGE_ARCH_RISCV64: {
+ unwindstack::riscv64_user_regs riscv64_user_regs = {};
+ // RISCV64_REG_PC is at the first position.
+ riscv64_user_regs.regs[0] = guest_regs.regs_riscv64.ip;
+ for (size_t i = 1; i < unwindstack::RISCV64_REG_REAL_COUNT; i++) {
+ riscv64_user_regs.regs[i] = guest_regs.regs_riscv64.x[i];
+ }
+ regs->reset(unwindstack::RegsRiscv64::Read(&riscv64_user_regs, tid));
+
+ g_guest_arch = Architecture::RISCV64;
+ break;
+ }
+#endif
+ default:
+ break;
+ }
+}
+
int main(int argc, char** argv) {
DefuseSignalHandlers();
InstallSigPipeHandler();
@@ -551,6 +677,7 @@
continue;
}
}
+ ReadGuestRegisters(&info.guest_registers, thread);
thread_info[thread] = std::move(info);
}
@@ -660,8 +787,32 @@
{
ATRACE_NAME("engrave_tombstone");
- engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,
- g_target_thread, process_info, &open_files, &amfd_data);
+ unwindstack::ArchEnum regs_arch = unwindstack::ARCH_UNKNOWN;
+ switch (g_guest_arch) {
+ case Architecture::ARM32: {
+ regs_arch = unwindstack::ARCH_ARM;
+ break;
+ }
+ case Architecture::ARM64: {
+ regs_arch = unwindstack::ARCH_ARM64;
+ break;
+ }
+ case Architecture::RISCV64: {
+ regs_arch = unwindstack::ARCH_RISCV64;
+ break;
+ }
+ default: {
+ }
+ }
+ if (regs_arch == unwindstack::ARCH_UNKNOWN) {
+ engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,
+ g_target_thread, process_info, &open_files, &amfd_data);
+ } else {
+ unwindstack::AndroidRemoteUnwinder guest_unwinder(vm_pid, regs_arch);
+ engrave_tombstone(std::move(g_output_fd), std::move(g_proto_fd), &unwinder, thread_info,
+ g_target_thread, process_info, &open_files, &amfd_data, &g_guest_arch,
+ &guest_unwinder);
+ }
}
}
diff --git a/debuggerd/crasher/crasher.cpp b/debuggerd/crasher/crasher.cpp
index 3b52776..05143ed 100644
--- a/debuggerd/crasher/crasher.cpp
+++ b/debuggerd/crasher/crasher.cpp
@@ -202,7 +202,9 @@
fprintf(stderr, " fdsan_file close a file descriptor that's owned by a FILE*\n");
fprintf(stderr, " fdsan_dir close a file descriptor that's owned by a DIR*\n");
fprintf(stderr, " seccomp fail a seccomp check\n");
+#if defined(__LP64__)
fprintf(stderr, " xom read execute-only memory\n");
+#endif
fprintf(stderr, "\n");
fprintf(stderr, " LOG_ALWAYS_FATAL call liblog LOG_ALWAYS_FATAL\n");
fprintf(stderr, " LOG_ALWAYS_FATAL_IF call liblog LOG_ALWAYS_FATAL_IF\n");
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 7c52e6e..baddf65 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -332,12 +332,7 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
-#ifdef __LP64__
- ASSERT_MATCH(result,
- R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x000000000000dead)");
-#else
- ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0000dead)");
-#endif
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x0+dead)");
if (mte_supported()) {
// Test that the default TAGGED_ADDR_CTRL value is set.
@@ -1667,6 +1662,9 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(
+ result,
+ R"(signal 6 \(SIGABRT\))");
ASSERT_BACKTRACE_FRAME(result, "abort");
}
@@ -1826,10 +1824,14 @@
"Use After Free, 0 bytes into a 7-byte allocation"},
{/* alloc_size */ 15, /* free_before_access */ true, /* access_offset */ 1,
"Use After Free, 1 byte into a 15-byte allocation"},
- {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ 4098,
- "Buffer Overflow, 2 bytes right of a 4096-byte allocation"},
- {/* alloc_size */ 4096, /* free_before_access */ false, /* access_offset */ -1,
- "Buffer Underflow, 1 byte left of a 4096-byte allocation"},
+ {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
+ /* access_offset */ getpagesize() + 2,
+ android::base::StringPrintf("Buffer Overflow, 2 bytes right of a %d-byte allocation",
+ getpagesize())},
+ {/* alloc_size */ static_cast<size_t>(getpagesize()), /* free_before_access */ false,
+ /* access_offset */ -1,
+ android::base::StringPrintf("Buffer Underflow, 1 byte left of a %d-byte allocation",
+ getpagesize())},
};
INSTANTIATE_TEST_SUITE_P(
@@ -2974,30 +2976,34 @@
std::string match_str;
// Verify none.
match_str = android::base::StringPrintf(
- " %s-%s --- 0 1000\\n",
+ " %s-%s --- 0 %x\\n",
format_map_pointer(reinterpret_cast<uintptr_t>(none_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str());
+ format_map_pointer(reinterpret_cast<uintptr_t>(none_map) + getpagesize() - 1).c_str(),
+ getpagesize());
ASSERT_MATCH(result, match_str);
// Verify read-only.
match_str = android::base::StringPrintf(
- " %s-%s r-- 0 1000\\n",
+ " %s-%s r-- 0 %x\\n",
format_map_pointer(reinterpret_cast<uintptr_t>(r_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str());
+ format_map_pointer(reinterpret_cast<uintptr_t>(r_map) + getpagesize() - 1).c_str(),
+ getpagesize());
ASSERT_MATCH(result, match_str);
// Verify write-only.
match_str = android::base::StringPrintf(
- " %s-%s -w- 0 1000\\n",
+ " %s-%s -w- 0 %x\\n",
format_map_pointer(reinterpret_cast<uintptr_t>(w_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str());
+ format_map_pointer(reinterpret_cast<uintptr_t>(w_map) + getpagesize() - 1).c_str(),
+ getpagesize());
ASSERT_MATCH(result, match_str);
// Verify exec-only.
match_str = android::base::StringPrintf(
- " %s-%s --x 0 1000\\n",
+ " %s-%s --x 0 %x\\n",
format_map_pointer(reinterpret_cast<uintptr_t>(x_map)).c_str(),
- format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str());
+ format_map_pointer(reinterpret_cast<uintptr_t>(x_map) + getpagesize() - 1).c_str(),
+ getpagesize());
ASSERT_MATCH(result, match_str);
// Verify file map with non-zero offset and a name.
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
index a506859..89bf5a9 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/scudo.h
@@ -16,6 +16,8 @@
#pragma once
+#if defined(USE_SCUDO)
+
#include "types.h"
#include "utility.h"
@@ -49,3 +51,5 @@
void FillInCause(Cause* cause, const scudo_error_report* report,
unwindstack::AndroidUnwinder* unwinder) const;
};
+
+#endif // USE_SCUDO
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index be999e0..dfdfabd 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -28,6 +28,7 @@
#include <android-base/unique_fd.h>
#include "open_files_list.h"
+#include "tombstone.pb.h"
#include "types.h"
// Forward declarations
@@ -54,14 +55,17 @@
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);
+ std::string* amfd_data, const Architecture* guest_arch = nullptr,
+ unwindstack::AndroidUnwinder* guest_unwinder = nullptr);
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::AndroidUnwinder* unwinder,
const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
- const ProcessInfo& process_info, const OpenFilesList* open_files);
+ const ProcessInfo& process_info, const OpenFilesList* open_files,
+ const Architecture* guest_arch,
+ unwindstack::AndroidUnwinder* guest_unwinder);
bool tombstone_proto_to_text(
const Tombstone& tombstone,
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 4d69658..c799f24 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -39,6 +39,8 @@
int signo = 0;
siginfo_t* siginfo = nullptr;
+
+ std::unique_ptr<unwindstack::Regs> guest_registers;
};
// This struct is written into a pipe from inside the crashing process.
diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp
index 3fa3bd0..4ee87c8 100644
--- a/debuggerd/libdebuggerd/scudo.cpp
+++ b/debuggerd/libdebuggerd/scudo.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#if defined(USE_SCUDO)
+
#include "libdebuggerd/scudo.h"
#include "libdebuggerd/tombstone.h"
@@ -141,3 +143,5 @@
FillInCause(tombstone->add_causes(), &error_info_.reports[report_num++], unwinder);
}
}
+
+#endif // USE_SCUDO
diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
index 5be145a..dee7b48 100644
--- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp
+++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp
@@ -20,6 +20,8 @@
#include <string>
#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
@@ -27,61 +29,64 @@
#include "log_fake.h"
-const char g_expected_full_dump[] =
-"\nmemory near r1:\n"
-#if defined(__LP64__)
-" 0000000012345650 0706050403020100 0f0e0d0c0b0a0908 ................\n"
-" 0000000012345660 1716151413121110 1f1e1d1c1b1a1918 ................\n"
-" 0000000012345670 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
-" 0000000012345680 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
-" 0000000012345690 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
-" 00000000123456a0 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
-" 00000000123456b0 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
-" 00000000123456c0 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
-" 00000000123456d0 8786858483828180 8f8e8d8c8b8a8988 ................\n"
-" 00000000123456e0 9796959493929190 9f9e9d9c9b9a9998 ................\n"
-" 00000000123456f0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
-" 0000000012345700 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
-" 0000000012345710 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
-" 0000000012345720 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
-" 0000000012345730 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
-" 0000000012345740 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
-#else
-" 12345650 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
-" 12345660 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
-" 12345670 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
-" 12345680 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
-" 12345690 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
-" 123456a0 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
-" 123456b0 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
-" 123456c0 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
-" 123456d0 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
-" 123456e0 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
-" 123456f0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
-" 12345700 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
-" 12345710 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
-" 12345720 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
-" 12345730 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
-" 12345740 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
-#endif
+std::string GetMemoryString(uintptr_t addr, const std::vector<uint64_t>& data) {
+ // Must be even number of data values.
+ CHECK((data.size() & 1) == 0);
-const char g_expected_partial_dump[] = \
-"\nmemory near pc:\n"
+ std::string str;
+ for (size_t i = 0; i < data.size(); i += 2) {
+ str += " ";
+ std::string ascii_str = "";
+ for (size_t j = 0; j < 2; j++) {
+ for (size_t k = 0; k < 8; k++) {
+ uint8_t c = (data[i + j] >> (k * 8)) & 0xff;
+ if (c >= 0x20 && c < 0x7f) {
+ ascii_str += c;
+ } else {
+ ascii_str += '.';
+ }
+ }
+ }
#if defined(__LP64__)
-" 00000000123455e0 0706050403020100 0f0e0d0c0b0a0908 ................\n"
-" 00000000123455f0 1716151413121110 1f1e1d1c1b1a1918 ................\n"
-" 0000000012345600 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
-" 0000000012345610 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
-" 0000000012345620 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
-" 0000000012345630 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n";
+ str += android::base::StringPrintf("%016zx %016zx %016zx ", addr, data[i], data[i + 1]);
#else
-" 123455e0 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
-" 123455f0 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
-" 12345600 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
-" 12345610 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
-" 12345620 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
-" 12345630 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n";
+ str += android::base::StringPrintf(
+ "%08zx %08zx %08zx %08zx %08zx ", addr, static_cast<uintptr_t>(data[i] & 0xffffffff),
+ static_cast<uintptr_t>(data[i] >> 32), static_cast<uintptr_t>(data[i + 1] & 0xffffffff),
+ static_cast<uintptr_t>(data[i + 1] >> 32));
#endif
+ str += ascii_str + "\n";
+ addr += 0x10;
+ }
+ return str;
+}
+
+const std::vector<uint64_t>& GetDefaultData() {
+ static std::vector<uint64_t> data(
+ {0x0706050403020100UL, 0x0f0e0d0c0b0a0908UL, 0x1716151413121110UL, 0x1f1e1d1c1b1a1918UL,
+ 0x2726252423222120UL, 0x2f2e2d2c2b2a2928UL, 0x3736353433323130UL, 0x3f3e3d3c3b3a3938UL,
+ 0x4746454443424140UL, 0x4f4e4d4c4b4a4948UL, 0x5756555453525150UL, 0x5f5e5d5c5b5a5958UL,
+ 0x6766656463626160UL, 0x6f6e6d6c6b6a6968UL, 0x7776757473727170UL, 0x7f7e7d7c7b7a7978UL,
+ 0x8786858483828180UL, 0x8f8e8d8c8b8a8988UL, 0x9796959493929190UL, 0x9f9e9d9c9b9a9998UL,
+ 0xa7a6a5a4a3a2a1a0UL, 0xafaeadacabaaa9a8UL, 0xb7b6b5b4b3b2b1b0UL, 0xbfbebdbcbbbab9b8UL,
+ 0xc7c6c5c4c3c2c1c0UL, 0xcfcecdcccbcac9c8UL, 0xd7d6d5d4d3d2d1d0UL, 0xdfdedddcdbdad9d8UL,
+ 0xe7e6e5e4e3e2e1e0UL, 0xefeeedecebeae9e8UL, 0xf7f6f5f4f3f2f1f0UL, 0xfffefdfcfbfaf9f8UL});
+ return data;
+}
+
+std::string GetFullDumpString() {
+ std::string str = "\nmemory near r1:\n";
+ str += GetMemoryString(0x12345650U, GetDefaultData());
+ return str;
+}
+
+std::string GetPartialDumpString() {
+ std::string str = "\nmemory near pc:\n";
+ std::vector<uint64_t> data = GetDefaultData();
+ data.resize(12);
+ str += GetMemoryString(0x123455e0U, data);
+ return str;
+}
class MemoryMock : public unwindstack::Memory {
public:
@@ -189,7 +194,7 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+ ASSERT_EQ(GetFullDumpString(), tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -209,7 +214,7 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+ ASSERT_EQ(GetFullDumpString(), tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -228,7 +233,7 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- ASSERT_STREQ(g_expected_full_dump, tombstone_contents.c_str());
+ ASSERT_EQ(GetFullDumpString(), tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -260,7 +265,7 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+ ASSERT_EQ(GetPartialDumpString(), tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -280,7 +285,7 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+ ASSERT_EQ(GetPartialDumpString(), tombstone_contents);
#if defined(__LP64__)
ASSERT_STREQ("6 DEBUG Bytes read 102, is not a multiple of 8\n", getFakeLogPrint().c_str());
@@ -305,7 +310,7 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- ASSERT_STREQ(g_expected_partial_dump, tombstone_contents.c_str());
+ ASSERT_EQ(GetPartialDumpString(), tombstone_contents);
#if defined(__LP64__)
ASSERT_STREQ("6 DEBUG Bytes read 45, is not a multiple of 8\n"
@@ -331,44 +336,9 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory near r1:\n"
-#if defined(__LP64__)
-" 0000000000001000 0000000000000000 0000000000000000 ................\n"
-" 0000000000001010 0000000000000000 0000000000000000 ................\n"
-" 0000000000001020 0000000000000000 0000000000000000 ................\n"
-" 0000000000001030 0000000000000000 0000000000000000 ................\n"
-" 0000000000001040 0000000000000000 0000000000000000 ................\n"
-" 0000000000001050 0000000000000000 0000000000000000 ................\n"
-" 0000000000001060 0000000000000000 0000000000000000 ................\n"
-" 0000000000001070 0000000000000000 0000000000000000 ................\n"
-" 0000000000001080 0000000000000000 0000000000000000 ................\n"
-" 0000000000001090 0000000000000000 0000000000000000 ................\n"
-" 00000000000010a0 0000000000000000 0000000000000000 ................\n"
-" 00000000000010b0 0000000000000000 0000000000000000 ................\n"
-" 00000000000010c0 0000000000000000 0000000000000000 ................\n"
-" 00000000000010d0 0000000000000000 0000000000000000 ................\n"
-" 00000000000010e0 0000000000000000 0000000000000000 ................\n"
-" 00000000000010f0 0000000000000000 0000000000000000 ................\n";
-#else
-" 00001000 00000000 00000000 00000000 00000000 ................\n"
-" 00001010 00000000 00000000 00000000 00000000 ................\n"
-" 00001020 00000000 00000000 00000000 00000000 ................\n"
-" 00001030 00000000 00000000 00000000 00000000 ................\n"
-" 00001040 00000000 00000000 00000000 00000000 ................\n"
-" 00001050 00000000 00000000 00000000 00000000 ................\n"
-" 00001060 00000000 00000000 00000000 00000000 ................\n"
-" 00001070 00000000 00000000 00000000 00000000 ................\n"
-" 00001080 00000000 00000000 00000000 00000000 ................\n"
-" 00001090 00000000 00000000 00000000 00000000 ................\n"
-" 000010a0 00000000 00000000 00000000 00000000 ................\n"
-" 000010b0 00000000 00000000 00000000 00000000 ................\n"
-" 000010c0 00000000 00000000 00000000 00000000 ................\n"
-" 000010d0 00000000 00000000 00000000 00000000 ................\n"
-" 000010e0 00000000 00000000 00000000 00000000 ................\n"
-" 000010f0 00000000 00000000 00000000 00000000 ................\n";
-#endif
- ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ std::string expected_dump = "\nmemory near r1:\n";
+ expected_dump += GetMemoryString(0x1000, std::vector<uint64_t>(32, 0UL));
+ ASSERT_EQ(expected_dump, tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -414,61 +384,17 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory near r4:\n"
+ std::string expected_dump = "\nmemory near r4:\n";
+ uintptr_t addr;
#if defined(__aarch64__)
-" 00ffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n"
-" 00ffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n"
-" 00ffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
-" 00ffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
-" 00ffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
-" 00ffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
-" 00ffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
-" 00ffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
-" 00ffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n"
-" 00ffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n"
-" 00ffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
-" 00ffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
-" 00ffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
-" 00ffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
-" 00ffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
-" 00fffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
+ addr = 0x00ffffffffffff00UL;
#elif defined(__LP64__)
-" ffffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n"
-" ffffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n"
-" ffffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n"
-" ffffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n"
-" ffffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n"
-" ffffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n"
-" ffffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n"
-" ffffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n"
-" ffffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n"
-" ffffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n"
-" ffffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n"
-" ffffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n"
-" ffffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
-" ffffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n"
-" ffffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n"
-" fffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n";
+ addr = 0xffffffffffffff00UL;
#else
-" ffffff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n"
-" ffffff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n"
-" ffffff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n"
-" ffffff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n"
-" ffffff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n"
-" ffffff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n"
-" ffffff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n"
-" ffffff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n"
-" ffffff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n"
-" ffffff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n"
-" ffffffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n"
-" ffffffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n"
-" ffffffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
-" ffffffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n"
-" ffffffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n"
-" fffffff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n";
+ addr = 0xffffff00UL;
#endif
- ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ expected_dump += GetMemoryString(addr, GetDefaultData());
+ ASSERT_EQ(expected_dump, tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -490,30 +416,15 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory near r4:\n"
-#if defined(__LP64__)
-R"( 0000000010001000 8786858483828180 8f8e8d8c8b8a8988 ................
- 0000000010001010 9796959493929190 9f9e9d9c9b9a9998 ................
- 0000000010001020 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................
- 0000000010001030 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................
- 0000000010001040 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................
- 0000000010001050 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................
- 0000000010001060 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................
- 0000000010001070 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................
-)";
-#else
-R"( 10001000 83828180 87868584 8b8a8988 8f8e8d8c ................
- 10001010 93929190 97969594 9b9a9998 9f9e9d9c ................
- 10001020 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................
- 10001030 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................
- 10001040 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................
- 10001050 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................
- 10001060 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................
- 10001070 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................
-)";
-#endif
- ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ std::string expected_dump = "\nmemory near r4:\n";
+ expected_dump += GetMemoryString(
+ 0x10000000 + page_size,
+ std::vector<uint64_t>{
+ 0x8786858483828180UL, 0x8f8e8d8c8b8a8988UL, 0x9796959493929190UL, 0x9f9e9d9c9b9a9998UL,
+ 0xa7a6a5a4a3a2a1a0UL, 0xafaeadacabaaa9a8UL, 0xb7b6b5b4b3b2b1b0UL, 0xbfbebdbcbbbab9b8UL,
+ 0xc7c6c5c4c3c2c1c0UL, 0xcfcecdcccbcac9c8UL, 0xd7d6d5d4d3d2d1d0UL, 0xdfdedddcdbdad9d8UL,
+ 0xe7e6e5e4e3e2e1e0UL, 0xefeeedecebeae9e8UL, 0xf7f6f5f4f3f2f1f0UL, 0xfffefdfcfbfaf9f8UL});
+ ASSERT_EQ(expected_dump, tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
@@ -535,16 +446,11 @@
std::string tombstone_contents;
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
- const char* expected_dump = \
-"\nmemory near r4:\n"
-#if defined(__LP64__)
-" 0000000010001000 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n"
-" 0000000010001010 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n";
-#else
-" 10001000 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n"
-" 10001010 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n";
-#endif
- ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
+ std::string expected_dump = "\nmemory near r4:\n";
+ expected_dump += GetMemoryString(
+ 0x10000000 + page_size, std::vector<uint64_t>{0xc7c6c5c4c3c2c1c0UL, 0xcfcecdcccbcac9c8UL,
+ 0xd7d6d5d4d3d2d1d0UL, 0xdfdedddcdbdad9d8UL});
+ ASSERT_EQ(expected_dump, tombstone_contents);
// Verify that the log buf is empty, and no error messages.
ASSERT_STREQ("", getFakeLogBuf().c_str());
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 375ed8a..0ce5573 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -76,7 +76,7 @@
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,
+ .selinux_label = std::move(selinux_label), .siginfo = siginfo, .signo = siginfo->si_signo,
// Only supported on aarch64 for now.
#if defined(__aarch64__)
.tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0),
@@ -125,10 +125,12 @@
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) {
+ std::string* amfd_data, const Architecture* guest_arch,
+ unwindstack::AndroidUnwinder* guest_unwinder) {
// Don't copy log messages to tombstone unless this is a development device.
Tombstone tombstone;
- engrave_tombstone_proto(&tombstone, unwinder, threads, target_thread, process_info, open_files);
+ engrave_tombstone_proto(&tombstone, unwinder, threads, target_thread, process_info, open_files,
+ guest_arch, guest_unwinder);
if (proto_fd != -1) {
if (!tombstone.SerializeToFileDescriptor(proto_fd.get())) {
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index 74f9a8c..3e8ab6e 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -203,7 +203,7 @@
}
static void dump_probable_cause(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
- const ProcessInfo& process_info, const ThreadInfo& main_thread) {
+ const ProcessInfo& process_info, const ThreadInfo& target_thread) {
#if defined(USE_SCUDO)
ScudoCrashData scudo_crash_data(unwinder->GetProcessMemory().get(), process_info);
if (scudo_crash_data.CrashIsMine()) {
@@ -213,13 +213,13 @@
#endif
GwpAsanCrashData gwp_asan_crash_data(unwinder->GetProcessMemory().get(), process_info,
- main_thread);
+ target_thread);
if (gwp_asan_crash_data.CrashIsMine()) {
gwp_asan_crash_data.AddCauseProtos(tombstone, unwinder);
return;
}
- const siginfo *si = main_thread.siginfo;
+ const siginfo *si = target_thread.siginfo;
auto fault_addr = reinterpret_cast<uint64_t>(si->si_addr);
unwindstack::Maps* maps = unwinder->GetMaps();
@@ -238,14 +238,14 @@
} else if (fault_addr == 0xffff0f60) {
cause = "call to kuser_cmpxchg64";
} else {
- cause = get_stack_overflow_cause(fault_addr, main_thread.registers->sp(), maps);
+ cause = get_stack_overflow_cause(fault_addr, target_thread.registers->sp(), maps);
}
} else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
auto map_info = maps->Find(fault_addr);
if (map_info != nullptr && map_info->flags() == PROT_EXEC) {
cause = "execute-only (no-read) memory access error; likely due to data in .text.";
} else {
- cause = get_stack_overflow_cause(fault_addr, main_thread.registers->sp(), maps);
+ cause = get_stack_overflow_cause(fault_addr, target_thread.registers->sp(), maps);
}
} else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
@@ -482,7 +482,8 @@
}
static void dump_thread(Tombstone* tombstone, unwindstack::AndroidUnwinder* unwinder,
- const ThreadInfo& thread_info, bool memory_dump = false) {
+ const ThreadInfo& thread_info, bool memory_dump = false,
+ unwindstack::AndroidUnwinder* guest_unwinder = nullptr) {
Thread thread;
thread.set_id(thread_info.tid);
@@ -509,6 +510,27 @@
auto& threads = *tombstone->mutable_threads();
threads[thread_info.tid] = thread;
+
+ if (guest_unwinder) {
+ if (!thread_info.guest_registers) {
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+ "No guest state registers information for tid %d", thread_info.tid);
+ return;
+ }
+ Thread guest_thread;
+ unwindstack::AndroidUnwinderData guest_data;
+ guest_data.saved_initial_regs = std::make_optional<std::unique_ptr<unwindstack::Regs>>();
+ if (guest_unwinder->Unwind(thread_info.guest_registers.get(), guest_data)) {
+ dump_thread_backtrace(guest_data.frames, guest_thread);
+ } else {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Unwind guest state registers failed for tid %d: Error %s",
+ thread_info.tid, guest_data.GetErrorString().c_str());
+ }
+ dump_registers(guest_unwinder, *guest_data.saved_initial_regs, guest_thread, memory_dump);
+ auto& guest_threads = *tombstone->mutable_guest_threads();
+ guest_threads[thread_info.tid] = guest_thread;
+ }
}
static void dump_mappings(Tombstone* tombstone, unwindstack::Maps* maps,
@@ -685,28 +707,35 @@
}
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) {
+ const std::map<pid_t, ThreadInfo>& threads, pid_t target_tid,
+ const ProcessInfo& process_info, const OpenFilesList* open_files,
+ const Architecture* guest_arch,
+ unwindstack::AndroidUnwinder* guest_unwinder) {
Tombstone result;
result.set_arch(get_arch());
+ if (guest_arch != nullptr) {
+ result.set_guest_arch(*guest_arch);
+ } else {
+ result.set_guest_arch(Architecture::NONE);
+ }
result.set_build_fingerprint(android::base::GetProperty("ro.build.fingerprint", "unknown"));
result.set_revision(android::base::GetProperty("ro.revision", "unknown"));
result.set_timestamp(get_timestamp());
- const ThreadInfo& main_thread = threads.at(target_thread);
- result.set_pid(main_thread.pid);
- result.set_tid(main_thread.tid);
- result.set_uid(main_thread.uid);
- result.set_selinux_label(main_thread.selinux_label);
+ const ThreadInfo& target_thread = threads.at(target_tid);
+ result.set_pid(target_thread.pid);
+ result.set_tid(target_thread.tid);
+ result.set_uid(target_thread.uid);
+ result.set_selinux_label(target_thread.selinux_label);
// The main thread must have a valid siginfo.
- CHECK(main_thread.siginfo != nullptr);
+ CHECK(target_thread.siginfo != nullptr);
struct sysinfo si;
sysinfo(&si);
android::procinfo::ProcessInfo proc_info;
std::string error;
- if (android::procinfo::GetProcessInfo(main_thread.pid, &proc_info, &error)) {
+ if (android::procinfo::GetProcessInfo(target_thread.pid, &proc_info, &error)) {
uint64_t starttime = proc_info.starttime / sysconf(_SC_CLK_TCK);
result.set_process_uptime(si.uptime - starttime);
} else {
@@ -714,25 +743,28 @@
error.c_str());
}
+ result.set_page_size(getpagesize());
+ result.set_has_been_16kb_mode(android::base::GetBoolProperty("ro.misctrl.16kb_before", false));
+
auto cmd_line = result.mutable_command_line();
- for (const auto& arg : main_thread.command_line) {
+ for (const auto& arg : target_thread.command_line) {
*cmd_line->Add() = arg;
}
- if (!main_thread.siginfo) {
+ if (!target_thread.siginfo) {
async_safe_fatal("siginfo missing");
}
Signal sig;
- sig.set_number(main_thread.signo);
- sig.set_name(get_signame(main_thread.siginfo));
- sig.set_code(main_thread.siginfo->si_code);
- sig.set_code_name(get_sigcode(main_thread.siginfo));
+ sig.set_number(target_thread.signo);
+ sig.set_name(get_signame(target_thread.siginfo));
+ sig.set_code(target_thread.siginfo->si_code);
+ sig.set_code_name(get_sigcode(target_thread.siginfo));
- if (signal_has_sender(main_thread.siginfo, main_thread.pid)) {
+ if (signal_has_sender(target_thread.siginfo, target_thread.pid)) {
sig.set_has_sender(true);
- sig.set_sender_uid(main_thread.siginfo->si_uid);
- sig.set_sender_pid(main_thread.siginfo->si_pid);
+ sig.set_sender_uid(target_thread.siginfo->si_uid);
+ sig.set_sender_pid(target_thread.siginfo->si_pid);
}
if (process_info.has_fault_address) {
@@ -746,28 +778,28 @@
dump_abort_message(&result, unwinder->GetProcessMemory(), process_info);
dump_crash_details(&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);
+ // Dump the target thread, but save the memory around the registers.
+ dump_thread(&result, unwinder, target_thread, /* memory_dump */ true, guest_unwinder);
for (const auto& [tid, thread_info] : threads) {
- if (tid != target_thread) {
- dump_thread(&result, unwinder, thread_info);
+ if (tid != target_tid) {
+ dump_thread(&result, unwinder, thread_info, /* memory_dump */ false, guest_unwinder);
}
}
- dump_probable_cause(&result, unwinder, process_info, main_thread);
+ dump_probable_cause(&result, unwinder, process_info, target_thread);
dump_mappings(&result, unwinder->GetMaps(), unwinder->GetProcessMemory());
// Only dump logs on debuggable devices.
if (android::base::GetBoolProperty("ro.debuggable", false)) {
// Get the thread that corresponds to the main pid of the process.
- const ThreadInfo& thread = threads.at(main_thread.pid);
+ const ThreadInfo& thread = threads.at(target_thread.pid);
// Do not attempt to dump logs of the logd process because the gathering
// of logs can hang until a timeout occurs.
if (thread.thread_name != "logd") {
- dump_logcat(&result, main_thread.pid);
+ dump_logcat(&result, target_thread.pid);
}
}
diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
index cefa2d6..1900719 100644
--- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
@@ -79,8 +79,8 @@
return describe_end(value, desc);
}
-static const char* abi_string(const Tombstone& tombstone) {
- switch (tombstone.arch()) {
+static const char* abi_string(const Architecture& arch) {
+ switch (arch) {
case Architecture::ARM32:
return "arm";
case Architecture::ARM64:
@@ -578,14 +578,38 @@
}
}
+static void print_guest_thread(CallbackType callback, const Tombstone& tombstone,
+ const Thread& guest_thread, pid_t tid, bool should_log) {
+ CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
+ CBS("Guest thread information for tid: %d", tid);
+ print_thread_registers(callback, tombstone, guest_thread, should_log);
+
+ CBS("");
+ CB(true, "%d total frames", guest_thread.current_backtrace().size());
+ CB(true, "backtrace:");
+ print_backtrace(callback, tombstone, guest_thread.current_backtrace(), should_log);
+
+ print_thread_memory_dump(callback, tombstone, guest_thread);
+}
+
bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) {
CBL("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***");
CBL("Build fingerprint: '%s'", tombstone.build_fingerprint().c_str());
CBL("Revision: '%s'", tombstone.revision().c_str());
- CBL("ABI: '%s'", abi_string(tombstone));
+ CBL("ABI: '%s'", abi_string(tombstone.arch()));
+ if (tombstone.guest_arch() != Architecture::NONE) {
+ CBL("Guest architecture: '%s'", abi_string(tombstone.guest_arch()));
+ }
CBL("Timestamp: %s", tombstone.timestamp().c_str());
CBL("Process uptime: %ds", tombstone.process_uptime());
+ // only print this info if the page size is not 4k or has been in 16k mode
+ if (tombstone.page_size() != 4096) {
+ CBL("Page size: %d bytes", tombstone.page_size());
+ } else if (tombstone.has_been_16kb_mode()) {
+ CBL("Has been in 16kb mode: yes");
+ }
+
// Process header
const auto& threads = tombstone.threads();
auto main_thread_it = threads.find(tombstone.tid());
@@ -600,6 +624,12 @@
print_logs(callback, tombstone, 50);
+ const auto& guest_threads = tombstone.guest_threads();
+ auto main_guest_thread_it = guest_threads.find(tombstone.tid());
+ if (main_guest_thread_it != threads.end()) {
+ print_guest_thread(callback, tombstone, main_guest_thread_it->second, tombstone.tid(), true);
+ }
+
// protobuf's map is unordered, so sort the keys first.
std::set<int> thread_ids;
for (const auto& [tid, _] : threads) {
@@ -611,6 +641,10 @@
for (const auto& tid : thread_ids) {
CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---");
print_thread(callback, tombstone, threads.find(tid)->second);
+ auto guest_thread_it = guest_threads.find(tid);
+ if (guest_thread_it != guest_threads.end()) {
+ print_guest_thread(callback, tombstone, guest_thread_it->second, tid, false);
+ }
}
if (tombstone.open_fds().size() > 0) {
diff --git a/debuggerd/proto/tombstone.proto b/debuggerd/proto/tombstone.proto
index 214cbfb..6f9cd96 100644
--- a/debuggerd/proto/tombstone.proto
+++ b/debuggerd/proto/tombstone.proto
@@ -22,6 +22,7 @@
message Tombstone {
Architecture arch = 1;
+ Architecture guest_arch = 24;
string build_fingerprint = 2;
string revision = 3;
string timestamp = 4;
@@ -42,11 +43,15 @@
repeated Cause causes = 15;
map<uint32, Thread> threads = 16;
+ map<uint32, Thread> guest_threads = 25;
repeated MemoryMapping memory_mappings = 17;
repeated LogBuffer log_buffers = 18;
repeated FD open_fds = 19;
- reserved 22 to 999;
+ uint32 page_size = 22;
+ bool has_been_16kb_mode = 23;
+
+ reserved 26 to 999;
}
enum Architecture {
@@ -55,8 +60,9 @@
X86 = 2;
X86_64 = 3;
RISCV64 = 4;
+ NONE = 5;
- reserved 5 to 999;
+ reserved 6 to 999;
}
message Signal {
diff --git a/debuggerd/test_permissive_mte/AndroidTest.xml b/debuggerd/test_permissive_mte/AndroidTest.xml
index bd3d018..db5f5b8 100644
--- a/debuggerd/test_permissive_mte/AndroidTest.xml
+++ b/debuggerd/test_permissive_mte/AndroidTest.xml
@@ -17,8 +17,6 @@
<option name="test-suite-tag" value="init_test_upgrade_mte" />
<option name="test-suite-tag" value="apct" />
- <!-- For tombstone inspection. -->
- <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="mte_crash->/data/local/tmp/mte_crash" />
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8c0c1ef..7f41cea 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -40,6 +40,7 @@
#include <functional>
#include <map>
#include <memory>
+#include <numeric>
#include <string>
#include <string_view>
#include <thread>
@@ -1553,7 +1554,9 @@
fs_mgr_set_blk_ro(attempted_entry.blk_device, false);
if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.blk_device,
attempted_entry.mount_point, wiped ? "true" : "false",
- attempted_entry.fs_type, attempted_entry.zoned_device},
+ attempted_entry.fs_type,
+ attempted_entry.fs_mgr_flags.is_zoned ? "true" : "false",
+ android::base::Join(attempted_entry.user_devices, ' ')},
nullptr)) {
LERROR << "Encryption failed";
set_type_property(encryptable);
@@ -1596,7 +1599,9 @@
if (!call_vdc({"cryptfs", "encryptFstab", current_entry.blk_device,
current_entry.mount_point, "true" /* shouldFormat */,
- current_entry.fs_type, current_entry.zoned_device},
+ current_entry.fs_type,
+ current_entry.fs_mgr_flags.is_zoned ? "true" : "false",
+ android::base::Join(current_entry.user_devices, ' ')},
nullptr)) {
LERROR << "Encryption failed";
} else {
@@ -1621,7 +1626,9 @@
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.zoned_device},
+ attempted_entry.mount_point,
+ current_entry.fs_mgr_flags.is_zoned ? "true" : "false",
+ android::base::Join(current_entry.user_devices, ' ')},
nullptr)) {
++error_count;
} else if (current_entry.mount_point == "/data") {
@@ -1649,6 +1656,19 @@
continue;
}
}
+ if (userdata_mounted) {
+ Fstab mounted_fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &mounted_fstab)) {
+ LOG(ERROR) << "Could't load fstab from /proc/mounts , unable to set ro.fstype.data . "
+ "init.rc actions depending on this prop would not run, boot might fail.";
+ } else {
+ for (const auto& entry : mounted_fstab) {
+ if (entry.mount_point == "/data") {
+ android::base::SetProperty("ro.fstype.data", entry.fs_type);
+ }
+ }
+ }
+ }
set_type_property(encryptable);
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 8e76150..0dde1d3 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -125,7 +125,8 @@
}
static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs_projid,
- bool needs_casefold, bool fs_compress, const std::string& zoned_device) {
+ bool needs_casefold, bool fs_compress, bool is_zoned,
+ const std::vector<std::string>& user_devices) {
if (!dev_sz) {
int rc = get_dev_sz(fs_blkdev, &dev_sz);
if (rc) {
@@ -159,16 +160,21 @@
args.push_back(block_size.c_str());
args.push_back("-b");
args.push_back(block_size.c_str());
- if (!zoned_device.empty()) {
- args.push_back("-c");
- args.push_back(zoned_device.c_str());
+
+ if (is_zoned) {
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());
+ }
+ for (auto& device : user_devices) {
+ args.push_back("-c");
+ args.push_back(device.c_str());
}
+ if (user_devices.empty()) {
+ args.push_back(fs_blkdev.c_str());
+ args.push_back(size_str.c_str());
+ } else {
+ args.push_back(fs_blkdev.c_str());
+ }
return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, false, nullptr);
}
@@ -184,7 +190,8 @@
if (entry.fs_type == "f2fs") {
return format_f2fs(entry.blk_device, entry.length, needs_projid, needs_casefold,
- entry.fs_mgr_flags.fs_compress, entry.zoned_device);
+ entry.fs_mgr_flags.fs_compress, entry.fs_mgr_flags.is_zoned,
+ entry.user_devices);
} 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/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp
index 6fa22fe..f00e0dc 100644
--- a/fs_mgr/libfstab/fstab.cpp
+++ b/fs_mgr/libfstab/fstab.cpp
@@ -147,6 +147,29 @@
entry->fs_options = std::move(fs_options);
}
+void ParseUserDevices(const std::string& arg, FstabEntry* entry) {
+ auto param = Split(arg, ":");
+ if (param.size() != 2) {
+ LWARNING << "Warning: device= malformed: " << arg;
+ return;
+ }
+
+ if (access(param[1].c_str(), F_OK) != 0) {
+ LWARNING << "Warning: device does not exist : " << param[1];
+ return;
+ }
+
+ if (param[0] == "zoned") {
+ // atgc in f2fs does not support a zoned device
+ auto options = Split(entry->fs_options, ",");
+ options.erase(std::remove(options.begin(), options.end(), "atgc"), options.end());
+ entry->fs_options = android::base::Join(options, ",");
+ LINFO << "Removed ATGC in fs_options as " << entry->fs_options << " for zoned device";
+ entry->fs_mgr_flags.is_zoned = true;
+ }
+ entry->user_devices.push_back(param[1]);
+}
+
bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
for (const auto& flag : Split(flags, ",")) {
if (flag.empty() || flag == "defaults") continue;
@@ -311,17 +334,8 @@
if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
}
- } else if (flag == "zoned_device") {
- if (access("/dev/block/by-name/zoned_device", F_OK) == 0) {
- entry->zoned_device = "/dev/block/by-name/zoned_device";
-
- // atgc in f2fs does not support a zoned device
- auto options = Split(entry->fs_options, ",");
- options.erase(std::remove(options.begin(), options.end(), "atgc"), options.end());
- entry->fs_options = android::base::Join(options, ",");
- LINFO << "Removed ATGC in fs_options as " << entry->fs_options
- << " for zoned device=" << entry->zoned_device;
- }
+ } else if (StartsWith(flag, "device=")) {
+ ParseUserDevices(arg, entry);
} else {
LWARNING << "Warning: unknown flag: " << flag;
}
@@ -849,6 +863,14 @@
[&path](const FstabEntry& entry) { return entry.mount_point == path; });
}
+FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string_view path,
+ const std::string_view fstype) {
+ auto&& vec = GetEntriesByPred(fstab, [&path, fstype](const FstabEntry& entry) {
+ return entry.mount_point == path && entry.fs_type == fstype;
+ });
+ return vec.empty() ? nullptr : vec.front();
+}
+
std::vector<const FstabEntry*> GetEntriesForMountPoint(const Fstab* fstab,
const std::string& path) {
return GetEntriesByPred(fstab,
diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h
index 5e4019c..1696daf 100644
--- a/fs_mgr/libfstab/include/fstab/fstab.h
+++ b/fs_mgr/libfstab/include/fstab/fstab.h
@@ -32,7 +32,7 @@
struct FstabEntry {
std::string blk_device;
- std::string zoned_device;
+ std::vector<std::string> user_devices;
std::string logical_partition_name;
std::string mount_point;
std::string fs_type;
@@ -85,6 +85,7 @@
bool ext_meta_csum : 1;
bool fs_compress : 1;
bool overlayfs_remove_missing_lowerdir : 1;
+ bool is_zoned : 1;
} fs_mgr_flags = {};
bool is_encryptable() const { return fs_mgr_flags.crypt; }
@@ -108,6 +109,9 @@
FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
const FstabEntry* GetEntryForMountPoint(const Fstab* fstab, const std::string& path);
+FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string_view path,
+ const std::string_view fstype);
+
// This method builds DSU fstab entries and transfer the fstab.
//
// fstab points to the unmodified fstab.
diff --git a/fs_mgr/liblp/fuzzer/Android.bp b/fs_mgr/liblp/fuzzer/Android.bp
index a9e3509..46bd031 100644
--- a/fs_mgr/liblp/fuzzer/Android.bp
+++ b/fs_mgr/liblp/fuzzer/Android.bp
@@ -15,6 +15,10 @@
*
*/
+package {
+ default_team: "trendy_team_android_kernel",
+}
+
cc_defaults {
name: "liblp_fuzz_defaults",
header_libs: [
@@ -33,7 +37,7 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-systems-storage@google.com",
],
componentid: 59148,
hotlists: ["4593311"],
@@ -41,8 +45,8 @@
vector: "local_no_privileges_required",
service_privilege: "privileged",
users: "multi_user",
- fuzzed_code_usage: "shipped"
- }
+ fuzzed_code_usage: "shipped",
+ },
}
cc_fuzz {
@@ -196,6 +200,6 @@
":test_vendor_boot_v4_with_frag",
],
cflags: [
- "-Wno-unused-parameter",
- ],
+ "-Wno-unused-parameter",
+ ],
}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 914b4a6..402eb82 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -503,6 +503,8 @@
enabled: false,
},
},
+ stl: "libc++_static",
+ static_executable: true,
}
python_library_host {
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 076a918..d04c9c1 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -103,7 +103,7 @@
// The old partition size (if none existed, this will be zero).
uint64 old_partition_size = 10;
- // Compression algorithm (none, gz, lz4, zstd, or brotli).
+ // Compression algorithm (none, lz4, zstd).
string compression_algorithm = 11;
// Estimated COW size from OTA manifest.
@@ -120,6 +120,18 @@
// Max bytes to be compressed at once (4k, 8k, 16k, 32k, 64k, 128k)
uint64 compression_factor = 16;
+
+ // Default value is 32, can be set lower for low mem devices
+ uint32 read_ahead_size = 17;
+
+ // Enable direct reads on source device
+ bool o_direct = 18;
+
+ // Blocks size to be verified at once
+ uint64 verify_block_size = 19;
+
+ // Default value is 2, configures threads to do verification phase
+ uint32 num_verify_threads = 20;
}
// Next: 8
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
index 21dc666..635a38c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_compress.h
@@ -17,6 +17,8 @@
#pragma once
#include <memory>
+#include <vector>
+
#include "libsnapshot/cow_format.h"
namespace android {
@@ -50,4 +52,4 @@
const uint32_t block_size_;
};
} // namespace snapshot
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 6a7153d..991e17c 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -31,15 +31,9 @@
static constexpr uint32_t kCowVersionMajor = 2;
static constexpr uint32_t kCowVersionMinor = 0;
-static constexpr uint32_t kCowVersionManifest = 2;
-
static constexpr uint32_t kMinCowVersion = 1;
static constexpr uint32_t kMaxCowVersion = 3;
-// Normally, this should be kMaxCowVersion. When a new version is under testing
-// it may be the previous value of kMaxCowVersion.
-static constexpr uint32_t kDefaultCowVersion = 2;
-
// This header appears as the first sequence of bytes in the COW. All fields
// in the layout are little-endian encoded. The on-disk layout is:
//
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index 3f49c69..3389f58 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -19,6 +19,7 @@
#include <memory>
#include <optional>
#include <unordered_map>
+#include <vector>
#include <android-base/unique_fd.h>
#include <libsnapshot/cow_format.h>
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
index 10cb06d..f00f236 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/snapshot_reader_test.cpp
@@ -184,7 +184,7 @@
unique_fd cow_fd(dup(cow_->fd));
ASSERT_GE(cow_fd, 0);
- auto writer = CreateCowWriter(kDefaultCowVersion, options, std::move(cow_fd));
+ auto writer = CreateCowWriter(2, options, std::move(cow_fd));
ASSERT_NO_FATAL_FAILURE(WriteCow(writer.get()));
ASSERT_NO_FATAL_FAILURE(TestReads(writer.get()));
}
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
index 95398e4..1117ec9 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp
@@ -731,7 +731,8 @@
i += chunk;
}
if (total_written != total_data_size) {
- PLOG(ERROR) << "write failed for data of size: " << data.size()
+ PLOG(ERROR) << "write failed for data vector of size: " << data.size()
+ << " and total data length: " << total_data_size
<< " at offset: " << next_data_pos_ << " " << errno
<< ", only wrote: " << total_written;
return false;
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.h b/fs_mgr/libsnapshot/partition_cow_creator.h
index cbd664f..a75d993 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.h
+++ b/fs_mgr/libsnapshot/partition_cow_creator.h
@@ -60,6 +60,7 @@
bool using_snapuserd = false;
std::string compression_algorithm;
uint64_t compression_factor;
+ uint32_t read_ahead_size;
// True if multi-threaded compression should be enabled
bool enable_threading;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 7ca53ad..8620620 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -101,8 +101,7 @@
* time, they could use O_DIRECT functionality wherein the I/O to the source
* block device will be O_DIRECT.
*/
-static constexpr auto kCowReadAheadSizeKb = 32;
-static constexpr auto kSourceReadAheadSizeKb = 32;
+static constexpr auto kReadAheadSizeKb = 32;
// Note: IImageManager is an incomplete type in the header, so the default
// destructor doesn't work.
@@ -418,6 +417,7 @@
status->set_using_snapuserd(cow_creator->using_snapuserd);
status->set_compression_algorithm(cow_creator->compression_algorithm);
status->set_compression_factor(cow_creator->compression_factor);
+ status->set_read_ahead_size(cow_creator->read_ahead_size);
if (cow_creator->enable_threading) {
status->set_enable_threading(cow_creator->enable_threading);
}
@@ -1142,8 +1142,8 @@
return result;
}
-auto SnapshotManager::CheckMergeState(LockedFile* lock, const std::function<bool()>& before_cancel)
- -> MergeResult {
+auto SnapshotManager::CheckMergeState(LockedFile* lock,
+ const std::function<bool()>& before_cancel) -> MergeResult {
SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
switch (update_status.state()) {
case UpdateState::None:
@@ -1765,9 +1765,8 @@
base_path_merge;
snapuserd_argv->emplace_back(std::move(message));
}
-
- SetReadAheadSize(cow_image_device, kCowReadAheadSizeKb);
- SetReadAheadSize(source_device, kSourceReadAheadSizeKb);
+ SetReadAheadSize(cow_image_device, snapshot_status.read_ahead_size());
+ SetReadAheadSize(source_device, snapshot_status.read_ahead_size());
// Do not attempt to connect to the new snapuserd yet, it hasn't
// been started. We do however want to wait for the misc device
@@ -2852,8 +2851,8 @@
return true;
}
-auto SnapshotManager::OpenFile(const std::string& file, int lock_flags)
- -> std::unique_ptr<LockedFile> {
+auto SnapshotManager::OpenFile(const std::string& file,
+ int lock_flags) -> std::unique_ptr<LockedFile> {
unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
if (fd < 0) {
PLOG(ERROR) << "Open failed: " << file;
@@ -3309,19 +3308,19 @@
LOG(INFO) << "using compression algorithm: " << compression_algorithm
<< ", max compressible block size: " << compression_factor;
}
-
- PartitionCowCreator cow_creator{
- .target_metadata = target_metadata.get(),
- .target_suffix = target_suffix,
- .target_partition = nullptr,
- .current_metadata = current_metadata.get(),
- .current_suffix = current_suffix,
- .update = nullptr,
- .extra_extents = {},
- .using_snapuserd = using_snapuserd,
- .compression_algorithm = compression_algorithm,
- .compression_factor = compression_factor,
- };
+ auto read_ahead_size =
+ android::base::GetUintProperty<uint>("ro.virtual_ab.read_ahead_size", kReadAheadSizeKb);
+ PartitionCowCreator cow_creator{.target_metadata = target_metadata.get(),
+ .target_suffix = target_suffix,
+ .target_partition = nullptr,
+ .current_metadata = current_metadata.get(),
+ .current_suffix = current_suffix,
+ .update = nullptr,
+ .extra_extents = {},
+ .using_snapuserd = using_snapuserd,
+ .compression_algorithm = compression_algorithm,
+ .compression_factor = compression_factor,
+ .read_ahead_size = read_ahead_size};
if (dap_metadata.vabc_feature_set().has_threaded()) {
cow_creator.enable_threading = dap_metadata.vabc_feature_set().threaded();
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
index 711e704..ea11f0e 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
+#include "android-base/properties.h"
#include "merge_worker.h"
#include "read_worker.h"
#include "snapuserd_core.h"
@@ -235,8 +236,10 @@
LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_;
{
+ auto num_merge_threads = android::base::GetUintProperty<uint>(
+ "ro.virtual_ab.num_merge_threads", kMaxMergeThreads);
std::lock_guard<std::mutex> lock(lock_);
- while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) {
+ while (active_merge_threads_ < num_merge_threads && merge_handlers_.size() > 0) {
auto handler = merge_handlers_.front();
merge_handlers_.pop();
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 3013c47..d9cf97f 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
@@ -39,7 +39,7 @@
namespace snapshot {
static constexpr uint32_t kMaxPacketSize = 512;
-static constexpr uint8_t kMaxMergeThreads = 2;
+
static constexpr char kBootSnapshotsWithoutSlotSwitch[] =
"/metadata/ota/snapshot-boot-without-slot-switch";
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index d05df82..56f7b59 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -135,7 +135,7 @@
unique_fd fd(cow_system_->fd);
cow_system_->fd = -1;
- return CreateCowWriter(kDefaultCowVersion, options, std::move(fd));
+ return CreateCowWriter(2, options, std::move(fd));
}
std::unique_ptr<ICowWriter> SnapuserdTestBase::CreateV3Cow() {
diff --git a/init/Android.bp b/init/Android.bp
index c4e74d0..dd1f9aa 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -330,7 +330,7 @@
recovery_available: false,
static_libs: ["libinit.microdroid"],
cflags: ["-DMICRODROID=1"],
- installable: false,
+ no_full_install: true,
visibility: ["//packages/modules/Virtualization/microdroid"],
}
@@ -456,6 +456,7 @@
// First stage init is weird: it may start without stdout/stderr, and no /proc.
hwaddress: false,
+ memtag_stack: false,
},
// Install adb_debug.prop into debug ramdisk.
@@ -479,7 +480,7 @@
"init_first_stage_defaults",
],
cflags: ["-DMICRODROID=1"],
- installable: false,
+ no_full_install: true,
}
phony {
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index 3c7107a..7d00195 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -59,9 +59,10 @@
`subsystem_name` is used to match uevent `SUBSYSTEM` value
-`devname` takes one of two options
+`devname` takes one of three options
1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME`
- 2. `uevent_devpath` specified that the name of the node will be basename uevent `DEVPATH`
+ 2. `uevent_devpath` specifies that the name of the node will be basename uevent `DEVPATH`
+ 3. `sys_name` specifies that the name of the node will be the contents of `/sys/DEVPATH/name`
`dirname` is an optional parameter that specifies a directory within `/dev` where the node will be
created.
diff --git a/init/devices.cpp b/init/devices.cpp
index e76786a..5560c20 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -25,6 +25,7 @@
#include <filesystem>
#include <memory>
#include <string>
+#include <string_view>
#include <thread>
#include <android-base/chrono_utils.h>
@@ -377,8 +378,8 @@
if (FindPlatformDevice(uevent.path, &device)) {
// Skip /devices/platform or /devices/ if present
- static const std::string devices_platform_prefix = "/devices/platform/";
- static const std::string devices_prefix = "/devices/";
+ static constexpr std::string_view devices_platform_prefix = "/devices/platform/";
+ static constexpr std::string_view devices_prefix = "/devices/";
if (StartsWith(device, devices_platform_prefix)) {
device = device.substr(devices_platform_prefix.length());
@@ -434,6 +435,7 @@
if (ReadFileToString("/sys/class/block/" + uevent.device_name + "/queue/zoned", &model) &&
!StartsWith(model, "none")) {
links.emplace_back("/dev/block/by-name/zoned_device");
+ links.emplace_back("/dev/sys/block/by-name/zoned_device");
}
auto last_slash = uevent.path.rfind('/');
@@ -482,11 +484,21 @@
// event.
if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
for (const auto& link : links) {
+ std::string target;
+ if (StartsWith(link, "/dev/block/")) {
+ target = devpath;
+ } else if (StartsWith(link, "/dev/sys/block/")) {
+ target = "/sys/class/block/" + Basename(devpath);
+ } else {
+ LOG(ERROR) << "Unrecognized link type: " << link;
+ continue;
+ }
+
if (!mkdir_recursive(Dirname(link), 0755)) {
PLOG(ERROR) << "Failed to create directory " << Dirname(link);
}
- if (symlink(devpath.c_str(), link.c_str())) {
+ if (symlink(target.c_str(), link.c_str())) {
if (errno != EEXIST) {
PLOG(ERROR) << "Failed to symlink " << devpath << " to " << link;
} else if (std::string link_path;
diff --git a/init/devices.h b/init/devices.h
index f9f4d79..6da1232 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -82,6 +82,7 @@
enum DevnameSource {
DEVNAME_UEVENT_DEVNAME,
DEVNAME_UEVENT_DEVPATH,
+ DEVNAME_SYS_NAME,
};
Subsystem() {}
@@ -92,10 +93,18 @@
// Returns the full path for a uevent of a device that is a member of this subsystem,
// according to the rules parsed from ueventd.rc
std::string ParseDevPath(const Uevent& uevent) const {
- std::string devname = devname_source_ == DEVNAME_UEVENT_DEVNAME
- ? uevent.device_name
- : android::base::Basename(uevent.path);
-
+ std::string devname;
+ if (devname_source_ == DEVNAME_UEVENT_DEVNAME) {
+ devname = uevent.device_name;
+ } else if (devname_source_ == DEVNAME_UEVENT_DEVPATH) {
+ devname = android::base::Basename(uevent.path);
+ } else if (devname_source_ == DEVNAME_SYS_NAME) {
+ if (android::base::ReadFileToString("/sys/" + uevent.path + "/name", &devname)) {
+ devname.pop_back(); // Remove terminating newline
+ } else {
+ devname = uevent.device_name;
+ }
+ }
return dir_name_ + "/" + devname;
}
@@ -118,9 +127,6 @@
virtual ~DeviceHandler() = default;
void HandleUevent(const Uevent& uevent) override;
- void ColdbootDone() override;
-
- std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
// `androidboot.partition_map` allows associating a partition name for a raw block device
// through a comma separated and semicolon deliminated list. For example,
@@ -129,11 +135,13 @@
static std::string GetPartitionNameForDevice(const std::string& device);
private:
+ void ColdbootDone() override;
bool FindPlatformDevice(std::string path, std::string* platform_device_path) const;
std::tuple<mode_t, uid_t, gid_t> GetDevicePermissions(
const std::string& path, const std::vector<std::string>& links) const;
void MakeDevice(const std::string& path, bool block, int major, int minor,
const std::vector<std::string>& links) const;
+ std::vector<std::string> GetBlockDeviceSymlinks(const Uevent& uevent) const;
void HandleDevice(const std::string& action, const std::string& devpath, bool block, int major,
int minor, const std::vector<std::string>& links) const;
void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const;
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index 3c012fe..01957ef 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -264,8 +264,9 @@
return uevent.firmware;
}
-void FirmwareHandler::ProcessFirmwareEvent(const std::string& root,
+void FirmwareHandler::ProcessFirmwareEvent(const std::string& path,
const std::string& firmware) const {
+ std::string root = "/sys" + path;
std::string loading = root + "/loading";
std::string data = root + "/data";
@@ -296,6 +297,7 @@
", fstat failed: " + strerror(errno));
return false;
}
+ LOG(INFO) << "found " << file << " for " << path;
LoadFirmware(firmware, root, fw_fd.get(), sb.st_size, loading_fd.get(), data_fd.get());
return true;
};
@@ -362,7 +364,7 @@
if (pid == 0) {
Timer t;
auto firmware = GetFirmwarePath(uevent);
- ProcessFirmwareEvent("/sys" + uevent.path, firmware);
+ ProcessFirmwareEvent(uevent.path, firmware);
LOG(INFO) << "loading " << uevent.path << " took " << t;
_exit(EXIT_SUCCESS);
}
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index d2f7347..fceb392 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -57,7 +57,7 @@
Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid, gid_t gid,
const Uevent& uevent) const;
std::string GetFirmwarePath(const Uevent& uevent) const;
- void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const;
+ void ProcessFirmwareEvent(const std::string& path, const std::string& firmware) const;
bool ForEachFirmwareDirectory(std::function<bool(const std::string&)> handler) const;
std::vector<std::string> firmware_directories_;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index ae216c6..5d3a273 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -556,11 +556,11 @@
return true;
}
// clang-format off
- const std::array<const char*, 7> args = {
+ const std::array<const char*, 8> args = {
"/system/bin/derive_microdroid_vendor_dice_node",
"--dice-driver", "/dev/open-dice0",
"--microdroid-vendor-disk-image", microdroid_vendor_block_dev->data(),
- "--output", "/microdroid_resources/dice_chain.raw",
+ "--output", "/microdroid_resources/dice_chain.raw", nullptr,
};
// clang-format-on
// ForkExecveAndWaitForCompletion calls waitpid to wait for the fork-ed process to finish.
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 7e8513b..5088273 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -630,7 +630,7 @@
ASSERT_TRUE(parser.ParseConfig(tf.path));
- if (GetIntProperty("ro.vendor.api_level", 0) > __ANDROID_API_U__) {
+ if (GetIntProperty("ro.vendor.api_level", 0) > 202404) {
ASSERT_EQ(1u, parser.parse_error_count());
} else {
ASSERT_EQ(0u, parser.parse_error_count());
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 5a1b63b..0d6eb15 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -453,6 +453,10 @@
SocketConnection* socket, std::string* error) {
auto lock = std::lock_guard{accept_messages_lock};
if (!accept_messages) {
+ // If we're already shutting down and you're asking us to stop something,
+ // just say we did (https://issuetracker.google.com/336223505).
+ if (msg == "stop") return PROP_SUCCESS;
+
*error = "Received control message after shutdown, ignoring";
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
}
@@ -970,6 +974,17 @@
std::string build_fingerprint = GetProperty("ro.product.brand", UNKNOWN);
build_fingerprint += '/';
build_fingerprint += GetProperty("ro.product.name", UNKNOWN);
+
+ // should be set in /product/etc/build.prop
+ // when we have a dev option device, and we've switched the kernel to 16kb mode
+ // we use the same system image, but we've switched out the kernel, so make it
+ // visible at a high level
+ bool has16KbDevOption =
+ android::base::GetBoolProperty("ro.product.build.16k_page.enabled", false);
+ if (has16KbDevOption && getpagesize() == 16384) {
+ build_fingerprint += "_16kb";
+ }
+
build_fingerprint += '/';
build_fingerprint += GetProperty("ro.product.device", UNKNOWN);
build_fingerprint += ':';
diff --git a/init/security.cpp b/init/security.cpp
index 3e15447..a0d63bc 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -114,10 +114,9 @@
return {};
}
#elif defined(__riscv)
- // TODO: sv48 and sv57 have both been added to the kernel, but the kernel
- // still doesn't support more than 24 bits.
- // https://github.com/google/android-riscv64/issues/1
- if (SetMmapRndBitsMin(24, 24, false)) {
+ // riscv64 supports 24 rnd bits with Sv39, and starting with the 6.9 kernel,
+ // 33 bits with Sv48 and Sv57.
+ if (SetMmapRndBitsMin(33, 24, false)) {
return {};
}
#elif defined(__x86_64__)
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 92e350b..de902e6 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -680,12 +680,12 @@
}
if (service_->proc_attr_.parsed_uid == std::nullopt) {
- if (android::base::GetIntProperty("ro.vendor.api_level", 0) > __ANDROID_API_U__) {
+ if (android::base::GetIntProperty("ro.vendor.api_level", 0) > 202404) {
return Error() << "No user specified for service '" << service_->name()
- << "'. Defaults to root.";
+ << "', so it would have been root.";
} else {
LOG(WARNING) << "No user specified for service '" << service_->name()
- << "'. Defaults to root.";
+ << "', so it is root.";
}
}
diff --git a/init/test_upgrade_mte/AndroidTest.xml b/init/test_upgrade_mte/AndroidTest.xml
index b89cde8..e08afc0 100644
--- a/init/test_upgrade_mte/AndroidTest.xml
+++ b/init/test_upgrade_mte/AndroidTest.xml
@@ -20,11 +20,13 @@
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="remount-system" value="true" />
- <option name="push" value="mte_upgrade_test.rc->/system/etc/init/mte_upgrade_test.rc" />
- <option name="push" value="mte_upgrade_test_helper->/system/bin/mte_upgrade_test_helper" />
- <option name="push" value="mte_upgrade_test_helper->/data/local/tmp/app_process64" />
+
+ <option name="push-file" key="mte_upgrade_test.rc" value="/system/etc/init/mte_upgrade_test.rc" />
+ <option name="push-file" key="mte_upgrade_test_helper" value="/system/bin/mte_upgrade_test_helper" />
+ <option name="push-file" key="mte_upgrade_test_helper" value="/data/local/tmp/app_process64" />
+ <option name="post-push" value="chmod 644 /system/etc/init/mte_upgrade_test.rc" />
</target_preparer>
<test class="com.android.tradefed.testtype.HostTest" >
<option name="jar" value="mte_upgrade_test.jar" />
</test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/init/test_upgrade_mte/OWNERS b/init/test_upgrade_mte/OWNERS
new file mode 100644
index 0000000..79625df
--- /dev/null
+++ b/init/test_upgrade_mte/OWNERS
@@ -0,0 +1,5 @@
+fmayer@google.com
+
+eugenis@google.com
+mitchp@google.com
+pcc@google.com
diff --git a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
index 6728cc6..c4b175a 100644
--- a/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
+++ b/init/test_upgrade_mte/mte_upgrade_test_helper.cpp
@@ -22,6 +22,7 @@
#include <sys/prctl.h>
#include <time.h>
#include <unistd.h>
+
#include <memory>
int MaybeDowngrade() {
@@ -65,7 +66,5 @@
// This binary gets run by src/com/android/tests/init/MteUpgradeTest.java, which
// asserts that it crashes as expected.
f[17] = 'x';
- char buf[1];
- read(1, buf, 1);
return 0;
}
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index d34672e..4395d88 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -218,6 +218,10 @@
subsystem_.devname_source_ = Subsystem::DEVNAME_UEVENT_DEVPATH;
return {};
}
+ if (args[1] == "sys_name") {
+ subsystem_.devname_source_ = Subsystem::DEVNAME_SYS_NAME;
+ return {};
+ }
return Error() << "invalid devname '" << args[1] << "'";
}
diff --git a/init/util.cpp b/init/util.cpp
index e5efc7d..375e905 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -570,6 +570,8 @@
{"--recursive", SELINUX_ANDROID_RESTORECON_RECURSE},
{"--skip-ce", SELINUX_ANDROID_RESTORECON_SKIPCE},
{"--cross-filesystems", SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS},
+ {"--force", SELINUX_ANDROID_RESTORECON_FORCE},
+ {"--data-data", SELINUX_ANDROID_RESTORECON_DATADATA},
{0, 0}};
int flag = 0;
diff --git a/janitors/OWNERS b/janitors/OWNERS
index a28737e..c25d9e4 100644
--- a/janitors/OWNERS
+++ b/janitors/OWNERS
@@ -3,4 +3,5 @@
cferris@google.com
dwillemsen@google.com
enh@google.com
+maco@google.com
sadafebrahimi@google.com
diff --git a/libcrypto_utils/Android.bp b/libcrypto_utils/Android.bp
index 2559137..b2af06c 100644
--- a/libcrypto_utils/Android.bp
+++ b/libcrypto_utils/Android.bp
@@ -24,9 +24,6 @@
ramdisk_available: true,
vendor_ramdisk_available: true,
recovery_available: true,
- vndk: {
- enabled: true,
- },
host_supported: true,
srcs: [
"android_pubkey.cpp",
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index b7752d9..e297581 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -129,10 +129,7 @@
cc_library {
name: "libcutils",
defaults: ["libcutils_defaults"],
- vndk: {
- enabled: true,
- support_system_process: true,
- },
+ double_loadable: true,
srcs: [
"config_utils.cpp",
"iosched_policy.cpp",
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 5efe209..2e4b9b4 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -68,10 +68,6 @@
{ 01771, AID_SYSTEM, AID_MISC, 0, "data/misc" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/Music" },
{ 00775, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/benchmarktest" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/benchmarktest64" },
{ 00775, AID_ROOT, AID_ROOT, 0, "data/preloads" },
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
{ 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" },
@@ -143,12 +139,6 @@
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
{ 00644, AID_APP, AID_APP, 0, "data/data/*" },
{ 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" },
- { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest/tests.txt" },
- { 00640, AID_ROOT, AID_SHELL, 0, "data/nativetest64/tests.txt" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest/*" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/benchmarktest/*" },
- { 00750, AID_ROOT, AID_SHELL, 0, "data/benchmarktest64/*" },
{ 00600, AID_ROOT, AID_ROOT, 0, "default.prop" }, // legacy
{ 00600, AID_ROOT, AID_ROOT, 0, "system/etc/prop.default" },
{ 00600, AID_ROOT, AID_ROOT, 0, "odm/build.prop" }, // legacy; only for P release
@@ -217,6 +207,7 @@
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
+ { 00644, AID_ROOT, AID_ROOT, 0, "*.rc" },
{ 00755, AID_ROOT, AID_SHELL, 0, "odm/bin/*" },
{ 00644, AID_ROOT, AID_ROOT, 0, "odm/framework/*" },
{ 00644, AID_ROOT, AID_ROOT, 0, "odm/app/*" },
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 5023c79..1a40da1 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -484,7 +484,11 @@
return false;
}
- if (module_options_[cnd_last].find("load_sequential=1") != std::string::npos) {
+ std::string str = "load_sequential=1";
+ auto it = module_options_[cnd_last].find(str);
+ if (it != std::string::npos) {
+ module_options_[cnd_last].erase(it, it + str.size());
+
if (!LoadWithAliases(cnd_last, true)) {
return false;
}
diff --git a/libnetutils/Android.bp b/libnetutils/Android.bp
index 02bd2e3..0bca662 100644
--- a/libnetutils/Android.bp
+++ b/libnetutils/Android.bp
@@ -18,9 +18,6 @@
cc_library_shared {
name: "libnetutils",
vendor_available: true,
- vndk: {
- enabled: true,
- },
srcs: [
"dhcpclient.c",
diff --git a/libpackagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h
index e89cb54..9bd212a 100644
--- a/libpackagelistparser/include/packagelistparser/packagelistparser.h
+++ b/libpackagelistparser/include/packagelistparser/packagelistparser.h
@@ -33,7 +33,10 @@
/** Package name like "com.android.blah". */
char* name;
- /** Package uid like 10014. */
+ /**
+ * Package uid like 10014.
+ * Note that apexes and SDK libraries may have a bogus 0xffffffff value.
+ */
uid_t uid;
/** Package's AndroidManifest.xml debuggable flag. */
diff --git a/libpackagelistparser/packagelistparser.cpp b/libpackagelistparser/packagelistparser.cpp
index 59c3a74..638cc43 100644
--- a/libpackagelistparser/packagelistparser.cpp
+++ b/libpackagelistparser/packagelistparser.cpp
@@ -63,14 +63,13 @@
}
static bool parse_line(const char* path, size_t line_number, const char* line, pkg_info* info) {
- unsigned long uid;
int debuggable;
char* gid_list;
int profileable_from_shell = 0;
-
int fields =
- sscanf(line, "%ms %lu %d %ms %ms %ms %d %ld", &info->name, &uid, &debuggable, &info->data_dir,
- &info->seinfo, &gid_list, &profileable_from_shell, &info->version_code);
+ sscanf(line, "%ms %u %d %ms %ms %ms %d %ld", &info->name, &info->uid,
+ &debuggable, &info->data_dir, &info->seinfo, &gid_list,
+ &profileable_from_shell, &info->version_code);
// Handle the more complicated gids field and free the temporary string.
bool gids_okay = parse_gids(path, line_number, gid_list, info);
@@ -84,14 +83,7 @@
return false;
}
- // Extra validation.
- if (uid > UID_MAX) {
- ALOGE("%s:%zu: uid %lu > UID_MAX", path, line_number, uid);
- return false;
- }
- info->uid = uid;
-
- // Integer to bool conversions.
+ // Convert integers to bools.
info->debuggable = debuggable;
info->profileable_from_shell = profileable_from_shell;
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index bb855d5..d40be9f 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -72,10 +72,7 @@
recovery_available: true,
vendor_available: true,
product_available: true,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
+ double_loadable: true,
shared_libs: [
"libbase",
"libcgrouprc",
diff --git a/libstats/socket_lazy/Android.bp b/libstats/socket_lazy/Android.bp
index b2cd7b2..241e87a 100644
--- a/libstats/socket_lazy/Android.bp
+++ b/libstats/socket_lazy/Android.bp
@@ -7,6 +7,12 @@
cc_library_static {
name: "libstatssocket_lazy",
+ local_include_dirs: [
+ "include",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
header_libs: [
"libstatssocket_headers",
],
@@ -28,7 +34,10 @@
"-Wall",
"-Werror",
],
- test_suites: ["device-tests", "mts-statsd"],
+ test_suites: [
+ "device-tests",
+ "mts-statsd",
+ ],
test_config: "libstatssocket_lazy_test.xml",
// TODO(b/153588990): Remove when the build system properly separates.
// 32bit and 64bit architectures.
diff --git a/libstats/socket_lazy/include/statssocket_lazy.h b/libstats/socket_lazy/include/statssocket_lazy.h
new file mode 100644
index 0000000..7dda0ba
--- /dev/null
+++ b/libstats/socket_lazy/include/statssocket_lazy.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::statssocket::lazy {
+
+// See if libstatssocket.so is available. Early processes relying on _lazy might not have access
+// to libstatssocket.so when they start before the StatsD APEX is available.
+bool IsAvailable();
+
+} // namespace android::statssocket::lazy
diff --git a/libstats/socket_lazy/libstatssocket_lazy.cpp b/libstats/socket_lazy/libstatssocket_lazy.cpp
index fe94ef2..d907c7e 100644
--- a/libstats/socket_lazy/libstatssocket_lazy.cpp
+++ b/libstats/socket_lazy/libstatssocket_lazy.cpp
@@ -23,8 +23,10 @@
#include "log/log.h"
-#include "stats_event.h"
-#include "stats_socket.h"
+#include <stats_event.h>
+#include <stats_socket.h>
+
+#include "statssocket_lazy.h"
// This file provides a lazy interface to libstatssocket.so to address early boot dependencies.
// Specifically bootanimation, surfaceflinger, and lmkd run before the statsd APEX is loaded and
@@ -77,6 +79,13 @@
return dlopen("libstatssocket.so", dlopen_flags);
}
+namespace android::statssocket::lazy {
+bool IsAvailable() {
+ static const void* handle = LoadLibstatssocket(RTLD_NOW);
+ return handle != nullptr;
+}
+} // namespace android::statssocket::lazy
+
//
// Initialization and symbol binding.
diff --git a/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp b/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp
index 3de6cd7..733f1e4 100644
--- a/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp
+++ b/libstats/socket_lazy/tests/libstatssocket_lazy_test.cpp
@@ -21,6 +21,8 @@
#include "stats_event.h"
#include "stats_socket.h"
+#include "statssocket_lazy.h"
+
// The tests here are just for the case when libstatssocket.so cannot be loaded by
// libstatssocket_lazy.
class LibstatssocketLazyTest : public ::testing::Test {
@@ -57,3 +59,7 @@
TEST_F(LibstatssocketLazyTest, NoLibstatssocketForStatsSocket) {
EXPECT_DEATH(AStatsSocket_close(), kLoadFailed);
}
+
+TEST_F(LibstatssocketLazyTest, IsAvailableFalse) {
+ EXPECT_FALSE(android::statssocket::lazy::IsAvailable());
+}
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index 1b41a6b..842db40 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -5,9 +5,6 @@
cc_library {
name: "libsysutils",
vendor_available: true,
- vndk: {
- enabled: true,
- },
srcs: [
"src/SocketListener.cpp",
diff --git a/libsysutils/include/sysutils/SocketListener.h b/libsysutils/include/sysutils/SocketListener.h
index 67a691a..a7fd09e 100644
--- a/libsysutils/include/sysutils/SocketListener.h
+++ b/libsysutils/include/sysutils/SocketListener.h
@@ -19,6 +19,7 @@
#include <pthread.h>
#include <unordered_map>
+#include <vector>
#include <sysutils/SocketClient.h>
#include "SocketClientCommand.h"
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp
index 9ae73d0..f8a73ad 100644
--- a/libusbhost/Android.bp
+++ b/libusbhost/Android.bp
@@ -21,9 +21,6 @@
cc_library {
name: "libusbhost",
vendor_available: true,
- vndk: {
- enabled: true,
- },
host_supported: true,
srcs: ["usbhost.c"],
cflags: ["-Werror"],
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 1741187..ba19ace 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -183,10 +183,7 @@
name: "libutils",
defaults: ["libutils_impl_defaults"],
- vndk: {
- enabled: true,
- support_system_process: true,
- },
+ double_loadable: true,
target: {
product: {
@@ -228,10 +225,7 @@
// TODO(b/153609531): remove when no longer needed.
native_bridge_supported: true,
min_sdk_version: "29",
- vndk: {
- enabled: true,
- support_system_process: true,
- },
+ double_loadable: true,
header_libs: [
"libbase_headers",
diff --git a/libutils/binder/Android.bp b/libutils/binder/Android.bp
index 60b0cb6..e358391 100644
--- a/libutils/binder/Android.bp
+++ b/libutils/binder/Android.bp
@@ -22,6 +22,12 @@
"VectorImpl.cpp",
],
+ cflags: [
+ "-Winvalid-offsetof",
+ "-Wsequence-point",
+ "-Wzero-as-null-pointer-constant",
+ ],
+
apex_available: [
"//apex_available:anyapex",
"//apex_available:platform",
@@ -41,11 +47,13 @@
cc_library {
name: "libutils_binder",
defaults: ["libutils_binder_impl_defaults"],
+ cmake_snapshot_supported: false,
}
cc_library_shared {
name: "libutils_binder_sdk",
defaults: ["libutils_binder_impl_defaults_nodeps"],
+ cmake_snapshot_supported: true,
header_libs: [
"liblog_stub",
diff --git a/libutils/binder/SharedBuffer.cpp b/libutils/binder/SharedBuffer.cpp
index 3e703db..d16bdb0 100644
--- a/libutils/binder/SharedBuffer.cpp
+++ b/libutils/binder/SharedBuffer.cpp
@@ -75,7 +75,7 @@
LOG_ALWAYS_FATAL_IF((newSize >= (SIZE_MAX - sizeof(SharedBuffer))),
"Invalid buffer size %zu", newSize);
- buf = (SharedBuffer*)realloc(buf, sizeof(SharedBuffer) + newSize);
+ buf = (SharedBuffer*)realloc(reinterpret_cast<void*>(buf), sizeof(SharedBuffer) + newSize);
if (buf != nullptr) {
buf->mSize = newSize;
return buf;
diff --git a/libutils/binder/String16.cpp b/libutils/binder/String16.cpp
index 07a3d23..96e1477 100644
--- a/libutils/binder/String16.cpp
+++ b/libutils/binder/String16.cpp
@@ -22,6 +22,19 @@
#include "SharedBuffer.h"
+#define LIBUTILS_PRAGMA(arg) _Pragma(#arg)
+#if defined(__clang__)
+#define LIBUTILS_PRAGMA_FOR_COMPILER(arg) LIBUTILS_PRAGMA(clang arg)
+#elif defined(__GNUC__)
+#define LIBUTILS_PRAGMA_FOR_COMPILER(arg) LIBUTILS_PRAGMA(GCC arg)
+#else
+#define LIBUTILS_PRAGMA_FOR_COMPILER(arg)
+#endif
+#define LIBUTILS_IGNORE(warning_flag) \
+ LIBUTILS_PRAGMA_FOR_COMPILER(diagnostic push) \
+ LIBUTILS_PRAGMA_FOR_COMPILER(diagnostic ignored warning_flag)
+#define LIBUTILS_IGNORE_END() LIBUTILS_PRAGMA_FOR_COMPILER(diagnostic pop)
+
namespace android {
static const StaticString16 emptyString(u"");
@@ -347,7 +360,9 @@
bool String16::isStaticString() const {
// See String16.h for notes on the memory layout of String16::StaticData and
// SharedBuffer.
+ LIBUTILS_IGNORE("-Winvalid-offsetof")
static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
+ LIBUTILS_IGNORE_END()
const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
return (*(p - 1) & kIsSharedBufferAllocated) == 0;
}
@@ -355,7 +370,9 @@
size_t String16::staticStringSize() const {
// See String16.h for notes on the memory layout of String16::StaticData and
// SharedBuffer.
+ LIBUTILS_IGNORE("-Winvalid-offsetof")
static_assert(sizeof(SharedBuffer) - offsetof(SharedBuffer, mClientMetadata) == 4);
+ LIBUTILS_IGNORE_END()
const uint32_t* p = reinterpret_cast<const uint32_t*>(mString);
return static_cast<size_t>(*(p - 1));
}
diff --git a/libutils/binder/String16_test.cpp b/libutils/binder/String16_test.cpp
index 6f4642e..83cc599 100644
--- a/libutils/binder/String16_test.cpp
+++ b/libutils/binder/String16_test.cpp
@@ -16,6 +16,8 @@
#include <utils/String16.h>
#include <utils/String8.h>
+#include <compare>
+#include <utility>
#include <gtest/gtest.h>
@@ -257,3 +259,45 @@
EXPECT_EQ(NO_MEMORY, s.insert(3, u"", SIZE_MAX));
EXPECT_STR16EQ(u"foo!bar", s.c_str());
}
+
+TEST(String16Test, comparisons) {
+ const char16_t* cstr1 = u"abc";
+ const char16_t* cstr2 = u"def";
+
+ // str1 and str1b will point to different blocks of memory but with equal contents.
+ String16 str1(cstr1);
+ String16 str1b(cstr1);
+ String16 str2(cstr2);
+
+ EXPECT_TRUE((str1 <=> str1b) == 0);
+ EXPECT_FALSE(str1 != str1b);
+ EXPECT_FALSE(str1 < str1b);
+ EXPECT_TRUE(str1 <= str1b);
+ EXPECT_TRUE(str1 == str1b);
+ EXPECT_TRUE(str1 >= str1b);
+ EXPECT_FALSE(str1 > str1b);
+
+ EXPECT_TRUE((str1 <=> str2) < 0);
+ EXPECT_TRUE((str2 <=> str1) > 0);
+ EXPECT_TRUE(str1 != str2);
+ EXPECT_TRUE(str1 < str2);
+ EXPECT_TRUE(str1 <= str2);
+ EXPECT_FALSE(str1 == str2);
+ EXPECT_FALSE(str1 >= str2);
+ EXPECT_FALSE(str1 > str2);
+
+ // Verify that pre-C++20 comparison operators work with a std::pair of a String8, which only
+ // provides <=> in C++20 and up. See b/339775405.
+
+ std::pair<String16, int> pair1(str1, 13);
+ std::pair<String16, int> pair1b(str1b, 13);
+ std::pair<String16, int> pair2(str2, 13);
+
+ EXPECT_TRUE(pair1 == pair1b);
+ EXPECT_FALSE(pair1 < pair1b);
+ EXPECT_FALSE(pair1 > pair1b);
+
+ EXPECT_TRUE(pair1 != pair2);
+ EXPECT_TRUE(pair1 < pair2);
+ EXPECT_FALSE(pair1 > pair2);
+}
diff --git a/libutils/binder/String8_test.cpp b/libutils/binder/String8_test.cpp
index 6f7882a..fc3c329 100644
--- a/libutils/binder/String8_test.cpp
+++ b/libutils/binder/String8_test.cpp
@@ -17,8 +17,10 @@
#define LOG_TAG "String8_test"
#include <log/log.h>
-#include <utils/String8.h>
#include <utils/String16.h>
+#include <utils/String8.h>
+#include <compare>
+#include <utility>
#include <gtest/gtest.h>
@@ -132,3 +134,45 @@
EXPECT_TRUE(s.removeAll("o"));
EXPECT_STREQ("Hell, wrld!", s.c_str());
}
+
+TEST_F(String8Test, comparisons) {
+ const char* cstr1 = "abc";
+ const char* cstr2 = "def";
+
+ // str1 and str1b will point to different blocks of memory but with equal contents.
+ String8 str1(cstr1);
+ String8 str1b(cstr1);
+ String8 str2(cstr2);
+
+ EXPECT_TRUE((str1 <=> str1b) == 0);
+ EXPECT_FALSE(str1 != str1b);
+ EXPECT_FALSE(str1 < str1b);
+ EXPECT_TRUE(str1 <= str1b);
+ EXPECT_TRUE(str1 == str1b);
+ EXPECT_TRUE(str1 >= str1b);
+ EXPECT_FALSE(str1 > str1b);
+
+ EXPECT_TRUE((str1 <=> str2) < 0);
+ EXPECT_TRUE((str2 <=> str1) > 0);
+ EXPECT_TRUE(str1 != str2);
+ EXPECT_TRUE(str1 < str2);
+ EXPECT_TRUE(str1 <= str2);
+ EXPECT_FALSE(str1 == str2);
+ EXPECT_FALSE(str1 >= str2);
+ EXPECT_FALSE(str1 > str2);
+
+ // Verify that pre-C++20 comparison operators work with a std::pair of a String8, which only
+ // provides <=> in C++20 and up. See b/339775405.
+
+ std::pair<String8, int> pair1(str1, 13);
+ std::pair<String8, int> pair1b(str1b, 13);
+ std::pair<String8, int> pair2(str2, 13);
+
+ EXPECT_TRUE(pair1 == pair1b);
+ EXPECT_FALSE(pair1 < pair1b);
+ EXPECT_FALSE(pair1 > pair1b);
+
+ EXPECT_TRUE(pair1 != pair2);
+ EXPECT_TRUE(pair1 < pair2);
+ EXPECT_FALSE(pair1 > pair2);
+}
diff --git a/libutils/binder/include/utils/RefBase.h b/libutils/binder/include/utils/RefBase.h
index f03e1be..b6a8707 100644
--- a/libutils/binder/include/utils/RefBase.h
+++ b/libutils/binder/include/utils/RefBase.h
@@ -555,7 +555,7 @@
wp<T>::wp(T* other)
: m_ptr(other)
{
- m_refs = other ? m_refs = other->createWeak(this) : nullptr;
+ m_refs = other ? other->createWeak(this) : nullptr;
}
template <typename T>
@@ -662,8 +662,7 @@
template<typename T> template<typename U>
wp<T>& wp<T>::operator = (const sp<U>& other)
{
- weakref_type* newRefs =
- other != nullptr ? other->createWeak(this) : 0;
+ weakref_type* newRefs = other != nullptr ? other->createWeak(this) : nullptr;
U* otherPtr(other.m_ptr);
if (m_ptr) m_refs->decWeak(this);
m_ptr = otherPtr;
@@ -695,8 +694,8 @@
{
if (m_ptr) {
m_refs->decWeak(this);
- m_refs = 0;
- m_ptr = 0;
+ m_refs = nullptr;
+ m_ptr = nullptr;
}
}
diff --git a/libutils/binder/include/utils/String16.h b/libutils/binder/include/utils/String16.h
index c713576..867dbac 100644
--- a/libutils/binder/include/utils/String16.h
+++ b/libutils/binder/include/utils/String16.h
@@ -29,6 +29,10 @@
#define HAS_STRING_VIEW
#endif
+#if __cplusplus >= 202002L
+#include <compare>
+#endif
+
// ---------------------------------------------------------------------------
namespace android {
@@ -105,6 +109,9 @@
inline bool operator!=(const String16& other) const;
inline bool operator>=(const String16& other) const;
inline bool operator>(const String16& other) const;
+#if __cplusplus >= 202002L
+ inline std::strong_ordering operator<=>(const String16& other) const;
+#endif
inline bool operator<(const char16_t* other) const;
inline bool operator<=(const char16_t* other) const;
@@ -112,6 +119,9 @@
inline bool operator!=(const char16_t* other) const;
inline bool operator>=(const char16_t* other) const;
inline bool operator>(const char16_t* other) const;
+#if __cplusplus >= 202002L
+ inline std::strong_ordering operator<=>(const char16_t* other) const;
+#endif
inline operator const char16_t*() const;
@@ -334,6 +344,19 @@
return strzcmp16(mString, size(), other.mString, other.size()) > 0;
}
+#if __cplusplus >= 202002L
+inline std::strong_ordering String16::operator<=>(const String16& other) const {
+ int result = strzcmp16(mString, size(), other.mString, other.size());
+ if (result == 0) {
+ return std::strong_ordering::equal;
+ } else if (result < 0) {
+ return std::strong_ordering::less;
+ } else {
+ return std::strong_ordering::greater;
+ }
+}
+#endif
+
inline bool String16::operator<(const char16_t* other) const
{
return strcmp16(mString, other) < 0;
@@ -364,6 +387,19 @@
return strcmp16(mString, other) > 0;
}
+#if __cplusplus >= 202002L
+inline std::strong_ordering String16::operator<=>(const char16_t* other) const {
+ int result = strcmp16(mString, other);
+ if (result == 0) {
+ return std::strong_ordering::equal;
+ } else if (result < 0) {
+ return std::strong_ordering::less;
+ } else {
+ return std::strong_ordering::greater;
+ }
+}
+#endif
+
inline String16::operator const char16_t*() const
{
return mString;
diff --git a/libutils/binder/include/utils/String8.h b/libutils/binder/include/utils/String8.h
index 6d25072..e0d7588 100644
--- a/libutils/binder/include/utils/String8.h
+++ b/libutils/binder/include/utils/String8.h
@@ -36,6 +36,10 @@
#define HAS_STRING_VIEW
#endif
+#if __cplusplus >= 202002L
+#include <compare>
+#endif
+
// ---------------------------------------------------------------------------
namespace android {
@@ -106,6 +110,9 @@
inline bool operator!=(const String8& other) const;
inline bool operator>=(const String8& other) const;
inline bool operator>(const String8& other) const;
+#if __cplusplus >= 202002L
+ inline std::strong_ordering operator<=>(const String8& other) const;
+#endif
inline bool operator<(const char* other) const;
inline bool operator<=(const char* other) const;
@@ -113,6 +120,9 @@
inline bool operator!=(const char* other) const;
inline bool operator>=(const char* other) const;
inline bool operator>(const char* other) const;
+#if __cplusplus >= 202002L
+ inline std::strong_ordering operator<=>(const char* other) const;
+#endif
inline operator const char*() const;
@@ -302,6 +312,19 @@
return strcmp(mString, other.mString) > 0;
}
+#if __cplusplus >= 202002L
+inline std::strong_ordering String8::operator<=>(const String8& other) const {
+ int result = strcmp(mString, other.mString);
+ if (result == 0) {
+ return std::strong_ordering::equal;
+ } else if (result < 0) {
+ return std::strong_ordering::less;
+ } else {
+ return std::strong_ordering::greater;
+ }
+}
+#endif
+
inline bool String8::operator<(const char* other) const
{
return strcmp(mString, other) < 0;
@@ -332,6 +355,19 @@
return strcmp(mString, other) > 0;
}
+#if __cplusplus >= 202002L
+inline std::strong_ordering String8::operator<=>(const char* other) const {
+ int result = strcmp(mString, other);
+ if (result == 0) {
+ return std::strong_ordering::equal;
+ } else if (result < 0) {
+ return std::strong_ordering::less;
+ } else {
+ return std::strong_ordering::greater;
+ }
+}
+#endif
+
inline String8::operator const char*() const
{
return mString;
diff --git a/libutils/binder/include/utils/TypeHelpers.h b/libutils/binder/include/utils/TypeHelpers.h
index 1554f52..007036b 100644
--- a/libutils/binder/include/utils/TypeHelpers.h
+++ b/libutils/binder/include/utils/TypeHelpers.h
@@ -109,6 +109,11 @@
ANDROID_BASIC_TYPES_TRAITS( float )
ANDROID_BASIC_TYPES_TRAITS( double )
+template<typename T> struct trait_trivial_ctor<T*> { enum { value = true }; };
+template<typename T> struct trait_trivial_dtor<T*> { enum { value = true }; };
+template<typename T> struct trait_trivial_copy<T*> { enum { value = true }; };
+template<typename T> struct trait_trivial_move<T*> { enum { value = true }; };
+
// ---------------------------------------------------------------------------
@@ -195,7 +200,7 @@
typename std::enable_if<use_trivial_move<TYPE>::value>::type
inline
move_forward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- memmove(d, s, n*sizeof(TYPE));
+ memmove(reinterpret_cast<void*>(d), s, n * sizeof(TYPE));
}
template<typename TYPE>
@@ -222,7 +227,7 @@
typename std::enable_if<use_trivial_move<TYPE>::value>::type
inline
move_backward_type(TYPE* d, const TYPE* s, size_t n = 1) {
- memmove(d, s, n*sizeof(TYPE));
+ memmove(reinterpret_cast<void*>(d), s, n * sizeof(TYPE));
}
template<typename TYPE>
diff --git a/libvendorsupport/Android.bp b/libvendorsupport/Android.bp
index e87959e..a22737c 100644
--- a/libvendorsupport/Android.bp
+++ b/libvendorsupport/Android.bp
@@ -23,7 +23,7 @@
llndk: {
symbol_file: "libvendorsupport.map.txt",
},
- srcs: ["version_props.c"],
+ srcs: ["version_props.cpp"],
cflags: [
"-Wall",
"-Werror",
@@ -32,6 +32,7 @@
export_include_dirs: ["include"],
shared_libs: [
"liblog",
+ "libbase",
],
}
diff --git a/libvendorsupport/include/vendorsupport/api_level.h b/libvendorsupport/include/vendorsupport/api_level.h
index d365075..3427bc6 100644
--- a/libvendorsupport/include/vendorsupport/api_level.h
+++ b/libvendorsupport/include/vendorsupport/api_level.h
@@ -44,4 +44,22 @@
*/
int AVendorSupport_getSdkApiLevelOf(int vendorApiLevel);
+#if !defined(__ANDROID_VENDOR__)
+/**
+ * @brief Provide vendor API level to system modules.
+ *
+ * @details
+ * Before deprecating VNDK, system modules read ro.vndk.version to find the
+ * API level that vendor image had implemented. With the VNDK deprecation, this
+ * must be replaced with ro.board.api_level. However, there still are devices
+ * keeping old vendor partitions with the new system upgraded. In this case, the
+ * VNDK version can be used as before.
+ * This API is for platform only.
+ *
+ * @return ro.vndk.version if exist. Otherwise fallback to ro.board.api_level.
+ * 0 if none of these properties are found. This is unexpected, though.
+ */
+int AVendorSupport_getVendorApiLevel();
+#endif // __ANDROID_VENDOR__
+
__END_DECLS
diff --git a/libvendorsupport/version_props.c b/libvendorsupport/version_props.cpp
similarity index 79%
rename from libvendorsupport/version_props.c
rename to libvendorsupport/version_props.cpp
index 835828c..ecba899 100644
--- a/libvendorsupport/version_props.c
+++ b/libvendorsupport/version_props.cpp
@@ -16,6 +16,10 @@
#include <log/log.h>
+#if !defined(__ANDROID_VENDOR__)
+#include <android-base/properties.h>
+#endif
+
int AVendorSupport_getVendorApiLevelOf(int sdkApiLevel) {
if (sdkApiLevel < __ANDROID_API_V__) {
return sdkApiLevel;
@@ -39,3 +43,13 @@
ALOGE("Unexpected vendor api level: %d", vendorApiLevel);
return __INVALID_API_LEVEL;
}
+
+#if !defined(__ANDROID_VENDOR__)
+int AVendorSupport_getVendorApiLevel() {
+ int vendorApiLevel = android::base::GetIntProperty("ro.vndk.version", 0);
+ if (vendorApiLevel) {
+ return vendorApiLevel;
+ }
+ return android::base::GetIntProperty("ro.board.api_level", 0);
+}
+#endif // __ANDROID_VENDOR__
diff --git a/mkbootfs/mkbootfs.c b/mkbootfs/mkbootfs.c
index d3922bf..84a0a4e 100644
--- a/mkbootfs/mkbootfs.c
+++ b/mkbootfs/mkbootfs.c
@@ -402,7 +402,7 @@
static void usage(void)
{
fprintf(stderr,
- "Usage: mkbootfs [-n FILE] [-d DIR|-F FILE] DIR...\n"
+ "Usage: mkbootfs [-n FILE] [-d DIR|-f FILE] DIR...\n"
"\n"
"\t-d, --dirname=DIR: fs-config directory\n"
"\t-f, --file=FILE: Canned configuration file\n"
@@ -410,11 +410,11 @@
"\t-n, --nodes=FILE: Dev nodes description file\n"
"\n"
"Dev nodes description:\n"
- "\t[dir|nod] [perms] [uid] [gid] [c|b] [minor] [major]\n"
+ "\t[dir|nod] [perms] [uid] [gid] [c|b] [major] [minor]\n"
"\tExample:\n"
"\t\t# My device nodes\n"
"\t\tdir dev 0755 0 0\n"
- "\t\tnod dev/null 0600 0 0 c 1 5\n"
+ "\t\tnod dev/null 0600 0 0 c 1 3\n"
);
}
@@ -445,11 +445,6 @@
int num_dirs = argc - optind;
argv += optind;
- if (num_dirs <= 0) {
- usage();
- errx(1, "no directories to process?!");
- }
-
while(num_dirs-- > 0){
char *x = strchr(*argv, '=');
if(x != 0) {
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index 9a64310..bd24f22 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -107,3 +107,17 @@
src: "etc/hosts",
filename: "hosts",
}
+
+prebuilt_etc {
+ name: "init-debug.rc",
+ src: "init-debug.rc",
+ sub_dir: "init",
+}
+
+llndk_libraries_txt {
+ name: "llndk.libraries.txt",
+}
+
+sanitizer_libraries_txt {
+ name: "sanitizer.libraries.txt",
+}
\ No newline at end of file
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 593bb1e..06e8730 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -3,19 +3,6 @@
$(eval $(call declare-1p-copy-files,system/core/rootdir,))
#######################################
-# init-debug.rc
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := init-debug.rc
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init
-
-include $(BUILD_PREBUILT)
-
-#######################################
# asan.options
ifneq ($(filter address,$(SANITIZE_TARGET)),)
@@ -85,9 +72,9 @@
EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS :=
ifeq ($(CLANG_COVERAGE),true)
ifeq ($(CLANG_COVERAGE_CONTINUOUS_MODE),true)
- EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang%c-%20m.profraw
+ EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/local/tmp/clang%c-%20m.profraw
else
- EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/misc/trace/clang-%20m.profraw
+ EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS := export LLVM_PROFILE_FILE /data/local/tmp/clang-%20m.profraw
endif
endif
@@ -224,26 +211,6 @@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE%?$(EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE)?g' $@
#######################################
-# sanitizer.libraries.txt
-include $(CLEAR_VARS)
-LOCAL_MODULE := sanitizer.libraries.txt
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
-LOCAL_MODULE_STEM := $(LOCAL_MODULE)
-include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := \
- $(SANITIZER_STEMS) \
- $(2ND_SANITIZER_STEMS)
-$(LOCAL_BUILT_MODULE):
- @echo "Generate: $@"
- @mkdir -p $(dir $@)
- $(hide) echo -n > $@
- $(hide) $(foreach lib,$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES), \
- echo $(lib) >> $@;)
-
-#######################################
# ramdisk_node_list
include $(CLEAR_VARS)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1af46c1..5953769 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -425,16 +425,6 @@
chown system system /proc/pressure/memory
chmod 0664 /proc/pressure/memory
- # qtaguid will limit access to specific data based on group memberships.
- # net_bw_acct grants impersonation of socket owners.
- # net_bw_stats grants access to other apps' detailed tagged-socket stats.
- chown root net_bw_acct /proc/net/xt_qtaguid/ctrl
- chown root net_bw_stats /proc/net/xt_qtaguid/stats
-
- # Allow everybody to read the xt_qtaguid resource tracking misc dev.
- # This is needed by any process that uses socket tagging.
- chmod 0644 /dev/xt_qtaguid
-
mount bpf bpf /sys/fs/bpf nodev noexec nosuid
# pstore/ramoops previous console log
@@ -647,11 +637,11 @@
mkdir /metadata/aconfig 0775 root system
mkdir /metadata/aconfig/flags 0770 root system
+ mkdir /metadata/aconfig/maps 0775 root system
mkdir /metadata/aconfig/boot 0775 root system
mkdir /metadata/aconfig_test_missions 0775 root system
- exec_start aconfigd-init
- start aconfigd
+ exec_start aconfigd-platform-init
on late-fs
# Ensure that tracefs has the correct permissions.
@@ -666,10 +656,6 @@
exec -- /system/bin/fsverity_init --load-verified-keys
# Only enable the bootreceiver tracing instance for kernels 5.10 and above.
-on late-fs && property:ro.kernel.version=4.9
- setprop bootreceiver.enable 0
-on late-fs && property:ro.kernel.version=4.14
- setprop bootreceiver.enable 0
on late-fs && property:ro.kernel.version=4.19
setprop bootreceiver.enable 0
on late-fs && property:ro.kernel.version=5.4
@@ -884,6 +870,9 @@
mkdir /data/app-lib 0771 system system encryption=Require
mkdir /data/app 0771 system system encryption=Require
+ # Create directory for app metadata files
+ mkdir /data/app-metadata 0700 system system encryption=Require
+
# create directory for updated font files.
mkdir /data/fonts/ 0771 root root encryption=Require
mkdir /data/fonts/files 0771 system system
@@ -972,6 +961,10 @@
mkdir /data/vendor_ce 0551 root root encryption=None
mkdir /data/vendor_de 0551 root root encryption=None
+ # Similar to the top-level CE and DE directories, /data/storage_area must
+ # itself be unencrypted, since it contains encrypted directories.
+ mkdir /data/storage_area 0551 root root encryption=None
+
# 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
@@ -985,8 +978,12 @@
mkdir /data_mirror/data_de 0700 root root
mkdir /data_mirror/misc_ce 0700 root root
mkdir /data_mirror/misc_de 0700 root root
+ mkdir /data_mirror/storage_area 0700 root root
# Create CE and DE data directory for default volume
+ # Not needed for storage_area directory, since this is
+ # not supported for non-default volumes and the path
+ # does not include the volume ID
mkdir /data_mirror/data_ce/null 0700 root root
mkdir /data_mirror/data_de/null 0700 root root
mkdir /data_mirror/misc_ce/null 0700 root root
@@ -1001,6 +998,9 @@
mount none /data/misc_ce /data_mirror/misc_ce/null bind rec
mount none /data/misc_de /data_mirror/misc_de/null bind rec
+ # Also bind mount for the storage area directory (minus the volume ID)
+ mount none /data/storage_area /data_mirror/storage_area bind rec
+
# Create mirror directory for jit profiles
mkdir /data_mirror/cur_profiles 0700 root root
mount none /data/misc/profiles/cur /data_mirror/cur_profiles bind rec
@@ -1031,6 +1031,8 @@
# Wait for apexd to finish activating APEXes before starting more processes.
wait_for_prop apexd.status activated
perform_apex_config
+ exec_start aconfigd-mainline-init
+ start aconfigd
# Create directories for boot animation.
mkdir /data/misc/bootanim 0755 system system
@@ -1341,6 +1343,8 @@
umount /data_mirror/data_ce/null/0
umount /data_mirror/data_ce/null
umount /data_mirror/data_de/null
+ umount /data_mirror/storage_area/0
+ umount /data_mirror/storage_area
umount /data_mirror/cur_profiles
umount /data_mirror/ref_profiles
umount /data_mirror
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index 9a733bb..c7c622e 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -37,7 +37,46 @@
full list for a release by running `toybox` directly.
-## Android 14 ("U")
+## Android 15 (API level 35, "Vanilla Ice Cream")
+
+BSD: fsck\_msdos newfs\_msdos
+
+bzip2: bzcat bzip2 bunzip2
+
+gavinhoward/bc: bc
+
+one-true-awk: awk
+
+toolbox: getevent getprop setprop start stop
+
+toybox ([0.8.11](https://landley.net/toybox/news.html#08-04-2024)-ish):
+[ acpi base64 basename blkdiscard blkid blockdev brctl cal cat chattr
+chcon chgrp chmod chown chroot chrt cksum clear cmp comm cp cpio cut
+date dd devmem df diff dirname dmesg dos2unix du echo egrep env expand
+expr fallocate false fgrep file find flock fmt free freeramdisk fsfreeze
+fsync getconf getenforce **getfattr** getopt **gpiodetect** **gpiofind**
+**gpioget** **gpioinfo** **gpioset** grep groups gunzip gzip head help hostname
+hwclock i2cdetect i2cdump i2cget i2cset **i2ctransfer** iconv id ifconfig
+inotifyd insmod install ionice iorenice iotop kill killall ln load\_policy
+log logger logname losetup ls lsattr lsmod lsof lspci lsusb makedevs
+md5sum **memeater** microcom mkdir mkfifo mknod mkswap mktemp modinfo modprobe
+more mount mountpoint mv nbd-client nc netcat netstat nice nl nohup
+nproc nsenter od partprobe paste patch pgrep pidof ping ping6 pivot\_root
+pkill pmap printenv printf prlimit ps pwd pwdx readelf readlink realpath
+renice restorecon rev rfkill rm rmdir rmmod rtcwake runcon sed sendevent
+seq setenforce **setfattr** setsid sha1sum sha224sum sha256sum sha384sum
+sha512sum sleep sort split stat strings stty swapoff swapon sync sysctl
+tac tail tar taskset tee test time timeout top touch tr traceroute
+traceroute6 true truncate tty tunctl uclampset ulimit umount uname
+uniq unix2dos unlink unshare uptime usleep uudecode uuencode uuidgen
+vconfig vi vmstat watch wc which whoami xargs xxd yes zcat
+
+Note: technically getfattr and setfattr were available in earlier versions,
+but the symlinks were missing until this release, so they were only available
+as `toybox getfattr` and `toybox setfattr` rather than directly.
+
+
+## Android 14 (API level 34, "Upside Down Cake")
BSD: fsck\_msdos newfs\_msdos
@@ -71,7 +110,7 @@
vconfig vi vmstat watch wc which whoami xargs xxd yes zcat
-## Android 13 ("T")
+## Android 13 (33, "Tiramisu")
BSD: fsck\_msdos newfs\_msdos
@@ -105,7 +144,7 @@
vconfig vi vmstat watch wc which whoami xargs xxd yes zcat
-## Android 12 ("S")
+## Android 12 (31, "Snow Cone")
BSD: fsck\_msdos newfs\_msdos
@@ -139,7 +178,7 @@
vmstat watch wc which whoami xargs xxd yes zcat
-## Android 11 ("R")
+## Android 11 (API level 30, "Red Velvet Cake")
BSD: fsck\_msdos newfs\_msdos
@@ -173,7 +212,7 @@
whoami xargs xxd yes zcat
-## Android 10 ("Q")
+## Android 10 (API level 29, "Quince Tart")
BSD: grep fsck\_msdos newfs\_msdos
@@ -205,7 +244,7 @@
wc which whoami xargs xxd yes zcat
-## Android 9.0 (Pie)
+## Android 9.0 (API level 28, "Pie")
BSD: dd grep
@@ -232,7 +271,7 @@
which whoami xargs xxd yes zcat
-## Android 8.0 (Oreo)
+## Android 8.0 (API level 26, "Oreo")
BSD: dd grep
@@ -257,7 +296,7 @@
vmstat wc which whoami xargs xxd yes **zcat**
-## Android 7.0 (Nougat)
+## Android 7.0 (API level 24, "Nougat")
BSD: dd grep
@@ -279,7 +318,7 @@
**uptime** usleep vmstat wc which whoami xargs **xxd** yes
-## Android 6.0 (Marshmallow)
+## Android 6.0 (API level 23, "Marshmallow")
BSD: dd du grep
@@ -300,7 +339,7 @@
vmstat wc which whoami xargs yes
-## Android 5.0 (Lollipop)
+## Android 5.0 (API level 21, "Lollipop")
BSD: cat chown cp dd du grep kill ln mv printenv rm rmdir sleep sync
@@ -312,7 +351,7 @@
top touch umount uptime vmstat watchprops wipe
-## Android 4.4 (KitKat)
+## Android 4.4 (API level 19, "KitKat")
BSD: cat cp dd du grep newfs\_msdos
@@ -324,7 +363,7 @@
stop swapoff swapon sync top touch umount uptime vmstat watchprops wipe
-## Android 4.1-4.3 (JellyBean)
+## Android 4.1-4.3 (API level 16, "Jelly Bean")
BSD: cat cp dd du grep newfs\_msdos
@@ -336,7 +375,7 @@
sync top touch umount uptime vmstat watchprops wipe
-## Android 4.0 (IceCreamSandwich)
+## Android 4.0 (API level 14, "Ice Cream Sandwich")
BSD: cat dd newfs\_msdos
@@ -347,7 +386,7 @@
touch umount uptime vmstat watchprops wipe
-## Android 2.3 (Gingerbread)
+## Android 2.3 (API level 9, "Gingerbread")
BSD: cat dd newfs\_msdos
diff --git a/toolbox/modprobe.cpp b/toolbox/modprobe.cpp
index 45dd9b8..b0e76ea 100644
--- a/toolbox/modprobe.cpp
+++ b/toolbox/modprobe.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <fcntl.h>
#include <getopt.h>
#include <stdlib.h>
@@ -27,6 +28,7 @@
#include <modprobe/modprobe.h>
#include <sys/utsname.h>
+#include <unistd.h>
namespace {
@@ -105,6 +107,11 @@
return 0;
}
+std::string GetPageSizeSuffix() {
+ static const size_t page_size = sysconf(_SC_PAGE_SIZE);
+ return android::base::StringPrintf("_%zuk", page_size / 1024);
+}
+
} // anonymous namespace
extern "C" int modprobe_main(int argc, char** argv) {
@@ -233,6 +240,19 @@
// Allow modules to be directly inside /lib/modules
mod_dirs.emplace_back(LIB_MODULES_PREFIX);
}
+ if (getpagesize() != 4096) {
+ struct utsname uts {};
+ if (uname(&uts)) {
+ PLOG(FATAL) << "Failed to get kernel version";
+ }
+ const auto module_dir = android::base::StringPrintf("/lib/modules/%s%s", uts.release,
+ GetPageSizeSuffix().c_str());
+ struct stat st {};
+ if (stat(module_dir.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
+ mod_dirs.clear();
+ mod_dirs.emplace_back(module_dir);
+ }
+ }
LOG(DEBUG) << "mode is " << mode;
LOG(DEBUG) << "mod_dirs is: " << android::base::Join(mod_dirs, " ");
diff --git a/toolbox/setprop.cpp b/toolbox/setprop.cpp
index acf8c3e..91edf45 100644
--- a/toolbox/setprop.cpp
+++ b/toolbox/setprop.cpp
@@ -58,7 +58,7 @@
}
}
- if (value.size() >= PROP_VALUE_MAX && !StartsWith(value, "ro.")) {
+ if (value.size() >= PROP_VALUE_MAX && !StartsWith(name, "ro.")) {
std::cerr << "Value '" << value << "' is too long, " << value.size()
<< " bytes vs a max of " << PROP_VALUE_MAX << std::endl;
return EXIT_FAILURE;
diff --git a/trusty/OWNERS b/trusty/OWNERS
index 4016792..46f1410 100644
--- a/trusty/OWNERS
+++ b/trusty/OWNERS
@@ -1,11 +1,5 @@
-armellel@google.com
-arve@android.com
-danielangell@google.com
-gmar@google.com
+# include OWNERS from the top level trusty repo
+include trusty:main:/OWNERS
+
mikemcternan@google.com
-mmaurer@google.com
-ncbray@google.com
-swillden@google.com
-thurston@google.com
-trong@google.com
-wenhaowang@google.com
+swillden@google.com
\ No newline at end of file
diff --git a/trusty/line-coverage/coverage.cpp b/trusty/line-coverage/coverage.cpp
index 5f7b3a3..e4db59c 100644
--- a/trusty/line-coverage/coverage.cpp
+++ b/trusty/line-coverage/coverage.cpp
@@ -174,7 +174,7 @@
}
uintptr_t* begin = (uintptr_t*)((char *)shm_ + sizeof(struct control));
- bool ret = WriteFully(output_fd, begin, record_len_);
+ bool ret = WriteFully(output_fd, begin, record_len_ - sizeof(struct control));
if(!ret) {
fprintf(stderr, "Coverage write to file failed\n");
}
diff --git a/trusty/metrics/include/trusty/metrics/tipc.h b/trusty/metrics/include/trusty/metrics/tipc.h
index e2cf57b..b4428d5 100644
--- a/trusty/metrics/include/trusty/metrics/tipc.h
+++ b/trusty/metrics/include/trusty/metrics/tipc.h
@@ -49,6 +49,7 @@
* @METRICS_CMD_REQ_SHIFT: number of bits used by @METRICS_CMD_RESP_BIT
* @METRICS_CMD_REPORT_EVENT_DROP: report gaps in the event stream
* @METRICS_CMD_REPORT_CRASH: report an app crash event
+ * @METRICS_CMD_REPORT_EXIT: report an app exit
* @METRICS_CMD_REPORT_STORAGE_ERROR: report trusty storage error
*/
enum metrics_cmd {
@@ -57,7 +58,8 @@
METRICS_CMD_REPORT_EVENT_DROP = (1 << METRICS_CMD_REQ_SHIFT),
METRICS_CMD_REPORT_CRASH = (2 << METRICS_CMD_REQ_SHIFT),
- METRICS_CMD_REPORT_STORAGE_ERROR = (3 << METRICS_CMD_REQ_SHIFT),
+ METRICS_CMD_REPORT_EXIT = (3 << METRICS_CMD_REQ_SHIFT),
+ METRICS_CMD_REPORT_STORAGE_ERROR = (4 << METRICS_CMD_REQ_SHIFT),
};
/**
@@ -92,9 +94,22 @@
} __attribute__((__packed__));
/**
+ * struct metrics_report_exit_req - arguments of %METRICS_CMD_REPORT_EXIT
+ * requests
+ * @app_id: app_id in the form UUID in ascii format
+ * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ * @exit_code: architecture-specific exit code
+ */
+struct metrics_report_exit_req {
+ char app_id[UUID_STR_SIZE];
+ uint32_t exit_code;
+} __attribute__((__packed__));
+
+/**
* struct metrics_report_crash_req - arguments of %METRICS_CMD_REPORT_CRASH
* requests
- * @app_id: uuid of the app that crashed
+ * @app_id: app_id in the form UUID in ascii format
+ * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
* @crash_reason: architecture-specific code representing the reason for the
* crash
*/
@@ -158,6 +173,7 @@
struct metrics_req req;
union {
struct metrics_report_crash_req crash_args;
+ struct metrics_report_exit_req exit_args;
struct metrics_report_storage_error_req storage_args;
};
} __attribute__((__packed__));
\ No newline at end of file
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 67e935e..6cb72d5 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -41,9 +41,13 @@
static const char* trusty_devname;
static const char* rpmb_devname;
static const char* ss_srv_name = STORAGE_DISK_PROXY_PORT;
+static const char* max_file_size_from;
static enum dev_type dev_type = MMC_RPMB;
+/* List head for storage mapping, elements added at init, and never removed */
+static struct storage_mapping_node* storage_mapping_head;
+
static enum dev_type parse_dev_type(const char* dev_type_name) {
if (!strcmp(dev_type_name, "mmc")) {
return MMC_RPMB;
@@ -58,17 +62,61 @@
}
}
-static const char* _sopts = "hp:d:r:t:";
+static int parse_and_append_file_mapping(const char* file_mapping) {
+ if (file_mapping == NULL) {
+ ALOGE("Provided file mapping is null\n");
+ return -1;
+ }
+ char* file_mapping_dup = strdup(file_mapping);
+ if (file_mapping_dup == NULL) {
+ ALOGE("Couldn't duplicate string: %s\n", file_mapping);
+ return -1;
+ }
+ const char* file_name = strtok(file_mapping_dup, ":");
+ if (file_name == NULL) {
+ ALOGE("No file name found\n");
+ return -1;
+ }
+ const char* backing_storage = strtok(NULL, ":");
+ if (backing_storage == NULL) {
+ ALOGE("No backing storage found\n");
+ return -1;
+ }
+
+ struct storage_mapping_node* new_node = malloc(sizeof(struct storage_mapping_node));
+ if (new_node == NULL) {
+ ALOGE("Couldn't allocate additional storage_mapping_node\n");
+ return -1;
+ }
+ *new_node = (struct storage_mapping_node){.file_name = file_name,
+ .backing_storage = backing_storage,
+ .next = storage_mapping_head,
+ .fd = -1};
+ storage_mapping_head = new_node;
+ return 0;
+}
+
+static const char* _sopts = "hp:d:r:t:m:f:";
static const struct option _lopts[] = {{"help", no_argument, NULL, 'h'},
{"trusty_dev", required_argument, NULL, 'd'},
{"data_path", required_argument, NULL, 'p'},
{"rpmb_dev", required_argument, NULL, 'r'},
{"dev_type", required_argument, NULL, 't'},
+ {"max_file_size_from", required_argument, NULL, 'm'},
+ {"file_storage_mapping", required_argument, NULL, 'f'},
{0, 0, 0, 0}};
static void show_usage_and_exit(int code) {
- ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type>\n");
+ ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev> -t <dev_type> [-m "
+ "<file>] [-f <file>:<mapping>]\n");
ALOGE("Available dev types: mmc, virt\n");
+ ALOGE("-f = Maps secure storage files like `0` and `persist/0`\n"
+ "to block devices. Storageproxyd will handle creating the\n"
+ "appropriate symlinks in the root datapath.\n");
+ ALOGE("-m = Specifies the max size constraint for file backed storages.\n"
+ "The constraint is chosen by giving a file, this allows for passing a\n"
+ "block device for which a max file size can be queried. File based\n"
+ "storages will be constrained to that size as well.\n");
exit(code);
}
@@ -187,6 +235,7 @@
static void parse_args(int argc, char* argv[]) {
int opt;
int oidx = 0;
+ int rc = 0;
while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) {
switch (opt) {
@@ -210,6 +259,18 @@
}
break;
+ case 'f':
+ rc = parse_and_append_file_mapping(optarg);
+ if (rc < 0) {
+ ALOGE("Failed to parse file mapping: %s\n", optarg);
+ show_usage_and_exit(EXIT_FAILURE);
+ }
+ break;
+
+ case 'm':
+ max_file_size_from = strdup(optarg);
+ break;
+
default:
ALOGE("unrecognized option (%c):\n", opt);
show_usage_and_exit(EXIT_FAILURE);
@@ -225,6 +286,12 @@
ALOGI("storage data root: %s\n", ss_data_root);
ALOGI("trusty dev: %s\n", trusty_devname);
ALOGI("rpmb dev: %s\n", rpmb_devname);
+ ALOGI("File Mappings: \n");
+ const struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ ALOGI("\t%s -> %s\n", curr->file_name, curr->backing_storage);
+ }
+ ALOGI("max file size from: %s\n", max_file_size_from ? max_file_size_from : "(unset)");
}
int main(int argc, char* argv[]) {
@@ -252,7 +319,7 @@
ABinderProcess_startThreadPool();
/* initialize secure storage directory */
- rc = storage_init(ss_data_root);
+ rc = storage_init(ss_data_root, storage_mapping_head, max_file_size_from);
if (rc < 0) return EXIT_FAILURE;
/* open rpmb device */
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index 8c8edb7..6d0c616 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <assert.h>
#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
@@ -39,16 +40,20 @@
#define ALTERNATE_DATA_DIR "alternate/"
/* Maximum file size for filesystem backed storage (i.e. not block dev backed storage) */
-#define MAX_FILE_SIZE (0x10000000000)
+static uint64_t max_file_size = 0x10000000000;
enum sync_state {
SS_UNUSED = -1,
- SS_CLEAN = 0,
- SS_DIRTY = 1,
+ SS_CLEAN = 0,
+ SS_DIRTY = 1,
+ SS_CLEAN_NEED_SYMLINK = 2,
};
static const char *ssdir_name;
+/* List head for storage mapping, elements added at init, and never removed */
+static struct storage_mapping_node* storage_mapping_head;
+
/*
* Property set to 1 after we have opened a file under ssdir_name. The backing
* files for both TD and TDP are currently located under /data/vendor/ss and can
@@ -75,24 +80,103 @@
uint8_t data[MAX_READ_SIZE];
} read_rsp;
-static uint32_t insert_fd(int open_flags, int fd)
-{
+static uint32_t insert_fd(int open_flags, int fd, struct storage_mapping_node* node) {
uint32_t handle = fd;
if (handle < FD_TBL_SIZE) {
- fd_state[fd] = SS_CLEAN; /* fd clean */
- if (open_flags & O_TRUNC) {
- fd_state[fd] = SS_DIRTY; /* set fd dirty */
- }
+ fd_state[fd] = SS_CLEAN; /* fd clean */
+ if (open_flags & O_TRUNC) {
+ assert(node == NULL);
+ fd_state[fd] = SS_DIRTY; /* set fd dirty */
+ }
+
+ if (node != NULL) {
+ fd_state[fd] = SS_CLEAN_NEED_SYMLINK;
+ }
} else {
ALOGW("%s: untracked fd %u\n", __func__, fd);
if (open_flags & (O_TRUNC | O_CREAT)) {
fs_state = SS_DIRTY;
}
}
+
+ if (node != NULL) {
+ node->fd = fd;
+ }
+
return handle;
}
+static void clear_fd_symlink_status(uint32_t handle, struct storage_mapping_node* entry) {
+ /* Always clear FD, in case fd is not in FD_TBL */
+ entry->fd = -1;
+
+ if (handle >= FD_TBL_SIZE) {
+ ALOGE("%s: untracked fd=%u\n", __func__, handle);
+ return;
+ }
+
+ if (fd_state[handle] == SS_CLEAN_NEED_SYMLINK) {
+ fd_state[handle] = SS_CLEAN;
+ }
+}
+
+static struct storage_mapping_node* get_pending_symlink_mapping(uint32_t handle) {
+ /* Fast lookup failure, is it in FD TBL */
+ if (handle < FD_TBL_SIZE && fd_state[handle] != SS_CLEAN_NEED_SYMLINK) {
+ return NULL;
+ }
+
+ /* Go find our mapping */
+ struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ if (curr->fd == handle) {
+ return curr;
+ }
+ }
+
+ /* Safety check: state inconsistent if we get here with handle inside table range */
+ assert(handle >= FD_TBL_SIZE);
+
+ return NULL;
+};
+
+static int possibly_symlink_and_clear_mapping(uint32_t handle) {
+ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle);
+ if (entry == NULL) {
+ /* No mappings pending */
+ return 0;
+ }
+
+ /* Create full path */
+ char* path = NULL;
+ int rc = asprintf(&path, "%s/%s", ssdir_name, entry->file_name);
+ if (rc < 0) {
+ ALOGE("%s: asprintf failed\n", __func__);
+ return -1;
+ }
+
+ /* Try and setup the symlinking */
+ ALOGI("Creating symlink %s->%s\n", path, entry->backing_storage);
+ rc = symlink(entry->backing_storage, path);
+ if (rc < 0) {
+ ALOGE("%s: error symlinking %s->%s (%s)\n", __func__, path, entry->backing_storage,
+ strerror(errno));
+ free(path);
+ return rc;
+ }
+ free(path);
+
+ clear_fd_symlink_status(handle, entry);
+
+ return rc;
+}
+
+static bool is_pending_symlink(uint32_t handle) {
+ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle);
+ return entry != NULL;
+}
+
static int lookup_fd(uint32_t handle, bool dirty)
{
if (dirty) {
@@ -107,6 +191,12 @@
static int remove_fd(uint32_t handle)
{
+ /* Cleanup fd in symlink mapping if it exists */
+ struct storage_mapping_node* entry = get_pending_symlink_mapping(handle);
+ if (entry != NULL) {
+ entry->fd = -1;
+ }
+
if (handle < FD_TBL_SIZE) {
fd_state[handle] = SS_UNUSED; /* set to uninstalled */
}
@@ -247,11 +337,73 @@
watch_progress(watcher, "done syncing parent");
}
+static struct storage_mapping_node* get_storage_mapping_entry(const char* source) {
+ struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ if (!strcmp(source, curr->file_name)) {
+ ALOGI("Found backing file %s for %s\n", curr->backing_storage, source);
+ return curr;
+ }
+ }
+ return NULL;
+}
+
+static bool is_backing_storage_mapped(const char* source) {
+ const struct storage_mapping_node* curr = storage_mapping_head;
+ for (; curr != NULL; curr = curr->next) {
+ if (!strcmp(source, curr->backing_storage)) {
+ ALOGI("Backed storage mapping exists for %s\n", curr->backing_storage);
+ return true;
+ }
+ }
+ return false;
+}
+
+/* Attempts to open a backed file, if mapped, without creating the symlink. Symlink will be created
+ * later on the first write. This allows us to continue reporting zero read sizes until the first
+ * write. */
+static int open_possibly_mapped_file(const char* short_path, const char* full_path, int open_flags,
+ struct storage_mapping_node** entry) {
+ /* See if mapping exists, report upstream if there is no mapping. */
+ struct storage_mapping_node* mapping_entry = get_storage_mapping_entry(short_path);
+ if (mapping_entry == NULL) {
+ return TEMP_FAILURE_RETRY(open(full_path, open_flags, S_IRUSR | S_IWUSR));
+ }
+
+ /* Check for existence of root path, we don't allow mappings during early boot */
+ struct stat buf = {0};
+ if (stat(ssdir_name, &buf) != 0) {
+ ALOGW("Root path not accessible yet, refuse to open mappings for now.\n");
+ return -1;
+ }
+
+ /* We don't support exclusive opening of mapped files */
+ if (open_flags & O_EXCL) {
+ ALOGE("Requesting exclusive open on backed storage isn't supported: %s\n", full_path);
+ return -1;
+ }
+
+ /* Try and open mapping file */
+ open_flags &= ~(O_CREAT | O_EXCL);
+ ALOGI("%s Attempting to open mapped file: %s\n", __func__, mapping_entry->backing_storage);
+ int fd =
+ TEMP_FAILURE_RETRY(open(mapping_entry->backing_storage, open_flags, S_IRUSR | S_IWUSR));
+ if (fd < 0) {
+ ALOGE("%s Failed to open mapping file: %s\n", __func__, mapping_entry->backing_storage);
+ return -1;
+ }
+
+ /* Let caller know which entry we used for opening */
+ *entry = mapping_entry;
+ return fd;
+}
+
int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len,
struct watcher* watcher) {
char* path = NULL;
const struct storage_file_open_req *req = r;
struct storage_file_open_resp resp = {0};
+ struct storage_mapping_node* mapping_entry = NULL;
if (req_len < sizeof(*req)) {
ALOGE("%s: invalid request length (%zd < %zd)\n",
@@ -321,14 +473,18 @@
if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
/* create exclusive */
open_flags |= O_CREAT | O_EXCL;
- rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+
+ /* Look for and attempt opening a mapping, else just do normal open. */
+ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry);
} else {
/* try open first */
rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
if (rc == -1 && errno == ENOENT) {
/* then try open with O_CREATE */
open_flags |= O_CREAT;
- rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+
+ /* Look for and attempt opening a mapping, else just do normal open. */
+ rc = open_possibly_mapped_file(req->name, path, open_flags, &mapping_entry);
}
}
@@ -356,7 +512,7 @@
/* at this point rc contains storage file fd */
msg->result = STORAGE_NO_ERROR;
- resp.handle = insert_fd(open_flags, rc);
+ resp.handle = insert_fd(open_flags, rc, mapping_entry);
ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
__func__, path, rc, resp.handle);
@@ -433,6 +589,14 @@
goto err_response;
}
+ /* Handle any delayed symlinking for this handle if any */
+ rc = possibly_symlink_and_clear_mapping(req->handle);
+ if (rc < 0) {
+ ALOGE("Failed to symlink storage\n");
+ msg->result = STORAGE_ERR_GENERIC;
+ goto err_response;
+ }
+
int fd = lookup_fd(req->handle, true);
watch_progress(watcher, "writing");
if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req),
@@ -479,6 +643,14 @@
goto err_response;
}
+ /* If this handle has a delayed symlink we should report 0 size reads until first write occurs
+ */
+ if (is_pending_symlink(req->handle)) {
+ ALOGI("Pending symlink: Forcing read result 0.\n");
+ msg->result = STORAGE_NO_ERROR;
+ return ipc_respond(msg, &read_rsp, sizeof(read_rsp.hdr));
+ }
+
int fd = lookup_fd(req->handle, false);
watch_progress(watcher, "reading");
ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size,
@@ -592,7 +764,7 @@
goto err_response;
}
} else {
- max_size = MAX_FILE_SIZE;
+ max_size = max_file_size;
}
resp.max_size = max_size;
@@ -603,17 +775,79 @@
return ipc_respond(msg, NULL, 0);
}
-int storage_init(const char *dirname)
-{
+int determine_max_file_size(const char* max_file_size_from) {
+ /* Use default if none passed in */
+ if (max_file_size_from == NULL) {
+ ALOGI("No max file source given, continuing to use default: 0x%" PRIx64 "\n",
+ max_file_size);
+ return 0;
+ }
+
+ /* Check that max_file_size_from is part of our mapping list. */
+ if (!is_backing_storage_mapped(max_file_size_from)) {
+ ALOGE("%s: file doesn't match mapped storages (filename=%s)\n", __func__,
+ max_file_size_from);
+ return -1;
+ }
+
+ ALOGI("Using %s to determine max file size.\n", max_file_size_from);
+
+ /* Error if max file size source not found, possible misconfig. */
+ struct stat buf = {0};
+ int rc = stat(max_file_size_from, &buf);
+ if (rc < 0) {
+ ALOGE("%s: error stat'ing file (filename=%s): %s\n", __func__, max_file_size_from,
+ strerror(errno));
+ return -1;
+ }
+
+ /* Currently only support block device as max file size source */
+ if ((buf.st_mode & S_IFMT) != S_IFBLK) {
+ ALOGE("Unsupported max file size source type: %d\n", buf.st_mode);
+ return -1;
+ }
+
+ ALOGI("%s is a block device, determining block device size\n", max_file_size_from);
+ uint64_t max_size = 0;
+ int fd = TEMP_FAILURE_RETRY(open(max_file_size_from, O_RDONLY | O_NONBLOCK));
+ if (fd < 0) {
+ ALOGE("%s: failed to open backing file %s for ioctl: %s\n", __func__, max_file_size_from,
+ strerror(errno));
+ return -1;
+ }
+ rc = ioctl(fd, BLKGETSIZE64, &max_size);
+ if (rc < 0) {
+ ALOGE("%s: error calling ioctl on file (fd=%d): %s\n", __func__, fd, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ max_file_size = max_size;
+
+ ALOGI("Using 0x%" PRIx64 " as max file size\n", max_file_size);
+ return 0;
+}
+
+int storage_init(const char* dirname, struct storage_mapping_node* mappings,
+ const char* max_file_size_from) {
/* If there is an active DSU image, use the alternate fs mode. */
alternate_mode = is_gsi_running();
fs_state = SS_CLEAN;
for (uint i = 0; i < FD_TBL_SIZE; i++) {
- fd_state[i] = SS_UNUSED; /* uninstalled */
+ fd_state[i] = SS_UNUSED; /* uninstalled */
}
ssdir_name = dirname;
+
+ storage_mapping_head = mappings;
+
+ /* Set the max file size based on incoming configuration */
+ int rc = determine_max_file_size(max_file_size_from);
+ if (rc < 0) {
+ return rc;
+ }
+
return 0;
}
@@ -623,17 +857,17 @@
watch_progress(watcher, "sync fd table");
/* sync fd table and reset it to clean state first */
for (uint fd = 0; fd < FD_TBL_SIZE; fd++) {
- if (fd_state[fd] == SS_DIRTY) {
- if (fs_state == SS_CLEAN) {
- /* need to sync individual fd */
- rc = fsync(fd);
- if (rc < 0) {
- ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
- return rc;
- }
- }
- fd_state[fd] = SS_CLEAN; /* set to clean */
- }
+ if (fd_state[fd] == SS_DIRTY) {
+ if (fs_state == SS_CLEAN) {
+ /* need to sync individual fd */
+ rc = fsync(fd);
+ if (rc < 0) {
+ ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
+ return rc;
+ }
+ }
+ fd_state[fd] = SS_CLEAN; /* set to clean */
+ }
}
/* check if we need to sync all filesystems */
diff --git a/trusty/storage/proxy/storage.h b/trusty/storage/proxy/storage.h
index f29fdf2..6dbfe37 100644
--- a/trusty/storage/proxy/storage.h
+++ b/trusty/storage/proxy/storage.h
@@ -21,6 +21,14 @@
/* Defined in watchdog.h */
struct watcher;
+/* Is used for managing alternate backing storage, generally will be a block device. */
+struct storage_mapping_node {
+ struct storage_mapping_node* next;
+ const char* file_name;
+ const char* backing_storage;
+ int fd;
+};
+
int storage_file_delete(struct storage_msg* msg, const void* req, size_t req_len,
struct watcher* watcher);
@@ -45,6 +53,7 @@
int storage_file_get_max_size(struct storage_msg* msg, const void* req, size_t req_len,
struct watcher* watcher);
-int storage_init(const char* dirname);
+int storage_init(const char* dirname, struct storage_mapping_node* head,
+ const char* max_file_size_from);
int storage_sync_checkpoint(struct watcher* watcher);
diff --git a/trusty/utils/coverage-controller/controller.cpp b/trusty/utils/coverage-controller/controller.cpp
index 381a452..f5d70b1 100644
--- a/trusty/utils/coverage-controller/controller.cpp
+++ b/trusty/utils/coverage-controller/controller.cpp
@@ -60,6 +60,7 @@
filename.insert(0, output_dir);
android::base::Result<void> res = record_list_[index]->SaveFile(filename);
counters[index]++;
+ WRITE_ONCE(control->read_buffer_cnt, counters[index]);
}
if(complete_cnt == counters[index] &&
!(flags & FLAG_RUN)) {
diff --git a/trusty/utils/coverage-controller/controller.h b/trusty/utils/coverage-controller/controller.h
index f7789bf..841a1ae 100644
--- a/trusty/utils/coverage-controller/controller.h
+++ b/trusty/utils/coverage-controller/controller.h
@@ -35,9 +35,9 @@
struct control {
/* Written by controller, read by instrumented TA */
uint64_t cntrl_flags;
+ uint64_t read_buffer_cnt;
/* Written by instrumented TA, read by controller */
- uint64_t oper_flags;
uint64_t write_buffer_start_count;
uint64_t write_buffer_complete_count;
};