summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralk3pInjection <webmaster@raspii.tech>2023-04-20 00:08:54 +0800
committeralk3pInjection <webmaster@raspii.tech>2023-04-20 00:08:54 +0800
commita7dd355e8fe8ad0c579a4f0acd06b2e3b52dfc3a (patch)
tree2b552b59793a33466247fc6fb8cf89ecbfdc4a05
parentf0103ea35d56ccebbae16a43cac19ac38b11a9a2 (diff)
parent43816573a268998f892081eebf3ffe91d65b7e18 (diff)
Merge tag 'LA.QSSI.13.0.r1-09800-qssi.0' into tachibanatachibana
"LA.QSSI.13.0.r1-09800-qssi.0" Change-Id: I06ecf682f4d5595bce3383b6031506cc56bc0db2
-rw-r--r--bootstat/bootstat.cpp5
-rw-r--r--debuggerd/Android.bp6
-rw-r--r--debuggerd/include/debuggerd/handler.h7
-rw-r--r--fastboot/fastboot.bash2
-rw-r--r--fastboot/fastboot.cpp5
-rw-r--r--fs_mgr/fs_mgr_overlayfs.cpp8
-rw-r--r--fs_mgr/libdm/dm.cpp38
-rw-r--r--fs_mgr/libdm/dm_test.cpp20
-rw-r--r--fs_mgr/libdm/include/libdm/dm.h15
-rw-r--r--fs_mgr/libdm/include/libdm/dm_table.h3
-rw-r--r--fs_mgr/libdm/include/libdm/dm_target.h8
-rw-r--r--fs_mgr/libsnapshot/cow_reader.cpp70
-rw-r--r--fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h3
-rw-r--r--fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h3
-rw-r--r--fs_mgr/libsnapshot/snapshot.cpp11
-rw-r--r--fs_mgr/libsnapshot/snapshot_test.cpp4
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp5
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h11
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp20
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp4
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp73
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h18
-rw-r--r--fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp19
-rw-r--r--fs_mgr/libsnapshot/vts_ota_config_test.cpp7
-rw-r--r--fs_mgr/tests/vts_fs_test.cpp4
-rw-r--r--fs_mgr/tools/dmctl.cpp62
-rw-r--r--healthd/healthd_draw.cpp7
-rw-r--r--healthd/healthd_draw.h3
-rw-r--r--healthd/healthd_mode_charger.cpp15
-rw-r--r--healthd/include_charger/charger/healthd_mode_charger.h2
-rw-r--r--init/README.md7
-rw-r--r--init/devices.cpp6
-rw-r--r--init/property_service.cpp3
-rw-r--r--init/reboot.cpp6
-rw-r--r--init/reboot_utils.cpp9
-rw-r--r--init/reboot_utils.h3
-rw-r--r--init/service_parser.cpp9
-rw-r--r--init/service_utils.cpp3
-rw-r--r--init/service_utils.h1
-rw-r--r--init/util.cpp7
-rw-r--r--init/util.h4
-rw-r--r--libcutils/include/private/android_filesystem_config.h1
-rw-r--r--libmodprobe/libmodprobe.cpp81
-rw-r--r--rootdir/init.rc28
-rw-r--r--rootdir/ueventd.rc2
-rw-r--r--trusty/apploader/apploader.cpp3
-rw-r--r--trusty/apploader/apploader_ipc.h5
-rw-r--r--trusty/storage/interface/include/trusty/interface/storage.h4
-rw-r--r--trusty/storage/proxy/Android.bp2
-rw-r--r--trusty/storage/proxy/proxy.c9
-rw-r--r--trusty/storage/proxy/storage.c35
51 files changed, 519 insertions, 167 deletions
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 2c878f024..af0c89e9f 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -463,6 +463,11 @@ const std::map<std::string, int32_t> kBootReasonMap = {
{"watchdog,gsa,hard", 215},
{"watchdog,gsa,soft", 216},
{"watchdog,pmucal", 217},
+ {"reboot,early,bl", 218},
+ {"watchdog,apc,gsa,crashed", 219},
+ {"watchdog,apc,bl31,crashed", 220},
+ {"watchdog,apc,pbl,crashed", 221},
+ {"reboot,memory_protect,hyp", 222},
};
// Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index b6e08fd94..5b9936748 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -13,9 +13,15 @@ cc_defaults {
"-Wno-nullability-completeness",
"-Os",
"-fno-finite-loops",
+ "-DANDROID_DEBUGGABLE=0",
],
local_include_dirs: ["include"],
+ product_variables: {
+ debuggable: {
+ cflags: ["-UANDROID_DEBUGGABLE", "-DANDROID_DEBUGGABLE=1"],
+ }
+ },
}
cc_library_headers {
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index bc08327a1..68b2e678b 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -62,10 +62,11 @@ void debuggerd_init(debuggerd_callbacks_t* callbacks);
#define DEBUGGER_SIGNAL BIONIC_SIGNAL_DEBUGGER
static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) {
+ bool enabled = true;
+#if ANDROID_DEBUGGABLE
char value[PROP_VALUE_MAX] = "";
- bool enabled =
- !(__system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1") &&
- __system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1"));
+ enabled = !(__system_property_get("debug.debuggerd.disable", value) > 0 && !strcmp(value, "1"));
+#endif
if (enabled) {
sigaction(SIGABRT, action, nullptr);
sigaction(SIGBUS, action, nullptr);
diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash
index e9bf9e940..911071aee 100644
--- a/fastboot/fastboot.bash
+++ b/fastboot/fastboot.bash
@@ -109,7 +109,7 @@ _fastboot_cmd_flash() {
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ $i -eq $COMP_CWORD ]]; then
- partitions="boot bootloader dtbo init_boot modem odm odm_dlkm oem product pvmfw radio recovery system system_dlkm vbmeta vendor vendor_dlkm"
+ partitions="boot bootloader dtbo init_boot modem odm odm_dlkm oem product pvmfw radio recovery system system_dlkm vbmeta vendor vendor_dlkm vendor_kernel_boot"
COMPREPLY=( $(compgen -W "$partitions" -- $cur) )
else
_fastboot_util_complete_local_file "${cur}" '!*.img'
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 39d86f9b3..79c3ac746 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -186,6 +186,11 @@ static Image images[] = {
"vendor_dlkm.img", "vendor_dlkm.sig",
"vendor_dlkm",
true, ImageType::Normal },
+ { "vendor_kernel_boot",
+ "vendor_kernel_boot.img",
+ "vendor_kernel_boot.sig",
+ "vendor_kernel_boot",
+ true, ImageType::BootCritical },
{ nullptr, "vendor_other.img", "vendor.sig", "vendor", true, ImageType::Normal },
// clang-format on
};
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 82b5275a3..6942d0ccd 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -1140,7 +1140,13 @@ static inline uint64_t GetIdealDataScratchSize() {
return 0;
}
- return std::min(super_info.size, (uint64_t(s.f_frsize) * s.f_bfree) / 2);
+ auto ideal_size = std::min(super_info.size, (uint64_t(s.f_frsize) * s.f_bfree) / 2);
+
+ // Align up to the filesystem block size.
+ if (auto remainder = ideal_size % s.f_bsize; remainder > 0) {
+ ideal_size += s.f_bsize - remainder;
+ }
+ return ideal_size;
}
static bool CreateScratchOnData(std::string* scratch_device, bool* partition_exists, bool* change) {
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 4034e30ab..deffae1ad 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -20,6 +20,7 @@
#include <sys/ioctl.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <chrono>
#include <functional>
@@ -289,7 +290,7 @@ bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
return true;
}
-bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
+bool DeviceMapper::LoadTable(const std::string& name, const DmTable& table) {
std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
ioctl_buffer += table.Serialize();
@@ -305,9 +306,17 @@ bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable&
PLOG(ERROR) << "DM_TABLE_LOAD failed";
return false;
}
+ return true;
+}
- InitIo(io, name);
- if (ioctl(fd_, DM_DEV_SUSPEND, io)) {
+bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
+ if (!LoadTable(name, table)) {
+ return false;
+ }
+
+ struct dm_ioctl io;
+ InitIo(&io, name);
+ if (ioctl(fd_, DM_DEV_SUSPEND, &io)) {
PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
return false;
}
@@ -703,5 +712,28 @@ std::map<std::string, std::string> DeviceMapper::FindDmPartitions() {
return dm_block_devices;
}
+bool DeviceMapper::CreatePlaceholderDevice(const std::string& name) {
+ if (!CreateEmptyDevice(name)) {
+ return false;
+ }
+
+ struct utsname uts;
+ unsigned int major, minor;
+ if (uname(&uts) != 0 || sscanf(uts.release, "%u.%u", &major, &minor) != 2) {
+ LOG(ERROR) << "Could not parse the kernel version from uname";
+ return true;
+ }
+
+ // On Linux 5.15+, there is no uevent until DM_TABLE_LOAD.
+ if (major > 5 || (major == 5 && minor >= 15)) {
+ DmTable table;
+ table.Emplace<DmTargetError>(0, 1);
+ if (!LoadTable(name, table)) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 541f254cb..4448d35c5 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -690,3 +690,23 @@ TEST(libdm, CreateEmptyDevice) {
// Empty device should be in suspended state.
ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
}
+
+TEST(libdm, UeventAfterLoadTable) {
+ static const char* kDeviceName = "libmd-test-uevent-load-table";
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ ASSERT_TRUE(dm.CreateEmptyDevice(kDeviceName));
+
+ DmTable table;
+ table.Emplace<DmTargetError>(0, 1);
+ ASSERT_TRUE(dm.LoadTable(kDeviceName, table));
+
+ std::string ignore_path;
+ ASSERT_TRUE(dm.WaitForDevice(kDeviceName, 5s, &ignore_path));
+
+ auto info = dm.GetDetailedInfo(kDeviceName);
+ ASSERT_TRUE(info.has_value());
+ ASSERT_TRUE(info->IsSuspended());
+
+ ASSERT_TRUE(dm.DeleteDevice(kDeviceName));
+}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 1057d7f7a..dbef8f902 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -75,6 +75,7 @@ class IDeviceMapper {
const std::chrono::milliseconds& timeout_ms) = 0;
virtual DmDeviceState GetState(const std::string& name) const = 0;
virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) = 0;
+ virtual bool LoadTable(const std::string& name, const DmTable& table) = 0;
virtual bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) = 0;
virtual bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) = 0;
virtual bool GetDmDevicePathByName(const std::string& name, std::string* path) = 0;
@@ -116,7 +117,7 @@ class DeviceMapper final : public IDeviceMapper {
bool IsBufferFull() const { return flags_ & DM_BUFFER_FULL_FLAG; }
bool IsInactiveTablePresent() const { return flags_ & DM_INACTIVE_PRESENT_FLAG; }
bool IsReadOnly() const { return flags_ & DM_READONLY_FLAG; }
- bool IsSuspended() const { return flags_ & DM_SUSPEND_FLAG; }
+ bool IsSuspended() const { return !IsActiveTablePresent() || (flags_ & DM_SUSPEND_FLAG); }
};
// Removes a device mapper device with the given name.
@@ -199,6 +200,12 @@ class DeviceMapper final : public IDeviceMapper {
// Returns 'true' on success, false otherwise.
bool LoadTableAndActivate(const std::string& name, const DmTable& table) override;
+ // Same as LoadTableAndActivate, but there is no resume step. This puts the
+ // new table in the inactive slot.
+ //
+ // Returns 'true' on success, false otherwise.
+ bool LoadTable(const std::string& name, const DmTable& table) override;
+
// Returns true if a list of available device mapper targets registered in the kernel was
// successfully read and stored in 'targets'. Returns 'false' otherwise.
bool GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets);
@@ -285,6 +292,12 @@ class DeviceMapper final : public IDeviceMapper {
// Returns mapping <partition-name, /dev/block/dm-x>
std::map<std::string, std::string> FindDmPartitions();
+ // Create a placeholder device. This is useful for ensuring that a uevent is in the pipeline,
+ // to reduce the amount of time a future WaitForDevice will block. On kernels < 5.15, this
+ // simply calls CreateEmptyDevice. On 5.15 and higher, it also loads (but does not activate)
+ // a placeholder table containing dm-error.
+ bool CreatePlaceholderDevice(const std::string& name);
+
private:
// Maximum possible device mapper targets registered in the kernel.
// This is only used to read the list of targets from kernel so we allocate
diff --git a/fs_mgr/libdm/include/libdm/dm_table.h b/fs_mgr/libdm/include/libdm/dm_table.h
index ee66653a5..427f34dea 100644
--- a/fs_mgr/libdm/include/libdm/dm_table.h
+++ b/fs_mgr/libdm/include/libdm/dm_table.h
@@ -31,6 +31,7 @@ namespace dm {
class DmTable {
public:
DmTable() : num_sectors_(0), readonly_(false) {}
+ DmTable(DmTable&& other) = default;
// Adds a target to the device mapper table for a range specified in the target object.
// The function will return 'true' if the target was successfully added and doesn't overlap with
@@ -70,6 +71,8 @@ class DmTable {
void set_readonly(bool readonly) { readonly_ = readonly; }
bool readonly() const { return readonly_; }
+ DmTable& operator=(DmTable&& other) = default;
+
~DmTable() = default;
private:
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 954305816..09fe20012 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -323,6 +323,14 @@ class DmTargetUser final : public DmTarget {
std::string control_device_;
};
+class DmTargetError final : public DmTarget {
+ public:
+ DmTargetError(uint64_t start, uint64_t length) : DmTarget(start, length) {}
+
+ std::string name() const override { return "error"; }
+ std::string GetParameterString() const override { return ""; }
+};
+
} // namespace dm
} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 746feeb8d..75a58a6fc 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -38,7 +38,7 @@ CowReader::CowReader(ReaderFlags reader_flag)
: fd_(-1),
header_(),
fd_size_(0),
- merge_op_blocks_(std::make_shared<std::vector<uint32_t>>()),
+ block_pos_index_(std::make_shared<std::vector<int>>()),
reader_flag_(reader_flag) {}
static void SHA256(const void*, size_t, uint8_t[]) {
@@ -58,13 +58,12 @@ std::unique_ptr<CowReader> CowReader::CloneCowReader() {
cow->fd_size_ = fd_size_;
cow->last_label_ = last_label_;
cow->ops_ = ops_;
- cow->merge_op_blocks_ = merge_op_blocks_;
cow->merge_op_start_ = merge_op_start_;
- cow->block_map_ = block_map_;
cow->num_total_data_ops_ = num_total_data_ops_;
cow->num_ordered_ops_to_merge_ = num_ordered_ops_to_merge_;
cow->has_seq_ops_ = has_seq_ops_;
cow->data_loc_ = data_loc_;
+ cow->block_pos_index_ = block_pos_index_;
return cow;
}
@@ -415,10 +414,10 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
// Replace-op-4, Zero-op-9, Replace-op-5 }
//==============================================================
bool CowReader::PrepMergeOps() {
- auto merge_op_blocks = std::make_shared<std::vector<uint32_t>>();
+ auto merge_op_blocks = std::make_unique<std::vector<uint32_t>>();
std::vector<int> other_ops;
auto seq_ops_set = std::unordered_set<uint32_t>();
- auto block_map = std::make_shared<std::unordered_map<uint32_t, int>>();
+ auto block_map = std::make_unique<std::unordered_map<uint32_t, int>>();
size_t num_seqs = 0;
size_t read;
@@ -477,13 +476,18 @@ bool CowReader::PrepMergeOps() {
merge_op_blocks->insert(merge_op_blocks->end(), other_ops.begin(), other_ops.end());
+ for (auto block : *merge_op_blocks) {
+ block_pos_index_->push_back(block_map->at(block));
+ }
+
num_total_data_ops_ = merge_op_blocks->size();
if (header_.num_merge_ops > 0) {
merge_op_start_ = header_.num_merge_ops;
}
- block_map_ = block_map;
- merge_op_blocks_ = merge_op_blocks;
+ block_map->clear();
+ merge_op_blocks->clear();
+
return true;
}
@@ -589,9 +593,7 @@ const CowOperation& CowOpIter::Get() {
class CowRevMergeOpIter final : public ICowOpIter {
public:
explicit CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
- uint64_t start);
+ std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start);
bool Done() override;
const CowOperation& Get() override;
@@ -602,17 +604,15 @@ class CowRevMergeOpIter final : public ICowOpIter {
private:
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
- std::vector<uint32_t>::reverse_iterator block_riter_;
+ std::vector<int>::reverse_iterator block_riter_;
+ std::shared_ptr<std::vector<int>> cow_op_index_vec_;
uint64_t start_;
};
class CowMergeOpIter final : public ICowOpIter {
public:
explicit CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map, uint64_t start);
+ std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start);
bool Done() override;
const CowOperation& Get() override;
@@ -623,26 +623,21 @@ class CowMergeOpIter final : public ICowOpIter {
private:
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
- std::shared_ptr<std::unordered_map<uint32_t, int>> map_;
- std::vector<uint32_t>::iterator block_iter_;
+ std::vector<int>::iterator block_iter_;
+ std::shared_ptr<std::vector<int>> cow_op_index_vec_;
uint64_t start_;
};
CowMergeOpIter::CowMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
- uint64_t start) {
+ std::shared_ptr<std::vector<int>> block_pos_index, uint64_t start) {
ops_ = ops;
- merge_op_blocks_ = merge_op_blocks;
- map_ = map;
start_ = start;
-
- block_iter_ = merge_op_blocks->begin() + start;
+ cow_op_index_vec_ = block_pos_index;
+ block_iter_ = cow_op_index_vec_->begin() + start;
}
bool CowMergeOpIter::RDone() {
- return block_iter_ == merge_op_blocks_->begin();
+ return block_iter_ == cow_op_index_vec_->begin();
}
void CowMergeOpIter::Prev() {
@@ -651,7 +646,7 @@ void CowMergeOpIter::Prev() {
}
bool CowMergeOpIter::Done() {
- return block_iter_ == merge_op_blocks_->end();
+ return block_iter_ == cow_op_index_vec_->end();
}
void CowMergeOpIter::Next() {
@@ -661,23 +656,20 @@ void CowMergeOpIter::Next() {
const CowOperation& CowMergeOpIter::Get() {
CHECK(!Done());
- return ops_->data()[map_->at(*block_iter_)];
+ return ops_->data()[*block_iter_];
}
CowRevMergeOpIter::CowRevMergeOpIter(std::shared_ptr<std::vector<CowOperation>> ops,
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks,
- std::shared_ptr<std::unordered_map<uint32_t, int>> map,
+ std::shared_ptr<std::vector<int>> block_pos_index,
uint64_t start) {
ops_ = ops;
- merge_op_blocks_ = merge_op_blocks;
- map_ = map;
start_ = start;
-
- block_riter_ = merge_op_blocks->rbegin();
+ cow_op_index_vec_ = block_pos_index;
+ block_riter_ = cow_op_index_vec_->rbegin();
}
bool CowRevMergeOpIter::RDone() {
- return block_riter_ == merge_op_blocks_->rbegin();
+ return block_riter_ == cow_op_index_vec_->rbegin();
}
void CowRevMergeOpIter::Prev() {
@@ -686,7 +678,7 @@ void CowRevMergeOpIter::Prev() {
}
bool CowRevMergeOpIter::Done() {
- return block_riter_ == merge_op_blocks_->rend() - start_;
+ return block_riter_ == cow_op_index_vec_->rend() - start_;
}
void CowRevMergeOpIter::Next() {
@@ -696,7 +688,7 @@ void CowRevMergeOpIter::Next() {
const CowOperation& CowRevMergeOpIter::Get() {
CHECK(!Done());
- return ops_->data()[map_->at(*block_riter_)];
+ return ops_->data()[*block_riter_];
}
std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
@@ -704,12 +696,12 @@ std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
}
std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter(bool ignore_progress) {
- return std::make_unique<CowRevMergeOpIter>(ops_, merge_op_blocks_, block_map_,
+ return std::make_unique<CowRevMergeOpIter>(ops_, block_pos_index_,
ignore_progress ? 0 : merge_op_start_);
}
std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) {
- return std::make_unique<CowMergeOpIter>(ops_, merge_op_blocks_, block_map_,
+ return std::make_unique<CowMergeOpIter>(ops_, block_pos_index_,
ignore_progress ? 0 : merge_op_start_);
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index f4d5c72f3..fbdd6b98b 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -170,9 +170,8 @@ class CowReader final : public ICowReader {
uint64_t fd_size_;
std::optional<uint64_t> last_label_;
std::shared_ptr<std::vector<CowOperation>> ops_;
- std::shared_ptr<std::vector<uint32_t>> merge_op_blocks_;
uint64_t merge_op_start_{};
- std::shared_ptr<std::unordered_map<uint32_t, int>> block_map_;
+ std::shared_ptr<std::vector<int>> block_pos_index_;
uint64_t num_total_data_ops_{};
uint64_t num_ordered_ops_to_merge_{};
bool has_seq_ops_{};
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index c3b40dca4..1de6d9835 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -143,6 +143,9 @@ class DeviceMapperWrapper : public android::dm::IDeviceMapper {
virtual DmDeviceState GetState(const std::string& name) const override {
return impl_.GetState(name);
}
+ virtual bool LoadTable(const std::string& name, const DmTable& table) {
+ return impl_.LoadTable(name, table);
+ }
virtual bool LoadTableAndActivate(const std::string& name, const DmTable& table) {
return impl_.LoadTableAndActivate(name, table);
}
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 019b64a44..870801ef1 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2151,8 +2151,17 @@ bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>*
if (!suffix.empty() && !android::base::EndsWith(name, suffix)) {
continue;
}
- snapshots->emplace_back(std::move(name));
+
+ // Insert system and product partition at the beginning so that
+ // during snapshot-merge, these partitions are merged first.
+ if (name == "system_a" || name == "system_b" || name == "product_a" ||
+ name == "product_b") {
+ snapshots->insert(snapshots->begin(), std::move(name));
+ } else {
+ snapshots->emplace_back(std::move(name));
+ }
}
+
return true;
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 6a348b4e5..c145da718 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2755,6 +2755,10 @@ bool IsDaemonRequired() {
return false;
}
+ if (!IsCompressionEnabled()) {
+ return false;
+ }
+
const std::string UNKNOWN = "unknown";
const std::string vendor_release =
android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 692cb740c..718c13ce0 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -143,17 +143,18 @@ void SnapshotHandler::PrepareReadAhead() {
NotifyRAForMergeReady();
}
-void SnapshotHandler::CheckMergeCompletionStatus() {
+bool SnapshotHandler::CheckMergeCompletionStatus() {
if (!merge_initiated_) {
SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: "
<< reader_->get_num_total_data_ops();
- return;
+ return false;
}
struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
SNAP_LOG(INFO) << "Merge-status: Total-Merged-ops: " << ch->num_merge_ops
<< " Total-data-ops: " << reader_->get_num_total_data_ops();
+ return true;
}
bool SnapshotHandler::ReadMetadata() {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
index 83d40f635..c6805e5d9 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -18,6 +18,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <unistd.h>
#include <condition_variable>
#include <cstring>
@@ -54,6 +57,8 @@ static_assert(PAYLOAD_BUFFER_SZ >= BLOCK_SZ);
static constexpr int kNumWorkerThreads = 4;
+static constexpr int kNiceValueForMergeThreads = -5;
+
#define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
@@ -274,7 +279,7 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
const bool& IsAttached() const { return attached_; }
void AttachControlDevice() { attached_ = true; }
- void CheckMergeCompletionStatus();
+ bool CheckMergeCompletionStatus();
bool CommitMerge(int num_merge_ops);
void CloseFds() { cow_fd_ = {}; }
@@ -305,6 +310,8 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
// State transitions for merge
void InitiateMerge();
+ void MonitorMerge();
+ void WakeupMonitorMergeThread();
void WaitForMergeComplete();
bool WaitForMergeBegin();
void NotifyRAForMergeReady();
@@ -333,6 +340,7 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
void SetSocketPresent(bool socket) { is_socket_present_ = socket; }
void SetIouringEnabled(bool io_uring_enabled) { is_io_uring_enabled_ = io_uring_enabled; }
bool MergeInitiated() { return merge_initiated_; }
+ bool MergeMonitored() { return merge_monitored_; }
double GetMergePercentage() { return merge_completion_percentage_; }
// Merge Block State Transitions
@@ -407,6 +415,7 @@ class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
double merge_completion_percentage_;
bool merge_initiated_ = false;
+ bool merge_monitored_ = false;
bool attached_ = false;
bool is_socket_present_;
bool is_io_uring_enabled_ = false;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
index c26a2cd5c..63f47d6f0 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
@@ -71,16 +71,16 @@ int Worker::PrepareMerge(uint64_t* source_offset, int* pending_ops,
}
bool Worker::MergeReplaceZeroOps() {
- // Flush every 8192 ops. Since all ops are independent and there is no
+ // Flush after merging 2MB. Since all ops are independent and there is no
// dependency between COW ops, we will flush the data and the number
- // of ops merged in COW file for every 8192 ops. If there is a crash,
- // we will end up replaying some of the COW ops which were already merged.
- // That is ok.
+ // of ops merged in COW block device. If there is a crash, we will
+ // end up replaying some of the COW ops which were already merged. That is
+ // ok.
//
- // Why 8192 ops ? Increasing this may improve merge time 3-4 seconds but
- // we need to make sure that we checkpoint; 8k ops seems optimal. In-case
- // if there is a crash merge should always make forward progress.
- int total_ops_merged_per_commit = (PAYLOAD_BUFFER_SZ / BLOCK_SZ) * 32;
+ // Although increasing this greater than 2MB may help in improving merge
+ // times; however, on devices with low memory, this can be problematic
+ // when there are multiple merge threads in parallel.
+ int total_ops_merged_per_commit = (PAYLOAD_BUFFER_SZ / BLOCK_SZ) * 2;
int num_ops_merged = 0;
SNAP_LOG(INFO) << "MergeReplaceZeroOps started....";
@@ -543,6 +543,10 @@ bool Worker::RunMergeThread() {
return true;
}
+ if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) {
+ SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid();
+ }
+
SNAP_LOG(INFO) << "Merge starting..";
if (!Init()) {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
index fa2866f39..b9e4255b2 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -727,6 +727,10 @@ bool ReadAhead::RunThread() {
InitializeIouring();
+ if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) {
+ SNAP_PLOG(ERROR) << "Failed to set priority for TID: " << gettid();
+ }
+
while (!RAIterDone()) {
if (!ReadAheadIOStart()) {
break;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
index 82b2b25dd..5d93f01a7 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -59,6 +59,14 @@ DaemonOps UserSnapshotServer::Resolveop(std::string& input) {
return DaemonOps::INVALID;
}
+UserSnapshotServer::UserSnapshotServer() {
+ monitor_merge_event_fd_.reset(eventfd(0, EFD_CLOEXEC));
+ if (monitor_merge_event_fd_ == -1) {
+ PLOG(FATAL) << "monitor_merge_event_fd_: failed to create eventfd";
+ }
+ terminating_ = false;
+}
+
UserSnapshotServer::~UserSnapshotServer() {
// Close any client sockets that were added via AcceptClient().
for (size_t i = 1; i < watched_fds_.size(); i++) {
@@ -249,7 +257,7 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st
return Sendmsg(fd, "fail");
}
- if (!StartMerge(*iter)) {
+ if (!StartMerge(&lock, *iter)) {
return Sendmsg(fd, "fail");
}
@@ -298,7 +306,7 @@ void UserSnapshotServer::RunThread(std::shared_ptr<UserSnapshotDmUserHandler> ha
}
handler->snapuserd()->CloseFds();
- handler->snapuserd()->CheckMergeCompletionStatus();
+ bool merge_completed = handler->snapuserd()->CheckMergeCompletionStatus();
handler->snapuserd()->UnmapBufferRegion();
auto misc_name = handler->misc_name();
@@ -306,7 +314,11 @@ void UserSnapshotServer::RunThread(std::shared_ptr<UserSnapshotDmUserHandler> ha
{
std::lock_guard<std::mutex> lock(lock_);
- num_partitions_merge_complete_ += 1;
+ if (merge_completed) {
+ num_partitions_merge_complete_ += 1;
+ active_merge_threads_ -= 1;
+ WakeupMonitorMergeThread();
+ }
handler->SetThreadTerminated();
auto iter = FindHandler(&lock, handler->misc_name());
if (iter == dm_users_.end()) {
@@ -418,6 +430,9 @@ void UserSnapshotServer::JoinAllThreads() {
if (th.joinable()) th.join();
}
+
+ stop_monitor_merge_thread_ = true;
+ WakeupMonitorMergeThread();
}
void UserSnapshotServer::AddWatchedFd(android::base::borrowed_fd fd, int events) {
@@ -502,13 +517,24 @@ bool UserSnapshotServer::StartHandler(const std::shared_ptr<UserSnapshotDmUserHa
return true;
}
-bool UserSnapshotServer::StartMerge(const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
+bool UserSnapshotServer::StartMerge(std::lock_guard<std::mutex>* proof_of_lock,
+ const std::shared_ptr<UserSnapshotDmUserHandler>& handler) {
+ CHECK(proof_of_lock);
+
if (!handler->snapuserd()->IsAttached()) {
LOG(ERROR) << "Handler not attached to dm-user - Merge thread cannot be started";
return false;
}
- handler->snapuserd()->InitiateMerge();
+ handler->snapuserd()->MonitorMerge();
+
+ if (!is_merge_monitor_started_.has_value()) {
+ std::thread(&UserSnapshotServer::MonitorMerge, this).detach();
+ is_merge_monitor_started_ = true;
+ }
+
+ merge_handlers_.push(handler);
+ WakeupMonitorMergeThread();
return true;
}
@@ -590,6 +616,42 @@ bool UserSnapshotServer::RemoveAndJoinHandler(const std::string& misc_name) {
return true;
}
+void UserSnapshotServer::WakeupMonitorMergeThread() {
+ uint64_t notify = 1;
+ ssize_t rc = TEMP_FAILURE_RETRY(write(monitor_merge_event_fd_.get(), &notify, sizeof(notify)));
+ if (rc < 0) {
+ PLOG(FATAL) << "failed to notify monitor merge thread";
+ }
+}
+
+void UserSnapshotServer::MonitorMerge() {
+ while (!stop_monitor_merge_thread_) {
+ uint64_t testVal;
+ ssize_t ret =
+ TEMP_FAILURE_RETRY(read(monitor_merge_event_fd_.get(), &testVal, sizeof(testVal)));
+ if (ret == -1) {
+ PLOG(FATAL) << "Failed to read from eventfd";
+ } else if (ret == 0) {
+ LOG(FATAL) << "Hit EOF on eventfd";
+ }
+
+ LOG(INFO) << "MonitorMerge: active-merge-threads: " << active_merge_threads_;
+ {
+ std::lock_guard<std::mutex> lock(lock_);
+ while (active_merge_threads_ < kMaxMergeThreads && merge_handlers_.size() > 0) {
+ auto handler = merge_handlers_.front();
+ merge_handlers_.pop();
+ LOG(INFO) << "Starting merge for partition: "
+ << handler->snapuserd()->GetMiscName();
+ handler->snapuserd()->InitiateMerge();
+ active_merge_threads_ += 1;
+ }
+ }
+ }
+
+ LOG(INFO) << "Exiting MonitorMerge: size: " << merge_handlers_.size();
+}
+
bool UserSnapshotServer::WaitForSocket() {
auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); });
@@ -646,6 +708,7 @@ bool UserSnapshotServer::WaitForSocket() {
if (!StartWithSocket(true)) {
return false;
}
+
return Run();
}
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
index 34e7941bc..e0844aeb1 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
@@ -15,6 +15,7 @@
#pragma once
#include <poll.h>
+#include <sys/eventfd.h>
#include <cstdio>
#include <cstring>
@@ -22,6 +23,8 @@
#include <future>
#include <iostream>
#include <mutex>
+#include <optional>
+#include <queue>
#include <sstream>
#include <string>
#include <thread>
@@ -34,6 +37,7 @@ namespace android {
namespace snapshot {
static constexpr uint32_t kMaxPacketSize = 512;
+static constexpr uint8_t kMaxMergeThreads = 2;
enum class DaemonOps {
INIT,
@@ -84,13 +88,19 @@ class UserSnapshotServer {
std::vector<struct pollfd> watched_fds_;
bool is_socket_present_ = false;
int num_partitions_merge_complete_ = 0;
+ int active_merge_threads_ = 0;
+ bool stop_monitor_merge_thread_ = false;
bool is_server_running_ = false;
bool io_uring_enabled_ = false;
+ std::optional<bool> is_merge_monitor_started_;
+
+ android::base::unique_fd monitor_merge_event_fd_;
std::mutex lock_;
using HandlerList = std::vector<std::shared_ptr<UserSnapshotDmUserHandler>>;
HandlerList dm_users_;
+ std::queue<std::shared_ptr<UserSnapshotDmUserHandler>> merge_handlers_;
void AddWatchedFd(android::base::borrowed_fd fd, int events);
void AcceptClient();
@@ -108,6 +118,8 @@ class UserSnapshotServer {
bool IsTerminating() { return terminating_; }
void RunThread(std::shared_ptr<UserSnapshotDmUserHandler> handler);
+ void MonitorMerge();
+
void JoinAllThreads();
bool StartWithSocket(bool start_listening);
@@ -119,7 +131,7 @@ class UserSnapshotServer {
void TerminateMergeThreads(std::lock_guard<std::mutex>* proof_of_lock);
public:
- UserSnapshotServer() { terminating_ = false; }
+ UserSnapshotServer();
~UserSnapshotServer();
bool Start(const std::string& socketname);
@@ -133,9 +145,11 @@ class UserSnapshotServer {
const std::string& backing_device,
const std::string& base_path_merge);
bool StartHandler(const std::shared_ptr<UserSnapshotDmUserHandler>& handler);
- bool StartMerge(const std::shared_ptr<UserSnapshotDmUserHandler>& handler);
+ bool StartMerge(std::lock_guard<std::mutex>* proof_of_lock,
+ const std::shared_ptr<UserSnapshotDmUserHandler>& handler);
std::string GetMergeStatus(const std::shared_ptr<UserSnapshotDmUserHandler>& handler);
+ void WakeupMonitorMergeThread();
void SetTerminating() { terminating_ = true; }
void ReceivedSocketSignal() { received_socket_signal_ = true; }
void SetServerRunning() { is_server_running_ = true; }
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp
index d4e1d7c7e..28c9f688a 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp
@@ -165,6 +165,13 @@ using namespace android;
using namespace android::dm;
using android::base::unique_fd;
+void SnapshotHandler::MonitorMerge() {
+ {
+ std::lock_guard<std::mutex> lock(lock_);
+ merge_monitored_ = true;
+ }
+}
+
// This is invoked once primarily by update-engine to initiate
// the merge
void SnapshotHandler::InitiateMerge() {
@@ -361,10 +368,16 @@ void SnapshotHandler::WaitForMergeComplete() {
std::string SnapshotHandler::GetMergeStatus() {
bool merge_not_initiated = false;
+ bool merge_monitored = false;
bool merge_failed = false;
{
std::lock_guard<std::mutex> lock(lock_);
+
+ if (MergeMonitored()) {
+ merge_monitored = true;
+ }
+
if (!MergeInitiated()) {
merge_not_initiated = true;
}
@@ -387,6 +400,12 @@ std::string SnapshotHandler::GetMergeStatus() {
return "snapshot-merge-complete";
}
+ // Merge monitor thread is tracking the merge but the merge thread
+ // is not started yet.
+ if (merge_monitored) {
+ return "snapshot-merge";
+ }
+
// Return the state as "snapshot". If the device was rebooted during
// merge, we will return the status as "snapshot". This is ok, as
// libsnapshot will explicitly resume the merge. This is slightly
diff --git a/fs_mgr/libsnapshot/vts_ota_config_test.cpp b/fs_mgr/libsnapshot/vts_ota_config_test.cpp
index afc2d81a4..02bcc3438 100644
--- a/fs_mgr/libsnapshot/vts_ota_config_test.cpp
+++ b/fs_mgr/libsnapshot/vts_ota_config_test.cpp
@@ -17,7 +17,14 @@
#include <android-base/properties.h>
#include <gtest/gtest.h>
+static int GetVsrLevel() {
+ return android::base::GetIntProperty("ro.vendor.api_level", -1);
+}
+
TEST(VAB, Enabled) {
ASSERT_TRUE(android::base::GetBoolProperty("ro.virtual_ab.enabled", false));
+ if (GetVsrLevel() < __ANDROID_API_T__) {
+ GTEST_SKIP();
+ }
ASSERT_TRUE(android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false));
}
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index aac2cfd9b..ae8e45992 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -28,8 +28,8 @@ static int GetVsrLevel() {
}
TEST(fs, ErofsSupported) {
- // S and higher for this test.
- if (GetVsrLevel() < __ANDROID_API_S__) {
+ // T-launch GKI kernels and higher must support EROFS.
+ if (GetVsrLevel() < __ANDROID_API_T__) {
GTEST_SKIP();
}
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 62ca1620b..10efd0cab 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -33,6 +33,7 @@
#include <ios>
#include <iostream>
#include <map>
+#include <optional>
#include <sstream>
#include <string>
#include <vector>
@@ -183,6 +184,8 @@ class TargetParser final {
}
std::string control_device = NextArg();
return std::make_unique<DmTargetUser>(start_sector, num_sectors, control_device);
+ } else if (target_type == "error") {
+ return std::make_unique<DmTargetError>(start_sector, num_sectors);
} else {
std::cerr << "Unrecognized target type: " << target_type << std::endl;
return nullptr;
@@ -206,16 +209,26 @@ class TargetParser final {
char** argv_;
};
-static bool parse_table_args(DmTable* table, int argc, char** argv) {
+struct TableArgs {
+ DmTable table;
+ bool suspended = false;
+};
+
+static std::optional<TableArgs> parse_table_args(int argc, char** argv) {
+ TableArgs out;
+
// Parse extended options first.
int arg_index = 1;
while (arg_index < argc && argv[arg_index][0] == '-') {
if (strcmp(argv[arg_index], "-ro") == 0) {
- table->set_readonly(true);
+ out.table.set_readonly(true);
+ arg_index++;
+ } else if (strcmp(argv[arg_index], "-suspended") == 0) {
+ out.suspended = true;
arg_index++;
} else {
std::cerr << "Unrecognized option: " << argv[arg_index] << std::endl;
- return -EINVAL;
+ return {};
}
}
@@ -223,37 +236,44 @@ static bool parse_table_args(DmTable* table, int argc, char** argv) {
TargetParser parser(argc - arg_index, argv + arg_index);
while (parser.More()) {
std::unique_ptr<DmTarget> target = parser.Next();
- if (!target || !table->AddTarget(std::move(target))) {
- return -EINVAL;
+ if (!target || !out.table.AddTarget(std::move(target))) {
+ return {};
}
}
- if (table->num_targets() == 0) {
+ if (out.table.num_targets() == 0) {
std::cerr << "Must define at least one target." << std::endl;
- return -EINVAL;
+ return {};
}
- return 0;
+ return {std::move(out)};
}
static int DmCreateCmdHandler(int argc, char** argv) {
if (argc < 1) {
- std::cerr << "Usage: dmctl create <dm-name> [-ro] <targets...>" << std::endl;
+ std::cerr << "Usage: dmctl create <dm-name> [--suspended] [-ro] <targets...>" << std::endl;
return -EINVAL;
}
std::string name = argv[0];
- DmTable table;
- int ret = parse_table_args(&table, argc, argv);
- if (ret) {
- return ret;
+ auto table_args = parse_table_args(argc, argv);
+ if (!table_args) {
+ return -EINVAL;
}
std::string ignore_path;
DeviceMapper& dm = DeviceMapper::Instance();
- if (!dm.CreateDevice(name, table, &ignore_path, 5s)) {
+ if (!dm.CreateEmptyDevice(name)) {
std::cerr << "Failed to create device-mapper device with name: " << name << std::endl;
return -EIO;
}
+ if (!dm.LoadTable(name, table_args->table)) {
+ std::cerr << "Failed to load table for dm device: " << name << std::endl;
+ return -EIO;
+ }
+ if (!table_args->suspended && !dm.ChangeState(name, DmDeviceState::ACTIVE)) {
+ std::cerr << "Failed to activate table for " << name << std::endl;
+ return -EIO;
+ }
return 0;
}
@@ -269,7 +289,6 @@ static int DmDeleteCmdHandler(int argc, char** argv) {
std::cerr << "Failed to delete [" << name << "]" << std::endl;
return -EIO;
}
-
return 0;
}
@@ -280,17 +299,20 @@ static int DmReplaceCmdHandler(int argc, char** argv) {
}
std::string name = argv[0];
- DmTable table;
- int ret = parse_table_args(&table, argc, argv);
- if (ret) {
- return ret;
+ auto table_args = parse_table_args(argc, argv);
+ if (!table_args) {
+ return -EINVAL;
}
DeviceMapper& dm = DeviceMapper::Instance();
- if (!dm.LoadTableAndActivate(name, table)) {
+ if (!dm.LoadTable(name, table_args->table)) {
std::cerr << "Failed to replace device-mapper table to: " << name << std::endl;
return -EIO;
}
+ if (!table_args->suspended && !dm.ChangeState(name, DmDeviceState::ACTIVE)) {
+ std::cerr << "Failed to activate table for " << name << std::endl;
+ return -EIO;
+ }
return 0;
}
diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp
index 3e73fcd08..7c7931944 100644
--- a/healthd/healthd_draw.cpp
+++ b/healthd/healthd_draw.cpp
@@ -99,7 +99,7 @@ void HealthdDraw::blank_screen(bool blank, int drm) {
gr_fb_blank(blank, drm);
}
-/* support screen rotation for foldable phone */
+// support screen rotation for foldable phone
void HealthdDraw::rotate_screen(int drm) {
if (!graphics_available) return;
if (drm == 0)
@@ -108,6 +108,11 @@ void HealthdDraw::rotate_screen(int drm) {
gr_rotate(GRRotation::NONE /* Portrait mode */);
}
+// detect dual display
+bool HealthdDraw::has_multiple_connectors() {
+ return graphics_available && gr_has_multiple_connectors();
+}
+
void HealthdDraw::clear_screen(void) {
if (!graphics_available) return;
gr_color(0, 0, 0, 255);
diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h
index 3d4abbdda..016db8e07 100644
--- a/healthd/healthd_draw.h
+++ b/healthd/healthd_draw.h
@@ -38,6 +38,9 @@ class HealthdDraw {
// Rotate screen.
virtual void rotate_screen(int drm);
+ // Detect dual display
+ virtual bool has_multiple_connectors();
+
static std::unique_ptr<HealthdDraw> Create(animation *anim);
protected:
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index aa98d4817..4aae27948 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -289,6 +289,18 @@ static void reset_animation(animation* anim) {
anim->run = false;
}
+void Charger::BlankSecScreen() {
+ int drm = drm_ == DRM_INNER ? 1 : 0;
+
+ if (!init_screen_) {
+ /* blank the secondary screen */
+ healthd_draw_->blank_screen(false, drm);
+ healthd_draw_->redraw_screen(&batt_anim_, surf_unknown_);
+ healthd_draw_->blank_screen(true, drm);
+ init_screen_ = true;
+ }
+}
+
void Charger::UpdateScreenState(int64_t now) {
int disp_time;
@@ -338,6 +350,9 @@ void Charger::UpdateScreenState(int64_t now) {
reset_animation(&batt_anim_);
next_screen_transition_ = -1;
healthd_draw_->blank_screen(true, static_cast<int>(drm_));
+ if (healthd_draw_->has_multiple_connectors()) {
+ BlankSecScreen();
+ }
screen_blanked_ = true;
LOGV("[%" PRId64 "] animation done\n", now);
if (configuration_->ChargerIsOnline()) {
diff --git a/healthd/include_charger/charger/healthd_mode_charger.h b/healthd/include_charger/charger/healthd_mode_charger.h
index 28e1fb531..8957a7b22 100644
--- a/healthd/include_charger/charger/healthd_mode_charger.h
+++ b/healthd/include_charger/charger/healthd_mode_charger.h
@@ -107,9 +107,11 @@ class Charger {
void InitAnimation();
int RequestEnableSuspend();
int RequestDisableSuspend();
+ void BlankSecScreen();
bool have_battery_state_ = false;
bool screen_blanked_ = false;
+ bool init_screen_ = false;
int64_t next_screen_transition_ = 0;
int64_t next_key_check_ = 0;
int64_t next_pwr_check_ = 0;
diff --git a/init/README.md b/init/README.md
index 13c6ebdfa..aaafe7887 100644
--- a/init/README.md
+++ b/init/README.md
@@ -352,9 +352,10 @@ runs the service.
`socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]`
> Create a UNIX domain socket named /dev/socket/_name_ and pass its fd to the
- launched process. _type_ must be "dgram", "stream" or "seqpacket". _type_
- may end with "+passcred" to enable SO_PASSCRED on the socket. User and
- group default to 0. 'seclabel' is the SELinux security context for the
+ launched process. The socket is created synchronously when the service starts.
+ _type_ must be "dgram", "stream" or "seqpacket". _type_ may end with "+passcred"
+ to enable SO_PASSCRED on the socket or "+listen" to synchronously make it a listening socket.
+ User and group default to 0. 'seclabel' is the SELinux security context for the
socket. It defaults to the service security context, as specified by
seclabel or computed based on the service executable file security context.
For native executables see libcutils android\_get\_control\_socket().
diff --git a/init/devices.cpp b/init/devices.cpp
index d4a3cb9d3..ee8738c2a 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -465,7 +465,11 @@ void DeviceHandler::HandleDevice(const std::string& action, const std::string& d
MakeDevice(devpath, block, major, minor, links);
}
- // We don't have full device-mapper information until a change event is fired.
+ // Handle device-mapper nodes.
+ // On kernels <= 5.10, the "add" event is fired on DM_DEV_CREATE, but does not contain name
+ // information until DM_TABLE_LOAD - thus, we wait for a "change" event.
+ // On kernels >= 5.15, the "add" event is fired on DM_TABLE_LOAD, followed by a "change"
+ // event.
if (action == "add" || (action == "change" && StartsWith(devpath, "/dev/block/dm-"))) {
for (const auto& link : links) {
if (!mkdir_recursive(Dirname(link), 0755)) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index f9b4de94a..392d35c5b 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1519,7 +1519,8 @@ void StartPropertyService(int* epoll_socket) {
StartSendingMessages();
if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
- false, 0666, 0, 0, {});
+ /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0,
+ /*gid=*/0, /*socketcon=*/{});
result.ok()) {
property_set_fd = *result;
} else {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 580d8a67a..9edc32808 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -616,7 +616,7 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
if (sem_init(&reboot_semaphore, false, 0) == -1) {
// These should never fail, but if they do, skip the graceful reboot and reboot immediately.
LOG(ERROR) << "sem_init() fail and RebootSystem() return!";
- RebootSystem(cmd, reboot_target);
+ RebootSystem(cmd, reboot_target, reason);
}
// Start a thread to monitor init shutdown process
@@ -644,7 +644,7 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
// worry about unmounting it.
if (!IsDataMounted("*")) {
sync();
- RebootSystem(cmd, reboot_target);
+ RebootSystem(cmd, reboot_target, reason);
abort();
}
@@ -777,7 +777,7 @@ static void DoReboot(unsigned int cmd, const std::string& reason, const std::str
LOG(INFO) << "Shutdown /data";
}
}
- RebootSystem(cmd, reboot_target);
+ RebootSystem(cmd, reboot_target, reason);
abort();
}
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index b3fa9fd3b..1f411636c 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -106,7 +106,8 @@ bool IsRebootCapable() {
return value == CAP_SET;
}
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+void __attribute__((noreturn))
+RebootSystem(unsigned int cmd, const std::string& rebootTarget, const std::string& reboot_reason) {
LOG(INFO) << "Reboot ending, jumping to kernel";
if (!IsRebootCapable()) {
@@ -127,10 +128,12 @@ void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string&
case ANDROID_RB_THERMOFF:
if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) {
+ std::string reason = "shutdown,thermal";
+ if (!reboot_reason.empty()) reason = reboot_reason;
+
LOG(INFO) << "Try to trigger a warm reset for thermal shutdown";
- static constexpr const char kThermalShutdownTarget[] = "shutdown,thermal";
syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
- LINUX_REBOOT_CMD_RESTART2, kThermalShutdownTarget);
+ LINUX_REBOOT_CMD_RESTART2, reason.c_str());
} else {
reboot(RB_POWER_OFF);
}
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index a0023b9bb..09e87ef67 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -29,7 +29,8 @@ void SetFatalRebootTarget(const std::optional<std::string>& reboot_target = std:
// so if any of the attempts to determine this fail, it will still return true.
bool IsRebootCapable();
// This is a wrapper around the actual reboot calls.
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target);
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target,
+ const std::string& reboot_reason = "");
void __attribute__((noreturn)) InitFatalReboot(int signal_number);
void InstallRebootSignalHandlers();
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 9e914ee7c..1ee309d98 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -434,11 +434,14 @@ Result<void> ServiceParser::ParseSocket(std::vector<std::string>&& args) {
<< "' instead.";
}
- if (types.size() > 1) {
- if (types.size() == 2 && types[1] == "passcred") {
+ for (size_t i = 1; i < types.size(); i++) {
+ if (types[i] == "passcred") {
socket.passcred = true;
+ } else if (types[i] == "listen") {
+ socket.listen = true;
} else {
- return Error() << "Only 'passcred' may be used to modify the socket type";
+ return Error() << "Unknown socket type decoration '" << types[i]
+ << "'. Known values are ['passcred', 'listen']";
}
}
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index eed5c65db..d19f5eef5 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -168,7 +168,8 @@ void Descriptor::Publish() const {
Result<Descriptor> SocketDescriptor::Create(const std::string& global_context) const {
const auto& socket_context = context.empty() ? global_context : context;
- auto result = CreateSocket(name, type | SOCK_CLOEXEC, passcred, perm, uid, gid, socket_context);
+ auto result = CreateSocket(name, type | SOCK_CLOEXEC, passcred, listen, perm, uid, gid,
+ socket_context);
if (!result.ok()) {
return result.error();
}
diff --git a/init/service_utils.h b/init/service_utils.h
index 9b65dca74..65a2012ff 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -54,6 +54,7 @@ struct SocketDescriptor {
int perm = 0;
std::string context;
bool passcred = false;
+ bool listen = false;
bool persist = false;
// Create() creates the named unix domain socket in /dev/socket and returns a Descriptor object.
diff --git a/init/util.cpp b/init/util.cpp
index d1e518b57..5b3a73c0d 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -86,8 +86,8 @@ Result<uid_t> DecodeUid(const std::string& name) {
* daemon. We communicate the file descriptor's value via the environment
* variable ANDROID_SOCKET_ENV_PREFIX<name> ("ANDROID_SOCKET_foo").
*/
-Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
- gid_t gid, const std::string& socketcon) {
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, bool should_listen,
+ mode_t perm, uid_t uid, gid_t gid, const std::string& socketcon) {
if (!socketcon.empty()) {
if (setsockcreatecon(socketcon.c_str()) == -1) {
return ErrnoError() << "setsockcreatecon(\"" << socketcon << "\") failed";
@@ -142,6 +142,9 @@ Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_
if (fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW)) {
return ErrnoError() << "Failed to fchmodat socket '" << addr.sun_path << "'";
}
+ if (should_listen && listen(fd, /* use OS maximum */ 1 << 30)) {
+ return ErrnoError() << "Failed to listen on socket '" << addr.sun_path << "'";
+ }
LOG(INFO) << "Created socket '" << addr.sun_path << "'"
<< ", mode " << std::oct << perm << std::dec
diff --git a/init/util.h b/init/util.h
index bf5367531..1e2eef090 100644
--- a/init/util.h
+++ b/init/util.h
@@ -44,8 +44,8 @@ static const char kColdBootDoneProp[] = "ro.cold_boot_done";
extern void (*trigger_shutdown)(const std::string& command);
-Result<int> CreateSocket(const std::string& name, int type, bool passcred, mode_t perm, uid_t uid,
- gid_t gid, const std::string& socketcon);
+Result<int> CreateSocket(const std::string& name, int type, bool passcred, bool should_listen,
+ mode_t perm, uid_t uid, gid_t gid, const std::string& socketcon);
Result<std::string> ReadFile(const std::string& path);
Result<void> WriteFile(const std::string& path, const std::string& content);
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index bdb807538..0030887a1 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -138,6 +138,7 @@
#define AID_JC_IDENTITYCRED 1089 /* Javacard Identity Cred HAL - to manage omapi ARA rules */
#define AID_SDK_SANDBOX 1090 /* SDK sandbox virtual UID */
#define AID_SECURITY_LOG_WRITER 1091 /* write to security log */
+#define AID_PRNG_SEEDER 1092 /* PRNG seeder daemon */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index e071c96d9..4fbb19d1a 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -439,54 +439,58 @@ bool Modprobe::IsBlocklisted(const std::string& module_name) {
return module_blocklist_.count(canonical_name) > 0;
}
-// Another option to load kernel modules. load in independent modules in parallel
-// and then update dependency list of other remaining modules, repeat these steps
-// until all modules are loaded.
+// Another option to load kernel modules. load independent modules dependencies
+// in parallel and then update dependency list of other remaining modules,
+// repeat these steps until all modules are loaded.
+// Discard all blocklist.
+// Softdeps are taken care in InsmodWithDeps().
bool Modprobe::LoadModulesParallel(int num_threads) {
bool ret = true;
- int count = -1;
- std::map<std::string, std::set<std::string>> mod_with_deps;
+ std::unordered_map<std::string, std::vector<std::string>> mod_with_deps;
// Get dependencies
for (const auto& module : module_load_) {
- auto dependencies = GetDependencies(MakeCanonical(module));
-
- for (auto dep = dependencies.rbegin(); dep != dependencies.rend(); dep++) {
- mod_with_deps[module].emplace(*dep);
- }
- }
-
- // Get soft dependencies
- for (const auto& [it_mod, it_softdep] : module_pre_softdep_) {
- if (mod_with_deps.find(MakeCanonical(it_softdep)) != mod_with_deps.end()) {
- mod_with_deps[MakeCanonical(it_mod)].emplace(
- GetDependencies(MakeCanonical(it_softdep))[0]);
+ // Skip blocklist modules
+ if (IsBlocklisted(module)) {
+ LOG(VERBOSE) << "LMP: Blocklist: Module " << module << " skipping...";
+ continue;
}
- }
-
- // Get soft post dependencies
- for (const auto& [it_mod, it_softdep] : module_post_softdep_) {
- if (mod_with_deps.find(MakeCanonical(it_softdep)) != mod_with_deps.end()) {
- mod_with_deps[MakeCanonical(it_softdep)].emplace(
- GetDependencies(MakeCanonical(it_mod))[0]);
+ auto dependencies = GetDependencies(MakeCanonical(module));
+ if (dependencies.empty()) {
+ LOG(ERROR) << "LMP: Hard-dep: Module " << module
+ << " not in .dep file";
+ return false;
}
+ mod_with_deps[MakeCanonical(module)] = dependencies;
}
- while (!mod_with_deps.empty() && count != module_loaded_.size()) {
+ while (!mod_with_deps.empty()) {
std::vector<std::thread> threads;
std::vector<std::string> mods_path_to_load;
std::mutex vector_lock;
- count = module_loaded_.size();
// Find independent modules
for (const auto& [it_mod, it_dep] : mod_with_deps) {
- if (it_dep.size() == 1) {
- if (module_options_[it_mod].find("load_sequential=1") != std::string::npos) {
- if (!LoadWithAliases(it_mod, true) && !IsBlocklisted(it_mod)) {
- return false;
- }
- } else {
- mods_path_to_load.emplace_back(it_mod);
+ auto itd_last = it_dep.rbegin();
+ if (itd_last == it_dep.rend())
+ continue;
+
+ auto cnd_last = MakeCanonical(*itd_last);
+ // Hard-dependencies cannot be blocklisted
+ if (IsBlocklisted(cnd_last)) {
+ LOG(ERROR) << "LMP: Blocklist: Module-dep " << cnd_last
+ << " : failed to load module " << it_mod;
+ return false;
+ }
+
+ if (module_options_[cnd_last].find("load_sequential=1") != std::string::npos) {
+ if (!LoadWithAliases(cnd_last, true)) {
+ return false;
+ }
+ } else {
+ if (std::find(mods_path_to_load.begin(), mods_path_to_load.end(),
+ cnd_last) == mods_path_to_load.end()) {
+ mods_path_to_load.emplace_back(cnd_last);
}
}
}
@@ -502,7 +506,7 @@ bool Modprobe::LoadModulesParallel(int num_threads) {
lk.unlock();
ret_load &= LoadWithAliases(mod_to_load, true);
lk.lock();
- if (!ret_load && !IsBlocklisted(mod_to_load)) {
+ if (!ret_load) {
ret &= ret_load;
}
}
@@ -521,13 +525,18 @@ bool Modprobe::LoadModulesParallel(int num_threads) {
std::lock_guard guard(module_loaded_lock_);
// Remove loaded module form mod_with_deps and soft dependencies of other modules
for (const auto& module_loaded : module_loaded_) {
- mod_with_deps.erase(module_loaded);
+ if (mod_with_deps.find(module_loaded) != mod_with_deps.end()) {
+ mod_with_deps.erase(module_loaded);
+ }
}
// Remove loaded module form dependencies of other modules which are not loaded yet
for (const auto& module_loaded_path : module_loaded_paths_) {
for (auto& [mod, deps] : mod_with_deps) {
- deps.erase(module_loaded_path);
+ auto it = std::find(deps.begin(), deps.end(), module_loaded_path);
+ if (it != deps.end()) {
+ deps.erase(it);
+ }
}
}
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index e901a1028..c264ebb0e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -654,18 +654,9 @@ on late-fs
# Load trusted keys from dm-verity protected partitions
exec -- /system/bin/fsverity_init --load-verified-keys
-# Only enable the bootreceiver tracing instance for kernels 5.10 and above.
-on late-fs && property:ro.kernel.version=4.9
- setprop bootreceiver.enable 0
-on late-fs && property:ro.kernel.version=4.14
- setprop bootreceiver.enable 0
-on late-fs && property:ro.kernel.version=4.19
- setprop bootreceiver.enable 0
-on late-fs && property:ro.kernel.version=5.4
- setprop bootreceiver.enable 0
+# Don't enable the bootreceiver tracing instance to save 10MB of memory
on late-fs
- # Bootreceiver tracing instance is enabled by default.
- setprop bootreceiver.enable ${bootreceiver.enable:-1}
+ setprop bootreceiver.enable 0
on property:ro.product.cpu.abilist64=* && property:bootreceiver.enable=1
# Set up a tracing instance for system_server to monitor error_report_end events.
@@ -738,9 +729,13 @@ on post-fs-data
# Multi-installed APEXes are selected using persist props.
# Load persist properties and override properties (if enabled) from /data,
# before starting apexd.
+ # /data/property should be created before `load_persist_props`
+ mkdir /data/property 0700 root root encryption=Require
load_persist_props
+
start logd
start logd-reinit
+
# Some existing vendor rc files use 'on load_persist_props_action' to know
# when persist props are ready. These are difficult to change due to GRF,
# so continue triggering this action here even though props are already loaded
@@ -860,7 +855,6 @@ on post-fs-data
mkdir /data/app-asec 0700 root root encryption=Require
mkdir /data/app-lib 0771 system system encryption=Require
mkdir /data/app 0771 system system encryption=Require
- mkdir /data/property 0700 root root encryption=Require
# create directory for updated font files.
mkdir /data/fonts/ 0771 root root encryption=Require
@@ -936,20 +930,26 @@ on post-fs-data
mkdir /data/user/0 0700 system system encryption=None
mount none /data/data /data/user/0 bind rec
- # A tmpfs directory, which will contain all apps CE DE data directory that
- # bind mount from the original source.
+ # A tmpfs directory, which will contain all apps and sdk sandbox CE and DE
+ # data directory that bind mount from the original source.
mount tmpfs tmpfs /data_mirror nodev noexec nosuid mode=0700,uid=0,gid=1000
restorecon /data_mirror
mkdir /data_mirror/data_ce 0700 root root
mkdir /data_mirror/data_de 0700 root root
+ mkdir /data_mirror/misc_ce 0700 root root
+ mkdir /data_mirror/misc_de 0700 root root
# Create CE and DE data directory for default volume
mkdir /data_mirror/data_ce/null 0700 root root
mkdir /data_mirror/data_de/null 0700 root root
+ mkdir /data_mirror/misc_ce/null 0700 root root
+ mkdir /data_mirror/misc_de/null 0700 root root
# Bind mount CE and DE data directory to mirror's default volume directory
mount none /data/user /data_mirror/data_ce/null bind rec
mount none /data/user_de /data_mirror/data_de/null bind rec
+ mount none /data/misc_ce /data_mirror/misc_ce/null bind rec
+ mount none /data/misc_de /data_mirror/misc_de/null bind rec
# Create mirror directory for jit profiles
mkdir /data_mirror/cur_profiles 0700 root root
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index a140c8c51..4ec59afe9 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -37,6 +37,8 @@ subsystem dma_heap
/dev/tty 0666 root root
/dev/random 0666 root root
/dev/urandom 0666 root root
+# Aside from kernel threads, only prng_seeder needs access to HW RNG
+/dev/hw_random 0400 prng_seeder prng_seeder
/dev/ashmem* 0666 root root
/dev/binder 0666 root root
/dev/hwbinder 0666 root root
diff --git a/trusty/apploader/apploader.cpp b/trusty/apploader/apploader.cpp
index 278499f17..17d083c73 100644
--- a/trusty/apploader/apploader.cpp
+++ b/trusty/apploader/apploader.cpp
@@ -226,6 +226,9 @@ static ssize_t read_response(int tipc_fd) {
case APPLOADER_ERR_POLICY_VIOLATION:
LOG(ERROR) << "Error: loading denied by policy engine";
break;
+ case APPLOADER_ERR_NOT_ENCRYPTED:
+ LOG(ERROR) << "Error: unmet application encryption requirement";
+ break;
default:
LOG(ERROR) << "Unrecognized error: " << resp.error;
break;
diff --git a/trusty/apploader/apploader_ipc.h b/trusty/apploader/apploader_ipc.h
index 306596eba..f0376929c 100644
--- a/trusty/apploader/apploader_ipc.h
+++ b/trusty/apploader/apploader_ipc.h
@@ -45,6 +45,10 @@ enum apploader_command : uint32_t {
* @APPLOADER_ERR_INTERNAL: miscellaneous or internal apploader
* error not covered by the above
* @APPLOADER_ERR_INVALID_VERSION: invalid application version
+ * @APPLOADER_ERR_POLICY_VIOLATION: signature verification succeeded but
+ * key+manifest combination not allowed
+ * by app loader policy engine
+ * @APPLOADER_ERR_NOT_ENCRYPTED: unmet application encryption requirement
*/
enum apploader_error : uint32_t {
APPLOADER_NO_ERROR = 0,
@@ -57,6 +61,7 @@ enum apploader_error : uint32_t {
APPLOADER_ERR_INTERNAL,
APPLOADER_ERR_INVALID_VERSION,
APPLOADER_ERR_POLICY_VIOLATION,
+ APPLOADER_ERR_NOT_ENCRYPTED,
};
/**
diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h
index 3f1dcb8c6..255ade127 100644
--- a/trusty/storage/interface/include/trusty/interface/storage.h
+++ b/trusty/storage/interface/include/trusty/interface/storage.h
@@ -70,6 +70,9 @@ enum storage_cmd {
* @STORAGE_ERR_TRANSACT returned by various operations to indicate that current transaction
* is in error state. Such state could be only cleared by sending
* STORAGE_END_TRANSACTION message.
+ * @STORAGE_ERR_SYNC_FAILURE indicates that the current operation failed to sync
+ * to disk. Only returned if STORAGE_MSG_FLAG_PRE_COMMIT or
+ * STORAGE_MSG_FLAG_POST_COMMIT was set for the request.
*/
enum storage_err {
STORAGE_NO_ERROR = 0,
@@ -80,6 +83,7 @@ enum storage_err {
STORAGE_ERR_NOT_FOUND = 5,
STORAGE_ERR_EXIST = 6,
STORAGE_ERR_TRANSACT = 7,
+ STORAGE_ERR_SYNC_FAILURE = 8,
};
/**
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
index 94f26d8a6..e952ee0bc 100644
--- a/trusty/storage/proxy/Android.bp
+++ b/trusty/storage/proxy/Android.bp
@@ -32,11 +32,11 @@ cc_binary {
shared_libs: [
"libbase",
+ "libcutils",
"liblog",
"libhardware_legacy",
],
header_libs: [
- "libcutils_headers",
"libgsi_headers",
],
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 262003427..f01589287 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -116,10 +116,11 @@ static int drop_privs(void) {
static int handle_req(struct storage_msg* msg, const void* req, size_t req_len) {
int rc;
- if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) && (msg->cmd != STORAGE_RPMB_SEND)) {
+ if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) && msg->cmd != STORAGE_RPMB_SEND &&
+ msg->cmd != STORAGE_FILE_WRITE) {
/*
- * handling post commit messages on non rpmb commands are not
- * implemented as there is no use case for this yet.
+ * handling post commit messages on commands other than rpmb and write
+ * operations are not implemented as there is no use case for this yet.
*/
ALOGE("cmd 0x%x: post commit option is not implemented\n", msg->cmd);
msg->result = STORAGE_ERR_UNIMPLEMENTED;
@@ -129,7 +130,7 @@ static int handle_req(struct storage_msg* msg, const void* req, size_t req_len)
if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
rc = storage_sync_checkpoint();
if (rc < 0) {
- msg->result = STORAGE_ERR_GENERIC;
+ msg->result = STORAGE_ERR_SYNC_FAILURE;
return ipc_respond(msg, NULL, 0);
}
}
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index c00c399d9..033dc2117 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <cutils/properties.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -43,6 +44,22 @@ enum sync_state {
static const char *ssdir_name;
+/*
+ * Property set to 1 after we have opened a file under ssdir_name. The backing
+ * files for both TD and TDP are currently located under /data/vendor/ss and can
+ * only be opened once userdata is mounted. This storageproxyd service is
+ * restarted when userdata is available, which causes the Trusty storage service
+ * to reconnect and attempt to open the backing files for TD and TDP. Once we
+ * set this property, other users can expect that the Trusty storage service
+ * ports will be available (although they may block if still being initialized),
+ * and connections will not be reset after this point (assuming the
+ * storageproxyd service stays running).
+ */
+#define FS_READY_PROPERTY "ro.vendor.trusty.storage.fs_ready"
+
+/* has FS_READY_PROPERTY been set? */
+static bool fs_ready_initialized = false;
+
static enum sync_state fs_state;
static enum sync_state fd_state[FD_TBL_SIZE];
@@ -336,6 +353,16 @@ int storage_file_open(struct storage_msg* msg, const void* r, size_t req_len) {
ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
__func__, path, rc, resp.handle);
+ /* a backing file has been opened, notify any waiting init steps */
+ if (!fs_ready_initialized) {
+ rc = property_set(FS_READY_PROPERTY, "1");
+ if (rc == 0) {
+ fs_ready_initialized = true;
+ } else {
+ ALOGE("Could not set property %s, rc: %d\n", FS_READY_PROPERTY, rc);
+ }
+ }
+
return ipc_respond(msg, &resp, sizeof(resp));
err_response:
@@ -407,6 +434,14 @@ int storage_file_write(struct storage_msg *msg,
goto err_response;
}
+ if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
+ rc = storage_sync_checkpoint();
+ if (rc < 0) {
+ msg->result = STORAGE_ERR_SYNC_FAILURE;
+ goto err_response;
+ }
+ }
+
msg->result = STORAGE_NO_ERROR;
err_response: