Merge "Add proposed trendy teams for VTS modules" into main
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..c77a803
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,5 @@
+dirgroup {
+ name: "trusty_dirgroup_system_core",
+ dirs: ["."],
+ visibility: ["//trusty/vendor/google/aosp/scripts"],
+}
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index c9235ee..15e8319 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -470,14 +470,12 @@
}
NativeBridgeGuestStateHeader header;
- if (!process_memory->ReadFully(header_ptr, &header, sizeof(NativeBridgeGuestStateHeader))) {
- PLOG(ERROR) << "failed to get the guest state header for thread " << tid;
- return false;
- }
- if (header.signature != NATIVE_BRIDGE_GUEST_STATE_SIGNATURE) {
+ if (!process_memory->ReadFully(header_ptr, &header, sizeof(NativeBridgeGuestStateHeader)) ||
+ header.signature != NATIVE_BRIDGE_GUEST_STATE_SIGNATURE) {
// Return when ptr points to unmapped memory or no valid guest state.
return false;
}
+
auto guest_state_data_copy = std::make_unique<unsigned char[]>(header.guest_state_data_size);
if (!process_memory->ReadFully(reinterpret_cast<uintptr_t>(header.guest_state_data),
guest_state_data_copy.get(), header.guest_state_data_size)) {
diff --git a/fs_mgr/liblp/super_layout_builder.cpp b/fs_mgr/liblp/super_layout_builder.cpp
index fd7416b..bff26ea 100644
--- a/fs_mgr/liblp/super_layout_builder.cpp
+++ b/fs_mgr/liblp/super_layout_builder.cpp
@@ -184,7 +184,7 @@
return {};
}
- size_t size = e.num_sectors * LP_SECTOR_SIZE;
+ uint64_t size = e.num_sectors * LP_SECTOR_SIZE;
uint64_t super_offset = e.target_data * LP_SECTOR_SIZE;
extents.emplace_back(super_offset, size, image_name, image_offset);
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 8ff41db..de20526 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -442,6 +442,7 @@
FRIEND_TEST(SnapshotUpdateTest, QueryStatusError);
FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow);
FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate);
+ FRIEND_TEST(SnapshotUpdateTest, InterruptMergeDuringPhaseUpdate);
FRIEND_TEST(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch);
friend class SnapshotTest;
friend class SnapshotUpdateTest;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 05dec68..acabd67 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1343,10 +1343,25 @@
}
if (merge_status == "snapshot" &&
- DecideMergePhase(snapshot_status) == MergePhase::SECOND_PHASE &&
- update_status.merge_phase() == MergePhase::FIRST_PHASE) {
- // The snapshot is not being merged because it's in the wrong phase.
- return MergeResult(UpdateState::None);
+ DecideMergePhase(snapshot_status) == MergePhase::SECOND_PHASE) {
+ if (update_status.merge_phase() == MergePhase::FIRST_PHASE) {
+ // The snapshot is not being merged because it's in the wrong phase.
+ return MergeResult(UpdateState::None);
+ } else {
+ // update_status is already in second phase but the
+ // snapshot_status is still not set to SnapshotState::MERGING.
+ //
+ // Resume the merge at this point. see b/374225913
+ LOG(INFO) << "SwitchSnapshotToMerge: " << name << " after resuming merge";
+ auto code = SwitchSnapshotToMerge(lock, name);
+ if (code != MergeFailureCode::Ok) {
+ LOG(ERROR) << "Failed to switch snapshot: " << name
+ << " to merge during second phase";
+ return MergeResult(UpdateState::MergeFailed,
+ MergeFailureCode::UnknownTargetType);
+ }
+ return MergeResult(UpdateState::Merging);
+ }
}
if (merge_status == "snapshot-merge") {
@@ -1442,8 +1457,14 @@
return MergeFailureCode::WriteStatus;
}
+ auto current_slot_suffix = device_->GetSlotSuffix();
MergeFailureCode result = MergeFailureCode::Ok;
for (const auto& snapshot : snapshots) {
+ if (!android::base::EndsWith(snapshot, current_slot_suffix)) {
+ LOG(ERROR) << "Skipping invalid snapshot: " << snapshot
+ << " during MergeSecondPhaseSnapshots";
+ continue;
+ }
SnapshotStatus snapshot_status;
if (!ReadSnapshotStatus(lock, snapshot, &snapshot_status)) {
return MergeFailureCode::ReadStatus;
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 46c3a35..3e5ae2a 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1607,6 +1607,146 @@
}
}
+// Test that shrinking and growing partitions at the same time is handled
+// correctly in VABC.
+TEST_F(SnapshotUpdateTest, InterruptMergeDuringPhaseUpdate) {
+ if (!snapuserd_required_) {
+ // b/179111359
+ GTEST_SKIP() << "Skipping snapuserd 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_));
+
+ // Check that the old partition sizes were saved correctly.
+ {
+ ASSERT_TRUE(AcquireLock());
+ auto local_lock = std::move(lock_);
+
+ SnapshotStatus status;
+ ASSERT_TRUE(sm->ReadSnapshotStatus(local_lock.get(), "prd_b", &status));
+ ASSERT_EQ(status.old_partition_size(), 3145728);
+ ASSERT_TRUE(sm->ReadSnapshotStatus(local_lock.get(), "sys_b", &status));
+ ASSERT_EQ(status.old_partition_size(), 3145728);
+ }
+
+ ASSERT_TRUE(WriteSnapshotAndHash(sys_));
+ ASSERT_TRUE(WriteSnapshotAndHash(vnd_));
+ 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));
+ }
+
+ // Initiate the merge and wait for it to be completed.
+ if (ShouldSkipLegacyMerging()) {
+ LOG(INFO) << "Skipping legacy merge in test";
+ return;
+ }
+ ASSERT_TRUE(init->InitiateMerge());
+ ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_);
+ {
+ // 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);
+ }
+
+ // Wait until prd_b merge is completed which is part of first phase
+ std::chrono::milliseconds timeout(6000);
+ auto start = std::chrono::steady_clock::now();
+ // Keep polling until the merge is complete or timeout is reached
+ while (true) {
+ // Query the merge status
+ const auto merge_status = init->snapuserd_client()->QuerySnapshotStatus("prd_b");
+ if (merge_status == "snapshot-merge-complete") {
+ break;
+ }
+
+ auto now = std::chrono::steady_clock::now();
+ auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
+
+ ASSERT_TRUE(elapsed < timeout);
+ // sleep for a second and allow merge to complete
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+ }
+
+ // Now, forcefully update the snapshot-update status to SECOND PHASE
+ // This will not update the snapshot status of sys_b to MERGING
+ if (init->UpdateUsesUserSnapshots()) {
+ ASSERT_TRUE(AcquireLock());
+ auto local_lock = std::move(lock_);
+ auto status = init->ReadSnapshotUpdateStatus(local_lock.get());
+ status.set_merge_phase(MergePhase::SECOND_PHASE);
+ ASSERT_TRUE(init->WriteSnapshotUpdateStatus(local_lock.get(), status));
+ }
+
+ // Simulate shutting down the device and creating partitions again.
+ ASSERT_TRUE(UnmapAll());
+ ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_));
+
+ DeviceMapper::TargetInfo target;
+ ASSERT_TRUE(init->IsSnapshotDevice("prd_b", &target));
+
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
+ ASSERT_TRUE(init->IsSnapshotDevice("sys_b", &target));
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
+ ASSERT_TRUE(init->IsSnapshotDevice("vnd_b", &target));
+ ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user");
+
+ // Complete the merge; "sys" and "vnd" should resume the merge
+ // even though merge was interrupted after update_status was updated to
+ // SECOND_PHASE
+ ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState());
+
+ // Make sure the second phase ran and deleted snapshots.
+ {
+ ASSERT_TRUE(AcquireLock());
+ auto local_lock = std::move(lock_);
+ std::vector<std::string> snapshots;
+ ASSERT_TRUE(init->ListSnapshots(local_lock.get(), &snapshots));
+ ASSERT_TRUE(snapshots.empty());
+ }
+
+ // 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/init/Android.bp b/init/Android.bp
index 18a79d6..5e06000 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -390,6 +390,7 @@
"libsnapshot_init",
"update_metadata-protos",
"libprocinfo",
+ "libbootloader_message",
],
static_executable: true,
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 99bf0de..4f1af30 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -32,9 +32,12 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android/avf_cc_flags.h>
+#include <bootloader_message/bootloader_message.h>
+#include <cutils/android_reboot.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
@@ -46,6 +49,7 @@
#include "block_dev_initializer.h"
#include "devices.h"
+#include "reboot_utils.h"
#include "result.h"
#include "snapuserd_transition.h"
#include "switch_root.h"
@@ -111,6 +115,8 @@
bool GetDmVerityDevices(std::set<std::string>* devices);
bool SetUpDmVerity(FstabEntry* fstab_entry);
+ void RequestTradeInModeWipeIfNeeded();
+
bool InitAvbHandle();
bool need_dm_verity_;
@@ -263,6 +269,8 @@
}
bool FirstStageMountVBootV2::DoFirstStageMount() {
+ RequestTradeInModeWipeIfNeeded();
+
if (!IsDmLinearEnabled() && fstab_.empty()) {
// Nothing to mount.
LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
@@ -878,6 +886,55 @@
return true;
}
+void FirstStageMountVBootV2::RequestTradeInModeWipeIfNeeded() {
+ static constexpr const char* kWipeIndicator = "/metadata/tradeinmode/wipe";
+ static constexpr size_t kWipeAttempts = 3;
+
+ if (access(kWipeIndicator, R_OK) == -1) {
+ return;
+ }
+
+ // Write a counter to the wipe indicator, to try and prevent boot loops if
+ // recovery fails to wipe data.
+ uint32_t counter = 0;
+ std::string contents;
+ if (ReadFileToString(kWipeIndicator, &contents)) {
+ android::base::ParseUint(contents, &counter);
+ contents = std::to_string(++counter);
+ if (android::base::WriteStringToFile(contents, kWipeIndicator)) {
+ sync();
+ } else {
+ PLOG(ERROR) << "Failed to update " << kWipeIndicator;
+ }
+ } else {
+ PLOG(ERROR) << "Failed to read " << kWipeIndicator;
+ }
+
+ std::string err;
+ auto misc_device = get_misc_blk_device(&err);
+ if (misc_device.empty()) {
+ LOG(FATAL) << "Could not find misc device: " << err;
+ }
+
+ auto misc_name = android::base::Basename(misc_device);
+ if (!block_dev_init_.InitDevices({misc_name})) {
+ LOG(FATAL) << "Could not find misc device: " << misc_device;
+ }
+
+ // If we've failed to wipe three times, don't include the wipe command. This
+ // will force us to boot into the recovery menu instead where a manual wipe
+ // can be attempted.
+ std::vector<std::string> options;
+ if (counter <= kWipeAttempts) {
+ options.emplace_back("--wipe_data");
+ options.emplace_back("--reason=tradeinmode");
+ }
+ if (!write_bootloader_message(options, &err)) {
+ LOG(FATAL) << "Could not issue wipe: " << err;
+ }
+ RebootSystem(ANDROID_RB_RESTART2, "recovery", "reboot,tradeinmode,wipe");
+}
+
void SetInitAvbVersionInRecovery() {
if (!IsRecoveryMode()) {
LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
diff --git a/libprocessgroup/OWNERS b/libprocessgroup/OWNERS
index d5aa721..accd7df 100644
--- a/libprocessgroup/OWNERS
+++ b/libprocessgroup/OWNERS
@@ -1,4 +1,3 @@
# Bug component: 1293033
surenb@google.com
-tjmercier@google.com
-carlosgalo@google.com
+tjmercier@google.com
\ No newline at end of file
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 411c38c..feda3b4 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -572,33 +572,6 @@
},
{
- "Name": "PerfBoost",
- "Actions": [
- {
- "Name": "SetClamps",
- "Params":
- {
- "Boost": "50%",
- "Clamp": "0"
- }
- }
- ]
- },
- {
- "Name": "PerfClamp",
- "Actions": [
- {
- "Name": "SetClamps",
- "Params":
- {
- "Boost": "0",
- "Clamp": "30%"
- }
- }
- ]
- },
-
- {
"Name": "LowMemoryUsage",
"Actions": [
{
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 7f33d4a..cc675b3 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -17,11 +17,16 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "libprocessgroup"
+#include <task_profiles.h>
+
+#include <map>
+#include <string>
+
#include <dirent.h>
#include <fcntl.h>
+#include <sched.h>
+#include <sys/resource.h>
#include <unistd.h>
-#include <task_profiles.h>
-#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -30,13 +35,13 @@
#include <android-base/strings.h>
#include <android-base/threads.h>
+#include <build_flags.h>
+
#include <cutils/android_filesystem_config.h>
#include <json/reader.h>
#include <json/value.h>
-#include <build_flags.h>
-
using android::base::GetThreadId;
using android::base::GetUintProperty;
using android::base::StringPrintf;
@@ -183,18 +188,6 @@
return true;
}
-bool SetClampsAction::ExecuteForProcess(uid_t, pid_t) const {
- // TODO: add support when kernel supports util_clamp
- LOG(WARNING) << "SetClampsAction::ExecuteForProcess is not supported";
- return false;
-}
-
-bool SetClampsAction::ExecuteForTask(int) const {
- // TODO: add support when kernel supports util_clamp
- LOG(WARNING) << "SetClampsAction::ExecuteForTask is not supported";
- return false;
-}
-
// To avoid issues in sdk_mac build
#if defined(__ANDROID__)
@@ -649,6 +642,57 @@
return access(task_path_.c_str(), W_OK) == 0;
}
+bool SetSchedulerPolicyAction::isNormalPolicy(int policy) {
+ return policy == SCHED_OTHER || policy == SCHED_BATCH || policy == SCHED_IDLE;
+}
+
+bool SetSchedulerPolicyAction::toPriority(int policy, int virtual_priority, int& priority_out) {
+ constexpr int VIRTUAL_PRIORITY_MIN = 1;
+ constexpr int VIRTUAL_PRIORITY_MAX = 99;
+
+ if (virtual_priority < VIRTUAL_PRIORITY_MIN || virtual_priority > VIRTUAL_PRIORITY_MAX) {
+ LOG(WARNING) << "SetSchedulerPolicy: invalid priority (" << virtual_priority
+ << ") for policy (" << policy << ")";
+ return false;
+ }
+
+ const int min = sched_get_priority_min(policy);
+ if (min == -1) {
+ PLOG(ERROR) << "SetSchedulerPolicy: Cannot get min sched priority for policy " << policy;
+ return false;
+ }
+
+ const int max = sched_get_priority_max(policy);
+ if (max == -1) {
+ PLOG(ERROR) << "SetSchedulerPolicy: Cannot get max sched priority for policy " << policy;
+ return false;
+ }
+
+ priority_out = min + (virtual_priority - VIRTUAL_PRIORITY_MIN) * (max - min) /
+ (VIRTUAL_PRIORITY_MAX - VIRTUAL_PRIORITY_MIN);
+
+ return true;
+}
+
+bool SetSchedulerPolicyAction::ExecuteForTask(pid_t tid) const {
+ struct sched_param param = {};
+ param.sched_priority = isNormalPolicy(policy_) ? 0 : *priority_or_nice_;
+ if (sched_setscheduler(tid, policy_, ¶m) == -1) {
+ PLOG(WARNING) << "SetSchedulerPolicy: Failed to apply scheduler policy (" << policy_
+ << ") with priority (" << *priority_or_nice_ << ") to tid " << tid;
+ return false;
+ }
+
+ if (isNormalPolicy(policy_) && priority_or_nice_ &&
+ setpriority(PRIO_PROCESS, tid, *priority_or_nice_) == -1) {
+ PLOG(WARNING) << "SetSchedulerPolicy: Failed to apply nice (" << *priority_or_nice_
+ << ") to tid " << tid;
+ return false;
+ }
+
+ return true;
+}
+
bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
for (const auto& profile : profiles_) {
profile->ExecuteForProcess(uid, pid);
@@ -902,23 +946,6 @@
} else {
LOG(WARNING) << "SetAttribute: unknown attribute: " << attr_name;
}
- } else if (action_name == "SetClamps") {
- std::string boost_value = params_val["Boost"].asString();
- std::string clamp_value = params_val["Clamp"].asString();
- char* end;
- unsigned long boost;
-
- boost = strtoul(boost_value.c_str(), &end, 10);
- if (end > boost_value.c_str()) {
- unsigned long clamp = strtoul(clamp_value.c_str(), &end, 10);
- if (end > clamp_value.c_str()) {
- profile->Add(std::make_unique<SetClampsAction>(boost, clamp));
- } else {
- LOG(WARNING) << "SetClamps: invalid parameter " << clamp_value;
- }
- } else {
- LOG(WARNING) << "SetClamps: invalid parameter: " << boost_value;
- }
} else if (action_name == "WriteFile") {
std::string attr_filepath = params_val["FilePath"].asString();
std::string attr_procfilepath = params_val["ProcFilePath"].asString();
@@ -936,6 +963,62 @@
LOG(WARNING) << "WriteFile: invalid parameter: "
<< "empty value";
}
+ } else if (action_name == "SetSchedulerPolicy") {
+ const std::map<std::string, int> POLICY_MAP = {
+ {"SCHED_OTHER", SCHED_OTHER},
+ {"SCHED_BATCH", SCHED_BATCH},
+ {"SCHED_IDLE", SCHED_IDLE},
+ {"SCHED_FIFO", SCHED_FIFO},
+ {"SCHED_RR", SCHED_RR},
+ };
+ const std::string policy_str = params_val["Policy"].asString();
+
+ const auto it = POLICY_MAP.find(policy_str);
+ if (it == POLICY_MAP.end()) {
+ LOG(WARNING) << "SetSchedulerPolicy: invalid policy " << policy_str;
+ continue;
+ }
+
+ const int policy = it->second;
+
+ if (SetSchedulerPolicyAction::isNormalPolicy(policy)) {
+ if (params_val.isMember("Priority")) {
+ LOG(WARNING) << "SetSchedulerPolicy: Normal policies (" << policy_str
+ << ") use Nice values, not Priority values";
+ }
+
+ if (params_val.isMember("Nice")) {
+ // If present, this optional value will be passed in an additional syscall
+ // to setpriority(), since the sched_priority value must be 0 for calls to
+ // sched_setscheduler() with "normal" policies.
+ const int nice = params_val["Nice"].asInt();
+
+ const int LINUX_MIN_NICE = -20;
+ const int LINUX_MAX_NICE = 19;
+ if (nice < LINUX_MIN_NICE || nice > LINUX_MAX_NICE) {
+ LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << nice
+ << ") appears out of range.";
+ }
+ profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy, nice));
+ } else {
+ profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy));
+ }
+ } else {
+ if (params_val.isMember("Nice")) {
+ LOG(WARNING) << "SetSchedulerPolicy: Real-time policies (" << policy_str
+ << ") use Priority values, not Nice values";
+ }
+
+ // This is a "virtual priority" as described by `man 2 sched_get_priority_min`
+ // that will be mapped onto the following range for the provided policy:
+ // [sched_get_priority_min(), sched_get_priority_max()]
+ const int virtual_priority = params_val["Priority"].asInt();
+
+ int priority;
+ if (SetSchedulerPolicyAction::toPriority(policy, virtual_priority, priority)) {
+ profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy, priority));
+ }
+ }
} else {
LOG(WARNING) << "Unknown profile action: " << action_name;
}
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index e52ce38..d0b5043 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -21,6 +21,7 @@
#include <map>
#include <memory>
#include <mutex>
+#include <optional>
#include <span>
#include <string>
#include <string_view>
@@ -90,19 +91,6 @@
};
// Profile actions
-class SetClampsAction : public ProfileAction {
- public:
- SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {}
-
- const char* Name() const override { return "SetClamps"; }
- bool ExecuteForProcess(uid_t uid, pid_t pid) const override;
- bool ExecuteForTask(pid_t tid) const override;
-
- protected:
- int boost_;
- int clamp_;
-};
-
class SetTimerSlackAction : public ProfileAction {
public:
SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {}
@@ -187,6 +175,25 @@
CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const;
};
+// Set scheduler policy action
+class SetSchedulerPolicyAction : public ProfileAction {
+ public:
+ SetSchedulerPolicyAction(int policy)
+ : policy_(policy) {}
+ SetSchedulerPolicyAction(int policy, int priority_or_nice)
+ : policy_(policy), priority_or_nice_(priority_or_nice) {}
+
+ const char* Name() const override { return "SetSchedulerPolicy"; }
+ bool ExecuteForTask(pid_t tid) const override;
+
+ static bool isNormalPolicy(int policy);
+ static bool toPriority(int policy, int virtual_priority, int& priority_out);
+
+ private:
+ int policy_;
+ std::optional<int> priority_or_nice_;
+};
+
class TaskProfile {
public:
TaskProfile(const std::string& name) : name_(name), res_cached_(false) {}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 3e1d481..12d9c43 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -595,6 +595,7 @@
mkdir /metadata/ota 0750 root system
mkdir /metadata/ota/snapshots 0750 root system
mkdir /metadata/watchdog 0770 root system
+ mkdir /metadata/tradeinmode 0770 root system
mkdir /metadata/apex 0700 root system
mkdir /metadata/apex/sessions 0700 root system
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index d5893de..1f5c179 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -58,6 +58,7 @@
"toolbox_vendor",
"toybox_vendor",
],
+ vendor: true,
}
// shell and utilities for first stage console. The list of binaries are