Merge "libsnapshot: Add script to test snapshot updates" into main
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index feda3b4..d61939f 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -203,6 +203,19 @@
       ]
     },
     {
+      "Name": "RealTimeInputScheduling",
+      "Actions": [
+        {
+          "Name": "SetSchedulerPolicy",
+          "Params":
+          {
+            "Policy": "SCHED_FIFO",
+            "Priority": "98"
+          }
+        }
+      ]
+    },
+    {
       "Name": "CameraServicePerformance",
       "Actions": [
         {
@@ -704,7 +717,7 @@
     },
     {
       "Name": "InputPolicy",
-      "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ]
+      "Profiles": [ "RealTimeInputScheduling", "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ]
     }
   ]
 }
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index c96feb3..dc6c8c0 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -20,6 +20,7 @@
 #include <task_profiles.h>
 
 #include <map>
+#include <optional>
 #include <string>
 
 #include <dirent.h>
@@ -54,6 +55,7 @@
 
 static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE =
         "/etc/task_profiles/task_profiles_%u.json";
+namespace {
 
 class FdCacheHelper {
   public:
@@ -64,8 +66,11 @@
     };
 
     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:
@@ -116,6 +121,17 @@
     return path.find("<uid>", 0) != std::string::npos || path.find("<pid>", 0) != std::string::npos;
 }
 
+std::optional<long> readLong(const std::string& str) {
+    char* end;
+    const long result = strtol(str.c_str(), &end, 10);
+    if (end > str.c_str()) {
+        return result;
+    }
+    return std::nullopt;
+}
+
+}  // namespace
+
 IProfileAttribute::~IProfileAttribute() = default;
 
 const std::string& ProfileAttribute::file_name() const {
@@ -913,15 +929,12 @@
                     LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found";
                 }
             } else if (action_name == "SetTimerSlack") {
-                std::string slack_value = params_val["Slack"].asString();
-                char* end;
-                unsigned long slack;
-
-                slack = strtoul(slack_value.c_str(), &end, 10);
-                if (end > slack_value.c_str()) {
-                    profile->Add(std::make_unique<SetTimerSlackAction>(slack));
+                const std::string slack_string = params_val["Slack"].asString();
+                std::optional<long> slack = readLong(slack_string);
+                if (slack && *slack >= 0) {
+                    profile->Add(std::make_unique<SetTimerSlackAction>(*slack));
                 } else {
-                    LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_value;
+                    LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_string;
                 }
             } else if (action_name == "SetAttribute") {
                 std::string attr_name = params_val["Name"].asString();
@@ -980,15 +993,19 @@
                         // 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 std::string nice_string = params_val["Nice"].asString();
+                        const std::optional<int> nice = readLong(nice_string);
 
+                        if (!nice) {
+                            LOG(FATAL) << "Invalid nice value specified: " << nice_string;
+                        }
                         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
+                        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));
+                        profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy, *nice));
                     } else {
                         profile->Add(std::make_unique<SetSchedulerPolicyAction>(policy));
                     }
@@ -1001,11 +1018,18 @@
                     // 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));
+                    const std::string priority_string = params_val["Priority"].asString();
+                    std::optional<long> virtual_priority = readLong(priority_string);
+                    if (virtual_priority && *virtual_priority > 0) {
+                        int priority;
+                        if (SetSchedulerPolicyAction::toPriority(policy, *virtual_priority,
+                                                                 priority)) {
+                            profile->Add(
+                                    std::make_unique<SetSchedulerPolicyAction>(policy, priority));
+                        }
+                    } else {
+                        LOG(WARNING) << "Invalid priority value: " << priority_string;
                     }
                 }
             } else {
diff --git a/mkbootfs/mkbootfs.cpp b/mkbootfs/mkbootfs.cpp
index 65cf497..a45c6a2 100644
--- a/mkbootfs/mkbootfs.cpp
+++ b/mkbootfs/mkbootfs.cpp
@@ -19,6 +19,9 @@
 #include <private/android_filesystem_config.h>
 #include <private/fs_config.h>
 
+#include <android-base/file.h>
+#include <string>
+
 /* NOTES
 **
 ** - see https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt
@@ -212,20 +215,12 @@
     if(lstat(in, &s)) err(1, "could not stat '%s'", in);
 
     if(S_ISREG(s.st_mode)){
-        int fd = open(in, O_RDONLY);
-        if(fd < 0) err(1, "cannot open '%s' for read", in);
-
-        char* tmp = (char*) malloc(s.st_size);
-        if(tmp == 0) errx(1, "cannot allocate %zd bytes", s.st_size);
-
-        if(read(fd, tmp, s.st_size) != s.st_size) {
-            err(1, "cannot read %zd bytes", s.st_size);
+        std::string content;
+        if (!android::base::ReadFileToString(in, &content)) {
+            err(1, "cannot read '%s'", in);
         }
 
-        _eject(&s, out, olen, tmp, s.st_size);
-
-        free(tmp);
-        close(fd);
+        _eject(&s, out, olen, content.data(), content.size());
     } else if(S_ISDIR(s.st_mode)) {
         _eject(&s, out, olen, 0, 0);
         _archive_dir(in, out, ilen, olen);