libprocessgroup/tools: Add settaskprofile command-line tool

Add a command-line tool to apply task profile(s) to a given thread.

Test: taskprofile $pid ProcessCapacityHigh; grep cpuset /proc/$pid/cgroup
Test: taskprofile $pid ProcessCapacityNormal; grep cpuset /proc/$pid/cgroup
Bug: 204808810
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Change-Id: I1c13731f7a9a1161f36e27436ee104964aacbfd0
diff --git a/libprocessgroup/tools/Android.bp b/libprocessgroup/tools/Android.bp
new file mode 100644
index 0000000..91418e1
--- /dev/null
+++ b/libprocessgroup/tools/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "settaskprofile",
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+
+    srcs: ["settaskprofile.cpp"],
+    shared_libs: [
+        "libprocessgroup",
+    ],
+}
diff --git a/libprocessgroup/tools/settaskprofile.cpp b/libprocessgroup/tools/settaskprofile.cpp
new file mode 100644
index 0000000..f83944a
--- /dev/null
+++ b/libprocessgroup/tools/settaskprofile.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+
+#include <iostream>
+
+#include <processgroup/processgroup.h>
+
+[[noreturn]] static void usage(int exit_status) {
+    std::cerr << "Usage: " << getprogname() << " <tid> <profile> [... profileN]" << std::endl
+              << "    tid      Thread ID to apply the profiles to." << std::endl
+              << "    profile  Name of the profile to apply." << std::endl
+              << "Applies listed profiles to the thread with specified ID." << std::endl
+              << "Profiles are applied in the order specified in the command line." << std::endl
+              << "If applying a profile fails, remaining profiles are ignored." << std::endl;
+    exit(exit_status);
+}
+
+int main(int argc, char* argv[]) {
+    if (argc < 3) {
+        usage(EXIT_FAILURE);
+    }
+
+    int tid = atoi(argv[1]);
+    if (tid == 0) {
+        std::cerr << "Invalid thread id" << std::endl;
+        exit(EXIT_FAILURE);
+    }
+
+    for (int i = 2; i < argc; i++) {
+        if (!SetTaskProfiles(tid, {argv[i]})) {
+            std::cerr << "Failed to apply " << argv[i] << " profile" << std::endl;
+            exit(EXIT_FAILURE);
+        }
+        std::cout << "Profile " << argv[i] << " is applied successfully!" << std::endl;
+    }
+
+    return 0;
+}