Merge "llkd: make 100% sure process that triggers panic still exists"
diff --git a/adb/Android.bp b/adb/Android.bp
index ae8e386..6234af1 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -24,7 +24,7 @@
"-Wno-missing-field-initializers",
"-Wvla",
],
- rtti: true,
+ cpp_std: "experimental",
use_version_lib: true,
diff --git a/adb/adb.h b/adb/adb.h
index e2911e8..cdd6346 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -149,6 +149,10 @@
#endif
#if !ADB_HOST
+asocket* daemon_service_to_socket(std::string_view name);
+#endif
+
+#if !ADB_HOST
int init_jdwp(void);
asocket* create_jdwp_service_socket();
asocket* create_jdwp_tracker_service_socket();
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 95e66ae..c8e834e 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1275,6 +1275,42 @@
return 0;
}
+static int adb_connect_command_bidirectional(const std::string& command) {
+ std::string error;
+ int fd = adb_connect(command, &error);
+ if (fd < 0) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+
+ static constexpr auto forward = [](int src, int sink, bool exit_on_end) {
+ char buf[4096];
+ while (true) {
+ int rc = adb_read(src, buf, sizeof(buf));
+ if (rc == 0) {
+ if (exit_on_end) {
+ exit(0);
+ } else {
+ adb_shutdown(sink, SHUT_WR);
+ }
+ return;
+ } else if (rc < 0) {
+ perror_exit("read failed");
+ }
+ if (!WriteFdExactly(sink, buf, rc)) {
+ perror_exit("write failed");
+ }
+ }
+ };
+
+ std::thread read(forward, fd, STDOUT_FILENO, true);
+ std::thread write(forward, STDIN_FILENO, fd, false);
+ read.join();
+ write.join();
+ adb_close(fd);
+ return 0;
+}
+
static int adb_query_command(const std::string& command) {
std::string result;
std::string error;
@@ -1766,7 +1802,7 @@
if (argc != 2) {
error_exit("usage: adb raw SERVICE");
}
- return adb_connect_command(argv[1]);
+ return adb_connect_command_bidirectional(argv[1]);
}
/* "adb /?" is a common idiom under Windows */
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index b72ed16..1a92317 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -245,9 +245,8 @@
// If we can use overlayfs, lets get it in place first
// before we struggle with determining deduplication operations.
if (!verity_enabled && fs_mgr_overlayfs_setup()) {
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
- if (fs_mgr_overlayfs_mount_all(fstab.get())) {
+ Fstab fstab;
+ if (ReadDefaultFstab(&fstab) && fs_mgr_overlayfs_mount_all(&fstab)) {
WriteFdExactly(fd.get(), "overlayfs mounted\n");
}
}
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index b300fac..3182ddd 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -33,6 +33,7 @@
#include <thread>
#include <android-base/file.h>
+#include <android-base/parseint.h>
#include <android-base/parsenetaddress.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
@@ -223,6 +224,105 @@
WriteFdExactly(fd.get(), "spinning\n");
}
+struct ServiceSocket : public asocket {
+ ServiceSocket() {
+ install_local_socket(this);
+ this->enqueue = [](asocket* self, apacket::payload_type data) {
+ return static_cast<ServiceSocket*>(self)->Enqueue(std::move(data));
+ };
+ this->ready = [](asocket* self) { return static_cast<ServiceSocket*>(self)->Ready(); };
+ this->close = [](asocket* self) { return static_cast<ServiceSocket*>(self)->Close(); };
+ }
+ virtual ~ServiceSocket() = default;
+
+ virtual int Enqueue(apacket::payload_type data) { return -1; }
+ virtual void Ready() {}
+ virtual void Close() {
+ if (peer) {
+ peer->peer = nullptr;
+ if (peer->shutdown) {
+ peer->shutdown(peer);
+ }
+ peer->close(peer);
+ }
+
+ remove_socket(this);
+ delete this;
+ }
+};
+
+struct SinkSocket : public ServiceSocket {
+ explicit SinkSocket(size_t byte_count) {
+ LOG(INFO) << "Creating new SinkSocket with capacity " << byte_count;
+ bytes_left_ = byte_count;
+ }
+
+ virtual ~SinkSocket() { LOG(INFO) << "SinkSocket destroyed"; }
+
+ virtual int Enqueue(apacket::payload_type data) override final {
+ if (bytes_left_ <= data.size()) {
+ // Done reading.
+ Close();
+ return -1;
+ }
+
+ bytes_left_ -= data.size();
+ return 0;
+ }
+
+ size_t bytes_left_;
+};
+
+struct SourceSocket : public ServiceSocket {
+ explicit SourceSocket(size_t byte_count) {
+ LOG(INFO) << "Creating new SourceSocket with capacity " << byte_count;
+ bytes_left_ = byte_count;
+ }
+
+ virtual ~SourceSocket() { LOG(INFO) << "SourceSocket destroyed"; }
+
+ void Ready() {
+ size_t len = std::min(bytes_left_, get_max_payload());
+ if (len == 0) {
+ Close();
+ return;
+ }
+
+ Block block(len);
+ memset(block.data(), 0, block.size());
+ peer->enqueue(peer, std::move(block));
+ bytes_left_ -= len;
+ }
+
+ int Enqueue(apacket::payload_type data) { return -1; }
+
+ size_t bytes_left_;
+};
+
+asocket* daemon_service_to_socket(std::string_view name) {
+ if (name == "jdwp") {
+ return create_jdwp_service_socket();
+ } else if (name == "track-jdwp") {
+ return create_jdwp_tracker_service_socket();
+ } else if (name.starts_with("sink:")) {
+ name.remove_prefix(strlen("sink:"));
+ uint64_t byte_count = 0;
+ if (!android::base::ParseUint(name.data(), &byte_count)) {
+ return nullptr;
+ }
+ return new SinkSocket(byte_count);
+ } else if (name.starts_with("source:")) {
+ name.remove_prefix(strlen("source:"));
+ uint64_t byte_count = 0;
+ if (!android::base::ParseUint(name.data(), &byte_count)) {
+ return nullptr;
+ }
+ return new SourceSocket(byte_count);
+ }
+
+ return nullptr;
+}
+
unique_fd daemon_service_to_fd(const char* name, atransport* transport) {
if (!strncmp("dev:", name, 4)) {
return unique_fd{unix_open(name + 4, O_RDWR | O_CLOEXEC)};
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index 01097ac..8805fc1 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -273,7 +273,7 @@
}
std::vector<std::string> joined_env;
- for (auto it : env) {
+ for (const auto& it : env) {
const char* key = it.first.c_str();
const char* value = it.second.c_str();
joined_env.push_back(android::base::StringPrintf("%s=%s", key, value));
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 8b07f74..1bd57c1 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -348,11 +348,8 @@
asocket* create_local_service_socket(const char* name, atransport* transport) {
#if !ADB_HOST
- if (!strcmp(name, "jdwp")) {
- return create_jdwp_service_socket();
- }
- if (!strcmp(name, "track-jdwp")) {
- return create_jdwp_tracker_service_socket();
+ if (asocket* s = daemon_service_to_socket(name); s) {
+ return s;
}
#endif
int fd = service_to_fd(name, transport);
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 8741654..f59a135 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -1305,11 +1305,7 @@
void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
transport_list.remove_if([usb](atransport* t) {
- auto connection = t->connection();
- if (auto usb_connection = dynamic_cast<UsbConnection*>(connection.get())) {
- return usb_connection->handle_ == usb && t->GetConnectionState() == kCsNoPerm;
- }
- return false;
+ return t->GetUsbHandle() == usb && t->GetConnectionState() == kCsNoPerm;
});
}
#endif
diff --git a/adb/transport.h b/adb/transport.h
index d593700..790004f 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -37,6 +37,7 @@
#include "adb.h"
#include "adb_unique_fd.h"
+#include "usb.h"
typedef std::unordered_set<std::string> FeatureSet;
@@ -242,6 +243,9 @@
return connection_;
}
+ void SetUsbHandle(usb_handle* h) { usb_handle_ = h; }
+ usb_handle* GetUsbHandle() { return usb_handle_; }
+
const TransportId id;
size_t ref_count = 0;
bool online = false;
@@ -333,6 +337,9 @@
// The underlying connection object.
std::shared_ptr<Connection> connection_ GUARDED_BY(mutex_);
+ // USB handle for the connection, if available.
+ usb_handle* usb_handle_ = nullptr;
+
// A callback that will be invoked when the atransport needs to reconnect.
ReconnectCallback reconnect_;
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index c471bf9..2e5918a 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -180,6 +180,7 @@
auto connection = std::make_unique<UsbConnection>(h);
t->SetConnection(std::make_unique<BlockingConnectionAdapter>(std::move(connection)));
t->type = kTransportUsb;
+ t->SetUsbHandle(h);
}
int is_adb_interface(int usb_class, int usb_subclass, int usb_protocol) {
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index d9fae52..5167481 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -116,14 +116,21 @@
"libdebuggerd",
"libbacktrace",
"libunwindstack",
- "libdexfile",
+ "libdexfile", // libunwindstack dependency
+ "libdexfile_external", // libunwindstack dependency
+ "libdexfile_support", // libunwindstack dependency
"liblzma",
"libcutils",
],
target: {
recovery: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- exclude_static_libs: ["libdexfile"],
+ exclude_static_libs: [
+ "libartbase",
+ "libdexfile",
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
},
},
@@ -170,12 +177,22 @@
static_libs: [
"libbacktrace",
+ "libdexfile_external", // libunwindstack dependency
+ "libdexfile_support", // libunwindstack dependency
"libunwindstack",
"liblzma",
"libbase",
"libcutils",
"liblog",
],
+ target: {
+ recovery: {
+ exclude_static_libs: [
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
+ },
+ },
}
cc_test {
@@ -216,6 +233,8 @@
static_libs: [
"libdebuggerd",
+ "libdexfile_external", // libunwindstack dependency
+ "libdexfile_support", // libunwindstack dependency
"libunwindstack",
],
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index 479a06a..ef34771 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -281,7 +281,7 @@
std::vector<std::string> vars;
EXPECT_EQ(fb->GetVarAll(&vars), SUCCESS) << "getvar:all failed";
EXPECT_GT(vars.size(), 0) << "getvar:all did not respond with any INFO responses";
- for (const auto s : vars) {
+ for (const auto& s : vars) {
EXPECT_LE(s.size(), FB_RESPONSE_SZ - 4)
<< "getvar:all included an INFO response: 'INFO" + s << "' which is too long";
}
@@ -316,7 +316,7 @@
EXPECT_GT(parts.size(), 0)
<< "getvar:all did not report any partition-size: through INFO responses";
std::set<std::string> allowed{"ext4", "f2fs", "raw"};
- for (const auto p : parts) {
+ for (const auto& p : parts) {
EXPECT_GE(std::get<1>(p), 0);
std::string part(std::get<0>(p));
std::set<std::string> allowed{"ext4", "f2fs", "raw"};
@@ -355,7 +355,7 @@
if (num_slots > 0) {
EXPECT_EQ(fb->GetVar("current-slot", &var), SUCCESS) << "getvar:current-slot failed";
- for (const auto p : parts) {
+ for (const auto& p : parts) {
std::string part(std::get<0>(p));
std::regex reg("([[:graph:]]*)_([[:lower:]])");
std::smatch sm;
@@ -378,7 +378,7 @@
}
}
// Ensure each partition has the correct slot suffix
- for (const auto iter : part_slots) {
+ for (const auto& iter : part_slots) {
const std::set<char>& char_set = iter.second;
std::string chars;
for (char c : char_set) {
@@ -572,7 +572,7 @@
std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed in locked mode";
std::string resp;
- for (const auto tup : parts) {
+ for (const auto& tup : parts) {
EXPECT_EQ(fb->Flash(std::get<0>(tup), &resp), DEVICE_FAIL)
<< "Device did not respond with FAIL when trying to flash '" << std::get<0>(tup)
<< "' in locked mode";
@@ -585,7 +585,7 @@
std::vector<std::tuple<std::string, uint64_t>> parts;
EXPECT_EQ(fb->Partitions(&parts), SUCCESS) << "getvar:all failed";
std::string resp;
- for (const auto tup : parts) {
+ for (const auto& tup : parts) {
EXPECT_EQ(fb->Erase(std::get<0>(tup), &resp), DEVICE_FAIL)
<< "Device did not respond with FAIL when trying to erase '" << std::get<0>(tup)
<< "' in locked mode";
@@ -601,7 +601,7 @@
EXPECT_EQ(fb->GetVar("slot-count", &resp), SUCCESS) << "getvar:slot-count failed";
int32_t num_slots = strtol(resp.c_str(), nullptr, 10);
- for (const auto tup : parts) {
+ for (const auto& tup : parts) {
std::string part(std::get<0>(tup));
std::regex reg("([[:graph:]]*)_([[:lower:]])");
std::smatch sm;
@@ -1554,12 +1554,12 @@
void GenerateXmlTests(const extension::Configuration& config) {
// Build the getvar tests
- for (const auto it : config.getvars) {
+ for (const auto& it : config.getvars) {
GETVAR_XML_TESTS.push_back(std::make_pair(it.first, it.second));
}
// Build the partition tests, to interface with gtest we need to do it this way
- for (const auto it : config.partitions) {
+ for (const auto& it : config.partitions) {
const auto tup = std::make_tuple(it.first, it.second);
PARTITION_XML_TESTS.push_back(tup); // All partitions
@@ -1581,7 +1581,7 @@
// Build the packed tests, only useful if we have a hash
if (!config.checksum.empty()) {
- for (const auto it : config.packed) {
+ for (const auto& it : config.packed) {
for (const auto& test : it.second.tests) {
const auto tup = std::make_tuple(it.first, test);
if (test.expect == extension::OKAY) { // only testing the success case
@@ -1608,7 +1608,7 @@
}
// Build oem tests
- for (const auto it : config.oem) {
+ for (const auto& it : config.oem) {
auto oem_cmd = it.second;
for (const auto& t : oem_cmd.tests) {
OEM_XML_TESTS.push_back(std::make_tuple(it.first, oem_cmd.restricted, t));
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 99231ac..ac138a3 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -23,7 +23,6 @@
cflags: [
"-Wall",
"-Werror",
- "-Wno-unused-variable",
],
}
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 4e1360e..8757689 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -336,10 +336,10 @@
}
// Enable/disable quota support on the filesystem if needed.
-static void tune_quota(const std::string& blk_device, const struct fstab_rec* rec,
+static void tune_quota(const std::string& blk_device, const FstabEntry& entry,
const struct ext4_super_block* sb, int* fs_stat) {
bool has_quota = (sb->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_QUOTA)) != 0;
- bool want_quota = fs_mgr_is_quota(rec) != 0;
+ bool want_quota = entry.fs_mgr_flags.quota;
if (has_quota == want_quota) {
return;
@@ -372,16 +372,16 @@
}
// Set the number of reserved filesystem blocks if needed.
-static void tune_reserved_size(const std::string& blk_device, const struct fstab_rec* rec,
+static void tune_reserved_size(const std::string& blk_device, const FstabEntry& entry,
const struct ext4_super_block* sb, int* fs_stat) {
- if (!(rec->fs_mgr_flags & MF_RESERVEDSIZE)) {
+ if (!entry.fs_mgr_flags.reserved_size) {
return;
}
// The size to reserve is given in the fstab, but we won't reserve more
// than 2% of the filesystem.
const uint64_t max_reserved_blocks = ext4_blocks_count(sb) * 0.02;
- uint64_t reserved_blocks = rec->reserved_size / EXT4_BLOCK_SIZE(sb);
+ uint64_t reserved_blocks = entry.reserved_size / EXT4_BLOCK_SIZE(sb);
if (reserved_blocks > max_reserved_blocks) {
LWARNING << "Reserved blocks " << reserved_blocks << " is too large; "
@@ -414,10 +414,10 @@
}
// Enable file-based encryption if needed.
-static void tune_encrypt(const std::string& blk_device, const struct fstab_rec* rec,
+static void tune_encrypt(const std::string& blk_device, const FstabEntry& entry,
const struct ext4_super_block* sb, int* fs_stat) {
bool has_encrypt = (sb->s_feature_incompat & cpu_to_le32(EXT4_FEATURE_INCOMPAT_ENCRYPT)) != 0;
- bool want_encrypt = fs_mgr_is_file_encrypted(rec) != 0;
+ bool want_encrypt = entry.fs_mgr_flags.file_encryption;
if (has_encrypt || !want_encrypt) {
return;
@@ -478,10 +478,10 @@
// If needed, we'll also enable (or disable) filesystem features as specified by
// the fstab record.
//
-static int prepare_fs_for_mount(const std::string& blk_device, const struct fstab_rec* rec) {
+static int prepare_fs_for_mount(const std::string& blk_device, const FstabEntry& entry) {
int fs_stat = 0;
- if (is_extfs(rec->fs_type)) {
+ if (is_extfs(entry.fs_type)) {
struct ext4_super_block sb;
if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
@@ -494,27 +494,28 @@
}
// Note: quotas should be enabled before running fsck.
- tune_quota(blk_device, rec, &sb, &fs_stat);
+ tune_quota(blk_device, entry, &sb, &fs_stat);
} else {
return fs_stat;
}
- } else if (is_f2fs(rec->fs_type)) {
+ } else if (is_f2fs(entry.fs_type)) {
if (!read_f2fs_superblock(blk_device, &fs_stat)) {
return fs_stat;
}
}
- if ((rec->fs_mgr_flags & MF_CHECK) ||
+ if (entry.fs_mgr_flags.check ||
(fs_stat & (FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED))) {
- check_fs(blk_device, rec->fs_type, rec->mount_point, &fs_stat);
+ check_fs(blk_device, entry.fs_type, entry.mount_point, &fs_stat);
}
- if (is_extfs(rec->fs_type) && (rec->fs_mgr_flags & (MF_RESERVEDSIZE | MF_FILEENCRYPTION))) {
+ if (is_extfs(entry.fs_type) &&
+ (entry.fs_mgr_flags.reserved_size || entry.fs_mgr_flags.file_encryption)) {
struct ext4_super_block sb;
if (read_ext4_superblock(blk_device, &sb, &fs_stat)) {
- tune_reserved_size(blk_device, rec, &sb, &fs_stat);
- tune_encrypt(blk_device, rec, &sb, &fs_stat);
+ tune_reserved_size(blk_device, entry, &sb, &fs_stat);
+ tune_encrypt(blk_device, entry, &sb, &fs_stat);
}
}
@@ -545,8 +546,7 @@
// __mount(): wrapper around the mount() system call which also
// sets the underlying block device to read-only if the mount is read-only.
// See "man 2 mount" for return values.
-static int __mount(const std::string& source, const std::string& target,
- const struct fstab_rec* rec) {
+static int __mount(const std::string& source, const std::string& target, const FstabEntry& entry) {
// We need this because sometimes we have legacy symlinks that are
// lingering around and need cleaning up.
struct stat info;
@@ -555,8 +555,9 @@
}
mkdir(target.c_str(), 0755);
errno = 0;
- unsigned long mountflags = rec->flags;
- int ret = mount(source.c_str(), target.c_str(), rec->fs_type, mountflags, rec->fs_options);
+ unsigned long mountflags = entry.flags;
+ int ret = mount(source.c_str(), target.c_str(), entry.fs_type.c_str(), mountflags,
+ entry.fs_options.c_str());
int save_errno = errno;
const char* target_missing = "";
const char* source_missing = "";
@@ -569,7 +570,7 @@
errno = save_errno;
}
PINFO << __FUNCTION__ << "(source=" << source << source_missing << ",target=" << target
- << target_missing << ",type=" << rec->fs_type << ")=" << ret;
+ << target_missing << ",type=" << entry.fs_type << ")=" << ret;
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(source);
}
@@ -605,106 +606,88 @@
return true;
}
-/*
- * Tries to mount any of the consecutive fstab entries that match
- * the mountpoint of the one given by fstab->recs[start_idx].
- *
- * end_idx: On return, will be the last rec that was looked at.
- * attempted_idx: On return, will indicate which fstab rec
- * succeeded. In case of failure, it will be the start_idx.
- * Returns
- * -1 on failure with errno set to match the 1st mount failure.
- * 0 on success.
- */
-static int mount_with_alternatives(fstab* fstab, int start_idx, int* end_idx, int* attempted_idx) {
+// Tries to mount any of the consecutive fstab entries that match
+// the mountpoint of the one given by fstab[start_idx].
+//
+// end_idx: On return, will be the last entry that was looked at.
+// attempted_idx: On return, will indicate which fstab entry
+// succeeded. In case of failure, it will be the start_idx.
+// Sets errno to match the 1st mount failure on failure.
+static bool mount_with_alternatives(const Fstab& fstab, int start_idx, int* end_idx,
+ int* attempted_idx) {
int i;
int mount_errno = 0;
- int mounted = 0;
+ bool mounted = false;
- if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
- errno = EINVAL;
- if (end_idx) *end_idx = start_idx;
- if (attempted_idx) *attempted_idx = start_idx;
- return -1;
- }
-
- /* Hunt down an fstab entry for the same mount point that might succeed */
+ // Hunt down an fstab entry for the same mount point that might succeed.
for (i = start_idx;
- /* We required that fstab entries for the same mountpoint be consecutive */
- i < fstab->num_entries && !strcmp(fstab->recs[start_idx].mount_point, fstab->recs[i].mount_point);
- i++) {
- /*
- * Don't try to mount/encrypt the same mount point again.
- * Deal with alternate entries for the same point which are required to be all following
- * each other.
- */
- if (mounted) {
- LERROR << __FUNCTION__ << "(): skipping fstab dup mountpoint="
- << fstab->recs[i].mount_point << " rec[" << i
- << "].fs_type=" << fstab->recs[i].fs_type
- << " already mounted as "
- << fstab->recs[*attempted_idx].fs_type;
- continue;
- }
+ // We required that fstab entries for the same mountpoint be consecutive.
+ i < fstab.size() && fstab[start_idx].mount_point == fstab[i].mount_point; i++) {
+ // Don't try to mount/encrypt the same mount point again.
+ // Deal with alternate entries for the same point which are required to be all following
+ // each other.
+ if (mounted) {
+ LERROR << __FUNCTION__ << "(): skipping fstab dup mountpoint=" << fstab[i].mount_point
+ << " rec[" << i << "].fs_type=" << fstab[i].fs_type << " already mounted as "
+ << fstab[*attempted_idx].fs_type;
+ continue;
+ }
- int fs_stat = prepare_fs_for_mount(fstab->recs[i].blk_device, &fstab->recs[i]);
- if (fs_stat & FS_STAT_INVALID_MAGIC) {
- LERROR << __FUNCTION__ << "(): skipping mount due to invalid magic, mountpoint="
- << fstab->recs[i].mount_point
- << " blk_dev=" << realpath(fstab->recs[i].blk_device) << " rec[" << i
- << "].fs_type=" << fstab->recs[i].fs_type;
- mount_errno = EINVAL; // continue bootup for FDE
- continue;
- }
+ int fs_stat = prepare_fs_for_mount(fstab[i].blk_device, fstab[i]);
+ if (fs_stat & FS_STAT_INVALID_MAGIC) {
+ LERROR << __FUNCTION__
+ << "(): skipping mount due to invalid magic, mountpoint=" << fstab[i].mount_point
+ << " blk_dev=" << realpath(fstab[i].blk_device) << " rec[" << i
+ << "].fs_type=" << fstab[i].fs_type;
+ mount_errno = EINVAL; // continue bootup for FDE
+ continue;
+ }
- int retry_count = 2;
- while (retry_count-- > 0) {
- if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
- &fstab->recs[i])) {
- *attempted_idx = i;
- mounted = 1;
- if (i != start_idx) {
- LERROR << __FUNCTION__ << "(): Mounted " << fstab->recs[i].blk_device
- << " on " << fstab->recs[i].mount_point
- << " with fs_type=" << fstab->recs[i].fs_type << " instead of "
- << fstab->recs[start_idx].fs_type;
- }
- fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
- mount_errno = 0;
- break;
- } else {
- if (retry_count <= 0) break; // run check_fs only once
- fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
- /* back up the first errno for crypto decisions */
- if (mount_errno == 0) {
- mount_errno = errno;
- }
- // retry after fsck
- check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
- fstab->recs[i].mount_point, &fs_stat);
+ int retry_count = 2;
+ while (retry_count-- > 0) {
+ if (!__mount(fstab[i].blk_device, fstab[i].mount_point, fstab[i])) {
+ *attempted_idx = i;
+ mounted = true;
+ if (i != start_idx) {
+ LERROR << __FUNCTION__ << "(): Mounted " << fstab[i].blk_device << " on "
+ << fstab[i].mount_point << " with fs_type=" << fstab[i].fs_type
+ << " instead of " << fstab[start_idx].fs_type;
}
+ fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
+ mount_errno = 0;
+ break;
+ } else {
+ if (retry_count <= 0) break; // run check_fs only once
+ fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
+ // back up the first errno for crypto decisions.
+ if (mount_errno == 0) {
+ mount_errno = errno;
+ }
+ // retry after fsck
+ check_fs(fstab[i].blk_device, fstab[i].fs_type, fstab[i].mount_point, &fs_stat);
}
- log_fs_stat(fstab->recs[i].blk_device, fs_stat);
+ }
+ log_fs_stat(fstab[i].blk_device, fs_stat);
}
/* Adjust i for the case where it was still withing the recs[] */
- if (i < fstab->num_entries) --i;
+ if (i < fstab.size()) --i;
*end_idx = i;
if (!mounted) {
*attempted_idx = start_idx;
errno = mount_errno;
- return -1;
+ return false;
}
- return 0;
+ return true;
}
-static bool TranslateExtLabels(fstab_rec* rec) {
- if (!StartsWith(rec->blk_device, "LABEL=")) {
+static bool TranslateExtLabels(FstabEntry* entry) {
+ if (!StartsWith(entry->blk_device, "LABEL=")) {
return true;
}
- std::string label = rec->blk_device + 6;
+ std::string label = entry->blk_device.substr(6);
if (label.size() > 16) {
LERROR << "FS label is longer than allowed by filesystem";
return false;
@@ -744,10 +727,9 @@
if (label == super_block.s_volume_name) {
std::string new_blk_device = "/dev/block/"s + ent->d_name;
- LINFO << "resolved label " << rec->blk_device << " to " << new_blk_device;
+ LINFO << "resolved label " << entry->blk_device << " to " << new_blk_device;
- free(rec->blk_device);
- rec->blk_device = strdup(new_blk_device.c_str());
+ entry->blk_device = new_blk_device;
return true;
}
}
@@ -755,54 +737,49 @@
return false;
}
-static bool needs_block_encryption(const struct fstab_rec* rec)
-{
- if (android::base::GetBoolProperty("ro.vold.forceencryption", false) &&
- fs_mgr_is_encryptable(rec))
+static bool needs_block_encryption(const FstabEntry& entry) {
+ if (android::base::GetBoolProperty("ro.vold.forceencryption", false) && entry.is_encryptable())
return true;
- if (rec->fs_mgr_flags & MF_FORCECRYPT) return true;
- if (rec->fs_mgr_flags & MF_CRYPT) {
+ if (entry.fs_mgr_flags.force_crypt) return true;
+ if (entry.fs_mgr_flags.crypt) {
// Check for existence of convert_fde breadcrumb file.
- auto convert_fde_name = rec->mount_point + "%s/misc/vold/convert_fde"s;
+ auto convert_fde_name = entry.mount_point + "/misc/vold/convert_fde";
if (access(convert_fde_name.c_str(), F_OK) == 0) return true;
}
- if (rec->fs_mgr_flags & MF_FORCEFDEORFBE) {
+ if (entry.fs_mgr_flags.force_fde_or_fbe) {
// Check for absence of convert_fbe breadcrumb file.
- auto convert_fbe_name = rec->mount_point + "/convert_fbe"s;
+ auto convert_fbe_name = entry.mount_point + "/convert_fbe";
if (access(convert_fbe_name.c_str(), F_OK) != 0) return true;
}
return false;
}
-static bool should_use_metadata_encryption(const struct fstab_rec* rec) {
- if (!(rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE))) return false;
- if (!(rec->fs_mgr_flags & MF_KEYDIRECTORY)) return false;
- return true;
+static bool should_use_metadata_encryption(const FstabEntry& entry) {
+ return entry.fs_mgr_flags.key_directory &&
+ (entry.fs_mgr_flags.file_encryption || entry.fs_mgr_flags.force_fde_or_fbe);
}
// Check to see if a mountable volume has encryption requirements
-static int handle_encryptable(const struct fstab_rec* rec)
-{
- /* If this is block encryptable, need to trigger encryption */
- if (needs_block_encryption(rec)) {
- if (umount(rec->mount_point) == 0) {
+static int handle_encryptable(const FstabEntry& entry) {
+ // If this is block encryptable, need to trigger encryption.
+ if (needs_block_encryption(entry)) {
+ if (umount(entry.mount_point.c_str()) == 0) {
return FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
} else {
- PWARNING << "Could not umount " << rec->mount_point
- << " - allow continue unencrypted";
+ PWARNING << "Could not umount " << entry.mount_point << " - allow continue unencrypted";
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
}
- } else if (should_use_metadata_encryption(rec)) {
- if (umount(rec->mount_point) == 0) {
+ } else if (should_use_metadata_encryption(entry)) {
+ if (umount(entry.mount_point.c_str()) == 0) {
return FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION;
} else {
- PERROR << "Could not umount " << rec->mount_point << " - fail since can't encrypt";
+ PERROR << "Could not umount " << entry.mount_point << " - fail since can't encrypt";
return FS_MGR_MNTALL_FAIL;
}
- } else if (rec->fs_mgr_flags & (MF_FILEENCRYPTION | MF_FORCEFDEORFBE)) {
- LINFO << rec->mount_point << " is file encrypted";
+ } else if (entry.fs_mgr_flags.file_encryption || entry.fs_mgr_flags.force_fde_or_fbe) {
+ LINFO << entry.mount_point << " is file encrypted";
return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
- } else if (fs_mgr_is_encryptable(rec)) {
+ } else if (entry.is_encryptable()) {
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
} else {
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
@@ -843,21 +820,34 @@
return true;
}
-bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
+bool fs_mgr_update_logical_partition(FstabEntry* entry) {
// Logical partitions are specified with a named partition rather than a
// block device, so if the block device is a path, then it has already
// been updated.
- if (rec->blk_device[0] == '/') {
+ if (entry->blk_device[0] == '/') {
return true;
}
DeviceMapper& dm = DeviceMapper::Instance();
std::string device_name;
- if (!dm.GetDmDevicePathByName(rec->blk_device, &device_name)) {
+ if (!dm.GetDmDevicePathByName(entry->blk_device, &device_name)) {
return false;
}
+
+ entry->blk_device = device_name;
+ return true;
+}
+
+bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
+ auto entry = FstabRecToFstabEntry(rec);
+
+ if (!fs_mgr_update_logical_partition(&entry)) {
+ return false;
+ }
+
free(rec->blk_device);
- rec->blk_device = strdup(device_name.c_str());
+ rec->blk_device = strdup(entry.blk_device.c_str());
+
return true;
}
@@ -865,13 +855,13 @@
public:
CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
- bool Update(struct fstab_rec* rec) {
- if (!fs_mgr_is_checkpoint(rec)) {
+ bool Update(FstabEntry* entry) {
+ if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
return true;
}
- if (fs_mgr_is_checkpoint_blk(rec)) {
- call_vdc({"checkpoint", "restoreCheckpoint", rec->blk_device});
+ if (entry->fs_mgr_flags.checkpoint_blk) {
+ call_vdc({"checkpoint", "restoreCheckpoint", entry->blk_device});
}
if (needs_checkpoint_ == UNKNOWN &&
@@ -884,7 +874,7 @@
return true;
}
- if (!UpdateCheckpointPartition(rec)) {
+ if (!UpdateCheckpointPartition(entry)) {
LERROR << "Could not set up checkpoint partition, skipping!";
return false;
}
@@ -892,18 +882,17 @@
return true;
}
- bool Revert(struct fstab_rec* rec) {
- if (!fs_mgr_is_checkpoint(rec)) {
+ bool Revert(FstabEntry* entry) {
+ if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
return true;
}
- if (device_map_.find(rec->blk_device) == device_map_.end()) {
+ if (device_map_.find(entry->blk_device) == device_map_.end()) {
return true;
}
- std::string bow_device = rec->blk_device;
- free(rec->blk_device);
- rec->blk_device = strdup(device_map_[bow_device].c_str());
+ std::string bow_device = entry->blk_device;
+ entry->blk_device = device_map_[bow_device];
device_map_.erase(bow_device);
DeviceMapper& dm = DeviceMapper::Instance();
@@ -915,21 +904,17 @@
}
private:
- bool UpdateCheckpointPartition(struct fstab_rec* rec) {
- if (fs_mgr_is_checkpoint_fs(rec)) {
- if (is_f2fs(rec->fs_type)) {
- std::string opts(rec->fs_options);
-
- opts += ",checkpoint=disable";
- free(rec->fs_options);
- rec->fs_options = strdup(opts.c_str());
+ bool UpdateCheckpointPartition(FstabEntry* entry) {
+ if (entry->fs_mgr_flags.checkpoint_fs) {
+ if (is_f2fs(entry->fs_type)) {
+ entry->fs_options += ",checkpoint=disable";
} else {
- LERROR << rec->fs_type << " does not implement checkpoints.";
+ LERROR << entry->fs_type << " does not implement checkpoints.";
}
- } else if (fs_mgr_is_checkpoint_blk(rec)) {
- unique_fd fd(TEMP_FAILURE_RETRY(open(rec->blk_device, O_RDONLY | O_CLOEXEC)));
+ } else if (entry->fs_mgr_flags.checkpoint_blk) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(entry->blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd < 0) {
- PERROR << "Cannot open device " << rec->blk_device;
+ PERROR << "Cannot open device " << entry->blk_device;
return false;
}
@@ -941,7 +926,7 @@
android::dm::DmTable table;
if (!table.AddTarget(
- std::make_unique<android::dm::DmTargetBow>(0, size, rec->blk_device))) {
+ std::make_unique<android::dm::DmTargetBow>(0, size, entry->blk_device))) {
LERROR << "Failed to add bow target";
return false;
}
@@ -958,9 +943,8 @@
return false;
}
- device_map_[name] = rec->blk_device;
- free(rec->blk_device);
- rec->blk_device = strdup(name.c_str());
+ device_map_[name] = entry->blk_device;
+ entry->blk_device = name;
}
return true;
}
@@ -970,76 +954,70 @@
std::map<std::string, std::string> device_map_;
};
-/* When multiple fstab records share the same mount_point, it will
- * try to mount each one in turn, and ignore any duplicates after a
- * first successful mount.
- * Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
- */
-int fs_mgr_mount_all(fstab* fstab, int mount_mode) {
- int i = 0;
+// When multiple fstab records share the same mount_point, it will try to mount each
+// one in turn, and ignore any duplicates after a first successful mount.
+// Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
+int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
int error_count = 0;
- int mret = -1;
- int mount_errno = 0;
- int attempted_idx = -1;
CheckpointManager checkpoint_manager;
AvbUniquePtr avb_handle(nullptr);
- if (!fstab) {
+ if (fstab->empty()) {
return FS_MGR_MNTALL_FAIL;
}
- for (i = 0; i < fstab->num_entries; i++) {
- /* Don't mount entries that are managed by vold or not for the mount mode*/
- if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
- ((mount_mode == MOUNT_MODE_LATE) && !fs_mgr_is_latemount(&fstab->recs[i])) ||
- ((mount_mode == MOUNT_MODE_EARLY) && fs_mgr_is_latemount(&fstab->recs[i])) ||
- fs_mgr_is_first_stage_mount(&fstab->recs[i])) {
+ for (size_t i = 0; i < fstab->size(); i++) {
+ auto& current_entry = (*fstab)[i];
+
+ // Don't mount entries that are managed by vold or not for the mount mode.
+ if (current_entry.fs_mgr_flags.vold_managed || current_entry.fs_mgr_flags.recovery_only ||
+ current_entry.fs_mgr_flags.first_stage_mount ||
+ ((mount_mode == MOUNT_MODE_LATE) && !current_entry.fs_mgr_flags.late_mount) ||
+ ((mount_mode == MOUNT_MODE_EARLY) && current_entry.fs_mgr_flags.late_mount)) {
continue;
}
- /* Skip swap and raw partition entries such as boot, recovery, etc */
- if (!strcmp(fstab->recs[i].fs_type, "swap") ||
- !strcmp(fstab->recs[i].fs_type, "emmc") ||
- !strcmp(fstab->recs[i].fs_type, "mtd")) {
+ // Skip swap and raw partition entries such as boot, recovery, etc.
+ if (current_entry.fs_type == "swap" || current_entry.fs_type == "emmc" ||
+ current_entry.fs_type == "mtd") {
continue;
}
- /* Skip mounting the root partition, as it will already have been mounted */
- if (!strcmp(fstab->recs[i].mount_point, "/") ||
- !strcmp(fstab->recs[i].mount_point, "/system")) {
- if ((fstab->recs[i].flags & MS_RDONLY) != 0) {
- fs_mgr_set_blk_ro(fstab->recs[i].blk_device);
+ // Skip mounting the root partition, as it will already have been mounted.
+ if (current_entry.mount_point == "/" || current_entry.mount_point == "/system") {
+ if ((current_entry.flags & MS_RDONLY) != 0) {
+ fs_mgr_set_blk_ro(current_entry.blk_device);
}
continue;
}
- /* Translate LABEL= file system labels into block devices */
- if (is_extfs(fstab->recs[i].fs_type)) {
- if (!TranslateExtLabels(&fstab->recs[i])) {
+ // Translate LABEL= file system labels into block devices.
+ if (is_extfs(current_entry.fs_type)) {
+ if (!TranslateExtLabels(¤t_entry)) {
LERROR << "Could not translate label to block device";
continue;
}
}
- if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
- if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+ if (current_entry.fs_mgr_flags.logical) {
+ if (!fs_mgr_update_logical_partition(¤t_entry)) {
LERROR << "Could not set up logical partition, skipping!";
continue;
}
}
- if (!checkpoint_manager.Update(&fstab->recs[i])) {
+ if (!checkpoint_manager.Update(¤t_entry)) {
continue;
}
- if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
- !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
- LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
+ if (current_entry.fs_mgr_flags.wait &&
+ !fs_mgr_wait_for_file(current_entry.blk_device, 20s)) {
+ LERROR << "Skipping '" << current_entry.blk_device << "' during mount_all";
continue;
}
- if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
+ if (current_entry.fs_mgr_flags.avb) {
if (!avb_handle) {
avb_handle = AvbHandle::Open();
if (!avb_handle) {
@@ -1047,15 +1025,15 @@
return FS_MGR_MNTALL_FAIL;
}
}
- if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
+ if (avb_handle->SetUpAvbHashtree(¤t_entry, true /* wait_for_verity_dev */) ==
AvbHashtreeResult::kFail) {
- LERROR << "Failed to set up AVB on partition: "
- << fstab->recs[i].mount_point << ", skipping!";
- /* Skips mounting the device. */
+ LERROR << "Failed to set up AVB on partition: " << current_entry.mount_point
+ << ", skipping!";
+ // Skips mounting the device.
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY)) {
- int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
+ } else if ((current_entry.fs_mgr_flags.verify)) {
+ int rc = fs_mgr_setup_verity(¤t_entry, true);
if (__android_log_is_debuggable() &&
(rc == FS_MGR_SETUP_VERITY_DISABLED ||
rc == FS_MGR_SETUP_VERITY_SKIPPED)) {
@@ -1068,17 +1046,19 @@
int last_idx_inspected;
int top_idx = i;
+ int attempted_idx = -1;
- mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
+ bool mret = mount_with_alternatives(*fstab, i, &last_idx_inspected, &attempted_idx);
+ auto& attempted_entry = (*fstab)[attempted_idx];
i = last_idx_inspected;
- mount_errno = errno;
+ int mount_errno = errno;
- /* Deal with encryptability. */
- if (!mret) {
- int status = handle_encryptable(&fstab->recs[attempted_idx]);
+ // Handle success and deal with encryptability.
+ if (mret) {
+ int status = handle_encryptable(attempted_entry);
if (status == FS_MGR_MNTALL_FAIL) {
- /* Fatal error - no point continuing */
+ // Fatal error - no point continuing.
return status;
}
@@ -1089,50 +1069,45 @@
}
encryptable = status;
if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
- if (!call_vdc(
- {"cryptfs", "encryptFstab", fstab->recs[attempted_idx].mount_point})) {
+ if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.mount_point})) {
LERROR << "Encryption failed";
return FS_MGR_MNTALL_FAIL;
}
}
}
- /* Success! Go get the next one */
+ // Success! Go get the next one.
continue;
}
- bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
+ // Mounting failed, understand why and retry.
+ bool wiped = partition_wiped(current_entry.blk_device.c_str());
bool crypt_footer = false;
- if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
- fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) {
- /* top_idx and attempted_idx point at the same partition, but sometimes
- * at two different lines in the fstab. Use the top one for formatting
- * as that is the preferred one.
- */
- LERROR << __FUNCTION__ << "(): " << realpath(fstab->recs[top_idx].blk_device)
- << " is wiped and " << fstab->recs[top_idx].mount_point << " "
- << fstab->recs[top_idx].fs_type << " is formattable. Format it.";
+ if (mount_errno != EBUSY && mount_errno != EACCES &&
+ current_entry.fs_mgr_flags.formattable && wiped) {
+ // current_entry and attempted_entry point at the same partition, but sometimes
+ // at two different lines in the fstab. Use current_entry for formatting
+ // as that is the preferred one.
+ LERROR << __FUNCTION__ << "(): " << realpath(current_entry.blk_device)
+ << " is wiped and " << current_entry.mount_point << " " << current_entry.fs_type
+ << " is formattable. Format it.";
- checkpoint_manager.Revert(&fstab->recs[top_idx]);
+ checkpoint_manager.Revert(¤t_entry);
- if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
- strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
+ if (current_entry.is_encryptable() && current_entry.key_loc != KEY_IN_FOOTER) {
unique_fd fd(TEMP_FAILURE_RETRY(
- open(fstab->recs[top_idx].key_loc, O_WRONLY | O_CLOEXEC)));
+ open(current_entry.key_loc.c_str(), O_WRONLY | O_CLOEXEC)));
if (fd >= 0) {
- LINFO << __FUNCTION__ << "(): also wipe "
- << fstab->recs[top_idx].key_loc;
+ LINFO << __FUNCTION__ << "(): also wipe " << current_entry.key_loc;
wipe_block_device(fd, get_file_size(fd));
} else {
- PERROR << __FUNCTION__ << "(): "
- << fstab->recs[top_idx].key_loc << " wouldn't open";
+ PERROR << __FUNCTION__ << "(): " << current_entry.key_loc << " wouldn't open";
}
- } else if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
- !strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
+ } else if (current_entry.is_encryptable() && current_entry.key_loc == KEY_IN_FOOTER) {
crypt_footer = true;
}
- if (fs_mgr_do_format(&fstab->recs[top_idx], crypt_footer) == 0) {
- /* Let's replay the mount actions. */
+ if (fs_mgr_do_format(current_entry, crypt_footer) == 0) {
+ // Let's replay the mount actions.
i = top_idx - 1;
continue;
} else {
@@ -1143,35 +1118,29 @@
}
}
- /* mount(2) returned an error, handle the encryptable/formattable case */
- if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
- fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
+ // mount(2) returned an error, handle the encryptable/formattable case.
+ if (mount_errno != EBUSY && mount_errno != EACCES && attempted_entry.is_encryptable()) {
if (wiped) {
- LERROR << __FUNCTION__ << "(): "
- << fstab->recs[attempted_idx].blk_device
- << " is wiped and "
- << fstab->recs[attempted_idx].mount_point << " "
- << fstab->recs[attempted_idx].fs_type
+ LERROR << __FUNCTION__ << "(): " << attempted_entry.blk_device << " is wiped and "
+ << attempted_entry.mount_point << " " << attempted_entry.fs_type
<< " is encryptable. Suggest recovery...";
encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
continue;
} else {
- /* Need to mount a tmpfs at this mountpoint for now, and set
- * properties that vold will query later for decrypting
- */
+ // Need to mount a tmpfs at this mountpoint for now, and set
+ // properties that vold will query later for decrypting
LERROR << __FUNCTION__ << "(): possibly an encryptable blkdev "
- << fstab->recs[attempted_idx].blk_device
- << " for mount " << fstab->recs[attempted_idx].mount_point
- << " type " << fstab->recs[attempted_idx].fs_type;
- if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
+ << attempted_entry.blk_device << " for mount " << attempted_entry.mount_point
+ << " type " << attempted_entry.fs_type;
+ if (fs_mgr_do_tmpfs_mount(attempted_entry.mount_point.c_str()) < 0) {
++error_count;
continue;
}
}
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
- } else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
- should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
- if (!call_vdc({"cryptfs", "mountFstab", fstab->recs[attempted_idx].mount_point})) {
+ } else if (mount_errno != EBUSY && mount_errno != EACCES &&
+ should_use_metadata_encryption(attempted_entry)) {
+ if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.mount_point})) {
++error_count;
}
encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
@@ -1179,18 +1148,18 @@
} else {
// fs_options might be null so we cannot use PERROR << directly.
// Use StringPrintf to output "(null)" instead.
- if (fs_mgr_is_nofail(&fstab->recs[attempted_idx])) {
+ if (attempted_entry.fs_mgr_flags.no_fail) {
PERROR << android::base::StringPrintf(
- "Ignoring failure to mount an un-encryptable or wiped "
- "partition on %s at %s options: %s",
- fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
- fstab->recs[attempted_idx].fs_options);
+ "Ignoring failure to mount an un-encryptable or wiped "
+ "partition on %s at %s options: %s",
+ attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
+ attempted_entry.fs_options.c_str());
} else {
PERROR << android::base::StringPrintf(
- "Failed to mount an un-encryptable or wiped partition "
- "on %s at %s options: %s",
- fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
- fstab->recs[attempted_idx].fs_options);
+ "Failed to mount an un-encryptable or wiped partition "
+ "on %s at %s options: %s",
+ attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(),
+ attempted_entry.fs_options.c_str());
++error_count;
}
continue;
@@ -1208,20 +1177,13 @@
}
}
-/* wrapper to __mount() and expects a fully prepared fstab_rec,
- * unlike fs_mgr_do_mount which does more things with avb / verity
- * etc.
- */
-int fs_mgr_do_mount_one(struct fstab_rec *rec)
-{
- if (!rec) {
- return FS_MGR_DOMNT_FAILED;
- }
-
+// wrapper to __mount() and expects a fully prepared fstab_rec,
+// unlike fs_mgr_do_mount which does more things with avb / verity etc.
+int fs_mgr_do_mount_one(const FstabEntry& entry) {
// Run fsck if needed
- prepare_fs_for_mount(rec->blk_device, rec);
+ prepare_fs_for_mount(entry.blk_device, entry);
- int ret = __mount(rec->blk_device, rec->mount_point, rec);
+ int ret = __mount(entry.blk_device, entry.mount_point, entry);
if (ret) {
ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
}
@@ -1229,17 +1191,26 @@
return ret;
}
-/* If tmp_mount_point is non-null, mount the filesystem there. This is for the
- * tmp mount we do to check the user password
- * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
- * in turn, and stop on 1st success, or no more match.
- */
-static int fs_mgr_do_mount_helper(fstab* fstab, const char* n_name, char* n_blk_device,
- char* tmp_mount_point, int needs_checkpoint) {
- int i = 0;
+int fs_mgr_do_mount_one(struct fstab_rec* rec) {
+ if (!rec) {
+ return FS_MGR_DOMNT_FAILED;
+ }
+
+ auto entry = FstabRecToFstabEntry(rec);
+
+ return fs_mgr_do_mount_one(entry);
+}
+
+// If tmp_mount_point is non-null, mount the filesystem there. This is for the
+// tmp mount we do to check the user password
+// If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
+// in turn, and stop on 1st success, or no more match.
+static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name,
+ const std::string& n_blk_device, const char* tmp_mount_point,
+ int needs_checkpoint) {
int mount_errors = 0;
int first_mount_errno = 0;
- char* mount_point;
+ std::string mount_point;
CheckpointManager checkpoint_manager(needs_checkpoint);
AvbUniquePtr avb_handle(nullptr);
@@ -1247,42 +1218,41 @@
return FS_MGR_DOMNT_FAILED;
}
- for (i = 0; i < fstab->num_entries; i++) {
- if (!fs_match(fstab->recs[i].mount_point, n_name)) {
+ for (auto& fstab_entry : *fstab) {
+ if (!fs_match(fstab_entry.mount_point, n_name)) {
continue;
}
- /* We found our match */
- /* If this swap or a raw partition, report an error */
- if (!strcmp(fstab->recs[i].fs_type, "swap") ||
- !strcmp(fstab->recs[i].fs_type, "emmc") ||
- !strcmp(fstab->recs[i].fs_type, "mtd")) {
- LERROR << "Cannot mount filesystem of type "
- << fstab->recs[i].fs_type << " on " << n_blk_device;
+ // We found our match.
+ // If this swap or a raw partition, report an error.
+ if (fstab_entry.fs_type == "swap" || fstab_entry.fs_type == "emmc" ||
+ fstab_entry.fs_type == "mtd") {
+ LERROR << "Cannot mount filesystem of type " << fstab_entry.fs_type << " on "
+ << n_blk_device;
return FS_MGR_DOMNT_FAILED;
}
- if ((fstab->recs[i].fs_mgr_flags & MF_LOGICAL)) {
- if (!fs_mgr_update_logical_partition(&fstab->recs[i])) {
+ if (fstab_entry.fs_mgr_flags.logical) {
+ if (!fs_mgr_update_logical_partition(&fstab_entry)) {
LERROR << "Could not set up logical partition, skipping!";
continue;
}
}
- if (!checkpoint_manager.Update(&fstab->recs[i])) {
+ if (!checkpoint_manager.Update(&fstab_entry)) {
LERROR << "Could not set up checkpoint partition, skipping!";
continue;
}
- /* First check the filesystem if requested */
- if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
+ // First check the filesystem if requested.
+ if (fstab_entry.fs_mgr_flags.wait && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
LERROR << "Skipping mounting '" << n_blk_device << "'";
continue;
}
- int fs_stat = prepare_fs_for_mount(n_blk_device, &fstab->recs[i]);
+ int fs_stat = prepare_fs_for_mount(n_blk_device, fstab_entry);
- if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
+ if (fstab_entry.fs_mgr_flags.avb) {
if (!avb_handle) {
avb_handle = AvbHandle::Open();
if (!avb_handle) {
@@ -1290,15 +1260,15 @@
return FS_MGR_DOMNT_FAILED;
}
}
- if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
+ if (avb_handle->SetUpAvbHashtree(&fstab_entry, true /* wait_for_verity_dev */) ==
AvbHashtreeResult::kFail) {
- LERROR << "Failed to set up AVB on partition: "
- << fstab->recs[i].mount_point << ", skipping!";
- /* Skips mounting the device. */
+ LERROR << "Failed to set up AVB on partition: " << fstab_entry.mount_point
+ << ", skipping!";
+ // Skips mounting the device.
continue;
}
- } else if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY)) {
- int rc = fs_mgr_setup_verity(&fstab->recs[i], true);
+ } else if (fstab_entry.fs_mgr_flags.verify) {
+ int rc = fs_mgr_setup_verity(&fstab_entry, true);
if (__android_log_is_debuggable() &&
(rc == FS_MGR_SETUP_VERITY_DISABLED ||
rc == FS_MGR_SETUP_VERITY_SKIPPED)) {
@@ -1309,15 +1279,15 @@
}
}
- /* Now mount it where requested */
+ // Now mount it where requested */
if (tmp_mount_point) {
mount_point = tmp_mount_point;
} else {
- mount_point = fstab->recs[i].mount_point;
+ mount_point = fstab_entry.mount_point;
}
int retry_count = 2;
while (retry_count-- > 0) {
- if (!__mount(n_blk_device, mount_point, &fstab->recs[i])) {
+ if (!__mount(n_blk_device, mount_point, fstab_entry)) {
fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
return FS_MGR_DOMNT_SUCCESS;
} else {
@@ -1326,10 +1296,10 @@
mount_errors++;
fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
// try again after fsck
- check_fs(n_blk_device, fstab->recs[i].fs_type, fstab->recs[i].mount_point, &fs_stat);
+ check_fs(n_blk_device, fstab_entry.fs_type, fstab_entry.mount_point, &fs_stat);
}
}
- log_fs_stat(fstab->recs[i].blk_device, fs_stat);
+ log_fs_stat(fstab_entry.blk_device, fs_stat);
}
// Reach here means the mount attempt fails.
@@ -1337,19 +1307,22 @@
PERROR << "Cannot mount filesystem on " << n_blk_device << " at " << mount_point;
if (first_mount_errno == EBUSY) return FS_MGR_DOMNT_BUSY;
} else {
- /* We didn't find a match, say so and return an error */
+ // We didn't find a match, say so and return an error.
LERROR << "Cannot find mount point " << n_name << " in fstab";
}
return FS_MGR_DOMNT_FAILED;
}
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point) {
- return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1);
+ auto new_fstab = LegacyFstabToFstab(fstab);
+ return fs_mgr_do_mount_helper(&new_fstab, n_name, n_blk_device, tmp_mount_point, -1);
}
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
bool needs_checkpoint) {
- return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_checkpoint);
+ auto new_fstab = LegacyFstabToFstab(fstab);
+ return fs_mgr_do_mount_helper(&new_fstab, n_name, n_blk_device, tmp_mount_point,
+ needs_checkpoint);
}
/*
@@ -1492,23 +1465,22 @@
* logging mode, in which case return that */
*mode = VERITY_MODE_DEFAULT;
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
- if (!fstab) {
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
LERROR << "Failed to read default fstab";
return false;
}
- for (int i = 0; i < fstab->num_entries; i++) {
- if (fs_mgr_is_avb(&fstab->recs[i])) {
+ for (const auto& entry : fstab) {
+ if (entry.fs_mgr_flags.avb) {
*mode = VERITY_MODE_RESTART; // avb only supports restart mode.
break;
- } else if (!fs_mgr_is_verified(&fstab->recs[i])) {
+ } else if (!entry.fs_mgr_flags.verify) {
continue;
}
int current;
- if (load_verity_state(&fstab->recs[i], ¤t) < 0) {
+ if (load_verity_state(entry, ¤t) < 0) {
continue;
}
if (current != VERITY_MODE_DEFAULT) {
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 737deca..1a0e7ab 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -120,20 +120,21 @@
LOG_KLOG, true, nullptr, nullptr, 0);
}
-int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
-{
- int rc = -EINVAL;
+int fs_mgr_do_format(const FstabEntry& entry, bool crypt_footer) {
+ LERROR << __FUNCTION__ << ": Format " << entry.blk_device << " as '" << entry.fs_type << "'";
- LERROR << __FUNCTION__ << ": Format " << fstab->blk_device
- << " as '" << fstab->fs_type << "'";
-
- if (!strncmp(fstab->fs_type, "f2fs", 4)) {
- rc = format_f2fs(fstab->blk_device, fstab->length, crypt_footer);
- } else if (!strncmp(fstab->fs_type, "ext4", 4)) {
- rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
+ if (entry.fs_type == "f2fs") {
+ return format_f2fs(entry.blk_device, entry.length, crypt_footer);
+ } else if (entry.fs_type == "ext4") {
+ return format_ext4(entry.blk_device, entry.mount_point, crypt_footer);
} else {
- LERROR << "File system type '" << fstab->fs_type << "' is not supported";
+ LERROR << "File system type '" << entry.fs_type << "' is not supported";
+ return -EINVAL;
}
+}
- return rc;
+int fs_mgr_do_format(struct fstab_rec* rec, bool crypt_footer) {
+ auto entry = FstabRecToFstabEntry(rec);
+
+ return fs_mgr_do_format(entry, crypt_footer);
}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 0fde22e..bd9d675 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -33,6 +33,7 @@
#include "fs_mgr_priv.h"
+using android::base::Split;
using android::base::StartsWith;
const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
@@ -53,11 +54,12 @@
int file_names_mode = 0;
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
+ std::string vbmeta_partition;
};
struct flag_list {
const char *name;
- unsigned int flag;
+ uint64_t flag;
};
static struct flag_list mount_flags[] = {
@@ -97,6 +99,7 @@
{"verifyatboot", MF_VERIFYATBOOT},
{"verify", MF_VERIFY},
{"avb", MF_AVB},
+ {"avb=", MF_AVB},
{"noemulatedsd", MF_NOEMULATEDSD},
{"notrim", MF_NOTRIM},
{"formattable", MF_FORMATTABLE},
@@ -113,6 +116,7 @@
{"logical", MF_LOGICAL},
{"checkpoint=block", MF_CHECKPOINT_BLK},
{"checkpoint=fs", MF_CHECKPOINT_FS},
+ {"slotselect_other", MF_SLOTSELECT_OTHER},
{0, 0},
};
@@ -120,9 +124,11 @@
#define EM_ICE 2
#define EM_AES_256_CTS 3
#define EM_AES_256_HEH 4
+#define EM_ADIANTUM 5
static const struct flag_list file_contents_encryption_modes[] = {
{"aes-256-xts", EM_AES_256_XTS},
+ {"adiantum", EM_ADIANTUM},
{"software", EM_AES_256_XTS}, /* alias for backwards compatibility */
{"ice", EM_ICE}, /* hardware-specific inline cryptographic engine */
{0, 0},
@@ -131,6 +137,7 @@
static const struct flag_list file_names_encryption_modes[] = {
{"aes-256-cts", EM_AES_256_CTS},
{"aes-256-heh", EM_AES_256_HEH},
+ {"adiantum", EM_ADIANTUM},
{0, 0},
};
@@ -201,11 +208,9 @@
return false;
}
-static int parse_flags(char *flags, struct flag_list *fl,
- struct fs_mgr_flag_values *flag_vals,
- char *fs_options, int fs_options_len)
-{
- int f = 0;
+static uint64_t parse_flags(char* flags, struct flag_list* fl, struct fs_mgr_flag_values* flag_vals,
+ char* fs_options, int fs_options_len) {
+ uint64_t f = 0;
int i;
char *p;
char *savep;
@@ -271,6 +276,8 @@
flag_vals->file_names_mode =
encryption_mode_to_flag(file_names_encryption_modes,
colon + 1, "file names");
+ } else if (flag_vals->file_contents_mode == EM_ADIANTUM) {
+ flag_vals->file_names_mode = EM_ADIANTUM;
} else {
flag_vals->file_names_mode = EM_AES_256_CTS;
}
@@ -309,6 +316,8 @@
flag_vals->swap_prio = strtoll(arg, NULL, 0);
} else if (flag == MF_MAX_COMP_STREAMS) {
flag_vals->max_comp_streams = strtoll(arg, NULL, 0);
+ } else if (flag == MF_AVB) {
+ flag_vals->vbmeta_partition = arg;
} else if (flag == MF_ZRAMSIZE) {
auto is_percent = !!strrchr(arg, '%');
auto val = strtoll(arg, NULL, 0);
@@ -578,6 +587,7 @@
entry.erase_blk_size = flag_vals.erase_blk_size;
entry.logical_blk_size = flag_vals.logical_blk_size;
entry.sysfs_path = std::move(flag_vals.sysfs_path);
+ entry.vbmeta_partition = std::move(flag_vals.vbmeta_partition);
if (entry.fs_mgr_flags.logical) {
entry.logical_partition_name = entry.blk_device;
}
@@ -840,11 +850,12 @@
}
std::set<std::string> fs_mgr_get_boot_devices() {
- // boot_devices can be specified in device tree.
- std::string dt_value;
- std::string file_name = get_android_dt_dir() + "/boot_devices";
- if (read_dt_file(file_name, &dt_value)) {
- auto boot_devices = android::base::Split(dt_value, ",");
+ // First check the kernel commandline, then try the device tree otherwise
+ std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
+ std::string value;
+ if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
+ read_dt_file(dt_file_name, &value)) {
+ auto boot_devices = Split(value, ",");
return std::set<std::string>(boot_devices.begin(), boot_devices.end());
}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index d2d8dc1..8bfcd81 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -70,19 +70,11 @@
#if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs
-bool fs_mgr_overlayfs_mount_all(fstab*) {
+bool fs_mgr_overlayfs_mount_all(Fstab*) {
return false;
}
-bool fs_mgr_overlayfs_mount_all(const std::vector<fstab_rec*>&) {
- return false;
-}
-
-std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab*) {
- return {};
-}
-
-std::vector<std::string> fs_mgr_overlayfs_required_devices(const std::vector<fstab_rec*>&) {
+std::vector<std::string> fs_mgr_overlayfs_required_devices(Fstab*) {
return {};
}
@@ -131,28 +123,31 @@
// At less than 1% free space return value of false,
// means we will try to wrap with overlayfs.
-bool fs_mgr_filesystem_has_space(const char* mount_point) {
+bool fs_mgr_filesystem_has_space(const std::string& mount_point) {
// If we have access issues to find out space remaining, return true
// to prevent us trying to override with overlayfs.
struct statvfs vst;
- if (statvfs(mount_point, &vst)) return true;
+ if (statvfs(mount_point.c_str(), &vst)) return true;
static constexpr int kPercentThreshold = 1; // 1%
return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100));
}
-bool fs_mgr_overlayfs_enabled(struct fstab_rec* fsrec) {
+bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
// readonly filesystem, can not be mount -o remount,rw
// if squashfs or if free space is (near) zero making such a remount
// virtually useless, or if there are shared blocks that prevent remount,rw
- if (("squashfs"s == fsrec->fs_type) || !fs_mgr_filesystem_has_space(fsrec->mount_point)) {
+ if ("squashfs" == entry->fs_type || !fs_mgr_filesystem_has_space(entry->mount_point)) {
return true;
}
- if (fs_mgr_is_logical(fsrec)) {
- fs_mgr_update_logical_partition(fsrec);
+ if (entry->fs_mgr_flags.logical) {
+ fs_mgr_update_logical_partition(entry);
}
- return fs_mgr_has_shared_blocks(fsrec->mount_point, fsrec->blk_device);
+ auto save_errno = errno;
+ auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
+ errno = save_errno;
+ return has_shared_blocks;
}
bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
@@ -250,22 +245,16 @@
}
bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"),
- fs_mgr_free_fstab);
- if (!fstab) return false;
+ Fstab fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+ return false;
+ }
const auto lowerdir = kLowerdirOption + mount_point;
- for (auto i = 0; i < fstab->num_entries; ++i) {
- const auto fsrec = &fstab->recs[i];
- const auto fs_type = fsrec->fs_type;
- if (!fs_type) continue;
- if (overlay_only && ("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue;
- auto fsrec_mount_point = fsrec->mount_point;
- if (!fsrec_mount_point) continue;
- if (mount_point != fsrec_mount_point) continue;
+ for (const auto& entry : fstab) {
+ if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
+ if (mount_point != entry.mount_point) continue;
if (!overlay_only) return true;
- const auto fs_options = fsrec->fs_options;
- if (!fs_options) continue;
- const auto options = android::base::Split(fs_options, ",");
+ const auto options = android::base::Split(entry.fs_options, ",");
for (const auto& opt : options) {
if (opt == lowerdir) {
return true;
@@ -277,33 +266,27 @@
std::vector<std::string> fs_mgr_overlayfs_verity_enabled_list() {
std::vector<std::string> ret;
+ auto save_errno = errno;
fs_mgr_update_verity_state(
[&ret](const std::string& mount_point, int) { ret.emplace_back(mount_point); });
+ if ((errno == ENOENT) || (errno == ENXIO)) errno = save_errno;
return ret;
}
-bool fs_mgr_wants_overlayfs(fstab_rec* fsrec) {
- if (!fsrec) return false;
-
- auto fsrec_mount_point = fsrec->mount_point;
- if (!fsrec_mount_point || !fsrec_mount_point[0]) return false;
- if (!fsrec->blk_device) return false;
-
- if (!fsrec->fs_type) return false;
-
+bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
// Don't check entries that are managed by vold.
- if (fsrec->fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) return false;
+ if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;
// Only concerned with readonly partitions.
- if (!(fsrec->flags & MS_RDONLY)) return false;
+ if (!(entry->flags & MS_RDONLY)) return false;
// If unbindable, do not allow overlayfs as this could expose us to
// security issues. On Android, this could also be used to turn off
// the ability to overlay an otherwise acceptable filesystem since
// /system and /vendor are never bound(sic) to.
- if (fsrec->flags & MS_UNBINDABLE) return false;
+ if (entry->flags & MS_UNBINDABLE) return false;
- if (!fs_mgr_overlayfs_enabled(fsrec)) return false;
+ if (!fs_mgr_overlayfs_enabled(entry)) return false;
return true;
}
@@ -391,11 +374,11 @@
return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number);
}
-bool fs_mgr_overlayfs_has_logical(const fstab* fstab) {
- if (!fstab) return false;
- for (auto i = 0; i < fstab->num_entries; i++) {
- const auto fsrec = &fstab->recs[i];
- if (fs_mgr_is_logical(fsrec)) return true;
+bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) {
+ for (const auto& entry : fstab) {
+ if (entry.fs_mgr_flags.logical) {
+ return true;
+ }
}
return false;
}
@@ -521,7 +504,7 @@
// hijack __mount() report format to help triage
auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
const auto opt_list = android::base::Split(options, ",");
- for (const auto opt : opt_list) {
+ for (const auto& opt : opt_list) {
if (android::base::StartsWith(opt, kUpperdirOption)) {
report = report + "," + opt;
break;
@@ -540,15 +523,12 @@
}
}
-std::vector<std::string> fs_mgr_candidate_list(fstab* fstab, const char* mount_point = nullptr) {
+std::vector<std::string> fs_mgr_candidate_list(Fstab* fstab, const char* mount_point = nullptr) {
std::vector<std::string> mounts;
- if (!fstab) return mounts;
-
auto verity = fs_mgr_overlayfs_verity_enabled_list();
- for (auto i = 0; i < fstab->num_entries; i++) {
- const auto fsrec = &fstab->recs[i];
- if (!fs_mgr_wants_overlayfs(fsrec)) continue;
- std::string new_mount_point(fs_mgr_mount_point(fsrec->mount_point));
+ for (auto& entry : *fstab) {
+ if (!fs_mgr_wants_overlayfs(&entry)) continue;
+ std::string new_mount_point(fs_mgr_mount_point(entry.mount_point.c_str()));
if (mount_point && (new_mount_point != mount_point)) continue;
if (std::find(verity.begin(), verity.end(), android::base::Basename(new_mount_point)) !=
verity.end()) {
@@ -580,10 +560,9 @@
if (std::find(verity.begin(), verity.end(), "system") != verity.end()) return mounts;
// confirm that fstab is missing system
- if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/")) {
- return mounts;
- }
- if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), "/system")) {
+ if (std::find_if(fstab->begin(), fstab->end(), [](const auto& entry) {
+ return entry.mount_point == "/" || entry.mount_point == "/system ";
+ }) != fstab->end()) {
return mounts;
}
@@ -605,26 +584,20 @@
PERROR << "create " << kScratchMountPoint;
}
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> local_fstab(
- static_cast<fstab*>(calloc(1, sizeof(fstab))), fs_mgr_free_fstab);
- auto fsrec = static_cast<fstab_rec*>(calloc(1, sizeof(fstab_rec)));
- local_fstab->num_entries = 1;
- local_fstab->recs = fsrec;
- fsrec->blk_device = strdup(device_path.c_str());
- fsrec->mount_point = strdup(kScratchMountPoint.c_str());
- fsrec->fs_type = strdup(mnt_type.c_str());
- fsrec->flags = MS_RELATIME;
- fsrec->fs_options = strdup("");
+ FstabEntry entry;
+ entry.blk_device = device_path;
+ entry.mount_point = kScratchMountPoint;
+ entry.fs_type = mnt_type;
+ entry.flags = MS_RELATIME;
auto save_errno = errno;
- auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
+ auto mounted = fs_mgr_do_mount_one(entry) == 0;
if (!mounted) {
- free(fsrec->fs_type);
if (mnt_type == "f2fs") {
- fsrec->fs_type = strdup("ext4");
+ entry.fs_type = "ext4";
} else {
- fsrec->fs_type = strdup("f2fs");
+ entry.fs_type = "f2fs";
}
- mounted = fs_mgr_do_mount_one(fsrec) == 0;
+ mounted = fs_mgr_do_mount_one(entry) == 0;
if (!mounted) save_errno = errno;
}
setfscreatecon(nullptr);
@@ -681,7 +654,7 @@
return true;
}
-bool fs_mgr_overlayfs_create_scratch(const fstab* fstab, std::string* scratch_device,
+bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device,
bool* partition_exists, bool* change) {
*scratch_device = fs_mgr_overlayfs_scratch_device();
*partition_exists = fs_mgr_rw_access(*scratch_device);
@@ -765,7 +738,7 @@
}
// Create and mount kScratchMountPoint storage if we have logical partitions
-bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) {
+bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab, bool* change) {
if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
std::string scratch_device;
@@ -805,20 +778,20 @@
return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr;
}
-bool fs_mgr_overlayfs_invalid(const fstab* fstab) {
+bool fs_mgr_overlayfs_invalid() {
if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true;
// in recovery or fastbootd mode, not allowed!
if (fs_mgr_access("/system/bin/recovery")) return true;
- return !fstab;
+ return false;
}
} // namespace
-bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
+bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
auto ret = false;
- if (fs_mgr_overlayfs_invalid(fstab)) return ret;
+ if (fs_mgr_overlayfs_invalid()) return ret;
auto scratch_can_be_mounted = true;
for (const auto& mount_point : fs_mgr_candidate_list(fstab)) {
@@ -839,17 +812,12 @@
return ret;
}
-bool fs_mgr_overlayfs_mount_all(const std::vector<fstab_rec*>& fsrecs) {
- std::vector<fstab_rec> recs;
- for (const auto& rec : fsrecs) recs.push_back(*rec);
- fstab fstab = {static_cast<int>(fsrecs.size()), &recs[0]};
- return fs_mgr_overlayfs_mount_all(&fstab);
-}
+std::vector<std::string> fs_mgr_overlayfs_required_devices(Fstab* fstab) {
+ if (fs_mgr_overlayfs_invalid()) return {};
-std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
- if (fs_mgr_overlayfs_invalid(fstab)) return {};
-
- if (fs_mgr_get_entry_for_mount_point(fstab, kScratchMountPoint)) {
+ if (std::find_if(fstab->begin(), fstab->end(), [](const auto& entry) {
+ return entry.mount_point == kScratchMountPoint;
+ }) != fstab->end()) {
return {};
}
@@ -862,13 +830,6 @@
return {};
}
-std::vector<std::string> fs_mgr_overlayfs_required_devices(const std::vector<fstab_rec*>& fsrecs) {
- std::vector<fstab_rec> recs;
- for (const auto& rec : fsrecs) recs.push_back(*rec);
- fstab fstab = {static_cast<int>(fsrecs.size()), &recs[0]};
- return fs_mgr_overlayfs_required_devices(&fstab);
-}
-
// Returns false if setup not permitted, errno set to last error.
// If something is altered, set *change.
bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) {
@@ -881,10 +842,13 @@
return ret;
}
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
- if (!fstab) return ret;
- auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(mount_point));
+ auto save_errno = errno;
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ return false;
+ }
+ errno = save_errno;
+ auto mounts = fs_mgr_candidate_list(&fstab, fs_mgr_mount_point(mount_point));
if (mounts.empty()) return ret;
std::string dir;
@@ -892,18 +856,23 @@
if (backing && backing[0] && (overlay_mount_point != backing)) continue;
if (overlay_mount_point == kScratchMountPoint) {
if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) ||
- !fs_mgr_overlayfs_has_logical(fstab.get())) {
+ !fs_mgr_overlayfs_has_logical(fstab)) {
continue;
}
- if (!fs_mgr_overlayfs_setup_scratch(fstab.get(), change)) continue;
+ if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
} else {
- if (!fs_mgr_get_entry_for_mount_point(fstab.get(), overlay_mount_point)) continue;
+ if (std::find_if(fstab.begin(), fstab.end(), [&overlay_mount_point](const auto& entry) {
+ return entry.mount_point == overlay_mount_point;
+ }) == fstab.end()) {
+ continue;
+ }
}
dir = overlay_mount_point;
break;
}
if (dir.empty()) {
- errno = ESRCH;
+ if (change && *change) errno = ESRCH;
+ if (errno == EPERM) errno = save_errno;
return ret;
}
@@ -959,10 +928,12 @@
bool fs_mgr_overlayfs_is_setup() {
if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(),
- fs_mgr_free_fstab);
- if (fs_mgr_overlayfs_invalid(fstab.get())) return false;
- for (const auto& mount_point : fs_mgr_candidate_list(fstab.get())) {
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ return false;
+ }
+ if (fs_mgr_overlayfs_invalid()) return false;
+ for (const auto& mount_point : fs_mgr_candidate_list(&fstab)) {
if (fs_mgr_overlayfs_already_mounted(mount_point)) return true;
}
return false;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index faef34b..7d1159b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -120,6 +120,8 @@
#define MF_CHECKPOINT_FS 0x40000000
#define MF_FIRST_STAGE_MOUNT \
0x80000000
+#define MF_SLOTSELECT_OTHER \
+ 0x100000000
// clang-format on
#define DM_BUF_SIZE 4096
@@ -137,6 +139,6 @@
bool fs_mgr_is_device_unlocked();
const std::string& get_android_dt_dir();
bool is_dt_compatible();
-int load_verity_state(fstab_rec* fstab, int* mode);
+int load_verity_state(const FstabEntry& entry, int* mode);
#endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 20d60ae..3cb718c 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -21,6 +21,19 @@
#include "fs_mgr.h"
#include "fs_mgr_priv.h"
+// https://source.android.com/devices/tech/ota/ab/ab_implement#partitions
+// All partitions that are A/B-ed should be named as follows (slots are always
+// named a, b, etc.): boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
+static std::string other_suffix(const std::string& slot_suffix) {
+ if (slot_suffix == "_a") {
+ return "_b";
+ }
+ if (slot_suffix == "_b") {
+ return "_a";
+ }
+ return "";
+}
+
// Returns "_a" or "_b" based on androidboot.slot_suffix in kernel cmdline, or an empty string
// if that parameter does not exist.
std::string fs_mgr_get_slot_suffix() {
@@ -32,11 +45,10 @@
// Updates |fstab| for slot_suffix. Returns true on success, false on error.
bool fs_mgr_update_for_slotselect(Fstab* fstab) {
- int n;
std::string ab_suffix;
for (auto& entry : *fstab) {
- if (!entry.fs_mgr_flags.slot_select) {
+ if (!entry.fs_mgr_flags.slot_select && !entry.fs_mgr_flags.slot_select_other) {
continue;
}
@@ -46,8 +58,10 @@
if (ab_suffix.empty()) return false;
}
- entry.blk_device = entry.blk_device + ab_suffix;
- entry.logical_partition_name = entry.logical_partition_name + ab_suffix;
+ const auto& update_suffix =
+ entry.fs_mgr_flags.slot_select ? ab_suffix : other_suffix(ab_suffix);
+ entry.blk_device = entry.blk_device + update_suffix;
+ entry.logical_partition_name = entry.logical_partition_name + update_suffix;
}
return true;
}
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 2727a6d..9adf8cc 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -536,8 +536,7 @@
return 0;
}
-static int compare_last_signature(struct fstab_rec *fstab, int *match)
-{
+static int compare_last_signature(const FstabEntry& entry, int* match) {
char tag[METADATA_TAG_MAX_LENGTH + 1];
int fd = -1;
int rc = -1;
@@ -549,42 +548,40 @@
*match = 1;
- if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
- FEC_DEFAULT_ROOTS) == -1) {
- PERROR << "Failed to open '" << fstab->blk_device << "'";
+ if (fec_open(&f, entry.blk_device.c_str(), O_RDONLY, FEC_VERITY_DISABLE, FEC_DEFAULT_ROOTS) ==
+ -1) {
+ PERROR << "Failed to open '" << entry.blk_device << "'";
return rc;
}
// read verity metadata
if (fec_verity_get_metadata(f, &verity) == -1) {
- PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
+ PERROR << "Failed to get verity metadata '" << entry.blk_device << "'";
goto out;
}
SHA256(verity.signature, sizeof(verity.signature), curr);
- if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
- basename(fstab->mount_point)) >= (int)sizeof(tag)) {
- LERROR << "Metadata tag name too long for " << fstab->mount_point;
+ if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s", basename(entry.mount_point.c_str())) >=
+ (int)sizeof(tag)) {
+ LERROR << "Metadata tag name too long for " << entry.mount_point;
goto out;
}
- if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_LENGTH,
- &offset) < 0) {
+ if (metadata_find(entry.verity_loc.c_str(), tag, SHA256_DIGEST_LENGTH, &offset) < 0) {
goto out;
}
- fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
+ fd = TEMP_FAILURE_RETRY(open(entry.verity_loc.c_str(), O_RDWR | O_SYNC | O_CLOEXEC));
if (fd == -1) {
- PERROR << "Failed to open " << fstab->verity_loc;
+ PERROR << "Failed to open " << entry.verity_loc;
goto out;
}
- if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
- offset)) != sizeof(prev)) {
- PERROR << "Failed to read " << sizeof(prev) << " bytes from "
- << fstab->verity_loc << " offset " << offset;
+ if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev), offset)) != sizeof(prev)) {
+ PERROR << "Failed to read " << sizeof(prev) << " bytes from " << entry.verity_loc
+ << " offset " << offset;
goto out;
}
@@ -594,8 +591,8 @@
/* update current signature hash */
if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
offset)) != sizeof(curr)) {
- PERROR << "Failed to write " << sizeof(curr) << " bytes to "
- << fstab->verity_loc << " offset " << offset;
+ PERROR << "Failed to write " << sizeof(curr) << " bytes to " << entry.verity_loc
+ << " offset " << offset;
goto out;
}
}
@@ -607,28 +604,23 @@
return rc;
}
-static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
-{
+static int get_verity_state_offset(const FstabEntry& entry, off64_t* offset) {
char tag[METADATA_TAG_MAX_LENGTH + 1];
- if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
- basename(fstab->mount_point)) >= (int)sizeof(tag)) {
- LERROR << "Metadata tag name too long for " << fstab->mount_point;
+ if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s", basename(entry.mount_point.c_str())) >=
+ (int)sizeof(tag)) {
+ LERROR << "Metadata tag name too long for " << entry.mount_point;
return -1;
}
- return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
- offset);
+ return metadata_find(entry.verity_loc.c_str(), tag, sizeof(struct verity_state), offset);
}
-int load_verity_state(struct fstab_rec* fstab, int* mode) {
- int match = 0;
- off64_t offset = 0;
-
- /* unless otherwise specified, use EIO mode */
+int load_verity_state(const FstabEntry& entry, int* mode) {
+ // unless otherwise specified, use EIO mode.
*mode = VERITY_MODE_EIO;
- /* use the kernel parameter if set */
+ // use the kernel parameter if set.
std::string veritymode;
if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
if (veritymode == "enforcing") {
@@ -637,7 +629,8 @@
return 0;
}
- if (get_verity_state_offset(fstab, &offset) < 0) {
+ off64_t offset = 0;
+ if (get_verity_state_offset(entry, &offset) < 0) {
/* fall back to stateless behavior */
return 0;
}
@@ -645,16 +638,17 @@
if (was_verity_restart()) {
/* device was restarted after dm-verity detected a corrupted
* block, so use EIO mode */
- return write_verity_state(fstab->verity_loc, offset, *mode);
+ return write_verity_state(entry.verity_loc.c_str(), offset, *mode);
}
- if (!compare_last_signature(fstab, &match) && !match) {
+ int match = 0;
+ if (!compare_last_signature(entry, &match) && !match) {
/* partition has been reflashed, reset dm-verity state */
*mode = VERITY_MODE_DEFAULT;
- return write_verity_state(fstab->verity_loc, offset, *mode);
+ return write_verity_state(entry.verity_loc.c_str(), offset, *mode);
}
- return read_verity_state(fstab->verity_loc, offset, mode);
+ return read_verity_state(entry.verity_loc.c_str(), offset, mode);
}
// Update the verity table using the actual block device path.
@@ -716,8 +710,7 @@
// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
// verity device to get created before return
-int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
-{
+int fs_mgr_setup_verity(FstabEntry* entry, bool wait_for_verity_dev) {
int retval = FS_MGR_SETUP_VERITY_FAIL;
int fd = -1;
std::string verity_blk_name;
@@ -725,20 +718,20 @@
struct fec_verity_metadata verity;
struct verity_table_params params = { .table = NULL };
- const std::string mount_point(basename(fstab->mount_point));
+ const std::string mount_point(basename(entry->mount_point.c_str()));
bool verified_at_boot = false;
android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
- if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
- FEC_DEFAULT_ROOTS) < 0) {
- PERROR << "Failed to open '" << fstab->blk_device << "'";
+ if (fec_open(&f, entry->blk_device.c_str(), O_RDONLY, FEC_VERITY_DISABLE, FEC_DEFAULT_ROOTS) <
+ 0) {
+ PERROR << "Failed to open '" << entry->blk_device << "'";
return retval;
}
// read verity metadata
if (fec_verity_get_metadata(f, &verity) < 0) {
- PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
+ PERROR << "Failed to get verity metadata '" << entry->blk_device << "'";
// Allow verity disabled when the device is unlocked without metadata
if (fs_mgr_is_device_unlocked()) {
retval = FS_MGR_SETUP_VERITY_SKIPPED;
@@ -760,9 +753,9 @@
params.ecc.valid = false;
}
- params.ecc_dev = fstab->blk_device;
+ params.ecc_dev = entry->blk_device.c_str();
- if (load_verity_state(fstab, ¶ms.mode) < 0) {
+ if (load_verity_state(*entry, ¶ms.mode) < 0) {
/* if accessing or updating the state failed, switch to the default
* safe mode. This makes sure the device won't end up in an endless
* restart loop, and no corrupted data will be exposed to userspace
@@ -803,8 +796,8 @@
<< " (mode " << params.mode << ")";
// Update the verity params using the actual block device path
- update_verity_table_blk_device(fstab->blk_device, ¶ms.table,
- fstab->fs_mgr_flags & MF_SLOTSELECT);
+ update_verity_table_blk_device(entry->blk_device, ¶ms.table,
+ entry->fs_mgr_flags.slot_select);
// load the verity mapping table
if (load_verity_table(dm, mount_point, verity.data_size, ¶ms, format_verity_table) == 0) {
@@ -848,31 +841,29 @@
}
// mark the underlying block device as read-only
- fs_mgr_set_blk_ro(fstab->blk_device);
+ fs_mgr_set_blk_ro(entry->blk_device);
// Verify the entire partition in one go
// If there is an error, allow it to mount as a normal verity partition.
- if (fstab->fs_mgr_flags & MF_VERIFYATBOOT) {
- LINFO << "Verifying partition " << fstab->blk_device << " at boot";
+ if (entry->fs_mgr_flags.verify_at_boot) {
+ LINFO << "Verifying partition " << entry->blk_device << " at boot";
int err = read_partition(verity_blk_name.c_str(), verity.data_size);
if (!err) {
- LINFO << "Verified verity partition "
- << fstab->blk_device << " at boot";
+ LINFO << "Verified verity partition " << entry->blk_device << " at boot";
verified_at_boot = true;
}
}
// assign the new verity block device as the block device
if (!verified_at_boot) {
- free(fstab->blk_device);
- fstab->blk_device = strdup(verity_blk_name.c_str());
+ entry->blk_device = verity_blk_name;
} else if (!dm.DeleteDevice(mount_point)) {
LERROR << "Failed to remove verity device " << mount_point.c_str();
goto out;
}
// make sure we've set everything up properly
- if (wait_for_verity_dev && !fs_mgr_wait_for_file(fstab->blk_device, 1s)) {
+ if (wait_for_verity_dev && !fs_mgr_wait_for_file(entry->blk_device, 1s)) {
goto out;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c1dc731..814ba46 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -59,7 +59,8 @@
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
-int fs_mgr_mount_all(fstab* fstab, int mount_mode);
+// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
+int fs_mgr_mount_all(Fstab* fstab, int mount_mode);
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
@@ -68,6 +69,7 @@
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
bool need_cp);
+int fs_mgr_do_mount_one(const FstabEntry& entry);
int fs_mgr_do_mount_one(fstab_rec* rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
@@ -76,15 +78,17 @@
bool fs_mgr_update_verity_state(
std::function<void(const std::string& mount_point, int mode)> callback);
bool fs_mgr_swapon_all(const Fstab& fstab);
+bool fs_mgr_update_logical_partition(FstabEntry* entry);
bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
-int fs_mgr_do_format(fstab_rec* fstab, bool reserve_footer);
+int fs_mgr_do_format(const FstabEntry& entry, bool reserve_footer);
+int fs_mgr_do_format(fstab_rec* rec, bool reserve_footer);
#define FS_MGR_SETUP_VERITY_SKIPPED (-3)
#define FS_MGR_SETUP_VERITY_DISABLED (-2)
#define FS_MGR_SETUP_VERITY_FAIL (-1)
#define FS_MGR_SETUP_VERITY_SUCCESS 0
-int fs_mgr_setup_verity(fstab_rec* fstab, bool wait_for_verity_dev);
+int fs_mgr_setup_verity(FstabEntry* fstab, bool wait_for_verity_dev);
// Return the name of the super partition if it exists. If a slot number is
// specified, the super partition for the corresponding metadata slot will be
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 0dd9121..4bf2238 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -21,10 +21,8 @@
#include <string>
#include <vector>
-bool fs_mgr_overlayfs_mount_all(fstab* fstab);
-bool fs_mgr_overlayfs_mount_all(const std::vector<fstab_rec*>& fstab);
-std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab);
-std::vector<std::string> fs_mgr_overlayfs_required_devices(const std::vector<fstab_rec*>& fstab);
+bool fs_mgr_overlayfs_mount_all(Fstab* fstab);
+std::vector<std::string> fs_mgr_overlayfs_required_devices(Fstab* fstab);
bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
bool* change = nullptr);
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 4706028..0997254 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -43,7 +43,7 @@
char* fs_type;
unsigned long flags;
char* fs_options;
- int fs_mgr_flags;
+ uint64_t fs_mgr_flags;
char* key_loc;
char* key_dir;
char* verity_loc;
@@ -118,12 +118,14 @@
off64_t erase_blk_size = 0;
off64_t logical_blk_size = 0;
std::string sysfs_path;
+ std::string vbmeta_partition;
// TODO: Remove this union once fstab_rec is deprecated. It only serves as a
// convenient way to convert between fstab_rec::fs_mgr_flags and these bools.
union {
- int val;
+ uint64_t val;
struct {
+ // bit 0
bool wait : 1;
bool check : 1;
bool crypt : 1;
@@ -132,6 +134,8 @@
bool length : 1;
bool recovery_only : 1;
bool swap_prio : 1;
+
+ // bit 8
bool zram_size : 1;
bool verify : 1;
bool force_crypt : 1;
@@ -141,6 +145,8 @@
bool file_encryption : 1;
bool formattable : 1;
bool slot_select : 1;
+
+ // bit 16
bool force_fde_or_fbe : 1;
bool late_mount : 1;
bool no_fail : 1;
@@ -149,6 +155,8 @@
bool reserved_size : 1;
bool quota : 1;
bool erase_blk_size : 1;
+
+ // bit 24
bool logical_blk_size : 1;
bool avb : 1;
bool key_directory : 1;
@@ -156,6 +164,10 @@
bool logical : 1;
bool checkpoint_blk : 1;
bool checkpoint_fs : 1;
+ bool first_stage_mount : 1;
+
+ // bit 32
+ bool slot_select_other : 1;
};
} fs_mgr_flags;
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index c4accad..89c755e 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -265,7 +265,7 @@
return table->AddTarget(std::make_unique<android::dm::DmTargetVerity>(target));
}
-static bool hashtree_dm_verity_setup(struct fstab_rec* fstab_entry,
+static bool hashtree_dm_verity_setup(FstabEntry* fstab_entry,
const AvbHashtreeDescriptor& hashtree_desc,
const std::string& salt, const std::string& root_digest,
bool wait_for_verity_dev) {
@@ -278,7 +278,7 @@
}
table.set_readonly(true);
- const std::string mount_point(basename(fstab_entry->mount_point));
+ const std::string mount_point(basename(fstab_entry->mount_point.c_str()));
android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
if (!dm.CreateDevice(mount_point, table)) {
LERROR << "Couldn't create verity device!";
@@ -295,8 +295,7 @@
fs_mgr_set_blk_ro(fstab_entry->blk_device);
// Updates fstab_rec->blk_device to verity device name.
- free(fstab_entry->blk_device);
- fstab_entry->blk_device = strdup(dev_path.c_str());
+ fstab_entry->blk_device = dev_path;
// Makes sure we've set everything up properly.
if (wait_for_verity_dev && !fs_mgr_wait_for_file(dev_path, 1s)) {
@@ -449,8 +448,7 @@
return avb_handle;
}
-AvbHashtreeResult AvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
- bool wait_for_verity_dev) {
+AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev) {
if (!fstab_entry || status_ == kAvbHandleUninitialized || !avb_slot_data_ ||
avb_slot_data_->num_vbmeta_images < 1) {
return AvbHashtreeResult::kFail;
@@ -464,13 +462,13 @@
// Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
// to setup dm-verity. The partition_names in AVB descriptors are without A/B suffix.
std::string partition_name;
- if (fstab_entry->fs_mgr_flags & MF_LOGICAL) {
+ if (fstab_entry->fs_mgr_flags.logical) {
partition_name = fstab_entry->logical_partition_name;
} else {
- partition_name = basename(fstab_entry->blk_device);
+ partition_name = basename(fstab_entry->blk_device.c_str());
}
- if (fstab_entry->fs_mgr_flags & MF_SLOTSELECT) {
+ if (fstab_entry->fs_mgr_flags.slot_select) {
auto ab_suffix = partition_name.rfind(fs_mgr_get_slot_suffix());
if (ab_suffix != std::string::npos) {
partition_name.erase(ab_suffix);
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 9adab3d..08bdbdc 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -85,7 +85,7 @@
// failed to get the HASHTREE descriptor, runtime error when set up
// device-mapper, etc.
// - kDisabled: hashtree is disabled.
- AvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
+ AvbHashtreeResult SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev);
const std::string& avb_version() const { return avb_version_; }
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 699b9e7..07f9d66 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -606,14 +606,23 @@
}
uint64_t sectors = std::min(sectors_needed, region.length());
+ if (sectors < region.length()) {
+ const auto& block_device = block_devices_[region.device_index];
+ if (block_device.alignment) {
+ const uint64_t alignment = block_device.alignment / LP_SECTOR_SIZE;
+ sectors = AlignTo(sectors, alignment);
+ sectors = std::min(sectors, region.length());
+ }
+ }
CHECK(sectors % sectors_per_block == 0);
auto extent = std::make_unique<LinearExtent>(sectors, region.device_index, region.start);
new_extents.push_back(std::move(extent));
- sectors_needed -= sectors;
- if (!sectors_needed) {
+ if (sectors >= sectors_needed) {
+ sectors_needed = 0;
break;
}
+ sectors_needed -= sectors;
}
if (sectors_needed) {
LERROR << "Not enough free space to expand partition: " << partition->name();
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 7833a25..3793964 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -209,8 +209,8 @@
ASSERT_TRUE(builder->ResizePartition(a, a->size() + 4096));
ASSERT_TRUE(builder->ResizePartition(b, b->size() + 4096));
}
- EXPECT_EQ(a->size(), 40960);
- EXPECT_EQ(b->size(), 40960);
+ EXPECT_EQ(a->size(), 7864320);
+ EXPECT_EQ(b->size(), 7864320);
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
@@ -218,7 +218,7 @@
// Check that each starting sector is aligned.
for (const auto& extent : exported->extents) {
ASSERT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR);
- EXPECT_EQ(extent.num_sectors, 8);
+ EXPECT_EQ(extent.num_sectors, 1536);
uint64_t lba = extent.target_data * LP_SECTOR_SIZE;
uint64_t aligned_lba = AlignTo(lba, device_info.alignment, device_info.alignment_offset);
@@ -645,7 +645,7 @@
EXPECT_EQ(metadata->extents[1].target_type, LP_TARGET_TYPE_LINEAR);
EXPECT_EQ(metadata->extents[1].target_data, 1472);
EXPECT_EQ(metadata->extents[1].target_source, 1);
- EXPECT_EQ(metadata->extents[2].num_sectors, 129088);
+ EXPECT_EQ(metadata->extents[2].num_sectors, 129600);
EXPECT_EQ(metadata->extents[2].target_type, LP_TARGET_TYPE_LINEAR);
EXPECT_EQ(metadata->extents[2].target_data, 1472);
EXPECT_EQ(metadata->extents[2].target_source, 2);
@@ -744,17 +744,41 @@
EXPECT_EQ(system_a->extents().size(), static_cast<size_t>(1));
EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(1));
ASSERT_TRUE(builder->ResizePartition(system_b, 6_GiB));
- EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(3));
+ EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(2));
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
- ASSERT_EQ(exported->extents.size(), static_cast<size_t>(4));
+ ASSERT_EQ(exported->extents.size(), static_cast<size_t>(3));
EXPECT_EQ(exported->extents[0].target_data, 10487808);
- EXPECT_EQ(exported->extents[0].num_sectors, 4194304);
- EXPECT_EQ(exported->extents[1].target_data, 14682624);
- EXPECT_EQ(exported->extents[1].num_sectors, 6288896);
- EXPECT_EQ(exported->extents[2].target_data, 6292992);
- EXPECT_EQ(exported->extents[2].num_sectors, 2099712);
- EXPECT_EQ(exported->extents[3].target_data, 1536);
- EXPECT_EQ(exported->extents[3].num_sectors, 6291456);
+ EXPECT_EQ(exported->extents[0].num_sectors, 10483712);
+ EXPECT_EQ(exported->extents[1].target_data, 6292992);
+ EXPECT_EQ(exported->extents[1].num_sectors, 2099712);
+ EXPECT_EQ(exported->extents[2].target_data, 1536);
+ EXPECT_EQ(exported->extents[2].num_sectors, 6291456);
+}
+
+TEST_F(BuilderTest, PartialExtents) {
+ // super has a minimum extent size of 768KiB.
+ BlockDeviceInfo device_info("super", 1_GiB, 768 * 1024, 0, 4096);
+ auto builder = MetadataBuilder::New(device_info, 65536, 1);
+ ASSERT_NE(builder, nullptr);
+ Partition* system = builder->AddPartition("system", 0);
+ ASSERT_NE(system, nullptr);
+ Partition* vendor = builder->AddPartition("vendor", 0);
+ ASSERT_NE(vendor, nullptr);
+ ASSERT_TRUE(builder->ResizePartition(system, device_info.alignment + 4096));
+ ASSERT_TRUE(builder->ResizePartition(vendor, device_info.alignment));
+ ASSERT_EQ(system->size(), device_info.alignment * 2);
+ ASSERT_EQ(vendor->size(), device_info.alignment);
+
+ ASSERT_TRUE(builder->ResizePartition(system, device_info.alignment * 2));
+ ASSERT_EQ(system->extents().size(), static_cast<size_t>(1));
+
+ unique_ptr<LpMetadata> exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
+ ASSERT_EQ(exported->extents.size(), static_cast<size_t>(2));
+ EXPECT_EQ(exported->extents[0].target_data, 1536);
+ EXPECT_EQ(exported->extents[0].num_sectors, 3072);
+ EXPECT_EQ(exported->extents[1].target_data, 4608);
+ EXPECT_EQ(exported->extents[1].num_sectors, 1536);
}
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index d8195ca..454258b 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -84,7 +84,6 @@
// with potentially invalid metadata, or random partition data with metadata.
static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
const std::string& slot_suffix, std::string* blob) {
- const LpMetadataHeader& header = metadata.header;
const LpMetadataGeometry& geometry = metadata.geometry;
*blob = SerializeMetadata(metadata);
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 561debb..aaee1a7 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -36,17 +36,28 @@
Returns: true if device is in fastboot mode" ]
inFastboot() {
- fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+ fastboot devices |
+ if [ -n "${ANDROID_SERIAL}" ]; then
+ grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+ else
+ wc -l | grep '^1$' >/dev/null
+ fi
}
[ "USAGE: inAdb
Returns: true if device is in adb mode" ]
inAdb() {
- adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+ adb devices |
+ grep -v 'List of devices attached' |
+ if [ -n "${ANDROID_SERIAL}" ]; then
+ grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+ else
+ wc -l | grep '^1$' >/dev/null
+ fi
}
-[ "USAGE: adb_sh <commands>
+[ "USAGE: adb_sh <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
Returns: true if the command succeeded" ]
adb_sh() {
@@ -86,7 +97,7 @@
fi
}
-[ "USAGE: adb_su <commands>
+[ "USAGE: adb_su <commands> </dev/stdin >/dev/stdout 2>/dev/stderr
Returns: true if the command running as root succeeded" ]
adb_su() {
@@ -277,30 +288,54 @@
echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode ... waiting 2 minutes"
adb_wait 2m
fi
-inAdb || die "device not in adb mode"
+inAdb || die "specified device not in adb mode"
isDebuggable || die "device not a debug build"
# Do something
echo "${GREEN}[ RUN ]${NORMAL} Testing kernel support for overlayfs" >&2
+overlayfs_supported=true;
adb_wait || die "wait for device failed"
adb_sh ls -d /sys/module/overlay </dev/null >/dev/null &&
echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 ||
- die "overlay module not present"
-adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
- echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
- die "overlay module can not be used on ANDROID"
+ (
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay module not present" >&2 &&
+ false
+ ) ||
+ overlayfs_supported=false
+if ${overlayfs_supported}; then
+ case `adb_sh uname -r </dev/null` in
+ 4.[6789].* | 4.[1-9][0-9]* | [56789].*)
+ adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
+ echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
+ (
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay module does not support override_creds" >&2 &&
+ false
+ ) ||
+ overlayfs_supported=false;
+ ;;
+ *)
+ echo "${GREEN}[ OK ]${NORMAL} overlay module uses callers creds" >&2
+ ;;
+ esac
+fi
+
adb_root ||
die "initial setup"
echo "${GREEN}[ RUN ]${NORMAL} Checking current overlayfs status" >&2
+# We can not universally use adb enable-verity to ensure device is
+# in a overlayfs disabled state since it can prevent reboot on
+# devices that remount the physical content rather than overlayfs.
+# So lets do our best to surgically wipe the overlayfs state without
+# having to go through enable-verity transition.
reboot=false
OVERLAYFS_BACKING="cache mnt/scratch"
for d in ${OVERLAYFS_BACKING}; do
if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then
- echo "${ORANGE}[ WARNING ]${NORMAL} /${d}/overlay is setup, wiping" >&2
+ echo "${ORANGE}[ WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2
adb_sh rm -rf /${d}/overlay </dev/null ||
die "/${d}/overlay wipe"
reboot=true
@@ -309,9 +344,10 @@
if ${reboot}; then
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
adb_reboot &&
- adb_wait 2m &&
- adb_root ||
- die "reboot after wipe"
+ adb_wait 2m ||
+ die "lost device after reboot after wipe"
+ adb_root ||
+ die "lost device after elevation to root after wipe"
fi
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
@@ -320,91 +356,146 @@
echo "${D}" &&
echo "${ORANGE}[ WARNING ]${NORMAL} overlays present before setup" >&2 ||
echo "${GREEN}[ OK ]${NORMAL} no overlay present before setup" >&2
-adb_sh df -k `adb_sh cat /proc/mounts |
- skip_administrative_mounts data |
- cut -s -d' ' -f1`
+overlayfs_needed=true
+D=`adb_sh cat /proc/mounts </dev/null |
+ skip_administrative_mounts data |
+ cut -s -d' ' -f1`
+D=`adb_sh df -k ${D} </dev/null`
+echo "${D}"
+if [ X"${D}" = X"${D##* 100[%] }" ]; then
+ overlayfs_needed=false
+elif ! ${overlayfs_supported}; then
+ die "need overlayfs, but do not have it"
+fi
echo "${GREEN}[ RUN ]${NORMAL} disable verity" >&2
T=`adb_date`
-D=`adb disable-verity 2>&1`
+H=`adb disable-verity 2>&1`
err=${?}
-if [ ${err} != 0 -o X"${D}" != X"${D##*setup failed}" ]; then
- echo "${D%?Now reboot your device for settings to take effect}"
- die -t ${T} "setup for overlay"
-fi
+L=
+D="${H%?Now reboot your device for settings to take effect}"
if [ X"${D}" != X"${D##*using overlayfs}" ]; then
echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
fi
-reboot=false
-if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
- echo "${GREEN}[ OK ]${NORMAL} disabled verity" >&2
- reboot=true
-else
- echo "${ORANGE}[ WARNING ]${NORMAL} verity already disabled" >&2
+if [ ${err} != 0 ]; then
+ echo "${H}"
+ ( [ -n "${L}" ] && echo "${L}" && false ) ||
+ die -t "${T}" "disable-verity"
fi
-D=`adb_sh df -k </dev/null` &&
- H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep "^overlay " | true` &&
- [ -n "${D}" ] &&
- ( echo "${H}" && echo "${D}" && true ) &&
- die -t ${T} "overlay takeover unexpected"
-L=
-if ${reboot}; then
+rebooted=false
+if [ X"${D}" != X"${H}" -a X"${D}" = X"${D##*using overlayfs}" ]; then
+ echo "${H}"
+ if [ X"${D}" != X"${D##*setup failed}" ]; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlayfs setup whined" >&2
+ fi
+ D=`adb_sh df -k </dev/null` &&
+ H=`echo "${D}" | head -1` &&
+ D=`echo "${D}" | grep "^overlay "` &&
+ [ -n "${D}" ] &&
+ ( echo "${H}" && echo "${D}" ) &&
+ die -t ${T} "overlay takeover unexpected at this phase"
+ echo "${GREEN}[ INFO ]${NORMAL} rebooting as requested" >&2
L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
adb_reboot &&
adb_wait 2m ||
- die "reboot after verity disabled failed"
- T=
+ die "lost device after reboot requested"
+ adb_root ||
+ die "lost device after elevation to root"
+ rebooted=true
+ # re-disable verity to see the setup remarks expected
+ T=`adb_date`
+ H=`adb disable-verity 2>&1`
+ err=${?}
+ D="${H%?Now reboot your device for settings to take effect}"
+ if [ X"${D}" != X"${D##*using overlayfs}" ]; then
+ echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
+ fi
+ if [ ${err} != 0 ]; then
+ T=
+ fi
+fi
+if ${overlayfs_supported} && ${overlayfs_needed} && [ X"${D}" != X"${D##*setup failed}" ]; then
+ echo "${D}"
+ ( [ -n "${L}" ] && echo "${L}" && false ) ||
+ die -t "${T}" "setup for overlay"
+fi
+if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
+ echo "${D}"
+ D=`adb_sh df -k </dev/null` &&
+ H=`echo "${D}" | head -1` &&
+ D=`echo "${D}" | grep "^overlay " | true` &&
+ [ -n "${D}" ] &&
+ ( echo "${H}" && echo "${D}" ) &&
+ ( [ -n "${L}" ] && echo "${L}" && false ) ||
+ die -t "${T}" "overlay takeover unexpected"
+ [ -n "${L}" ] && echo "${L}"
+ die -t "${T}" "unexpected report of verity being disabled a second time"
+elif ${rebooted}; then
+ echo "${GREEN}[ OK ]${NORMAL} verity already disabled" >&2
+else
+ echo "${ORANGE}[ WARNING ]${NORMAL} verity already disabled" >&2
fi
echo "${GREEN}[ RUN ]${NORMAL} remount" >&2
-adb_root &&
- adb remount ||
+adb remount ||
( [ -n "${L}" ] && echo "${L}" && false ) ||
die -t "${T}" "adb remount failed"
D=`adb_sh df -k </dev/null` &&
H=`echo "${D}" | head -1` &&
D=`echo "${D}" | grep "^overlay "` ||
- ( [ -n "${L}" ] && echo "${L}" && false ) ||
- die -t ${T} "overlay takeover failed"
-echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
- echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover not complete" >&2
-scratch_partition=scratch
-if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
- echo "${BLUE}[ INFO ]${NORMAL} using ${scratch_partition} dynamic partition for overrides" >&2
-fi
-M=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
-[ -n "${M}" ] &&
- echo "${BLUE}[ INFO ]${NORMAL} scratch filesystem ${M}"
-uses_dynamic_scratch=true
-if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then
- uses_dynamic_scratch=false
- scratch_partition="${M##*/dev/block/by-name/}"
-fi
-scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null |
- while read device kblocks used available use mounted on; do
- if [ "/mnt/scratch" = "\${mounted}" ]; then
- echo \${kblocks}
- fi
- done` &&
- [ -n "${scratch_size}" ] ||
- die "scratch size"
-echo "${BLUE}[ INFO ]${NORMAL} scratch size ${scratch_size}KB" >&2
-for d in ${OVERLAYFS_BACKING}; do
- if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
- echo "${BLUE}[ INFO ]${NORMAL} /${d}/overlay is setup" >&2
+ ( [ -n "${L}" ] && echo "${L}" && false )
+ret=${?}
+uses_dynamic_scratch=false
+scratch_partition=
+if ${overlayfs_needed}; then
+ if [ ${ret} != 0 ]; then
+ die -t ${T} "overlay takeover failed"
fi
-done
-
-echo "${H}" &&
- echo "${D}" &&
echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
- die "overlay takeover after remount"
-!(adb_sh grep "^overlay " /proc/mounts </dev/null | grep " overlay ro,") &&
- !(adb_sh grep " rw," /proc/mounts </dev/null | skip_administrative_mounts data) ||
- die "remount overlayfs missed a spot (ro)"
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover not complete" >&2
+ scratch_partition=scratch
+ if echo "${D}" | grep " /mnt/scratch" >/dev/null; then
+ echo "${BLUE}[ INFO ]${NORMAL} using ${scratch_partition} dynamic partition for overrides" >&2
+ fi
+ M=`adb_sh cat /proc/mounts </dev/null |
+ sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'`
+ [ -n "${M}" ] &&
+ echo "${BLUE}[ INFO ]${NORMAL} scratch filesystem ${M}"
+ uses_dynamic_scratch=true
+ if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then
+ uses_dynamic_scratch=false
+ scratch_partition="${M##*/dev/block/by-name/}"
+ fi
+ scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null |
+ while read device kblocks used available use mounted on; do
+ if [ "/mnt/scratch" = "\${mounted}" ]; then
+ echo \${kblocks}
+ fi
+ done` &&
+ [ -n "${scratch_size}" ] ||
+ die "scratch size"
+ echo "${BLUE}[ INFO ]${NORMAL} scratch size ${scratch_size}KB" >&2
+ for d in ${OVERLAYFS_BACKING}; do
+ if adb_sh ls -d /${d}/overlay/system/upper </dev/null >/dev/null 2>/dev/null; then
+ echo "${BLUE}[ INFO ]${NORMAL} /${d}/overlay is setup" >&2
+ fi
+ done
+
+ echo "${H}" &&
+ echo "${D}" &&
+ echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
+ die "overlay takeover after remount"
+ !(adb_sh grep "^overlay " /proc/mounts </dev/null | grep " overlay ro,") &&
+ !(adb_sh grep " rw," /proc/mounts </dev/null |
+ skip_administrative_mounts data) ||
+ die "remount overlayfs missed a spot (ro)"
+else
+ if [ ${ret} = 0 ]; then
+ die -t ${T} "unexpected overlay takeover"
+ fi
+fi
# Check something
@@ -426,17 +517,19 @@
adb_wait 2m ||
die "reboot after override content added failed"
-D=`adb_su df -k </dev/null` &&
- H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep "^overlay "` ||
- ( echo "${L}" && false ) ||
- die -d "overlay takeover failed after reboot"
+if ${overlayfs_needed}; then
+ D=`adb_su df -k </dev/null` &&
+ H=`echo "${D}" | head -1` &&
+ D=`echo "${D}" | grep "^overlay "` ||
+ ( echo "${L}" && false ) ||
+ die -d "overlay takeover failed after reboot"
-adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
- skip_administrative_mounts |
- grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
- echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
- echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
+ adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
+ skip_administrative_mounts |
+ grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
+ echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
+fi
B="`adb_cat /system/hello`" ||
die "re-read system hello after reboot"
@@ -452,63 +545,75 @@
echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears" >&2
-[ -n "${ANDROID_PRODUCT_OUT}" ] &&
- adb reboot-fastboot &&
- fastboot_wait 2m &&
- fastboot flash vendor ||
- ( fastboot reboot && false) ||
- die "fastboot flash vendor"
-fastboot_getvar partition-type:${scratch_partition} raw ||
- ( fastboot reboot && false) ||
- die "fastboot can not see ${scratch_partition} parameters"
-if ${uses_dynamic_scratch}; then
- # check ${scratch_partition} via fastboot
- fastboot_getvar has-slot:${scratch_partition} no &&
- fastboot_getvar is-logical:${scratch_partition} yes ||
- ( fastboot reboot && false) ||
- die "fastboot can not see ${scratch_partition} parameters"
+H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
+if [ -z "${ANDROID_PRODUCT_OUT}" ]; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} build tree not setup, skipping"
+elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} vendor image missing, skipping"
+elif [ "${ANDROID_PRODUCT_OUT}" = "${ANDROID_PRODUCT_OUT%*/${H}}" ]; then
+ echo "${ORANGE}[ WARNING ]${NORMAL} wrong vendor image, skipping"
else
- fastboot_getvar is-logical:${scratch_partition} no ||
+ adb reboot-fastboot &&
+ fastboot_wait 2m &&
+ fastboot flash vendor ||
( fastboot reboot && false) ||
- die "fastboot can not see ${scratch_partition} parameters"
+ die "fastboot flash vendor"
+ if [ -n "${scratch_paritition}" ]; then
+ fastboot_getvar partition-type:${scratch_partition} raw ||
+ ( fastboot reboot && false) ||
+ die "fastboot can not see ${scratch_partition} parameters"
+ if ${uses_dynamic_scratch}; then
+ # check ${scratch_partition} via fastboot
+ fastboot_getvar has-slot:${scratch_partition} no &&
+ fastboot_getvar is-logical:${scratch_partition} yes ||
+ ( fastboot reboot && false) ||
+ die "fastboot can not see ${scratch_partition} parameters"
+ else
+ fastboot_getvar is-logical:${scratch_partition} no ||
+ ( fastboot reboot && false) ||
+ die "fastboot can not see ${scratch_partition} parameters"
+ fi
+ if ! ${uses_dynamic_scratch}; then
+ fastboot reboot-bootloader ||
+ die "Reboot into fastboot"
+ fi
+ if ${uses_dynamic_scratch}; then
+ echo "${BLUE}[ INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2
+ fastboot erase ${scratch_partition} &&
+ ( fastboot reboot || true) &&
+ die "fastboot can erase ${scratch_partition}"
+ fi
+ echo "${BLUE}[ INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2
+ fastboot format ${scratch_partition} &&
+ ( fastboot reboot || true) &&
+ die "fastboot can format ${scratch_partition}"
+ fi
+ fastboot reboot ||
+ die "can not reboot out of fastboot"
+ echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
+ adb_wait 2m ||
+ die "did not reboot after flash"
+ if ${overlayfs_needed}; then
+ adb_root &&
+ D=`adb_sh df -k </dev/null` &&
+ H=`echo "${D}" | head -1` &&
+ D=`echo "${D}" | grep "^overlay "` &&
+ echo "${H}" &&
+ echo "${D}" &&
+ echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
+ die "overlay system takeover after flash vendor"
+ echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
+ die "overlay minus vendor takeover after flash vendor"
+ fi
+ B="`adb_cat /system/hello`" ||
+ die "re-read system hello after flash vendor"
+ check_eq "${A}" "${B}" system after flash vendor
+ adb_root ||
+ die "adb root"
+ B="`adb_cat /vendor/hello`" &&
+ die "re-read vendor hello after flash vendor"
+ check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
fi
-if ! ${uses_dynamic_scratch}; then
- fastboot reboot-bootloader ||
- die "Reboot into fastboot"
-fi
-if ${uses_dynamic_scratch}; then
- echo "${BLUE}[ INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2
- fastboot erase ${scratch_partition} &&
- ( fastboot reboot || true) &&
- die "fastboot can erase ${scratch_partition}"
-fi
-echo "${BLUE}[ INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2
-fastboot format ${scratch_partition} &&
- ( fastboot reboot || true) &&
- die "fastboot can format ${scratch_partition}"
-fastboot reboot ||
- die "can not reboot out of fastboot"
-echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
-adb_wait 2m ||
- die "did not reboot after flash"
-adb_root &&
- D=`adb_sh df -k </dev/null` &&
- H=`echo "${D}" | head -1` &&
- D=`echo "${D}" | grep "^overlay "` &&
- echo "${H}" &&
- echo "${D}" &&
- echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
- die "overlay system takeover after flash vendor"
-echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
- die "overlay minus vendor takeover after flash vendor"
-B="`adb_cat /system/hello`" ||
- die "re-read system hello after flash vendor"
-check_eq "${A}" "${B}" system after flash vendor
-adb_root ||
- die "adb root"
-B="`adb_cat /vendor/hello`" &&
- die "re-read vendor hello after flash vendor"
-check_eq "cat: /vendor/hello: No such file or directory" "${B}" vendor after flash vendor
echo "${GREEN}[ RUN ]${NORMAL} remove test content (cleanup)" >&2
@@ -524,32 +629,35 @@
die "re-read vendor hello after rm"
check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
-echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2
+if [ -n "${scratch_partition}" ]; then
-adb reboot-fastboot ||
- die "Reboot into fastbootd"
-dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null &&
- fastboot_wait 2m ||
- ( rm /tmp/adb-remount-test.img && false) ||
- die "reboot into fastboot"
-fastboot flash --force ${scratch_partition} /tmp/adb-remount-test.img
-err=${?}
-rm /tmp/adb-remount-test.img
-fastboot reboot ||
- die "can not reboot out of fastboot"
-[ 0 -eq ${err} ] ||
- die "fastboot flash ${scratch_partition}"
-adb_wait 2m &&
- adb_root ||
- die "did not reboot after flash"
-T=`adb_date`
-D=`adb disable-verity 2>&1`
-err=${?}
-echo "${D}"
-[ ${err} = 0 ] &&
- [ X"${D}" = X"${D##*setup failed}" ] &&
- [ X"${D}" != X"${D##*using overlayfs}" ] &&
- echo "${GREEN}[ OK ]${NORMAL} ${scratch_partition} recreated" >&2 ||
- die -t ${T} "setup for overlayfs"
+ echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2
+
+ adb reboot-fastboot ||
+ die "Reboot into fastbootd"
+ dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null &&
+ fastboot_wait 2m ||
+ ( rm /tmp/adb-remount-test.img && false) ||
+ die "reboot into fastboot"
+ fastboot flash --force ${scratch_partition} /tmp/adb-remount-test.img
+ err=${?}
+ rm /tmp/adb-remount-test.img
+ fastboot reboot ||
+ die "can not reboot out of fastboot"
+ [ 0 -eq ${err} ] ||
+ die "fastboot flash ${scratch_partition}"
+ adb_wait 2m &&
+ adb_root ||
+ die "did not reboot after flash"
+ T=`adb_date`
+ D=`adb disable-verity 2>&1`
+ err=${?}
+ echo "${D}"
+ [ ${err} = 0 ] &&
+ [ X"${D}" = X"${D##*setup failed}" ] &&
+ [ X"${D}" != X"${D##*using overlayfs}" ] &&
+ echo "${GREEN}[ OK ]${NORMAL} ${scratch_partition} recreated" >&2 ||
+ die -t ${T} "setup for overlayfs"
+fi
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2bebe76..7fd4e27 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -473,9 +473,10 @@
// Only needed if someone explicitly changes the default log level in their init.rc.
android::base::ScopedLogSeverity info(android::base::INFO);
- struct fstab* fstab = fs_mgr_read_fstab(fstabfile);
- int child_ret = fs_mgr_mount_all(fstab, mount_mode);
- fs_mgr_free_fstab(fstab);
+ Fstab fstab;
+ ReadFstabFromFile(fstabfile, &fstab);
+
+ int child_ret = fs_mgr_mount_all(&fstab, mount_mode);
if (child_ret == -1) {
PLOG(ERROR) << "fs_mgr_mount_all returned an error";
}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 6ae1123..c96c381 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -42,6 +42,7 @@
#include "uevent_listener.h"
#include "util.h"
+using android::base::Split;
using android::base::Timer;
using android::fs_mgr::AvbHandle;
using android::fs_mgr::AvbHashtreeResult;
@@ -56,7 +57,7 @@
// ------------------
class FirstStageMount {
public:
- FirstStageMount();
+ FirstStageMount(Fstab fstab);
virtual ~FirstStageMount() = default;
// The factory method to create either FirstStageMountVBootV1 or FirstStageMountVBootV2
@@ -70,7 +71,7 @@
bool InitRequiredDevices();
bool InitMappedDevice(const std::string& verity_device);
bool CreateLogicalPartitions();
- bool MountPartition(fstab_rec* fstab_rec);
+ bool MountPartition(FstabEntry* fstab_entry);
bool MountPartitions();
bool IsDmLinearEnabled();
bool GetDmLinearMetadataDevice();
@@ -80,13 +81,12 @@
// Pure virtual functions.
virtual bool GetDmVerityDevices() = 0;
- virtual bool SetUpDmVerity(fstab_rec* fstab_rec) = 0;
+ virtual bool SetUpDmVerity(FstabEntry* fstab_entry) = 0;
bool need_dm_verity_;
- std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab_;
+ Fstab fstab_;
std::string lp_metadata_partition_;
- std::vector<fstab_rec*> mount_fstab_recs_;
std::set<std::string> required_devices_partition_names_;
std::string super_partition_name_;
std::unique_ptr<DeviceHandler> device_handler_;
@@ -95,33 +95,37 @@
class FirstStageMountVBootV1 : public FirstStageMount {
public:
- FirstStageMountVBootV1() = default;
+ FirstStageMountVBootV1(Fstab fstab) : FirstStageMount(std::move(fstab)) {}
~FirstStageMountVBootV1() override = default;
protected:
bool GetDmVerityDevices() override;
- bool SetUpDmVerity(fstab_rec* fstab_rec) override;
+ bool SetUpDmVerity(FstabEntry* fstab_entry) override;
};
class FirstStageMountVBootV2 : public FirstStageMount {
public:
friend void SetInitAvbVersionInRecovery();
- FirstStageMountVBootV2();
+ FirstStageMountVBootV2(Fstab fstab);
~FirstStageMountVBootV2() override = default;
protected:
bool GetDmVerityDevices() override;
- bool SetUpDmVerity(fstab_rec* fstab_rec) override;
+ bool SetUpDmVerity(FstabEntry* fstab_entry) override;
bool InitAvbHandle();
- std::string device_tree_vbmeta_parts_;
+ std::vector<std::string> vbmeta_partitions_;
AvbUniquePtr avb_handle_;
};
// Static Functions
// ----------------
-static inline bool IsDtVbmetaCompatible() {
+static inline bool IsDtVbmetaCompatible(const Fstab& fstab) {
+ if (std::any_of(fstab.begin(), fstab.end(),
+ [](const auto& entry) { return entry.fs_mgr_flags.avb; })) {
+ return true;
+ }
return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
}
@@ -129,34 +133,26 @@
return access("/system/bin/recovery", F_OK) == 0;
}
-// Class Definitions
-// -----------------
-FirstStageMount::FirstStageMount()
- : need_dm_verity_(false),
- fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab),
- uevent_listener_(16 * 1024 * 1024) {
- // Stores fstab_->recs[] into mount_fstab_recs_ (vector<fstab_rec*>)
- // for easier manipulation later, e.g., range-base for loop.
- if (fstab_) {
- // DT Fstab predated having a first_stage_mount fs_mgr flag, so if it exists, we use it.
- for (int i = 0; i < fstab_->num_entries; i++) {
- mount_fstab_recs_.push_back(&fstab_->recs[i]);
- }
- } else {
- // Fstab found in first stage ramdisk, which should be a copy of the normal fstab.
- // Mounts intended for first stage are explicitly flagged as such.
- fstab_.reset(fs_mgr_read_fstab_default());
- if (fstab_) {
- for (int i = 0; i < fstab_->num_entries; i++) {
- if (fs_mgr_is_first_stage_mount(&fstab_->recs[i])) {
- mount_fstab_recs_.push_back(&fstab_->recs[i]);
- }
- }
+static Fstab ReadFirstStageFstab() {
+ Fstab fstab;
+ if (!ReadFstabFromDt(&fstab)) {
+ if (ReadDefaultFstab(&fstab)) {
+ fstab.erase(std::remove_if(fstab.begin(), fstab.end(),
+ [](const auto& entry) {
+ return !entry.fs_mgr_flags.first_stage_mount;
+ }),
+ fstab.end());
} else {
- LOG(INFO) << "Failed to read fstab from device tree";
+ LOG(INFO) << "Failed to fstab for first stage mount";
}
}
+ return fstab;
+}
+// Class Definitions
+// -----------------
+FirstStageMount::FirstStageMount(Fstab fstab)
+ : need_dm_verity_(false), fstab_(std::move(fstab)), uevent_listener_(16 * 1024 * 1024) {
auto boot_devices = fs_mgr_get_boot_devices();
device_handler_ = std::make_unique<DeviceHandler>(
std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
@@ -166,15 +162,16 @@
}
std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
- if (IsDtVbmetaCompatible()) {
- return std::make_unique<FirstStageMountVBootV2>();
+ auto fstab = ReadFirstStageFstab();
+ if (IsDtVbmetaCompatible(fstab)) {
+ return std::make_unique<FirstStageMountVBootV2>(std::move(fstab));
} else {
- return std::make_unique<FirstStageMountVBootV1>();
+ return std::make_unique<FirstStageMountVBootV1>(std::move(fstab));
}
}
bool FirstStageMount::DoFirstStageMount() {
- if (!IsDmLinearEnabled() && mount_fstab_recs_.empty()) {
+ if (!IsDmLinearEnabled() && fstab_.empty()) {
// Nothing to mount.
LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
return true;
@@ -194,8 +191,8 @@
}
bool FirstStageMount::IsDmLinearEnabled() {
- for (auto fstab_rec : mount_fstab_recs_) {
- if (fs_mgr_is_logical(fstab_rec)) return true;
+ for (const auto& entry : fstab_) {
+ if (entry.fs_mgr_flags.logical) return true;
}
return false;
}
@@ -381,21 +378,21 @@
return true;
}
-bool FirstStageMount::MountPartition(fstab_rec* fstab_rec) {
- if (fs_mgr_is_logical(fstab_rec)) {
- if (!fs_mgr_update_logical_partition(fstab_rec)) {
+bool FirstStageMount::MountPartition(FstabEntry* fstab_entry) {
+ if (fstab_entry->fs_mgr_flags.logical) {
+ if (!fs_mgr_update_logical_partition(fstab_entry)) {
return false;
}
- if (!InitMappedDevice(fstab_rec->blk_device)) {
+ if (!InitMappedDevice(fstab_entry->blk_device)) {
return false;
}
}
- if (!SetUpDmVerity(fstab_rec)) {
- PLOG(ERROR) << "Failed to setup verity for '" << fstab_rec->mount_point << "'";
+ if (!SetUpDmVerity(fstab_entry)) {
+ PLOG(ERROR) << "Failed to setup verity for '" << fstab_entry->mount_point << "'";
return false;
}
- if (fs_mgr_do_mount_one(fstab_rec)) {
- PLOG(ERROR) << "Failed to mount '" << fstab_rec->mount_point << "'";
+ if (fs_mgr_do_mount_one(*fstab_entry)) {
+ PLOG(ERROR) << "Failed to mount '" << fstab_entry->mount_point << "'";
return false;
}
return true;
@@ -405,28 +402,28 @@
// If system is in the fstab then we're not a system-as-root device, and in
// this case, we mount system first then pivot to it. From that point on,
// we are effectively identical to a system-as-root device.
- auto system_partition =
- std::find_if(mount_fstab_recs_.begin(), mount_fstab_recs_.end(),
- [](const auto& rec) { return rec->mount_point == "/system"s; });
+ auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
+ return entry.mount_point == "/system";
+ });
- if (system_partition != mount_fstab_recs_.end()) {
- if (!MountPartition(*system_partition)) {
+ if (system_partition != fstab_.end()) {
+ if (!MountPartition(&(*system_partition))) {
return false;
}
- SwitchRoot((*system_partition)->mount_point);
+ SwitchRoot((*system_partition).mount_point);
- mount_fstab_recs_.erase(system_partition);
+ fstab_.erase(system_partition);
}
- for (auto fstab_rec : mount_fstab_recs_) {
- if (!MountPartition(fstab_rec) && !fs_mgr_is_nofail(fstab_rec)) {
+ for (auto& fstab_entry : fstab_) {
+ if (!MountPartition(&fstab_entry) && !fstab_entry.fs_mgr_flags.no_fail) {
return false;
}
}
// heads up for instantiating required device(s) for overlayfs logic
- const auto devices = fs_mgr_overlayfs_required_devices(mount_fstab_recs_);
+ const auto devices = fs_mgr_overlayfs_required_devices(&fstab_);
for (auto const& device : devices) {
if (android::base::StartsWith(device, "/dev/block/by-name/")) {
required_devices_partition_names_.emplace(basename(device.c_str()));
@@ -438,7 +435,7 @@
}
}
- fs_mgr_overlayfs_mount_all(mount_fstab_recs_);
+ fs_mgr_overlayfs_mount_all(&fstab_);
return true;
}
@@ -447,25 +444,25 @@
std::string verity_loc_device;
need_dm_verity_ = false;
- for (auto fstab_rec : mount_fstab_recs_) {
+ for (const auto& fstab_entry : fstab_) {
// Don't allow verifyatboot in the first stage.
- if (fs_mgr_is_verifyatboot(fstab_rec)) {
+ if (fstab_entry.fs_mgr_flags.verify_at_boot) {
LOG(ERROR) << "Partitions can't be verified at boot";
return false;
}
// Checks for verified partitions.
- if (fs_mgr_is_verified(fstab_rec)) {
+ if (fstab_entry.fs_mgr_flags.verify) {
need_dm_verity_ = true;
}
// Checks if verity metadata is on a separate partition. Note that it is
// not partition specific, so there must be only one additional partition
// that carries verity state.
- if (fstab_rec->verity_loc) {
+ if (!fstab_entry.verity_loc.empty()) {
if (verity_loc_device.empty()) {
- verity_loc_device = fstab_rec->verity_loc;
- } else if (verity_loc_device != fstab_rec->verity_loc) {
+ verity_loc_device = fstab_entry.verity_loc;
+ } else if (verity_loc_device != fstab_entry.verity_loc) {
LOG(ERROR) << "More than one verity_loc found: " << verity_loc_device << ", "
- << fstab_rec->verity_loc;
+ << fstab_entry.verity_loc;
return false;
}
}
@@ -473,9 +470,9 @@
// Includes the partition names of fstab records and verity_loc_device (if any).
// Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
- for (auto fstab_rec : mount_fstab_recs_) {
- if (!fs_mgr_is_logical(fstab_rec)) {
- required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ for (const auto& fstab_entry : fstab_) {
+ if (!fstab_entry.fs_mgr_flags.logical) {
+ required_devices_partition_names_.emplace(basename(fstab_entry.blk_device.c_str()));
}
}
@@ -486,19 +483,19 @@
return true;
}
-bool FirstStageMountVBootV1::SetUpDmVerity(fstab_rec* fstab_rec) {
- if (fs_mgr_is_verified(fstab_rec)) {
- int ret = fs_mgr_setup_verity(fstab_rec, false /* wait_for_verity_dev */);
+bool FirstStageMountVBootV1::SetUpDmVerity(FstabEntry* fstab_entry) {
+ if (fstab_entry->fs_mgr_flags.verify) {
+ int ret = fs_mgr_setup_verity(fstab_entry, false /* wait_for_verity_dev */);
switch (ret) {
case FS_MGR_SETUP_VERITY_SKIPPED:
case FS_MGR_SETUP_VERITY_DISABLED:
- LOG(INFO) << "Verity disabled/skipped for '" << fstab_rec->mount_point << "'";
+ LOG(INFO) << "Verity disabled/skipped for '" << fstab_entry->mount_point << "'";
return true;
case FS_MGR_SETUP_VERITY_SUCCESS:
// The exact block device name (fstab_rec->blk_device) is changed to
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
// first stage.
- return InitMappedDevice(fstab_rec->blk_device);
+ return InitMappedDevice(fstab_entry->blk_device);
default:
return false;
}
@@ -506,22 +503,27 @@
return true; // Returns true to mount the partition.
}
-// FirstStageMountVBootV2 constructor.
-// Gets the vbmeta partitions from device tree.
-// /{
-// firmware {
-// android {
-// vbmeta {
-// compatible = "android,vbmeta";
-// parts = "vbmeta,boot,system,vendor"
-// };
-// };
-// };
-// }
-FirstStageMountVBootV2::FirstStageMountVBootV2() : avb_handle_(nullptr) {
- if (!read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts_)) {
- PLOG(ERROR) << "Failed to read vbmeta/parts from device tree";
- return;
+// First retrieve any vbmeta partitions from device tree (legacy) then read through the fstab
+// for any further vbmeta partitions.
+FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab)
+ : FirstStageMount(std::move(fstab)), avb_handle_(nullptr) {
+ std::string device_tree_vbmeta_parts;
+ read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts);
+
+ for (auto&& partition : Split(device_tree_vbmeta_parts, ",")) {
+ if (!partition.empty()) {
+ vbmeta_partitions_.emplace_back(std::move(partition));
+ }
+ }
+
+ for (const auto& entry : fstab_) {
+ if (!entry.vbmeta_partition.empty()) {
+ vbmeta_partitions_.emplace_back(entry.vbmeta_partition);
+ }
+ }
+
+ if (vbmeta_partitions_.empty()) {
+ LOG(ERROR) << "Failed to read vbmeta partitions.";
}
}
@@ -531,30 +533,27 @@
std::set<std::string> logical_partitions;
// fstab_rec->blk_device has A/B suffix.
- for (auto fstab_rec : mount_fstab_recs_) {
- if (fs_mgr_is_avb(fstab_rec)) {
+ for (const auto& fstab_entry : fstab_) {
+ if (fstab_entry.fs_mgr_flags.avb) {
need_dm_verity_ = true;
}
- if (fs_mgr_is_logical(fstab_rec)) {
+ if (fstab_entry.fs_mgr_flags.logical) {
// Don't try to find logical partitions via uevent regeneration.
- logical_partitions.emplace(basename(fstab_rec->blk_device));
+ logical_partitions.emplace(basename(fstab_entry.blk_device.c_str()));
} else {
- required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+ required_devices_partition_names_.emplace(basename(fstab_entry.blk_device.c_str()));
}
}
- // libavb verifies AVB metadata on all verified partitions at once.
- // e.g., The device_tree_vbmeta_parts_ will be "vbmeta,boot,system,vendor"
- // for libavb to verify metadata, even if there is only /vendor in the
- // above mount_fstab_recs_.
+ // Any partitions needed for verifying the partitions used in first stage mount, e.g. vbmeta
+ // must be provided as vbmeta_partitions.
if (need_dm_verity_) {
- if (device_tree_vbmeta_parts_.empty()) {
- LOG(ERROR) << "Missing vbmeta parts in device tree";
+ if (vbmeta_partitions_.empty()) {
+ LOG(ERROR) << "Missing vbmeta partitions";
return false;
}
- std::vector<std::string> partitions = android::base::Split(device_tree_vbmeta_parts_, ",");
std::string ab_suffix = fs_mgr_get_slot_suffix();
- for (const auto& partition : partitions) {
+ for (const auto& partition : vbmeta_partitions_) {
std::string partition_name = partition + ab_suffix;
if (logical_partitions.count(partition_name)) {
continue;
@@ -569,11 +568,11 @@
return true;
}
-bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
- if (fs_mgr_is_avb(fstab_rec)) {
+bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
+ if (fstab_entry->fs_mgr_flags.avb) {
if (!InitAvbHandle()) return false;
AvbHashtreeResult hashtree_result =
- avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
+ avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
switch (hashtree_result) {
case AvbHashtreeResult::kDisabled:
return true; // Returns true to mount the partition.
@@ -581,7 +580,7 @@
// The exact block device name (fstab_rec->blk_device) is changed to
// "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
// first stage.
- return InitMappedDevice(fstab_rec->blk_device);
+ return InitMappedDevice(fstab_entry->blk_device);
default:
return false;
}
@@ -627,7 +626,9 @@
return;
}
- if (!IsDtVbmetaCompatible()) {
+ auto fstab = ReadFirstStageFstab();
+
+ if (!IsDtVbmetaCompatible(fstab)) {
LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not vbmeta compatible)";
return;
}
@@ -637,7 +638,7 @@
// We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
// Open() function returns a valid handle.
// We don't need to mount partitions here in recovery mode.
- FirstStageMountVBootV2 avb_first_mount;
+ FirstStageMountVBootV2 avb_first_mount(std::move(fstab));
if (!avb_first_mount.InitDevices()) {
LOG(ERROR) << "Failed to init devices for INIT_AVB_VERSION";
return;
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index db59569..1490fbc 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -84,7 +84,7 @@
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin" },
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" },
- { 00751, AID_ROOT, AID_SHELL, 0, "system/bin" },
+ { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system/xbin" },
diff --git a/libcutils/include/cutils/partition_utils.h b/libcutils/include/cutils/partition_utils.h
index 7518559..8bc9b48 100644
--- a/libcutils/include/cutils/partition_utils.h
+++ b/libcutils/include/cutils/partition_utils.h
@@ -21,7 +21,7 @@
__BEGIN_DECLS
-int partition_wiped(char *source);
+int partition_wiped(const char* source);
__END_DECLS
diff --git a/libcutils/partition_utils.cpp b/libcutils/partition_utils.cpp
index 2211ff6..b840559 100644
--- a/libcutils/partition_utils.cpp
+++ b/libcutils/partition_utils.cpp
@@ -39,8 +39,7 @@
return ret;
}
-int partition_wiped(char *source)
-{
+int partition_wiped(const char* source) {
uint8_t buf[4096];
int fd, ret;
@@ -67,4 +66,3 @@
return 0;
}
-
diff --git a/libmeminfo/include/meminfo/sysmeminfo.h b/libmeminfo/include/meminfo/sysmeminfo.h
index 885be1d..f18ae08 100644
--- a/libmeminfo/include/meminfo/sysmeminfo.h
+++ b/libmeminfo/include/meminfo/sysmeminfo.h
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <functional>
#include <map>
#include <string>
#include <vector>
@@ -51,6 +52,9 @@
bool ReadMemInfo(const std::string& path = "/proc/meminfo");
bool ReadMemInfo(const std::vector<std::string>& tags,
const std::string& path = "/proc/meminfo");
+ bool ReadMemInfo(const std::vector<std::string>& tags, std::vector<uint64_t>* out,
+ const std::string& path = "/proc/meminfo");
+ bool ReadMemInfo(std::vector<uint64_t>* out, const std::string& path = "/proc/meminfo");
// getters
uint64_t mem_total_kb() { return mem_in_kb_[kMemTotal]; }
@@ -59,19 +63,21 @@
uint64_t mem_cached_kb() { return mem_in_kb_[kMemCached]; }
uint64_t mem_shmem_kb() { return mem_in_kb_[kMemShmem]; }
uint64_t mem_slab_kb() { return mem_in_kb_[kMemSlab]; }
- uint64_t mem_slab_reclailmable_kb() { return mem_in_kb_[kMemSReclaim]; }
+ uint64_t mem_slab_reclaimable_kb() { return mem_in_kb_[kMemSReclaim]; }
uint64_t mem_slab_unreclaimable_kb() { return mem_in_kb_[kMemSUnreclaim]; }
uint64_t mem_swap_kb() { return mem_in_kb_[kMemSwapTotal]; }
uint64_t mem_swap_free_kb() { return mem_in_kb_[kMemSwapFree]; }
uint64_t mem_mapped_kb() { return mem_in_kb_[kMemMapped]; }
uint64_t mem_vmalloc_used_kb() { return mem_in_kb_[kMemVmallocUsed]; }
uint64_t mem_page_tables_kb() { return mem_in_kb_[kMemPageTables]; }
- uint64_t mem_kernel_stack_kb() { return mem_in_kb_[kMemPageTables]; }
+ uint64_t mem_kernel_stack_kb() { return mem_in_kb_[kMemKernelStack]; }
uint64_t mem_zram_kb(const std::string& zram_dev = "");
private:
std::map<std::string, uint64_t> mem_in_kb_;
bool MemZramDevice(const std::string& zram_dev, uint64_t* mem_zram_dev);
+ bool ReadMemInfo(const std::vector<std::string>& tags, const std::string& path,
+ std::function<void(const std::string&, uint64_t)> store_val);
};
} // namespace meminfo
diff --git a/libmeminfo/libmeminfo_benchmark.cpp b/libmeminfo/libmeminfo_benchmark.cpp
index 1db0824..2660a4d 100644
--- a/libmeminfo/libmeminfo_benchmark.cpp
+++ b/libmeminfo/libmeminfo_benchmark.cpp
@@ -29,6 +29,8 @@
#include <benchmark/benchmark.h>
+using ::android::meminfo::SysMemInfo;
+
enum {
MEMINFO_TOTAL,
MEMINFO_FREE,
@@ -71,8 +73,7 @@
static const char* const tags[] = {
"MemTotal:", "MemFree:", "Buffers:", "Cached:", "Shmem:", "Slab:",
"SReclaimable:", "SUnreclaim:", "SwapTotal:", "SwapFree:", "ZRam:", "Mapped:",
- "VmallocUsed:", "PageTables:", "KernelStack:", NULL
- };
+ "VmallocUsed:", "PageTables:", "KernelStack:", NULL};
static const int tagsLen[] = {9, 8, 8, 7, 6, 5, 13, 11, 10, 9, 5, 7, 12, 11, 12, 0};
@@ -105,7 +106,7 @@
}
}
-static void BM_ParseSysMemInfo(benchmark::State& state) {
+static void BM_ReadMemInfo_old(benchmark::State& state) {
std::string meminfo = R"meminfo(MemTotal: 3019740 kB
MemFree: 1809728 kB
MemAvailable: 2546560 kB
@@ -159,9 +160,9 @@
get_mem_info(mem, tf.path);
}
}
-BENCHMARK(BM_ParseSysMemInfo);
+BENCHMARK(BM_ReadMemInfo_old);
-static void BM_ReadMemInfo(benchmark::State& state) {
+static void BM_ReadMemInfo_new(benchmark::State& state) {
std::string meminfo = R"meminfo(MemTotal: 3019740 kB
MemFree: 1809728 kB
MemAvailable: 2546560 kB
@@ -211,12 +212,21 @@
android::base::WriteStringToFd(meminfo, tf.fd);
std::string file = std::string(tf.path);
- ::android::meminfo::SysMemInfo mi;
+ std::vector<uint64_t> mem(MEMINFO_COUNT);
+ const std::vector<std::string> tags = {
+ SysMemInfo::kMemTotal, SysMemInfo::kMemFree, SysMemInfo::kMemBuffers,
+ SysMemInfo::kMemCached, SysMemInfo::kMemShmem, SysMemInfo::kMemSlab,
+ SysMemInfo::kMemSReclaim, SysMemInfo::kMemSUnreclaim, SysMemInfo::kMemSwapTotal,
+ SysMemInfo::kMemSwapFree, SysMemInfo::kMemMapped, SysMemInfo::kMemVmallocUsed,
+ SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack,
+ };
+
+ SysMemInfo smi;
for (auto _ : state) {
- mi.ReadMemInfo(file);
+ smi.ReadMemInfo(tags, &mem, file);
}
}
-BENCHMARK(BM_ReadMemInfo);
+BENCHMARK(BM_ReadMemInfo_new);
static uint64_t get_zram_mem_used(const std::string& zram_dir) {
FILE* f = fopen((zram_dir + "mm_stat").c_str(), "r");
@@ -246,23 +256,145 @@
return 0;
}
-static void BM_OldReadZramTotal(benchmark::State& state) {
+static void BM_ZramTotal_old(benchmark::State& state) {
std::string exec_dir = ::android::base::GetExecutableDirectory();
std::string zram_mmstat_dir = exec_dir + "/testdata1/";
for (auto _ : state) {
uint64_t zram_total __attribute__((unused)) = get_zram_mem_used(zram_mmstat_dir) / 1024;
}
}
-BENCHMARK(BM_OldReadZramTotal);
+BENCHMARK(BM_ZramTotal_old);
-static void BM_NewReadZramTotal(benchmark::State& state) {
+static void BM_ZramTotal_new(benchmark::State& state) {
std::string exec_dir = ::android::base::GetExecutableDirectory();
std::string zram_mmstat_dir = exec_dir + "/testdata1/";
- ::android::meminfo::SysMemInfo mi;
+ SysMemInfo smi;
for (auto _ : state) {
- uint64_t zram_total __attribute__((unused)) = mi.mem_zram_kb(zram_mmstat_dir);
+ uint64_t zram_total __attribute__((unused)) = smi.mem_zram_kb(zram_mmstat_dir);
}
}
-BENCHMARK(BM_NewReadZramTotal);
+BENCHMARK(BM_ZramTotal_new);
+
+static void BM_MemInfoWithZram_old(benchmark::State& state) {
+ std::string meminfo = R"meminfo(MemTotal: 3019740 kB
+MemFree: 1809728 kB
+MemAvailable: 2546560 kB
+Buffers: 54736 kB
+Cached: 776052 kB
+SwapCached: 0 kB
+Active: 445856 kB
+Inactive: 459092 kB
+Active(anon): 78492 kB
+Inactive(anon): 2240 kB
+Active(file): 367364 kB
+Inactive(file): 456852 kB
+Unevictable: 3096 kB
+Mlocked: 3096 kB
+SwapTotal: 0 kB
+SwapFree: 0 kB
+Dirty: 32 kB
+Writeback: 0 kB
+AnonPages: 74988 kB
+Mapped: 62624 kB
+Shmem: 4020 kB
+Slab: 86464 kB
+SReclaimable: 44432 kB
+SUnreclaim: 42032 kB
+KernelStack: 4880 kB
+PageTables: 2900 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 1509868 kB
+Committed_AS: 80296 kB
+VmallocTotal: 263061440 kB
+VmallocUsed: 0 kB
+VmallocChunk: 0 kB
+AnonHugePages: 6144 kB
+ShmemHugePages: 0 kB
+ShmemPmdMapped: 0 kB
+CmaTotal: 131072 kB
+CmaFree: 130380 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB)meminfo";
+
+ TemporaryFile tf;
+ ::android::base::WriteStringToFd(meminfo, tf.fd);
+ std::string exec_dir = ::android::base::GetExecutableDirectory();
+ std::string zram_mmstat_dir = exec_dir + "/testdata1/";
+ uint64_t mem[MEMINFO_COUNT];
+ for (auto _ : state) {
+ get_mem_info(mem, tf.path);
+ mem[MEMINFO_ZRAM_TOTAL] = get_zram_mem_used("/sys/block/zram0/") / 1024;
+ CHECK_EQ(mem[MEMINFO_KERNEL_STACK], 4880u);
+ }
+}
+BENCHMARK(BM_MemInfoWithZram_old);
+
+static void BM_MemInfoWithZram_new(benchmark::State& state) {
+ std::string meminfo = R"meminfo(MemTotal: 3019740 kB
+MemFree: 1809728 kB
+MemAvailable: 2546560 kB
+Buffers: 54736 kB
+Cached: 776052 kB
+SwapCached: 0 kB
+Active: 445856 kB
+Inactive: 459092 kB
+Active(anon): 78492 kB
+Inactive(anon): 2240 kB
+Active(file): 367364 kB
+Inactive(file): 456852 kB
+Unevictable: 3096 kB
+Mlocked: 3096 kB
+SwapTotal: 0 kB
+SwapFree: 0 kB
+Dirty: 32 kB
+Writeback: 0 kB
+AnonPages: 74988 kB
+Mapped: 62624 kB
+Shmem: 4020 kB
+Slab: 86464 kB
+SReclaimable: 44432 kB
+SUnreclaim: 42032 kB
+KernelStack: 4880 kB
+PageTables: 2900 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 1509868 kB
+Committed_AS: 80296 kB
+VmallocTotal: 263061440 kB
+VmallocUsed: 0 kB
+VmallocChunk: 0 kB
+AnonHugePages: 6144 kB
+ShmemHugePages: 0 kB
+ShmemPmdMapped: 0 kB
+CmaTotal: 131072 kB
+CmaFree: 130380 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB)meminfo";
+
+ TemporaryFile tf;
+ android::base::WriteStringToFd(meminfo, tf.fd);
+
+ std::string file = std::string(tf.path);
+ std::vector<uint64_t> mem(MEMINFO_COUNT);
+ std::vector<std::string> tags(SysMemInfo::kDefaultSysMemInfoTags);
+ auto it = tags.begin();
+ tags.insert(it + MEMINFO_ZRAM_TOTAL, "Zram:");
+ SysMemInfo smi;
+
+ for (auto _ : state) {
+ smi.ReadMemInfo(tags, &mem, file);
+ CHECK_EQ(mem[MEMINFO_KERNEL_STACK], 4880u);
+ }
+}
+BENCHMARK(BM_MemInfoWithZram_new);
BENCHMARK_MAIN();
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index b7a4b6b..2856c2d 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -347,8 +347,8 @@
Inactive(file): 456852 kB
Unevictable: 3096 kB
Mlocked: 3096 kB
-SwapTotal: 0 kB
-SwapFree: 0 kB
+SwapTotal: 32768 kB
+SwapFree: 4096 kB
Dirty: 32 kB
Writeback: 0 kB
AnonPages: 74988 kB
@@ -365,7 +365,7 @@
CommitLimit: 1509868 kB
Committed_AS: 80296 kB
VmallocTotal: 263061440 kB
-VmallocUsed: 0 kB
+VmallocUsed: 65536 kB
VmallocChunk: 0 kB
AnonHugePages: 6144 kB
ShmemHugePages: 0 kB
@@ -385,7 +385,19 @@
SysMemInfo mi;
ASSERT_TRUE(mi.ReadMemInfo(tf.path));
EXPECT_EQ(mi.mem_total_kb(), 3019740);
+ EXPECT_EQ(mi.mem_free_kb(), 1809728);
+ EXPECT_EQ(mi.mem_buffers_kb(), 54736);
+ EXPECT_EQ(mi.mem_cached_kb(), 776052);
+ EXPECT_EQ(mi.mem_shmem_kb(), 4020);
+ EXPECT_EQ(mi.mem_slab_kb(), 86464);
+ EXPECT_EQ(mi.mem_slab_reclaimable_kb(), 44432);
+ EXPECT_EQ(mi.mem_slab_unreclaimable_kb(), 42032);
+ EXPECT_EQ(mi.mem_swap_kb(), 32768);
+ EXPECT_EQ(mi.mem_swap_free_kb(), 4096);
+ EXPECT_EQ(mi.mem_mapped_kb(), 62624);
+ EXPECT_EQ(mi.mem_vmalloc_used_kb(), 65536);
EXPECT_EQ(mi.mem_page_tables_kb(), 2900);
+ EXPECT_EQ(mi.mem_kernel_stack_kb(), 4880);
}
TEST(SysMemInfoParser, TestEmptyFile) {
@@ -399,7 +411,7 @@
EXPECT_EQ(mi.mem_total_kb(), 0);
}
-TEST(SysMemInfoParse, TestZramTotal) {
+TEST(SysMemInfoParser, TestZramTotal) {
std::string exec_dir = ::android::base::GetExecutableDirectory();
SysMemInfo mi;
@@ -410,6 +422,100 @@
EXPECT_EQ(mi.mem_zram_kb(zram_memused_dir), 30504);
}
+enum {
+ MEMINFO_TOTAL,
+ MEMINFO_FREE,
+ MEMINFO_BUFFERS,
+ MEMINFO_CACHED,
+ MEMINFO_SHMEM,
+ MEMINFO_SLAB,
+ MEMINFO_SLAB_RECLAIMABLE,
+ MEMINFO_SLAB_UNRECLAIMABLE,
+ MEMINFO_SWAP_TOTAL,
+ MEMINFO_SWAP_FREE,
+ MEMINFO_ZRAM_TOTAL,
+ MEMINFO_MAPPED,
+ MEMINFO_VMALLOC_USED,
+ MEMINFO_PAGE_TABLES,
+ MEMINFO_KERNEL_STACK,
+ MEMINFO_COUNT
+};
+
+TEST(SysMemInfoParser, TestZramWithTags) {
+ std::string meminfo = R"meminfo(MemTotal: 3019740 kB
+MemFree: 1809728 kB
+MemAvailable: 2546560 kB
+Buffers: 54736 kB
+Cached: 776052 kB
+SwapCached: 0 kB
+Active: 445856 kB
+Inactive: 459092 kB
+Active(anon): 78492 kB
+Inactive(anon): 2240 kB
+Active(file): 367364 kB
+Inactive(file): 456852 kB
+Unevictable: 3096 kB
+Mlocked: 3096 kB
+SwapTotal: 32768 kB
+SwapFree: 4096 kB
+Dirty: 32 kB
+Writeback: 0 kB
+AnonPages: 74988 kB
+Mapped: 62624 kB
+Shmem: 4020 kB
+Slab: 86464 kB
+SReclaimable: 44432 kB
+SUnreclaim: 42032 kB
+KernelStack: 4880 kB
+PageTables: 2900 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
+CommitLimit: 1509868 kB
+Committed_AS: 80296 kB
+VmallocTotal: 263061440 kB
+VmallocUsed: 65536 kB
+VmallocChunk: 0 kB
+AnonHugePages: 6144 kB
+ShmemHugePages: 0 kB
+ShmemPmdMapped: 0 kB
+CmaTotal: 131072 kB
+CmaFree: 130380 kB
+HugePages_Total: 0
+HugePages_Free: 0
+HugePages_Rsvd: 0
+HugePages_Surp: 0
+Hugepagesize: 2048 kB)meminfo";
+
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ ASSERT_TRUE(::android::base::WriteStringToFd(meminfo, tf.fd));
+ std::string file = std::string(tf.path);
+ std::vector<uint64_t> mem(MEMINFO_COUNT);
+ std::vector<std::string> tags(SysMemInfo::kDefaultSysMemInfoTags);
+ auto it = tags.begin();
+ tags.insert(it + MEMINFO_ZRAM_TOTAL, "Zram:");
+ SysMemInfo mi;
+
+ // Read system memory info
+ EXPECT_TRUE(mi.ReadMemInfo(tags, &mem, file));
+
+ EXPECT_EQ(mem[MEMINFO_TOTAL], 3019740);
+ EXPECT_EQ(mem[MEMINFO_FREE], 1809728);
+ EXPECT_EQ(mem[MEMINFO_BUFFERS], 54736);
+ EXPECT_EQ(mem[MEMINFO_CACHED], 776052);
+ EXPECT_EQ(mem[MEMINFO_SHMEM], 4020);
+ EXPECT_EQ(mem[MEMINFO_SLAB], 86464);
+ EXPECT_EQ(mem[MEMINFO_SLAB_RECLAIMABLE], 44432);
+ EXPECT_EQ(mem[MEMINFO_SLAB_UNRECLAIMABLE], 42032);
+ EXPECT_EQ(mem[MEMINFO_SWAP_TOTAL], 32768);
+ EXPECT_EQ(mem[MEMINFO_SWAP_FREE], 4096);
+ EXPECT_EQ(mem[MEMINFO_MAPPED], 62624);
+ EXPECT_EQ(mem[MEMINFO_VMALLOC_USED], 65536);
+ EXPECT_EQ(mem[MEMINFO_PAGE_TABLES], 2900);
+ EXPECT_EQ(mem[MEMINFO_KERNEL_STACK], 4880);
+}
+
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
if (argc <= 1) {
diff --git a/libmeminfo/sysmeminfo.cpp b/libmeminfo/sysmeminfo.cpp
index 7e56238..4ec1c99 100644
--- a/libmeminfo/sysmeminfo.cpp
+++ b/libmeminfo/sysmeminfo.cpp
@@ -18,12 +18,15 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+#include <algorithm>
#include <cctype>
#include <cstdio>
#include <fstream>
+#include <iterator>
#include <string>
#include <utility>
#include <vector>
@@ -49,7 +52,29 @@
};
bool SysMemInfo::ReadMemInfo(const std::string& path) {
- return ReadMemInfo(SysMemInfo::kDefaultSysMemInfoTags, path);
+ return ReadMemInfo(SysMemInfo::kDefaultSysMemInfoTags, path,
+ [&](const std::string& tag, uint64_t val) { mem_in_kb_[tag] = val; });
+}
+
+bool SysMemInfo::ReadMemInfo(std::vector<uint64_t>* out, const std::string& path) {
+ return ReadMemInfo(SysMemInfo::kDefaultSysMemInfoTags, out, path);
+}
+
+bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, std::vector<uint64_t>* out,
+ const std::string& path) {
+ out->clear();
+ out->resize(tags.size());
+
+ return ReadMemInfo(tags, path, [&]([[maybe_unused]] const std::string& tag, uint64_t val) {
+ auto it = std::find(tags.begin(), tags.end(), tag);
+ if (it == tags.end()) {
+ LOG(ERROR) << "Tried to store invalid tag: " << tag;
+ return;
+ }
+ auto index = std::distance(tags.begin(), it);
+ // store the values in the same order as the tags
+ out->at(index) = val;
+ });
}
// TODO: Delete this function if it can't match up with the c-like implementation below.
@@ -88,7 +113,8 @@
}
#else
-bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, const std::string& path) {
+bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, const std::string& path,
+ std::function<void(const std::string&, uint64_t)> store_val) {
char buffer[4096];
int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
if (fd < 0) {
@@ -106,22 +132,34 @@
char* p = buffer;
uint32_t found = 0;
uint32_t lineno = 0;
+ bool zram_tag_found = false;
while (*p && found < tags.size()) {
for (auto& tag : tags) {
+ // Special case for "Zram:" tag that android_os_Debug and friends look
+ // up along with the rest of the numbers from /proc/meminfo
+ if (!zram_tag_found && tag == "Zram:") {
+ store_val(tag, mem_zram_kb());
+ zram_tag_found = true;
+ found++;
+ continue;
+ }
+
if (strncmp(p, tag.c_str(), tag.size()) == 0) {
p += tag.size();
while (*p == ' ') p++;
char* endptr = nullptr;
- mem_in_kb_[tag] = strtoull(p, &endptr, 10);
+ uint64_t val = strtoull(p, &endptr, 10);
if (p == endptr) {
PLOG(ERROR) << "Failed to parse line:" << lineno + 1 << " in file: " << path;
return false;
}
+ store_val(tag, val);
p = endptr;
found++;
break;
}
}
+
while (*p && *p != '\n') {
p++;
}
@@ -163,24 +201,19 @@
}
bool SysMemInfo::MemZramDevice(const std::string& zram_dev, uint64_t* mem_zram_dev) {
- std::string content;
- if (android::base::ReadFileToString(zram_dev + "mm_stat", &content)) {
- std::vector<std::string> values = ::android::base::Split(content, " ");
- if (values.size() < 3) {
- LOG(ERROR) << "Malformed mm_stat file for zram dev: " << zram_dev
- << " content: " << content;
+ std::string mmstat = ::android::base::StringPrintf("%s/%s", zram_dev.c_str(), "mm_stat");
+ auto mmstat_fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(mmstat.c_str(), "re"), fclose};
+ if (mmstat_fp != nullptr) {
+ // only if we do have mmstat, use it. Otherwise, fall through to trying out the old
+ // 'mem_used_total'
+ if (fscanf(mmstat_fp.get(), "%*" SCNu64 " %*" SCNu64 " %" SCNu64, mem_zram_dev) != 1) {
+ PLOG(ERROR) << "Malformed mm_stat file in: " << zram_dev;
return false;
}
-
- if (!::android::base::ParseUint(values[2], mem_zram_dev)) {
- LOG(ERROR) << "Malformed mm_stat file for zram dev: " << zram_dev
- << " value: " << values[2];
- return false;
- }
-
return true;
}
+ std::string content;
if (::android::base::ReadFileToString(zram_dev + "mem_used_total", &content)) {
*mem_zram_dev = strtoull(content.c_str(), NULL, 10);
if (*mem_zram_dev == ULLONG_MAX) {
diff --git a/libmeminfo/testdata1/mm_stat b/libmeminfo/testdata1/mm_stat
index 684f567..32b325f 100644
--- a/libmeminfo/testdata1/mm_stat
+++ b/libmeminfo/testdata1/mm_stat
@@ -1 +1 @@
-145674240 26801454 31236096 0 45772800 3042 1887 517
+ 145674240 26801454 31236096 0 45772800 3042 1887 517
diff --git a/libmetricslogger/include/metricslogger/metrics_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
index 56bd6c4..71c04a6 100644
--- a/libmetricslogger/include/metricslogger/metrics_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -116,7 +116,7 @@
FIELD_BATTERY_RESISTANCE_UOHMS = 1448,
FIELD_BATTERY_CURRENT_UA = 1449,
FIELD_HARDWARE_LOCATION = 1450,
- ACTION_BATTERY_CAUSED_SHUTDOWN = 1441,
+ ACTION_BATTERY_CAUSED_SHUTDOWN = 1451,
};
enum {
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
index 8516640..32691a3 100644
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ b/libpixelflinger/codeflinger/CodeCache.cpp
@@ -61,7 +61,11 @@
#define USAGE_ERROR_ACTION(m,p) \
heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wexpansion-to-defined"
+#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
#include "../../../../external/dlmalloc/malloc.c"
+#pragma GCC diagnostic pop
static void heap_error(const char* msg, const char* function, void* p) {
ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
diff --git a/libsparse/output_file.cpp b/libsparse/output_file.cpp
index fe314b3..5b8179f 100644
--- a/libsparse/output_file.cpp
+++ b/libsparse/output_file.cpp
@@ -508,7 +508,7 @@
out->len = len;
out->block_size = block_size;
- out->cur_out_ptr = 0ll;
+ out->cur_out_ptr = 0LL;
out->chunk_cnt = 0;
out->crc32 = 0;
out->use_crc = crc;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index a5e0dc9..89d4fc0 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -94,7 +94,10 @@
"DexFile.cpp",
"DexFiles.cpp",
],
- exclude_shared_libs: ["libdexfile"],
+ exclude_shared_libs: [
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
},
recovery: {
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
@@ -102,7 +105,10 @@
"DexFile.cpp",
"DexFiles.cpp",
],
- exclude_shared_libs: ["libdexfile"],
+ exclude_shared_libs: [
+ "libdexfile_external",
+ "libdexfile_support",
+ ],
},
},
@@ -127,7 +133,8 @@
shared_libs: [
"libbase",
- "libdexfile",
+ "libdexfile_external",
+ "libdexfile_support",
"liblog",
"liblzma",
],
@@ -215,6 +222,7 @@
"liblzma",
"libunwindstack",
"libdexfile",
+ "libdexfile_support",
],
static_libs: [
@@ -235,6 +243,8 @@
"tests/files/offline/jit_map_arm/*",
"tests/files/offline/gnu_debugdata_arm/*",
"tests/files/offline/offset_arm/*",
+ "tests/files/offline/shared_lib_in_apk_arm64/*",
+ "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
"tests/files/offline/straddle_arm/*",
"tests/files/offline/straddle_arm64/*",
],
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index 8ec560c..9b0b232 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -23,13 +23,7 @@
#include <memory>
#include <android-base/unique_fd.h>
-
-#include <dex/class_accessor-inl.h>
-#include <dex/code_item_accessors-inl.h>
-#include <dex/compact_dex_file.h>
-#include <dex/dex_file-inl.h>
-#include <dex/dex_file_loader.h>
-#include <dex/standard_dex_file.h>
+#include <art_api/ext_dex_file.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
@@ -38,169 +32,71 @@
namespace unwindstack {
-DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) {
+std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
+ MapInfo* info) {
if (!info->name.empty()) {
- std::unique_ptr<DexFileFromFile> dex_file(new DexFileFromFile);
- if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) {
- return dex_file.release();
+ std::unique_ptr<DexFile> dex_file =
+ DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
+ if (dex_file) {
+ return dex_file;
}
}
-
- std::unique_ptr<DexFileFromMemory> dex_file(new DexFileFromMemory);
- if (dex_file->Open(dex_file_offset_in_memory, memory)) {
- return dex_file.release();
- }
- return nullptr;
-}
-
-DexFileFromFile::~DexFileFromFile() {
- if (size_ != 0) {
- munmap(mapped_memory_, size_);
- }
+ return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
}
bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
uint64_t* method_offset) {
- if (dex_file_ == nullptr) {
+ art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset);
+ if (method_info.offset == 0) {
return false;
}
-
- if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) {
- return false; // The DEX offset is not within the bytecode of this dex file.
- }
-
- if (dex_file_->IsCompactDexFile()) {
- // The data section of compact dex files might be shared.
- // Check the subrange unique to this compact dex.
- const auto& cdex_header = dex_file_->AsCompactDexFile()->GetHeader();
- uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin();
- uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd();
- if (dex_offset < begin || dex_offset >= end) {
- return false; // The DEX offset is not within the bytecode of this dex file.
- }
- }
-
- // The method data is cached in a std::map indexed by method end offset and
- // contains the start offset and the method member index.
- // Only cache the method data as it is searched. Do not read the entire
- // set of method data into the cache at once.
- // This is done because many unwinds only find a single frame with dex file
- // info, so reading the entire method data is wasteful. However, still cache
- // the data so that anything doing multiple unwinds will have this data
- // cached for future use.
-
- // First look in the method cache.
- auto entry = method_cache_.upper_bound(dex_offset);
- if (entry != method_cache_.end() && dex_offset >= entry->second.first) {
- *method_name = dex_file_->PrettyMethod(entry->second.second, false);
- *method_offset = dex_offset - entry->second.first;
- return true;
- }
-
- // Check the methods we haven't cached.
- for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) {
- art::ClassAccessor accessor(*dex_file_, dex_file_->GetClassDef(class_def_index_));
-
- for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
- art::CodeItemInstructionAccessor code = method.GetInstructions();
- if (!code.HasCodeItem()) {
- continue;
- }
- uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
- uint32_t offset_end = offset + code.InsnsSizeInBytes();
- uint32_t member_index = method.GetIndex();
- method_cache_[offset_end] = std::make_pair(offset, member_index);
- if (offset <= dex_offset && dex_offset < offset_end) {
- *method_name = dex_file_->PrettyMethod(member_index, false);
- *method_offset = dex_offset - offset;
- return true;
- }
- }
- }
- return false;
+ *method_name = method_info.name;
+ *method_offset = dex_offset - method_info.offset;
+ return true;
}
-bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
+std::unique_ptr<DexFileFromFile> DexFileFromFile::Create(uint64_t dex_file_offset_in_file,
+ const std::string& file) {
android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
if (fd == -1) {
- return false;
- }
- struct stat buf;
- if (fstat(fd, &buf) == -1) {
- return false;
- }
- uint64_t length;
- if (buf.st_size < 0 ||
- __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) ||
- static_cast<uint64_t>(buf.st_size) < length) {
- return false;
+ return nullptr;
}
- mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
- if (mapped_memory_ == MAP_FAILED) {
- return false;
- }
- size_ = buf.st_size;
-
- uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_);
-
- art::DexFile::Header* header =
- reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]);
- if (!art::StandardDexFile::IsMagicValid(header->magic_) &&
- !art::CompactDexFile::IsMagicValid(header->magic_)) {
- return false;
- }
-
- if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) ||
- static_cast<uint64_t>(buf.st_size) < length) {
- return false;
- }
-
- art::DexFileLoader loader;
std::string error_msg;
- auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr,
- false, false, &error_msg);
- dex_file_.reset(dex.release());
- return dex_file_ != nullptr;
+ std::unique_ptr<art_api::dex::DexFile> art_dex_file =
+ OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg);
+ if (art_dex_file == nullptr) {
+ return nullptr;
+ }
+
+ return std::unique_ptr<DexFileFromFile>(new DexFileFromFile(std::move(*art_dex_file.release())));
}
-bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
- memory_.resize(sizeof(art::DexFile::Header));
- if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
- return false;
- }
+std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
+ Memory* memory,
+ const std::string& name) {
+ std::vector<uint8_t> backing_memory;
- art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
- uint32_t file_size = header->file_size_;
- if (art::CompactDexFile::IsMagicValid(header->magic_)) {
- // Compact dex file store data section separately so that it can be shared.
- // Therefore we need to extend the read memory range to include it.
- // TODO: This might be wasteful as we might read data in between as well.
- // In practice, this should be fine, as such sharing only happens on disk.
- uint32_t computed_file_size;
- if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
- return false;
+ for (size_t size = 0;;) {
+ std::string error_msg;
+ std::unique_ptr<art_api::dex::DexFile> art_dex_file =
+ OpenFromMemory(backing_memory.data(), &size, name, &error_msg);
+
+ if (art_dex_file != nullptr) {
+ return std::unique_ptr<DexFileFromMemory>(
+ new DexFileFromMemory(std::move(*art_dex_file.release()), std::move(backing_memory)));
}
- if (computed_file_size > file_size) {
- file_size = computed_file_size;
+
+ if (!error_msg.empty()) {
+ return nullptr;
}
- } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
- return false;
+
+ backing_memory.resize(size);
+ if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(),
+ backing_memory.size())) {
+ return nullptr;
+ }
}
-
- memory_.resize(file_size);
- if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
- return false;
- }
-
- header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
-
- art::DexFileLoader loader;
- std::string error_msg;
- auto dex =
- loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg);
- dex_file_.reset(dex.release());
- return dex_file_ != nullptr;
}
} // namespace unwindstack
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index c123158..5797dee 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -25,48 +25,41 @@
#include <utility>
#include <vector>
-#include <dex/dex_file-inl.h>
+#include <art_api/ext_dex_file.h>
namespace unwindstack {
-class DexFile {
+class DexFile : protected art_api::dex::DexFile {
public:
- DexFile() = default;
virtual ~DexFile() = default;
bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
- static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
+ static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory,
+ MapInfo* info);
protected:
- void Init();
-
- std::unique_ptr<const art::DexFile> dex_file_;
- std::map<uint32_t, std::pair<uint64_t, uint32_t>> method_cache_; // dex offset to method index.
-
- uint32_t class_def_index_ = 0;
+ DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {}
};
class DexFileFromFile : public DexFile {
public:
- DexFileFromFile() = default;
- virtual ~DexFileFromFile();
-
- bool Open(uint64_t dex_file_offset_in_file, const std::string& name);
+ static std::unique_ptr<DexFileFromFile> Create(uint64_t dex_file_offset_in_file,
+ const std::string& file);
private:
- void* mapped_memory_ = nullptr;
- size_t size_ = 0;
+ DexFileFromFile(art_api::dex::DexFile&& art_dex_file) : DexFile(std::move(art_dex_file)) {}
};
class DexFileFromMemory : public DexFile {
public:
- DexFileFromMemory() = default;
- virtual ~DexFileFromMemory() = default;
-
- bool Open(uint64_t dex_file_offset_in_memory, Memory* memory);
+ static std::unique_ptr<DexFileFromMemory> Create(uint64_t dex_file_offset_in_memory,
+ Memory* memory, const std::string& name);
private:
+ DexFileFromMemory(art_api::dex::DexFile&& art_dex_file, std::vector<uint8_t>&& memory)
+ : DexFile(std::move(art_dex_file)), memory_(std::move(memory)) {}
+
std::vector<uint8_t> memory_;
};
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index 451a0b9..63a77e5 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -48,11 +48,7 @@
DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
: Global(memory, search_libs) {}
-DexFiles::~DexFiles() {
- for (auto& entry : files_) {
- delete entry.second;
- }
-}
+DexFiles::~DexFiles() {}
void DexFiles::ProcessArch() {
switch (arch()) {
@@ -137,10 +133,11 @@
DexFile* dex_file;
auto entry = files_.find(dex_file_offset);
if (entry == files_.end()) {
- dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
- files_[dex_file_offset] = dex_file;
+ std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+ dex_file = new_dex_file.get();
+ files_[dex_file_offset] = std::move(new_dex_file);
} else {
- dex_file = entry->second;
+ dex_file = entry->second.get();
}
return dex_file;
}
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
index 0fa1638..4ba8a4b 100644
--- a/libunwindstack/DwarfCfa.cpp
+++ b/libunwindstack/DwarfCfa.cpp
@@ -260,7 +260,7 @@
}
// Log any of the expression data.
- for (const auto line : expression_lines) {
+ for (const auto& line : expression_lines) {
log(indent + 1, "%s", line.c_str());
}
return true;
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index e3b48ca..44ec5c1 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -29,6 +29,38 @@
namespace unwindstack {
+bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
+ // One last attempt, see if the previous map is read-only with the
+ // same name and stretches across this map.
+ for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
+ if (*iter == this) {
+ if (iter == maps_->begin()) {
+ return false;
+ }
+ --iter;
+ MapInfo* prev_map = *iter;
+ // Make sure this is a read-only map.
+ if (prev_map->flags != PROT_READ) {
+ return false;
+ }
+ uint64_t map_size = end - prev_map->end;
+ if (!memory->Init(name, prev_map->offset, map_size)) {
+ return false;
+ }
+ uint64_t max_size;
+ if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
+ return false;
+ }
+ if (!memory->Init(name, prev_map->offset, max_size)) {
+ return false;
+ }
+ elf_offset = offset - prev_map->offset;
+ return true;
+ }
+ }
+ return false;
+}
+
Memory* MapInfo::GetFileMemory() {
std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
if (offset == 0) {
@@ -38,8 +70,12 @@
return nullptr;
}
- // There are two possibilities when the offset is non-zero.
- // - There is an elf file embedded in a file.
+ // These are the possibilities when the offset is non-zero.
+ // - There is an elf file embedded in a file, and the offset is the
+ // the start of the elf in the file.
+ // - There is an elf file embedded in a file, and the offset is the
+ // the start of the executable part of the file. The actual start
+ // of the elf is in the read-only segment preceeding this map.
// - The whole file is an elf file, and the offset needs to be saved.
//
// Map in just the part of the file for the map. If this is not
@@ -53,27 +89,41 @@
return nullptr;
}
- uint64_t max_size;
- if (!Elf::GetInfo(memory.get(), &max_size)) {
- // Init as if the whole file is an elf.
- if (memory->Init(name, 0)) {
- elf_offset = offset;
- return memory.release();
+ // Check if the start of this map is an embedded elf.
+ uint64_t max_size = 0;
+ uint64_t file_offset = offset;
+ if (Elf::GetInfo(memory.get(), &max_size)) {
+ if (max_size > map_size) {
+ if (memory->Init(name, file_offset, max_size)) {
+ return memory.release();
+ }
+ // Try to reinit using the default map_size.
+ if (memory->Init(name, file_offset, map_size)) {
+ return memory.release();
+ }
+ return nullptr;
}
- return nullptr;
+ return memory.release();
}
- if (max_size > map_size) {
- if (memory->Init(name, offset, max_size)) {
- return memory.release();
- }
- // Try to reinit using the default map_size.
- if (memory->Init(name, offset, map_size)) {
- return memory.release();
- }
- return nullptr;
+ // No elf at offset, try to init as if the whole file is an elf.
+ if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
+ elf_offset = offset;
+ return memory.release();
}
- return memory.release();
+
+ // See if the map previous to this one contains a read-only map
+ // that represents the real start of the elf data.
+ if (InitFileMemoryFromPreviousReadOnlyMap(memory.get())) {
+ return memory.release();
+ }
+
+ // Failed to find elf at start of file or at read-only map, return
+ // file object from the current map.
+ if (memory->Init(name, offset, map_size)) {
+ return memory.release();
+ }
+ return nullptr;
}
Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
@@ -110,29 +160,27 @@
return nullptr;
}
- // Find the read-only map that has the same name and has an offset closest
- // to the current offset but less than the offset of the current map.
- // For shared libraries, there should be a r-x map that has a non-zero
- // offset and then a r-- map that has a zero offset.
- // For shared libraries loaded from an apk, there should be a r-x map that
- // has a non-zero offset and then a r-- map that has a non-zero offset less
- // than the offset from the r-x map.
- uint64_t closest_offset = 0;
+ // Find the read-only map by looking at the previous map. The linker
+ // doesn't guarantee that this invariant will always be true. However,
+ // if that changes, there is likely something else that will change and
+ // break something.
MapInfo* ro_map_info = nullptr;
- for (auto map_info : *maps_) {
- if (map_info->flags == PROT_READ && map_info->name == name && map_info->offset < offset &&
- map_info->offset >= closest_offset) {
- ro_map_info = map_info;
- closest_offset = ro_map_info->offset;
+ for (auto iter = maps_->begin(); iter != maps_->end(); ++iter) {
+ if (*iter == this) {
+ if (iter != maps_->begin()) {
+ --iter;
+ ro_map_info = *iter;
+ }
+ break;
}
}
- if (ro_map_info == nullptr) {
+ if (ro_map_info == nullptr || ro_map_info->name != name || ro_map_info->offset >= offset) {
return nullptr;
}
// Make sure that relative pc values are corrected properly.
- elf_offset = offset - closest_offset;
+ elf_offset = offset - ro_map_info->offset;
MemoryRanges* ranges = new MemoryRanges;
ranges->Insert(new MemoryRange(process_memory, ro_map_info->start,
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index b3c5549..792cd0b 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -239,8 +239,14 @@
if (!stepped) {
if (return_address_attempt) {
- // Remove the speculative frame.
- frames_.pop_back();
+ // Only remove the speculative frame if there are more than two frames
+ // or the pc in the first frame is in a valid map.
+ // This allows for a case where the code jumps into the middle of
+ // nowhere, but there is no other unwind information after that.
+ if (frames_.size() != 2 || maps_->Find(frames_[0].pc) != nullptr) {
+ // Remove the speculative frame.
+ frames_.pop_back();
+ }
break;
} else if (in_device_map) {
// Do not attempt any other unwinding, pc or sp is in a device
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index c202a33..0336173 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -66,7 +66,7 @@
std::mutex lock_;
bool initialized_ = false;
- std::unordered_map<uint64_t, DexFile*> files_;
+ std::unordered_map<uint64_t, std::unique_ptr<DexFile>> files_;
uint64_t entry_addr_ = 0;
uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr;
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 9c6b552..cfdefd0 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -83,6 +83,7 @@
void operator=(const MapInfo&) = delete;
Memory* GetFileMemory();
+ bool InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory);
// Protect the creation of the elf object.
std::mutex mutex_;
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 95d2176..21ca47b 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -21,44 +21,37 @@
#include <unordered_map>
#include <android-base/file.h>
-
+#include <dex/dex_file.h>
+#include <gtest/gtest.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
-#include <dex/code_item_accessors-inl.h>
-#include <dex/standard_dex_file.h>
-
-#include <gtest/gtest.h>
-
#include "DexFile.h"
-
#include "DexFileData.h"
#include "MemoryFake.h"
namespace unwindstack {
TEST(DexFileTest, from_file_open_non_exist) {
- DexFileFromFile dex_file;
- ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
+ EXPECT_TRUE(DexFileFromFile::Create(0, "/file/does/not/exist") == nullptr);
}
TEST(DexFileTest, from_file_open_too_small) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
- ASSERT_EQ(sizeof(art::DexFile::Header) - 2,
+ ASSERT_EQ(sizeof(art::DexFile::Header) - 1,
static_cast<size_t>(
- TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2)));
+ TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1))));
// Header too small.
- DexFileFromFile dex_file;
- ASSERT_FALSE(dex_file.Open(0, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
// Header correct, file too small.
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
tf.fd, kDexData, sizeof(art::DexFile::Header)))));
- ASSERT_FALSE(dex_file.Open(0, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
}
TEST(DexFileTest, from_file_open) {
@@ -68,8 +61,7 @@
ASSERT_EQ(sizeof(kDexData),
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
- DexFileFromFile dex_file;
- ASSERT_TRUE(dex_file.Open(0, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr);
}
TEST(DexFileTest, from_file_open_non_zero_offset) {
@@ -80,35 +72,31 @@
ASSERT_EQ(sizeof(kDexData),
static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
- DexFileFromFile dex_file;
- ASSERT_TRUE(dex_file.Open(0x100, tf.path));
+ EXPECT_TRUE(DexFileFromFile::Create(0x100, tf.path) != nullptr);
}
TEST(DexFileTest, from_memory_fail_too_small_for_header) {
MemoryFake memory;
memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
- DexFileFromMemory dex_file;
- ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+ EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr);
}
TEST(DexFileTest, from_memory_fail_too_small_for_data) {
MemoryFake memory;
memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
- DexFileFromMemory dex_file;
- ASSERT_FALSE(dex_file.Open(0x1000, &memory));
+ EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr);
}
TEST(DexFileTest, from_memory_open) {
MemoryFake memory;
memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
- DexFileFromMemory dex_file;
- ASSERT_TRUE(dex_file.Open(0x1000, &memory));
+ EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr);
}
TEST(DexFileTest, create_using_file) {
@@ -121,8 +109,7 @@
MemoryFake memory;
MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path);
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x500, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_file_non_zero_start) {
@@ -135,8 +122,7 @@
MemoryFake memory;
MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path);
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x600, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_file_non_zero_offset) {
@@ -149,24 +135,21 @@
MemoryFake memory;
MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path);
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x400, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_empty_file) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_file_does_not_exist) {
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
+ EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
}
TEST(DexFileTest, create_using_memory_file_is_malformed) {
@@ -179,22 +162,13 @@
MemoryFake memory;
memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
+ std::unique_ptr<DexFile> dex_file = DexFile::Create(0x4000, &memory, &info);
ASSERT_TRUE(dex_file != nullptr);
// Check it came from memory by clearing memory and verifying it fails.
memory.Clear();
- dex_file.reset(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file == nullptr);
-}
-
-TEST(DexFileTest, get_method_not_opened) {
- std::string method("something");
- uint64_t method_offset = 100;
- DexFile dex_file;
- dex_file.GetMethodInformation(0x100, &method, &method_offset);
- EXPECT_EQ("something", method);
- EXPECT_EQ(100U, method_offset);
+ dex_file = DexFile::Create(0x4000, &memory, &info);
+ EXPECT_TRUE(dex_file == nullptr);
}
TEST(DexFileTest, get_method) {
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
index 0987bc1..943b3c9 100644
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
@@ -59,16 +59,16 @@
}
static void SetUpTestCase() {
- std::vector<uint8_t> buffer(1024);
- memset(buffer.data(), 0, buffer.size());
+ std::vector<uint8_t> buffer(12288, 0);
memcpy(buffer.data(), ELFMAG, SELFMAG);
buffer[EI_CLASS] = ELFCLASS32;
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+ ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), 1024));
memset(buffer.data(), 0, buffer.size());
- memcpy(&buffer[0x100], ELFMAG, SELFMAG);
- buffer[0x100 + EI_CLASS] = ELFCLASS64;
- ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size()));
+ memcpy(&buffer[0x1000], ELFMAG, SELFMAG);
+ buffer[0x1000 + EI_CLASS] = ELFCLASS64;
+ buffer[0x2000] = 0xff;
+ ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, buffer.data(), buffer.size()));
InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32);
InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
@@ -84,13 +84,13 @@
static TemporaryFile elf_;
- static TemporaryFile elf_at_100_;
+ static TemporaryFile elf_at_1000_;
static TemporaryFile elf32_at_map_;
static TemporaryFile elf64_at_map_;
};
TemporaryFile MapInfoCreateMemoryTest::elf_;
-TemporaryFile MapInfoCreateMemoryTest::elf_at_100_;
+TemporaryFile MapInfoCreateMemoryTest::elf_at_1000_;
TemporaryFile MapInfoCreateMemoryTest::elf32_at_map_;
TemporaryFile MapInfoCreateMemoryTest::elf64_at_map_;
@@ -134,7 +134,7 @@
// Verify that if the offset is non-zero and there is an elf at that
// offset, that only part of the file is used.
TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
- MapInfo info(nullptr, 0x100, 0x200, 0x100, 0, elf_at_100_.path);
+ MapInfo info(nullptr, 0x100, 0x200, 0x1000, 0, elf_at_1000_.path);
std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
ASSERT_TRUE(memory.get() != nullptr);
@@ -312,4 +312,43 @@
}
}
+TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) {
+ Maps maps;
+ maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
+ maps.Add(0x1000, 0x2000, 0x1000, PROT_READ, elf_at_1000_.path, 0);
+ maps.Add(0x2000, 0x3000, 0x2000, PROT_READ | PROT_EXEC, elf_at_1000_.path, 0);
+
+ MapInfo* map_info = maps.Find(0x2000);
+ ASSERT_TRUE(map_info != nullptr);
+
+ // Set up the size
+ Elf64_Ehdr ehdr;
+ ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
+ ASSERT_TRUE(android::base::ReadFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
+
+ // Will not give the elf memory, because the read-only entry does not
+ // extend over the executable segment.
+ std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
+ ASSERT_TRUE(memory.get() != nullptr);
+ std::vector<uint8_t> buffer(0x100);
+ EXPECT_EQ(0x2000U, map_info->offset);
+ EXPECT_EQ(0U, map_info->elf_offset);
+ ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
+ EXPECT_EQ(0xffU, buffer[0]);
+
+ // Now init the elf data enough so that the file memory object will be used.
+ ehdr.e_shoff = 0x4000;
+ ehdr.e_shnum = 1;
+ ehdr.e_shentsize = 0x100;
+ ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
+ ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
+
+ memory.reset(map_info->CreateMemory(process_memory_));
+ EXPECT_EQ(0x2000U, map_info->offset);
+ EXPECT_EQ(0x1000U, map_info->elf_offset);
+ Elf64_Ehdr ehdr_mem;
+ ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem)));
+ EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index a65c077..dc015b4 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1239,4 +1239,79 @@
EXPECT_EQ(0xffd4a718U, unwinder.frames()[7].sp);
}
+TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) {
+ ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_arm64/", ARCH_ARM64));
+
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.Unwind();
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n"
+ " #01 pc 000000000005426c (offset 0x39000) linker64 "
+ "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
+ " #02 pc 00000000000008bc vdso.so\n"
+ " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n"
+ " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n"
+ " #05 pc 000000000003d5b4 (offset 0x40000) ANGLEPrebuilt.apk (ANGLEGetUtilityAPI+56)\n"
+ " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n",
+ frame_info);
+
+ EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
+ EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
+ EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
+ EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
+ EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
+ EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
+ EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
+ EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc);
+ EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp);
+ EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc);
+ EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp);
+ EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc);
+ EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp);
+ // Ignore top frame since the test code was modified to end in __libc_init.
+}
+
+TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) {
+ ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_memory_only_arm64/", ARCH_ARM64));
+ // Add the memory that represents the shared library.
+ MemoryOfflineParts* memory = reinterpret_cast<MemoryOfflineParts*>(process_memory_.get());
+ AddMemory(dir_ + "lib_mem.data", memory);
+
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.Unwind();
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 000000000014ccbc (offset 0x39000) linker64 (__dl_syscall+28)\n"
+ " #01 pc 000000000005426c (offset 0x39000) linker64 "
+ "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
+ " #02 pc 00000000000008bc vdso.so\n"
+ " #03 pc 00000000000846f4 (offset 0x40000) libc.so (abort+172)\n"
+ " #04 pc 0000000000084ad4 (offset 0x40000) libc.so (__assert2+36)\n"
+ " #05 pc 000000000003d5b4 (offset 0x2211000) ANGLEPrebuilt.apk\n"
+ " #06 pc 000000000007fe68 (offset 0x40000) libc.so (__libc_init)\n",
+ frame_info);
+
+ EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
+ EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
+ EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
+ EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
+ EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
+ EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
+ EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
+ EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc);
+ EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp);
+ EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc);
+ EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp);
+ EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc);
+ EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp);
+ // Ignore top frame since the test code was modified to end in __libc_init.
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 831d3b5..c4b8763 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -660,6 +660,54 @@
ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
// Fake as if code called a nullptr function.
+ regs_.set_pc(0x20000);
+ regs_.set_sp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0x10010, false));
+ regs_.FakeSetReturnAddress(0x12);
+ regs_.FakeSetReturnAddressValid(true);
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
+
+ ASSERT_EQ(2U, unwinder.NumFrames());
+
+ auto* frame = &unwinder.frames()[0];
+ EXPECT_EQ(0U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0x20000U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0x20000U, frame->map_start);
+ EXPECT_EQ(0x22000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+
+ frame = &unwinder.frames()[1];
+ EXPECT_EQ(1U, frame->num);
+ EXPECT_EQ(0U, frame->rel_pc);
+ EXPECT_EQ(0U, frame->pc);
+ EXPECT_EQ(0x10010U, frame->sp);
+ EXPECT_EQ("", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0U, frame->map_start);
+ EXPECT_EQ(0U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(0, frame->map_flags);
+}
+
+// Verify that a speculative frame is added and left if there are only
+// two frames and the pc is in the middle nowhere.
+TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
+
+ // Fake as if code called a nullptr function.
regs_.set_pc(0);
regs_.set_sp(0x10000);
regs_.FakeSetReturnAddress(0x1202);
@@ -669,7 +717,7 @@
unwinder.Unwind();
EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- ASSERT_EQ(1U, unwinder.NumFrames());
+ ASSERT_EQ(2U, unwinder.NumFrames());
auto* frame = &unwinder.frames()[0];
EXPECT_EQ(0U, frame->num);
@@ -684,6 +732,20 @@
EXPECT_EQ(0U, frame->map_end);
EXPECT_EQ(0U, frame->map_load_bias);
EXPECT_EQ(0, frame->map_flags);
+
+ frame = &unwinder.frames()[1];
+ EXPECT_EQ(1U, frame->num);
+ EXPECT_EQ(0x200U, frame->rel_pc);
+ EXPECT_EQ(0x1200U, frame->pc);
+ EXPECT_EQ(0x10000U, frame->sp);
+ EXPECT_EQ("Frame0", frame->function_name);
+ EXPECT_EQ(0U, frame->function_offset);
+ EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+ EXPECT_EQ(0U, frame->map_offset);
+ EXPECT_EQ(0x1000U, frame->map_start);
+ EXPECT_EQ(0x8000U, frame->map_end);
+ EXPECT_EQ(0U, frame->map_load_bias);
+ EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
// Verify that an unwind stops when a frame is in given suffix.
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk
new file mode 100644
index 0000000..0277359
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so
new file mode 100644
index 0000000..20008fd
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64 b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64
new file mode 100644
index 0000000..b90933b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt
new file mode 100644
index 0000000..c4fc067
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt
@@ -0,0 +1,7 @@
+7dabc03000-7dabc3f000 r--p 4000 00:00 0 ANGLEPrebuilt.apk
+7dabc3f000-7dabcf0000 r-xp 40000 00:00 0 ANGLEPrebuilt.apk
+7e7ee48000-7e7ee88000 r--p 0 00:00 0 libc.so
+7e7ee88000-7e7ef32000 r-xp 40000 00:00 0 libc.so
+7e82b01000-7e82b03000 r-xp 0 00:00 0 vdso.so
+7e82b03000-7e82b3c000 r--p 0 00:00 0 linker64
+7e82b3c000-7e82c77000 r-xp 39000 00:00 0 linker64
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt
new file mode 100644
index 0000000..1e2ea32
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt
@@ -0,0 +1,33 @@
+x0: 7df8ca3c24
+x1: 0
+x2: ffffffff
+x3: 0
+x4: 0
+x5: 0
+x6: 0
+x7: 7f7f7f7f7f7f7f7f
+x8: 62
+x9: 20dd5829922a93ac
+x10: 7e82b57420
+x11: 4100
+x12: 7df8ca3b70
+x13: 7df8ca3b98
+x14: 73d015e5
+x15: 39a36122467299
+x16: 76ac
+x17: 0
+x18: 7df8cfc000
+x19: 7dabf3e7a0
+x20: 7df8ca3da0
+x21: 59616d61
+x22: 1
+x23: 7df8ca3c24
+x24: 1894
+x25: 62
+x26: 2
+x27: 0
+x28: 7dabf3e790
+x29: 7df8ca3d90
+sp: 7df8ca3bf0
+lr: 7e82b57270
+pc: 7e82c4fcbc
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data
new file mode 100644
index 0000000..ec07e15
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data
new file mode 100644
index 0000000..825bb1a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so
new file mode 100644
index 0000000..205ebd4
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data
new file mode 100644
index 0000000..f39d127
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so
new file mode 100644
index 0000000..20008fd
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64 b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64
new file mode 100644
index 0000000..b90933b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt
new file mode 100644
index 0000000..386d57a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt
@@ -0,0 +1,7 @@
+7dabc03000-7dabc3f000 r--p 21d5000 00:00 0 ANGLEPrebuilt.apk
+7dabc3f000-7dabcf0000 r-xp 2211000 00:00 0 ANGLEPrebuilt.apk
+7e7ee48000-7e7ee88000 r--p 0 00:00 0 libc.so
+7e7ee88000-7e7ef32000 r-xp 40000 00:00 0 libc.so
+7e82b01000-7e82b03000 r-xp 0 00:00 0 vdso.so
+7e82b03000-7e82b3c000 r--p 0 00:00 0 linker64
+7e82b3c000-7e82c77000 r-xp 39000 00:00 0 linker64
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt
new file mode 100644
index 0000000..1e2ea32
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt
@@ -0,0 +1,33 @@
+x0: 7df8ca3c24
+x1: 0
+x2: ffffffff
+x3: 0
+x4: 0
+x5: 0
+x6: 0
+x7: 7f7f7f7f7f7f7f7f
+x8: 62
+x9: 20dd5829922a93ac
+x10: 7e82b57420
+x11: 4100
+x12: 7df8ca3b70
+x13: 7df8ca3b98
+x14: 73d015e5
+x15: 39a36122467299
+x16: 76ac
+x17: 0
+x18: 7df8cfc000
+x19: 7dabf3e7a0
+x20: 7df8ca3da0
+x21: 59616d61
+x22: 1
+x23: 7df8ca3c24
+x24: 1894
+x25: 62
+x26: 2
+x27: 0
+x28: 7dabf3e790
+x29: 7df8ca3d90
+sp: 7df8ca3bf0
+lr: 7e82b57270
+pc: 7e82c4fcbc
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data
new file mode 100644
index 0000000..ec07e15
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data
new file mode 100644
index 0000000..825bb1a
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so
new file mode 100644
index 0000000..205ebd4
--- /dev/null
+++ b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so
Binary files differ
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 22ca7bf..e729453 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -35,7 +35,12 @@
#include <unwindstack/Unwinder.h>
static bool Attach(pid_t pid) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+ if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) {
+ return false;
+ }
+
+ if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) {
+ ptrace(PTRACE_DETACH, pid, 0, 0);
return false;
}
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 640992f..652dbd1 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -50,7 +50,12 @@
};
static bool Attach(pid_t pid) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
+ if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) {
+ return false;
+ }
+
+ if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) {
+ ptrace(PTRACE_DETACH, pid, 0, 0);
return false;
}
@@ -224,7 +229,7 @@
sp_map_start = map_info->start;
}
- for (auto frame : unwinder.frames()) {
+ for (const auto& frame : unwinder.frames()) {
map_info = maps.Find(frame.sp);
if (map_info != nullptr && sp_map_start != map_info->start) {
stacks.emplace_back(std::make_pair(frame.sp, map_info->end));
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 5fca1ee..267da4a 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -616,7 +616,7 @@
std::string llkFormat(const std::unordered_set<std::string>& blacklist) {
std::string ret;
- for (auto entry : blacklist) {
+ for (const auto& entry : blacklist) {
if (ret.size()) {
ret += ",";
}
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 041f6d8..264c612 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -28,7 +28,7 @@
dir.postinstall = /postinstall
[system]
-additional.namespaces = sphal,vndk,rs
+additional.namespaces = runtime,sphal,vndk,rs
###############################################################################
# "default" namespace
@@ -38,8 +38,7 @@
###############################################################################
namespace.default.isolated = true
-namespace.default.search.paths = /apex/com.android.runtime/${LIB}
-namespace.default.search.paths += /system/${LIB}
+namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
@@ -76,7 +75,6 @@
namespace.default.permitted.paths += /mnt/expand
namespace.default.asan.search.paths = /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /apex/com.android.runtime/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
namespace.default.asan.search.paths += /data/asan/product/${LIB}
namespace.default.asan.search.paths += /%PRODUCT%/${LIB}
@@ -107,6 +105,28 @@
namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
namespace.default.asan.permitted.paths += /mnt/expand
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+namespace.default.link.runtime.shared_libs += libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
+namespace.default.link.runtime.shared_libs += libnativehelper.so
+namespace.default.link.runtime.shared_libs += libnativeloader.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace exposes externally accessible libraries from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
###############################################################################
# "sphal" namespace
#
@@ -141,8 +161,12 @@
# Once in this namespace, access to libraries in /system/lib is restricted. Only
# libs listed here can be used.
-namespace.sphal.links = default,vndk,rs
+namespace.sphal.links = runtime,default,vndk,rs
+namespace.sphal.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+# LLNDK_LIBRARIES includes the runtime libs above, but the order here ensures
+# that they are loaded from the runtime namespace.
namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -189,9 +213,11 @@
namespace.rs.asan.permitted.paths += /vendor/${LIB}
namespace.rs.asan.permitted.paths += /data
-namespace.rs.links = default,vndk
+namespace.rs.links = runtime,default,vndk
-namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
# namespace because RS framework libs are using them.
@@ -237,10 +263,13 @@
namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-# The "vndk" namespace links to "default" namespace for LLNDK libs and links to
-# "sphal" namespace for vendor libs. The ordering matters. The "default"
-# namespace has higher priority than the "sphal" namespace.
-namespace.vndk.links = default,sphal
+# The "vndk" namespace links to "runtime" for Bionic libs, "default" namespace
+# for LLNDK libs, and links to "sphal" namespace for vendor libs. The ordering
+# matters. The "default" namespace has higher priority than the "sphal"
+# namespace.
+namespace.vndk.links = runtime,default,sphal
+
+namespace.vndk.link.runtime.shared_libs = libc.so:libdl.so:libm.so
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
@@ -251,6 +280,7 @@
# Allow VNDK-SP extensions to use vendor libraries
namespace.vndk.link.sphal.allow_all_shared_libs = true
+
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
@@ -258,7 +288,7 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-additional.namespaces = system,vndk
+additional.namespaces = runtime,system,vndk
###############################################################################
# "default" namespace
@@ -289,12 +319,24 @@
namespace.default.asan.permitted.paths += /data/asan/vendor
namespace.default.asan.permitted.paths += /vendor
-namespace.default.links = system,vndk
+namespace.default.links = runtime,system,vndk
+namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace pulls in externally accessible libs from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
+###############################################################################
# "vndk" namespace
#
# This namespace is where VNDK and VNDK-SP libraries are loaded for
@@ -325,7 +367,10 @@
# When these NDK libs are required inside this namespace, then it is redirected
# to the system namespace. This is possible since their ABI is stable across
# Android releases.
-namespace.vndk.links = system,default
+namespace.vndk.links = runtime,system,default
+
+namespace.vndk.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -339,30 +384,47 @@
###############################################################################
namespace.system.isolated = false
-namespace.system.search.paths = /apex/com.android.runtime/${LIB}
-namespace.system.search.paths += /system/${LIB}
+namespace.system.search.paths = /system/${LIB}
namespace.system.search.paths += /%PRODUCT%/${LIB}
namespace.system.search.paths += /%PRODUCT_SERVICES%/${LIB}
namespace.system.asan.search.paths = /data/asan/system/${LIB}
-namespace.system.asan.search.paths += /apex/com.android.runtime/${LIB}
namespace.system.asan.search.paths += /system/${LIB}
namespace.system.asan.search.paths += /data/asan/product/${LIB}
namespace.system.asan.search.paths += /%PRODUCT%/${LIB}
namespace.system.asan.search.paths += /data/asan/product_services/${LIB}
namespace.system.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
+namespace.system.links = runtime
+namespace.system.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+
###############################################################################
# Namespace config for binaries under /postinstall.
-# Only one default namespace is defined and it has no directories other than
-# /system/lib in the search paths. This is because linker calls realpath on the
-# search paths and this causes selinux denial if the paths (/vendor, /odm) are
-# not allowed to the poinstall binaries. There is no reason to allow the
-# binaries to access the paths.
+# Only default and runtime namespaces are defined and default has no directories
+# other than /system/lib in the search paths. This is because linker calls
+# realpath on the search paths and this causes selinux denial if the paths
+# (/vendor, /odm) are not allowed to the postinstall binaries. There is no
+# reason to allow the binaries to access the paths.
###############################################################################
[postinstall]
+additional.namespaces = runtime
+
namespace.default.isolated = false
-namespace.default.search.paths = /apex/com.android.runtime/${LIB}
-namespace.default.search.paths += /system/${LIB}
+namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
+
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace pulls in externally accessible libs from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
+namespace.runtime.link.default.allow_all_shared_libs = true
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 6a53b03..7ca45ff 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -28,7 +28,7 @@
dir.postinstall = /postinstall
[system]
-additional.namespaces = sphal,vndk,rs
+additional.namespaces = runtime,sphal,vndk,rs
###############################################################################
# "default" namespace
@@ -38,15 +38,13 @@
###############################################################################
namespace.default.isolated = false
-namespace.default.search.paths = /apex/com.android.runtime/${LIB}
-namespace.default.search.paths += /system/${LIB}
+namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /odm/${LIB}
namespace.default.search.paths += /vendor/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
namespace.default.asan.search.paths = /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /apex/com.android.runtime/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
namespace.default.asan.search.paths += /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
@@ -57,6 +55,27 @@
namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+namespace.default.link.runtime.shared_libs += libart.so:libartd.so
+namespace.default.link.runtime.shared_libs += libnativehelper.so
+namespace.default.link.runtime.shared_libs += libnativeloader.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace pulls in externally accessible libs from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+
+# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies and PALette library
+# when it exists.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
###############################################################################
# "sphal" namespace
#
@@ -91,8 +110,12 @@
# Once in this namespace, access to libraries in /system/lib is restricted. Only
# libs listed here can be used.
-namespace.sphal.links = default,vndk,rs
+namespace.sphal.links = runtime,default,vndk,rs
+namespace.sphal.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+# LLNDK_LIBRARIES includes the runtime libs above, but the order here ensures
+# that they are loaded from the runtime namespace.
namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
@@ -139,9 +162,11 @@
namespace.rs.asan.permitted.paths += /vendor/${LIB}
namespace.rs.asan.permitted.paths += /data
-namespace.rs.links = default,vndk
+namespace.rs.links = runtime,default,vndk
-namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
# namespace because RS framework libs are using them.
@@ -190,10 +215,14 @@
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
# Android releases.
-namespace.vndk.links = default
+namespace.vndk.links = runtime,default
+
+namespace.vndk.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
@@ -201,6 +230,7 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
+additional.namespaces = runtime
namespace.default.isolated = false
namespace.default.search.paths = /odm/${LIB}
@@ -210,10 +240,9 @@
namespace.default.search.paths += /vendor/${LIB}/vndk
namespace.default.search.paths += /vendor/${LIB}/vndk-sp
-# Access to system libraries are allowed
+# Access to system libraries is allowed
namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.search.paths += /apex/com.android.runtime/${LIB}
namespace.default.search.paths += /system/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
@@ -235,24 +264,53 @@
namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.default.asan.search.paths += /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /apex/com.android.runtime/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
namespace.default.asan.search.paths += /data/asan/product/${LIB}
namespace.default.asan.search.paths += /%PRODUCT%/${LIB}
namespace.default.asan.search.paths += /data/asan/product_services/${LIB}
namespace.default.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace pulls in externally accessible libs from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
+namespace.runtime.link.default.allow_all_shared_libs = true
+
+
###############################################################################
# Namespace config for binaries under /postinstall.
-# Only one default namespace is defined and it has no directories other than
-# /system/lib in the search paths. This is because linker calls realpath on the
-# search paths and this causes selinux denial if the paths (/vendor, /odm) are
-# not allowed to the poinstall binaries. There is no reason to allow the
-# binaries to access the paths.
+# Only default and runtime namespaces are defined and default has no directories
+# other than /system/lib in the search paths. This is because linker calls
+# realpath on the search paths and this causes selinux denial if the paths
+# (/vendor, /odm) are not allowed to the postinstall binaries. There is no
+# reason to allow the binaries to access the paths.
###############################################################################
[postinstall]
+additional.namespaces = runtime
+
namespace.default.isolated = false
-namespace.default.search.paths = /apex/com.android.runtime/${LIB}
-namespace.default.search.paths += /system/${LIB}
+namespace.default.search.paths = /system/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
+
+namespace.default.links = runtime
+namespace.default.link.runtime.shared_libs = libc.so:libdl.so:libm.so
+
+###############################################################################
+# "runtime" APEX namespace
+#
+# This namespace pulls in externally accessible libs from the Runtime APEX.
+###############################################################################
+namespace.runtime.isolated = true
+namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
+namespace.runtime.links = default
+# TODO(b/119867084): Restrict to Bionic dlopen dependencies.
+namespace.runtime.link.default.allow_all_shared_libs = true
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index d90a1ce..a9658a4 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -1,6 +1,9 @@
firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/
uevent_socket_rcvbuf_size 16M
+subsystem adf
+ devname uevent_devname
+
subsystem graphics
devname uevent_devpath
dirname /dev/graphics
@@ -9,10 +12,26 @@
devname uevent_devpath
dirname /dev/dri
+subsystem oncrpc
+ devname uevent_devpath
+ dirname /dev/oncrpc
+
+subsystem adsp
+ devname uevent_devpath
+ dirname /dev/adsp
+
+subsystem msm_camera
+ devname uevent_devpath
+ dirname /dev/msm_camera
+
subsystem input
devname uevent_devpath
dirname /dev/input
+subsystem mtd
+ devname uevent_devpath
+ dirname /dev/mtd
+
subsystem sound
devname uevent_devpath
dirname /dev/snd
@@ -40,25 +59,73 @@
/dev/pmsg0 0222 root log
+# the msm hw3d client device node is world writable/readable.
+/dev/msm_hw3dc 0666 root root
+
+# gpu driver for adreno200 is globally accessible
+/dev/kgsl 0666 root root
+
# kms driver for drm based gpu
/dev/dri/* 0666 root graphics
# these should not be world writable
/dev/diag 0660 radio radio
+/dev/diag_arm9 0660 radio radio
/dev/ttyMSM0 0600 bluetooth bluetooth
/dev/uhid 0660 uhid uhid
/dev/uinput 0660 uhid uhid
+/dev/alarm 0664 system radio
/dev/rtc0 0640 system system
/dev/tty0 0660 root system
/dev/graphics/* 0660 root graphics
+/dev/msm_hw3dm 0660 system graphics
/dev/input/* 0660 root input
/dev/v4l-touch* 0660 root input
+/dev/eac 0660 root audio
+/dev/cam 0660 root camera
+/dev/pmem 0660 system graphics
+/dev/pmem_adsp* 0660 system audio
+/dev/pmem_camera* 0660 system camera
+/dev/oncrpc/* 0660 root system
+/dev/adsp/* 0660 system audio
/dev/snd/* 0660 system audio
+/dev/mt9t013 0660 system system
+/dev/msm_camera/* 0660 system system
+/dev/akm8976_daemon 0640 compass system
+/dev/akm8976_aot 0640 compass system
+/dev/akm8973_daemon 0640 compass system
+/dev/akm8973_aot 0640 compass system
+/dev/bma150 0640 compass system
+/dev/cm3602 0640 compass system
+/dev/akm8976_pffd 0640 compass system
+/dev/lightsensor 0640 system system
+/dev/msm_pcm_out* 0660 system audio
+/dev/msm_pcm_in* 0660 system audio
+/dev/msm_pcm_ctl* 0660 system audio
+/dev/msm_snd* 0660 system audio
/dev/msm_mp3* 0660 system audio
+/dev/audience_a1026* 0660 system audio
+/dev/tpa2018d1* 0660 system audio
+/dev/msm_audpre 0660 system audio
+/dev/msm_audio_ctl 0660 system audio
+/dev/htc-acoustic 0660 system audio
+/dev/vdec 0660 system audio
+/dev/q6venc 0660 system audio
+/dev/snd/dsp 0660 system audio
+/dev/snd/dsp1 0660 system audio
+/dev/snd/mixer 0660 system audio
+/dev/smd0 0640 radio radio
+/dev/qmi 0640 radio radio
+/dev/qmi0 0640 radio radio
+/dev/qmi1 0640 radio radio
+/dev/qmi2 0640 radio radio
+/dev/bus/usb/* 0660 root usb
+/dev/mtp_usb 0660 root mtp
/dev/usb_accessory 0660 root usb
/dev/tun 0660 system vpn
# CDMA radio interface MUX
+/dev/ts0710mux* 0640 radio radio
/dev/ppp 0660 radio vpn
# sysfs properties
@@ -68,3 +135,6 @@
/sys/devices/virtual/usb_composite/* enable 0664 root system
/sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system
/sys/devices/system/cpu/cpu* cpufreq/scaling_min_freq 0664 system system
+
+# DVB API device nodes
+/dev/dvb* 0660 root system