Merge "trusty: apploader: Handle invalid version error"
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index eb3738e..4634283 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -475,7 +475,7 @@
struct SizeParamCrasherTest : CrasherTest, testing::WithParamInterface<size_t> {};
-INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(16, 131072));
+INSTANTIATE_TEST_SUITE_P(Sizes, SizeParamCrasherTest, testing::Values(0, 16, 131072));
TEST_P(SizeParamCrasherTest, mte_uaf) {
#if defined(__aarch64__)
@@ -483,6 +483,11 @@
GTEST_SKIP() << "Requires MTE";
}
+ // Any UAF on a zero-sized allocation will be out-of-bounds so it won't be reported.
+ if (GetParam() == 0) {
+ return;
+ }
+
int intercept_result;
unique_fd output_fd;
StartProcess([&]() {
@@ -514,6 +519,38 @@
#endif
}
+TEST_P(SizeParamCrasherTest, mte_oob_uaf) {
+#if defined(__aarch64__)
+ if (!mte_supported()) {
+ GTEST_SKIP() << "Requires MTE";
+ }
+
+ int intercept_result;
+ unique_fd output_fd;
+ StartProcess([&]() {
+ SetTagCheckingLevelSync();
+ volatile int* p = (volatile int*)malloc(GetParam());
+ free((void *)p);
+ p[-1] = 42;
+ });
+
+ StartIntercept(&output_fd);
+ FinishCrasher();
+ AssertDeath(SIGSEGV);
+ 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\))");
+ ASSERT_NOT_MATCH(result, R"(Cause: \[MTE\]: Use After Free, 4 bytes left)");
+#else
+ GTEST_SKIP() << "Requires aarch64";
+#endif
+}
+
TEST_P(SizeParamCrasherTest, mte_overflow) {
#if defined(__aarch64__)
if (!mte_supported()) {
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index e0cc662..ad903ce 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -106,9 +106,9 @@
unwindstack::MapInfo* map_info = maps->Find(sp);
if (map_info == nullptr) {
return "stack pointer is in a non-existent map; likely due to stack overflow.";
- } else if ((map_info->flags & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
+ } else if ((map_info->flags() & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
return "stack pointer is not in a rw map; likely due to stack overflow.";
- } else if ((sp - map_info->start) <= kMaxDifferenceBytes) {
+ } else if ((sp - map_info->start()) <= kMaxDifferenceBytes) {
return "stack pointer is close to top of stack; likely stack overflow.";
}
}
@@ -137,7 +137,7 @@
} else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
uint64_t fault_addr = reinterpret_cast<uint64_t>(si->si_addr);
unwindstack::MapInfo* map_info = maps->Find(fault_addr);
- if (map_info != nullptr && map_info->flags == PROT_EXEC) {
+ 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, regs->sp(), maps);
@@ -244,7 +244,7 @@
"memory map (%zu entr%s):",
maps->Total(), maps->Total() == 1 ? "y" : "ies");
if (print_fault_address_marker) {
- if (maps->Total() != 0 && addr < maps->Get(0)->start) {
+ if (maps->Total() != 0 && addr < maps->Get(0)->start()) {
_LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
get_addr_string(addr).c_str());
print_fault_address_marker = false;
@@ -261,37 +261,37 @@
for (auto const& map_info : *maps) {
line = " ";
if (print_fault_address_marker) {
- if (addr < map_info->start) {
+ if (addr < map_info->start()) {
_LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
get_addr_string(addr).c_str());
print_fault_address_marker = false;
- } else if (addr >= map_info->start && addr < map_info->end) {
+ } else if (addr >= map_info->start() && addr < map_info->end()) {
line = "--->";
print_fault_address_marker = false;
}
}
- line += get_addr_string(map_info->start) + '-' + get_addr_string(map_info->end - 1) + ' ';
- if (map_info->flags & PROT_READ) {
+ line += get_addr_string(map_info->start()) + '-' + get_addr_string(map_info->end() - 1) + ' ';
+ if (map_info->flags() & PROT_READ) {
line += 'r';
} else {
line += '-';
}
- if (map_info->flags & PROT_WRITE) {
+ if (map_info->flags() & PROT_WRITE) {
line += 'w';
} else {
line += '-';
}
- if (map_info->flags & PROT_EXEC) {
+ if (map_info->flags() & PROT_EXEC) {
line += 'x';
} else {
line += '-';
}
- line += StringPrintf(" %8" PRIx64 " %8" PRIx64, map_info->offset,
- map_info->end - map_info->start);
+ line += StringPrintf(" %8" PRIx64 " %8" PRIx64, map_info->offset(),
+ map_info->end() - map_info->start());
bool space_needed = true;
- if (!map_info->name.empty()) {
+ if (!map_info->name().empty()) {
space_needed = false;
- line += " " + map_info->name;
+ line += " " + map_info->name();
std::string build_id = map_info->GetPrintableBuildID();
if (!build_id.empty()) {
line += " (BuildId: " + build_id + ")";
@@ -369,8 +369,8 @@
std::string label{"memory near "s + reg_name};
if (maps) {
unwindstack::MapInfo* map_info = maps->Find(untag_address(reg_value));
- if (map_info != nullptr && !map_info->name.empty()) {
- label += " (" + map_info->name + ")";
+ if (map_info != nullptr && !map_info->name().empty()) {
+ label += " (" + map_info->name() + ")";
}
}
dump_memory(log, memory, reg_value, label);
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index d4a35b3..abd1f12 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -102,9 +102,9 @@
unwindstack::MapInfo* map_info = maps->Find(sp);
if (map_info == nullptr) {
return "stack pointer is in a non-existent map; likely due to stack overflow.";
- } else if ((map_info->flags & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
+ } else if ((map_info->flags() & (PROT_READ | PROT_WRITE)) != (PROT_READ | PROT_WRITE)) {
return "stack pointer is not in a rw map; likely due to stack overflow.";
- } else if ((sp - map_info->start) <= kMaxDifferenceBytes) {
+ } else if ((sp - map_info->start()) <= kMaxDifferenceBytes) {
return "stack pointer is close to top of stack; likely stack overflow.";
}
}
@@ -221,7 +221,7 @@
}
} else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
unwindstack::MapInfo* map_info = maps->Find(fault_addr);
- if (map_info != nullptr && map_info->flags == PROT_EXEC) {
+ 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);
@@ -359,7 +359,7 @@
dump.set_register_name(name);
unwindstack::MapInfo* map_info = maps->Find(untag_address(value));
if (map_info) {
- dump.set_mapping_name(map_info->name);
+ dump.set_mapping_name(map_info->name());
}
char buf[256];
@@ -426,21 +426,21 @@
for (const auto& map_info : *maps) {
auto* map = tombstone->add_memory_mappings();
- map->set_begin_address(map_info->start);
- map->set_end_address(map_info->end);
- map->set_offset(map_info->offset);
+ map->set_begin_address(map_info->start());
+ map->set_end_address(map_info->end());
+ map->set_offset(map_info->offset());
- if (map_info->flags & PROT_READ) {
+ if (map_info->flags() & PROT_READ) {
map->set_read(true);
}
- if (map_info->flags & PROT_WRITE) {
+ if (map_info->flags() & PROT_WRITE) {
map->set_write(true);
}
- if (map_info->flags & PROT_EXEC) {
+ if (map_info->flags() & PROT_EXEC) {
map->set_execute(true);
}
- map->set_mapping_name(map_info->name);
+ map->set_mapping_name(map_info->name());
std::string build_id = map_info->GetPrintableBuildID();
if (!build_id.empty()) {
diff --git a/debuggerd/proto/Android.bp b/debuggerd/proto/Android.bp
index b78224b..73cf573 100644
--- a/debuggerd/proto/Android.bp
+++ b/debuggerd/proto/Android.bp
@@ -31,6 +31,7 @@
stl: "libc++_static",
apex_available: [
+ "//apex_available:platform",
"com.android.runtime",
],
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index 0b87b7a..05d8050 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -165,8 +165,7 @@
switch (dump_type) {
case kDebuggerdNativeBacktrace:
- case kDebuggerdJavaBacktrace:
- // Don't generate tombstones for backtrace requests.
+ // Don't generate tombstones for native backtrace requests.
return {};
case kDebuggerdTombstoneProto:
@@ -178,6 +177,7 @@
result.text = create_temporary_file();
break;
+ case kDebuggerdJavaBacktrace:
case kDebuggerdTombstone:
result.text = create_temporary_file();
break;
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index ea9d333..08ead7a 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -2265,3 +2265,72 @@
}
return LP_METADATA_DEFAULT_PARTITION_NAME;
}
+
+bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) {
+ auto overlayfs_valid_result = fs_mgr_overlayfs_valid();
+ if (overlayfs_valid_result == OverlayfsValidResult::kNotSupported) {
+ LERROR << __FUNCTION__ << "(): kernel does not support overlayfs";
+ return false;
+ }
+
+#if ALLOW_ADBD_DISABLE_VERITY == 0
+ // Allowlist the mount point if user build.
+ static const std::vector<const std::string> kAllowedPaths = {
+ "/odm", "/odm_dlkm", "/oem", "/product", "/system_ext", "/vendor", "/vendor_dlkm",
+ };
+ static const std::vector<const std::string> kAllowedPrefixes = {
+ "/mnt/product/",
+ "/mnt/vendor/",
+ };
+ if (std::none_of(kAllowedPaths.begin(), kAllowedPaths.end(),
+ [&entry](const auto& path) -> bool {
+ return entry.mount_point == path ||
+ StartsWith(entry.mount_point, path + "/");
+ }) &&
+ std::none_of(kAllowedPrefixes.begin(), kAllowedPrefixes.end(),
+ [&entry](const auto& prefix) -> bool {
+ return entry.mount_point != prefix &&
+ StartsWith(entry.mount_point, prefix);
+ })) {
+ LERROR << __FUNCTION__
+ << "(): mount point is forbidden on user build: " << entry.mount_point;
+ return false;
+ }
+#endif // ALLOW_ADBD_DISABLE_VERITY == 0
+
+ // Create the mount point in case it doesn't exist.
+ mkdir(entry.mount_point.c_str(), 0755);
+
+ // Ensure that mount point exists and doesn't contain symbolic link or /../.
+ std::string mount_point;
+ if (!Realpath(entry.mount_point, &mount_point)) {
+ PERROR << __FUNCTION__ << "(): failed to realpath " << entry.mount_point;
+ return false;
+ }
+ if (entry.mount_point != mount_point) {
+ LERROR << __FUNCTION__ << "(): mount point must be a canonicalized path: realpath "
+ << entry.mount_point << " = " << mount_point;
+ return false;
+ }
+
+ auto options = "lowerdir=" + entry.lowerdir;
+ if (overlayfs_valid_result == OverlayfsValidResult::kOverrideCredsRequired) {
+ options += ",override_creds=off";
+ }
+
+ // Use "overlay-" + entry.blk_device as the mount() source, so that adb-remout-test don't
+ // confuse this with adb remount overlay, whose device name is "overlay".
+ // Overlayfs is a pseudo filesystem, so the source device is a symbolic value and isn't used to
+ // back the filesystem. However the device name would be shown in /proc/mounts.
+ auto source = "overlay-" + entry.blk_device;
+ auto report = "__mount(source=" + source + ",target=" + entry.mount_point + ",type=overlay," +
+ options + ")=";
+ auto ret = mount(source.c_str(), entry.mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
+ options.c_str());
+ if (ret) {
+ PERROR << report << ret;
+ return false;
+ }
+ LINFO << report << ret;
+ return true;
+}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 9a94d79..cb09383 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -92,10 +92,6 @@
return false;
}
-bool fs_mgr_overlayfs_mount_fstab_entry(const std::string&, const std::string&) {
- return false;
-}
-
std::vector<std::string> fs_mgr_overlayfs_required_devices(Fstab*) {
return {};
}
@@ -1299,18 +1295,6 @@
}
}
-bool fs_mgr_overlayfs_mount_fstab_entry(const std::string& lowers,
- const std::string& mount_point) {
- if (fs_mgr_overlayfs_invalid()) return false;
-
- std::string aux = "lowerdir=" + lowers + ",override_creds=off";
- auto rc = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME, aux.c_str());
-
- if (rc == 0) return true;
-
- return false;
-}
-
bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
auto ret = false;
if (fs_mgr_overlayfs_invalid()) return ret;
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index 830f0dd..1372511 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -92,7 +92,7 @@
}
auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," +
options + ")=";
- auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
+ auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
options.c_str());
if (ret) {
PERROR << report << ret;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 22c02cc..b8ebd63 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -131,3 +131,8 @@
// Finds the dm_bow device on which this block device is stacked, or returns
// empty string
std::string fs_mgr_find_bow_device(const std::string& block_device);
+
+// Like fs_mgr_do_mount_one() but for overlayfs fstab entries.
+// Unlike fs_mgr_overlayfs, mount overlayfs without upperdir and workdir, so the
+// filesystem cannot be remount read-write.
+bool fs_mgr_mount_overlayfs_fstab_entry(const android::fs_mgr::FstabEntry& entry);
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index ac95ef5..d45e2de 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -27,7 +27,6 @@
android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
-bool fs_mgr_overlayfs_mount_fstab_entry (const std::string& lowers, const std::string& mount_point);
std::vector<std::string> fs_mgr_overlayfs_required_devices(android::fs_mgr::Fstab* fstab);
bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
bool* change = nullptr, bool force = true);
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index d5b8a61..c4874b8 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -35,6 +35,10 @@
#include "utility.h"
+#ifndef DM_DEFERRED_REMOVE
+#define DM_DEFERRED_REMOVE (1 << 17)
+#endif
+
namespace android {
namespace dm {
@@ -133,6 +137,25 @@
return DeleteDevice(name, 0ms);
}
+bool DeviceMapper::DeleteDeviceDeferred(const std::string& name) {
+ struct dm_ioctl io;
+ InitIo(&io, name);
+
+ io.flags |= DM_DEFERRED_REMOVE;
+ if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
+ PLOG(ERROR) << "DM_DEV_REMOVE with DM_DEFERRED_REMOVE failed for [" << name << "]";
+ return false;
+ }
+ return true;
+}
+
+bool DeviceMapper::DeleteDeviceIfExistsDeferred(const std::string& name) {
+ if (GetState(name) == DmDeviceState::INVALID) {
+ return true;
+ }
+ return DeleteDeviceDeferred(name);
+}
+
static std::string GenerateUuid() {
uuid_t uuid_bytes;
uuid_generate(uuid_bytes);
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 41d3145..8006db2 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -35,6 +35,7 @@
#include <libdm/dm.h>
#include <libdm/loop_control.h>
#include "test_util.h"
+#include "utility.h"
using namespace std;
using namespace std::chrono_literals;
@@ -617,3 +618,64 @@
auto sub_block_device = dm.GetParentBlockDeviceByPath(dev.path());
ASSERT_EQ(loop.device(), *sub_block_device);
}
+
+TEST(libdm, DeleteDeviceDeferredNoReferences) {
+ unique_fd tmp(CreateTempFile("file_1", 4096));
+ ASSERT_GE(tmp, 0);
+ LoopDevice loop(tmp, 10s);
+ ASSERT_TRUE(loop.valid());
+
+ DmTable table;
+ ASSERT_TRUE(table.Emplace<DmTargetLinear>(0, 1, loop.device(), 0));
+ ASSERT_TRUE(table.valid());
+ TempDevice dev("libdm-test-dm-linear", table);
+ ASSERT_TRUE(dev.valid());
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+
+ std::string path;
+ ASSERT_TRUE(dm.GetDmDevicePathByName("libdm-test-dm-linear", &path));
+ ASSERT_EQ(0, access(path.c_str(), F_OK));
+
+ ASSERT_TRUE(dm.DeleteDeviceDeferred("libdm-test-dm-linear"));
+
+ ASSERT_TRUE(WaitForFileDeleted(path, 5s));
+ ASSERT_EQ(DmDeviceState::INVALID, dm.GetState("libdm-test-dm-linear"));
+ ASSERT_NE(0, access(path.c_str(), F_OK));
+ ASSERT_EQ(ENOENT, errno);
+}
+
+TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) {
+ unique_fd tmp(CreateTempFile("file_1", 4096));
+ ASSERT_GE(tmp, 0);
+ LoopDevice loop(tmp, 10s);
+ ASSERT_TRUE(loop.valid());
+
+ DmTable table;
+ ASSERT_TRUE(table.Emplace<DmTargetLinear>(0, 1, loop.device(), 0));
+ ASSERT_TRUE(table.valid());
+ TempDevice dev("libdm-test-dm-linear", table);
+ ASSERT_TRUE(dev.valid());
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+
+ std::string path;
+ ASSERT_TRUE(dm.GetDmDevicePathByName("libdm-test-dm-linear", &path));
+ ASSERT_EQ(0, access(path.c_str(), F_OK));
+
+ {
+ // Open a reference to block device.
+ unique_fd fd(TEMP_FAILURE_RETRY(open(dev.path().c_str(), O_RDONLY | O_CLOEXEC)));
+ ASSERT_GE(fd.get(), 0);
+
+ ASSERT_TRUE(dm.DeleteDeviceDeferred("libdm-test-dm-linear"));
+
+ ASSERT_EQ(0, access(path.c_str(), F_OK));
+ }
+
+ // After release device will be removed.
+ ASSERT_TRUE(WaitForFileDeleted(path, 5s));
+ ASSERT_EQ(DmDeviceState::INVALID, dm.GetState("libdm-test-dm-linear"));
+ ASSERT_NE(0, access(path.c_str(), F_OK));
+ ASSERT_EQ(ENOENT, errno);
+}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 5d6db46..70b14fa 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -95,6 +95,12 @@
bool DeleteDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
bool DeleteDeviceIfExists(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+ // Enqueues a deletion of device mapper device with the given name once last reference is
+ // closed.
+ // Returns 'true' on success, false otherwise.
+ bool DeleteDeviceDeferred(const std::string& name);
+ bool DeleteDeviceIfExistsDeferred(const std::string& name);
+
// Fetches and returns the complete state of the underlying device mapper
// device with given name.
std::optional<Info> GetDetailedInfo(const std::string& name) const;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 104484d..6a764e4 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -266,7 +266,7 @@
"android.hardware.boot@1.1",
"libbrotli",
"libc++fs",
- "libfs_mgr",
+ "libfs_mgr_binder",
"libgsi",
"libgmock",
"liblp",
@@ -421,8 +421,8 @@
"snapuserd_server.cpp",
"snapuserd.cpp",
"snapuserd_daemon.cpp",
- "snapuserd_worker.cpp",
- "snapuserd_readahead.cpp",
+ "snapuserd_worker.cpp",
+ "snapuserd_readahead.cpp",
],
cflags: [
@@ -564,7 +564,7 @@
srcs: [
"cow_snapuserd_test.cpp",
"snapuserd.cpp",
- "snapuserd_worker.cpp",
+ "snapuserd_worker.cpp",
],
cflags: [
"-Wall",
@@ -581,7 +581,7 @@
"libsnapshot_snapuserd",
"libcutils_sockets",
"libz",
- "libfs_mgr",
+ "libfs_mgr",
"libdm",
],
header_libs: [
diff --git a/fs_mgr/libsnapshot/corpus/avoid-io-in-fuzzer.txt b/fs_mgr/libsnapshot/corpus/avoid-io-in-fuzzer.txt
new file mode 100644
index 0000000..c474f4c
--- /dev/null
+++ b/fs_mgr/libsnapshot/corpus/avoid-io-in-fuzzer.txt
@@ -0,0 +1,41 @@
+device_info_data {
+ allow_set_slot_as_unbootable: true
+ is_recovery: true
+}
+is_super_metadata_valid: true
+super_data {
+ partitions {
+ partition_name: "sys_a"
+ new_partition_info {
+ size: 3145728
+ }
+ }
+ partitions {
+ partition_name: "vnnd_"
+ new_partition_info {
+ size: 3145728
+ }
+ }
+ partitions {
+ partition_name: "prd_a"
+ new_partition_info {
+ }
+ }
+ dynamic_partition_metadata {
+ groups {
+ name: "group_google_dp_a"
+ size: 34375467008
+ partition_names: "sys_a"
+ partition_names: "vnd_a"
+ partition_names: "prd_a"
+ }
+ }
+}
+has_metadata_snapshots_dir: true
+actions {
+ handle_imminent_data_wipe: true
+}
+actions {
+ begin_update {
+ }
+}
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 35a02e6..2349e4a 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -377,7 +377,6 @@
});
if (header_.num_merge_ops > 0) {
- CHECK(ops_->size() >= header_.num_merge_ops);
ops_->erase(ops_.get()->begin(), ops_.get()->begin() + header_.num_merge_ops);
}
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 3888eb1..767cd04 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -103,6 +103,7 @@
void ReadSnapshotDeviceAndValidate();
void Shutdown();
void MergeInterrupt();
+ void ReadDmUserBlockWithoutDaemon();
std::string snapshot_dev() const { return snapshot_dev_->path(); }
@@ -481,6 +482,36 @@
ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
}
+void CowSnapuserdTest::ReadDmUserBlockWithoutDaemon() {
+ DmTable dmuser_table;
+ std::string dm_user_name = "dm-test-device";
+ unique_fd fd;
+
+ // Create a dm-user block device
+ ASSERT_TRUE(dmuser_table.AddTarget(std::make_unique<DmTargetUser>(0, 123456, dm_user_name)));
+ ASSERT_TRUE(dmuser_table.valid());
+
+ dmuser_dev_ = std::make_unique<TempDevice>(dm_user_name, dmuser_table);
+ ASSERT_TRUE(dmuser_dev_->valid());
+ ASSERT_FALSE(dmuser_dev_->path().empty());
+
+ fd.reset(open(dmuser_dev_->path().c_str(), O_RDONLY));
+ ASSERT_GE(fd, 0);
+
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(1_MiB);
+
+ loff_t offset = 0;
+ // Every IO should fail as there is no daemon to process the IO
+ for (size_t j = 0; j < 10; j++) {
+ ASSERT_EQ(ReadFullyAtOffset(fd, (char*)buffer.get() + offset, BLOCK_SZ, offset), false);
+
+ offset += BLOCK_SZ;
+ }
+
+ fd = {};
+ ASSERT_TRUE(dmuser_dev_->Destroy());
+}
+
void CowSnapuserdTest::InitDaemon() {
bool ok = client_->AttachDmUser(system_device_ctrl_name_);
ASSERT_TRUE(ok);
@@ -909,6 +940,11 @@
harness.Shutdown();
}
+TEST(Snapuserd_Test, ReadDmUserBlockWithoutDaemon) {
+ CowSnapuserdTest harness;
+ harness.ReadDmUserBlockWithoutDaemon();
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/device_info.cpp b/fs_mgr/libsnapshot/device_info.cpp
index 0e90100..14ce0ee 100644
--- a/fs_mgr/libsnapshot/device_info.cpp
+++ b/fs_mgr/libsnapshot/device_info.cpp
@@ -17,6 +17,7 @@
#include <android-base/logging.h>
#include <fs_mgr.h>
#include <fs_mgr_overlayfs.h>
+#include <libfiemap/image_manager.h>
namespace android {
namespace snapshot {
@@ -26,6 +27,7 @@
using android::hardware::boot::V1_0::CommandResult;
#endif
+using namespace std::chrono_literals;
using namespace std::string_literals;
#ifdef __ANDROID_RECOVERY__
@@ -34,10 +36,6 @@
constexpr bool kIsRecovery = false;
#endif
-std::string DeviceInfo::GetGsidDir() const {
- return "ota"s;
-}
-
std::string DeviceInfo::GetMetadataDir() const {
return "/metadata/ota"s;
}
@@ -100,6 +98,10 @@
return kIsRecovery;
}
+bool DeviceInfo::IsFirstStageInit() const {
+ return first_stage_init_;
+}
+
bool DeviceInfo::SetSlotAsUnbootable([[maybe_unused]] unsigned int slot) {
#ifdef LIBSNAPSHOT_USE_HAL
if (!EnsureBootHal()) {
@@ -120,5 +122,22 @@
#endif
}
+std::unique_ptr<android::fiemap::IImageManager> DeviceInfo::OpenImageManager() const {
+ return IDeviceInfo::OpenImageManager("ota");
+}
+
+std::unique_ptr<android::fiemap::IImageManager> ISnapshotManager::IDeviceInfo::OpenImageManager(
+ const std::string& gsid_dir) const {
+ if (IsRecovery() || IsFirstStageInit()) {
+ android::fiemap::ImageManager::DeviceInfo device_info = {
+ .is_recovery = {IsRecovery()},
+ };
+ return android::fiemap::ImageManager::Open(gsid_dir, device_info);
+ } else {
+ // For now, use a preset timeout.
+ return android::fiemap::IImageManager::Open(gsid_dir, 15000ms);
+ }
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/device_info.h b/fs_mgr/libsnapshot/device_info.h
index d8d3d91..7999c99 100644
--- a/fs_mgr/libsnapshot/device_info.h
+++ b/fs_mgr/libsnapshot/device_info.h
@@ -29,7 +29,6 @@
using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
public:
- std::string GetGsidDir() const override;
std::string GetMetadataDir() const override;
std::string GetSlotSuffix() const override;
std::string GetOtherSlotSuffix() const override;
@@ -39,11 +38,16 @@
bool SetBootControlMergeStatus(MergeStatus status) override;
bool SetSlotAsUnbootable(unsigned int slot) override;
bool IsRecovery() const override;
+ std::unique_ptr<IImageManager> OpenImageManager() const override;
+ bool IsFirstStageInit() const override;
+
+ void set_first_stage_init(bool value) { first_stage_init_ = value; }
private:
bool EnsureBootHal();
android::fs_mgr::PartitionOpener opener_;
+ bool first_stage_init_ = false;
#ifdef LIBSNAPSHOT_USE_HAL
android::sp<android::hardware::boot::V1_1::IBootControl> boot_control_;
#endif
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
index ef9d648..573a85b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
@@ -22,7 +22,6 @@
class MockDeviceInfo : public SnapshotManager::IDeviceInfo {
public:
- MOCK_METHOD(std::string, GetGsidDir, (), (const, override));
MOCK_METHOD(std::string, GetMetadataDir, (), (const, override));
MOCK_METHOD(std::string, GetSlotSuffix, (), (const, override));
MOCK_METHOD(std::string, GetOtherSlotSuffix, (), (const, override));
@@ -32,6 +31,9 @@
MOCK_METHOD(bool, SetBootControlMergeStatus, (MergeStatus status), (override));
MOCK_METHOD(bool, SetSlotAsUnbootable, (unsigned int slot), (override));
MOCK_METHOD(bool, IsRecovery, (), (const, override));
+ MOCK_METHOD(bool, IsFirstStageInit, (), (const, override));
+ MOCK_METHOD(std::unique_ptr<android::fiemap::IImageManager>, OpenImageManager, (),
+ (const, override));
};
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index d2fdfd6..603e896 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -94,8 +94,9 @@
// Dependency injection for testing.
class IDeviceInfo {
public:
+ using IImageManager = android::fiemap::IImageManager;
+
virtual ~IDeviceInfo() {}
- virtual std::string GetGsidDir() const = 0;
virtual std::string GetMetadataDir() const = 0;
virtual std::string GetSlotSuffix() const = 0;
virtual std::string GetOtherSlotSuffix() const = 0;
@@ -107,6 +108,11 @@
virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
virtual bool IsRecovery() const = 0;
virtual bool IsTestDevice() const { return false; }
+ virtual bool IsFirstStageInit() const = 0;
+ virtual std::unique_ptr<IImageManager> OpenImageManager() const = 0;
+
+ // Helper method for implementing OpenImageManager.
+ std::unique_ptr<IImageManager> OpenImageManager(const std::string& gsid_dir) const;
};
virtual ~ISnapshotManager() = default;
@@ -420,7 +426,6 @@
bool EnsureSnapuserdConnected();
// Helpers for first-stage init.
- bool ForceLocalImageManager();
const std::unique_ptr<IDeviceInfo>& device() const { return device_; }
// Helper functions for tests.
@@ -765,7 +770,6 @@
std::string metadata_dir_;
std::unique_ptr<IDeviceInfo> device_;
std::unique_ptr<IImageManager> images_;
- bool has_local_image_manager_ = false;
bool use_first_stage_snapuserd_ = false;
bool in_factory_data_reset_ = false;
std::function<bool(const std::string&)> uevent_regen_callback_;
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index b038527..4e7ccf1 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -77,7 +77,6 @@
: TestDeviceInfo(fake_super) {
set_slot_suffix(slot_suffix);
}
- std::string GetGsidDir() const override { return "ota/test"s; }
std::string GetMetadataDir() const override { return "/metadata/ota/test"s; }
std::string GetSlotSuffix() const override { return slot_suffix_; }
std::string GetOtherSlotSuffix() const override { return slot_suffix_ == "_a" ? "_b" : "_a"; }
@@ -96,6 +95,10 @@
return true;
}
bool IsTestDevice() const override { return true; }
+ bool IsFirstStageInit() const override { return first_stage_init_; }
+ std::unique_ptr<IImageManager> OpenImageManager() const override {
+ return IDeviceInfo::OpenImageManager("ota/test");
+ }
bool IsSlotUnbootable(uint32_t slot) { return unbootable_slots_.count(slot) != 0; }
@@ -104,6 +107,7 @@
opener_ = std::make_unique<TestPartitionOpener>(path);
}
void set_recovery(bool value) { recovery_ = value; }
+ void set_first_stage_init(bool value) { first_stage_init_ = value; }
MergeStatus merge_status() const { return merge_status_; }
private:
@@ -111,6 +115,7 @@
std::unique_ptr<TestPartitionOpener> opener_;
MergeStatus merge_status_;
bool recovery_ = false;
+ bool first_stage_init_ = false;
std::unordered_set<uint32_t> unbootable_slots_;
};
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 245742e..e2c03ae 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -95,18 +95,16 @@
if (!info) {
info = new DeviceInfo();
}
- auto sm = std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
- if (info->IsRecovery()) {
- sm->ForceLocalImageManager();
- }
- return sm;
+ return std::unique_ptr<SnapshotManager>(new SnapshotManager(info));
}
std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceInfo* info) {
- auto sm = New(info);
- if (!sm || !sm->ForceLocalImageManager()) {
- return nullptr;
+ if (!info) {
+ DeviceInfo* impl = new DeviceInfo();
+ impl->set_first_stage_init(true);
+ info = impl;
}
+ auto sm = New(info);
// The first-stage version of snapuserd is explicitly started by init. Do
// not attempt to using it during tests (which run in normal AOSP).
@@ -117,7 +115,6 @@
}
SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) {
- gsid_dir_ = device_->GetGsidDir();
metadata_dir_ = device_->GetMetadataDir();
}
@@ -538,9 +535,7 @@
bool ok;
std::string cow_dev;
- if (has_local_image_manager_) {
- // If we forced a local image manager, it means we don't have binder,
- // which means first-stage init. We must use device-mapper.
+ if (device_->IsRecovery() || device_->IsFirstStageInit()) {
const auto& opener = device_->GetPartitionOpener();
ok = images_->MapImageWithDeviceMapper(opener, cow_image_name, &cow_dev);
} else {
@@ -1836,6 +1831,10 @@
return false;
}
+ if (!EnsureImageManager()) {
+ return false;
+ }
+
for (const auto& partition : metadata->partitions) {
if (GetPartitionGroupName(metadata->groups[partition.group_index]) == kCowGroupName) {
LOG(INFO) << "Skip mapping partition " << GetPartitionName(partition) << " in group "
@@ -2556,8 +2555,7 @@
bool SnapshotManager::EnsureImageManager() {
if (images_) return true;
- // For now, use a preset timeout.
- images_ = android::fiemap::IImageManager::Open(gsid_dir_, 15000ms);
+ images_ = device_->OpenImageManager();
if (!images_) {
LOG(ERROR) << "Could not open ImageManager";
return false;
@@ -2582,20 +2580,6 @@
return true;
}
-bool SnapshotManager::ForceLocalImageManager() {
- android::fiemap::ImageManager::DeviceInfo device_info = {
- .is_recovery = {device_->IsRecovery()},
- };
-
- images_ = android::fiemap::ImageManager::Open(gsid_dir_, device_info);
- if (!images_) {
- LOG(ERROR) << "Could not open ImageManager";
- return false;
- }
- has_local_image_manager_ = true;
- return true;
-}
-
void SnapshotManager::UnmapAndDeleteCowPartition(MetadataBuilder* current_metadata) {
std::vector<std::string> to_delete;
for (auto* existing_cow_partition : current_metadata->ListPartitionsInGroup(kCowGroupName)) {
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
index 8926535..0096f85 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.cpp
@@ -381,8 +381,9 @@
CheckDetachLoopDevices({Basename(fake_super_), Basename(fake_data_block_device_)});
}
-std::unique_ptr<IImageManager> SnapshotFuzzEnv::CheckCreateFakeImageManager(
- const std::string& metadata_dir, const std::string& data_dir) {
+std::unique_ptr<IImageManager> SnapshotFuzzEnv::CheckCreateFakeImageManager() {
+ auto metadata_dir = fake_root_->tmp_path() + "/images_manager_metadata";
+ auto data_dir = fake_data_mount_point_ + "/image_manager_data";
PCHECK(Mkdir(metadata_dir));
PCHECK(Mkdir(data_dir));
return SnapshotFuzzImageManager::Open(metadata_dir, data_dir);
@@ -428,13 +429,9 @@
PCHECK(Mkdir(metadata_dir + "/snapshots"));
}
- ret.device_info = new SnapshotFuzzDeviceInfo(data.device_info_data(),
+ ret.device_info = new SnapshotFuzzDeviceInfo(this, data.device_info_data(),
std::move(partition_opener), metadata_dir);
auto snapshot = SnapshotManager::New(ret.device_info /* takes ownership */);
- snapshot->images_ =
- CheckCreateFakeImageManager(fake_root_->tmp_path() + "/images_manager_metadata",
- fake_data_mount_point_ + "/image_manager_data");
- snapshot->has_local_image_manager_ = data.manager_data().is_local_image_manager();
ret.snapshot = std::move(snapshot);
return ret;
diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
index 5319e69..3ed27c8 100644
--- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
+++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h
@@ -65,6 +65,8 @@
// ISnapshotManager.
SnapshotTestModule CheckCreateSnapshotManager(const SnapshotFuzzData& data);
+ std::unique_ptr<android::fiemap::IImageManager> CheckCreateFakeImageManager();
+
// Return path to super partition.
const std::string& super() const;
@@ -79,8 +81,6 @@
std::string fake_data_block_device_;
std::unique_ptr<AutoDevice> mounted_data_;
- static std::unique_ptr<android::fiemap::IImageManager> CheckCreateFakeImageManager(
- const std::string& metadata_dir, const std::string& data_dir);
static std::unique_ptr<AutoDevice> CheckMapImage(const std::string& fake_persist_path,
uint64_t size,
android::dm::LoopControl* control,
@@ -95,15 +95,15 @@
class SnapshotFuzzDeviceInfo : public ISnapshotManager::IDeviceInfo {
public:
// Client is responsible for maintaining the lifetime of |data|.
- SnapshotFuzzDeviceInfo(const FuzzDeviceInfoData& data,
+ SnapshotFuzzDeviceInfo(SnapshotFuzzEnv* env, const FuzzDeviceInfoData& data,
std::unique_ptr<TestPartitionOpener>&& partition_opener,
const std::string& metadata_dir)
- : data_(&data),
+ : env_(env),
+ data_(&data),
partition_opener_(std::move(partition_opener)),
metadata_dir_(metadata_dir) {}
// Following APIs are mocked.
- std::string GetGsidDir() const override { return "fuzz_ota"; }
std::string GetMetadataDir() const override { return metadata_dir_; }
std::string GetSuperDevice(uint32_t) const override {
// TestPartitionOpener can recognize this.
@@ -124,10 +124,15 @@
return data_->allow_set_slot_as_unbootable();
}
bool IsRecovery() const override { return data_->is_recovery(); }
+ bool IsFirstStageInit() const override { return false; }
+ std::unique_ptr<IImageManager> OpenImageManager() const {
+ return env_->CheckCreateFakeImageManager();
+ }
void SwitchSlot() { switched_slot_ = !switched_slot_; }
private:
+ SnapshotFuzzEnv* env_;
const FuzzDeviceInfoData* data_;
std::unique_ptr<TestPartitionOpener> partition_opener_;
std::string metadata_dir_;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 9226b7f..6018643 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -403,6 +403,7 @@
}
std::unique_ptr<SnapshotManager> NewManagerForFirstStageMount(TestDeviceInfo* info) {
+ info->set_first_stage_init(true);
auto init = SnapshotManager::NewForFirstStageMount(info);
if (!init) {
return nullptr;
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index 5eb2003..67189d4 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -36,7 +36,9 @@
" dump\n"
" Print snapshot states.\n"
" merge\n"
- " Deprecated.\n";
+ " Deprecated.\n"
+ " map\n"
+ " Map all partitions at /dev/block/mapper\n";
return EX_USAGE;
}
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 3210983..03c2ef6 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -90,7 +90,10 @@
}
bool Snapuserd::GetRABuffer(std::unique_lock<std::mutex>* lock, uint64_t block, void* buffer) {
- CHECK(lock->owns_lock());
+ if (!lock->owns_lock()) {
+ SNAP_LOG(ERROR) << "GetRABuffer - Lock not held";
+ return false;
+ }
std::unordered_map<uint64_t, void*>::iterator it = read_ahead_buffer_map_.find(block);
// This will be true only for IO's generated as part of reading a root
@@ -344,7 +347,10 @@
return false;
}
- CHECK(header.block_size == BLOCK_SZ);
+ if (!(header.block_size == BLOCK_SZ)) {
+ SNAP_LOG(ERROR) << "Invalid header block size found: " << header.block_size;
+ return false;
+ }
reader_->InitializeMerge();
SNAP_LOG(DEBUG) << "Merge-ops: " << header.num_merge_ops;
@@ -610,7 +616,11 @@
SNAP_LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size();
}
- CHECK(pending_copy_ops == 0);
+ if (!(pending_copy_ops == 0)) {
+ SNAP_LOG(ERROR)
+ << "Invalid pending_copy_ops: expected: 0 found: " << pending_copy_ops;
+ return false;
+ }
pending_copy_ops = exceptions_per_area_;
}
diff --git a/fs_mgr/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/snapuserd.h
index 0a5ab50..212c78e 100644
--- a/fs_mgr/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/snapuserd.h
@@ -99,6 +99,7 @@
struct dm_user_header* GetHeaderPtr();
bool ReturnData(void*, size_t) override { return true; }
void ResetBufferOffset() { buffer_offset_ = 0; }
+ void* GetPayloadBufPtr();
private:
std::unique_ptr<uint8_t[]> buffer_;
@@ -171,7 +172,7 @@
bool DmuserReadRequest();
bool DmuserWriteRequest();
bool ReadDmUserPayload(void* buffer, size_t size);
- bool WriteDmUserPayload(size_t size);
+ bool WriteDmUserPayload(size_t size, bool header_response);
bool ReadDiskExceptions(chunk_t chunk, size_t size);
bool ZerofillDiskExceptions(size_t read_size);
diff --git a/fs_mgr/libsnapshot/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd_readahead.cpp
index 09ee2f2..16d5919 100644
--- a/fs_mgr/libsnapshot/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_readahead.cpp
@@ -257,7 +257,12 @@
// Verify that we have covered all the ops which were re-constructed
// from COW device - These are the ops which are being
// re-constructed after crash.
- CHECK(num_ops == 0);
+ if (!(num_ops == 0)) {
+ SNAP_LOG(ERROR) << "ReconstructDataFromCow failed. Not all ops recoverd "
+ << " Pending ops: " << num_ops;
+ snapuserd_->ReadAheadIOFailed();
+ return false;
+ }
break;
}
}
@@ -370,8 +375,6 @@
bm->file_offset = 0;
buffer_offset += io_size;
- CHECK(offset == buffer_offset);
- CHECK((file_offset - snapuserd_->GetBufferDataOffset()) == offset);
}
snapuserd_->SetTotalRaBlocksMerged(total_blocks_merged);
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 3b0af3e..8339690 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -378,7 +378,10 @@
}
bool SnapuserdServer::StartHandler(const std::shared_ptr<DmUserHandler>& handler) {
- CHECK(!handler->snapuserd()->IsAttached());
+ if (handler->snapuserd()->IsAttached()) {
+ LOG(ERROR) << "Handler already attached";
+ return false;
+ }
handler->snapuserd()->AttachControlDevice();
diff --git a/fs_mgr/libsnapshot/snapuserd_worker.cpp b/fs_mgr/libsnapshot/snapuserd_worker.cpp
index 9f42ab8..682f9da 100644
--- a/fs_mgr/libsnapshot/snapuserd_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_worker.cpp
@@ -57,12 +57,20 @@
}
struct dm_user_header* BufferSink::GetHeaderPtr() {
- CHECK(sizeof(struct dm_user_header) <= buffer_size_);
+ if (!(sizeof(struct dm_user_header) <= buffer_size_)) {
+ return nullptr;
+ }
char* buf = reinterpret_cast<char*>(GetBufPtr());
struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
return header;
}
+void* BufferSink::GetPayloadBufPtr() {
+ char* buffer = reinterpret_cast<char*>(GetBufPtr());
+ struct dm_user_message* msg = reinterpret_cast<struct dm_user_message*>(&(buffer[0]));
+ return msg->payload.buf;
+}
+
WorkerThread::WorkerThread(const std::string& cow_device, const std::string& backing_device,
const std::string& control_device, const std::string& misc_name,
std::shared_ptr<Snapuserd> snapuserd) {
@@ -111,7 +119,6 @@
// the header, zero out the remaining block.
void WorkerThread::ConstructKernelCowHeader() {
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- CHECK(buffer != nullptr);
memset(buffer, 0, BLOCK_SZ);
@@ -137,7 +144,10 @@
bool WorkerThread::ReadFromBaseDevice(const CowOperation* cow_op) {
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- CHECK(buffer != nullptr);
+ if (buffer == nullptr) {
+ SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
+ return false;
+ }
SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
<< " Source: " << cow_op->source;
if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ,
@@ -152,7 +162,10 @@
bool WorkerThread::GetReadAheadPopulatedBuffer(const CowOperation* cow_op) {
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- CHECK(buffer != nullptr);
+ if (buffer == nullptr) {
+ SNAP_LOG(ERROR) << "GetReadAheadPopulatedBuffer: Failed to get payload buffer";
+ return false;
+ }
if (!snapuserd_->GetReadAheadPopulatedBuffer(cow_op->new_block, buffer)) {
return false;
@@ -178,14 +191,20 @@
bool WorkerThread::ProcessZeroOp() {
// Zero out the entire block
void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
- CHECK(buffer != nullptr);
+ if (buffer == nullptr) {
+ SNAP_LOG(ERROR) << "ProcessZeroOp: Failed to get payload buffer";
+ return false;
+ }
memset(buffer, 0, BLOCK_SZ);
return true;
}
bool WorkerThread::ProcessCowOp(const CowOperation* cow_op) {
- CHECK(cow_op != nullptr);
+ if (cow_op == nullptr) {
+ SNAP_LOG(ERROR) << "ProcessCowOp: Invalid cow_op";
+ return false;
+ }
switch (cow_op->type) {
case kCowReplaceOp: {
@@ -216,7 +235,8 @@
<< " Aligned sector: " << it->first;
if (!ProcessCowOp(it->second)) {
- SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size;
+ SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size
+ << " Aligned sector: " << it->first;
return -1;
}
@@ -227,6 +247,12 @@
char* buffer = reinterpret_cast<char*>(bufsink_.GetBufPtr());
struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
+ if (skip_sector_size == BLOCK_SZ) {
+ SNAP_LOG(ERROR) << "Invalid un-aligned IO request at sector: " << sector
+ << " Base-sector: " << it->first;
+ return -1;
+ }
+
memmove(msg->payload.buf, (char*)msg->payload.buf + skip_sector_size,
(BLOCK_SZ - skip_sector_size));
}
@@ -261,7 +287,10 @@
it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr),
Snapuserd::compare);
- CHECK(it != chunk_vec.end());
+ if (!(it != chunk_vec.end())) {
+ SNAP_LOG(ERROR) << "ReadData: Sector " << sector << " not found in chunk_vec";
+ return -1;
+ }
// We didn't find the required sector; hence find the previous sector
// as lower_bound will gives us the value greater than
@@ -298,16 +327,30 @@
}
int num_ops = DIV_ROUND_UP(size, BLOCK_SZ);
+ sector_t read_sector = sector;
while (num_ops) {
- if (!ProcessCowOp(it->second)) {
+ // We have to make sure that the reads are
+ // sequential; there shouldn't be a data
+ // request merged with a metadata IO.
+ if (it->first != read_sector) {
+ SNAP_LOG(ERROR) << "Invalid IO request: read_sector: " << read_sector
+ << " cow-op sector: " << it->first;
+ return -1;
+ } else if (!ProcessCowOp(it->second)) {
return -1;
}
num_ops -= 1;
+ read_sector += (BLOCK_SZ >> SECTOR_SHIFT);
+
it++;
+
+ if (it == chunk_vec.end() && num_ops) {
+ SNAP_LOG(ERROR) << "Invalid IO request at sector " << sector
+ << " COW ops completed; pending read-request: " << num_ops;
+ return -1;
+ }
// Update the buffer offset
bufsink_.UpdateBufferOffset(BLOCK_SZ);
-
- SNAP_LOG(DEBUG) << "ReadData at sector: " << sector << " size: " << size;
}
// Reset the buffer offset
@@ -334,7 +377,10 @@
}
void* buffer = bufsink_.GetPayloadBuffer(size);
- CHECK(buffer != nullptr);
+ if (buffer == nullptr) {
+ SNAP_LOG(ERROR) << "ZerofillDiskExceptions: Failed to get payload buffer";
+ return false;
+ }
memset(buffer, 0, size);
return true;
@@ -364,10 +410,17 @@
if (divresult.quot < vec.size()) {
size = exceptions_per_area_ * sizeof(struct disk_exception);
- CHECK(read_size == size);
+ if (read_size != size) {
+ SNAP_LOG(ERROR) << "ReadDiskExceptions: read_size: " << read_size
+ << " does not match with size: " << size;
+ return false;
+ }
void* buffer = bufsink_.GetPayloadBuffer(size);
- CHECK(buffer != nullptr);
+ if (buffer == nullptr) {
+ SNAP_LOG(ERROR) << "ReadDiskExceptions: Failed to get payload buffer of size: " << size;
+ return false;
+ }
memcpy(buffer, vec[divresult.quot].get(), size);
} else {
@@ -390,8 +443,19 @@
// Unmerged op by the kernel
if (merged_de->old_chunk != 0 || merged_de->new_chunk != 0) {
- CHECK(merged_de->old_chunk == cow_de->old_chunk);
- CHECK(merged_de->new_chunk == cow_de->new_chunk);
+ if (!(merged_de->old_chunk == cow_de->old_chunk)) {
+ SNAP_LOG(ERROR) << "GetMergeStartOffset: merged_de->old_chunk: "
+ << merged_de->old_chunk
+ << "cow_de->old_chunk: " << cow_de->old_chunk;
+ return -1;
+ }
+
+ if (!(merged_de->new_chunk == cow_de->new_chunk)) {
+ SNAP_LOG(ERROR) << "GetMergeStartOffset: merged_de->new_chunk: "
+ << merged_de->new_chunk
+ << "cow_de->new_chunk: " << cow_de->new_chunk;
+ return -1;
+ }
offset += sizeof(struct disk_exception);
*unmerged_exceptions += 1;
@@ -401,8 +465,6 @@
break;
}
- CHECK(!(*unmerged_exceptions == exceptions_per_area_));
-
SNAP_LOG(DEBUG) << "Unmerged_Exceptions: " << *unmerged_exceptions << " Offset: " << offset;
return offset;
}
@@ -421,8 +483,15 @@
struct disk_exception* cow_de =
reinterpret_cast<struct disk_exception*>((char*)unmerged_buffer + offset);
- CHECK(merged_de->new_chunk == 0);
- CHECK(merged_de->old_chunk == 0);
+ if (!(merged_de->new_chunk == 0)) {
+ SNAP_LOG(ERROR) << "GetNumberOfMergedOps: Invalid new-chunk: " << merged_de->new_chunk;
+ return -1;
+ }
+
+ if (!(merged_de->old_chunk == 0)) {
+ SNAP_LOG(ERROR) << "GetNumberOfMergedOps: Invalid old-chunk: " << merged_de->old_chunk;
+ return -1;
+ }
if (cow_de->new_chunk != 0) {
merged_ops_cur_iter += 1;
@@ -430,11 +499,18 @@
auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
std::make_pair(ChunkToSector(cow_de->new_chunk), nullptr),
Snapuserd::compare);
- CHECK(it != chunk_vec.end());
- CHECK(it->first == ChunkToSector(cow_de->new_chunk));
+
+ if (!(it != chunk_vec.end())) {
+ SNAP_LOG(ERROR) << "Sector not found: " << ChunkToSector(cow_de->new_chunk);
+ return -1;
+ }
+
+ if (!(it->first == ChunkToSector(cow_de->new_chunk))) {
+ SNAP_LOG(ERROR) << "Invalid sector: " << ChunkToSector(cow_de->new_chunk);
+ return -1;
+ }
const CowOperation* cow_op = it->second;
- CHECK(cow_op != nullptr);
if (snapuserd_->IsReadAheadFeaturePresent() && cow_op->type == kCowCopyOp) {
*copy_op = true;
// Every single copy operation has to come from read-ahead
@@ -453,7 +529,6 @@
}
}
- CHECK(cow_op->new_block == cow_de->old_chunk);
// zero out to indicate that operation is merged.
cow_de->old_chunk = 0;
cow_de->new_chunk = 0;
@@ -463,7 +538,6 @@
//
// If the op was merged in previous cycle, we don't have
// to count them.
- CHECK(cow_de->new_chunk == 0);
break;
} else {
SNAP_LOG(ERROR) << "Error in merge operation. Found invalid metadata: "
@@ -488,18 +562,33 @@
// ChunkID to vector index
lldiv_t divresult = lldiv(chunk, stride);
- CHECK(divresult.quot < vec.size());
+
+ if (!(divresult.quot < vec.size())) {
+ SNAP_LOG(ERROR) << "ProcessMergeComplete: Invalid chunk: " << chunk
+ << " Metadata-Index: " << divresult.quot << " Area-size: " << vec.size();
+ return false;
+ }
+
SNAP_LOG(DEBUG) << "ProcessMergeComplete: chunk: " << chunk
<< " Metadata-Index: " << divresult.quot;
int unmerged_exceptions = 0;
loff_t offset = GetMergeStartOffset(buffer, vec[divresult.quot].get(), &unmerged_exceptions);
+ if (offset < 0) {
+ SNAP_LOG(ERROR) << "GetMergeStartOffset failed: unmerged_exceptions: "
+ << unmerged_exceptions;
+ return false;
+ }
+
int merged_ops_cur_iter = GetNumberOfMergedOps(buffer, vec[divresult.quot].get(), offset,
unmerged_exceptions, ©_op, &commit);
// There should be at least one operation merged in this cycle
- CHECK(merged_ops_cur_iter > 0);
+ if (!(merged_ops_cur_iter > 0)) {
+ SNAP_LOG(ERROR) << "Merge operation failed: " << merged_ops_cur_iter;
+ return false;
+ }
if (copy_op) {
if (commit) {
@@ -526,6 +615,7 @@
if (errno != ENOTBLK) {
SNAP_PLOG(ERROR) << "Control-read failed";
}
+
return false;
}
@@ -533,10 +623,16 @@
}
// Send the payload/data back to dm-user misc device.
-bool WorkerThread::WriteDmUserPayload(size_t size) {
- if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
- sizeof(struct dm_user_header) + size)) {
- SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << size;
+bool WorkerThread::WriteDmUserPayload(size_t size, bool header_response) {
+ size_t payload_size = size;
+ void* buf = bufsink_.GetPayloadBufPtr();
+ if (header_response) {
+ payload_size += sizeof(struct dm_user_header);
+ buf = bufsink_.GetBufPtr();
+ }
+
+ if (!android::base::WriteFully(ctrl_fd_, buf, payload_size)) {
+ SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << payload_size;
return false;
}
@@ -570,9 +666,14 @@
// REQ_PREFLUSH flag set. Snapuser daemon doesn't have anything
// to flush per se; hence, just respond back with a success message.
if (header->sector == 0) {
- CHECK(header->len == 0);
- header->type = DM_USER_RESP_SUCCESS;
- if (!WriteDmUserPayload(0)) {
+ if (!(header->len == 0)) {
+ SNAP_LOG(ERROR) << "Invalid header length received from sector 0: " << header->len;
+ header->type = DM_USER_RESP_ERROR;
+ } else {
+ header->type = DM_USER_RESP_SUCCESS;
+ }
+
+ if (!WriteDmUserPayload(0, true)) {
return false;
}
return true;
@@ -581,36 +682,40 @@
std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
size_t remaining_size = header->len;
size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
- CHECK(read_size == BLOCK_SZ) << "DmuserWriteRequest: read_size: " << read_size;
- CHECK(header->sector > 0);
chunk_t chunk = SectorToChunk(header->sector);
auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
std::make_pair(header->sector, nullptr), Snapuserd::compare);
bool not_found = (it == chunk_vec.end() || it->first != header->sector);
- CHECK(not_found);
- void* buffer = bufsink_.GetPayloadBuffer(read_size);
- CHECK(buffer != nullptr);
- header->type = DM_USER_RESP_SUCCESS;
+ if (not_found) {
+ void* buffer = bufsink_.GetPayloadBuffer(read_size);
+ if (buffer == nullptr) {
+ SNAP_LOG(ERROR) << "DmuserWriteRequest: Failed to get payload buffer of size: "
+ << read_size;
+ header->type = DM_USER_RESP_ERROR;
+ } else {
+ header->type = DM_USER_RESP_SUCCESS;
- if (!ReadDmUserPayload(buffer, read_size)) {
- SNAP_LOG(ERROR) << "ReadDmUserPayload failed for chunk id: " << chunk
- << "Sector: " << header->sector;
- header->type = DM_USER_RESP_ERROR;
- }
+ if (!ReadDmUserPayload(buffer, read_size)) {
+ SNAP_LOG(ERROR) << "ReadDmUserPayload failed for chunk id: " << chunk
+ << "Sector: " << header->sector;
+ header->type = DM_USER_RESP_ERROR;
+ }
- if (header->type == DM_USER_RESP_SUCCESS && !ProcessMergeComplete(chunk, buffer)) {
- SNAP_LOG(ERROR) << "ProcessMergeComplete failed for chunk id: " << chunk
- << "Sector: " << header->sector;
- header->type = DM_USER_RESP_ERROR;
+ if (header->type == DM_USER_RESP_SUCCESS && !ProcessMergeComplete(chunk, buffer)) {
+ SNAP_LOG(ERROR) << "ProcessMergeComplete failed for chunk id: " << chunk
+ << "Sector: " << header->sector;
+ header->type = DM_USER_RESP_ERROR;
+ }
+ }
} else {
- SNAP_LOG(DEBUG) << "ProcessMergeComplete success for chunk id: " << chunk
- << "Sector: " << header->sector;
+ SNAP_LOG(ERROR) << "DmuserWriteRequest: Invalid sector received: header->sector";
+ header->type = DM_USER_RESP_ERROR;
}
- if (!WriteDmUserPayload(0)) {
+ if (!WriteDmUserPayload(0, true)) {
return false;
}
@@ -623,6 +728,7 @@
loff_t offset = 0;
sector_t sector = header->sector;
std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
+ bool header_response = true;
do {
size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
@@ -636,9 +742,13 @@
// never see multiple IO requests. Additionally this IO
// will always be a single 4k.
if (header->sector == 0) {
- CHECK(read_size == BLOCK_SZ) << " Sector 0 read request of size: " << read_size;
- ConstructKernelCowHeader();
- SNAP_LOG(DEBUG) << "Kernel header constructed";
+ if (read_size == BLOCK_SZ) {
+ ConstructKernelCowHeader();
+ SNAP_LOG(DEBUG) << "Kernel header constructed";
+ } else {
+ SNAP_LOG(ERROR) << "Invalid read_size: " << read_size << " for sector 0";
+ header->type = DM_USER_RESP_ERROR;
+ }
} else {
auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
std::make_pair(header->sector, nullptr), Snapuserd::compare);
@@ -654,6 +764,7 @@
}
} else {
chunk_t num_sectors_read = (offset >> SECTOR_SHIFT);
+
ret = ReadData(sector + num_sectors_read, read_size);
if (ret < 0) {
SNAP_LOG(ERROR) << "ReadData failed for chunk id: " << chunk
@@ -669,12 +780,19 @@
// Just return the header if it is an error
if (header->type == DM_USER_RESP_ERROR) {
+ SNAP_LOG(ERROR) << "IO read request failed...";
ret = 0;
}
+ if (!header_response) {
+ CHECK(header->type == DM_USER_RESP_SUCCESS)
+ << " failed for sector: " << sector << " header->len: " << header->len
+ << " remaining_size: " << remaining_size;
+ }
+
// Daemon will not be terminated if there is any error. We will
// just send the error back to dm-user.
- if (!WriteDmUserPayload(ret)) {
+ if (!WriteDmUserPayload(ret, header_response)) {
return false;
}
@@ -684,6 +802,7 @@
remaining_size -= ret;
offset += ret;
+ header_response = false;
} while (remaining_size > 0);
return true;
@@ -729,11 +848,11 @@
return false;
}
- SNAP_LOG(DEBUG) << "msg->seq: " << std::hex << header->seq;
- SNAP_LOG(DEBUG) << "msg->type: " << std::hex << header->type;
- SNAP_LOG(DEBUG) << "msg->flags: " << std::hex << header->flags;
- SNAP_LOG(DEBUG) << "msg->sector: " << std::hex << header->sector;
- SNAP_LOG(DEBUG) << "msg->len: " << std::hex << header->len;
+ SNAP_LOG(DEBUG) << "Daemon: msg->seq: " << std::dec << header->seq;
+ SNAP_LOG(DEBUG) << "Daemon: msg->len: " << std::dec << header->len;
+ SNAP_LOG(DEBUG) << "Daemon: msg->sector: " << std::dec << header->sector;
+ SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
+ SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;
switch (header->type) {
case DM_USER_REQ_MAP_READ: {
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 242fa93..0c5fe3d 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -735,23 +735,46 @@
fi
}
+[ "USAGE: join_with <delimiter> <strings>
+
+Joins strings with delimiter" ]
+join_with() {
+ if [ "${#}" -lt 2 ]; then
+ echo
+ return
+ fi
+ local delimiter="${1}"
+ local result="${2}"
+ shift 2
+ for element in "${@}"; do
+ result+="${delimiter}${element}"
+ done
+ echo "${result}"
+}
+
[ "USAGE: skip_administrative_mounts [data] < /proc/mounts
Filters out all administrative (eg: sysfs) mounts uninteresting to the test" ]
skip_administrative_mounts() {
+ local exclude_filesystems=(
+ "overlay" "tmpfs" "none" "sysfs" "proc" "selinuxfs" "debugfs" "bpf"
+ "binfmt_misc" "cg2_bpf" "pstore" "tracefs" "adb" "mtp" "ptp" "devpts"
+ "ramdumpfs" "binder" "securityfs" "functionfs" "rootfs"
+ )
+ local exclude_devices=(
+ "[/]sys[/]kernel[/]debug" "[/]data[/]media" "[/]dev[/]block[/]loop[0-9]*"
+ "${exclude_filesystems[@]}"
+ )
+ local exclude_mount_points=(
+ "[/]cache" "[/]mnt[/]scratch" "[/]mnt[/]vendor[/]persist" "[/]persist"
+ "[/]metadata"
+ )
if [ "data" = "${1}" ]; then
- grep -v " /data "
- else
- cat -
- fi |
- grep -v \
- -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
- -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
- -e "^\(ramdumpfs\|binder\|/sys/kernel/debug\|securityfs\) " \
- -e " functionfs " \
- -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
- -e "^rootfs / rootfs rw," \
- -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
+ exclude_mount_points+=("[/]data")
+ fi
+ awk '$1 !~ /^('"$(join_with "|" "${exclude_devices[@]}")"')$/ &&
+ $2 !~ /^('"$(join_with "|" "${exclude_mount_points[@]}")"')$/ &&
+ $3 !~ /^('"$(join_with "|" "${exclude_filesystems[@]}")"')$/'
}
[ "USAGE: skip_unrelated_mounts < /proc/mounts
@@ -907,9 +930,11 @@
# Acquire list of system partitions
+# KISS (assume system partition mount point is "/<partition name>")
PARTITIONS=`adb_su cat /vendor/etc/fstab* </dev/null |
+ grep -v "^[#${SPACE}${TAB}]" |
skip_administrative_mounts |
- sed -n "s@^\([^ ${TAB}/][^ ${TAB}/]*\)[ ${TAB}].*[, ${TAB}]ro[, ${TAB}].*@\1@p" |
+ awk '$1 ~ /^[^/]+$/ && "/"$1 == $2 && $4 ~ /(^|,)ro(,|$)/ { print $1 }' |
sort -u |
tr '\n' ' '`
PARTITIONS="${PARTITIONS:-system vendor}"
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 83174ef..eb2919b 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -325,14 +325,14 @@
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source / ext4 ro,barrier=1 wait,slotselect,avb
+source / ext4 ro,barrier=1 wait,avb
source /metadata ext4 noatime,nosuid,nodev,discard wait,formattable
source /data f2fs noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier latemount,wait,check,fileencryption=ice,keydirectory=/metadata/vold/metadata_encryption,quota,formattable,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,reservedsize=128M
source /misc emmc defaults defaults
-source /vendor/firmware_mnt vfat ro,shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337,context=u:object_r:firmware_file:s0 wait,slotselect
+source /vendor/firmware_mnt vfat ro,shortname=lower,uid=1000,gid=1000,dmask=227,fmask=337,context=u:object_r:firmware_file:s0 wait
source auto vfat defaults voldmanaged=usb:auto
source none swap defaults zramsize=1073741824,max_comp_streams=8
@@ -412,8 +412,8 @@
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
source none0 swap defaults wait,check,nonremovable,recoveryonly,verifyatboot,verify
-source none1 swap defaults avb,noemulatedsd,notrim,formattable,slotselect,nofail
-source none2 swap defaults first_stage_mount,latemount,quota,logical,slotselect_other
+source none1 swap defaults avb,noemulatedsd,notrim,formattable,nofail
+source none2 swap defaults first_stage_mount,latemount,quota,logical
source none3 swap defaults checkpoint=block
source none4 swap defaults checkpoint=fs
source none5 swap defaults defaults
@@ -445,7 +445,6 @@
flags.no_emulated_sd = true;
flags.no_trim = true;
flags.formattable = true;
- flags.slot_select = true;
flags.no_fail = true;
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
@@ -458,7 +457,6 @@
flags.late_mount = true;
flags.quota = true;
flags.logical = true;
- flags.slot_select_other = true;
EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
}
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index d22f68f..76f5193 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -123,7 +123,10 @@
The exact firmware file to be served can be customized by running an external program by a
`external_firmware_handler` line in a ueventd.rc file. This line takes the format of
- external_firmware_handler <devpath> <user name to run as> <path to external program>
+ external_firmware_handler <devpath> <user [group]> <path to external program>
+
+The handler will be run as the given user, or if a group is provided, as the given user and group.
+
For example
external_firmware_handler /devices/leds/red/firmware/coeffs.bin system /vendor/bin/led_coeffs.bin
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index bdc2922..30e808d 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -19,6 +19,7 @@
#include <fcntl.h>
#include <fnmatch.h>
#include <glob.h>
+#include <grp.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
@@ -81,9 +82,9 @@
return access("/dev/.booting", F_OK) == 0;
}
-ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
+ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid,
std::string handler_path)
- : devpath(std::move(devpath)), uid(uid), handler_path(std::move(handler_path)) {
+ : devpath(std::move(devpath)), uid(uid), gid(gid), handler_path(std::move(handler_path)) {
auto wildcard_position = this->devpath.find('*');
if (wildcard_position != std::string::npos) {
if (wildcard_position == this->devpath.length() - 1) {
@@ -97,13 +98,17 @@
}
}
+ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid,
+ std::string handler_path)
+ : ExternalFirmwareHandler(devpath, uid, 0, handler_path) {}
+
FirmwareHandler::FirmwareHandler(std::vector<std::string> firmware_directories,
std::vector<ExternalFirmwareHandler> external_firmware_handlers)
: firmware_directories_(std::move(firmware_directories)),
external_firmware_handlers_(std::move(external_firmware_handlers)) {}
Result<std::string> FirmwareHandler::RunExternalHandler(const std::string& handler, uid_t uid,
- const Uevent& uevent) const {
+ gid_t gid, const Uevent& uevent) const {
unique_fd child_stdout;
unique_fd parent_stdout;
if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) {
@@ -140,6 +145,13 @@
}
c_args.emplace_back(nullptr);
+ if (gid != 0) {
+ if (setgid(gid) != 0) {
+ fprintf(stderr, "setgid() failed: %s", strerror(errno));
+ _exit(EXIT_FAILURE);
+ }
+ }
+
if (setuid(uid) != 0) {
fprintf(stderr, "setuid() failed: %s", strerror(errno));
_exit(EXIT_FAILURE);
@@ -196,8 +208,8 @@
<< "' for devpath: '" << uevent.path << "' firmware: '" << uevent.firmware
<< "'";
- auto result =
- RunExternalHandler(external_handler.handler_path, external_handler.uid, uevent);
+ auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid,
+ external_handler.gid, uevent);
if (!result.ok()) {
LOG(ERROR) << "Using default firmware; External firmware handler failed: "
<< result.error();
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index 3c35b1f..d2f7347 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -16,6 +16,7 @@
#pragma once
+#include <grp.h>
#include <pwd.h>
#include <functional>
@@ -31,9 +32,11 @@
struct ExternalFirmwareHandler {
ExternalFirmwareHandler(std::string devpath, uid_t uid, std::string handler_path);
+ ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid, std::string handler_path);
std::string devpath;
uid_t uid;
+ gid_t gid;
std::string handler_path;
std::function<bool(const std::string&)> match;
@@ -51,7 +54,7 @@
friend void FirmwareTestWithExternalHandler(const std::string& test_name,
bool expect_new_firmware);
- Result<std::string> RunExternalHandler(const std::string& handler, uid_t uid,
+ 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;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index a733839..546ea8e 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -331,12 +331,6 @@
if (devices.empty()) {
return true;
}
- // excluding overlays
- for (auto iter = devices.begin(); iter != devices.end(); ) {
- if (*iter=="overlay") iter = devices.erase(iter);
- else iter++;
- }
-
return block_dev_init_.InitDevices(std::move(devices));
}
@@ -548,6 +542,7 @@
continue;
}
+ // Handle overlayfs entries later.
if (current->fs_type == "overlay") {
++current;
continue;
@@ -577,6 +572,12 @@
current = end;
}
+ for (const auto& entry : fstab_) {
+ if (entry.fs_type == "overlay") {
+ fs_mgr_mount_overlayfs_fstab_entry(entry);
+ }
+ }
+
// If we don't see /system or / in the fstab, then we need to create an root entry for
// overlayfs.
if (!GetEntryForMountPoint(&fstab_, "/system") && !GetEntryForMountPoint(&fstab_, "/")) {
@@ -602,13 +603,6 @@
};
MapScratchPartitionIfNeeded(&fstab_, init_devices);
- for (auto current = fstab_.begin(); current != fstab_.end(); ) {
- if (current->fs_type == "overlay") {
- fs_mgr_overlayfs_mount_fstab_entry(current->lowerdir, current->mount_point);
- }
- ++current;
- }
-
fs_mgr_overlayfs_mount_all(&fstab_);
return true;
@@ -695,6 +689,10 @@
// Includes the partition names of fstab records.
// Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
for (const auto& fstab_entry : fstab_) {
+ // Skip pseudo filesystems.
+ if (fstab_entry.fs_type == "overlay") {
+ continue;
+ }
if (!fstab_entry.fs_mgr_flags.logical) {
devices->emplace(basename(fstab_entry.blk_device.c_str()));
}
@@ -757,6 +755,10 @@
if (fstab_entry.fs_mgr_flags.avb) {
need_dm_verity_ = true;
}
+ // Skip pseudo filesystems.
+ if (fstab_entry.fs_type == "overlay") {
+ continue;
+ }
if (fstab_entry.fs_mgr_flags.logical) {
// Don't try to find logical partitions via uevent regeneration.
logical_partitions.emplace(basename(fstab_entry.blk_device.c_str()));
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
index c6dcfa2..ac6b7b2 100644
--- a/init/property_service_test.cpp
+++ b/init/property_service_test.cpp
@@ -23,6 +23,7 @@
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
+#include <android-base/strings.h>
#include <gtest/gtest.h>
using android::base::GetProperty;
@@ -90,5 +91,39 @@
EXPECT_FALSE(SetProperty("sys.powerctl", "reboot,userspace"));
}
+TEST(property_service, check_fingerprint_with_legacy_build_id) {
+ std::string legacy_build_id = GetProperty("ro.build.legacy.id", "");
+ if (legacy_build_id.empty()) {
+ GTEST_SKIP() << "Skipping test, legacy build id isn't set.";
+ }
+
+ std::string vbmeta_digest = GetProperty("ro.boot.vbmeta.digest", "");
+ ASSERT_GE(vbmeta_digest.size(), 8u);
+ std::string build_id = GetProperty("ro.boot.build.id", "");
+ // Check that the build id is constructed with the prefix of vbmeta digest
+ std::string expected_build_id = legacy_build_id + "." + vbmeta_digest.substr(0, 8);
+ ASSERT_EQ(expected_build_id, build_id);
+ // Check that the fingerprint is constructed with the expected format.
+ std::string fingerprint = GetProperty("ro.build.fingerprint", "");
+ std::vector<std::string> fingerprint_fields = {
+ GetProperty("ro.product.brand", ""),
+ "/",
+ GetProperty("ro.product.name", ""),
+ "/",
+ GetProperty("ro.product.device", ""),
+ ":",
+ GetProperty("ro.build.version.release_or_codename", ""),
+ "/",
+ expected_build_id,
+ "/",
+ GetProperty("ro.build.version.incremental", ""),
+ ":",
+ GetProperty("ro.build.type", ""),
+ "/",
+ GetProperty("ro.build.tags", "")};
+
+ ASSERT_EQ(android::base::Join(fingerprint_fields, ""), fingerprint);
+}
+
} // namespace init
} // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index ab0e48e..0e788e4 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -478,6 +478,11 @@
// cut the last "\n"
backing_dev.erase(backing_dev.length() - 1);
+ if (android::base::StartsWith(backing_dev, "none")) {
+ LOG(INFO) << "No zram backing device configured";
+ return {};
+ }
+
// shutdown zram handle
Timer swap_timer;
LOG(INFO) << "swapoff() start...";
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 2221228..9a14406 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -101,8 +101,8 @@
Result<void> ParseExternalFirmwareHandlerLine(
std::vector<std::string>&& args,
std::vector<ExternalFirmwareHandler>* external_firmware_handlers) {
- if (args.size() != 4) {
- return Error() << "external_firmware_handler lines must have exactly 3 parameters";
+ if (args.size() != 4 && args.size() != 5) {
+ return Error() << "external_firmware_handler lines must have 3 or 4 parameters";
}
if (std::find_if(external_firmware_handlers->begin(), external_firmware_handlers->end(),
@@ -117,7 +117,19 @@
return ErrnoError() << "invalid handler uid'" << args[2] << "'";
}
- ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, std::move(args[3]));
+ gid_t gid = 0;
+ int handler_index = 3;
+ if (args.size() == 5) {
+ struct group* grp = getgrnam(args[3].c_str());
+ if (!grp) {
+ return ErrnoError() << "invalid handler gid '" << args[3] << "'";
+ }
+ gid = grp->gr_gid;
+ handler_index = 4;
+ }
+
+ ExternalFirmwareHandler handler(std::move(args[1]), pwd->pw_uid, gid,
+ std::move(args[handler_index]));
external_firmware_handlers->emplace_back(std::move(handler));
return {};
diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp
index c5aa9e3..d77cb03 100644
--- a/init/ueventd_parser_test.cpp
+++ b/init/ueventd_parser_test.cpp
@@ -49,6 +49,7 @@
const ExternalFirmwareHandler& test) {
EXPECT_EQ(expected.devpath, test.devpath) << expected.devpath;
EXPECT_EQ(expected.uid, test.uid) << expected.uid;
+ EXPECT_EQ(expected.gid, test.gid) << expected.gid;
EXPECT_EQ(expected.handler_path, test.handler_path) << expected.handler_path;
}
@@ -157,39 +158,59 @@
external_firmware_handler /devices/path/firmware/* root "/vendor/bin/firmware_handler.sh"
external_firmware_handler /devices/path/firmware/something* system "/vendor/bin/firmware_handler.sh"
external_firmware_handler /devices/path/*/firmware/something*.bin radio "/vendor/bin/firmware_handler.sh"
+external_firmware_handler /devices/path/firmware/something003.bin system system /vendor/bin/firmware_handler.sh
+external_firmware_handler /devices/path/firmware/something004.bin radio radio "/vendor/bin/firmware_handler.sh --has --arguments"
)";
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
{
"devpath",
AID_ROOT,
+ AID_ROOT,
"handler_path",
},
{
"/devices/path/firmware/something001.bin",
AID_SYSTEM,
+ AID_ROOT,
"/vendor/bin/firmware_handler.sh",
},
{
"/devices/path/firmware/something002.bin",
AID_RADIO,
+ AID_ROOT,
"/vendor/bin/firmware_handler.sh --has --arguments",
},
{
"/devices/path/firmware/",
AID_ROOT,
+ AID_ROOT,
"/vendor/bin/firmware_handler.sh",
},
{
"/devices/path/firmware/something",
AID_SYSTEM,
+ AID_ROOT,
"/vendor/bin/firmware_handler.sh",
},
{
"/devices/path/*/firmware/something*.bin",
AID_RADIO,
+ AID_ROOT,
"/vendor/bin/firmware_handler.sh",
},
+ {
+ "/devices/path/firmware/something003.bin",
+ AID_SYSTEM,
+ AID_SYSTEM,
+ "/vendor/bin/firmware_handler.sh",
+ },
+ {
+ "/devices/path/firmware/something004.bin",
+ AID_RADIO,
+ AID_RADIO,
+ "/vendor/bin/firmware_handler.sh --has --arguments",
+ },
};
TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers});
@@ -205,6 +226,7 @@
{
"devpath",
AID_ROOT,
+ AID_ROOT,
"handler_path",
},
};
@@ -305,7 +327,7 @@
};
auto external_firmware_handlers = std::vector<ExternalFirmwareHandler>{
- {"/devices/path/firmware/firmware001.bin", AID_ROOT, "/vendor/bin/touch.sh"},
+ {"/devices/path/firmware/firmware001.bin", AID_ROOT, AID_ROOT, "/vendor/bin/touch.sh"},
};
size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024;
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 8f22d89..c471fa0 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -127,7 +127,7 @@
#define AID_EXT_DATA_RW 1078 /* GID for app-private data directories on external storage */
#define AID_EXT_OBB_RW 1079 /* GID for OBB directories on external storage */
#define AID_CONTEXT_HUB 1080 /* GID for access to the Context Hub */
-#define AID_VIRTMANAGER 1081 /* VirtManager daemon */
+#define AID_VIRTUALIZATIONSERVICE 1081 /* VirtualizationService daemon */
#define AID_ARTD 1082 /* ART Service daemon */
#define AID_UWB 1083 /* UWB subsystem */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index db00a49..cf74e65 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -308,9 +308,7 @@
bool ApplyProfileAction::ExecuteForTask(int tid) const {
for (const auto& profile : profiles_) {
- if (!profile->ExecuteForTask(tid)) {
- PLOG(WARNING) << "ExecuteForTask failed for aggregate profile";
- }
+ profile->ExecuteForTask(tid);
}
return true;
}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 6395567..13e4c02 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -275,12 +275,6 @@
}
cc_fuzz {
- name: "libutils_fuzz_stopwatch",
- defaults: ["libutils_fuzz_defaults"],
- srcs: ["StopWatch_fuzz.cpp"],
-}
-
-cc_fuzz {
name: "libutils_fuzz_refbase",
defaults: ["libutils_fuzz_defaults"],
srcs: ["RefBase_fuzz.cpp"],
diff --git a/libutils/README b/libutils/README
deleted file mode 100644
index 01741e0..0000000
--- a/libutils/README
+++ /dev/null
@@ -1,289 +0,0 @@
-Android Utility Function Library
-================================
-
-
-If you need a feature that is native to Linux but not present on other
-platforms, construct a platform-dependent implementation that shares
-the Linux interface. That way the actual device runs as "light" as
-possible.
-
-If that isn't feasible, create a system-independent interface and hide
-the details.
-
-The ultimate goal is *not* to create a super-duper platform abstraction
-layer. The goal is to provide an optimized solution for Linux with
-reasonable implementations for other platforms.
-
-
-
-Resource overlay
-================
-
-
-Introduction
-------------
-
-Overlay packages are special .apk files which provide no code but
-additional resource values (and possibly new configurations) for
-resources in other packages. When an application requests resources,
-the system will return values from either the application's original
-package or any associated overlay package. Any redirection is completely
-transparent to the calling application.
-
-Resource values have the following precedence table, listed in
-descending precedence.
-
- * overlay package, matching config (eg res/values-en-land)
-
- * original package, matching config
-
- * overlay package, no config (eg res/values)
-
- * original package, no config
-
-During compilation, overlay packages are differentiated from regular
-packages by passing the -o flag to aapt.
-
-
-Background
-----------
-
-This section provides generic background material on resources in
-Android.
-
-
-How resources are bundled in .apk files
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Android .apk files are .zip files, usually housing .dex code,
-certificates and resources, though packages containing resources but
-no code are possible. Resources can be divided into the following
-categories; a `configuration' indicates a set of phone language, display
-density, network operator, etc.
-
- * assets: uncompressed, raw files packaged as part of an .apk and
- explicitly referenced by filename. These files are
- independent of configuration.
-
- * res/drawable: bitmap or xml graphics. Each file may have different
- values depending on configuration.
-
- * res/values: integers, strings, etc. Each resource may have different
- values depending on configuration.
-
-Resource meta information and information proper is stored in a binary
-format in a named file resources.arsc, bundled as part of the .apk.
-
-Resource IDs and lookup
-~~~~~~~~~~~~~~~~~~~~~~~
-During compilation, the aapt tool gathers application resources and
-generates a resources.arsc file. Each resource name is assigned an
-integer ID 0xppttiii (translated to a symbolic name via R.java), where
-
- * pp: corresponds to the package namespace (details below).
-
- * tt: corresponds to the resource type (string, int, etc). Every
- resource of the same type within the same package has the same
- tt value, but depending on available types, the actual numerical
- value may be different between packages.
-
- * iiii: sequential number, assigned in the order resources are found.
-
-Resource values are specified paired with a set of configuration
-constraints (the default being the empty set), eg res/values-sv-port
-which imposes restrictions on language (Swedish) and display orientation
-(portrait). During lookup, every constraint set is matched against the
-current configuration, and the value corresponding to the best matching
-constraint set is returned (ResourceTypes.{h,cpp}).
-
-Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility
-is governed by AssetManager.cpp, which tracks loaded resources per
-process.
-
-Assets are looked up by path and filename in AssetManager.cpp. The path
-to resources in res/drawable are located by ResourceTypes.cpp and then
-handled like assets by AssetManager.cpp. Other resources are handled
-solely by ResourceTypes.cpp.
-
-Package ID as namespace
-~~~~~~~~~~~~~~~~~~~~~~~
-The pp part of a resource ID defines a namespace. Android currently
-defines two namespaces:
-
- * 0x01: system resources (pre-installed in framework-res.apk)
-
- * 0x7f: application resources (bundled in the application .apk)
-
-ResourceTypes.cpp supports package IDs between 0x01 and 0x7f
-(inclusive); values outside this range are invalid.
-
-Each running (Dalvik) process is assigned a unique instance of
-AssetManager, which in turn keeps a forest structure of loaded
-resource.arsc files. Normally, this forest is structured as follows,
-where mPackageMap is the internal vector employed in ResourceTypes.cpp.
-
-mPackageMap[0x00] -> system package
-mPackageMap[0x01] -> NULL
-mPackageMap[0x02] -> NULL
-...
-mPackageMap[0x7f - 2] -> NULL
-mPackageMap[0x7f - 1] -> application package
-
-
-
-The resource overlay extension
-------------------------------
-
-The resource overlay mechanism aims to (partly) shadow and extend
-existing resources with new values for defined and new configurations.
-Technically, this is achieved by adding resource-only packages (called
-overlay packages) to existing resource namespaces, like so:
-
-mPackageMap[0x00] -> system package -> system overlay package
-mPackageMap[0x01] -> NULL
-mPackageMap[0x02] -> NULL
-...
-mPackageMap[0x7f - 2] -> NULL
-mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2
-
-The use of overlay resources is completely transparent to
-applications; no additional resource identifiers are introduced, only
-configuration/value pairs. Any number of overlay packages may be loaded
-at a time; overlay packages are agnostic to what they target -- both
-system and application resources are fair game.
-
-The package targeted by an overlay package is called the target or
-original package.
-
-Resource overlay operates on symbolic resources names. Hence, to
-override the string/str1 resources in a package, the overlay package
-would include a resource also named string/str1. The end user does not
-have to worry about the numeric resources IDs assigned by aapt, as this
-is resolved automatically by the system.
-
-As of this writing, the use of resource overlay has not been fully
-explored. Until it has, only OEMs are trusted to use resource overlay.
-For this reason, overlay packages must reside in /system/overlay.
-
-
-Resource ID mapping
-~~~~~~~~~~~~~~~~~~~
-Resource identifiers must be coherent within the same namespace (ie
-PackageGroup in ResourceTypes.cpp). Calling applications will refer to
-resources using the IDs defined in the original package, but there is no
-guarantee aapt has assigned the same ID to the corresponding resource in
-an overlay package. To translate between the two, a resource ID mapping
-{original ID -> overlay ID} is created during package installation
-(PackageManagerService.java) and used during resource lookup. The
-mapping is stored in /data/resource-cache, with a @idmap file name
-suffix.
-
-The idmap file format is documented in a separate section, below.
-
-
-Package management
-~~~~~~~~~~~~~~~~~~
-Packages are managed by the PackageManagerService. Addition and removal
-of packages are monitored via the inotify framework, exposed via
-android.os.FileObserver.
-
-During initialization of a Dalvik process, ActivityThread.java requests
-the process' AssetManager (by proxy, via AssetManager.java and JNI)
-to load a list of packages. This list includes overlay packages, if
-present.
-
-When a target package or a corresponding overlay package is installed,
-the target package's process is stopped and a new idmap is generated.
-This is similar to how applications are stopped when their packages are
-upgraded.
-
-
-Creating overlay packages
--------------------------
-
-Overlay packages should contain no code, define (some) resources with
-the same type and name as in the original package, and be compiled with
-the -o flag passed to aapt.
-
-The aapt -o flag instructs aapt to create an overlay package.
-Technically, this means the package will be assigned package id 0x00.
-
-There are no restrictions on overlay packages names, though the naming
-convention <original.package.name>.overlay.<name> is recommended.
-
-
-Example overlay package
-~~~~~~~~~~~~~~~~~~~~~~~
-
-To overlay the resource bool/b in package com.foo.bar, to be applied
-when the display is in landscape mode, create a new package with
-no source code and a single .xml file under res/values-land, with
-an entry for bool/b. Compile with aapt -o and place the results in
-/system/overlay by adding the following to Android.mk:
-
-LOCAL_AAPT_FLAGS := -o com.foo.bar
-LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay
-
-
-The ID map (idmap) file format
-------------------------------
-
-The idmap format is designed for lookup performance. However, leading
-and trailing undefined overlay values are discarded to reduce the memory
-footprint.
-
-
-idmap grammar
-~~~~~~~~~~~~~
-All atoms (names in square brackets) are uint32_t integers. The
-idmap-magic constant spells "idmp" in ASCII. Offsets are given relative
-to the data_header, not to the beginning of the file.
-
-map := header data
-header := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg>
-idmap-magic := <0x706d6469>
-data := data_header type_block+
-data_header := <m> header_block{m}
-header_block := <0> | <type_block_offset>
-type_block := <n> <id_offset> entry{n}
-entry := <resource_id_in_target_package>
-
-
-idmap example
-~~~~~~~~~~~~~
-Given a pair of target and overlay packages with CRC sums 0x216a8fe2
-and 0x6b9beaec, each defining the following resources
-
-Name Target package Overlay package
-string/str0 0x7f010000 -
-string/str1 0x7f010001 0x7f010000
-string/str2 0x7f010002 -
-string/str3 0x7f010003 0x7f010001
-string/str4 0x7f010004 -
-bool/bool0 0x7f020000 -
-integer/int0 0x7f030000 0x7f020000
-integer/int1 0x7f030001 -
-
-the corresponding resource map is
-
-0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \
-0x00000004 0x00000000 0x00000009 0x00000003 \
-0x00000001 0x7f010000 0x00000000 0x7f010001 \
-0x00000001 0x00000000 0x7f020000
-
-or, formatted differently
-
-0x706d6469 # magic: all idmap files begin with this constant
-0x216a8fe2 # CRC32 of the resources.arsc file in the original package
-0x6b9beaec # CRC32 of the resources.arsc file in the overlay package
-0x00000003 # header; three types (string, bool, integer) in the target package
-0x00000004 # header_block for type 0 (string) is located at offset 4
-0x00000000 # no bool type exists in overlay package -> no header_block
-0x00000009 # header_block for type 2 (integer) is located at offset 9
-0x00000003 # header_block for string; overlay IDs span 3 elements
-0x00000001 # the first string in target package is entry 1 == offset
-0x7f010000 # target 0x7f01001 -> overlay 0x7f010000
-0x00000000 # str2 not defined in overlay package
-0x7f010001 # target 0x7f010003 -> overlay 0x7f010001
-0x00000001 # header_block for integer; overlay IDs span 1 element
-0x00000000 # offset == 0
-0x7f020000 # target 0x7f030000 -> overlay 0x7f020000
diff --git a/libutils/StopWatch.cpp b/libutils/StopWatch.cpp
index d01865e..28e2d76 100644
--- a/libutils/StopWatch.cpp
+++ b/libutils/StopWatch.cpp
@@ -26,58 +26,26 @@
#include <utils/Log.h>
-/*****************************************************************************/
-
namespace android {
StopWatch::StopWatch(const char* name, int clock) : mName(name), mClock(clock) {
reset();
}
-StopWatch::~StopWatch()
-{
- nsecs_t elapsed = elapsedTime();
- const int n = mNumLaps;
- ALOGD("StopWatch %s (us): %" PRId64 " ", mName, ns2us(elapsed));
- for (int i=0 ; i<n ; i++) {
- const nsecs_t soFar = mLaps[i].soFar;
- const nsecs_t thisLap = mLaps[i].thisLap;
- ALOGD(" [%d: %" PRId64 ", %" PRId64, i, ns2us(soFar), ns2us(thisLap));
- }
+StopWatch::~StopWatch() {
+ ALOGD("StopWatch %s (us): %" PRId64 " ", name(), ns2us(elapsedTime()));
}
-const char* StopWatch::name() const
-{
+const char* StopWatch::name() const {
return mName;
}
-nsecs_t StopWatch::lap()
-{
- nsecs_t elapsed = elapsedTime();
- if (mNumLaps >= 8) {
- elapsed = 0;
- } else {
- const int n = mNumLaps;
- mLaps[n].soFar = elapsed;
- mLaps[n].thisLap = n ? (elapsed - mLaps[n-1].soFar) : elapsed;
- mNumLaps = n+1;
- }
- return elapsed;
-}
-
-nsecs_t StopWatch::elapsedTime() const
-{
+nsecs_t StopWatch::elapsedTime() const {
return systemTime(mClock) - mStartTime;
}
-void StopWatch::reset()
-{
- mNumLaps = 0;
+void StopWatch::reset() {
mStartTime = systemTime(mClock);
}
-
-/*****************************************************************************/
-
-}; // namespace android
-
+} // namespace android
diff --git a/libutils/StopWatch_fuzz.cpp b/libutils/StopWatch_fuzz.cpp
deleted file mode 100644
index 63d8a28..0000000
--- a/libutils/StopWatch_fuzz.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "fuzzer/FuzzedDataProvider.h"
-#include "utils/StopWatch.h"
-
-static constexpr int MAX_OPERATIONS = 100;
-static constexpr int MAX_NAME_LEN = 2048;
-
-static const std::vector<std::function<void(android::StopWatch)>> operations = {
- [](android::StopWatch stopWatch) -> void { stopWatch.reset(); },
- [](android::StopWatch stopWatch) -> void { stopWatch.lap(); },
- [](android::StopWatch stopWatch) -> void { stopWatch.elapsedTime(); },
- [](android::StopWatch stopWatch) -> void { stopWatch.name(); },
-};
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider dataProvider(data, size);
- std::string nameStr = dataProvider.ConsumeRandomLengthString(MAX_NAME_LEN);
- int clockVal = dataProvider.ConsumeIntegral<int>();
- android::StopWatch stopWatch = android::StopWatch(nameStr.c_str(), clockVal);
- std::vector<uint8_t> opsToRun = dataProvider.ConsumeRemainingBytes<uint8_t>();
- int opsRun = 0;
- for (auto it : opsToRun) {
- if (opsRun++ >= MAX_OPERATIONS) {
- break;
- }
- it = it % operations.size();
- operations[it](stopWatch);
- }
- return 0;
-}
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index e3e5f11..faf90c2 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -411,36 +411,4 @@
return OK;
}
-status_t String16::remove(size_t len, size_t begin)
-{
- const size_t N = size();
- if (begin >= N) {
- release();
- mString = getEmptyString();
- return OK;
- }
- if (len > N || len > N - begin) len = N - begin;
- if (begin == 0 && len == N) {
- return OK;
- }
-
- if (begin > 0) {
- SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((N + 1) * sizeof(char16_t)));
- if (!buf) {
- return NO_MEMORY;
- }
- char16_t* str = (char16_t*)buf->data();
- memmove(str, str+begin, (N-begin+1)*sizeof(char16_t));
- mString = str;
- }
- SharedBuffer* buf = static_cast<SharedBuffer*>(editResize((len + 1) * sizeof(char16_t)));
- if (buf) {
- char16_t* str = (char16_t*)buf->data();
- str[len] = 0;
- mString = str;
- return OK;
- }
- return NO_MEMORY;
-}
-
}; // namespace android
diff --git a/libutils/String16_fuzz.cpp b/libutils/String16_fuzz.cpp
index defa0f5..d7e5ec7 100644
--- a/libutils/String16_fuzz.cpp
+++ b/libutils/String16_fuzz.cpp
@@ -72,12 +72,6 @@
char16_t replaceChar = dataProvider.ConsumeIntegral<char16_t>();
str1.replaceAll(findChar, replaceChar);
}),
- ([](FuzzedDataProvider& dataProvider, android::String16 str1,
- android::String16) -> void {
- size_t len = dataProvider.ConsumeIntegral<size_t>();
- size_t begin = dataProvider.ConsumeIntegral<size_t>();
- str1.remove(len, begin);
- }),
};
void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String16 str1,
@@ -111,7 +105,5 @@
callFunc(op, dataProvider, str_one_utf16, str_two_utf16);
}
- str_one_utf16.remove(0, str_one_utf16.size());
- str_two_utf16.remove(0, str_two_utf16.size());
return 0;
}
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
index c2e9b02..54662ac 100644
--- a/libutils/String16_test.cpp
+++ b/libutils/String16_test.cpp
@@ -90,13 +90,6 @@
EXPECT_STR16EQ(u"VerifyInsert me", tmp);
}
-TEST(String16Test, Remove) {
- String16 tmp("Verify me");
- tmp.remove(2, 6);
- EXPECT_EQ(2U, tmp.size());
- EXPECT_STR16EQ(u" m", tmp);
-}
-
TEST(String16Test, ReplaceAll) {
String16 tmp("Verify verify Verify");
tmp.replaceAll(u'r', u'!');
@@ -161,14 +154,6 @@
EXPECT_FALSE(tmp.isStaticString());
}
-TEST(String16Test, StaticStringRemove) {
- StaticString16 tmp(u"Verify me");
- tmp.remove(2, 6);
- EXPECT_EQ(2U, tmp.size());
- EXPECT_STR16EQ(u" m", tmp);
- EXPECT_FALSE(tmp.isStaticString());
-}
-
TEST(String16Test, StaticStringReplaceAll) {
StaticString16 tmp(u"Verify verify Verify");
tmp.replaceAll(u'r', u'!');
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index fd3f4a9..4cfac57 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -14,9 +14,6 @@
* limitations under the License.
*/
-//
-// Timer functions.
-//
#include <utils/Timers.h>
#include <limits.h>
@@ -24,11 +21,12 @@
#include <time.h>
#include <android-base/macros.h>
+#include <utils/Log.h>
static constexpr size_t clock_id_max = 5;
static void checkClockId(int clock) {
- if (clock < 0 || clock >= clock_id_max) abort();
+ LOG_ALWAYS_FATAL_IF(clock < 0 || clock >= clock_id_max, "invalid clock id");
}
#if defined(__linux__)
@@ -56,18 +54,10 @@
}
#endif
-int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime)
-{
- nsecs_t timeoutDelayMillis;
- if (timeoutTime > referenceTime) {
- uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
- if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) {
- timeoutDelayMillis = -1;
- } else {
- timeoutDelayMillis = (timeoutDelay + 999999LL) / 1000000LL;
- }
- } else {
- timeoutDelayMillis = 0;
- }
- return (int)timeoutDelayMillis;
+int toMillisecondTimeoutDelay(nsecs_t referenceTime, nsecs_t timeoutTime) {
+ if (timeoutTime <= referenceTime) return 0;
+
+ uint64_t timeoutDelay = uint64_t(timeoutTime - referenceTime);
+ if (timeoutDelay > uint64_t((INT_MAX - 1) * 1000000LL)) return -1;
+ return (timeoutDelay + 999999LL) / 1000000LL;
}
diff --git a/libutils/Timers_test.cpp b/libutils/Timers_test.cpp
index ec0051e..c0a6d49 100644
--- a/libutils/Timers_test.cpp
+++ b/libutils/Timers_test.cpp
@@ -27,3 +27,12 @@
systemTime(SYSTEM_TIME_BOOTTIME);
EXPECT_EXIT(systemTime(SYSTEM_TIME_BOOTTIME + 1), testing::KilledBySignal(SIGABRT), "");
}
+
+TEST(Timers, toMillisecondTimeoutDelay) {
+ EXPECT_EQ(0, toMillisecondTimeoutDelay(100, 100));
+ EXPECT_EQ(0, toMillisecondTimeoutDelay(100, 10));
+
+ EXPECT_EQ(-1, toMillisecondTimeoutDelay(0, INT_MAX * 1000000LL));
+
+ EXPECT_EQ(123, toMillisecondTimeoutDelay(0, 123000000));
+}
diff --git a/libutils/include/utils/KeyedVector.h b/libutils/include/utils/KeyedVector.h
index 7bda99b..5cf7a11 100644
--- a/libutils/include/utils/KeyedVector.h
+++ b/libutils/include/utils/KeyedVector.h
@@ -47,7 +47,7 @@
inline void clear() { mVector.clear(); }
- /*!
+ /*!
* vector stats
*/
@@ -63,14 +63,14 @@
// returns true if the arguments is known to be identical to this vector
inline bool isIdenticalTo(const KeyedVector& rhs) const;
- /*!
+ /*!
* accessors
*/
- const VALUE& valueFor(const KEY& key) const;
- const VALUE& valueAt(size_t index) const;
- const KEY& keyAt(size_t index) const;
- ssize_t indexOfKey(const KEY& key) const;
- const VALUE& operator[] (size_t index) const;
+ const VALUE& valueFor(const KEY& key) const;
+ const VALUE& valueAt(size_t index) const;
+ const KEY& keyAt(size_t index) const;
+ ssize_t indexOfKey(const KEY& key) const;
+ const VALUE& operator[](size_t index) const;
/*!
* modifying the array
@@ -79,10 +79,10 @@
VALUE& editValueFor(const KEY& key);
VALUE& editValueAt(size_t index);
- /*!
+ /*!
* add/insert/replace items
*/
-
+
ssize_t add(const KEY& key, const VALUE& item);
ssize_t replaceValueFor(const KEY& key, const VALUE& item);
ssize_t replaceValueAt(size_t index, const VALUE& item);
@@ -93,7 +93,7 @@
ssize_t removeItem(const KEY& key);
ssize_t removeItemsAt(size_t index, size_t count = 1);
-
+
private:
SortedVector< key_value_pair_t<KEY, VALUE> > mVector;
};
@@ -208,7 +208,7 @@
template<typename KEY, typename VALUE> inline
const VALUE& DefaultKeyedVector<KEY,VALUE>::valueFor(const KEY& key) const {
ssize_t i = this->indexOfKey(key);
- return i >= 0 ? KeyedVector<KEY,VALUE>::valueAt(i) : mDefault;
+ return i >= 0 ? KeyedVector<KEY, VALUE>::valueAt(static_cast<size_t>(i)) : mDefault;
}
} // namespace android
diff --git a/libutils/include/utils/StopWatch.h b/libutils/include/utils/StopWatch.h
index 9b14ac8..4e53eda 100644
--- a/libutils/include/utils/StopWatch.h
+++ b/libutils/include/utils/StopWatch.h
@@ -14,46 +14,30 @@
* limitations under the License.
*/
-#ifndef ANDROID_STOPWATCH_H
-#define ANDROID_STOPWATCH_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
#include <utils/Timers.h>
-// ---------------------------------------------------------------------------
-
namespace android {
-class StopWatch
-{
-public:
- StopWatch(const char* name, int clock = SYSTEM_TIME_MONOTONIC);
- ~StopWatch();
+class StopWatch {
+ public:
+ StopWatch(const char* name, int clock = SYSTEM_TIME_MONOTONIC);
+ ~StopWatch();
- const char* name() const;
- nsecs_t lap();
- nsecs_t elapsedTime() const;
+ const char* name() const;
+ nsecs_t elapsedTime() const;
- void reset();
+ void reset();
-private:
- const char* mName;
- int mClock;
-
- struct lap_t {
- nsecs_t soFar;
- nsecs_t thisLap;
- };
-
- nsecs_t mStartTime;
- lap_t mLaps[8];
- int mNumLaps;
+ private:
+ const char* mName;
+ int mClock;
+
+ nsecs_t mStartTime;
};
} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_STOPWATCH_H
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 5ce48c6..60d523a 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -88,8 +88,6 @@
status_t replaceAll(char16_t replaceThis,
char16_t withThis);
- status_t remove(size_t len, size_t begin=0);
-
inline int compare(const String16& other) const;
inline bool operator<(const String16& other) const;
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index 6b03a1d..c58f298 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -19,7 +19,6 @@
"libnetd_resolv.so",
// nn
"libneuralnetworks.so",
- "libneuralnetworks_shim.so",
// statsd
"libstatspull.so",
"libstatssocket.so",
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1013d41..6e85da5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -762,7 +762,7 @@
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system
- mkdir /data/misc/profiles/ref 0770 system system
+ mkdir /data/misc/profiles/ref 0771 system system
mkdir /data/misc/profman 0770 system shell
mkdir /data/misc/gcov 0770 root root
mkdir /data/misc/installd 0700 root root
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 56e774b..3101974 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -67,9 +67,9 @@
# CDMA radio interface MUX
/dev/ppp 0660 radio vpn
-# Virtualisation is managed by Virt Manager
-/dev/kvm 0600 virtmanager root
-/dev/vhost-vsock 0600 virtmanager root
+# Virtualization is managed by VirtualizationService.
+/dev/kvm 0600 virtualizationservice root
+/dev/vhost-vsock 0600 virtualizationservice root
# sysfs properties
/sys/devices/platform/trusty.* trusty_version 0440 root log