Merge "[fs_mgr] Use shared libutils for remount"
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 59643d9..68c9aca 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1889,3 +1889,178 @@
ConsumeFd(std::move(output_fd), &result);
ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
}
+
+static std::string format_pointer(uintptr_t ptr) {
+#if defined(__LP64__)
+ return android::base::StringPrintf("%08x'%08x", static_cast<uint32_t>(ptr >> 32),
+ static_cast<uint32_t>(ptr & 0xffffffff));
+#else
+ return android::base::StringPrintf("%08x", static_cast<uint32_t>(ptr & 0xffffffff));
+#endif
+}
+
+static std::string format_pointer(void* ptr) {
+ return format_pointer(reinterpret_cast<uintptr_t>(ptr));
+}
+
+static std::string format_full_pointer(uintptr_t ptr) {
+#if defined(__LP64__)
+ return android::base::StringPrintf("%016" PRIx64, ptr);
+#else
+ return android::base::StringPrintf("%08x", ptr);
+#endif
+}
+
+static std::string format_full_pointer(void* ptr) {
+ return format_full_pointer(reinterpret_cast<uintptr_t>(ptr));
+}
+
+__attribute__((__noinline__)) int crash_call(uintptr_t ptr) {
+ int* crash_ptr = reinterpret_cast<int*>(ptr);
+ *crash_ptr = 1;
+ return *crash_ptr;
+}
+
+// Verify that a fault address before the first map is properly handled.
+TEST_F(CrasherTest, fault_address_before_first_map) {
+ StartProcess([]() {
+ ASSERT_EQ(0, crash_call(0x1024));
+ _exit(0);
+ });
+
+ unique_fd output_fd;
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+
+ int intercept_result;
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+ ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0x1024)");
+
+ ASSERT_MATCH(result, R"(\nmemory map \(.*\):\n)");
+
+ std::string match_str = android::base::StringPrintf(
+ R"(memory map .*:\n--->Fault address falls at %s before any mapped regions\n )",
+ format_pointer(0x1024).c_str());
+ ASSERT_MATCH(result, match_str);
+}
+
+// Verify that a fault address after the last map is properly handled.
+TEST_F(CrasherTest, fault_address_after_last_map) {
+ uintptr_t crash_uptr = untag_address(UINTPTR_MAX - 15);
+ StartProcess([crash_uptr]() {
+ ASSERT_EQ(0, crash_call(crash_uptr));
+ _exit(0);
+ });
+
+ unique_fd output_fd;
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+
+ int intercept_result;
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
+ match_str += android::base::StringPrintf("0x%" PRIxPTR, crash_uptr);
+ ASSERT_MATCH(result, match_str);
+
+ ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
+
+ // Assumes that the open files section comes after the map section.
+ // If that assumption changes, the regex below needs to change.
+ match_str = android::base::StringPrintf(
+ R"(\n--->Fault address falls at %s after any mapped regions\n\nopen files:)",
+ format_pointer(crash_uptr).c_str());
+ ASSERT_MATCH(result, match_str);
+}
+
+// Verify that a fault address between maps is properly handled.
+TEST_F(CrasherTest, fault_address_between_maps) {
+ // Create a map before the fork so it will be present in the child.
+ void* start_ptr =
+ mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ ASSERT_NE(MAP_FAILED, start_ptr);
+ // Unmap the page in the middle.
+ void* middle_ptr =
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + getpagesize());
+ ASSERT_EQ(0, munmap(middle_ptr, getpagesize()));
+
+ StartProcess([middle_ptr]() {
+ ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(middle_ptr)));
+ _exit(0);
+ });
+
+ // Unmap the two maps.
+ ASSERT_EQ(0, munmap(start_ptr, getpagesize()));
+ void* end_ptr =
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(start_ptr) + 2 * getpagesize());
+ ASSERT_EQ(0, munmap(end_ptr, getpagesize()));
+
+ unique_fd output_fd;
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+
+ int intercept_result;
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ std::string match_str = R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr )";
+ match_str += android::base::StringPrintf("%p", middle_ptr);
+ ASSERT_MATCH(result, match_str);
+
+ ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
+
+ match_str = android::base::StringPrintf(
+ R"( %s.*\n--->Fault address falls at %s between mapped regions\n %s)",
+ format_pointer(start_ptr).c_str(), format_pointer(middle_ptr).c_str(),
+ format_pointer(end_ptr).c_str());
+ ASSERT_MATCH(result, match_str);
+}
+
+// Verify that a fault address happens in the correct map.
+TEST_F(CrasherTest, fault_address_in_map) {
+ // Create a map before the fork so it will be present in the child.
+ void* ptr = mmap(nullptr, getpagesize(), 0, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ ASSERT_NE(MAP_FAILED, ptr);
+
+ StartProcess([ptr]() {
+ ASSERT_EQ(0, crash_call(reinterpret_cast<uintptr_t>(ptr)));
+ _exit(0);
+ });
+
+ ASSERT_EQ(0, munmap(ptr, getpagesize()));
+
+ unique_fd output_fd;
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+
+ int intercept_result;
+ FinishIntercept(&intercept_result);
+ ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+ std::string result;
+ ConsumeFd(std::move(output_fd), &result);
+
+ std::string match_str = R"(signal 11 \(SIGSEGV\), code 2 \(SEGV_ACCERR\), fault addr )";
+ match_str += android::base::StringPrintf("%p", ptr);
+ ASSERT_MATCH(result, match_str);
+
+ ASSERT_MATCH(result, R"(\nmemory map \(.*\): \(fault address prefixed with --->)\n)");
+
+ match_str = android::base::StringPrintf(R"(\n--->%s.*\n)", format_pointer(ptr).c_str());
+ ASSERT_MATCH(result, match_str);
+}
diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
index 053299a..681b963 100644
--- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp
@@ -362,8 +362,13 @@
print_thread_memory_dump(callback, tombstone, thread);
CBS("");
- CBS("memory map (%d %s):", tombstone.memory_mappings().size(),
- tombstone.memory_mappings().size() == 1 ? "entry" : "entries");
+
+ // No memory maps to print.
+ if (tombstone.memory_mappings().empty()) {
+ CBS("No memory maps found");
+ return;
+ }
+
int word_size = pointer_width(tombstone);
const auto format_pointer = [word_size](uint64_t ptr) -> std::string {
if (word_size == 8) {
@@ -375,8 +380,41 @@
return StringPrintf("%0*" PRIx64, word_size * 2, ptr);
};
+ std::string memory_map_header =
+ StringPrintf("memory map (%d %s):", tombstone.memory_mappings().size(),
+ tombstone.memory_mappings().size() == 1 ? "entry" : "entries");
+
+ bool has_fault_address = signal_info.has_fault_address();
+ uint64_t fault_address = untag_address(signal_info.fault_address());
+ bool preamble_printed = false;
+ bool printed_fault_address_marker = false;
for (const auto& map : tombstone.memory_mappings()) {
+ if (!preamble_printed) {
+ preamble_printed = true;
+ if (has_fault_address) {
+ if (fault_address < map.begin_address()) {
+ memory_map_header +=
+ StringPrintf("\n--->Fault address falls at %s before any mapped regions",
+ format_pointer(fault_address).c_str());
+ printed_fault_address_marker = true;
+ } else {
+ memory_map_header += " (fault address prefixed with --->)";
+ }
+ }
+ CBS("%s", memory_map_header.c_str());
+ }
+
std::string line = " ";
+ if (has_fault_address && !printed_fault_address_marker) {
+ if (fault_address < map.begin_address()) {
+ printed_fault_address_marker = true;
+ CBS("--->Fault address falls at %s between mapped regions",
+ format_pointer(fault_address).c_str());
+ } else if (fault_address >= map.begin_address() && fault_address < map.end_address()) {
+ printed_fault_address_marker = true;
+ line = "--->";
+ }
+ }
StringAppendF(&line, "%s-%s", format_pointer(map.begin_address()).c_str(),
format_pointer(map.end_address() - 1).c_str());
StringAppendF(&line, " %s%s%s", map.read() ? "r" : "-", map.write() ? "w" : "-",
@@ -398,6 +436,11 @@
CBS("%s", line.c_str());
}
+
+ if (has_fault_address && !printed_fault_address_marker) {
+ CBS("--->Fault address falls at %s after any mapped regions",
+ format_pointer(fault_address).c_str());
+ }
}
void print_logs(CallbackType callback, const Tombstone& tombstone, int tail) {
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 05d8050..02ded1e 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -448,8 +448,10 @@
return;
}
- if (crash->output.text.fd == -1) {
- LOG(WARNING) << "missing output fd";
+ if (crash->output.text.fd < 0) {
+ if (crash->output.text.fd == -1) {
+ LOG(WARNING) << "skipping tombstone file creation due to intercept";
+ }
return;
}
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index 458a7a1..d268a50 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -143,6 +143,13 @@
mke2fs_args.push_back("512");
}
+ if (fsOptions & (1 << FS_OPT_CASEFOLD)) {
+ mke2fs_args.push_back("-O");
+ mke2fs_args.push_back("casefold");
+ mke2fs_args.push_back("-E");
+ mke2fs_args.push_back("encoding=utf8");
+ }
+
mke2fs_args.push_back(fileName);
std::string size_str = std::to_string(partSize / block_size);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index e60da31..d9a0cd9 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -399,6 +399,7 @@
FRIEND_TEST(SnapshotTest, MergeFailureCode);
FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
+ FRIEND_TEST(SnapshotUpdateTest, AddPartition);
FRIEND_TEST(SnapshotUpdateTest, DaemonTransition);
FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index c3db32e..52324ba 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2087,14 +2087,18 @@
if (live_snapshot_status->compression_enabled()) {
// Get the source device (eg the view of the partition from before it was resized).
std::string source_device_path;
- if (!MapSourceDevice(lock, params.GetPartitionName(), remaining_time,
- &source_device_path)) {
- LOG(ERROR) << "Could not map source device for: " << cow_name;
- return false;
- }
+ if (live_snapshot_status->old_partition_size() > 0) {
+ if (!MapSourceDevice(lock, params.GetPartitionName(), remaining_time,
+ &source_device_path)) {
+ LOG(ERROR) << "Could not map source device for: " << cow_name;
+ return false;
+ }
- auto source_device = GetSourceDeviceName(params.GetPartitionName());
- created_devices.EmplaceBack<AutoUnmapDevice>(&dm, source_device);
+ auto source_device = GetSourceDeviceName(params.GetPartitionName());
+ created_devices.EmplaceBack<AutoUnmapDevice>(&dm, source_device);
+ } else {
+ source_device_path = base_path;
+ }
if (!WaitForDevice(source_device_path, remaining_time)) {
return false;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index b2203fe..057e5b19a 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -963,7 +963,7 @@
}
AssertionResult UnmapAll() {
- for (const auto& name : {"sys", "vnd", "prd"}) {
+ for (const auto& name : {"sys", "vnd", "prd", "dlkm"}) {
if (!dm_.DeleteDeviceIfExists(name + "_a"s)) {
return AssertionFailure() << "Cannot unmap " << name << "_a";
}
@@ -2073,6 +2073,70 @@
ASSERT_LT(res.required_size(), 40_MiB);
}
+TEST_F(SnapshotUpdateTest, AddPartition) {
+ // OTA client blindly unmaps all partitions that are possibly mapped.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(sm->UnmapUpdateSnapshot(name));
+ }
+
+ group_->add_partition_names("dlkm");
+
+ auto dlkm = manifest_.add_partitions();
+ dlkm->set_partition_name("dlkm");
+ dlkm->set_estimate_cow_size(2_MiB);
+ SetSize(dlkm, 3_MiB);
+
+ // Grow all partitions. Set |prd| large enough that |sys| and |vnd|'s COWs
+ // fit in super, but not |prd|.
+ constexpr uint64_t partition_size = 3788_KiB;
+ SetSize(sys_, partition_size);
+ SetSize(vnd_, partition_size);
+ SetSize(prd_, partition_size);
+ SetSize(dlkm, partition_size);
+
+ AddOperationForPartitions({sys_, vnd_, prd_, dlkm});
+
+ // Execute the update.
+ ASSERT_TRUE(sm->BeginUpdate());
+ ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+
+ // Write some data to target partitions.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) {
+ ASSERT_TRUE(WriteSnapshotAndHash(name));
+ }
+
+ // Assert that source partitions aren't affected.
+ for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name));
+ }
+
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+ // Simulate shutting down the device.
+ ASSERT_TRUE(UnmapAll());
+
+ // After reboot, init does first stage mount.
+ auto init = NewManagerForFirstStageMount("_b");
+ ASSERT_NE(init, nullptr);
+ ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+
+ // Check that the target partitions have the same content.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name));
+ }
+
+ // Initiate the merge and wait for it to be completed.
+ ASSERT_TRUE(init->InitiateMerge());
+ ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
+
+ // Check that the target partitions have the same content after the merge.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b", "dlkm_b"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name))
+ << "Content of " << name << " changes after the merge";
+ }
+}
+
class AutoKill final {
public:
explicit AutoKill(pid_t pid) : pid_(pid) {}
diff --git a/init/TEST_MAPPING b/init/TEST_MAPPING
index 905d41e..03b9eaa 100644
--- a/init/TEST_MAPPING
+++ b/init/TEST_MAPPING
@@ -5,6 +5,9 @@
},
{
"name": "init_kill_services_test"
+ },
+ {
+ "name": "MicrodroidHostTestCases"
}
]
}
diff --git a/init/first_stage_console.cpp b/init/first_stage_console.cpp
index e2ea0ab..67cac19 100644
--- a/init/first_stage_console.cpp
+++ b/init/first_stage_console.cpp
@@ -85,7 +85,10 @@
void StartConsole(const std::string& cmdline) {
bool console = KernelConsolePresent(cmdline);
+ // Use a simple sigchld handler -- first_stage_console doesn't need to track or log zombies
+ const struct sigaction chld_act { .sa_handler = SIG_DFL, .sa_flags = SA_NOCLDWAIT };
+ sigaction(SIGCHLD, &chld_act, nullptr);
pid_t pid = fork();
if (pid != 0) {
int status;
diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp
index 2a89e29..f07e32b 100644
--- a/libstats/pull_rust/Android.bp
+++ b/libstats/pull_rust/Android.bp
@@ -57,3 +57,13 @@
"libstatspull_bindgen",
],
}
+
+rust_test {
+ name: "libstatspull_bindgen_test",
+ srcs: [":libstatspull_bindgen"],
+ crate_name: "statspull_bindgen_test",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ clippy_lints: "none",
+ lints: "none",
+}
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index b57e287..0518927 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -170,7 +170,7 @@
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
- , mFlags(0)
+ , mFlags(OBJECT_LIFETIME_STRONG)
{
}
@@ -189,7 +189,7 @@
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
- , mFlags(0)
+ , mFlags(OBJECT_LIFETIME_STRONG)
, mStrongRefs(NULL)
, mWeakRefs(NULL)
, mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)