Merge "Add noexcept to missing places in expected.h"
diff --git a/adb/Android.bp b/adb/Android.bp
index f6aede8..6558b1b 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -436,7 +436,6 @@
shared_libs: [
"libbootloader_message",
"libmdnssd",
- "libext4_utils",
"libfec",
"libfs_mgr",
"libselinux",
diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp
index 2ebd57d..e01e39b 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -61,7 +61,7 @@
LOG(ERROR) << "Could not map partition: " << partition_name;
return false;
}
- auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name, 5s); };
+ auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name); };
*handle = PartitionHandle(dm_path, std::move(closer));
return true;
}
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 3d3503c..65f0eff 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -73,6 +73,7 @@
whole_static_libs: [
"liblogwrap",
"libdm",
+ "libext2_uuid",
"libfstab",
],
cppflags: [
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 259f800..7a0d019 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1331,7 +1331,7 @@
continue;
}
} else if ((current_entry.fs_mgr_flags.verify)) {
- if (!fs_mgr_teardown_verity(¤t_entry, true /* wait */)) {
+ if (!fs_mgr_teardown_verity(¤t_entry)) {
LERROR << "Failed to tear down verified partition on mount point: "
<< current_entry.mount_point;
ret |= FsMgrUmountStatus::ERROR_VERITY;
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 1f21a71..04ba0bf 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -122,19 +122,9 @@
table.set_readonly(false);
}
std::string name = GetPartitionName(partition);
- if (!dm.CreateDevice(name, table)) {
+ if (!dm.CreateDevice(name, table, path, timeout_ms)) {
return false;
}
- if (!dm.GetDmDevicePathByName(name, path)) {
- return false;
- }
- if (timeout_ms > std::chrono::milliseconds::zero()) {
- if (!WaitForFile(*path, timeout_ms)) {
- DestroyLogicalPartition(name, {});
- LERROR << "Timed out waiting for device path: " << *path;
- return false;
- }
- }
LINFO << "Created logical partition " << name << " on device " << *path;
return true;
}
@@ -194,24 +184,16 @@
timeout_ms, path);
}
-bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
+bool UnmapDevice(const std::string& name) {
DeviceMapper& dm = DeviceMapper::Instance();
- std::string path;
- if (timeout_ms > std::chrono::milliseconds::zero()) {
- dm.GetDmDevicePathByName(name, &path);
- }
if (!dm.DeleteDevice(name)) {
return false;
}
- if (!path.empty() && !WaitForFileDeleted(path, timeout_ms)) {
- LERROR << "Timed out waiting for device path to unlink: " << path;
- return false;
- }
return true;
}
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
- if (!UnmapDevice(name, timeout_ms)) {
+bool DestroyLogicalPartition(const std::string& name) {
+ if (!UnmapDevice(name)) {
return false;
}
LINFO << "Unmapped logical partition " << name;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 31790b1..9a0f4fe 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -704,10 +704,9 @@
return true;
}
-// For GSI to skip mounting /product and /product_services, until there are
-// well-defined interfaces between them and /system. Otherwise, the GSI flashed
-// on /system might not be able to work with /product and /product_services.
-// When they're skipped here, /system/product and /system/product_services in
+// For GSI to skip mounting /product and /system_ext, until there are well-defined interfaces
+// between them and /system. Otherwise, the GSI flashed on /system might not be able to work with
+// /product and /system_ext. When they're skipped here, /system/product and /system/system_ext in
// GSI will be used.
bool SkipMountingPartitions(Fstab* fstab) {
constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 05ca5fc..ac15ce4 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -32,7 +32,6 @@
#include <unistd.h>
#include <algorithm>
-#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -445,7 +444,7 @@
auto metadata = builder->Export();
if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
if (change) *change = true;
- if (!DestroyLogicalPartition(partition_name, 0s)) return false;
+ if (!DestroyLogicalPartition(partition_name)) return false;
} else {
LERROR << "delete partition " << overlay;
return false;
@@ -518,10 +517,166 @@
return ret;
}
+bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) {
+ auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE,
+ nullptr);
+ if (ret) {
+ PERROR << "__mount(target=" << mount_point
+ << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret;
+ return false;
+ }
+ return true;
+}
+
+bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) {
+ auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr);
+ if (ret) {
+ PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret;
+ return false;
+ }
+ return true;
+}
+
+struct mount_info {
+ std::string mount_point;
+ bool shared_flag;
+};
+
+std::vector<mount_info> ReadMountinfoFromFile(const std::string& path) {
+ std::vector<mount_info> info;
+
+ auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+ if (!file) {
+ PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
+ return info;
+ }
+
+ ssize_t len;
+ size_t alloc_len = 0;
+ char* line = nullptr;
+ while ((len = getline(&line, &alloc_len, file.get())) != -1) {
+ /* if the last character is a newline, shorten the string by 1 byte */
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ }
+
+ static constexpr char delim[] = " \t";
+ char* save_ptr;
+ if (!strtok_r(line, delim, &save_ptr)) {
+ LERROR << "Error parsing mount ID";
+ break;
+ }
+ if (!strtok_r(nullptr, delim, &save_ptr)) {
+ LERROR << "Error parsing parent ID";
+ break;
+ }
+ if (!strtok_r(nullptr, delim, &save_ptr)) {
+ LERROR << "Error parsing mount source";
+ break;
+ }
+ if (!strtok_r(nullptr, delim, &save_ptr)) {
+ LERROR << "Error parsing root";
+ break;
+ }
+
+ char* p;
+ if (!(p = strtok_r(nullptr, delim, &save_ptr))) {
+ LERROR << "Error parsing mount_point";
+ break;
+ }
+ mount_info entry = {p, false};
+
+ if (!strtok_r(nullptr, delim, &save_ptr)) {
+ LERROR << "Error parsing mount_flags";
+ break;
+ }
+
+ while ((p = strtok_r(nullptr, delim, &save_ptr))) {
+ if ((p[0] == '-') && (p[1] == '\0')) break;
+ if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true;
+ }
+ if (!p) {
+ LERROR << "Error parsing fields";
+ break;
+ }
+ info.emplace_back(std::move(entry));
+ }
+
+ free(line);
+ if (info.empty()) {
+ LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'";
+ }
+ return info;
+}
+
bool fs_mgr_overlayfs_mount(const std::string& mount_point) {
auto options = fs_mgr_get_overlayfs_options(mount_point);
if (options.empty()) return false;
+ auto retval = true;
+ auto save_errno = errno;
+
+ struct move_entry {
+ std::string mount_point;
+ std::string dir;
+ bool shared_flag;
+ };
+ std::vector<move_entry> move;
+ auto parent_private = false;
+ auto parent_made_private = false;
+ auto dev_private = false;
+ auto dev_made_private = false;
+ for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) {
+ if ((entry.mount_point == mount_point) && !entry.shared_flag) {
+ parent_private = true;
+ }
+ if ((entry.mount_point == "/dev") && !entry.shared_flag) {
+ dev_private = true;
+ }
+
+ if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
+ continue;
+ }
+ if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) {
+ return android::base::StartsWith(entry.mount_point, it.mount_point + "/");
+ }) != move.end()) {
+ continue;
+ }
+
+ // use as the bound directory in /dev.
+ auto new_context = fs_mgr_get_context(entry.mount_point);
+ if (!new_context.empty() && setfscreatecon(new_context.c_str())) {
+ PERROR << "setfscreatecon " << new_context;
+ }
+ move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX",
+ entry.shared_flag};
+ const auto target = mkdtemp(new_entry.dir.data());
+ if (!target) {
+ retval = false;
+ save_errno = errno;
+ PERROR << "temporary directory for MS_BIND";
+ setfscreatecon(nullptr);
+ continue;
+ }
+ setfscreatecon(nullptr);
+
+ if (!parent_private && !parent_made_private) {
+ parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
+ }
+ if (new_entry.shared_flag) {
+ new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
+ }
+ if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) {
+ retval = false;
+ save_errno = errno;
+ if (new_entry.shared_flag) {
+ fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
+ }
+ continue;
+ }
+ move.emplace_back(std::move(new_entry));
+ }
+
// 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, ",");
@@ -536,12 +691,38 @@
auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_RELATIME,
options.c_str());
if (ret) {
+ retval = false;
+ save_errno = errno;
PERROR << report << ret;
- return false;
} else {
LINFO << report << ret;
- return true;
}
+
+ // Move submounts back.
+ for (const auto& entry : move) {
+ if (!dev_private && !dev_made_private) {
+ dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false);
+ }
+
+ if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) {
+ retval = false;
+ save_errno = errno;
+ } else if (entry.shared_flag &&
+ !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) {
+ retval = false;
+ save_errno = errno;
+ }
+ rmdir(entry.dir.c_str());
+ }
+ if (dev_made_private) {
+ fs_mgr_overlayfs_set_shared_mount("/dev", true);
+ }
+ if (parent_made_private) {
+ fs_mgr_overlayfs_set_shared_mount(mount_point, true);
+ }
+
+ errno = save_errno;
+ return retval;
}
// Mount kScratchMountPoint
@@ -663,7 +844,7 @@
if (!android::base::EndsWith(name, suffix)) {
continue;
}
- if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name, 2s)) {
+ if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name)) {
continue;
}
builder->ResizePartition(builder->FindPartition(name), 0);
@@ -737,7 +918,7 @@
return false;
}
}
- if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+ if (!partition_create) DestroyLogicalPartition(partition_name);
changed = true;
*partition_exists = false;
}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 3a33cf3..c5e477c 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -97,10 +97,10 @@
bool fs_mgr_is_ext4(const std::string& blk_device);
bool fs_mgr_is_f2fs(const std::string& blk_device);
-bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab, bool wait);
+bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab);
namespace android {
namespace fs_mgr {
-bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+bool UnmapDevice(const std::string& name);
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index be8077b..efa2180 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -547,9 +547,9 @@
return retval;
}
-bool fs_mgr_teardown_verity(FstabEntry* entry, bool wait) {
+bool fs_mgr_teardown_verity(FstabEntry* entry) {
const std::string mount_point(basename(entry->mount_point.c_str()));
- if (!android::fs_mgr::UnmapDevice(mount_point, wait ? 1000ms : 0ms)) {
+ if (!android::fs_mgr::UnmapDevice(mount_point)) {
return false;
}
LINFO << "Unmapped verity device " << mount_point;
diff --git a/fs_mgr/include/fs_mgr_dm_linear.h b/fs_mgr/include/fs_mgr_dm_linear.h
index f33fc02..a1dc2dc 100644
--- a/fs_mgr/include/fs_mgr_dm_linear.h
+++ b/fs_mgr/include/fs_mgr_dm_linear.h
@@ -68,7 +68,7 @@
// Destroy the block device for a logical partition, by name. If |timeout_ms|
// is non-zero, then this will block until the device path has been unlinked.
-bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms);
+bool DestroyLogicalPartition(const std::string& name);
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 21255df..e429d9f 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -29,6 +29,9 @@
"loop_control.cpp",
],
+ static_libs: [
+ "libext2_uuid",
+ ],
header_libs: [
"libbase_headers",
"liblog_headers",
@@ -46,6 +49,7 @@
static_libs: [
"libdm",
"libbase",
+ "libext2_uuid",
"libfs_mgr",
"liblog",
],
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index d54b6ef..d56a4b1 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -20,12 +20,20 @@
#include <sys/sysmacros.h>
#include <sys/types.h>
+#include <functional>
+#include <thread>
+
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
+#include <android-base/strings.h>
+#include <uuid/uuid.h>
namespace android {
namespace dm {
+using namespace std::literals;
+
DeviceMapper::DeviceMapper() : fd_(-1) {
fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
if (fd_ < 0) {
@@ -37,13 +45,13 @@
static DeviceMapper instance;
return instance;
}
+
// Creates a new device mapper device
-bool DeviceMapper::CreateDevice(const std::string& name) {
+bool DeviceMapper::CreateDevice(const std::string& name, const std::string& uuid) {
if (name.empty()) {
LOG(ERROR) << "Unnamed device mapper device creation is not supported";
return false;
}
-
if (name.size() >= DM_NAME_LEN) {
LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
return false;
@@ -51,6 +59,9 @@
struct dm_ioctl io;
InitIo(&io, name);
+ if (!uuid.empty()) {
+ snprintf(io.uuid, sizeof(io.uuid), "%s", uuid.c_str());
+ }
if (ioctl(fd_, DM_DEV_CREATE, &io)) {
PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
@@ -67,16 +78,6 @@
}
bool DeviceMapper::DeleteDevice(const std::string& name) {
- if (name.empty()) {
- LOG(ERROR) << "Unnamed device mapper device creation is not supported";
- return false;
- }
-
- if (name.size() >= DM_NAME_LEN) {
- LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
- return false;
- }
-
struct dm_ioctl io;
InitIo(&io, name);
@@ -93,9 +94,81 @@
return true;
}
-const std::unique_ptr<DmTable> DeviceMapper::table(const std::string& /* name */) const {
- // TODO(b/110035986): Return the table, as read from the kernel instead
- return nullptr;
+bool WaitForCondition(const std::function<bool()>& condition,
+ const std::chrono::milliseconds& timeout_ms) {
+ auto start_time = std::chrono::steady_clock::now();
+ while (true) {
+ if (condition()) return true;
+
+ std::this_thread::sleep_for(20ms);
+
+ auto now = std::chrono::steady_clock::now();
+ auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ if (time_elapsed > timeout_ms) return false;
+ }
+}
+
+static std::string GenerateUuid() {
+ uuid_t uuid_bytes;
+ uuid_generate(uuid_bytes);
+
+ char uuid_chars[37] = {};
+ uuid_unparse_lower(uuid_bytes, uuid_chars);
+
+ return std::string{uuid_chars};
+}
+
+bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+ const std::chrono::milliseconds& timeout_ms) {
+ std::string uuid = GenerateUuid();
+ if (!CreateDevice(name, uuid)) {
+ return false;
+ }
+
+ // We use the unique path for testing whether the device is ready. After
+ // that, it's safe to use the dm-N path which is compatible with callers
+ // that expect it to be formatted as such.
+ std::string unique_path;
+ if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
+ !GetDmDevicePathByName(name, path)) {
+ DeleteDevice(name);
+ return false;
+ }
+
+ if (timeout_ms <= std::chrono::milliseconds::zero()) {
+ return true;
+ }
+
+ auto condition = [&]() -> bool {
+ // If the file exists but returns EPERM or something, we consider the
+ // condition met.
+ if (access(unique_path.c_str(), F_OK) != 0) {
+ if (errno == ENOENT) return false;
+ }
+ return true;
+ };
+ if (!WaitForCondition(condition, timeout_ms)) {
+ LOG(ERROR) << "Timed out waiting for device path: " << unique_path;
+ DeleteDevice(name);
+ return false;
+ }
+ return true;
+}
+
+bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
+ struct dm_ioctl io;
+ InitIo(&io, name);
+ if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
+ PLOG(ERROR) << "Failed to get device path: " << name;
+ return false;
+ }
+
+ if (io.uuid[0] == '\0') {
+ LOG(ERROR) << "Device does not have a unique path: " << name;
+ return false;
+ }
+ *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
+ return true;
}
DmDeviceState DeviceMapper::GetState(const std::string& name) const {
@@ -111,11 +184,8 @@
}
bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
- if (!CreateDevice(name)) {
- return false;
- }
- if (!LoadTableAndActivate(name, table)) {
- DeleteDevice(name);
+ std::string ignore_path;
+ if (!CreateDevice(name, table, &ignore_path, 0ms)) {
return false;
}
return true;
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index c5881dd..7a834e2 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -52,10 +52,10 @@
public:
TempDevice(const std::string& name, const DmTable& table)
: dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
- valid_ = dm_.CreateDevice(name, table);
+ valid_ = dm_.CreateDevice(name, table, &path_, 5s);
}
TempDevice(TempDevice&& other) noexcept
- : dm_(other.dm_), name_(other.name_), valid_(other.valid_) {
+ : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
other.valid_ = false;
}
~TempDevice() {
@@ -70,29 +70,7 @@
valid_ = false;
return dm_.DeleteDevice(name_);
}
- bool WaitForUdev() const {
- auto start_time = std::chrono::steady_clock::now();
- while (true) {
- if (!access(path().c_str(), F_OK)) {
- return true;
- }
- if (errno != ENOENT) {
- return false;
- }
- std::this_thread::sleep_for(50ms);
- std::chrono::duration elapsed = std::chrono::steady_clock::now() - start_time;
- if (elapsed >= 5s) {
- return false;
- }
- }
- }
- std::string path() const {
- std::string device_path;
- if (!dm_.GetDmDevicePathByName(name_, &device_path)) {
- return "";
- }
- return device_path;
- }
+ std::string path() const { return path_; }
const std::string& name() const { return name_; }
bool valid() const { return valid_; }
@@ -109,6 +87,7 @@
private:
DeviceMapper& dm_;
std::string name_;
+ std::string path_;
bool valid_;
};
@@ -139,7 +118,6 @@
TempDevice dev("libdm-test-dm-linear", table);
ASSERT_TRUE(dev.valid());
ASSERT_FALSE(dev.path().empty());
- ASSERT_TRUE(dev.WaitForUdev());
auto& dm = DeviceMapper::Instance();
@@ -290,7 +268,6 @@
origin_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot-origin", origin_table);
ASSERT_TRUE(origin_dev_->valid());
ASSERT_FALSE(origin_dev_->path().empty());
- ASSERT_TRUE(origin_dev_->WaitForUdev());
// chunk size = 4K blocks.
DmTable snap_table;
@@ -302,7 +279,6 @@
snapshot_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot", snap_table);
ASSERT_TRUE(snapshot_dev_->valid());
ASSERT_FALSE(snapshot_dev_->path().empty());
- ASSERT_TRUE(snapshot_dev_->WaitForUdev());
setup_ok_ = true;
}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 08376c0..9c0c2f3 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -25,6 +25,7 @@
#include <sys/sysmacros.h>
#include <unistd.h>
+#include <chrono>
#include <memory>
#include <string>
#include <utility>
@@ -73,10 +74,6 @@
// Returns 'true' on success, false otherwise.
bool DeleteDevice(const std::string& name);
- // Reads the device mapper table from the device with given anme and
- // returns it in a DmTable object.
- const std::unique_ptr<DmTable> table(const std::string& name) const;
-
// Returns the current state of the underlying device mapper device
// with given name.
// One of INVALID, SUSPENDED or ACTIVE.
@@ -84,6 +81,33 @@
// Creates a device, loads the given table, and activates it. If the device
// is not able to be activated, it is destroyed, and false is returned.
+ // After creation, |path| contains the result of calling
+ // GetDmDevicePathByName, and the path is guaranteed to exist. If after
+ // |timeout_ms| the path is not available, the device will be deleted and
+ // this function will return false.
+ //
+ // This variant must be used when depending on the device path. The
+ // following manual sequence should not be used:
+ //
+ // 1. CreateDevice(name, table)
+ // 2. GetDmDevicePathByName(name, &path)
+ // 3. fs_mgr::WaitForFile(path, <timeout>)
+ //
+ // This sequence has a race condition where, if another process deletes a
+ // device, CreateDevice may acquire the same path. When this happens, the
+ // WaitForFile() may early-return since ueventd has not yet processed all
+ // of the outstanding udev events. The caller may unexpectedly get an
+ // ENOENT on a system call using the affected path.
+ //
+ // If |timeout_ms| is 0ms, then this function will return true whether or
+ // not |path| is available. It is the caller's responsibility to ensure
+ // there are no races.
+ bool CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+ const std::chrono::milliseconds& timeout_ms);
+
+ // Create a device and activate the given table, without waiting to acquire
+ // a valid path. If the caller will use GetDmDevicePathByName(), it should
+ // use the timeout variant above.
bool CreateDevice(const std::string& name, const DmTable& table);
// Loads the device mapper table from parameter into the underlying device
@@ -110,8 +134,21 @@
// Returns the path to the device mapper device node in '/dev' corresponding to
// 'name'. If the device does not exist, false is returned, and the path
// parameter is not set.
+ //
+ // This returns a path in the format "/dev/block/dm-N" that can be easily
+ // re-used with sysfs.
+ //
+ // WaitForFile() should not be used in conjunction with this call, since it
+ // could race with ueventd.
bool GetDmDevicePathByName(const std::string& name, std::string* path);
+ // Returns a device's unique path as generated by ueventd. This will return
+ // true as long as the device has been created, even if ueventd has not
+ // processed it yet.
+ //
+ // The formatting of this path is /dev/block/mapper/by-uuid/<uuid>.
+ bool GetDeviceUniquePath(const std::string& name, std::string* path);
+
// Returns the dev_t for the named device-mapper node.
bool GetDeviceNumber(const std::string& name, dev_t* dev);
@@ -158,18 +195,12 @@
// limit we are imposing here of 256.
static constexpr uint32_t kMaxPossibleDmDevices = 256;
+ bool CreateDevice(const std::string& name, const std::string& uuid = {});
bool GetTable(const std::string& name, uint32_t flags, std::vector<TargetInfo>* table);
-
void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
DeviceMapper();
- // Creates a device mapper device with given name.
- // Return 'true' on success and 'false' on failure to
- // create OR if a device mapper device with the same name already
- // exists.
- bool CreateDevice(const std::string& name);
-
int fd_;
// Non-copyable & Non-movable
DeviceMapper(const DeviceMapper&) = delete;
diff --git a/fs_mgr/libfs_avb/Android.bp b/fs_mgr/libfs_avb/Android.bp
index a3c76ab..414a186 100644
--- a/fs_mgr/libfs_avb/Android.bp
+++ b/fs_mgr/libfs_avb/Android.bp
@@ -61,6 +61,7 @@
"libavb",
"libavb_host_sysdeps",
"libdm",
+ "libext2_uuid",
"libfs_avb",
"libfstab",
"libgtest_host",
diff --git a/fs_mgr/libfs_avb/avb_util.cpp b/fs_mgr/libfs_avb/avb_util.cpp
index d9650f3..4505382 100644
--- a/fs_mgr/libfs_avb/avb_util.cpp
+++ b/fs_mgr/libfs_avb/avb_util.cpp
@@ -104,31 +104,23 @@
}
table.set_readonly(true);
+ std::chrono::milliseconds timeout = {};
+ if (wait_for_verity_dev) timeout = 1s;
+
+ std::string dev_path;
const std::string mount_point(Basename(fstab_entry->mount_point));
const std::string device_name(GetVerityDeviceName(*fstab_entry));
android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
- if (!dm.CreateDevice(device_name, table)) {
+ if (!dm.CreateDevice(device_name, table, &dev_path, timeout)) {
LERROR << "Couldn't create verity device!";
return false;
}
- std::string dev_path;
- if (!dm.GetDmDevicePathByName(device_name, &dev_path)) {
- LERROR << "Couldn't get verity device path!";
- return false;
- }
-
// Marks the underlying block device as read-only.
SetBlockDeviceReadOnly(fstab_entry->blk_device);
// Updates fstab_rec->blk_device to verity device name.
fstab_entry->blk_device = dev_path;
-
- // Makes sure we've set everything up properly.
- if (wait_for_verity_dev && !WaitForFile(dev_path, 1s)) {
- return false;
- }
-
return true;
}
diff --git a/init/Android.bp b/init/Android.bp
index 86dcb4c..ee339dd 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -74,7 +74,6 @@
shared_libs: [
"libbacktrace",
"libbase",
- "libbinder",
"libbootloader_message",
"libcutils",
"libcrypto",
@@ -243,11 +242,12 @@
],
whole_static_libs: ["libcap"],
shared_libs: [
- "libprotobuf-cpp-lite",
- "libhidl-gen-utils",
- "libprocessgroup",
- "liblog",
"libcutils",
+ "libhidl-gen-utils",
+ "libjsoncpp",
+ "liblog",
+ "libprocessgroup",
+ "libprotobuf-cpp-lite",
],
srcs: [
"action.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index 9017772..006e1bf 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -113,6 +113,7 @@
libunwindstack \
libbacktrace \
libmodprobe \
+ libext2_uuid \
LOCAL_SANITIZE := signed-integer-overflow
# First stage init is weird: it may start without stdout/stderr, and no /proc.
diff --git a/init/action.cpp b/init/action.cpp
index a169591..8cf7645 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -95,7 +95,7 @@
}
void Action::AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line) {
- commands_.emplace_back(f, false, std::move(args), line);
+ commands_.emplace_back(std::move(f), false, std::move(args), line);
}
std::size_t Action::NumCommands() const {
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
index 985b8ad..541c8f2 100644
--- a/init/action_manager.cpp
+++ b/init/action_manager.cpp
@@ -47,7 +47,7 @@
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
std::map<std::string, std::string>{});
- action->AddCommand(func, {name}, 0);
+ action->AddCommand(std::move(func), {name}, 0);
event_queue_.emplace(action.get());
actions_.emplace_back(std::move(action));
diff --git a/init/devices.cpp b/init/devices.cpp
index e8e6cd7..f6e453a 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -22,7 +22,6 @@
#include <unistd.h>
#include <chrono>
-#include <map>
#include <memory>
#include <string>
#include <thread>
@@ -111,24 +110,16 @@
// the supplied buffer with the dm module's instantiated name.
// If it doesn't start with a virtual block device, or there is some
// error, return false.
-static bool FindDmDevicePartition(const std::string& path, std::string* result) {
- result->clear();
+static bool FindDmDevice(const std::string& path, std::string* name, std::string* uuid) {
if (!StartsWith(path, "/devices/virtual/block/dm-")) return false;
- if (getpid() == 1) return false; // first_stage_init has no sepolicy needs
- static std::map<std::string, std::string> cache;
- // wait_for_file will not work, the content is also delayed ...
- for (android::base::Timer t; t.duration() < 200ms; std::this_thread::sleep_for(10ms)) {
- if (ReadFileToString("/sys" + path + "/dm/name", result) && !result->empty()) {
- // Got it, set cache with result, when node arrives
- cache[path] = *result = Trim(*result);
- return true;
- }
+ if (!ReadFileToString("/sys" + path + "/dm/name", name)) {
+ return false;
}
- auto it = cache.find(path);
- if ((it == cache.end()) || (it->second.empty())) return false;
- // Return cached results, when node goes away
- *result = it->second;
+ ReadFileToString("/sys" + path + "/dm/uuid", uuid);
+
+ *name = android::base::Trim(*name);
+ *uuid = android::base::Trim(*uuid);
return true;
}
@@ -325,6 +316,7 @@
std::string device;
std::string type;
std::string partition;
+ std::string uuid;
if (FindPlatformDevice(uevent.path, &device)) {
// Skip /devices/platform or /devices/ if present
@@ -342,8 +334,12 @@
type = "pci";
} else if (FindVbdDevicePrefix(uevent.path, &device)) {
type = "vbd";
- } else if (FindDmDevicePartition(uevent.path, &partition)) {
- return {"/dev/block/mapper/" + partition};
+ } else if (FindDmDevice(uevent.path, &partition, &uuid)) {
+ std::vector<std::string> symlinks = {"/dev/block/mapper/" + partition};
+ if (!uuid.empty()) {
+ symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid);
+ }
+ return symlinks;
} else {
return {};
}
@@ -379,10 +375,41 @@
return links;
}
+static void RemoveDeviceMapperLinks(const std::string& devpath) {
+ std::vector<std::string> dirs = {
+ "/dev/block/mapper",
+ "/dev/block/mapper/by-uuid",
+ };
+ for (const auto& dir : dirs) {
+ if (access(dir.c_str(), F_OK) != 0) continue;
+
+ std::unique_ptr<DIR, decltype(&closedir)> dh(opendir(dir.c_str()), closedir);
+ if (!dh) {
+ PLOG(ERROR) << "Failed to open directory " << dir;
+ continue;
+ }
+
+ struct dirent* dp;
+ std::string link_path;
+ while ((dp = readdir(dh.get())) != nullptr) {
+ if (dp->d_type != DT_LNK) continue;
+
+ auto path = dir + "/" + dp->d_name;
+ if (Readlink(path, &link_path) && link_path == devpath) {
+ unlink(path.c_str());
+ }
+ }
+ }
+}
+
void DeviceHandler::HandleDevice(const std::string& action, const std::string& devpath, bool block,
int major, int minor, const std::vector<std::string>& links) const {
if (action == "add") {
MakeDevice(devpath, block, major, minor, links);
+ }
+
+ // We don't have full device-mapper information until a change event is fired.
+ if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
for (const auto& link : links) {
if (!mkdir_recursive(Dirname(link), 0755)) {
PLOG(ERROR) << "Failed to create directory " << Dirname(link);
@@ -401,6 +428,9 @@
}
if (action == "remove") {
+ if (StartsWith(devpath, "/dev/block/dm-")) {
+ RemoveDeviceMapperLinks(devpath);
+ }
for (const auto& link : links) {
std::string link_path;
if (Readlink(link, &link_path) && link_path == devpath) {
diff --git a/init/devices.h b/init/devices.h
index 9d39eaa..442c53f 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -84,9 +84,9 @@
};
Subsystem() {}
- Subsystem(const std::string& name) : name_(name) {}
- Subsystem(const std::string& name, DevnameSource source, const std::string& dir_name)
- : name_(name), devname_source_(source), dir_name_(dir_name) {}
+ Subsystem(std::string name) : name_(std::move(name)) {}
+ Subsystem(std::string name, DevnameSource source, std::string dir_name)
+ : name_(std::move(name)), devname_source_(source), dir_name_(std::move(dir_name)) {}
// Returns the full path for a uevent of a device that is a member of this subsystem,
// according to the rules parsed from ueventd.rc
diff --git a/init/devices_test.cpp b/init/devices_test.cpp
index 3e7c1a8..c408bc1 100644
--- a/init/devices_test.cpp
+++ b/init/devices_test.cpp
@@ -30,7 +30,7 @@
class DeviceHandlerTester {
public:
void TestGetSymlinks(const std::string& platform_device, const Uevent& uevent,
- const std::vector<std::string> expected_links) {
+ const std::vector<std::string>& expected_links) {
TemporaryDir fake_sys_root;
device_handler_.sysfs_mount_point_ = fake_sys_root.path;
diff --git a/init/host_init_verifier.cpp b/init/host_init_verifier.cpp
index 8aa3509..92c2aa5 100644
--- a/init/host_init_verifier.cpp
+++ b/init/host_init_verifier.cpp
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <fstream>
#include <iostream>
#include <iterator>
#include <string>
@@ -29,6 +30,7 @@
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
+#include <json/json.h>
#include "action.h"
#include "action_manager.h"
@@ -129,21 +131,33 @@
return nullptr;
}
-static std::optional<std::set<std::string>> ReadKnownInterfaces(
- const std::string& known_interfaces_file) {
- if (known_interfaces_file.empty()) {
- LOG(WARNING) << "Missing a known interfaces file.";
+static std::optional<android::init::InterfaceInheritanceHierarchyMap>
+ReadInterfaceInheritanceHierarchy(const std::string& interface_inheritance_hierarchy_file) {
+ if (interface_inheritance_hierarchy_file.empty()) {
+ LOG(WARNING) << "Missing an interface inheritance hierarchy file.";
return {};
}
- std::string known_interfaces;
- if (!ReadFileToString(known_interfaces_file, &known_interfaces)) {
- LOG(ERROR) << "Failed to read known interfaces file '" << known_interfaces_file << "'";
+ Json::Value root;
+ Json::Reader reader;
+ std::ifstream stream(interface_inheritance_hierarchy_file);
+ if (!reader.parse(stream, root)) {
+ LOG(ERROR) << "Failed to read interface inheritance hierarchy file: "
+ << interface_inheritance_hierarchy_file << "\n"
+ << reader.getFormattedErrorMessages();
return {};
}
- auto interfaces = Split(known_interfaces, " ");
- return std::set<std::string>(interfaces.begin(), interfaces.end());
+ android::init::InterfaceInheritanceHierarchyMap result;
+ for (const Json::Value& entry : root) {
+ std::set<std::string> inherited_interfaces;
+ for (const Json::Value& intf : entry["inheritedInterfaces"]) {
+ inherited_interfaces.insert(intf.asString());
+ }
+ result[entry["interface"].asString()] = inherited_interfaces;
+ }
+
+ return result;
}
namespace android {
@@ -169,7 +183,7 @@
android::base::InitLogging(argv, &android::base::StdioLogger);
android::base::SetMinimumLogSeverity(android::base::ERROR);
- std::string known_interfaces_file;
+ std::string interface_inheritance_hierarchy_file;
while (true) {
static const struct option long_options[] = {
@@ -177,7 +191,7 @@
{nullptr, 0, nullptr, 0},
};
- int arg = getopt_long(argc, argv, "p:k:", long_options, nullptr);
+ int arg = getopt_long(argc, argv, "p:i:", long_options, nullptr);
if (arg == -1) {
break;
@@ -190,8 +204,8 @@
case 'p':
passwd_files.emplace_back(optarg);
break;
- case 'k':
- known_interfaces_file = optarg;
+ case 'i':
+ interface_inheritance_hierarchy_file = optarg;
break;
default:
std::cerr << "getprop: getopt returned invalid result: " << arg << std::endl;
@@ -213,8 +227,10 @@
ServiceList& sl = ServiceList::GetInstance();
Parser parser;
parser.AddSectionParser(
- "service", std::make_unique<ServiceParser>(&sl, nullptr,
- ReadKnownInterfaces(known_interfaces_file)));
+ "service",
+ std::make_unique<ServiceParser>(
+ &sl, nullptr,
+ ReadInterfaceInheritanceHierarchy(interface_inheritance_hierarchy_file)));
parser.AddSectionParser("on", std::make_unique<ActionParser>(&am, nullptr));
parser.AddSectionParser("import", std::make_unique<HostImportParser>());
diff --git a/init/init.cpp b/init/init.cpp
index 675f3e5..5dba54d 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -50,10 +50,6 @@
#include <processgroup/setup.h>
#include <selinux/android.h>
-#ifndef RECOVERY
-#include <binder/ProcessState.h>
-#endif
-
#include "action_parser.h"
#include "boringssl_self_test.h"
#include "builtins.h"
@@ -139,12 +135,12 @@
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
+ // late_import is available only in Q and earlier release. As we don't
+ // have system_ext in those versions, skip late_import for system_ext.
+ parser.ParseConfig("/system_ext/etc/init");
if (!parser.ParseConfig("/product/etc/init")) {
late_import_paths.emplace_back("/product/etc/init");
}
- if (!parser.ParseConfig("/product_services/etc/init")) {
- late_import_paths.emplace_back("/product_services/etc/init");
- }
if (!parser.ParseConfig("/odm/etc/init")) {
late_import_paths.emplace_back("/odm/etc/init");
}
@@ -453,24 +449,6 @@
return {};
}
-static Result<void> InitBinder(const BuiltinArguments& args) {
- // init's use of binder is very limited. init cannot:
- // - have any binder threads
- // - receive incoming binder calls
- // - pass local binder services to remote processes
- // - use death recipients
- // The main supported usecases are:
- // - notifying other daemons (oneway calls only)
- // - retrieving data that is necessary to boot
- // Also, binder can't be used by recovery.
-#ifndef RECOVERY
- android::ProcessState::self()->setThreadPoolMaxThreadCount(0);
- android::ProcessState::self()->setCallRestriction(
- ProcessState::CallRestriction::ERROR_IF_NOT_ONEWAY);
-#endif
- return {};
-}
-
// Set the UDC controller for the ConfigFS USB Gadgets.
// Read the UDC controller in use from "/sys/class/udc".
// In case of multiple UDC controllers select the first one.
@@ -766,9 +744,6 @@
// wasn't ready immediately after wait_for_coldboot_done
am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
- // Initialize binder before bringing up other system services
- am.QueueBuiltinAction(InitBinder, "InitBinder");
-
// Don't mount filesystems or start core system services in charger mode.
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
diff --git a/init/keychords.cpp b/init/keychords.cpp
index d0ca3e7..5f2682b 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -285,7 +285,7 @@
void Keychords::Start(Epoll* epoll, std::function<void(const std::vector<int>&)> handler) {
epoll_ = epoll;
- handler_ = handler;
+ handler_ = std::move(handler);
if (entries_.size()) GeteventOpenDevice();
}
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index b0b63c5..791a019 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -140,11 +140,11 @@
}
}
free(buf);
- for (auto entry : untouched) {
+ for (auto& entry : untouched) {
SetMountProperty(entry, false);
mounts_.erase(entry);
}
- for (auto entry : touched) {
+ for (auto& entry : touched) {
SetMountProperty(entry, true);
mounts_.emplace(std::move(entry));
}
diff --git a/init/parser.cpp b/init/parser.cpp
index bbfbdc6..6ab61cb 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -37,7 +37,7 @@
}
void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
- line_callbacks_.emplace_back(prefix, callback);
+ line_callbacks_.emplace_back(prefix, std::move(callback));
}
void Parser::ParseData(const std::string& filename, std::string* data) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index b89914f..8623c30 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -782,10 +782,9 @@
"brand", "device", "manufacturer", "model", "name",
};
const char* RO_PRODUCT_PROPS_ALLOWED_SOURCES[] = {
- "odm", "product", "product_services", "system", "vendor",
+ "odm", "product", "system_ext", "system", "vendor",
};
- const char* RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER =
- "product,product_services,odm,vendor,system";
+ const char* RO_PRODUCT_PROPS_DEFAULT_SOURCE_ORDER = "product,odm,vendor,system_ext,system";
const std::string EMPTY = "";
std::string ro_product_props_source_order =
@@ -892,6 +891,7 @@
}
}
load_properties_from_file("/system/build.prop", nullptr, &properties);
+ load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
load_properties_from_file("/vendor/default.prop", nullptr, &properties);
load_properties_from_file("/vendor/build.prop", nullptr, &properties);
if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
@@ -901,7 +901,6 @@
load_properties_from_file("/odm/build.prop", nullptr, &properties);
}
load_properties_from_file("/product/build.prop", nullptr, &properties);
- load_properties_from_file("/product_services/build.prop", nullptr, &properties);
load_properties_from_file("/factory/factory.prop", "ro.*", &properties);
if (load_debug_prop) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index d9d885c..cb54d34 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -636,11 +636,9 @@
bool run_fsck = false;
bool command_invalid = false;
- if (cmd_params.size() > 3) {
- command_invalid = true;
- } else if (cmd_params[0] == "shutdown") {
+ if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
- if (cmd_params.size() == 2) {
+ if (cmd_params.size() >= 2) {
if (cmd_params[1] == "userrequested") {
// The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
// Run fsck once the file system is remounted in read-only mode.
@@ -671,6 +669,13 @@
"bootloader_message: "
<< err;
}
+ } else if (reboot_target == "recovery") {
+ const std::vector<std::string> options = {};
+ std::string err;
+ if (!write_bootloader_message(options, &err)) {
+ LOG(ERROR) << "Failed to set bootloader message: " << err;
+ return false;
+ }
} else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
reboot_target == "fastboot") {
std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
@@ -686,9 +691,9 @@
reboot_target = "recovery";
}
- // If there is an additional parameter, pass it along
- if ((cmd_params.size() == 3) && cmd_params[2].size()) {
- reboot_target += "," + cmd_params[2];
+ // If there are additional parameter, pass them along
+ for (size_t i = 2; (cmd_params.size() > i) && cmd_params[i].size(); ++i) {
+ reboot_target += "," + cmd_params[i];
}
}
} else {
diff --git a/init/security.cpp b/init/security.cpp
index 5d87f3c..586d0c7 100644
--- a/init/security.cpp
+++ b/init/security.cpp
@@ -83,7 +83,7 @@
return {};
}
-static bool SetHighestAvailableOptionValue(std::string path, int min, int max) {
+static bool SetHighestAvailableOptionValue(const std::string& path, int min, int max) {
std::ifstream inf(path, std::fstream::in);
if (!inf) {
LOG(ERROR) << "Cannot open for reading: " << path;
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index ba35104..88ce364 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -18,6 +18,9 @@
#include <linux/input.h>
+#include <algorithm>
+#include <sstream>
+
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
@@ -152,12 +155,6 @@
return Error() << "Interface name must not be a value name '" << interface_name << "'";
}
- if (known_interfaces_ && known_interfaces_->count(interface_name) == 0) {
- return Error() << "Interface is not in the known set of hidl_interfaces: '"
- << interface_name << "'. Please ensure the interface is built "
- << "by a hidl_interface target.";
- }
-
const std::string fullname = interface_name + "/" + instance_name;
for (const auto& svc : *service_list_) {
@@ -540,6 +537,37 @@
return {};
}
+ if (interface_inheritance_hierarchy_) {
+ std::set<std::string> interface_names;
+ for (const std::string& intf : service_->interfaces()) {
+ interface_names.insert(Split(intf, "/")[0]);
+ }
+ std::ostringstream error_stream;
+ for (const std::string& intf : interface_names) {
+ if (interface_inheritance_hierarchy_->count(intf) == 0) {
+ error_stream << "\nInterface is not in the known set of hidl_interfaces: '" << intf
+ << "'. Please ensure the interface is spelled correctly and built "
+ << "by a hidl_interface target.";
+ continue;
+ }
+ const std::set<std::string>& required_interfaces =
+ (*interface_inheritance_hierarchy_)[intf];
+ std::set<std::string> diff;
+ std::set_difference(required_interfaces.begin(), required_interfaces.end(),
+ interface_names.begin(), interface_names.end(),
+ std::inserter(diff, diff.begin()));
+ if (!diff.empty()) {
+ error_stream << "\nInterface '" << intf << "' requires its full inheritance "
+ << "hierarchy to be listed in this init_rc file. Missing "
+ << "interfaces: [" << base::Join(diff, " ") << "]";
+ }
+ }
+ const std::string& errors = error_stream.str();
+ if (!errors.empty()) {
+ return Error() << errors;
+ }
+ }
+
Service* old_service = service_list_->FindService(service_->name());
if (old_service) {
if (!service_->is_override()) {
diff --git a/init/service_parser.h b/init/service_parser.h
index 5a16768..5ad26ef 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -26,13 +26,16 @@
namespace android {
namespace init {
+using InterfaceInheritanceHierarchyMap = std::map<std::string, std::set<std::string>>;
+
class ServiceParser : public SectionParser {
public:
- ServiceParser(ServiceList* service_list, std::vector<Subcontext>* subcontexts,
- const std::optional<std::set<std::string>>& known_interfaces)
+ ServiceParser(
+ ServiceList* service_list, std::vector<Subcontext>* subcontexts,
+ const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
: service_list_(service_list),
subcontexts_(subcontexts),
- known_interfaces_(known_interfaces),
+ interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
service_(nullptr) {}
Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
int line) override;
@@ -85,7 +88,7 @@
ServiceList* service_list_;
std::vector<Subcontext>* subcontexts_;
- std::optional<std::set<std::string>> known_interfaces_;
+ std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
std::unique_ptr<Service> service_;
std::string filename_;
};
diff --git a/init/test_function_map.h b/init/test_function_map.h
index 293f1f9..466836c 100644
--- a/init/test_function_map.h
+++ b/init/test_function_map.h
@@ -30,17 +30,17 @@
public:
// Helper for argument-less functions
using BuiltinFunctionNoArgs = std::function<void(void)>;
- void Add(const std::string& name, const BuiltinFunctionNoArgs function) {
- Add(name, 0, 0, false, [function](const BuiltinArguments&) {
- function();
+ void Add(const std::string& name, BuiltinFunctionNoArgs function) {
+ Add(name, 0, 0, false, [f = std::move(function)](const BuiltinArguments&) {
+ f();
return Result<void>{};
});
}
void Add(const std::string& name, std::size_t min_parameters, std::size_t max_parameters,
- bool run_in_subcontext, const BuiltinFunction function) {
- builtin_functions_[name] =
- make_tuple(min_parameters, max_parameters, make_pair(run_in_subcontext, function));
+ bool run_in_subcontext, BuiltinFunction function) {
+ builtin_functions_[name] = make_tuple(min_parameters, max_parameters,
+ make_pair(run_in_subcontext, std::move(function)));
}
private:
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 3b9de0f..8b2cf62 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -146,7 +146,7 @@
void ColdBoot::RegenerateUevents() {
uevent_listener_.RegenerateUevents([this](const Uevent& uevent) {
- uevent_queue_.emplace_back(std::move(uevent));
+ uevent_queue_.emplace_back(uevent);
return ListenerAction::kContinue;
});
}
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 897a169..b29638c 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -106,7 +106,7 @@
// oem/ file-system since the intent is to provide support for customized
// portions of a separate vendor.img or oem.img. Has to remain open so that
// customization can also land on /system/vendor, /system/oem, /system/odm,
-// /system/product or /system/product_services.
+// /system/product or /system/system_ext.
//
// We expect build-time checking or filtering when constructing the associated
// fs_config_* files (see build/tools/fs_config/fs_config_generate.c)
@@ -118,15 +118,12 @@
static const char odm_conf_file[] = "/odm/etc/fs_config_files";
static const char product_conf_dir[] = "/product/etc/fs_config_dirs";
static const char product_conf_file[] = "/product/etc/fs_config_files";
-static const char product_services_conf_dir[] = "/product_services/etc/fs_config_dirs";
-static const char product_services_conf_file[] = "/product_services/etc/fs_config_files";
+static const char system_ext_conf_dir[] = "/system_ext/etc/fs_config_dirs";
+static const char system_ext_conf_file[] = "/system_ext/etc/fs_config_files";
static const char* conf[][2] = {
- {sys_conf_file, sys_conf_dir},
- {ven_conf_file, ven_conf_dir},
- {oem_conf_file, oem_conf_dir},
- {odm_conf_file, odm_conf_dir},
- {product_conf_file, product_conf_dir},
- {product_services_conf_file, product_services_conf_dir},
+ {sys_conf_file, sys_conf_dir}, {ven_conf_file, ven_conf_dir},
+ {oem_conf_file, oem_conf_dir}, {odm_conf_file, odm_conf_dir},
+ {product_conf_file, product_conf_dir}, {system_ext_conf_file, system_ext_conf_dir},
};
// Do not use android_files to grant Linux capabilities. Use ambient capabilities in their
@@ -158,9 +155,9 @@
{ 00600, AID_ROOT, AID_ROOT, 0, "product/build.prop" },
{ 00444, AID_ROOT, AID_ROOT, 0, product_conf_dir + 1 },
{ 00444, AID_ROOT, AID_ROOT, 0, product_conf_file + 1 },
- { 00600, AID_ROOT, AID_ROOT, 0, "product_services/build.prop" },
- { 00444, AID_ROOT, AID_ROOT, 0, product_services_conf_dir + 1 },
- { 00444, AID_ROOT, AID_ROOT, 0, product_services_conf_file + 1 },
+ { 00600, AID_ROOT, AID_ROOT, 0, "system_ext/build.prop" },
+ { 00444, AID_ROOT, AID_ROOT, 0, system_ext_conf_dir + 1 },
+ { 00444, AID_ROOT, AID_ROOT, 0, system_ext_conf_file + 1 },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/debuggerd" },
@@ -248,9 +245,9 @@
}
// if path is "odm/<stuff>", "oem/<stuff>", "product/<stuff>",
-// "product_services/<stuff>" or "vendor/<stuff>"
+// "system_ext/<stuff>" or "vendor/<stuff>"
static bool is_partition(const std::string& path) {
- static const char* partitions[] = {"odm/", "oem/", "product/", "product_services/", "vendor/"};
+ static const char* partitions[] = {"odm/", "oem/", "product/", "system_ext/", "vendor/"};
for (size_t i = 0; i < (sizeof(partitions) / sizeof(partitions[0])); ++i) {
if (StartsWith(path, partitions[i])) return true;
}
@@ -285,10 +282,8 @@
if (fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0) return true;
// Check match between logical partition's files and patterns.
- static constexpr const char* kLogicalPartitions[] = {"system/product/",
- "system/product_services/",
- "system/vendor/",
- "vendor/odm/"};
+ static constexpr const char* kLogicalPartitions[] = {"system/product/", "system/system_ext/",
+ "system/vendor/", "vendor/odm/"};
for (auto& logical_partition : kLogicalPartitions) {
if (StartsWith(input, logical_partition)) {
std::string input_in_partition = input.substr(input.find('/') + 1);
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 5423de5..a0a6b4f 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -246,6 +246,7 @@
"tests/files/offline/jit_debug_x86/*",
"tests/files/offline/jit_map_arm/*",
"tests/files/offline/gnu_debugdata_arm/*",
+ "tests/files/offline/load_bias_ro_rx_x86_64/*",
"tests/files/offline/offset_arm/*",
"tests/files/offline/shared_lib_in_apk_arm64/*",
"tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index f0e4138..bdfee01 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -197,6 +197,7 @@
template <typename EhdrType, typename PhdrType>
void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
uint64_t offset = ehdr.e_phoff;
+ bool first_exec_load_header = true;
for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
PhdrType phdr;
if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
@@ -212,9 +213,11 @@
pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
static_cast<size_t>(phdr.p_memsz)};
- if (phdr.p_offset == 0) {
- *load_bias = phdr.p_vaddr;
+ // Only set the load bias from the first executable load header.
+ if (first_exec_load_header && phdr.p_vaddr > phdr.p_offset) {
+ *load_bias = phdr.p_vaddr - phdr.p_offset;
}
+ first_exec_load_header = false;
break;
}
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index cdc927a..f9ee9eb 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -360,7 +360,7 @@
uint64_t load_bias = 0;
ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0U, load_bias);
+ EXPECT_EQ(0x1001U, load_bias);
const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
ASSERT_EQ(1U, pt_loads.size());
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index baada82..e6158a2 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -1457,4 +1457,77 @@
EXPECT_EQ(0xc2044218, unwinder.frames()[0].sp);
}
+TEST_F(UnwindOfflineTest, load_bias_ro_rx_x86_64) {
+ ASSERT_NO_FATAL_FAILURE(Init("load_bias_ro_rx_x86_64/", ARCH_X86_64));
+
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.Unwind();
+
+ std::string frame_info(DumpFrames(unwinder));
+ ASSERT_EQ(17U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 00000000000e9dd4 libc.so (__write+20)\n"
+ " #01 pc 000000000007ab9c libc.so (_IO_file_write+44)\n"
+ " #02 pc 0000000000079f3e libc.so\n"
+ " #03 pc 000000000007bce8 libc.so (_IO_do_write+24)\n"
+ " #04 pc 000000000007b26e libc.so (_IO_file_xsputn+270)\n"
+ " #05 pc 000000000004f7f9 libc.so (_IO_vfprintf+1945)\n"
+ " #06 pc 0000000000057cb5 libc.so (_IO_printf+165)\n"
+ " #07 pc 0000000000ed1796 perfetto_unittests "
+ "(testing::internal::PrettyUnitTestResultPrinter::OnTestIterationStart(testing::UnitTest "
+ "const&, int)+374)\n"
+ " #08 pc 0000000000ed30fd perfetto_unittests "
+ "(testing::internal::TestEventRepeater::OnTestIterationStart(testing::UnitTest const&, "
+ "int)+125)\n"
+ " #09 pc 0000000000ed5e25 perfetto_unittests "
+ "(testing::internal::UnitTestImpl::RunAllTests()+581)\n"
+ " #10 pc 0000000000ef63f3 perfetto_unittests "
+ "(_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS0_12UnitTestImplEbEET0_PT_"
+ "MS4_FS3_vEPKc+131)\n"
+ " #11 pc 0000000000ee2a21 perfetto_unittests "
+ "(_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS0_12UnitTestImplEbEET0_PT_MS4_"
+ "FS3_vEPKc+113)\n"
+ " #12 pc 0000000000ed5bb9 perfetto_unittests (testing::UnitTest::Run()+185)\n"
+ " #13 pc 0000000000e900f0 perfetto_unittests (RUN_ALL_TESTS()+16)\n"
+ " #14 pc 0000000000e900d8 perfetto_unittests (main+56)\n"
+ " #15 pc 000000000002352a libc.so (__libc_start_main+234)\n"
+ " #16 pc 0000000000919029 perfetto_unittests (_start+41)\n",
+ frame_info);
+
+ EXPECT_EQ(0x7f9326a57dd4ULL, unwinder.frames()[0].pc);
+ EXPECT_EQ(0x7ffd224153c8ULL, unwinder.frames()[0].sp);
+ EXPECT_EQ(0x7f93269e8b9cULL, unwinder.frames()[1].pc);
+ EXPECT_EQ(0x7ffd224153d0ULL, unwinder.frames()[1].sp);
+ EXPECT_EQ(0x7f93269e7f3eULL, unwinder.frames()[2].pc);
+ EXPECT_EQ(0x7ffd22415400ULL, unwinder.frames()[2].sp);
+ EXPECT_EQ(0x7f93269e9ce8ULL, unwinder.frames()[3].pc);
+ EXPECT_EQ(0x7ffd22415440ULL, unwinder.frames()[3].sp);
+ EXPECT_EQ(0x7f93269e926eULL, unwinder.frames()[4].pc);
+ EXPECT_EQ(0x7ffd22415450ULL, unwinder.frames()[4].sp);
+ EXPECT_EQ(0x7f93269bd7f9ULL, unwinder.frames()[5].pc);
+ EXPECT_EQ(0x7ffd22415490ULL, unwinder.frames()[5].sp);
+ EXPECT_EQ(0x7f93269c5cb5ULL, unwinder.frames()[6].pc);
+ EXPECT_EQ(0x7ffd22415a10ULL, unwinder.frames()[6].sp);
+ EXPECT_EQ(0xed1796ULL, unwinder.frames()[7].pc);
+ EXPECT_EQ(0x7ffd22415af0ULL, unwinder.frames()[7].sp);
+ EXPECT_EQ(0xed30fdULL, unwinder.frames()[8].pc);
+ EXPECT_EQ(0x7ffd22415b70ULL, unwinder.frames()[8].sp);
+ EXPECT_EQ(0xed5e25ULL, unwinder.frames()[9].pc);
+ EXPECT_EQ(0x7ffd22415bb0ULL, unwinder.frames()[9].sp);
+ EXPECT_EQ(0xef63f3ULL, unwinder.frames()[10].pc);
+ EXPECT_EQ(0x7ffd22415c60ULL, unwinder.frames()[10].sp);
+ EXPECT_EQ(0xee2a21ULL, unwinder.frames()[11].pc);
+ EXPECT_EQ(0x7ffd22415cc0ULL, unwinder.frames()[11].sp);
+ EXPECT_EQ(0xed5bb9ULL, unwinder.frames()[12].pc);
+ EXPECT_EQ(0x7ffd22415d40ULL, unwinder.frames()[12].sp);
+ EXPECT_EQ(0xe900f0ULL, unwinder.frames()[13].pc);
+ EXPECT_EQ(0x7ffd22415d90ULL, unwinder.frames()[13].sp);
+ EXPECT_EQ(0xe900d8ULL, unwinder.frames()[14].pc);
+ EXPECT_EQ(0x7ffd22415da0ULL, unwinder.frames()[14].sp);
+ EXPECT_EQ(0x7f932699152aULL, unwinder.frames()[15].pc);
+ EXPECT_EQ(0x7ffd22415dd0ULL, unwinder.frames()[15].sp);
+ EXPECT_EQ(0x919029ULL, unwinder.frames()[16].pc);
+ EXPECT_EQ(0x7ffd22415e90ULL, unwinder.frames()[16].sp);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
new file mode 100644
index 0000000..63383d0
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
new file mode 100644
index 0000000..ba5a31b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
@@ -0,0 +1,3 @@
+200000-919000 r--p 0 00:00 0 perfetto_unittests
+919000-1a0c000 r-xp 719000 00:00 0 perfetto_unittests
+7f932696e000-7f9326b23000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
new file mode 100644
index 0000000..a30e599
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
new file mode 100644
index 0000000..6cb4055
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
@@ -0,0 +1,17 @@
+rax: 3b
+rbx: 3b
+rcx: 7f9326a57dd4
+rdx: 3b
+r8: 7ffd22415b09
+r9: 7ffd224155e0
+r10: 0
+r11: 246
+r12: 7f9326d28760
+r13: 3b
+r14: 7f9326d23760
+r15: 3b
+rdi: 1
+rsi: 2678850
+rbp: 2678850
+rsp: 7ffd224153c8
+rip: 7f9326a57dd4
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
new file mode 100644
index 0000000..4edfe07
--- /dev/null
+++ b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
Binary files differ
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index a105474..3a02a8a 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -188,9 +188,6 @@
// ---------------------------------------------------------------------------
namespace android {
-class TextOutput;
-TextOutput& printWeakPointer(TextOutput& to, const void* val);
-
// ---------------------------------------------------------------------------
#define COMPARE_WEAK(_op_) \
@@ -459,9 +456,6 @@
weakref_type* m_refs;
};
-template <typename T>
-TextOutput& operator<<(TextOutput& to, const wp<T>& val);
-
#undef COMPARE_WEAK
// ---------------------------------------------------------------------------
@@ -635,12 +629,6 @@
}
}
-template <typename T>
-inline TextOutput& operator<<(TextOutput& to, const wp<T>& val)
-{
- return printWeakPointer(to, val.unsafe_get());
-}
-
// ---------------------------------------------------------------------------
// this class just serves as a namespace so TYPE::moveReferences can stay
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 48140b8..42af751 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -79,6 +79,7 @@
#define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes"
#define ZONEINFO_PATH "/proc/zoneinfo"
#define MEMINFO_PATH "/proc/meminfo"
+#define PROC_STATUS_TGID_FIELD "Tgid:"
#define LINE_MAX 128
/* Android Logger event logtags (see event.logtags) */
@@ -551,6 +552,49 @@
(to->tv_nsec - from->tv_nsec) / (long)NS_PER_MS;
}
+static int proc_get_tgid(int pid) {
+ char path[PATH_MAX];
+ char buf[PAGE_SIZE];
+ int fd;
+ ssize_t size;
+ char *pos;
+ int64_t tgid = -1;
+
+ snprintf(path, PATH_MAX, "/proc/%d/status", pid);
+ fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ return -1;
+ }
+
+ size = read_all(fd, buf, sizeof(buf) - 1);
+ if (size < 0) {
+ goto out;
+ }
+ buf[size] = 0;
+
+ pos = buf;
+ while (true) {
+ pos = strstr(pos, PROC_STATUS_TGID_FIELD);
+ /* Stop if TGID tag not found or found at the line beginning */
+ if (pos == NULL || pos == buf || pos[-1] == '\n') {
+ break;
+ }
+ pos++;
+ }
+
+ if (pos == NULL) {
+ goto out;
+ }
+
+ pos += strlen(PROC_STATUS_TGID_FIELD);
+ while (*pos == ' ') pos++;
+ parse_int64(pos, &tgid);
+
+out:
+ close(fd);
+ return (int)tgid;
+}
+
static void cmd_procprio(LMKD_CTRL_PACKET packet) {
struct proc *procp;
char path[80];
@@ -559,6 +603,7 @@
struct lmk_procprio params;
bool is_system_server;
struct passwd *pwdrec;
+ int tgid;
lmkd_pack_get_procprio(packet, ¶ms);
@@ -568,6 +613,14 @@
return;
}
+ /* Check if registered process is a thread group leader */
+ tgid = proc_get_tgid(params.pid);
+ if (tgid >= 0 && tgid != params.pid) {
+ ALOGE("Attempt to register a task that is not a thread group leader (tid %d, tgid %d)",
+ params.pid, tgid);
+ return;
+ }
+
/* gid containing AID_READPROC required */
/* CAP_SYS_RESOURCE required */
/* CAP_DAC_OVERRIDE required */
@@ -1332,6 +1385,7 @@
static int kill_one_process(struct proc* procp, int min_oom_score) {
int pid = procp->pid;
uid_t uid = procp->uid;
+ int tgid;
char *taskname;
int tasksize;
int r;
@@ -1345,6 +1399,12 @@
(void)(min_oom_score);
#endif
+ tgid = proc_get_tgid(pid);
+ if (tgid >= 0 && tgid != pid) {
+ ALOGE("Possible pid reuse detected (pid %d, tgid %d)!", pid, tgid);
+ goto out;
+ }
+
taskname = proc_get_name(pid);
if (!taskname) {
goto out;
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index b1616d3..a6ea2ab 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,6 +7,7 @@
# absolute path of an executable is selected.
dir.system = /system/bin/
dir.system = /system/xbin/
+dir.system = /%SYSTEM_EXT%/bin/
dir.system = /%PRODUCT%/bin/
dir.vendor = /odm/bin/
@@ -48,8 +49,8 @@
namespace.default.visible = true
namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
# We can't have entire /system/${LIB} as permitted paths because doing so
# makes it possible to load libs in /system/${LIB}/vndk* directories by
@@ -61,12 +62,15 @@
namespace.default.permitted.paths = /system/${LIB}/drm
namespace.default.permitted.paths += /system/${LIB}/extractors
namespace.default.permitted.paths += /system/${LIB}/hw
+namespace.default.permitted.paths += /%SYSTEM_EXT%/${LIB}
namespace.default.permitted.paths += /%PRODUCT%/${LIB}
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/${LIB}
# These are where odex files are located. libart has to be able to dlopen the files
namespace.default.permitted.paths += /system/framework
namespace.default.permitted.paths += /system/app
namespace.default.permitted.paths += /system/priv-app
+namespace.default.permitted.paths += /%SYSTEM_EXT%/framework
+namespace.default.permitted.paths += /%SYSTEM_EXT%/app
+namespace.default.permitted.paths += /%SYSTEM_EXT%/priv-app
namespace.default.permitted.paths += /vendor/framework
namespace.default.permitted.paths += /vendor/app
namespace.default.permitted.paths += /vendor/priv-app
@@ -80,9 +84,6 @@
namespace.default.permitted.paths += /%PRODUCT%/framework
namespace.default.permitted.paths += /%PRODUCT%/app
namespace.default.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/framework
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/app
-namespace.default.permitted.paths += /%PRODUCT_SERVICES%/priv-app
namespace.default.permitted.paths += /data
namespace.default.permitted.paths += /mnt/expand
namespace.default.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
@@ -90,10 +91,10 @@
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths += /%SYSTEM_EXT%/${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.asan.permitted.paths = /data
namespace.default.asan.permitted.paths += /system/${LIB}/drm
@@ -102,6 +103,10 @@
namespace.default.asan.permitted.paths += /system/framework
namespace.default.asan.permitted.paths += /system/app
namespace.default.asan.permitted.paths += /system/priv-app
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/${LIB}
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/framework
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/app
+namespace.default.asan.permitted.paths += /%SYSTEM_EXT%/priv-app
namespace.default.asan.permitted.paths += /vendor/framework
namespace.default.asan.permitted.paths += /vendor/app
namespace.default.asan.permitted.paths += /vendor/priv-app
@@ -116,10 +121,6 @@
namespace.default.asan.permitted.paths += /%PRODUCT%/framework
namespace.default.asan.permitted.paths += /%PRODUCT%/app
namespace.default.asan.permitted.paths += /%PRODUCT%/priv-app
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/${LIB}
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/framework
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/app
-namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
namespace.default.asan.permitted.paths += /mnt/expand
namespace.default.asan.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
@@ -510,15 +511,15 @@
namespace.system.isolated = false
namespace.system.search.paths = /system/${LIB}
+namespace.system.search.paths += /%SYSTEM_EXT%/${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 += /system/${LIB}
-namespace.system.asan.search.paths += /data/asan/product/${LIB}
+namespace.system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.system.asan.search.paths += /%SYSTEM_EXT%/${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 = libdexfile_external.so
@@ -553,15 +554,15 @@
# The search paths here should be kept the same as that of the 'system'
# namespace.
namespace.vndk_in_system.search.paths = /system/${LIB}
+namespace.vndk_in_system.search.paths += /%SYSTEM_EXT%/${LIB}
namespace.vndk_in_system.search.paths += /%PRODUCT%/${LIB}
-namespace.vndk_in_system.search.paths += /%PRODUCT_SERVICES%/${LIB}
namespace.vndk_in_system.asan.search.paths = /data/asan/system/${LIB}
namespace.vndk_in_system.asan.search.paths += /system/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/product/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.vndk_in_system.asan.search.paths += /%SYSTEM_EXT%/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
namespace.vndk_in_system.asan.search.paths += /%PRODUCT%/${LIB}
-namespace.vndk_in_system.asan.search.paths += /data/asan/product_services/${LIB}
-namespace.vndk_in_system.asan.search.paths += /%PRODUCT_SERVICES%/${LIB}
namespace.vndk_in_system.whitelisted = %VNDK_USING_CORE_VARIANT_LIBRARIES%
@@ -705,7 +706,7 @@
[postinstall]
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
namespace.default.link.runtime.shared_libs = %SANITIZER_RUNTIME_LIBRARIES%
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 9212408..69535a9 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -7,6 +7,7 @@
# absolute path of an executable is selected.
dir.system = /system/bin/
dir.system = /system/xbin/
+dir.system = /%SYSTEM_EXT%/bin/
dir.system = /%PRODUCT%/bin/
dir.vendor = /odm/bin/
@@ -48,21 +49,21 @@
namespace.default.visible = true
namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
+namespace.default.search.paths += /%PRODUCT%/${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 += /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths += /%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
+namespace.default.asan.search.paths += /%PRODUCT%/${LIB}
namespace.default.asan.search.paths += /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${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}
# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
# If a shared library or an executable requests a shared library that
@@ -336,8 +337,9 @@
# Access to system libraries is allowed
namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
namespace.default.search.paths += /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
+# Put /system/lib/vndk at the last search order in vndk_lite for GSI
namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
namespace.default.asan.search.paths = /data/asan/odm/${LIB}
@@ -356,10 +358,10 @@
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 += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/product/${LIB}
+namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
+namespace.default.asan.search.paths += /%SYSTEM_EXT%/${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.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
namespace.default.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
@@ -514,5 +516,5 @@
[postinstall]
namespace.default.isolated = false
namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /%PRODUCT_SERVICES%/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 3acf301..96ffa69 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -413,6 +413,10 @@
# HALs required before storage encryption can get unlocked (FBE/FDE)
class_start early_hal
+ # Check and mark a successful boot, before mounting userdata with mount_all.
+ # No-op for non-A/B device.
+ exec_start update_verifier_nonencrypted
+
on post-fs-data
mark_post_data
@@ -628,22 +632,16 @@
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
- # A/B update verifier that marks a successful boot.
- exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported
- # A/B update verifier that marks a successful boot.
- exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
- # A/B update verifier that marks a successful boot.
- exec_start update_verifier_nonencrypted
start netd
start zygote
start zygote_secondary
@@ -770,8 +768,6 @@
trigger zygote-start
on property:vold.decrypt=trigger_restart_min_framework
- # A/B update verifier that marks a successful boot.
- exec_start update_verifier
class_start main
on property:vold.decrypt=trigger_restart_framework
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index f62c3df..c949a4f 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -147,12 +147,7 @@
$(hide) sed -i.bak -e "s?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g" $@
$(hide) sed -i.bak -e "s?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g" $@
$(hide) sed -i.bak -e "s?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g" $@
-ifeq ($(TARGET_COPY_OUT_PRODUCT),$(TARGET_COPY_OUT_PRODUCT_SERVICES))
- # Remove lines containing %PRODUCT_SERVICES% (identical to the %PRODUCT% ones)
- $(hide) sed -i.bak -e "\?%PRODUCT_SERVICES%?d" $@
-else
- $(hide) sed -i.bak -e "s?%PRODUCT_SERVICES%?$(TARGET_COPY_OUT_PRODUCT_SERVICES)?g" $@
-endif
+ $(hide) sed -i.bak -e "s?%SYSTEM_EXT%?$(TARGET_COPY_OUT_SYSTEM_EXT)?g" $@
$(hide) sed -i.bak -e "s?^$(PRIVATE_VNDK_VERSION_TAG)??g" $@
$(hide) sed -i.bak "/^\#VNDK[0-9]\{2\}\#.*$$/d" $@
$(hide) rm -f $@.bak
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index 1926a4f..d391cc1 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -214,7 +214,7 @@
## Android R
-BSD: grep fsck\_msdos newfs\_msdos
+BSD: fsck\_msdos newfs\_msdos
bzip2: bzcat bzip2 bunzip2