[automerger skipped] Backport of Win-specific suppression of potentially rogue construct that can engage am: c3483e4c8a am: 07995227fe -s ours am: b446f13c58 -s ours am: b0bae04b87 -s ours
am skip reason: Merged-In Ie1f82db2fb14e1bdd183bf8d3d93d5e9f974be5d with SHA-1 efe701798b is already in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/system/core/+/17586924
Change-Id: If3a24cff2e54cb9ae2465f39c59adbed0aad7d4a
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 21df8af..8896ec3 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -170,6 +170,22 @@
FS_STAT_SET_RESERVED_BLOCKS_FAILED | FS_STAT_ENABLE_ENCRYPTION_FAILED);
}
+static bool umount_retry(const std::string& mount_point) {
+ int retry_count = 5;
+ bool umounted = false;
+
+ while (retry_count-- > 0) {
+ umounted = umount(mount_point.c_str()) == 0;
+ if (umounted) {
+ LINFO << __FUNCTION__ << "(): unmount(" << mount_point << ") succeeded";
+ break;
+ }
+ PERROR << __FUNCTION__ << "(): umount(" << mount_point << ") failed";
+ if (retry_count) sleep(1);
+ }
+ return umounted;
+}
+
static void check_fs(const std::string& blk_device, const std::string& fs_type,
const std::string& target, int* fs_stat) {
int status;
@@ -209,25 +225,12 @@
tmpmnt_opts.c_str());
PINFO << __FUNCTION__ << "(): mount(" << blk_device << "," << target << "," << fs_type
<< ")=" << ret;
- if (!ret) {
- bool umounted = false;
- int retry_count = 5;
- while (retry_count-- > 0) {
- umounted = umount(target.c_str()) == 0;
- if (umounted) {
- LINFO << __FUNCTION__ << "(): unmount(" << target << ") succeeded";
- break;
- }
- PERROR << __FUNCTION__ << "(): umount(" << target << ") failed";
- if (retry_count) sleep(1);
- }
- if (!umounted) {
- // boot may fail but continue and leave it to later stage for now.
- PERROR << __FUNCTION__ << "(): umount(" << target << ") timed out";
- *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
- }
- } else {
+ if (ret) {
*fs_stat |= FS_STAT_RO_MOUNT_FAILED;
+ } else if (!umount_retry(target)) {
+ // boot may fail but continue and leave it to later stage for now.
+ PERROR << __FUNCTION__ << "(): umount(" << target << ") timed out";
+ *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
}
}
@@ -268,12 +271,12 @@
LINFO << "Running " << F2FS_FSCK_BIN << " -f -c 10000 --debug-cache "
<< realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_forced_argv), f2fs_fsck_forced_argv,
- &status, false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
+ &status, false, LOG_KLOG | LOG_FILE, false, nullptr);
} else {
LINFO << "Running " << F2FS_FSCK_BIN << " -a -c 10000 --debug-cache "
<< realpath(blk_device);
ret = logwrap_fork_execvp(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, false,
- LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE);
+ LOG_KLOG | LOG_FILE, false, nullptr);
}
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
@@ -1029,12 +1032,11 @@
return FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
}
} else if (should_use_metadata_encryption(entry)) {
- if (umount(entry.mount_point.c_str()) == 0) {
+ if (umount_retry(entry.mount_point)) {
return FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION;
- } else {
- PERROR << "Could not umount " << entry.mount_point << " - fail since can't encrypt";
- return FS_MGR_MNTALL_FAIL;
}
+ PERROR << "Could not umount " << entry.mount_point << " - fail since can't encrypt";
+ return FS_MGR_MNTALL_FAIL;
} else if (entry.fs_mgr_flags.file_encryption || entry.fs_mgr_flags.force_fde_or_fbe) {
LINFO << entry.mount_point << " is file encrypted";
return FS_MGR_MNTALL_DEV_FILE_ENCRYPTED;
@@ -1880,9 +1882,13 @@
auto& mount_point = alt_mount_point.empty() ? entry.mount_point : alt_mount_point;
// Run fsck if needed
- prepare_fs_for_mount(entry.blk_device, entry, mount_point);
+ int ret = prepare_fs_for_mount(entry.blk_device, entry, mount_point);
+ // Wiped case doesn't require to try __mount below.
+ if (ret & FS_STAT_INVALID_MAGIC) {
+ return FS_MGR_DOMNT_FAILED;
+ }
- int ret = __mount(entry.blk_device, mount_point, entry);
+ ret = __mount(entry.blk_device, mount_point, entry);
if (ret) {
ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;
}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 4d32bda..cb2f249 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -866,9 +866,14 @@
errno = save_errno;
}
entry.flags &= ~MS_RDONLY;
+ entry.flags |= MS_SYNCHRONOUS;
+ entry.fs_options = "nodiscard";
fs_mgr_set_blk_ro(device_path, false);
}
- entry.fs_mgr_flags.check = true;
+ // check_fs requires apex runtime library
+ if (fs_mgr_overlayfs_already_mounted("/data", false)) {
+ entry.fs_mgr_flags.check = true;
+ }
auto save_errno = errno;
if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0;
if (!mounted) {
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index e43c00b..b1d5b39 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -170,19 +170,18 @@
return access("/system/bin/recovery", F_OK) == 0;
}
-bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
- const std::chrono::milliseconds& timeout_ms) {
+bool DeviceMapper::CreateEmptyDevice(const std::string& name) {
std::string uuid = GenerateUuid();
- if (!CreateDevice(name, uuid)) {
- return false;
- }
+ return CreateDevice(name, uuid);
+}
+bool DeviceMapper::WaitForDevice(const std::string& name,
+ const std::chrono::milliseconds& timeout_ms, std::string* path) {
// We use the unique path for testing whether the device is ready. After
// that, it's safe to use the dm-N path which is compatible with callers
// that expect it to be formatted as such.
std::string unique_path;
- if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
- !GetDmDevicePathByName(name, path)) {
+ if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) {
DeleteDevice(name);
return false;
}
@@ -208,6 +207,25 @@
return true;
}
+bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
+ const std::chrono::milliseconds& timeout_ms) {
+ if (!CreateEmptyDevice(name)) {
+ return false;
+ }
+
+ if (!LoadTableAndActivate(name, table)) {
+ DeleteDevice(name);
+ return false;
+ }
+
+ if (!WaitForDevice(name, timeout_ms, path)) {
+ DeleteDevice(name);
+ return false;
+ }
+
+ return true;
+}
+
bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
struct dm_ioctl io;
InitIo(&io, name);
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 8006db2..541f254 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -29,6 +29,7 @@
#include <thread>
#include <android-base/file.h>
+#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
@@ -679,3 +680,13 @@
ASSERT_NE(0, access(path.c_str(), F_OK));
ASSERT_EQ(ENOENT, errno);
}
+
+TEST(libdm, CreateEmptyDevice) {
+ DeviceMapper& dm = DeviceMapper::Instance();
+ ASSERT_TRUE(dm.CreateEmptyDevice("empty-device"));
+ auto guard =
+ android::base::make_scope_guard([&]() { dm.DeleteDeviceIfExists("empty-device", 5s); });
+
+ // Empty device should be in suspended state.
+ ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device"));
+}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index bdbbf91..e6698ea 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -119,6 +119,19 @@
// - ACTIVE: resumes the device.
bool ChangeState(const std::string& name, DmDeviceState state);
+ // Creates empty device.
+ // This supports a use case when a caller doesn't need a device straight away, but instead
+ // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd
+ // to create user space paths.
+ // Callers are expected to then activate their device by calling LoadTableAndActivate function.
+ // To avoid race conditions, callers must still synchronize with ueventd by calling
+ // WaitForDevice function.
+ bool CreateEmptyDevice(const std::string& name);
+
+ // Waits for device paths to be created in the user space.
+ bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
+ std::string* path);
+
// Creates a device, loads the given table, and activates it. If the device
// is not able to be activated, it is destroyed, and false is returned.
// After creation, |path| contains the result of calling
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 9bf5db1..69d8967 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -386,6 +386,17 @@
// first-stage to decide whether to launch snapuserd.
bool IsSnapuserdRequired();
+ // Add new public entries above this line.
+
+ // Helpers for failure injection.
+ using MergeConsistencyChecker =
+ std::function<MergeFailureCode(const std::string& name, const SnapshotStatus& status)>;
+
+ void set_merge_consistency_checker(MergeConsistencyChecker checker) {
+ merge_consistency_checker_ = checker;
+ }
+ MergeConsistencyChecker merge_consistency_checker() const { return merge_consistency_checker_; }
+
private:
FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
FRIEND_TEST(SnapshotTest, CreateSnapshot);
@@ -400,6 +411,7 @@
FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
FRIEND_TEST(SnapshotUpdateTest, AddPartition);
+ FRIEND_TEST(SnapshotUpdateTest, ConsistencyCheckResume);
FRIEND_TEST(SnapshotUpdateTest, DaemonTransition);
FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
@@ -782,6 +794,7 @@
std::function<bool(const std::string&)> uevent_regen_callback_;
std::unique_ptr<SnapuserdClient> snapuserd_client_;
std::unique_ptr<LpMetadata> old_partition_metadata_;
+ MergeConsistencyChecker merge_consistency_checker_;
};
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 4c94da2..40cb35b 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -87,6 +87,8 @@
static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator";
static constexpr auto kUpdateStateCheckInterval = 2s;
+MergeFailureCode CheckMergeConsistency(const std::string& name, const SnapshotStatus& status);
+
// Note: IImageManager is an incomplete type in the header, so the default
// destructor doesn't work.
SnapshotManager::~SnapshotManager() {}
@@ -116,6 +118,7 @@
SnapshotManager::SnapshotManager(IDeviceInfo* device) : device_(device) {
metadata_dir_ = device_->GetMetadataDir();
+ merge_consistency_checker_ = android::snapshot::CheckMergeConsistency;
}
static std::string GetCowName(const std::string& snapshot_name) {
@@ -1175,6 +1178,10 @@
const SnapshotStatus& status) {
CHECK(lock);
+ return merge_consistency_checker_(name, status);
+}
+
+MergeFailureCode CheckMergeConsistency(const std::string& name, const SnapshotStatus& status) {
if (!status.compression_enabled()) {
// Do not try to verify old-style COWs yet.
return MergeFailureCode::Ok;
@@ -1252,9 +1259,11 @@
}
SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
- CHECK(update_status.state() == UpdateState::Merging);
+ CHECK(update_status.state() == UpdateState::Merging ||
+ update_status.state() == UpdateState::MergeFailed);
CHECK(update_status.merge_phase() == MergePhase::FIRST_PHASE);
+ update_status.set_state(UpdateState::Merging);
update_status.set_merge_phase(MergePhase::SECOND_PHASE);
if (!WriteSnapshotUpdateStatus(lock, update_status)) {
return MergeFailureCode::WriteStatus;
@@ -2556,6 +2565,7 @@
SnapshotUpdateStatus old_status = ReadSnapshotUpdateStatus(lock);
status.set_compression_enabled(old_status.compression_enabled());
status.set_source_build_fingerprint(old_status.source_build_fingerprint());
+ status.set_merge_phase(old_status.merge_phase());
}
return WriteSnapshotUpdateStatus(lock, status);
}
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 7630efe..3a3aedc 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1297,6 +1297,92 @@
}
}
+// Test that a transient merge consistency check failure can resume properly.
+TEST_F(SnapshotUpdateTest, ConsistencyCheckResume) {
+ if (!IsCompressionEnabled()) {
+ // b/179111359
+ GTEST_SKIP() << "Skipping Virtual A/B Compression test";
+ }
+
+ auto old_sys_size = GetSize(sys_);
+ auto old_prd_size = GetSize(prd_);
+
+ // Grow |sys| but shrink |prd|.
+ SetSize(sys_, old_sys_size * 2);
+ sys_->set_estimate_cow_size(8_MiB);
+ SetSize(prd_, old_prd_size / 2);
+ prd_->set_estimate_cow_size(1_MiB);
+
+ AddOperationForPartitions();
+
+ ASSERT_TRUE(sm->BeginUpdate());
+ ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_));
+ ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
+ ASSERT_TRUE(WriteSnapshotAndHash("vnd_b"));
+ ASSERT_TRUE(ShiftAllSnapshotBlocks("prd_b", old_prd_size));
+
+ sync();
+
+ // Assert that source partitions aren't affected.
+ for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name));
+ }
+
+ ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
+
+ // Simulate shutting down the device.
+ ASSERT_TRUE(UnmapAll());
+
+ // After reboot, init does first stage mount.
+ auto init = NewManagerForFirstStageMount("_b");
+ ASSERT_NE(init, nullptr);
+ ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount());
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+
+ // Check that the target partitions have the same content.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name));
+ }
+
+ auto old_checker = init->merge_consistency_checker();
+
+ init->set_merge_consistency_checker(
+ [](const std::string&, const SnapshotStatus&) -> MergeFailureCode {
+ return MergeFailureCode::WrongMergeCountConsistencyCheck;
+ });
+
+ // Initiate the merge and wait for it to be completed.
+ ASSERT_TRUE(init->InitiateMerge());
+ {
+ // Check that the merge phase is FIRST_PHASE until at least one call
+ // to ProcessUpdateState() occurs.
+ ASSERT_TRUE(AcquireLock());
+ auto local_lock = std::move(lock_);
+ auto status = init->ReadSnapshotUpdateStatus(local_lock.get());
+ ASSERT_EQ(status.merge_phase(), MergePhase::FIRST_PHASE);
+ }
+
+ // Merge should have failed.
+ ASSERT_EQ(UpdateState::MergeFailed, init->ProcessUpdateState());
+
+ // Simulate shutting down the device and creating partitions again.
+ ASSERT_TRUE(UnmapAll());
+
+ // Restore the checker.
+ init->set_merge_consistency_checker(std::move(old_checker));
+
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+
+ // Complete the merge.
+ ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
+
+ // Check that the target partitions have the same content after the merge.
+ for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
+ ASSERT_TRUE(IsPartitionUnchanged(name))
+ << "Content of " << name << " changes after the merge";
+ }
+}
+
// Test that if new system partitions uses empty space in super, that region is not snapshotted.
TEST_F(SnapshotUpdateTest, DirectWriteEmptySpace) {
GTEST_SKIP() << "b/141889746";
diff --git a/fs_mgr/libsnapshot/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd_readahead.cpp
index 16d5919..e55fea3 100644
--- a/fs_mgr/libsnapshot/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_readahead.cpp
@@ -226,9 +226,15 @@
int num_ops = 0;
int total_blocks_merged = 0;
+ // This memcpy is important as metadata_buffer_ will be an unaligned address and will fault
+ // on 32-bit systems
+ std::unique_ptr<uint8_t[]> metadata_buffer =
+ std::make_unique<uint8_t[]>(snapuserd_->GetBufferMetadataSize());
+ memcpy(metadata_buffer.get(), metadata_buffer_, snapuserd_->GetBufferMetadataSize());
+
while (true) {
struct ScratchMetadata* bm = reinterpret_cast<struct ScratchMetadata*>(
- (char*)metadata_buffer_ + metadata_offset);
+ (char*)metadata_buffer.get() + metadata_offset);
// Done reading metadata
if (bm->new_block == 0 && bm->file_offset == 0) {
diff --git a/init/Android.bp b/init/Android.bp
index 7eeafa2..a57f3a4 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -89,7 +89,19 @@
"host_init_verifier.cpp",
]
-cc_defaults {
+soong_config_module_type {
+ name: "libinit_cc_defaults",
+ module_type: "cc_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT",
+ ],
+ properties: [
+ "cflags",
+ ],
+}
+
+libinit_cc_defaults {
name: "init_defaults",
sanitize: {
misc_undefined: ["signed-integer-overflow"],
@@ -109,6 +121,7 @@
"-DDUMP_ON_UMOUNT_FAILURE=0",
"-DSHUTDOWN_ZERO_TIMEOUT=0",
"-DINIT_FULL_SOURCES",
+ "-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=0",
],
product_variables: {
debuggable: {
@@ -137,6 +150,14 @@
cppflags: ["-DUSER_MODE_LINUX"],
},
},
+ soong_config_variables: {
+ PRODUCT_INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT: {
+ cflags: [
+ "-UINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT",
+ "-DINSTALL_DEBUG_POLICY_TO_SYSTEM_EXT=1",
+ ],
+ },
+ },
static_libs: [
"libavb",
"libc++fs",
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 78e5b60..c7b7b0c 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -330,14 +330,21 @@
// If "/force_debuggable" is present, the second-stage init will use a userdebug
// sepolicy and load adb_debug.prop to allow adb root, if the device is unlocked.
if (access("/force_debuggable", F_OK) == 0) {
+ constexpr const char adb_debug_prop_src[] = "/adb_debug.prop";
+ constexpr const char userdebug_plat_sepolicy_cil_src[] = "/userdebug_plat_sepolicy.cil";
std::error_code ec; // to invoke the overloaded copy_file() that won't throw.
- if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) ||
- !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) {
- LOG(ERROR) << "Failed to setup debug ramdisk";
- } else {
- // setenv for second-stage init to read above kDebugRamdisk* files.
- setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
+ if (access(adb_debug_prop_src, F_OK) == 0 &&
+ !fs::copy_file(adb_debug_prop_src, kDebugRamdiskProp, ec)) {
+ LOG(WARNING) << "Can't copy " << adb_debug_prop_src << " to " << kDebugRamdiskProp
+ << ": " << ec.message();
}
+ if (access(userdebug_plat_sepolicy_cil_src, F_OK) == 0 &&
+ !fs::copy_file(userdebug_plat_sepolicy_cil_src, kDebugRamdiskSEPolicy, ec)) {
+ LOG(WARNING) << "Can't copy " << userdebug_plat_sepolicy_cil_src << " to "
+ << kDebugRamdiskSEPolicy << ": " << ec.message();
+ }
+ // setenv for second-stage init to read above kDebugRamdisk* files.
+ setenv("INIT_FORCE_DEBUGGABLE", "true", 1);
}
if (ForceNormalBoot(cmdline, bootconfig)) {
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 42d3023..29c0ff3 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -295,6 +295,25 @@
return access(plat_policy_cil_file, R_OK) != -1;
}
+std::optional<const char*> GetUserdebugPlatformPolicyFile() {
+ // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
+ const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
+ if (force_debuggable_env && "true"s == force_debuggable_env && AvbHandle::IsDeviceUnlocked()) {
+ const std::vector<const char*> debug_policy_candidates = {
+#if INSTALL_DEBUG_POLICY_TO_SYSTEM_EXT == 1
+ "/system_ext/etc/selinux/userdebug_plat_sepolicy.cil",
+#endif
+ kDebugRamdiskSEPolicy,
+ };
+ for (const char* debug_policy : debug_policy_candidates) {
+ if (access(debug_policy, F_OK) == 0) {
+ return debug_policy;
+ }
+ }
+ }
+ return std::nullopt;
+}
+
struct PolicyFile {
unique_fd fd;
std::string path;
@@ -310,13 +329,10 @@
// secilc is invoked to compile the above three policy files into a single monolithic policy
// file. This file is then loaded into the kernel.
- // See if we need to load userdebug_plat_sepolicy.cil instead of plat_sepolicy.cil.
- const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE");
- bool use_userdebug_policy =
- ((force_debuggable_env && "true"s == force_debuggable_env) &&
- AvbHandle::IsDeviceUnlocked() && access(kDebugRamdiskSEPolicy, F_OK) == 0);
+ const auto userdebug_plat_sepolicy = GetUserdebugPlatformPolicyFile();
+ const bool use_userdebug_policy = userdebug_plat_sepolicy.has_value();
if (use_userdebug_policy) {
- LOG(WARNING) << "Using userdebug system sepolicy";
+ LOG(INFO) << "Using userdebug system sepolicy " << *userdebug_plat_sepolicy;
}
// Load precompiled policy from vendor image, if a matching policy is found there. The policy
@@ -413,7 +429,7 @@
// clang-format off
std::vector<const char*> compile_args {
"/system/bin/secilc",
- use_userdebug_policy ? kDebugRamdiskSEPolicy: plat_policy_cil_file,
+ use_userdebug_policy ? *userdebug_plat_sepolicy : plat_policy_cil_file,
"-m", "-M", "true", "-G", "-N",
"-c", version_as_string.c_str(),
plat_mapping_file.c_str(),
diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp
index 40467b7..7fd3f65 100644
--- a/init/snapuserd_transition.cpp
+++ b/init/snapuserd_transition.cpp
@@ -32,6 +32,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
+#include <fs_avb/fs_avb.h>
#include <libsnapshot/snapshot.h>
#include <libsnapshot/snapuserd_client.h>
#include <private/android_filesystem_config.h>
@@ -227,6 +228,56 @@
}
}
+/*
+ * Before starting init second stage, we will wait
+ * for snapuserd daemon to be up and running; bionic libc
+ * may read /system/etc/selinux/plat_property_contexts file
+ * before invoking main() function. This will happen if
+ * init initializes property during second stage. Any access
+ * to /system without snapuserd daemon will lead to a deadlock.
+ *
+ * Thus, we do a simple probe by reading system partition. This
+ * read will eventually be serviced by daemon confirming that
+ * daemon is up and running. Furthermore, we are still in the kernel
+ * domain and sepolicy has not been enforced yet. Thus, access
+ * to these device mapper block devices are ok even though
+ * we may see audit logs.
+ */
+bool SnapuserdSelinuxHelper::TestSnapuserdIsReady() {
+ std::string dev = "/dev/block/mapper/system"s + fs_mgr_get_slot_suffix();
+ android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_DIRECT));
+ if (fd < 0) {
+ PLOG(ERROR) << "open " << dev << " failed";
+ return false;
+ }
+
+ void* addr;
+ ssize_t page_size = getpagesize();
+ if (posix_memalign(&addr, page_size, page_size) < 0) {
+ PLOG(ERROR) << "posix_memalign with page size " << page_size;
+ return false;
+ }
+
+ std::unique_ptr<void, decltype(&::free)> buffer(addr, ::free);
+
+ int iter = 0;
+ while (iter < 10) {
+ ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), buffer.get(), page_size, 0));
+ if (n < 0) {
+ // Wait for sometime before retry
+ std::this_thread::sleep_for(100ms);
+ } else if (n == page_size) {
+ return true;
+ } else {
+ LOG(ERROR) << "pread returned: " << n << " from: " << dev << " expected: " << page_size;
+ }
+
+ iter += 1;
+ }
+
+ return false;
+}
+
void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
auto fd = GetRamdiskSnapuserdFd();
if (!fd) {
@@ -248,6 +299,13 @@
setenv(kSnapuserdFirstStagePidVar, std::to_string(pid).c_str(), 1);
LOG(INFO) << "Relaunched snapuserd with pid: " << pid;
+
+ if (!TestSnapuserdIsReady()) {
+ PLOG(FATAL) << "snapuserd daemon failed to launch";
+ } else {
+ LOG(INFO) << "snapuserd daemon is up and running";
+ }
+
return;
}
diff --git a/init/snapuserd_transition.h b/init/snapuserd_transition.h
index a5ab652..757af13 100644
--- a/init/snapuserd_transition.h
+++ b/init/snapuserd_transition.h
@@ -51,6 +51,7 @@
private:
void RelaunchFirstStageSnapuserd();
void ExecSnapuserd();
+ bool TestSnapuserdIsReady();
std::unique_ptr<SnapshotManager> sm_;
BlockDevInitializer block_dev_init_;
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index e9497a8..a6835fc 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -211,6 +211,7 @@
{ 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/resize2fs" },
{ 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/snapuserd" },
{ 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/tune2fs" },
+ { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/fsck.f2fs" },
// generic defaults
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 8f22d89..ffd4d12 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -157,6 +157,7 @@
#define AID_READPROC 3009 /* Allow /proc read access */
#define AID_WAKELOCK 3010 /* Allow system wakelock read/write access */
#define AID_UHID 3011 /* Allow read/write to /dev/uhid node */
+#define AID_READTRACEFS 3012 /* Allow tracefs read */
/* The range 5000-5999 is also reserved for vendor partition. */
#define AID_OEM_RESERVED_2_START 5000
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index fa2642d..50416fa 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -34,6 +34,8 @@
#ifndef __ANDROID_VNDK__
+bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+
static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc";
bool UsePerAppMemcg();
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index c824376..2ce3fa0 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -112,11 +112,16 @@
}
void DropTaskProfilesResourceCaching() {
- TaskProfiles::GetInstance().DropResourceCaching();
+ TaskProfiles::GetInstance().DropResourceCaching(ProfileAction::RCT_TASK);
+ TaskProfiles::GetInstance().DropResourceCaching(ProfileAction::RCT_PROCESS);
}
bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
- return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles);
+ return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, false);
+}
+
+bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+ return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, true);
}
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 449a505..45d3c7c 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -183,7 +183,19 @@
}
]
},
-
+ {
+ "Name": "Dex2oatPerformance",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "cpu",
+ "Path": "dex2oat"
+ }
+ }
+ ]
+ },
{
"Name": "CpuPolicySpread",
"Actions": [
@@ -638,7 +650,7 @@
},
{
"Name": "Dex2OatBootComplete",
- "Profiles": [ "SCHED_SP_BACKGROUND" ]
+ "Profiles": [ "Dex2oatPerformance", "LowIoPriority", "TimerSlackHigh" ]
}
]
}
diff --git a/libprocessgroup/profiles/task_profiles_28.json b/libprocessgroup/profiles/task_profiles_28.json
index 56053e0..e7be548 100644
--- a/libprocessgroup/profiles/task_profiles_28.json
+++ b/libprocessgroup/profiles/task_profiles_28.json
@@ -117,7 +117,19 @@
}
]
},
-
+ {
+ "Name": "Dex2oatPerformance",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "schedtune",
+ "Path": "background"
+ }
+ }
+ ]
+ },
{
"Name": "CpuPolicySpread",
"Actions": [
diff --git a/libprocessgroup/profiles/task_profiles_29.json b/libprocessgroup/profiles/task_profiles_29.json
index 52279b8..6174c8d 100644
--- a/libprocessgroup/profiles/task_profiles_29.json
+++ b/libprocessgroup/profiles/task_profiles_29.json
@@ -117,7 +117,19 @@
}
]
},
-
+ {
+ "Name": "Dex2oatPerformance",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "schedtune",
+ "Path": "background"
+ }
+ }
+ ]
+ },
{
"Name": "CpuPolicySpread",
"Actions": [
diff --git a/libprocessgroup/profiles/task_profiles_30.json b/libprocessgroup/profiles/task_profiles_30.json
index 56053e0..e7be548 100644
--- a/libprocessgroup/profiles/task_profiles_30.json
+++ b/libprocessgroup/profiles/task_profiles_30.json
@@ -117,7 +117,19 @@
}
]
},
-
+ {
+ "Name": "Dex2oatPerformance",
+ "Actions": [
+ {
+ "Name": "JoinCgroup",
+ "Params":
+ {
+ "Controller": "schedtune",
+ "Path": "background"
+ }
+ }
+ ]
+ },
{
"Name": "CpuPolicySpread",
"Actions": [
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index 1a4196a..169b1d3 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -165,27 +165,7 @@
return 0;
}
-int get_sched_policy(int tid, SchedPolicy* policy) {
- if (tid == 0) {
- tid = GetThreadId();
- }
-
- std::string group;
- if (schedboost_enabled()) {
- if ((getCGroupSubsys(tid, "schedtune", group) < 0) &&
- (getCGroupSubsys(tid, "cpu", group) < 0)) {
- LOG(ERROR) << "Failed to find cpu cgroup for tid " << tid;
- return -1;
- }
- }
- if (group.empty() && cpusets_enabled()) {
- if (getCGroupSubsys(tid, "cpuset", group) < 0) {
- LOG(ERROR) << "Failed to find cpuset cgroup for tid " << tid;
- return -1;
- }
- }
-
- // TODO: replace hardcoded directories
+static int get_sched_policy_from_group(const std::string& group, SchedPolicy* policy) {
if (group.empty()) {
*policy = SP_FOREGROUND;
} else if (group == "foreground") {
@@ -205,6 +185,35 @@
return 0;
}
+int get_sched_policy(int tid, SchedPolicy* policy) {
+ if (tid == 0) {
+ tid = GetThreadId();
+ }
+
+ std::string group;
+ if (schedboost_enabled()) {
+ if ((getCGroupSubsys(tid, "schedtune", group) < 0) &&
+ (getCGroupSubsys(tid, "cpu", group) < 0)) {
+ LOG(ERROR) << "Failed to find cpu cgroup for tid " << tid;
+ return -1;
+ }
+ // Wipe invalid group to fallback to cpuset
+ if (!group.empty()) {
+ if (get_sched_policy_from_group(group, policy) < 0) {
+ group.clear();
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ if (cpusets_enabled() && getCGroupSubsys(tid, "cpuset", group) < 0) {
+ LOG(ERROR) << "Failed to find cpuset cgroup for tid " << tid;
+ return -1;
+ }
+ return get_sched_policy_from_group(group, policy);
+}
+
#else
/* Stubs for non-Android targets. */
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index cf74e65..74ba7f6 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -51,6 +51,67 @@
static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE =
"/etc/task_profiles/task_profiles_%u.json";
+class FdCacheHelper {
+ public:
+ enum FdState {
+ FDS_INACCESSIBLE = -1,
+ FDS_APP_DEPENDENT = -2,
+ FDS_NOT_CACHED = -3,
+ };
+
+ static void Cache(const std::string& path, android::base::unique_fd& fd);
+ static void Drop(android::base::unique_fd& fd);
+ static void Init(const std::string& path, android::base::unique_fd& fd);
+ static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; }
+
+ private:
+ static bool IsAppDependentPath(const std::string& path);
+};
+
+void FdCacheHelper::Init(const std::string& path, android::base::unique_fd& fd) {
+ // file descriptors for app-dependent paths can't be cached
+ if (IsAppDependentPath(path)) {
+ // file descriptor is not cached
+ fd.reset(FDS_APP_DEPENDENT);
+ return;
+ }
+ // file descriptor can be cached later on request
+ fd.reset(FDS_NOT_CACHED);
+}
+
+void FdCacheHelper::Cache(const std::string& path, android::base::unique_fd& fd) {
+ if (fd != FDS_NOT_CACHED) {
+ return;
+ }
+
+ if (access(path.c_str(), W_OK) != 0) {
+ // file is not accessible
+ fd.reset(FDS_INACCESSIBLE);
+ return;
+ }
+
+ unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
+ if (tmp_fd < 0) {
+ PLOG(ERROR) << "Failed to cache fd '" << path << "'";
+ fd.reset(FDS_INACCESSIBLE);
+ return;
+ }
+
+ fd = std::move(tmp_fd);
+}
+
+void FdCacheHelper::Drop(android::base::unique_fd& fd) {
+ if (fd == FDS_NOT_CACHED) {
+ return;
+ }
+
+ fd.reset(FDS_NOT_CACHED);
+}
+
+bool FdCacheHelper::IsAppDependentPath(const std::string& path) {
+ return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
+}
+
void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) {
controller_ = controller;
file_name_ = file_name;
@@ -144,82 +205,89 @@
return true;
}
-bool SetCgroupAction::IsAppDependentPath(const std::string& path) {
- return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
-}
-
SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p)
: controller_(c), path_(p) {
- // file descriptors for app-dependent paths can't be cached
- if (IsAppDependentPath(path_)) {
- // file descriptor is not cached
- fd_.reset(FDS_APP_DEPENDENT);
- return;
- }
-
- // file descriptor can be cached later on request
- fd_.reset(FDS_NOT_CACHED);
+ FdCacheHelper::Init(controller_.GetTasksFilePath(path_), fd_[ProfileAction::RCT_TASK]);
+ // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
+ FdCacheHelper::Init(controller_.GetProcsFilePath(path_, 0, 0), fd_[ProfileAction::RCT_PROCESS]);
}
-void SetCgroupAction::EnableResourceCaching() {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (fd_ != FDS_NOT_CACHED) {
- return;
- }
-
- std::string tasks_path = controller_.GetTasksFilePath(path_);
-
- if (access(tasks_path.c_str(), W_OK) != 0) {
- // file is not accessible
- fd_.reset(FDS_INACCESSIBLE);
- return;
- }
-
- unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
- if (fd < 0) {
- PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'";
- fd_.reset(FDS_INACCESSIBLE);
- return;
- }
-
- fd_ = std::move(fd);
-}
-
-void SetCgroupAction::DropResourceCaching() {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (fd_ == FDS_NOT_CACHED) {
- return;
- }
-
- fd_.reset(FDS_NOT_CACHED);
-}
-
-bool SetCgroupAction::AddTidToCgroup(int tid, int fd) {
+bool SetCgroupAction::AddTidToCgroup(int tid, int fd, const char* controller_name) {
if (tid <= 0) {
return true;
}
std::string value = std::to_string(tid);
- if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) < 0) {
- // If the thread is in the process of exiting, don't flag an error
- if (errno != ESRCH) {
- PLOG(ERROR) << "AddTidToCgroup failed to write '" << value << "'; fd=" << fd;
- return false;
- }
+ if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) == value.length()) {
+ return true;
}
- return true;
+ // If the thread is in the process of exiting, don't flag an error
+ if (errno == ESRCH) {
+ return true;
+ }
+
+ // ENOSPC is returned when cpuset cgroup that we are joining has no online cpus
+ if (errno == ENOSPC && !strcmp(controller_name, "cpuset")) {
+ // This is an abnormal case happening only in testing, so report it only once
+ static bool empty_cpuset_reported = false;
+
+ if (empty_cpuset_reported) {
+ return true;
+ }
+
+ LOG(ERROR) << "Failed to add task '" << value
+ << "' into cpuset because all cpus in that cpuset are offline";
+ empty_cpuset_reported = true;
+ } else {
+ PLOG(ERROR) << "AddTidToCgroup failed to write '" << value << "'; fd=" << fd;
+ }
+
+ return false;
+}
+
+ProfileAction::CacheUseResult SetCgroupAction::UseCachedFd(ResourceCacheType cache_type,
+ int id) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_[cache_type])) {
+ // fd is cached, reuse it
+ if (!AddTidToCgroup(id, fd_[cache_type], controller()->name())) {
+ LOG(ERROR) << "Failed to add task into cgroup";
+ return ProfileAction::FAIL;
+ }
+ return ProfileAction::SUCCESS;
+ }
+
+ if (fd_[cache_type] == FdCacheHelper::FDS_INACCESSIBLE) {
+ // no permissions to access the file, ignore
+ return ProfileAction::SUCCESS;
+ }
+
+ if (cache_type == ResourceCacheType::RCT_TASK &&
+ fd_[cache_type] == FdCacheHelper::FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
+ return ProfileAction::FAIL;
+ }
+
+ return ProfileAction::UNUSED;
}
bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, pid);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
+ }
+
+ // fd was not cached or cached fd can't be used
std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
PLOG(WARNING) << "Failed to open " << procs_path;
return false;
}
- if (!AddTidToCgroup(pid, tmp_fd)) {
+ if (!AddTidToCgroup(pid, tmp_fd, controller()->name())) {
LOG(ERROR) << "Failed to add task into cgroup";
return false;
}
@@ -228,35 +296,19 @@
}
bool SetCgroupAction::ExecuteForTask(int tid) const {
- std::lock_guard<std::mutex> lock(fd_mutex_);
- if (IsFdValid()) {
- // fd is cached, reuse it
- if (!AddTidToCgroup(tid, fd_)) {
- LOG(ERROR) << "Failed to add task into cgroup";
- return false;
- }
- return true;
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, tid);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
}
- if (fd_ == FDS_INACCESSIBLE) {
- // no permissions to access the file, ignore
- return true;
- }
-
- if (fd_ == FDS_APP_DEPENDENT) {
- // application-dependent path can't be used with tid
- PLOG(ERROR) << "Application profile can't be applied to a thread";
- return false;
- }
-
- // fd was not cached because cached fd can't be used
+ // fd was not cached or cached fd can't be used
std::string tasks_path = controller()->GetTasksFilePath(path_);
unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC)));
if (tmp_fd < 0) {
- PLOG(WARNING) << "Failed to open " << tasks_path << ": " << strerror(errno);
+ PLOG(WARNING) << "Failed to open " << tasks_path;
return false;
}
- if (!AddTidToCgroup(tid, tmp_fd)) {
+ if (!AddTidToCgroup(tid, tmp_fd, controller()->name())) {
LOG(ERROR) << "Failed to add task into cgroup";
return false;
}
@@ -264,44 +316,128 @@
return true;
}
-bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
- std::string filepath(filepath_), value(value_);
+void SetCgroupAction::EnableResourceCaching(ResourceCacheType cache_type) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ // Return early to prevent unnecessary calls to controller_.Get{Tasks|Procs}FilePath() which
+ // include regex evaluations
+ if (fd_[cache_type] != FdCacheHelper::FDS_NOT_CACHED) {
+ return;
+ }
+ switch (cache_type) {
+ case (ProfileAction::RCT_TASK):
+ FdCacheHelper::Cache(controller_.GetTasksFilePath(path_), fd_[cache_type]);
+ break;
+ case (ProfileAction::RCT_PROCESS):
+ // uid and pid don't matter because IsAppDependentPath ensures the path doesn't use them
+ FdCacheHelper::Cache(controller_.GetProcsFilePath(path_, 0, 0), fd_[cache_type]);
+ break;
+ default:
+ LOG(ERROR) << "Invalid cache type is specified!";
+ break;
+ }
+}
- filepath = StringReplace(filepath, "<uid>", std::to_string(uid), true);
- filepath = StringReplace(filepath, "<pid>", std::to_string(pid), true);
- value = StringReplace(value, "<uid>", std::to_string(uid), true);
- value = StringReplace(value, "<pid>", std::to_string(pid), true);
+void SetCgroupAction::DropResourceCaching(ResourceCacheType cache_type) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ FdCacheHelper::Drop(fd_[cache_type]);
+}
- if (!WriteStringToFile(value, filepath)) {
- if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << filepath;
+WriteFileAction::WriteFileAction(const std::string& path, const std::string& value,
+ bool logfailures)
+ : path_(path), value_(value), logfailures_(logfailures) {
+ FdCacheHelper::Init(path_, fd_);
+}
+
+bool WriteFileAction::WriteValueToFile(const std::string& value, const std::string& path,
+ bool logfailures) {
+ // Use WriteStringToFd instead of WriteStringToFile because the latter will open file with
+ // O_TRUNC which causes kernfs_mutex contention
+ unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_WRONLY | O_CLOEXEC)));
+
+ if (tmp_fd < 0) {
+ if (logfailures) PLOG(WARNING) << "Failed to open " << path;
+ return false;
+ }
+
+ if (!WriteStringToFd(value, tmp_fd)) {
+ if (logfailures) PLOG(ERROR) << "Failed to write '" << value << "' to " << path;
return false;
}
return true;
}
+ProfileAction::CacheUseResult WriteFileAction::UseCachedFd(ResourceCacheType cache_type,
+ const std::string& value) const {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ if (FdCacheHelper::IsCached(fd_)) {
+ // fd is cached, reuse it
+ if (!WriteStringToFd(value, fd_)) {
+ if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << path_;
+ return ProfileAction::FAIL;
+ }
+ return ProfileAction::SUCCESS;
+ }
+
+ if (fd_ == FdCacheHelper::FDS_INACCESSIBLE) {
+ // no permissions to access the file, ignore
+ return ProfileAction::SUCCESS;
+ }
+
+ if (cache_type == ResourceCacheType::RCT_TASK && fd_ == FdCacheHelper::FDS_APP_DEPENDENT) {
+ // application-dependent path can't be used with tid
+ PLOG(ERROR) << "Application profile can't be applied to a thread";
+ return ProfileAction::FAIL;
+ }
+ return ProfileAction::UNUSED;
+}
+
+bool WriteFileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+ std::string value(value_);
+
+ value = StringReplace(value, "<uid>", std::to_string(uid), true);
+ value = StringReplace(value, "<pid>", std::to_string(pid), true);
+
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_PROCESS, value);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
+ }
+
+ std::string path(path_);
+ path = StringReplace(path, "<uid>", std::to_string(uid), true);
+ path = StringReplace(path, "<pid>", std::to_string(pid), true);
+
+ return WriteValueToFile(value, path, logfailures_);
+}
+
bool WriteFileAction::ExecuteForTask(int tid) const {
- std::string filepath(filepath_), value(value_);
+ std::string value(value_);
int uid = getuid();
- filepath = StringReplace(filepath, "<uid>", std::to_string(uid), true);
- filepath = StringReplace(filepath, "<pid>", std::to_string(tid), true);
value = StringReplace(value, "<uid>", std::to_string(uid), true);
value = StringReplace(value, "<pid>", std::to_string(tid), true);
- if (!WriteStringToFile(value, filepath)) {
- if (logfailures_) PLOG(ERROR) << "Failed to write '" << value << "' to " << filepath;
- return false;
+ CacheUseResult result = UseCachedFd(ProfileAction::RCT_TASK, value);
+ if (result != ProfileAction::UNUSED) {
+ return result == ProfileAction::SUCCESS;
}
- return true;
+ return WriteValueToFile(value, path_, logfailures_);
+}
+
+void WriteFileAction::EnableResourceCaching(ResourceCacheType) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ FdCacheHelper::Cache(path_, fd_);
+}
+
+void WriteFileAction::DropResourceCaching(ResourceCacheType) {
+ std::lock_guard<std::mutex> lock(fd_mutex_);
+ FdCacheHelper::Drop(fd_);
}
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
- if (!profile->ExecuteForProcess(uid, pid)) {
- PLOG(WARNING) << "ExecuteForProcess failed for aggregate profile";
- }
+ profile->ExecuteForProcess(uid, pid);
}
return true;
}
@@ -313,15 +449,15 @@
return true;
}
-void ApplyProfileAction::EnableResourceCaching() {
+void ApplyProfileAction::EnableResourceCaching(ResourceCacheType cache_type) {
for (const auto& profile : profiles_) {
- profile->EnableResourceCaching();
+ profile->EnableResourceCaching(cache_type);
}
}
-void ApplyProfileAction::DropResourceCaching() {
+void ApplyProfileAction::DropResourceCaching(ResourceCacheType cache_type) {
for (const auto& profile : profiles_) {
- profile->DropResourceCaching();
+ profile->DropResourceCaching(cache_type);
}
}
@@ -351,33 +487,33 @@
return true;
}
-void TaskProfile::EnableResourceCaching() {
+void TaskProfile::EnableResourceCaching(ProfileAction::ResourceCacheType cache_type) {
if (res_cached_) {
return;
}
for (auto& element : elements_) {
- element->EnableResourceCaching();
+ element->EnableResourceCaching(cache_type);
}
res_cached_ = true;
}
-void TaskProfile::DropResourceCaching() {
+void TaskProfile::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) {
if (!res_cached_) {
return;
}
for (auto& element : elements_) {
- element->DropResourceCaching();
+ element->DropResourceCaching(cache_type);
}
res_cached_ = false;
}
-void TaskProfiles::DropResourceCaching() const {
+void TaskProfiles::DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const {
for (auto& iter : profiles_) {
- iter.second->DropResourceCaching();
+ iter.second->DropResourceCaching(cache_type);
}
}
@@ -401,8 +537,7 @@
android::base::StringPrintf(TEMPLATE_TASK_PROFILE_API_FILE, api_level);
if (!access(api_profiles_path.c_str(), F_OK) || errno != ENOENT) {
if (!Load(CgroupMap::GetInstance(), api_profiles_path)) {
- LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid()
- << "] failed";
+ LOG(ERROR) << "Loading " << api_profiles_path << " for [" << getpid() << "] failed";
}
}
}
@@ -595,10 +730,13 @@
}
bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
- const std::vector<std::string>& profiles) {
+ const std::vector<std::string>& profiles, bool use_fd_cache) {
for (const auto& name : profiles) {
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
+ if (use_fd_cache) {
+ profile->EnableResourceCaching(ProfileAction::RCT_PROCESS);
+ }
if (!profile->ExecuteForProcess(uid, pid)) {
PLOG(WARNING) << "Failed to apply " << name << " process profile";
}
@@ -615,7 +753,7 @@
TaskProfile* profile = GetProfile(name);
if (profile != nullptr) {
if (use_fd_cache) {
- profile->EnableResourceCaching();
+ profile->EnableResourceCaching(ProfileAction::RCT_TASK);
}
if (!profile->ExecuteForTask(tid)) {
PLOG(WARNING) << "Failed to apply " << name << " task profile";
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index 25a84b0..1aaa196 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -45,14 +45,19 @@
// Abstract profile element
class ProfileAction {
public:
+ enum ResourceCacheType { RCT_TASK = 0, RCT_PROCESS, RCT_COUNT };
+
virtual ~ProfileAction() {}
// Default implementations will fail
virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; };
virtual bool ExecuteForTask(int) const { return false; };
- virtual void EnableResourceCaching() {}
- virtual void DropResourceCaching() {}
+ virtual void EnableResourceCaching(ResourceCacheType) {}
+ virtual void DropResourceCaching(ResourceCacheType) {}
+
+ protected:
+ enum CacheUseResult { SUCCESS, FAIL, UNUSED };
};
// Profile actions
@@ -115,43 +120,40 @@
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
- virtual void EnableResourceCaching();
- virtual void DropResourceCaching();
+ virtual void EnableResourceCaching(ResourceCacheType cache_type);
+ virtual void DropResourceCaching(ResourceCacheType cache_type);
const CgroupController* controller() const { return &controller_; }
- std::string path() const { return path_; }
private:
- enum FdState {
- FDS_INACCESSIBLE = -1,
- FDS_APP_DEPENDENT = -2,
- FDS_NOT_CACHED = -3,
- };
-
CgroupController controller_;
std::string path_;
- android::base::unique_fd fd_;
+ android::base::unique_fd fd_[ProfileAction::RCT_COUNT];
mutable std::mutex fd_mutex_;
- static bool IsAppDependentPath(const std::string& path);
- static bool AddTidToCgroup(int tid, int fd);
-
- bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; }
+ static bool AddTidToCgroup(int tid, int fd, const char* controller_name);
+ CacheUseResult UseCachedFd(ResourceCacheType cache_type, int id) const;
};
// Write to file action
class WriteFileAction : public ProfileAction {
public:
- WriteFileAction(const std::string& filepath, const std::string& value,
- bool logfailures) noexcept
- : filepath_(filepath), value_(value), logfailures_(logfailures) {}
+ WriteFileAction(const std::string& path, const std::string& value, bool logfailures);
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
+ virtual void EnableResourceCaching(ResourceCacheType cache_type);
+ virtual void DropResourceCaching(ResourceCacheType cache_type);
private:
- std::string filepath_, value_;
+ std::string path_, value_;
bool logfailures_;
+ android::base::unique_fd fd_;
+ mutable std::mutex fd_mutex_;
+
+ static bool WriteValueToFile(const std::string& value, const std::string& path,
+ bool logfailures);
+ CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const;
};
class TaskProfile {
@@ -163,8 +165,8 @@
bool ExecuteForProcess(uid_t uid, pid_t pid) const;
bool ExecuteForTask(int tid) const;
- void EnableResourceCaching();
- void DropResourceCaching();
+ void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
+ void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
private:
bool res_cached_;
@@ -179,8 +181,8 @@
virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
virtual bool ExecuteForTask(int tid) const;
- virtual void EnableResourceCaching();
- virtual void DropResourceCaching();
+ virtual void EnableResourceCaching(ProfileAction::ResourceCacheType cache_type);
+ virtual void DropResourceCaching(ProfileAction::ResourceCacheType cache_type);
private:
std::vector<std::shared_ptr<TaskProfile>> profiles_;
@@ -193,8 +195,9 @@
TaskProfile* GetProfile(const std::string& name) const;
const ProfileAttribute* GetAttribute(const std::string& name) const;
- void DropResourceCaching() const;
- bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
+ void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const;
+ bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
+ bool use_fd_cache);
bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
private:
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 6e293c7..3bf5779 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -317,10 +317,7 @@
if (pri >= ANDROID_PRIORITY_BACKGROUND) {
rc = SetTaskProfiles(tid, {"SCHED_SP_SYSTEM"}, true) ? 0 : -1;
} else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
- SchedPolicy policy = SP_FOREGROUND;
- // Change to the sched policy group of the process.
- get_sched_policy(getpid(), &policy);
- rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
+ rc = SetTaskProfiles(tid, {"SCHED_SP_FOREGROUND"}, true) ? 0 : -1;
}
if (rc) {
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index c4c58ee..42602e9 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -1283,8 +1283,7 @@
llkEnableSysrqT &= !llkLowRam;
if (debuggable) {
llkEnableSysrqT |= llkCheckEng(LLK_ENABLE_SYSRQ_T_PROPERTY);
- if (!LLK_ENABLE_DEFAULT) { // NB: default is currently true ...
- llkEnable |= llkCheckEng(LLK_ENABLE_PROPERTY);
+ if (!LLK_ENABLE_DEFAULT) {
khtEnable |= llkCheckEng(KHT_ENABLE_PROPERTY);
}
}
diff --git a/llkd/llkd-debuggable.rc b/llkd/llkd-debuggable.rc
index 4b11b1c..c075609 100644
--- a/llkd/llkd-debuggable.rc
+++ b/llkd/llkd-debuggable.rc
@@ -1,5 +1,5 @@
on property:ro.debuggable=1
- setprop llk.enable ${ro.llk.enable:-1}
+ setprop llk.enable ${ro.llk.enable:-0}
setprop khungtask.enable ${ro.khungtask.enable:-1}
on property:ro.llk.enable=eng
diff --git a/llkd/tests/llkd_test.cpp b/llkd/tests/llkd_test.cpp
index 475512c..8eb9b00 100644
--- a/llkd/tests/llkd_test.cpp
+++ b/llkd/tests/llkd_test.cpp
@@ -69,13 +69,9 @@
seconds llkdSleepPeriod(char state) {
auto default_eng = android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng";
auto default_enable = LLK_ENABLE_DEFAULT;
- if (!LLK_ENABLE_DEFAULT && default_eng &&
- android::base::GetBoolProperty("ro.debuggable", false)) {
- default_enable = true;
- }
default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
if (default_eng) {
- GTEST_LOG_INFO << LLK_ENABLE_PROPERTY " defaults to \"eng\" thus "
+ GTEST_LOG_INFO << LLK_ENABLE_PROPERTY " defaults to "
<< (default_enable ? "true" : "false") << "\n";
}
// Hail Mary hope is unconfigured.
@@ -108,10 +104,6 @@
rest();
}
default_enable = LLK_ENABLE_DEFAULT;
- if (!LLK_ENABLE_DEFAULT && (android::base::GetProperty(LLK_ENABLE_PROPERTY, "eng") == "eng") &&
- android::base::GetBoolProperty("ro.debuggable", false)) {
- default_enable = true;
- }
default_enable = android::base::GetBoolProperty(LLK_ENABLE_PROPERTY, default_enable);
if (default_enable) {
execute("start llkd-1");
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4515950..8a38559 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -78,8 +78,8 @@
mkdir /dev/boringssl 0755 root root
mkdir /dev/boringssl/selftest 0755 root root
- # Mount tracefs
- mount tracefs tracefs /sys/kernel/tracing
+ # Mount tracefs (with GID=AID_READTRACEFS)
+ mount tracefs tracefs /sys/kernel/tracing gid=3012
# create sys dirctory
mkdir /dev/sys 0755 system system
@@ -142,11 +142,21 @@
chown system system /dev/stune/background/tasks
chown system system /dev/stune/top-app/tasks
chown system system /dev/stune/rt/tasks
+ chown system system /dev/stune/cgroup.procs
+ chown system system /dev/stune/foreground/cgroup.procs
+ chown system system /dev/stune/background/cgroup.procs
+ chown system system /dev/stune/top-app/cgroup.procs
+ chown system system /dev/stune/rt/cgroup.procs
chmod 0664 /dev/stune/tasks
chmod 0664 /dev/stune/foreground/tasks
chmod 0664 /dev/stune/background/tasks
chmod 0664 /dev/stune/top-app/tasks
chmod 0664 /dev/stune/rt/tasks
+ chmod 0664 /dev/stune/cgroup.procs
+ chmod 0664 /dev/stune/foreground/cgroup.procs
+ chmod 0664 /dev/stune/background/cgroup.procs
+ chmod 0664 /dev/stune/top-app/cgroup.procs
+ chmod 0664 /dev/stune/rt/cgroup.procs
# cpuctl hierarchy for devices using utilclamp
mkdir /dev/cpuctl/foreground
@@ -155,6 +165,7 @@
mkdir /dev/cpuctl/rt
mkdir /dev/cpuctl/system
mkdir /dev/cpuctl/system-background
+ mkdir /dev/cpuctl/dex2oat
chown system system /dev/cpuctl
chown system system /dev/cpuctl/foreground
chown system system /dev/cpuctl/background
@@ -162,6 +173,7 @@
chown system system /dev/cpuctl/rt
chown system system /dev/cpuctl/system
chown system system /dev/cpuctl/system-background
+ chown system system /dev/cpuctl/dex2oat
chown system system /dev/cpuctl/tasks
chown system system /dev/cpuctl/foreground/tasks
chown system system /dev/cpuctl/background/tasks
@@ -169,6 +181,15 @@
chown system system /dev/cpuctl/rt/tasks
chown system system /dev/cpuctl/system/tasks
chown system system /dev/cpuctl/system-background/tasks
+ 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/background/cgroup.procs
+ chown system system /dev/cpuctl/top-app/cgroup.procs
+ chown system system /dev/cpuctl/rt/cgroup.procs
+ chown system system /dev/cpuctl/system/cgroup.procs
+ chown system system /dev/cpuctl/system-background/cgroup.procs
+ chown system system /dev/cpuctl/dex2oat/cgroup.procs
chmod 0664 /dev/cpuctl/tasks
chmod 0664 /dev/cpuctl/foreground/tasks
chmod 0664 /dev/cpuctl/background/tasks
@@ -176,12 +197,23 @@
chmod 0664 /dev/cpuctl/rt/tasks
chmod 0664 /dev/cpuctl/system/tasks
chmod 0664 /dev/cpuctl/system-background/tasks
+ chmod 0664 /dev/cpuctl/dex2oat/tasks
+ chmod 0664 /dev/cpuctl/cgroup.procs
+ chmod 0664 /dev/cpuctl/foreground/cgroup.procs
+ chmod 0664 /dev/cpuctl/background/cgroup.procs
+ chmod 0664 /dev/cpuctl/top-app/cgroup.procs
+ chmod 0664 /dev/cpuctl/rt/cgroup.procs
+ chmod 0664 /dev/cpuctl/system/cgroup.procs
+ chmod 0664 /dev/cpuctl/system-background/cgroup.procs
+ chmod 0664 /dev/cpuctl/dex2oat/cgroup.procs
# Create a cpu group for NNAPI HAL processes
mkdir /dev/cpuctl/nnapi-hal
chown system system /dev/cpuctl/nnapi-hal
chown system system /dev/cpuctl/nnapi-hal/tasks
+ chown system system /dev/cpuctl/nnapi-hal/cgroup.procs
chmod 0664 /dev/cpuctl/nnapi-hal/tasks
+ chmod 0664 /dev/cpuctl/nnapi-hal/cgroup.procs
write /dev/cpuctl/nnapi-hal/cpu.uclamp.min 1
write /dev/cpuctl/nnapi-hal/cpu.uclamp.latency_sensitive 1
@@ -189,19 +221,25 @@
mkdir /dev/cpuctl/camera-daemon
chown system system /dev/cpuctl/camera-daemon
chown system system /dev/cpuctl/camera-daemon/tasks
+ chown system system /dev/cpuctl/camera-daemon/cgroup.procs
chmod 0664 /dev/cpuctl/camera-daemon/tasks
+ chmod 0664 /dev/cpuctl/camera-daemon/cgroup.procs
# Create an stune group for camera-specific processes
mkdir /dev/stune/camera-daemon
chown system system /dev/stune/camera-daemon
chown system system /dev/stune/camera-daemon/tasks
+ chown system system /dev/stune/camera-daemon/cgroup.procs
chmod 0664 /dev/stune/camera-daemon/tasks
+ chmod 0664 /dev/stune/camera-daemon/cgroup.procs
# Create an stune group for NNAPI HAL processes
mkdir /dev/stune/nnapi-hal
chown system system /dev/stune/nnapi-hal
chown system system /dev/stune/nnapi-hal/tasks
+ chown system system /dev/stune/nnapi-hal/cgroup.procs
chmod 0664 /dev/stune/nnapi-hal/tasks
+ chmod 0664 /dev/stune/nnapi-hal/cgroup.procs
write /dev/stune/nnapi-hal/schedtune.boost 1
write /dev/stune/nnapi-hal/schedtune.prefer_idle 1
@@ -213,8 +251,12 @@
chown system system /dev/blkio/background
chown system system /dev/blkio/tasks
chown system system /dev/blkio/background/tasks
+ chown system system /dev/blkio/cgroup.procs
+ chown system system /dev/blkio/background/cgroup.procs
chmod 0664 /dev/blkio/tasks
chmod 0664 /dev/blkio/background/tasks
+ chmod 0664 /dev/blkio/cgroup.procs
+ chmod 0664 /dev/blkio/background/cgroup.procs
write /dev/blkio/blkio.weight 1000
write /dev/blkio/background/blkio.weight 200
write /dev/blkio/background/blkio.bfq.weight 10
@@ -363,6 +405,13 @@
chown system system /dev/cpuset/top-app/tasks
chown system system /dev/cpuset/restricted/tasks
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/background/cgroup.procs
+ chown system system /dev/cpuset/system-background/cgroup.procs
+ chown system system /dev/cpuset/top-app/cgroup.procs
+ chown system system /dev/cpuset/restricted/cgroup.procs
+ chown system system /dev/cpuset/camera-daemon/cgroup.procs
# set system-background to 0775 so SurfaceFlinger can touch it
chmod 0775 /dev/cpuset/system-background
@@ -374,6 +423,13 @@
chmod 0664 /dev/cpuset/restricted/tasks
chmod 0664 /dev/cpuset/tasks
chmod 0664 /dev/cpuset/camera-daemon/tasks
+ chmod 0664 /dev/cpuset/foreground/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
+ chmod 0664 /dev/cpuset/restricted/cgroup.procs
+ chmod 0664 /dev/cpuset/cgroup.procs
+ chmod 0664 /dev/cpuset/camera-daemon/cgroup.procs
# make the PSI monitor accessible to others
chown system system /proc/pressure/memory
diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp
index 38d8685..94f26d8 100644
--- a/trusty/storage/proxy/Android.bp
+++ b/trusty/storage/proxy/Android.bp
@@ -35,7 +35,10 @@
"liblog",
"libhardware_legacy",
],
- header_libs: ["libcutils_headers"],
+ header_libs: [
+ "libcutils_headers",
+ "libgsi_headers",
+ ],
static_libs: [
"libfstab",
diff --git a/trusty/storage/proxy/checkpoint_handling.cpp b/trusty/storage/proxy/checkpoint_handling.cpp
index 6c2fd36..3305d8d 100644
--- a/trusty/storage/proxy/checkpoint_handling.cpp
+++ b/trusty/storage/proxy/checkpoint_handling.cpp
@@ -18,9 +18,12 @@
#include "log.h"
#include <fstab/fstab.h>
+#include <unistd.h>
#include <cstring>
#include <string>
+#include <libgsi/libgsi.h>
+
namespace {
bool checkpointingDoneForever = false;
@@ -75,3 +78,15 @@
return 0;
}
+
+/**
+ * is_gsi_running() - Check if a GSI image is running via DSU.
+ *
+ * This function is equivalent to android::gsi::IsGsiRunning(), but this API is
+ * not yet vendor-accessible although the underlying metadata file is.
+ *
+ */
+bool is_gsi_running() {
+ /* TODO(b/210501710): Expose GSI image running state to vendor storageproxyd */
+ return !access(android::gsi::kGsiBootedIndicatorFile, F_OK);
+}
diff --git a/trusty/storage/proxy/checkpoint_handling.h b/trusty/storage/proxy/checkpoint_handling.h
index f1bf27c..dfe2947 100644
--- a/trusty/storage/proxy/checkpoint_handling.h
+++ b/trusty/storage/proxy/checkpoint_handling.h
@@ -32,6 +32,8 @@
*/
int is_data_checkpoint_active(bool* active);
+bool is_gsi_running();
+
#ifdef __cplusplus
}
#endif
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index c690a28..2620034 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -104,8 +104,11 @@
return -1;
}
- /* no-execute for user, no access for group and other */
- umask(S_IXUSR | S_IRWXG | S_IRWXO);
+ /*
+ * No access for group and other. We need execute access for user to create
+ * an accessible directory.
+ */
+ umask(S_IRWXG | S_IRWXO);
return 0;
}
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
index 2fde30f..d74a708 100644
--- a/trusty/storage/proxy/storage.c
+++ b/trusty/storage/proxy/storage.c
@@ -16,6 +16,7 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <libgen.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
@@ -24,13 +25,16 @@
#include <sys/types.h>
#include <unistd.h>
-#include "log.h"
+#include "checkpoint_handling.h"
#include "ipc.h"
+#include "log.h"
#include "storage.h"
#define FD_TBL_SIZE 64
#define MAX_READ_SIZE 4096
+#define ALTERNATE_DATA_DIR "alternate/"
+
enum sync_state {
SS_UNUSED = -1,
SS_CLEAN = 0,
@@ -44,6 +48,8 @@
static enum sync_state dir_state;
static enum sync_state fd_state[FD_TBL_SIZE];
+static bool alternate_mode;
+
static struct {
struct storage_file_read_resp hdr;
uint8_t data[MAX_READ_SIZE];
@@ -216,6 +222,7 @@
const void *r, size_t req_len)
{
char *path = NULL;
+ char* parent_path;
const struct storage_file_open_req *req = r;
struct storage_file_open_resp resp = {0};
@@ -234,6 +241,24 @@
goto err_response;
}
+ /*
+ * TODO(b/210501710): Expose GSI image running state to vendor
+ * storageproxyd. We want to control data file paths in vendor_init, but we
+ * don't have access to the necessary property there yet. When we have
+ * access to that property we can set the root data path read-only and only
+ * allow creation of files in alternate/. Checking paths here temporarily
+ * until that is fixed.
+ *
+ * We are just checking for "/" instead of "alternate/" because we still
+ * want to still allow access to "persist/" in alternate mode (for now, this
+ * may change in the future).
+ */
+ if (alternate_mode && !strchr(req->name, '/')) {
+ ALOGE("%s: Cannot open root data file \"%s\" in alternate mode\n", __func__, req->name);
+ msg->result = STORAGE_ERR_ACCESS;
+ goto err_response;
+ }
+
int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
if (rc < 0) {
ALOGE("%s: asprintf failed\n", __func__);
@@ -246,7 +271,23 @@
if (req->flags & STORAGE_FILE_OPEN_TRUNCATE)
open_flags |= O_TRUNC;
+ parent_path = dirname(path);
if (req->flags & STORAGE_FILE_OPEN_CREATE) {
+ /*
+ * Create the alternate parent dir if needed & allowed.
+ *
+ * TODO(b/210501710): Expose GSI image running state to vendor
+ * storageproxyd. This directory should be created by vendor_init, once
+ * it has access to the necessary bit of information.
+ */
+ if (strstr(req->name, ALTERNATE_DATA_DIR) == req->name) {
+ rc = mkdir(parent_path, S_IRWXU);
+ if (rc && errno != EEXIST) {
+ ALOGE("%s: Could not create parent directory \"%s\": %s\n", __func__, parent_path,
+ strerror(errno));
+ }
+ }
+
/* open or create */
if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
/* create exclusive */
@@ -467,6 +508,9 @@
int storage_init(const char *dirname)
{
+ /* If there is an active DSU image, use the alternate fs mode. */
+ alternate_mode = is_gsi_running();
+
fs_state = SS_CLEAN;
dir_state = SS_CLEAN;
for (uint i = 0; i < FD_TBL_SIZE; i++) {