Merge "[MTE] write stack history into tombstone" into main
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index baddf65..08619b9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -18,6 +18,7 @@
#include <dlfcn.h>
#include <err.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <linux/prctl.h>
#include <malloc.h>
#include <pthread.h>
@@ -69,7 +70,6 @@
#include "crash_test.h"
#include "debuggerd/handler.h"
#include "gtest/gtest.h"
-#include "libdebuggerd/utility.h"
#include "protocol.h"
#include "tombstoned/tombstoned.h"
#include "util.h"
@@ -86,6 +86,7 @@
#define ARCH_SUFFIX ""
#endif
+constexpr size_t kTagGranuleSize = 16;
constexpr char kWaitForDebuggerKey[] = "debug.debuggerd.wait_for_debugger";
#define TIMEOUT(seconds, expr) \
diff --git a/debuggerd/tombstoned/tombstoned.cpp b/debuggerd/tombstoned/tombstoned.cpp
index fa67d46..2c72379 100644
--- a/debuggerd/tombstoned/tombstoned.cpp
+++ b/debuggerd/tombstoned/tombstoned.cpp
@@ -158,7 +158,7 @@
}
}
- return std::move(result);
+ return result;
}
std::optional<CrashOutput> get_output(DebuggerdDumpType dump_type) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 3e70f79..76578dd 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1433,16 +1433,16 @@
// When multiple fstab records share the same mount_point, it will try to mount each
// one in turn, and ignore any duplicates after a first successful mount.
// Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
-MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
+int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
int error_count = 0;
CheckpointManager checkpoint_manager;
AvbUniquePtr avb_handle(nullptr);
bool wiped = false;
-
bool userdata_mounted = false;
+
if (fstab->empty()) {
- return {FS_MGR_MNTALL_FAIL, userdata_mounted};
+ return FS_MGR_MNTALL_FAIL;
}
bool scratch_can_be_mounted = true;
@@ -1521,7 +1521,7 @@
if (!avb_handle) {
LERROR << "Failed to open AvbHandle";
set_type_property(encryptable);
- return {FS_MGR_MNTALL_FAIL, userdata_mounted};
+ return FS_MGR_MNTALL_FAIL;
}
}
if (avb_handle->SetUpAvbHashtree(¤t_entry, true /* wait_for_verity_dev */) ==
@@ -1557,7 +1557,7 @@
if (status == FS_MGR_MNTALL_FAIL) {
// Fatal error - no point continuing.
- return {status, userdata_mounted};
+ return status;
}
if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
@@ -1577,7 +1577,7 @@
nullptr)) {
LERROR << "Encryption failed";
set_type_property(encryptable);
- return {FS_MGR_MNTALL_FAIL, userdata_mounted};
+ return FS_MGR_MNTALL_FAIL;
}
}
}
@@ -1696,9 +1696,9 @@
set_type_property(encryptable);
if (error_count) {
- return {FS_MGR_MNTALL_FAIL, userdata_mounted};
+ return FS_MGR_MNTALL_FAIL;
} else {
- return {encryptable, userdata_mounted};
+ return encryptable;
}
}
@@ -1735,190 +1735,6 @@
return ret;
}
-static std::chrono::milliseconds GetMillisProperty(const std::string& name,
- std::chrono::milliseconds default_value) {
- auto value = GetUintProperty(name, static_cast<uint64_t>(default_value.count()));
- return std::chrono::milliseconds(std::move(value));
-}
-
-static bool fs_mgr_unmount_all_data_mounts(const std::string& data_block_device) {
- LINFO << __FUNCTION__ << "(): about to umount everything on top of " << data_block_device;
- Timer t;
- auto timeout = GetMillisProperty("init.userspace_reboot.userdata_remount.timeoutmillis", 5s);
- while (true) {
- bool umount_done = true;
- Fstab proc_mounts;
- if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
- LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
- return false;
- }
- // Now proceed with other bind mounts on top of /data.
- for (const auto& entry : proc_mounts) {
- std::string block_device;
- if (StartsWith(entry.blk_device, "/dev/block") &&
- !Realpath(entry.blk_device, &block_device)) {
- PWARNING << __FUNCTION__ << "(): failed to realpath " << entry.blk_device;
- block_device = entry.blk_device;
- }
- if (data_block_device == block_device) {
- if (umount2(entry.mount_point.c_str(), 0) != 0) {
- PERROR << __FUNCTION__ << "(): Failed to umount " << entry.mount_point;
- umount_done = false;
- }
- }
- }
- if (umount_done) {
- LINFO << __FUNCTION__ << "(): Unmounting /data took " << t;
- return true;
- }
- if (t.duration() > timeout) {
- LERROR << __FUNCTION__ << "(): Timed out unmounting all mounts on "
- << data_block_device;
- Fstab remaining_mounts;
- if (!ReadFstabFromFile("/proc/mounts", &remaining_mounts)) {
- LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
- } else {
- LERROR << __FUNCTION__ << "(): Following mounts remaining";
- for (const auto& e : remaining_mounts) {
- LERROR << __FUNCTION__ << "(): mount point: " << e.mount_point
- << " block device: " << e.blk_device;
- }
- }
- return false;
- }
- std::this_thread::sleep_for(50ms);
- }
-}
-
-static bool UnwindDmDeviceStack(const std::string& block_device,
- std::vector<std::string>* dm_stack) {
- if (!StartsWith(block_device, "/dev/block/")) {
- LWARNING << block_device << " is not a block device";
- return false;
- }
- std::string current = block_device;
- DeviceMapper& dm = DeviceMapper::Instance();
- while (true) {
- dm_stack->push_back(current);
- if (!dm.IsDmBlockDevice(current)) {
- break;
- }
- auto parent = dm.GetParentBlockDeviceByPath(current);
- if (!parent) {
- return false;
- }
- current = *parent;
- }
- return true;
-}
-
-FstabEntry* fs_mgr_get_mounted_entry_for_userdata(Fstab* fstab,
- const std::string& data_block_device) {
- std::vector<std::string> dm_stack;
- if (!UnwindDmDeviceStack(data_block_device, &dm_stack)) {
- LERROR << "Failed to unwind dm-device stack for " << data_block_device;
- return nullptr;
- }
- for (auto& entry : *fstab) {
- if (entry.mount_point != "/data") {
- continue;
- }
- std::string block_device;
- if (entry.fs_mgr_flags.logical) {
- if (!fs_mgr_update_logical_partition(&entry)) {
- LERROR << "Failed to update logic partition " << entry.blk_device;
- continue;
- }
- block_device = entry.blk_device;
- } else if (!Realpath(entry.blk_device, &block_device)) {
- PWARNING << "Failed to realpath " << entry.blk_device;
- block_device = entry.blk_device;
- }
- if (std::find(dm_stack.begin(), dm_stack.end(), block_device) != dm_stack.end()) {
- return &entry;
- }
- }
- LERROR << "Didn't find entry that was used to mount /data onto " << data_block_device;
- return nullptr;
-}
-
-// TODO(b/143970043): return different error codes based on which step failed.
-int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
- Fstab proc_mounts;
- if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
- LERROR << "Can't read /proc/mounts";
- return -1;
- }
- auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
- if (mounted_entry == nullptr) {
- LERROR << "/data is not mounted";
- return -1;
- }
- std::string block_device;
- if (!Realpath(mounted_entry->blk_device, &block_device)) {
- PERROR << "Failed to realpath " << mounted_entry->blk_device;
- return -1;
- }
- auto fstab_entry = fs_mgr_get_mounted_entry_for_userdata(fstab, block_device);
- if (fstab_entry == nullptr) {
- LERROR << "Can't find /data in fstab";
- return -1;
- }
- bool force_umount = GetBoolProperty("sys.init.userdata_remount.force_umount", false);
- if (force_umount) {
- LINFO << "Will force an umount of userdata even if it's not required";
- }
- if (!force_umount && !SupportsCheckpoint(fstab_entry)) {
- LINFO << "Userdata doesn't support checkpointing. Nothing to do";
- return 0;
- }
- CheckpointManager checkpoint_manager;
- if (!force_umount && !checkpoint_manager.NeedsCheckpoint()) {
- LINFO << "Checkpointing not needed. Don't remount";
- return 0;
- }
- if (!force_umount && fstab_entry->fs_mgr_flags.checkpoint_fs) {
- // Userdata is f2fs, simply remount it.
- if (!checkpoint_manager.Update(fstab_entry)) {
- LERROR << "Failed to remount userdata in checkpointing mode";
- return -1;
- }
- if (mount(block_device.c_str(), fstab_entry->mount_point.c_str(), "none",
- MS_REMOUNT | fstab_entry->flags, fstab_entry->fs_options.c_str()) != 0) {
- PERROR << "Failed to remount userdata in checkpointing mode";
- return -1;
- }
- } else {
- LINFO << "Unmounting /data before remounting into checkpointing mode";
- if (!fs_mgr_unmount_all_data_mounts(block_device)) {
- LERROR << "Failed to umount /data";
- return -1;
- }
- DeviceMapper& dm = DeviceMapper::Instance();
- while (dm.IsDmBlockDevice(block_device)) {
- auto next_device = dm.GetParentBlockDeviceByPath(block_device);
- auto name = dm.GetDmDeviceNameByPath(block_device);
- if (!name) {
- LERROR << "Failed to get dm-name for " << block_device;
- return -1;
- }
- LINFO << "Deleting " << block_device << " named " << *name;
- if (!dm.DeleteDevice(*name, 3s)) {
- return -1;
- }
- if (!next_device) {
- LERROR << "Failed to find parent device for " << block_device;
- }
- block_device = *next_device;
- }
- LINFO << "Remounting /data";
- // TODO(b/143970043): remove this hack after fs_mgr_mount_all is refactored.
- auto result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
- return result.code == FS_MGR_MNTALL_FAIL ? -1 : 0;
- }
- return 0;
-}
-
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& alt_mount_point) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 2e1cf76..af5ae2d 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -58,13 +58,8 @@
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 4
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
-
-struct MountAllResult {
- // One of the FS_MGR_MNTALL_* returned code defined above.
- int code;
- // Whether userdata was mounted as a result of |fs_mgr_mount_all| call.
- bool userdata_mounted;
-};
+// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
+int fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
struct HashtreeInfo {
// The hash algorithm used to build the merkle tree.
@@ -75,13 +70,6 @@
bool check_at_most_once;
};
-// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
-// Returns a |MountAllResult|. The first element is one of the FS_MNG_MNTALL_* return codes
-// defined above, and the second element tells whether this call to fs_mgr_mount_all was responsible
-// for mounting userdata. Later is required for init to correctly enqueue fs-related events as part
-// of userdata remount during userspace reboot.
-MountAllResult fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
-
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
#define FS_MGR_DOMNT_SUCCESS 0
@@ -127,11 +115,6 @@
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
-// Finds a entry in |fstab| that was used to mount a /data on |data_block_device|.
-android::fs_mgr::FstabEntry* fs_mgr_get_mounted_entry_for_userdata(
- android::fs_mgr::Fstab* fstab, const std::string& data_block_device);
-int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);
-
// Finds the dm_bow device on which this block device is stacked, or returns
// empty string
std::string fs_mgr_find_bow_device(const std::string& block_device);
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index cc6db35..f297125 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -294,7 +294,7 @@
],
test_suites: [
"vts",
- "device-tests",
+ "general-tests",
],
test_options: {
min_shipping_api_level: 30,
@@ -311,7 +311,7 @@
"-DLIBSNAPSHOT_TEST_VAB_LEGACY",
],
test_suites: [
- "device-tests",
+ "general-tests",
],
test_options: {
// Legacy VAB launched in Android R.
@@ -420,7 +420,7 @@
"libstorage_literals_headers",
],
test_suites: [
- "device-tests",
+ "general-tests",
],
test_options: {
min_shipping_api_level: 30,
diff --git a/fs_mgr/libsnapshot/device_info.cpp b/fs_mgr/libsnapshot/device_info.cpp
index 0ab6103..e0969f4 100644
--- a/fs_mgr/libsnapshot/device_info.cpp
+++ b/fs_mgr/libsnapshot/device_info.cpp
@@ -104,6 +104,24 @@
return first_stage_init_;
}
+bool DeviceInfo::SetActiveBootSlot([[maybe_unused]] unsigned int slot) {
+#ifdef LIBSNAPSHOT_USE_HAL
+ if (!EnsureBootHal()) {
+ return false;
+ }
+
+ CommandResult result = boot_control_->SetActiveBootSlot(slot);
+ if (!result.success) {
+ LOG(ERROR) << "Error setting slot " << slot << " active: " << result.errMsg;
+ return false;
+ }
+ return true;
+#else
+ LOG(ERROR) << "HAL support not enabled.";
+ return false;
+#endif
+}
+
bool DeviceInfo::SetSlotAsUnbootable([[maybe_unused]] unsigned int slot) {
#ifdef LIBSNAPSHOT_USE_HAL
if (!EnsureBootHal()) {
diff --git a/fs_mgr/libsnapshot/device_info.h b/fs_mgr/libsnapshot/device_info.h
index d06f1be..9153abb 100644
--- a/fs_mgr/libsnapshot/device_info.h
+++ b/fs_mgr/libsnapshot/device_info.h
@@ -36,6 +36,7 @@
std::string GetSuperDevice(uint32_t slot) const override;
bool IsOverlayfsSetup() const override;
bool SetBootControlMergeStatus(MergeStatus status) override;
+ bool SetActiveBootSlot(unsigned int slot) override;
bool SetSlotAsUnbootable(unsigned int slot) override;
bool IsRecovery() const override;
std::unique_ptr<IImageManager> OpenImageManager() const override;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
index 573a85b..ca1ac1e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_device_info.h
@@ -29,6 +29,7 @@
MOCK_METHOD(const android::fs_mgr::IPartitionOpener&, GetPartitionOpener, (), (const));
MOCK_METHOD(bool, IsOverlayfsSetup, (), (const, override));
MOCK_METHOD(bool, SetBootControlMergeStatus, (MergeStatus status), (override));
+ MOCK_METHOD(bool, SetActiveBootSlot, (unsigned int slot), (override));
MOCK_METHOD(bool, SetSlotAsUnbootable, (unsigned int slot), (override));
MOCK_METHOD(bool, IsRecovery, (), (const, override));
MOCK_METHOD(bool, IsFirstStageInit, (), (const, override));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 4a3ec1d..deb2d6e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -104,6 +104,7 @@
virtual const android::fs_mgr::IPartitionOpener& GetPartitionOpener() const = 0;
virtual bool IsOverlayfsSetup() const = 0;
virtual bool SetBootControlMergeStatus(MergeStatus status) = 0;
+ virtual bool SetActiveBootSlot(unsigned int slot) = 0;
virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
virtual bool IsRecovery() const = 0;
virtual bool IsTestDevice() const { return false; }
@@ -675,6 +676,8 @@
std::string GetBootSnapshotsWithoutSlotSwitchPath();
std::string GetSnapuserdFromSystemPath();
+ bool HasForwardMergeIndicator();
+
const LpMetadata* ReadOldPartitionMetadata(LockedFile* lock);
bool MapAllPartitions(LockedFile* lock, const std::string& super_device, uint32_t slot,
@@ -785,11 +788,8 @@
bool UpdateForwardMergeIndicator(bool wipe);
// Helper for HandleImminentDataWipe.
- // Call ProcessUpdateState and handle states with special rules before data wipe. Specifically,
- // if |allow_forward_merge| and allow-forward-merge indicator exists, initiate merge if
- // necessary.
- UpdateState ProcessUpdateStateOnDataWipe(bool allow_forward_merge,
- const std::function<bool()>& callback);
+ // Call ProcessUpdateState and handle states with special rules before data wipe.
+ UpdateState ProcessUpdateStateOnDataWipe(const std::function<bool()>& callback);
// Return device string of a mapped image, or if it is not available, the mapped image path.
bool GetMappedImageDeviceStringOrPath(const std::string& device_name,
@@ -848,7 +848,6 @@
std::string metadata_dir_;
std::unique_ptr<IImageManager> images_;
bool use_first_stage_snapuserd_ = false;
- bool in_factory_data_reset_ = false;
std::function<bool(const std::string&)> uevent_regen_callback_;
std::unique_ptr<SnapuserdClient> snapuserd_client_;
std::unique_ptr<LpMetadata> old_partition_metadata_;
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 0afd8bd..620b03c 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -92,6 +92,7 @@
}
bool IsOverlayfsSetup() const override { return false; }
bool IsRecovery() const override { return recovery_; }
+ bool SetActiveBootSlot([[maybe_unused]] unsigned int slot) override { return true; }
bool SetSlotAsUnbootable(unsigned int slot) override {
unbootable_slots_.insert(slot);
return true;
diff --git a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
index a4a2c1a..8356c0c 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
+++ b/fs_mgr/libsnapshot/partition_cow_creator_test.cpp
@@ -250,8 +250,8 @@
.target_partition = system_b,
.current_metadata = builder_a.get(),
.current_suffix = "_a",
- .using_snapuserd = true,
- .update = &update};
+ .update = &update,
+ .using_snapuserd = true};
auto ret = creator.Run();
ASSERT_TRUE(ret.has_value());
@@ -276,8 +276,8 @@
.target_partition = system_b,
.current_metadata = builder_a.get(),
.current_suffix = "_a",
- .using_snapuserd = true,
- .update = nullptr};
+ .update = nullptr,
+ .using_snapuserd = true};
auto ret = creator.Run();
ASSERT_FALSE(ret.has_value());
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 265445b..108fd90 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -4005,44 +4005,90 @@
// We allow the wipe to continue, because if we can't mount /metadata,
// it is unlikely the device would have booted anyway. If there is no
// metadata partition, then the device predates Virtual A/B.
+ LOG(INFO) << "/metadata not found; allowing wipe.";
return true;
}
- // Check this early, so we don't accidentally start trying to populate
- // the state file in recovery. Note we don't call GetUpdateState since
- // we want errors in acquiring the lock to be propagated, instead of
- // returning UpdateState::None.
- auto state_file = GetStateFilePath();
- if (access(state_file.c_str(), F_OK) != 0 && errno == ENOENT) {
- return true;
- }
-
- auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
- auto super_path = device_->GetSuperDevice(slot_number);
- if (!CreateLogicalAndSnapshotPartitions(super_path, 20s)) {
- LOG(ERROR) << "Unable to map partitions to complete merge.";
- return false;
- }
-
- auto process_callback = [&]() -> bool {
- if (callback) {
- callback();
+ // This could happen if /metadata mounted but there is no filesystem
+ // structure. Weird, but we have to assume there's no OTA pending, and
+ // thus we let the wipe proceed.
+ UpdateState state;
+ {
+ auto lock = LockExclusive();
+ if (!lock) {
+ LOG(ERROR) << "Unable to determine update state; allowing wipe.";
+ return true;
}
- return true;
- };
- in_factory_data_reset_ = true;
- UpdateState state =
- ProcessUpdateStateOnDataWipe(true /* allow_forward_merge */, process_callback);
- in_factory_data_reset_ = false;
-
- if (state == UpdateState::MergeFailed) {
- return false;
+ state = ReadUpdateState(lock.get());
+ LOG(INFO) << "Update state before wipe: " << state << "; slot: " << GetCurrentSlot()
+ << "; suffix: " << device_->GetSlotSuffix();
}
- // Nothing should be depending on partitions now, so unmap them all.
- if (!UnmapAllPartitionsInRecovery()) {
- LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
+ bool try_merge = false;
+ switch (state) {
+ case UpdateState::None:
+ case UpdateState::Initiated:
+ LOG(INFO) << "Wipe is not impacted by update state; allowing wipe.";
+ break;
+ case UpdateState::Unverified:
+ if (GetCurrentSlot() != Slot::Target) {
+ LOG(INFO) << "Wipe is not impacted by rolled back update; allowing wipe";
+ break;
+ }
+ if (!HasForwardMergeIndicator()) {
+ auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
+ auto other_slot_number = SlotNumberForSlotSuffix(device_->GetOtherSlotSuffix());
+
+ // We're not allowed to forward merge, so forcefully rollback the
+ // slot switch.
+ LOG(INFO) << "Allowing wipe due to lack of forward merge indicator; reverting to "
+ "old slot since update will be deleted.";
+ device_->SetSlotAsUnbootable(slot_number);
+ device_->SetActiveBootSlot(other_slot_number);
+ break;
+ }
+
+ // Forward merge indicator means we have to mount snapshots and try to merge.
+ LOG(INFO) << "Forward merge indicator is present.";
+ try_merge = true;
+ break;
+ case UpdateState::Merging:
+ case UpdateState::MergeFailed:
+ try_merge = true;
+ break;
+ case UpdateState::MergeNeedsReboot:
+ case UpdateState::Cancelled:
+ LOG(INFO) << "Unexpected update state in recovery; allowing wipe.";
+ break;
+ default:
+ break;
+ }
+
+ if (try_merge) {
+ auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
+ auto super_path = device_->GetSuperDevice(slot_number);
+ if (!CreateLogicalAndSnapshotPartitions(super_path, 20s)) {
+ LOG(ERROR) << "Unable to map partitions to complete merge.";
+ return false;
+ }
+
+ auto process_callback = [&]() -> bool {
+ if (callback) {
+ callback();
+ }
+ return true;
+ };
+
+ state = ProcessUpdateStateOnDataWipe(process_callback);
+ if (state == UpdateState::MergeFailed) {
+ return false;
+ }
+
+ // Nothing should be depending on partitions now, so unmap them all.
+ if (!UnmapAllPartitionsInRecovery()) {
+ LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
+ }
}
if (state != UpdateState::None) {
@@ -4088,58 +4134,40 @@
return true;
}
-UpdateState SnapshotManager::ProcessUpdateStateOnDataWipe(bool allow_forward_merge,
- const std::function<bool()>& callback) {
- auto slot_number = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
- UpdateState state = ProcessUpdateState(callback);
- LOG(INFO) << "Update state in recovery: " << state;
- switch (state) {
- case UpdateState::MergeFailed:
- LOG(ERROR) << "Unrecoverable merge failure detected.";
- return state;
- case UpdateState::Unverified: {
- // If an OTA was just applied but has not yet started merging:
- //
- // - if forward merge is allowed, initiate merge and call
- // ProcessUpdateState again.
- //
- // - if forward merge is not allowed, we
- // have no choice but to revert slots, because the current slot will
- // immediately become unbootable. Rather than wait for the device
- // to reboot N times until a rollback, we proactively disable the
- // new slot instead.
- //
- // Since the rollback is inevitable, we don't treat a HAL failure
- // as an error here.
- auto slot = GetCurrentSlot();
- if (slot == Slot::Target) {
- if (allow_forward_merge &&
- access(GetForwardMergeIndicatorPath().c_str(), F_OK) == 0) {
- LOG(INFO) << "Forward merge allowed, initiating merge now.";
-
- if (!InitiateMerge()) {
- LOG(ERROR) << "Failed to initiate merge on data wipe.";
- return UpdateState::MergeFailed;
- }
- return ProcessUpdateStateOnDataWipe(false /* allow_forward_merge */, callback);
+UpdateState SnapshotManager::ProcessUpdateStateOnDataWipe(const std::function<bool()>& callback) {
+ while (true) {
+ UpdateState state = ProcessUpdateState(callback);
+ LOG(INFO) << "Processed updated state in recovery: " << state;
+ switch (state) {
+ case UpdateState::MergeFailed:
+ LOG(ERROR) << "Unrecoverable merge failure detected.";
+ return state;
+ case UpdateState::Unverified: {
+ // Unverified was already handled earlier, in HandleImminentDataWipe,
+ // but it will fall through here if a forward merge is required.
+ //
+ // If InitiateMerge fails, we early return. If it succeeds, then we
+ // are guaranteed that the next call to ProcessUpdateState will not
+ // return Unverified.
+ if (!InitiateMerge()) {
+ LOG(ERROR) << "Failed to initiate merge on data wipe.";
+ return UpdateState::MergeFailed;
}
-
- LOG(ERROR) << "Reverting to old slot since update will be deleted.";
- device_->SetSlotAsUnbootable(slot_number);
- } else {
- LOG(INFO) << "Booting from " << slot << " slot, no action is taken.";
+ continue;
}
- break;
+ case UpdateState::MergeNeedsReboot:
+ // We shouldn't get here, because nothing is depending on
+ // logical partitions.
+ LOG(ERROR) << "Unexpected merge-needs-reboot state in recovery.";
+ return state;
+ default:
+ return state;
}
- case UpdateState::MergeNeedsReboot:
- // We shouldn't get here, because nothing is depending on
- // logical partitions.
- LOG(ERROR) << "Unexpected merge-needs-reboot state in recovery.";
- break;
- default:
- break;
}
- return state;
+}
+
+bool SnapshotManager::HasForwardMergeIndicator() {
+ return access(GetForwardMergeIndicatorPath().c_str(), F_OK) == 0;
}
bool SnapshotManager::EnsureNoOverflowSnapshot(LockedFile* lock) {
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index b2e36d4..16c247f 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -2102,10 +2102,10 @@
test_device->set_recovery(true);
auto new_sm = NewManagerForFirstStageMount(test_device);
+ EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::Unverified);
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
// Manually mount metadata so that we can call GetUpdateState() below.
MountMetadata();
- EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
EXPECT_TRUE(test_device->IsSlotUnbootable(1));
EXPECT_FALSE(test_device->IsSlotUnbootable(0));
}
@@ -2127,6 +2127,7 @@
test_device->set_recovery(true);
auto new_sm = NewManagerForFirstStageMount(test_device);
+ EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::Unverified);
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::None);
EXPECT_FALSE(test_device->IsSlotUnbootable(0));
@@ -2135,10 +2136,6 @@
// Test update package that requests data wipe.
TEST_F(SnapshotUpdateTest, DataWipeRequiredInPackage) {
- if (ShouldSkipLegacyMerging()) {
- GTEST_SKIP() << "Skipping legacy merge in test";
- }
-
AddOperationForPartitions();
// Execute the update.
ASSERT_TRUE(sm->BeginUpdate());
@@ -2157,6 +2154,7 @@
test_device->set_recovery(true);
auto new_sm = NewManagerForFirstStageMount(test_device);
+ EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::Unverified);
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
// Manually mount metadata so that we can call GetUpdateState() below.
MountMetadata();
@@ -2178,10 +2176,6 @@
// Test update package that requests data wipe.
TEST_F(SnapshotUpdateTest, DataWipeWithStaleSnapshots) {
- if (ShouldSkipLegacyMerging()) {
- GTEST_SKIP() << "Skipping legacy merge in test";
- }
-
AddOperationForPartitions();
// Execute the update.
@@ -2222,6 +2216,7 @@
test_device->set_recovery(true);
auto new_sm = NewManagerForFirstStageMount(test_device);
+ EXPECT_EQ(new_sm->GetUpdateState(), UpdateState::Unverified);
ASSERT_TRUE(new_sm->HandleImminentDataWipe());
// Manually mount metadata so that we can call GetUpdateState() below.
MountMetadata();
@@ -2840,7 +2835,6 @@
// that is fixed, don't call GTEST_SKIP here, but instead call GTEST_SKIP in individual test
// suites.
RETURN_IF_NON_VIRTUAL_AB_MSG("Virtual A/B is not enabled, skipping global setup.\n");
- RETURN_IF_VENDOR_ON_ANDROID_S_MSG("Test not enabled for Vendor on Android S.\n");
std::vector<std::string> paths = {
// clang-format off
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 c0af5c5..013df35 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -22,6 +22,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
+#include <sys/system_properties.h>
#include <sys/types.h>
#include <unistd.h>
@@ -35,9 +36,6 @@
#include <snapuserd/snapuserd_client.h>
#include "snapuserd_server.h"
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
namespace android {
namespace snapshot {
diff --git a/fs_mgr/tests/AndroidTest.xml b/fs_mgr/tests/AndroidTest.xml
index de835b3..1c06ebd 100644
--- a/fs_mgr/tests/AndroidTest.xml
+++ b/fs_mgr/tests/AndroidTest.xml
@@ -16,6 +16,7 @@
<option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user_on_secondary_display" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
<option name="cleanup" value="true" />
<option name="push" value="CtsFsMgrTestCases->/data/local/tmp/CtsFsMgrTestCases" />
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 322bf1b..bd3d6b5 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -1062,23 +1062,6 @@
<< "Default fstab doesn't contain /data entry";
}
-TEST(fs_mgr, UserdataMountedFromDefaultFstab) {
- if (getuid() != 0) {
- GTEST_SKIP() << "Must be run as root.";
- return;
- }
- Fstab fstab;
- ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab";
- Fstab proc_mounts;
- ASSERT_TRUE(ReadFstabFromFile("/proc/mounts", &proc_mounts)) << "Failed to read /proc/mounts";
- auto mounted_entry = GetEntryForMountPoint(&proc_mounts, "/data");
- ASSERT_NE(mounted_entry, nullptr) << "/data is not mounted";
- std::string block_device;
- ASSERT_TRUE(android::base::Realpath(mounted_entry->blk_device, &block_device));
- ASSERT_NE(nullptr, fs_mgr_get_mounted_entry_for_userdata(&fstab, block_device))
- << "/data wasn't mounted from default fstab";
-}
-
TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Readahead_Size_KB) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
diff --git a/init/Android.bp b/init/Android.bp
index ffb6380..ed1f148 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -226,7 +226,6 @@
],
whole_static_libs: [
"libcap",
- "libcom.android.sysprop.init",
],
header_libs: ["bootimg_headers"],
proto: {
diff --git a/init/README.md b/init/README.md
index 0bb26e8..1e15765 100644
--- a/init/README.md
+++ b/init/README.md
@@ -636,7 +636,7 @@
Properties are expanded within _level_.
`mark_post_data`
-> Used to mark the point right after /data is mounted.
+> (This action is deprecated and no-op.)
`mkdir <path> [<mode>] [<owner>] [<group>] [encryption=<action>] [key=<key>]`
> Create a directory at _path_, optionally with the given mode, owner, and
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 606ea8c..3f3bec6 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -46,7 +46,6 @@
#include <map>
#include <memory>
-#include <InitProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -606,8 +605,6 @@
return Error() << "Invalid code: " << code;
}
-static int initial_mount_fstab_return_code = -1;
-
/* <= Q: mount_all <fstab> [ <path> ]* [--<options>]*
* >= R: mount_all [ <fstab> ] [--<options>]*
*
@@ -648,19 +645,10 @@
import_late(mount_all->rc_paths);
}
- if (mount_fstab_result.userdata_mounted) {
- // This call to fs_mgr_mount_all mounted userdata. Keep the result in
- // order for userspace reboot to correctly remount userdata.
- LOG(INFO) << "Userdata mounted using "
- << (mount_all->fstab_path.empty() ? "(default fstab)" : mount_all->fstab_path)
- << " result : " << mount_fstab_result.code;
- initial_mount_fstab_return_code = mount_fstab_result.code;
- }
-
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
- auto queue_fs_result = queue_fs_event(mount_fstab_result.code);
+ auto queue_fs_result = queue_fs_event(mount_fstab_result);
if (!queue_fs_result.ok()) {
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
}
@@ -1148,29 +1136,19 @@
}
static Result<void> ExecVdcRebootOnFailure(const std::string& vdc_arg) {
- bool should_reboot_into_recovery = true;
auto reboot_reason = vdc_arg + "_failed";
- if (android::sysprop::InitProperties::userspace_reboot_in_progress().value_or(false)) {
- should_reboot_into_recovery = false;
- reboot_reason = "userspace_failed," + vdc_arg;
- }
- auto reboot = [reboot_reason, should_reboot_into_recovery](const std::string& message) {
+ auto reboot = [reboot_reason](const std::string& message) {
// TODO (b/122850122): support this in gsi
- if (should_reboot_into_recovery) {
- if (IsFbeEnabled() && !android::gsi::IsGsiRunning()) {
- LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason;
- if (auto result = reboot_into_recovery(
- {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
- !result.ok()) {
- LOG(FATAL) << "Could not reboot into recovery: " << result.error();
- }
- } else {
- LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
+ if (IsFbeEnabled() && !android::gsi::IsGsiRunning()) {
+ LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason;
+ if (auto result = reboot_into_recovery(
+ {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+ !result.ok()) {
+ LOG(FATAL) << "Could not reboot into recovery: " << result.error();
}
} else {
- LOG(ERROR) << message << ": rebooting, reason: " << reboot_reason;
- trigger_shutdown("reboot," + reboot_reason);
+ LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
}
};
@@ -1178,29 +1156,6 @@
return ExecWithFunctionOnFailure(args, reboot);
}
-static Result<void> do_remount_userdata(const BuiltinArguments& args) {
- if (initial_mount_fstab_return_code == -1) {
- return Error() << "Calling remount_userdata too early";
- }
- Fstab fstab;
- if (!ReadDefaultFstab(&fstab)) {
- // TODO(b/135984674): should we reboot here?
- return Error() << "Failed to read fstab";
- }
- // TODO(b/135984674): check that fstab contains /data.
- if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
- std::string proc_mounts_output;
- android::base::ReadFileToString("/proc/mounts", &proc_mounts_output, true);
- android::base::WriteStringToFile(proc_mounts_output,
- "/metadata/userspacereboot/mount_info.txt");
- trigger_shutdown("reboot,mount_userdata_failed");
- }
- if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result.ok()) {
- return Error() << "queue_fs_event() failed: " << result.error();
- }
- return {};
-}
-
static Result<void> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return {};
@@ -1216,8 +1171,7 @@
}
static Result<void> do_mark_post_data(const BuiltinArguments& args) {
- ServiceList::GetInstance().MarkPostData();
-
+ LOG(INFO) << "deprecated action `mark_post_data` called.";
return {};
}
@@ -1361,7 +1315,6 @@
{"umount_all", {0, 1, {false, do_umount_all}}},
{"update_linker_config", {0, 0, {false, do_update_linker_config}}},
{"readahead", {1, 2, {true, do_readahead}}},
- {"remount_userdata", {0, 0, {false, do_remount_userdata}}},
{"restart", {1, 2, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
diff --git a/init/init.cpp b/init/init.cpp
index 19e909f..4878660 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -26,13 +26,11 @@
#include <sys/eventfd.h>
#include <sys/mount.h>
#include <sys/signalfd.h>
+#include <sys/system_properties.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include <unistd.h>
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
#include <filesystem>
#include <fstream>
#include <functional>
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0d6eb15..4d3742a 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -31,14 +31,12 @@
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/select.h>
+#include <sys/system_properties.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <wchar.h>
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
#include <map>
#include <memory>
#include <mutex>
@@ -48,7 +46,6 @@
#include <thread>
#include <vector>
-#include <InitProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -102,7 +99,6 @@
using android::properties::ParsePropertyInfoFile;
using android::properties::PropertyInfoAreaFile;
using android::properties::PropertyInfoEntry;
-using android::sysprop::InitProperties::is_userspace_reboot_supported;
namespace android {
namespace init {
@@ -569,8 +565,8 @@
}
LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
<< process_log_string;
- if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
- *error = "Userspace reboot is not supported by this device";
+ if (value == "reboot,userspace") {
+ *error = "Userspace reboot is deprecated.";
return {PROP_ERROR_INVALID_VALUE};
}
}
diff --git a/init/property_service_test.cpp b/init/property_service_test.cpp
index 5f34cc4..c12ff72 100644
--- a/init/property_service_test.cpp
+++ b/init/property_service_test.cpp
@@ -16,11 +16,9 @@
#include <errno.h>
#include <sys/socket.h>
+#include <sys/system_properties.h>
#include <sys/un.h>
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
#include <android-base/properties.h>
#include <android-base/scopeguard.h>
#include <android-base/strings.h>
@@ -82,12 +80,6 @@
GTEST_SKIP() << "Skipping test, must be run as root.";
return;
}
- const std::string original_value = GetProperty("init.userspace_reboot.is_supported", "");
- auto guard = android::base::make_scope_guard([&original_value]() {
- SetProperty("init.userspace_reboot.is_supported", original_value);
- });
-
- ASSERT_TRUE(SetProperty("init.userspace_reboot.is_supported", "false"));
EXPECT_FALSE(SetProperty("sys.powerctl", "reboot,userspace"));
}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 150f8f4..ef9db9f 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -39,7 +39,6 @@
#include <thread>
#include <vector>
-#include <InitProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -87,16 +86,6 @@
static const std::set<std::string> kDebuggingServices{"tombstoned", "logd", "adbd", "console"};
-static std::set<std::string> GetPostDataDebuggingServices() {
- std::set<std::string> ret;
- for (const auto& s : ServiceList::GetInstance()) {
- if (kDebuggingServices.count(s->name()) && s->is_post_data()) {
- ret.insert(s->name());
- }
- }
- return ret;
-}
-
static void PersistRebootReason(const char* reason, bool write_to_property) {
if (write_to_property) {
SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
@@ -810,196 +799,6 @@
}
}
-static void LeaveShutdown() {
- LOG(INFO) << "Leaving shutdown mode";
- shutting_down = false;
- StartSendingMessages();
-}
-
-static std::chrono::milliseconds GetMillisProperty(const std::string& name,
- std::chrono::milliseconds default_value) {
- auto value = GetUintProperty(name, static_cast<uint64_t>(default_value.count()));
- return std::chrono::milliseconds(std::move(value));
-}
-
-static Result<void> DoUserspaceReboot() {
- LOG(INFO) << "Userspace reboot initiated";
- // An ugly way to pass a more precise reason on why fallback to hard reboot was triggered.
- std::string sub_reason = "";
- auto guard = android::base::make_scope_guard([&sub_reason] {
- // Leave shutdown so that we can handle a full reboot.
- LeaveShutdown();
- trigger_shutdown("reboot,userspace_failed,shutdown_aborted," + sub_reason);
- });
- // Triggering userspace-reboot-requested will result in a bunch of setprop
- // actions. We should make sure, that all of them are propagated before
- // proceeding with userspace reboot. Synchronously setting sys.init.userspace_reboot.in_progress
- // property is not perfect, but it should do the trick.
- if (!android::sysprop::InitProperties::userspace_reboot_in_progress(true)) {
- sub_reason = "setprop";
- return Error() << "Failed to set sys.init.userspace_reboot.in_progress property";
- }
- EnterShutdown();
- if (!SetProperty("sys.powerctl", "")) {
- sub_reason = "resetprop";
- return Error() << "Failed to reset sys.powerctl property";
- }
- std::set<std::string> stop_first;
- // Remember the services that were enabled. We will need to manually enable them again otherwise
- // triggers like class_start won't restart them.
- std::set<std::string> were_enabled;
- for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
- if (s->is_post_data() && !kDebuggingServices.count(s->name())) {
- stop_first.insert(s->name());
- }
- // TODO(ioffe): we should also filter out temporary services here.
- if (s->is_post_data() && s->IsEnabled()) {
- were_enabled.insert(s->name());
- }
- }
- {
- Timer sync_timer;
- LOG(INFO) << "sync() before terminating services...";
- sync();
- LOG(INFO) << "sync() took " << sync_timer;
- }
- auto sigterm_timeout = GetMillisProperty("init.userspace_reboot.sigterm.timeoutmillis", 5s);
- auto sigkill_timeout = GetMillisProperty("init.userspace_reboot.sigkill.timeoutmillis", 10s);
- LOG(INFO) << "Timeout to terminate services: " << sigterm_timeout.count() << "ms "
- << "Timeout to kill services: " << sigkill_timeout.count() << "ms";
- std::string services_file_name = "/metadata/userspacereboot/services.txt";
- const int flags = O_RDWR | O_CREAT | O_SYNC | O_APPEND | O_CLOEXEC;
- StopServicesAndLogViolations(stop_first, sigterm_timeout, true /* SIGTERM */);
- if (int r = StopServicesAndLogViolations(stop_first, sigkill_timeout, false /* SIGKILL */);
- r > 0) {
- auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
- android::base::WriteStringToFd("Post-data services still running: \n", fd);
- for (const auto& s : ServiceList::GetInstance()) {
- if (s->IsRunning() && stop_first.count(s->name())) {
- android::base::WriteStringToFd(s->name() + "\n", fd);
- }
- }
- sub_reason = "sigkill";
- return Error() << r << " post-data services are still running";
- }
- if (auto result = KillZramBackingDevice(); !result.ok()) {
- sub_reason = "zram";
- return result;
- }
- if (auto result = CallVdc("volume", "reset"); !result.ok()) {
- sub_reason = "vold_reset";
- return result;
- }
- const auto& debugging_services = GetPostDataDebuggingServices();
- if (int r = StopServicesAndLogViolations(debugging_services, sigkill_timeout,
- false /* SIGKILL */);
- r > 0) {
- auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
- android::base::WriteStringToFd("Debugging services still running: \n", fd);
- for (const auto& s : ServiceList::GetInstance()) {
- if (s->IsRunning() && debugging_services.count(s->name())) {
- android::base::WriteStringToFd(s->name() + "\n", fd);
- }
- }
- sub_reason = "sigkill_debug";
- return Error() << r << " debugging services are still running";
- }
- {
- Timer sync_timer;
- LOG(INFO) << "sync() after stopping services...";
- sync();
- LOG(INFO) << "sync() took " << sync_timer;
- }
- if (auto result = UnmountAllApexes(); !result.ok()) {
- sub_reason = "apex";
- return result;
- }
- if (!SwitchToMountNamespaceIfNeeded(NS_BOOTSTRAP).ok()) {
- sub_reason = "ns_switch";
- return Error() << "Failed to switch to bootstrap namespace";
- }
- ActionManager::GetInstance().RemoveActionIf([](const auto& action) -> bool {
- if (action->IsFromApex()) {
- std::string trigger_name = action->BuildTriggersString();
- LOG(INFO) << "Removing action (" << trigger_name << ") from (" << action->filename()
- << ":" << action->line() << ")";
- return true;
- }
- return false;
- });
- // Remove services that were defined in an APEX
- ServiceList::GetInstance().RemoveServiceIf([](const std::unique_ptr<Service>& s) -> bool {
- if (s->is_from_apex()) {
- LOG(INFO) << "Removing service '" << s->name() << "' because it's defined in an APEX";
- return true;
- }
- return false;
- });
- // Re-enable services
- for (const auto& s : ServiceList::GetInstance()) {
- if (were_enabled.count(s->name())) {
- LOG(INFO) << "Re-enabling service '" << s->name() << "'";
- s->Enable();
- }
- }
- ServiceList::GetInstance().ResetState();
- LeaveShutdown();
- ActionManager::GetInstance().QueueEventTrigger("userspace-reboot-resume");
- guard.Disable(); // Go on with userspace reboot.
- return {};
-}
-
-static void UserspaceRebootWatchdogThread() {
- auto started_timeout = GetMillisProperty("init.userspace_reboot.started.timeoutmillis", 10s);
- if (!WaitForProperty("sys.init.userspace_reboot.in_progress", "1", started_timeout)) {
- LOG(ERROR) << "Userspace reboot didn't start in " << started_timeout.count()
- << "ms. Switching to full reboot";
- // Init might be wedged, don't try to write reboot reason into a persistent property and do
- // a dirty reboot.
- PersistRebootReason("userspace_failed,watchdog_triggered,failed_to_start", false);
- RebootSystem(ANDROID_RB_RESTART2, "userspace_failed,watchdog_triggered,failed_to_start");
- }
- LOG(INFO) << "Starting userspace reboot watchdog";
- auto watchdog_timeout = GetMillisProperty("init.userspace_reboot.watchdog.timeoutmillis", 5min);
- LOG(INFO) << "UserspaceRebootWatchdog timeout: " << watchdog_timeout.count() << "ms";
- if (!WaitForProperty("sys.boot_completed", "1", watchdog_timeout)) {
- LOG(ERROR) << "Failed to boot in " << watchdog_timeout.count()
- << "ms. Switching to full reboot";
- // In this case device is in a boot loop. Only way to recover is to do dirty reboot.
- // Since init might be wedged, don't try to write reboot reason into a persistent property.
- PersistRebootReason("userspace_failed,watchdog_triggered,failed_to_boot", false);
- RebootSystem(ANDROID_RB_RESTART2, "userspace_failed,watchdog_triggered,failed_to_boot");
- }
- LOG(INFO) << "Device booted, stopping userspace reboot watchdog";
-}
-
-static void HandleUserspaceReboot() {
- if (!android::sysprop::InitProperties::is_userspace_reboot_supported().value_or(false)) {
- LOG(ERROR) << "Attempted a userspace reboot on a device that doesn't support it";
- return;
- }
- // Spinnig up a separate thread will fail the setns call later in the boot sequence.
- // Fork a new process to monitor userspace reboot while we are investigating a better solution.
- pid_t pid = fork();
- if (pid < 0) {
- PLOG(ERROR) << "Failed to fork process for userspace reboot watchdog. Switching to full "
- << "reboot";
- trigger_shutdown("reboot,userspace_failed,watchdog_fork");
- return;
- }
- if (pid == 0) {
- // Child
- UserspaceRebootWatchdogThread();
- _exit(EXIT_SUCCESS);
- }
- LOG(INFO) << "Clearing queue and starting userspace-reboot-requested trigger";
- auto& am = ActionManager::GetInstance();
- am.ClearQueue();
- am.QueueEventTrigger("userspace-reboot-requested");
- auto handler = [](const BuiltinArguments&) { return DoUserspaceReboot(); };
- am.QueueBuiltinAction(handler, "userspace-reboot");
-}
-
/**
* Check if "command" field is set in bootloader message.
*
@@ -1030,7 +829,6 @@
std::string reboot_target = "";
bool run_fsck = false;
bool command_invalid = false;
- bool userspace_reboot = false;
if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
@@ -1051,8 +849,8 @@
if (cmd_params.size() >= 2) {
reboot_target = cmd_params[1];
if (reboot_target == "userspace") {
- LOG(INFO) << "Userspace reboot requested";
- userspace_reboot = true;
+ LOG(ERROR) << "Userspace reboot is deprecated.";
+ return;
}
// adb reboot fastboot should boot into bootloader for devices not
// supporting logical partitions.
@@ -1130,11 +928,6 @@
// messages, etc) from properties during reboot.
StopSendingMessages();
- if (userspace_reboot) {
- HandleUserspaceReboot();
- return;
- }
-
LOG(INFO) << "Clear action queue and start shutdown trigger";
ActionManager::GetInstance().ClearQueue();
// Queue shutdown trigger first
diff --git a/init/service.cpp b/init/service.cpp
index 31308a0..d76a5d5 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -653,8 +653,6 @@
SetMountNamespace();
}
- post_data_ = ServiceList::GetInstance().IsPostData();
-
LOG(INFO) << "starting service '" << name_ << "'...";
std::vector<Descriptor> descriptors;
diff --git a/init/service.h b/init/service.h
index 5e9af25..ae75553 100644
--- a/init/service.h
+++ b/init/service.h
@@ -144,8 +144,6 @@
std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
const std::vector<std::string>& args() const { return args_; }
bool is_updatable() const { return updatable_; }
- bool is_post_data() const { return post_data_; }
- bool is_from_apex() const { return base::StartsWith(filename_, "/apex/"); }
void set_oneshot(bool value) {
if (value) {
flags_ |= SVC_ONESHOT;
@@ -244,8 +242,6 @@
std::optional<MountNamespace> mount_namespace_;
- bool post_data_ = false;
-
std::optional<std::string> on_failure_reboot_target_;
std::string filename_;
diff --git a/init/service_list.cpp b/init/service_list.cpp
index 1c56e8a..e6cc2c9 100644
--- a/init/service_list.cpp
+++ b/init/service_list.cpp
@@ -68,14 +68,6 @@
}
}
-void ServiceList::MarkPostData() {
- post_data_ = true;
-}
-
-bool ServiceList::IsPostData() {
- return post_data_;
-}
-
void ServiceList::StartDelayedServices() {
for (const auto& name : delayed_service_names_) {
Service* service = FindService(name);
diff --git a/init/service_list.h b/init/service_list.h
index 44e8453..fd7fc05 100644
--- a/init/service_list.h
+++ b/init/service_list.h
@@ -83,19 +83,14 @@
auto end() const { return services_.end(); }
const std::vector<Service*> services_in_shutdown_order() const;
- void MarkPostData();
- bool IsPostData();
void DelayService(const Service& service);
void StartDelayedServices();
- void ResetState() { post_data_ = false; }
-
auto size() const { return services_.size(); }
private:
std::vector<std::unique_ptr<Service>> services_;
- bool post_data_ = false;
std::vector<std::string> delayed_service_names_;
};
diff --git a/init/sysprop/Android.bp b/init/sysprop/Android.bp
deleted file mode 100644
index 296cdc1..0000000
--- a/init/sysprop/Android.bp
+++ /dev/null
@@ -1,16 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "system_core_init_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["system_core_init_license"],
-}
-
-sysprop_library {
- name: "com.android.sysprop.init",
- srcs: ["InitProperties.sysprop"],
- property_owner: "Platform",
- api_packages: ["android.sysprop"],
- recovery_available: true,
-}
diff --git a/init/sysprop/InitProperties.sysprop b/init/sysprop/InitProperties.sysprop
deleted file mode 100644
index 24c2434..0000000
--- a/init/sysprop/InitProperties.sysprop
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-owner: Platform
-module: "android.sysprop.InitProperties"
-
-# Serves as a signal to all processes that userspace reboot is happening.
-prop {
- api_name: "userspace_reboot_in_progress"
- type: Boolean
- scope: Public
- access: ReadWrite
- prop_name: "sys.init.userspace_reboot.in_progress"
- integer_as_bool: true
-}
-
-# Shows whenever the device supports userspace reboot or not.
-prop {
- api_name: "is_userspace_reboot_supported"
- type: Boolean
- scope: Public
- access: Readonly
- prop_name: "init.userspace_reboot.is_supported"
- integer_as_bool: true
-}
diff --git a/init/sysprop/api/com.android.sysprop.init-current.txt b/init/sysprop/api/com.android.sysprop.init-current.txt
deleted file mode 100644
index 01f4e9a..0000000
--- a/init/sysprop/api/com.android.sysprop.init-current.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-props {
- module: "android.sysprop.InitProperties"
- prop {
- api_name: "is_userspace_reboot_supported"
- prop_name: "init.userspace_reboot.is_supported"
- integer_as_bool: true
- }
- prop {
- api_name: "userspace_reboot_in_progress"
- access: ReadWrite
- prop_name: "sys.init.userspace_reboot.in_progress"
- integer_as_bool: true
- }
-}
diff --git a/init/sysprop/api/com.android.sysprop.init-latest.txt b/init/sysprop/api/com.android.sysprop.init-latest.txt
deleted file mode 100644
index 01f4e9a..0000000
--- a/init/sysprop/api/com.android.sysprop.init-latest.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-props {
- module: "android.sysprop.InitProperties"
- prop {
- api_name: "is_userspace_reboot_supported"
- prop_name: "init.userspace_reboot.is_supported"
- integer_as_bool: true
- }
- prop {
- api_name: "userspace_reboot_in_progress"
- access: ReadWrite
- prop_name: "sys.init.userspace_reboot.in_progress"
- integer_as_bool: true
- }
-}
diff --git a/init/test_kill_services/OWNERS b/init/test_kill_services/OWNERS
new file mode 100644
index 0000000..40164aa
--- /dev/null
+++ b/init/test_kill_services/OWNERS
@@ -0,0 +1 @@
+smoreland@google.com
diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp
index 3af92bb..efba9f6 100644
--- a/init/test_kill_services/init_kill_services_test.cpp
+++ b/init/test_kill_services/init_kill_services_test.cpp
@@ -87,6 +87,25 @@
return info.param;
}
-INSTANTIATE_TEST_CASE_P(DeathTest, InitKillServicesTest,
- ::testing::Values("lmkd", "ueventd", "hwservicemanager", "servicemanager"),
- PrintName);
+INSTANTIATE_TEST_CASE_P(
+ DeathTest, InitKillServicesTest,
+ ::testing::Values(
+ // clang-format off
+
+// TODO: we may want a more automatic way of testing this for services based on some
+// criteria (e.g. not disabled), but for now adding core services one at a time
+
+// BEGIN INTERNAL ONLY MERGE GUARD (add things here if internal only, move down later)
+// END INTERNAL ONLY MERGE GUARD
+
+// BEGIN AOSP ONLY (add things here if adding to AOSP)
+ "lmkd",
+ "ueventd",
+ "hwservicemanager",
+ "servicemanager",
+ "system_suspend"
+// END AOSP ONLY
+
+ // clang-format on
+ ),
+ PrintName);
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 03f0496..d3a2b50 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -93,8 +93,7 @@
#if __has_include(<sys/system_properties.h>)
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
+#include <sys/system_properties.h>
struct callback_data {
void (*callback)(const char* name, const char* value, void* cookie);
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index 3bc6dc3..c911b4f 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -36,8 +36,7 @@
#include <log/log_properties.h>
#if defined(__BIONIC__)
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
+#include <sys/system_properties.h>
#endif
/**
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 33e00bc..a60bfe9 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -79,12 +79,12 @@
],
static_libs: [
"libjsoncpp",
+ "libprocessgroup_util",
],
// for cutils/android_filesystem_config.h
header_libs: [
"libcutils_headers",
"libprocessgroup_headers",
- "libprocessgroup_util",
],
export_include_dirs: ["include"],
export_header_lib_headers: [
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 52b5afe..fb01cfd 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -38,26 +38,26 @@
static constexpr const char* CGROUP_TASKS_FILE = "/tasks";
static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.threads";
-uint32_t CgroupController::version() const {
+uint32_t CgroupControllerWrapper::version() const {
CHECK(HasValue());
return ACgroupController_getVersion(controller_);
}
-const char* CgroupController::name() const {
+const char* CgroupControllerWrapper::name() const {
CHECK(HasValue());
return ACgroupController_getName(controller_);
}
-const char* CgroupController::path() const {
+const char* CgroupControllerWrapper::path() const {
CHECK(HasValue());
return ACgroupController_getPath(controller_);
}
-bool CgroupController::HasValue() const {
+bool CgroupControllerWrapper::HasValue() const {
return controller_ != nullptr;
}
-bool CgroupController::IsUsable() {
+bool CgroupControllerWrapper::IsUsable() {
if (!HasValue()) return false;
if (state_ == UNKNOWN) {
@@ -72,7 +72,7 @@
return state_ == USABLE;
}
-std::string CgroupController::GetTasksFilePath(const std::string& rel_path) const {
+std::string CgroupControllerWrapper::GetTasksFilePath(const std::string& rel_path) const {
std::string tasks_path = path();
if (!rel_path.empty()) {
@@ -81,8 +81,8 @@
return (version() == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2;
}
-std::string CgroupController::GetProcsFilePath(const std::string& rel_path, uid_t uid,
- pid_t pid) const {
+std::string CgroupControllerWrapper::GetProcsFilePath(const std::string& rel_path, uid_t uid,
+ pid_t pid) const {
std::string proc_path(path());
proc_path.append("/").append(rel_path);
proc_path = regex_replace(proc_path, std::regex("<uid>"), std::to_string(uid));
@@ -91,7 +91,7 @@
return proc_path.append(CGROUP_PROCS_FILE);
}
-bool CgroupController::GetTaskGroup(pid_t tid, std::string* group) const {
+bool CgroupControllerWrapper::GetTaskGroup(pid_t tid, std::string* group) const {
std::string file_name = StringPrintf("/proc/%d/cgroup", tid);
std::string content;
if (!android::base::ReadFileToString(file_name, &content)) {
@@ -175,40 +175,40 @@
}
}
-CgroupController CgroupMap::FindController(const std::string& name) const {
+CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const {
if (!loaded_) {
LOG(ERROR) << "CgroupMap::FindController called for [" << getpid()
<< "] failed, RC file was not initialized properly";
- return CgroupController(nullptr);
+ return CgroupControllerWrapper(nullptr);
}
auto controller_count = ACgroupFile_getControllerCount();
for (uint32_t i = 0; i < controller_count; ++i) {
const ACgroupController* controller = ACgroupFile_getController(i);
if (name == ACgroupController_getName(controller)) {
- return CgroupController(controller);
+ return CgroupControllerWrapper(controller);
}
}
- return CgroupController(nullptr);
+ return CgroupControllerWrapper(nullptr);
}
-CgroupController CgroupMap::FindControllerByPath(const std::string& path) const {
+CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) const {
if (!loaded_) {
LOG(ERROR) << "CgroupMap::FindControllerByPath called for [" << getpid()
<< "] failed, RC file was not initialized properly";
- return CgroupController(nullptr);
+ return CgroupControllerWrapper(nullptr);
}
auto controller_count = ACgroupFile_getControllerCount();
for (uint32_t i = 0; i < controller_count; ++i) {
const ACgroupController* controller = ACgroupFile_getController(i);
if (StartsWith(path, ACgroupController_getPath(controller))) {
- return CgroupController(controller);
+ return CgroupControllerWrapper(controller);
}
}
- return CgroupController(nullptr);
+ return CgroupControllerWrapper(nullptr);
}
int CgroupMap::ActivateControllers(const std::string& path) const {
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index 31925d5..3642794 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -23,10 +23,10 @@
#include <android/cgrouprc.h>
// Convenient wrapper of an ACgroupController pointer.
-class CgroupController {
+class CgroupControllerWrapper {
public:
// Does not own controller
- explicit CgroupController(const ACgroupController* controller)
+ explicit CgroupControllerWrapper(const ACgroupController* controller)
: controller_(controller) {}
uint32_t version() const;
@@ -53,12 +53,9 @@
class CgroupMap {
public:
- // Selinux policy ensures only init process can successfully use this function
- static bool SetupCgroups();
-
static CgroupMap& GetInstance();
- CgroupController FindController(const std::string& name) const;
- CgroupController FindControllerByPath(const std::string& path) const;
+ CgroupControllerWrapper FindController(const std::string& name) const;
+ CgroupControllerWrapper FindControllerByPath(const std::string& path) const;
int ActivateControllers(const std::string& path) const;
private:
diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp
index 7522cfe..cb91247 100644
--- a/libprocessgroup/cgrouprc/Android.bp
+++ b/libprocessgroup/cgrouprc/Android.bp
@@ -32,8 +32,8 @@
symbol_file: "libcgrouprc.map.txt",
},
srcs: [
- "cgroup_controller.cpp",
- "cgroup_file.cpp",
+ "a_cgroup_controller.cpp",
+ "a_cgroup_file.cpp",
],
cflags: [
"-Wall",
diff --git a/libprocessgroup/cgrouprc/cgroup_controller.cpp b/libprocessgroup/cgrouprc/a_cgroup_controller.cpp
similarity index 100%
rename from libprocessgroup/cgrouprc/cgroup_controller.cpp
rename to libprocessgroup/cgrouprc/a_cgroup_controller.cpp
diff --git a/libprocessgroup/cgrouprc/cgroup_file.cpp b/libprocessgroup/cgrouprc/a_cgroup_file.cpp
similarity index 100%
rename from libprocessgroup/cgrouprc/cgroup_file.cpp
rename to libprocessgroup/cgrouprc/a_cgroup_file.cpp
diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h
index a18847e..1b6ea66 100644
--- a/libprocessgroup/include/processgroup/sched_policy.h
+++ b/libprocessgroup/include/processgroup/sched_policy.h
@@ -48,6 +48,7 @@
SP_TOP_APP = 5,
SP_RT_APP = 6,
SP_RESTRICTED = 7,
+ SP_FOREGROUND_WINDOW = 8,
SP_CNT,
SP_MAX = SP_CNT - 1,
SP_SYSTEM_DEFAULT = SP_FOREGROUND,
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 387c104..83a2258 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -94,7 +94,7 @@
}
static bool CgroupGetMemcgAppsPath(std::string* path) {
- CgroupController controller = CgroupMap::GetInstance().FindController("memory");
+ CgroupControllerWrapper controller = CgroupMap::GetInstance().FindController("memory");
if (!controller.HasValue()) {
return false;
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 1fc66ba..ec125aa 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -11,6 +11,11 @@
"File": "foreground/cpus"
},
{
+ "Name": "HighCapacityWICPUs",
+ "Controller": "cpuset",
+ "File": "foreground_window/cpus"
+ },
+ {
"Name": "MaxCapacityCPUs",
"Controller": "cpuset",
"File": "top-app/cpus"
@@ -159,6 +164,19 @@
]
},
{
+ "Name": "HighPerformanceWI",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "cpu",
+ "Path": "foreground_window"
+ }
+ }
+ ]
+ },
+ {
"Name": "MaxPerformance",
"Actions": [
{
@@ -382,6 +400,19 @@
]
},
{
+ "Name": "ProcessCapacityHighWI",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "cpuset",
+ "Path": "foreground_window"
+ }
+ }
+ ]
+ },
+ {
"Name": "ProcessCapacityMax",
"Actions": [
{
@@ -639,6 +670,10 @@
"Profiles": [ "HighPerformance", "HighIoPriority", "TimerSlackNormal" ]
},
{
+ "Name": "SCHED_SP_FOREGROUND_WINDOW",
+ "Profiles": [ "HighPerformanceWI", "HighIoPriority", "TimerSlackNormal" ]
+ },
+ {
"Name": "SCHED_SP_TOP_APP",
"Profiles": [ "MaxPerformance", "MaxIoPriority", "TimerSlackNormal" ]
},
@@ -667,6 +702,10 @@
"Profiles": [ "HighPerformance", "ProcessCapacityHigh", "HighIoPriority", "TimerSlackNormal" ]
},
{
+ "Name": "CPUSET_SP_FOREGROUND_WINDOW",
+ "Profiles": [ "HighPerformanceWI", "ProcessCapacityHighWI", "HighIoPriority", "TimerSlackNormal" ]
+ },
+ {
"Name": "CPUSET_SP_TOP_APP",
"Profiles": [ "MaxPerformance", "ProcessCapacityMax", "MaxIoPriority", "TimerSlackNormal" ]
},
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 0f2640a..042bcd2 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -58,6 +58,8 @@
return SetTaskProfiles(tid, {"CPUSET_SP_SYSTEM"}, true) ? 0 : -1;
case SP_RESTRICTED:
return SetTaskProfiles(tid, {"CPUSET_SP_RESTRICTED"}, true) ? 0 : -1;
+ case SP_FOREGROUND_WINDOW:
+ return SetTaskProfiles(tid, {"CPUSET_SP_FOREGROUND_WINDOW"}, true) ? 0 : -1;
default:
break;
}
@@ -110,6 +112,9 @@
case SP_RT_APP:
SLOGD("RT tid %d (%s)", tid, thread_name);
break;
+ case SP_FOREGROUND_WINDOW:
+ SLOGD("WI tid %d (%s)", tid, thread_name);
+ break;
default:
SLOGD("??? tid %d (%s)", tid, thread_name);
break;
@@ -129,6 +134,8 @@
return SetTaskProfiles(tid, {"SCHED_SP_SYSTEM"}, true) ? 0 : -1;
case SP_RT_APP:
return SetTaskProfiles(tid, {"SCHED_SP_RT_APP"}, true) ? 0 : -1;
+ case SP_FOREGROUND_WINDOW:
+ return SetTaskProfiles(tid, {"SCHED_SP_FOREGROUND_WINDOW"}, true) ? 0 : -1;
default:
return SetTaskProfiles(tid, {"SCHED_SP_DEFAULT"}, true) ? 0 : -1;
}
@@ -179,6 +186,8 @@
*policy = SP_TOP_APP;
} else if (group == "restricted") {
*policy = SP_RESTRICTED;
+ } else if (group == "foreground_window") {
+ *policy = SP_FOREGROUND_WINDOW;
} else {
errno = ERANGE;
return -1;
@@ -235,7 +244,7 @@
static const char* const kSchedPolicyNames[] = {
[SP_BACKGROUND] = "bg", [SP_FOREGROUND] = "fg", [SP_SYSTEM] = " ",
[SP_AUDIO_APP] = "aa", [SP_AUDIO_SYS] = "as", [SP_TOP_APP] = "ta",
- [SP_RT_APP] = "rt", [SP_RESTRICTED] = "rs",
+ [SP_RT_APP] = "rt", [SP_RESTRICTED] = "rs", [SP_FOREGROUND_WINDOW] = "wi",
};
static_assert(arraysize(kSchedPolicyNames) == SP_CNT, "missing name");
if (policy < SP_BACKGROUND || policy >= SP_CNT) {
@@ -249,14 +258,16 @@
* cpuset profile array for:
* SP_DEFAULT(-1), SP_BACKGROUND(0), SP_FOREGROUND(1),
* SP_SYSTEM(2), SP_AUDIO_APP(3), SP_AUDIO_SYS(4),
- * SP_TOP_APP(5), SP_RT_APP(6), SP_RESTRICTED(7)
+ * SP_TOP_APP(5), SP_RT_APP(6), SP_RESTRICTED(7),
+ * SP_FOREGROUND_WINDOW(8)
* index is policy + 1
* this need keep in sync with SchedPolicy enum
*/
static constexpr const char* kCpusetProfiles[SP_CNT + 1] = {
- "CPUSET_SP_DEFAULT", "CPUSET_SP_BACKGROUND", "CPUSET_SP_FOREGROUND",
- "CPUSET_SP_SYSTEM", "CPUSET_SP_FOREGROUND", "CPUSET_SP_FOREGROUND",
- "CPUSET_SP_TOP_APP", "CPUSET_SP_DEFAULT", "CPUSET_SP_RESTRICTED"};
+ "CPUSET_SP_DEFAULT", "CPUSET_SP_BACKGROUND", "CPUSET_SP_FOREGROUND",
+ "CPUSET_SP_SYSTEM", "CPUSET_SP_FOREGROUND", "CPUSET_SP_FOREGROUND",
+ "CPUSET_SP_TOP_APP", "CPUSET_SP_DEFAULT", "CPUSET_SP_RESTRICTED",
+ "CPUSET_SP_FOREGROUND_WINDOW"};
if (policy < SP_DEFAULT || policy >= SP_CNT) {
return nullptr;
}
@@ -268,14 +279,16 @@
* sched profile array for:
* SP_DEFAULT(-1), SP_BACKGROUND(0), SP_FOREGROUND(1),
* SP_SYSTEM(2), SP_AUDIO_APP(3), SP_AUDIO_SYS(4),
- * SP_TOP_APP(5), SP_RT_APP(6), SP_RESTRICTED(7)
+ * SP_TOP_APP(5), SP_RT_APP(6), SP_RESTRICTED(7),
+ * SP_FOREGROUND_WINDOW(8)
* index is policy + 1
* this need keep in sync with SchedPolicy enum
*/
static constexpr const char* kSchedProfiles[SP_CNT + 1] = {
- "SCHED_SP_DEFAULT", "SCHED_SP_BACKGROUND", "SCHED_SP_FOREGROUND",
- "SCHED_SP_SYSTEM", "SCHED_SP_FOREGROUND", "SCHED_SP_FOREGROUND",
- "SCHED_SP_TOP_APP", "SCHED_SP_RT_APP", "SCHED_SP_DEFAULT"};
+ "SCHED_SP_DEFAULT", "SCHED_SP_BACKGROUND", "SCHED_SP_FOREGROUND",
+ "SCHED_SP_SYSTEM", "SCHED_SP_FOREGROUND", "SCHED_SP_FOREGROUND",
+ "SCHED_SP_TOP_APP", "SCHED_SP_RT_APP", "SCHED_SP_DEFAULT",
+ "SCHED_SP_FOREGROUND_WINDOW"};
if (policy < SP_DEFAULT || policy >= SP_CNT) {
return nullptr;
}
diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp
index 76f0a11..1a4ad01 100644
--- a/libprocessgroup/setup/Android.bp
+++ b/libprocessgroup/setup/Android.bp
@@ -34,10 +34,10 @@
],
static_libs: [
"libcgrouprc_format",
+ "libprocessgroup_util",
],
header_libs: [
"libprocessgroup_headers",
- "libprocessgroup_util",
],
export_header_lib_headers: [
"libprocessgroup_headers",
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 4870548..67ecc1d 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -123,8 +123,8 @@
return file_name_;
}
-void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name,
- const std::string& file_v2_name) {
+void ProfileAttribute::Reset(const CgroupControllerWrapper& controller,
+ const std::string& file_name, const std::string& file_v2_name) {
controller_ = controller;
file_name_ = file_name;
file_v2_name_ = file_v2_name;
@@ -333,7 +333,7 @@
return optional_;
}
-SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
+SetCgroupAction::SetCgroupAction(const CgroupControllerWrapper& c, const std::string& p)
: controller_(c), path_(p) {
FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
// uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 184e9e3..abb3ca5 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -32,9 +32,9 @@
class IProfileAttribute {
public:
virtual ~IProfileAttribute() = 0;
- virtual void Reset(const CgroupController& controller, const std::string& file_name,
+ virtual void Reset(const CgroupControllerWrapper& controller, const std::string& file_name,
const std::string& file_v2_name) = 0;
- virtual const CgroupController* controller() const = 0;
+ virtual const CgroupControllerWrapper* controller() const = 0;
virtual const std::string& file_name() const = 0;
virtual bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const = 0;
virtual bool GetPathForTask(pid_t tid, std::string* path) const = 0;
@@ -46,14 +46,14 @@
// Cgroup attributes may have different names in the v1 and v2 hierarchies. If `file_v2_name` is
// not empty, `file_name` is the name for the v1 hierarchy and `file_v2_name` is the name for
// the v2 hierarchy. If `file_v2_name` is empty, `file_name` is used for both hierarchies.
- ProfileAttribute(const CgroupController& controller, const std::string& file_name,
+ ProfileAttribute(const CgroupControllerWrapper& controller, const std::string& file_name,
const std::string& file_v2_name)
: controller_(controller), file_name_(file_name), file_v2_name_(file_v2_name) {}
~ProfileAttribute() = default;
- const CgroupController* controller() const override { return &controller_; }
+ const CgroupControllerWrapper* controller() const override { return &controller_; }
const std::string& file_name() const override;
- void Reset(const CgroupController& controller, const std::string& file_name,
+ void Reset(const CgroupControllerWrapper& controller, const std::string& file_name,
const std::string& file_v2_name) override;
bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override;
@@ -61,7 +61,7 @@
bool GetPathForUID(uid_t uid, std::string* path) const override;
private:
- CgroupController controller_;
+ CgroupControllerWrapper controller_;
std::string file_name_;
std::string file_v2_name_;
};
@@ -142,7 +142,7 @@
// Set cgroup profile element
class SetCgroupAction : public ProfileAction {
public:
- SetCgroupAction(const CgroupController& c, const std::string& p);
+ SetCgroupAction(const CgroupControllerWrapper& c, const std::string& p);
const char* Name() const override { return "SetCgroup"; }
bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
@@ -152,10 +152,10 @@
bool IsValidForProcess(uid_t uid, pid_t pid) const override;
bool IsValidForTask(pid_t tid) const override;
- const CgroupController* controller() const { return &controller_; }
+ const CgroupControllerWrapper* controller() const { return &controller_; }
private:
- CgroupController controller_;
+ CgroupControllerWrapper controller_;
std::string path_;
android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
mutable std::mutex fd_mutex_;
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
index d19da2b..dff6d67 100644
--- a/libprocessgroup/task_profiles_test.cpp
+++ b/libprocessgroup/task_profiles_test.cpp
@@ -102,10 +102,10 @@
public:
ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {}
~ProfileAttributeMock() override = default;
- void Reset(const CgroupController&, const std::string&, const std::string&) override {
+ void Reset(const CgroupControllerWrapper&, const std::string&, const std::string&) override {
CHECK(false);
}
- const CgroupController* controller() const override {
+ const CgroupControllerWrapper* controller() const override {
CHECK(false);
return {};
}
diff --git a/libprocessgroup/util/Android.bp b/libprocessgroup/util/Android.bp
index 4a940b7..54ba69b 100644
--- a/libprocessgroup/util/Android.bp
+++ b/libprocessgroup/util/Android.bp
@@ -19,7 +19,7 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_library_headers {
+cc_library_static {
name: "libprocessgroup_util",
vendor_available: true,
product_available: true,
@@ -36,12 +36,15 @@
export_include_dirs: [
"include",
],
+ srcs: [
+ "util.cpp",
+ ],
defaults: ["libprocessgroup_build_flags_cc"],
}
cc_test {
name: "libprocessgroup_util_test",
- header_libs: ["libprocessgroup_util"],
+ static_libs: ["libprocessgroup_util"],
srcs: ["tests/util.cpp"],
test_suites: ["general-tests"],
}
diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h
index 5240744..8d013af 100644
--- a/libprocessgroup/util/include/processgroup/util.h
+++ b/libprocessgroup/util/include/processgroup/util.h
@@ -16,46 +16,10 @@
#pragma once
-#include <algorithm>
-#include <iterator>
#include <string>
namespace util {
-namespace internal {
-
-const char SEP = '/';
-
-std::string DeduplicateAndTrimSeparators(const std::string& path) {
- bool lastWasSep = false;
- std::string ret;
-
- std::copy_if(path.begin(), path.end(), std::back_inserter(ret), [&lastWasSep](char c) {
- if (lastWasSep) {
- if (c == SEP) return false;
- lastWasSep = false;
- } else if (c == SEP) {
- lastWasSep = true;
- }
- return true;
- });
-
- if (ret.length() > 1 && ret.back() == SEP) ret.pop_back();
-
- return ret;
-}
-
-} // namespace internal
-
-unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path) {
- const std::string deduped_root = internal::DeduplicateAndTrimSeparators(controller_root);
- const std::string deduped_path = internal::DeduplicateAndTrimSeparators(cgroup_path);
-
- if (deduped_root.empty() || deduped_path.empty() || !deduped_path.starts_with(deduped_root))
- return 0;
-
- return std::count(deduped_path.begin() + deduped_root.size(), deduped_path.end(),
- internal::SEP);
-}
+unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path);
} // namespace util
diff --git a/libprocessgroup/util/util.cpp b/libprocessgroup/util/util.cpp
new file mode 100644
index 0000000..9b88a22
--- /dev/null
+++ b/libprocessgroup/util/util.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <processgroup/util.h>
+
+#include <algorithm>
+#include <iterator>
+
+namespace {
+
+const char SEP = '/';
+
+std::string DeduplicateAndTrimSeparators(const std::string& path) {
+ bool lastWasSep = false;
+ std::string ret;
+
+ std::copy_if(path.begin(), path.end(), std::back_inserter(ret), [&lastWasSep](char c) {
+ if (lastWasSep) {
+ if (c == SEP) return false;
+ lastWasSep = false;
+ } else if (c == SEP) {
+ lastWasSep = true;
+ }
+ return true;
+ });
+
+ if (ret.length() > 1 && ret.back() == SEP) ret.pop_back();
+
+ return ret;
+}
+
+} // anonymous namespace
+
+namespace util {
+
+unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path) {
+ const std::string deduped_root = DeduplicateAndTrimSeparators(controller_root);
+ const std::string deduped_path = DeduplicateAndTrimSeparators(cgroup_path);
+
+ if (deduped_root.empty() || deduped_path.empty() || !deduped_path.starts_with(deduped_root))
+ return 0;
+
+ return std::count(deduped_path.begin() + deduped_root.size(), deduped_path.end(), SEP);
+}
+
+} // namespace util
diff --git a/rootdir/Android.bp b/rootdir/Android.bp
index 1e7b48b..5f0a2c3 100644
--- a/rootdir/Android.bp
+++ b/rootdir/Android.bp
@@ -189,3 +189,9 @@
(default, default): [],
}),
}
+
+filegroup {
+ name: "ramdisk_node_list",
+ srcs: ["ramdisk_node_list"],
+ export_to_make_var: "RAMDISK_NODE_LIST",
+}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e743743..f866e9b 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -151,17 +151,3 @@
$(eval $(call copy-one-file,$(init.environ.rc-soong),$(LOCAL_BUILT_MODULE)))
init.environ.rc-soong :=
-#######################################
-# ramdisk_node_list
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := ramdisk_node_list
-LOCAL_MODULE_CLASS := ETC
-LOCAL_SRC_FILES := $(LOCAL_MODULE)
-LOCAL_MODULE_PATH := $(PRODUCT_OUT)
-
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-include $(BUILD_PREBUILT)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b804c1b..7b2b96a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -145,6 +145,7 @@
# cpuctl hierarchy for devices using utilclamp
mkdir /dev/cpuctl/foreground
+ mkdir /dev/cpuctl/foreground_window
mkdir /dev/cpuctl/background
mkdir /dev/cpuctl/top-app
mkdir /dev/cpuctl/rt
@@ -153,6 +154,7 @@
mkdir /dev/cpuctl/dex2oat
chown system system /dev/cpuctl
chown system system /dev/cpuctl/foreground
+ chown system system /dev/cpuctl/foreground_window
chown system system /dev/cpuctl/background
chown system system /dev/cpuctl/top-app
chown system system /dev/cpuctl/rt
@@ -161,6 +163,7 @@
chown system system /dev/cpuctl/dex2oat
chown system system /dev/cpuctl/tasks
chown system system /dev/cpuctl/foreground/tasks
+ chown system system /dev/cpuctl/foreground_window/tasks
chown system system /dev/cpuctl/background/tasks
chown system system /dev/cpuctl/top-app/tasks
chown system system /dev/cpuctl/rt/tasks
@@ -169,6 +172,7 @@
chown system system /dev/cpuctl/dex2oat/tasks
chown system system /dev/cpuctl/cgroup.procs
chown system system /dev/cpuctl/foreground/cgroup.procs
+ chown system system /dev/cpuctl/foreground_window/cgroup.procs
chown system system /dev/cpuctl/background/cgroup.procs
chown system system /dev/cpuctl/top-app/cgroup.procs
chown system system /dev/cpuctl/rt/cgroup.procs
@@ -177,6 +181,7 @@
chown system system /dev/cpuctl/dex2oat/cgroup.procs
chmod 0664 /dev/cpuctl/tasks
chmod 0664 /dev/cpuctl/foreground/tasks
+ chmod 0664 /dev/cpuctl/foreground_window/tasks
chmod 0664 /dev/cpuctl/background/tasks
chmod 0664 /dev/cpuctl/top-app/tasks
chmod 0664 /dev/cpuctl/rt/tasks
@@ -185,6 +190,7 @@
chmod 0664 /dev/cpuctl/dex2oat/tasks
chmod 0664 /dev/cpuctl/cgroup.procs
chmod 0664 /dev/cpuctl/foreground/cgroup.procs
+ chmod 0664 /dev/cpuctl/foreground_window/cgroup.procs
chmod 0664 /dev/cpuctl/background/cgroup.procs
chmod 0664 /dev/cpuctl/top-app/cgroup.procs
chmod 0664 /dev/cpuctl/rt/cgroup.procs
@@ -354,6 +360,9 @@
mkdir /dev/cpuset/foreground
copy /dev/cpuset/cpus /dev/cpuset/foreground/cpus
copy /dev/cpuset/mems /dev/cpuset/foreground/mems
+ mkdir /dev/cpuset/foreground_window
+ copy /dev/cpuset/cpus /dev/cpuset/foreground_window/cpus
+ copy /dev/cpuset/mems /dev/cpuset/foreground_window/mems
mkdir /dev/cpuset/background
copy /dev/cpuset/cpus /dev/cpuset/background/cpus
copy /dev/cpuset/mems /dev/cpuset/background/mems
@@ -382,6 +391,7 @@
# change permissions for all cpusets we'll touch at runtime
chown system system /dev/cpuset
chown system system /dev/cpuset/foreground
+ chown system system /dev/cpuset/foreground_window
chown system system /dev/cpuset/background
chown system system /dev/cpuset/system-background
chown system system /dev/cpuset/top-app
@@ -389,6 +399,7 @@
chown system system /dev/cpuset/camera-daemon
chown system system /dev/cpuset/tasks
chown system system /dev/cpuset/foreground/tasks
+ chown system system /dev/cpuset/foreground_window/tasks
chown system system /dev/cpuset/background/tasks
chown system system /dev/cpuset/system-background/tasks
chown system system /dev/cpuset/top-app/tasks
@@ -396,6 +407,7 @@
chown system system /dev/cpuset/camera-daemon/tasks
chown system system /dev/cpuset/cgroup.procs
chown system system /dev/cpuset/foreground/cgroup.procs
+ chown system system /dev/cpuset/foreground_window/cgroup.procs
chown system system /dev/cpuset/background/cgroup.procs
chown system system /dev/cpuset/system-background/cgroup.procs
chown system system /dev/cpuset/top-app/cgroup.procs
@@ -406,6 +418,7 @@
chmod 0775 /dev/cpuset/system-background
chmod 0664 /dev/cpuset/foreground/tasks
+ chmod 0664 /dev/cpuset/foreground_window/tasks
chmod 0664 /dev/cpuset/background/tasks
chmod 0664 /dev/cpuset/system-background/tasks
chmod 0664 /dev/cpuset/top-app/tasks
@@ -413,6 +426,7 @@
chmod 0664 /dev/cpuset/tasks
chmod 0664 /dev/cpuset/camera-daemon/tasks
chmod 0664 /dev/cpuset/foreground/cgroup.procs
+ chmod 0664 /dev/cpuset/foreground_window/cgroup.procs
chmod 0664 /dev/cpuset/background/cgroup.procs
chmod 0664 /dev/cpuset/system-background/cgroup.procs
chmod 0664 /dev/cpuset/top-app/cgroup.procs
@@ -620,7 +634,6 @@
mkdir /metadata/bootstat 0750 system log
mkdir /metadata/ota 0750 root system
mkdir /metadata/ota/snapshots 0750 root system
- mkdir /metadata/userspacereboot 0770 root system
mkdir /metadata/watchdog 0770 root system
mkdir /metadata/apex 0700 root system
@@ -648,6 +661,14 @@
chmod 0755 /sys/kernel/tracing
chmod 0755 /sys/kernel/debug/tracing
+ # Early HALs may use early VM. Mount /mnt/vm before starting such HALs.
+ mkdir /mnt/vm 0755 root root
+ mount tmpfs tmpfs /mnt/vm nosuid nodev noexec rw
+ restorecon /mnt/vm
+ chown system system /mnt/vm
+ chmod 0770 /mnt/vm
+ mkdir /mnt/vm/early 0770 system system
+
# HALs required before storage encryption can get unlocked (FBE)
class_start early_hal
@@ -675,8 +696,6 @@
on post-fs-data
- mark_post_data
-
# Start checkpoint before we touch data
exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint
@@ -1323,46 +1342,6 @@
on init && property:ro.debuggable=1
start console
-on userspace-reboot-requested
- # TODO(b/135984674): reset all necessary properties here.
- setprop sys.boot_completed ""
- setprop dev.bootcomplete ""
- setprop sys.init.updatable_crashing ""
- setprop sys.init.updatable_crashing_process_name ""
- setprop sys.user.0.ce_available ""
- setprop sys.shutdown.requested ""
- setprop service.bootanim.exit ""
- setprop service.bootanim.progress ""
-
-on userspace-reboot-fs-remount
- # Make sure that vold is running.
- # This is mostly a precaution measure in case vold for some reason wasn't running when
- # userspace reboot was initiated.
- start vold
- exec - system system -- /system/bin/vdc checkpoint resetCheckpoint
- exec - system system -- /system/bin/vdc checkpoint markBootAttempt
- # Unmount /data_mirror mounts in the reverse order of corresponding mounts.
- umount /data_mirror/data_ce/null/0
- umount /data_mirror/data_ce/null
- umount /data_mirror/data_de/null
- umount /data_mirror/storage_area/0
- umount /data_mirror/storage_area
- umount /data_mirror/cur_profiles
- umount /data_mirror/ref_profiles
- umount /data_mirror
- remount_userdata
- start bootanim
-
-on userspace-reboot-resume
- trigger userspace-reboot-fs-remount
- trigger post-fs-data
- trigger zygote-start
- trigger early-boot
- trigger boot
-
-on property:sys.boot_completed=1 && property:sys.init.userspace_reboot.in_progress=1
- setprop sys.init.userspace_reboot.in_progress ""
-
# Multi-Gen LRU Experiment
on property:persist.device_config.mglru_native.lru_gen_config=none
write /sys/kernel/mm/lru_gen/enabled 0
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index dde784e..b30d6d0 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -139,7 +139,3 @@
on property:sys.usb.typec.power_role=sink
write /sys/class/dual_role_usb/otg_default/power_role ${sys.usb.typec.power_role}
setprop sys.usb.typec.state ${sys.usb.typec.power_role}
-
-on userspace-reboot-requested
- setprop sys.usb.config ""
- setprop sys.usb.state ""
diff --git a/trusty/libtrusty-rs/Android.bp b/trusty/libtrusty-rs/Android.bp
index 4fc162b..e289005 100644
--- a/trusty/libtrusty-rs/Android.bp
+++ b/trusty/libtrusty-rs/Android.bp
@@ -21,9 +21,10 @@
crate_name: "trusty",
vendor_available: true,
srcs: [
- "src/lib.rs"
+ "src/lib.rs",
],
rustlibs: [
+ "liblog_rust",
"libnix",
"liblibc",
],
@@ -36,5 +37,5 @@
rustlibs: [
"libtrusty-rs",
"liblibc",
- ]
+ ],
}
diff --git a/trusty/libtrusty-rs/src/lib.rs b/trusty/libtrusty-rs/src/lib.rs
index 22b894a..9237c8b 100644
--- a/trusty/libtrusty-rs/src/lib.rs
+++ b/trusty/libtrusty-rs/src/lib.rs
@@ -61,12 +61,18 @@
//! ```
use crate::sys::tipc_connect;
+use log::{trace, warn};
+use nix::sys::socket;
+use std::convert::From;
use std::ffi::CString;
use std::fs::File;
+use std::io;
use std::io::prelude::*;
use std::io::{ErrorKind, Result};
use std::os::unix::prelude::AsRawFd;
use std::path::Path;
+use std::thread;
+use std::time;
mod sys;
@@ -98,7 +104,89 @@
/// bytes. This is handled with a panic because the service names are all
/// hard-coded constants, and so such an error should always be indicative of a
/// bug in the calling code.
- pub fn connect(device: impl AsRef<Path>, service: &str) -> Result<Self> {
+ pub fn connect(device: &str, service: &str) -> Result<Self> {
+ if let Some(cid_port_str) = device.strip_prefix("VSOCK:") {
+ Self::connect_vsock(cid_port_str, service)
+ } else {
+ Self::connect_tipc(device, service)
+ }
+ }
+
+ fn connect_vsock(type_cid_port_str: &str, service: &str) -> Result<Self> {
+ let cid_port_str;
+ let socket_type;
+ if let Some(stream_cid_port_str) = type_cid_port_str.strip_prefix("STREAM:") {
+ socket_type = socket::SockType::Stream;
+ cid_port_str = stream_cid_port_str;
+ } else if let Some(seqpacket_cid_port_str) = type_cid_port_str.strip_prefix("SEQPACKET:") {
+ socket_type = socket::SockType::SeqPacket;
+ cid_port_str = seqpacket_cid_port_str;
+ } else {
+ /*
+ * Default to SOCK_STREAM if neither type is specified.
+ *
+ * TODO: use SOCK_SEQPACKET by default instead of SOCK_STREAM when SOCK_SEQPACKET is fully
+ * supported since it matches tipc better. At the moment SOCK_SEQPACKET is not supported by
+ * crosvm. It is also significantly slower since the Linux kernel implementation (as of
+ * v6.7-rc1) sends credit update packets every time it receives a data packet while the
+ * SOCK_STREAM version skips these unless the remaining buffer space is "low".
+ */
+ socket_type = socket::SockType::Stream;
+ cid_port_str = type_cid_port_str;
+ }
+
+ let [cid, port]: [u32; 2] = cid_port_str
+ .split(':')
+ .map(|v| v.parse::<u32>().map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e)))
+ .collect::<Result<Vec<u32>>>()?
+ .try_into()
+ .map_err(|e| {
+ io::Error::new(io::ErrorKind::InvalidInput, format!("Wrong number of args: {e:?}"))
+ })?;
+
+ trace!("got cid, port: {cid}, {port}");
+ let s = socket::socket(
+ socket::AddressFamily::Vsock,
+ socket_type,
+ socket::SockFlag::SOCK_CLOEXEC,
+ None,
+ )?;
+ trace!("got socket");
+ let sa = socket::VsockAddr::new(cid, port);
+ trace!("got sa");
+
+ //let connect_timeout = libc::timeval {tv_sec: 60, tv_usec: 0};
+ // TODO: Set AF_VSOCK/SO_VM_SOCKETS_CONNECT_TIMEOUT sockopt.
+
+ let mut retry = 10;
+ loop {
+ let res = socket::connect(s.as_raw_fd(), &sa);
+ if res.is_ok() || retry <= 0 {
+ res?;
+ break;
+ }
+ warn!("vsock:{cid}:{port} connect failed {res:?}, {retry} retries remaining");
+ retry -= 1;
+ thread::sleep(time::Duration::from_secs(5));
+ }
+ trace!("connected");
+ // TODO: Current vsock tipc bridge in trusty expects a port name in the
+ // first packet. We need to replace this with a protocol that also does DICE
+ // based authentication.
+ // `s` is a valid file descriptor because it came from socket::socket.
+ let mut channel = Self(File::from(s));
+ channel.send(service.as_bytes())?;
+ trace!("sent tipc port name");
+
+ // Work around lack of seq packet support. Read a status byte to prevent
+ // the caller from sending more data until srv_name has been read.
+ let mut status = [0; 1];
+ channel.recv_no_alloc(&mut status)?;
+ trace!("got status byte: {status:?}");
+ Ok(channel)
+ }
+
+ fn connect_tipc(device: impl AsRef<Path>, service: &str) -> Result<Self> {
let file = File::options().read(true).write(true).open(device)?;
let srv_name = CString::new(service).expect("Service name contained null bytes");
@@ -108,7 +196,7 @@
tipc_connect(file.as_raw_fd(), srv_name.as_ptr())?;
}
- Ok(TipcChannel(file))
+ Ok(Self(file))
}
/// Sends a message to the connected service.
diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c
index f44f8b4..63262a0 100644
--- a/trusty/libtrusty/trusty.c
+++ b/trusty/libtrusty/trusty.c
@@ -23,16 +23,161 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
#include <unistd.h>
+#include <linux/vm_sockets.h> /* must be after sys/socket.h */
#include <log/log.h>
#include <trusty/ipc.h>
+static const char* strip_prefix(const char* str, const char* prefix) {
+ size_t prefix_len = strlen(prefix);
+ if (strncmp(str, prefix, prefix_len) == 0) {
+ return str + prefix_len;
+ } else {
+ return NULL;
+ }
+}
+
+static bool use_vsock_connection = false;
+static int tipc_vsock_connect(const char* type_cid_port_str, const char* srv_name) {
+ int ret;
+ const char* cid_port_str;
+ char* port_str;
+ char* end_str;
+ int socket_type;
+ if ((cid_port_str = strip_prefix(type_cid_port_str, "STREAM:"))) {
+ socket_type = SOCK_STREAM;
+ } else if ((cid_port_str = strip_prefix(type_cid_port_str, "SEQPACKET:"))) {
+ socket_type = SOCK_SEQPACKET;
+ } else {
+ /*
+ * Default to SOCK_STREAM if neither type is specified.
+ *
+ * TODO: use SOCK_SEQPACKET by default instead of SOCK_STREAM when SOCK_SEQPACKET is fully
+ * supported since it matches tipc better. At the moment SOCK_SEQPACKET is not supported by
+ * crosvm. It is also significantly slower since the Linux kernel implementation (as of
+ * v6.7-rc1) sends credit update packets every time it receives a data packet while the
+ * SOCK_STREAM version skips these unless the remaining buffer space is "low".
+ */
+ socket_type = SOCK_STREAM;
+ cid_port_str = type_cid_port_str;
+ }
+ long cid = strtol(cid_port_str, &port_str, 0);
+ if (port_str[0] != ':') {
+ ALOGE("%s: invalid VSOCK str, \"%s\", need cid:port missing : after cid\n", __func__,
+ cid_port_str);
+ return -EINVAL;
+ }
+ long port = strtol(port_str + 1, &end_str, 0);
+ if (end_str[0] != '\0') {
+ ALOGE("%s: invalid VSOCK str, \"%s\", need cid:port got %ld:%ld\n", __func__, cid_port_str,
+ cid, port);
+ return -EINVAL;
+ }
+ int fd = socket(AF_VSOCK, socket_type, 0);
+ if (fd < 0) {
+ ret = -errno;
+ ALOGE("%s: can't get vsock %ld:%ld socket for tipc service \"%s\" (err=%d)\n", __func__,
+ cid, port, srv_name, errno);
+ return ret < 0 ? ret : -1;
+ }
+ struct timeval connect_timeout = {.tv_sec = 60, .tv_usec = 0};
+ ret = setsockopt(fd, AF_VSOCK, SO_VM_SOCKETS_CONNECT_TIMEOUT, &connect_timeout,
+ sizeof(connect_timeout));
+ if (ret) {
+ ALOGE("%s: vsock %ld:%ld: Failed to set connect timeout (err=%d)\n", __func__, cid, port,
+ errno);
+ /* failed to set longer timeout, but try to connect anyway */
+ }
+ struct sockaddr_vm sa = {
+ .svm_family = AF_VSOCK,
+ .svm_port = port,
+ .svm_cid = cid,
+ };
+ int retry = 10;
+ do {
+ ret = TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)&sa, sizeof(sa)));
+ if (ret && (errno == ENODEV || errno == ESOCKTNOSUPPORT) && --retry) {
+ /*
+ * The kernel returns ESOCKTNOSUPPORT instead of ENODEV if the socket type is
+ * SOCK_SEQPACKET and the guest CID we are trying to connect to is not ready yet.
+ */
+ ALOGE("%s: Can't connect to vsock %ld:%ld for tipc service \"%s\" (err=%d) %d retries "
+ "remaining\n",
+ __func__, cid, port, srv_name, errno, retry);
+ sleep(1);
+ } else {
+ retry = 0;
+ }
+ } while (retry);
+ if (ret) {
+ ret = -errno;
+ ALOGE("%s: Can't connect to vsock %ld:%ld for tipc service \"%s\" (err=%d)\n", __func__,
+ cid, port, srv_name, errno);
+ close(fd);
+ return ret < 0 ? ret : -1;
+ }
+ /*
+ * TODO: Current vsock tipc bridge in trusty expects a port name in the
+ * first packet. We need to replace this with a protocol that also does DICE
+ * based authentication.
+ */
+ ret = TEMP_FAILURE_RETRY(write(fd, srv_name, strlen(srv_name)));
+ if (ret != strlen(srv_name)) {
+ ret = -errno;
+ ALOGE("%s: vsock %ld:%ld: failed to send tipc service name \"%s\" (err=%d)\n", __func__,
+ cid, port, srv_name, errno);
+ close(fd);
+ return ret < 0 ? ret : -1;
+ }
+ /*
+ * Work around lack of seq packet support. Read a status byte to prevent
+ * the caller from sending more data until srv_name has been read.
+ */
+ int8_t status;
+ ret = TEMP_FAILURE_RETRY(read(fd, &status, sizeof(status)));
+ if (ret != sizeof(status)) {
+ ALOGE("%s: vsock %ld:%ld: failed to read status byte for connect to tipc service name "
+ "\"%s\" (err=%d)\n",
+ __func__, cid, port, srv_name, errno);
+ close(fd);
+ return ret < 0 ? ret : -1;
+ }
+ use_vsock_connection = true;
+ return fd;
+}
+
+static size_t tipc_vsock_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shms,
+ int shmcnt) {
+ int ret;
+
+ (void)shms;
+ if (shmcnt != 0) {
+ ALOGE("%s: vsock does not yet support passing fds\n", __func__);
+ return -ENOTSUP;
+ }
+ ret = TEMP_FAILURE_RETRY(writev(fd, iov, iovcnt));
+ if (ret < 0) {
+ ret = -errno;
+ ALOGE("%s: failed to send message (err=%d)\n", __func__, errno);
+ return ret < 0 ? ret : -1;
+ }
+
+ return ret;
+}
+
int tipc_connect(const char* dev_name, const char* srv_name) {
int fd;
int rc;
+ const char* type_cid_port_str = strip_prefix(dev_name, "VSOCK:");
+ if (type_cid_port_str) {
+ return tipc_vsock_connect(type_cid_port_str, srv_name);
+ }
+
fd = TEMP_FAILURE_RETRY(open(dev_name, O_RDWR));
if (fd < 0) {
rc = -errno;
@@ -54,6 +199,9 @@
ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shms,
int shmcnt) {
+ if (use_vsock_connection) {
+ return tipc_vsock_send(fd, iov, iovcnt, shms, shmcnt);
+ }
struct tipc_send_msg_req req;
req.iov = (__u64)iov;
req.iov_cnt = (__u64)iovcnt;