Merge "logd: strip out empty trailing iovec"
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 2d6c7f5..024bc3d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -161,6 +161,7 @@
     target: {
         android: {
             srcs: [
+                "client/debuggerd_client_test.cpp",
                 "debuggerd_test.cpp",
                 "util.cpp"
             ],
@@ -171,6 +172,7 @@
         "libbacktrace",
         "libbase",
         "libcutils",
+        "libdebuggerd_client",
     ],
 
     static_libs: [
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index f2975d1..b9fb512 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -19,12 +19,14 @@
 #include <fcntl.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/poll.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include <chrono>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
@@ -33,6 +35,8 @@
 #include <debuggerd/protocol.h>
 #include <debuggerd/util.h>
 
+using namespace std::chrono_literals;
+
 using android::base::unique_fd;
 
 static bool send_signal(pid_t pid, bool backtrace) {
@@ -45,28 +49,31 @@
   return true;
 }
 
+template <typename Duration>
+static void populate_timeval(struct timeval* tv, const Duration& duration) {
+  auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
+  auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(duration - seconds);
+  tv->tv_sec = static_cast<long>(seconds.count());
+  tv->tv_usec = static_cast<long>(microseconds.count());
+}
+
 bool debuggerd_trigger_dump(pid_t pid, unique_fd output_fd, DebuggerdDumpType dump_type,
                             int timeout_ms) {
   LOG(INFO) << "libdebuggerd_client: started dumping process " << pid;
   unique_fd sockfd;
   const auto end = std::chrono::steady_clock::now() + std::chrono::milliseconds(timeout_ms);
-  auto set_timeout = [timeout_ms, &sockfd, &end]() {
+  auto time_left = [timeout_ms, &end]() { return end - std::chrono::steady_clock::now(); };
+  auto set_timeout = [timeout_ms, &time_left](int sockfd) {
     if (timeout_ms <= 0) {
       return true;
     }
 
-    auto now = std::chrono::steady_clock::now();
-    if (now > end) {
+    auto remaining = time_left();
+    if (remaining < decltype(remaining)::zero()) {
       return false;
     }
-
-    auto time_left = std::chrono::duration_cast<std::chrono::microseconds>(end - now);
-    auto seconds = std::chrono::duration_cast<std::chrono::seconds>(time_left);
-    auto microseconds = std::chrono::duration_cast<std::chrono::microseconds>(time_left - seconds);
-    struct timeval timeout = {
-      .tv_sec = static_cast<long>(seconds.count()),
-      .tv_usec = static_cast<long>(microseconds.count()),
-    };
+    struct timeval timeout;
+    populate_timeval(&timeout, remaining);
 
     if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) != 0) {
       return false;
@@ -84,7 +91,7 @@
     return false;
   }
 
-  if (!set_timeout()) {
+  if (!set_timeout(sockfd)) {
     PLOG(ERROR) << "libdebugger_client: failed to set timeout";
     return false;
   }
@@ -96,11 +103,19 @@
   }
 
   InterceptRequest req = {.pid = pid };
-  if (!set_timeout()) {
+  if (!set_timeout(sockfd)) {
     PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+    return false;
   }
 
-  if (send_fd(sockfd.get(), &req, sizeof(req), std::move(output_fd)) != sizeof(req)) {
+  // Create an intermediate pipe to pass to the other end.
+  unique_fd pipe_read, pipe_write;
+  if (!Pipe(&pipe_read, &pipe_write)) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to create pipe";
+    return false;
+  }
+
+  if (send_fd(sockfd.get(), &req, sizeof(req), std::move(pipe_write)) != sizeof(req)) {
     PLOG(ERROR) << "libdebuggerd_client: failed to send output fd to tombstoned";
     return false;
   }
@@ -108,8 +123,9 @@
   bool backtrace = dump_type == kDebuggerdBacktrace;
   send_signal(pid, backtrace);
 
-  if (!set_timeout()) {
-    PLOG(ERROR) << "libdebugger_client: failed to set timeout";
+  if (!set_timeout(sockfd)) {
+    PLOG(ERROR) << "libdebuggerd_client: failed to set timeout";
+    return false;
   }
 
   InterceptResponse response;
@@ -127,6 +143,48 @@
   if (response.success != 1) {
     response.error_message[sizeof(response.error_message) - 1] = '\0';
     LOG(ERROR) << "libdebuggerd_client: tombstoned reported failure: " << response.error_message;
+    return false;
+  }
+
+  // Forward output from the pipe to the output fd.
+  while (true) {
+    auto remaining_ms = std::chrono::duration_cast<std::chrono::milliseconds>(time_left());
+    if (remaining_ms <= 1ms) {
+      LOG(ERROR) << "libdebuggerd_client: timeout expired";
+      return false;
+    }
+
+    struct pollfd pfd = {
+        .fd = pipe_read.get(), .events = POLLIN, .revents = 0,
+    };
+
+    rc = poll(&pfd, 1, remaining_ms.count());
+    if (rc == -1) {
+      if (errno == EINTR) {
+        continue;
+      } else {
+        PLOG(ERROR) << "libdebuggerd_client: error while polling";
+        return false;
+      }
+    } else if (rc == 0) {
+      LOG(ERROR) << "libdebuggerd_client: timeout expired";
+      return false;
+    }
+
+    char buf[1024];
+    rc = TEMP_FAILURE_RETRY(read(pipe_read.get(), buf, sizeof(buf)));
+    if (rc == 0) {
+      // Done.
+      break;
+    } else if (rc == -1) {
+      PLOG(ERROR) << "libdebuggerd_client: error while reading";
+      return false;
+    }
+
+    if (!android::base::WriteFully(output_fd.get(), buf, rc)) {
+      PLOG(ERROR) << "libdebuggerd_client: error while writing";
+      return false;
+    }
   }
 
   LOG(INFO) << "libdebuggerd_client: done dumping process " << pid;
diff --git a/debuggerd/client/debuggerd_client_test.cpp b/debuggerd/client/debuggerd_client_test.cpp
new file mode 100644
index 0000000..86d0314
--- /dev/null
+++ b/debuggerd/client/debuggerd_client_test.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017, 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 <debuggerd/client.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+
+#include <debuggerd/util.h>
+
+using namespace std::chrono_literals;
+using android::base::unique_fd;
+
+TEST(debuggerd_client, race) {
+  static constexpr int THREAD_COUNT = 1024;
+  pid_t forkpid = fork();
+
+  ASSERT_NE(-1, forkpid);
+
+  if (forkpid == 0) {
+    // Spawn a bunch of threads, to make crash_dump take longer.
+    std::vector<std::thread> threads;
+    for (int i = 0; i < THREAD_COUNT; ++i) {
+      threads.emplace_back([]() {
+        while (true) {
+          std::this_thread::sleep_for(60s);
+        }
+      });
+    }
+
+    std::this_thread::sleep_for(60s);
+    exit(0);
+  }
+
+  unique_fd pipe_read, pipe_write;
+  ASSERT_TRUE(Pipe(&pipe_read, &pipe_write));
+
+  // 64 kB should be enough for everyone.
+  constexpr int PIPE_SIZE = 64 * 1024 * 1024;
+  ASSERT_EQ(PIPE_SIZE, fcntl(pipe_read.get(), F_SETPIPE_SZ, PIPE_SIZE));
+
+  // Wait for a bit to let the child spawn all of its threads.
+  std::this_thread::sleep_for(250ms);
+
+  ASSERT_TRUE(debuggerd_trigger_dump(forkpid, std::move(pipe_write), kDebuggerdBacktrace, 10000));
+  // Immediately kill the forked child, to make sure that the dump didn't return early.
+  ASSERT_EQ(0, kill(forkpid, SIGKILL)) << strerror(errno);
+
+  // Check the output.
+  std::string result;
+  ASSERT_TRUE(android::base::ReadFdToString(pipe_read.get(), &result));
+
+  // Look for "----- end <PID> -----"
+  int found_end = 0;
+
+  std::string expected_end = android::base::StringPrintf("----- end %d -----", forkpid);
+
+  std::vector<std::string> lines = android::base::Split(result, "\n");
+  for (const std::string& line : lines) {
+    if (line == expected_end) {
+      ++found_end;
+    }
+  }
+
+  EXPECT_EQ(1, found_end) << "\nOutput: \n" << result;
+}
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/fs_mgr_avb_ops.cpp
index dd8c7e7..2c14c9b 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/fs_mgr_avb_ops.cpp
@@ -78,7 +78,7 @@
     // access. fs_mgr_test_access() will test a few iterations if the
     // path doesn't exist yet.
     if (fs_mgr_test_access(path.c_str()) < 0) {
-        return AVB_IO_RESULT_ERROR_IO;
+        return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
     }
 
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
diff --git a/init/README.md b/init/README.md
index 709c667..024d559 100644
--- a/init/README.md
+++ b/init/README.md
@@ -192,16 +192,17 @@
 `oneshot`
 > Do not restart the service when it exits.
 
-`class <name>`
-> Specify a class name for the service.  All services in a
+`class <name> [ <name>\* ]`
+> Specify class names for the service.  All services in a
   named class may be started or stopped together.  A service
   is in the class "default" if one is not specified via the
-  class option.
+  class option. Additional classnames beyond the (required) first
+  one are used to group services.
 
 `onrestart`
 > Execute a Command (see below) when service restarts.
 
-`writepid <file...>`
+`writepid <file> [ <file>\* ]`
 > Write the child's pid to the given files when it forks. Meant for
   cgroup/cpuset usage. If no files under /dev/cpuset/ are specified, but the
   system property 'ro.cpuset.default' is set to a non-empty cpuset name (e.g.
@@ -279,6 +280,9 @@
   currently running, without disabling them. They can be restarted
   later using `class_start`.
 
+`class_restart <serviceclass>`
+> Restarts all services of the specified class.
+
 `copy <src> <dst>`
 > Copies a file. Similar to write, but useful for binary/large
   amounts of data.
@@ -358,7 +362,8 @@
   "sys.powerctl" system property, used to implement rebooting.
 
 `restart <service>`
-> Like stop, but doesn't disable the service.
+> Stops and restarts a running service, does nothing if the service is currently
+  restarting, otherwise, it just starts the service.
 
 `restorecon <path> [ <path>\* ]`
 > Restore the file named by _path_ to the security context specified
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 32e9ef6..95f1aa0 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -148,6 +148,12 @@
     return 0;
 }
 
+static int do_class_restart(const std::vector<std::string>& args) {
+    ServiceManager::GetInstance().
+        ForEachServiceInClass(args[1], [] (Service* s) { s->Restart(); });
+    return 0;
+}
+
 static int do_domainname(const std::vector<std::string>& args) {
     return write_file("/proc/sys/kernel/domainname", args[1].c_str()) ? 0 : 1;
 }
@@ -897,6 +903,7 @@
         {"chmod",                   {2,     2,    do_chmod}},
         {"chown",                   {2,     3,    do_chown}},
         {"class_reset",             {1,     1,    do_class_reset}},
+        {"class_restart",           {1,     1,    do_class_restart}},
         {"class_start",             {1,     1,    do_class_start}},
         {"class_stop",              {1,     1,    do_class_stop}},
         {"copy",                    {2,     2,    do_copy}},
diff --git a/init/init.h b/init/init.h
index 3768c02..b4d25fb 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,9 +19,6 @@
 
 #include <string>
 
-class Action;
-class Service;
-
 extern const char *ENV[32];
 extern std::string default_console;
 extern struct selabel_handle *sehandle;
diff --git a/init/service.cpp b/init/service.cpp
index c8d1cb1..c6ef838 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -149,27 +149,44 @@
     : name(name), value(value) {
 }
 
-Service::Service(const std::string& name, const std::string& classname,
-                 const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(0), pid_(0),
-      crash_count_(0), uid_(0), gid_(0), namespace_flags_(0),
-      seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
-      priority_(0), oom_score_adjust_(-1000), args_(args) {
+Service::Service(const std::string& name, const std::vector<std::string>& args)
+    : name_(name),
+      classnames_({"default"}),
+      flags_(0),
+      pid_(0),
+      crash_count_(0),
+      uid_(0),
+      gid_(0),
+      namespace_flags_(0),
+      seclabel_(""),
+      ioprio_class_(IoSchedClass_NONE),
+      ioprio_pri_(0),
+      priority_(0),
+      oom_score_adjust_(-1000),
+      args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
-Service::Service(const std::string& name, const std::string& classname,
-                 unsigned flags, uid_t uid, gid_t gid,
-                 const std::vector<gid_t>& supp_gids,
-                 const CapSet& capabilities, unsigned namespace_flags,
-                 const std::string& seclabel,
+Service::Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
+                 const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
+                 unsigned namespace_flags, const std::string& seclabel,
                  const std::vector<std::string>& args)
-    : name_(name), classname_(classname), flags_(flags), pid_(0),
-      crash_count_(0), uid_(uid), gid_(gid),
-      supp_gids_(supp_gids), capabilities_(capabilities),
-      namespace_flags_(namespace_flags), seclabel_(seclabel),
-      ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
-      oom_score_adjust_(-1000), args_(args) {
+    : name_(name),
+      classnames_({"default"}),
+      flags_(flags),
+      pid_(0),
+      crash_count_(0),
+      uid_(uid),
+      gid_(gid),
+      supp_gids_(supp_gids),
+      capabilities_(capabilities),
+      namespace_flags_(namespace_flags),
+      seclabel_(seclabel),
+      ioprio_class_(IoSchedClass_NONE),
+      ioprio_pri_(0),
+      priority_(0),
+      oom_score_adjust_(-1000),
+      args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -297,7 +314,7 @@
 
 void Service::DumpState() const {
     LOG(INFO) << "service " << name_;
-    LOG(INFO) << "  class '" << classname_ << "'";
+    LOG(INFO) << "  class '" << android::base::Join(classnames_, " ") << "'";
     LOG(INFO) << "  exec "<< android::base::Join(args_, " ");
     std::for_each(descriptors_.begin(), descriptors_.end(),
                   [] (const auto& info) { LOG(INFO) << *info; });
@@ -334,7 +351,7 @@
 }
 
 bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
-    classname_ = args[1];
+    classnames_ = std::set<std::string>(args.begin() + 1, args.end());
     return true;
 }
 
@@ -516,10 +533,11 @@
 
 Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
+    // clang-format off
     static const Map option_parsers = {
         {"capabilities",
                         {1,     kMax, &Service::ParseCapabilities}},
-        {"class",       {1,     1,    &Service::ParseClass}},
+        {"class",       {1,     kMax, &Service::ParseClass}},
         {"console",     {0,     1,    &Service::ParseConsole}},
         {"critical",    {0,     0,    &Service::ParseCritical}},
         {"disabled",    {0,     0,    &Service::ParseDisabled}},
@@ -539,6 +557,7 @@
         {"user",        {1,     1,    &Service::ParseUser}},
         {"writepid",    {1,     kMax, &Service::ParseWritepid}},
     };
+    // clang-format on
     return option_parsers;
 }
 
@@ -889,8 +908,8 @@
         }
     }
 
-    auto svc_p = std::make_unique<Service>(name, "default", flags, uid, gid, supp_gids,
-                                           no_capabilities, namespace_flags, seclabel, str_args);
+    auto svc_p = std::make_unique<Service>(name, flags, uid, gid, supp_gids, no_capabilities,
+                                           namespace_flags, seclabel, str_args);
     Service* svc = svc_p.get();
     services_.emplace_back(std::move(svc_p));
 
@@ -940,7 +959,7 @@
 void ServiceManager::ForEachServiceInClass(const std::string& classname,
                                            void (*func)(Service* svc)) const {
     for (const auto& s : services_) {
-        if (classname == s->classname()) {
+        if (s->classnames().find(classname) != s->classnames().end()) {
             func(s.get());
         }
     }
@@ -1034,7 +1053,7 @@
     }
 
     std::vector<std::string> str_args(args.begin() + 2, args.end());
-    service_ = std::make_unique<Service>(name, "default", str_args);
+    service_ = std::make_unique<Service>(name, str_args);
     return true;
 }
 
diff --git a/init/service.h b/init/service.h
index 08388e2..9a9046b 100644
--- a/init/service.h
+++ b/init/service.h
@@ -22,6 +22,7 @@
 #include <cutils/iosched_policy.h>
 
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -61,12 +62,10 @@
 };
 
 class Service {
-public:
-    Service(const std::string& name, const std::string& classname,
-            const std::vector<std::string>& args);
+  public:
+    Service(const std::string& name, const std::vector<std::string>& args);
 
-    Service(const std::string& name, const std::string& classname,
-            unsigned flags, uid_t uid, gid_t gid,
+    Service(const std::string& name, unsigned flags, uid_t uid, gid_t gid,
             const std::vector<gid_t>& supp_gids, const CapSet& capabilities,
             unsigned namespace_flags, const std::string& seclabel,
             const std::vector<std::string>& args);
@@ -84,10 +83,10 @@
     bool Reap();
     void DumpState() const;
     void SetShutdownCritical() { flags_ |= SVC_SHUTDOWN_CRITICAL; }
-    bool IsShutdownCritical() { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
+    bool IsShutdownCritical() const { return (flags_ & SVC_SHUTDOWN_CRITICAL) != 0; }
 
     const std::string& name() const { return name_; }
-    const std::string& classname() const { return classname_; }
+    const std::set<std::string>& classnames() const { return classnames_; }
     unsigned flags() const { return flags_; }
     pid_t pid() const { return pid_; }
     uid_t uid() const { return uid_; }
@@ -100,7 +99,7 @@
     void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
     const std::vector<std::string>& args() const { return args_; }
 
-private:
+  private:
     using OptionParser = bool (Service::*) (const std::vector<std::string>& args,
                                             std::string* err);
     class OptionParserMap;
@@ -136,7 +135,7 @@
     bool AddDescriptor(const std::vector<std::string>& args, std::string* err);
 
     std::string name_;
-    std::string classname_;
+    std::set<std::string> classnames_;
     std::string console_;
 
     unsigned flags_;
diff --git a/libcutils/sched_policy.cpp b/libcutils/sched_policy.cpp
index 40144cf..0d459cc 100644
--- a/libcutils/sched_policy.cpp
+++ b/libcutils/sched_policy.cpp
@@ -51,13 +51,8 @@
 
 static pthread_once_t the_once = PTHREAD_ONCE_INIT;
 
-static int __sys_supports_schedgroups = -1;
 static int __sys_supports_timerslack = -1;
 
-// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
-static int bg_cgroup_fd = -1;
-static int fg_cgroup_fd = -1;
-
 // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
 static int system_bg_cpuset_fd = -1;
 static int bg_cpuset_fd = -1;
@@ -151,23 +146,6 @@
 
 static void __initialize() {
     const char* filename;
-    if (!access("/dev/cpuctl/tasks", W_OK)) {
-        __sys_supports_schedgroups = 1;
-
-        filename = "/dev/cpuctl/tasks";
-        fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        if (fg_cgroup_fd < 0) {
-            SLOGE("open of %s failed: %s\n", filename, strerror(errno));
-        }
-
-        filename = "/dev/cpuctl/bg_non_interactive/tasks";
-        bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
-        if (bg_cgroup_fd < 0) {
-            SLOGE("open of %s failed: %s\n", filename, strerror(errno));
-        }
-    } else {
-        __sys_supports_schedgroups = 0;
-    }
 
     if (cpusets_enabled()) {
         if (!access("/dev/cpuset/tasks", W_OK)) {
@@ -276,35 +254,21 @@
     }
     pthread_once(&the_once, __initialize);
 
-    if (__sys_supports_schedgroups) {
-        char grpBuf[32];
+    char grpBuf[32];
 
-        if (cpusets_enabled()) {
-            if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0)
-                return -1;
-            if (grpBuf[0] == '\0') {
-                *policy = SP_FOREGROUND;
-            } else if (!strcmp(grpBuf, "foreground")) {
-                *policy = SP_FOREGROUND;
-            } else if (!strcmp(grpBuf, "background")) {
-                *policy = SP_BACKGROUND;
-            } else if (!strcmp(grpBuf, "top-app")) {
-                *policy = SP_TOP_APP;
-            } else {
-                errno = ERANGE;
-                return -1;
-            }
+    if (cpusets_enabled()) {
+        if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0) return -1;
+        if (grpBuf[0] == '\0') {
+            *policy = SP_FOREGROUND;
+        } else if (!strcmp(grpBuf, "foreground")) {
+            *policy = SP_FOREGROUND;
+        } else if (!strcmp(grpBuf, "background")) {
+            *policy = SP_BACKGROUND;
+        } else if (!strcmp(grpBuf, "top-app")) {
+            *policy = SP_TOP_APP;
         } else {
-            if (getCGroupSubsys(tid, "cpu", grpBuf, sizeof(grpBuf)) < 0)
-                return -1;
-            if (grpBuf[0] == '\0') {
-                *policy = SP_FOREGROUND;
-            } else if (!strcmp(grpBuf, "bg_non_interactive")) {
-                *policy = SP_BACKGROUND;
-            } else {
-                errno = ERANGE;
-                return -1;
-            }
+            errno = ERANGE;
+            return -1;
         }
     } else {
         int rc = sched_getscheduler(tid);
@@ -440,41 +404,30 @@
     }
 #endif
 
-    if (__sys_supports_schedgroups) {
-        int fd = -1;
+    if (schedboost_enabled()) {
         int boost_fd = -1;
         switch (policy) {
         case SP_BACKGROUND:
-            fd = bg_cgroup_fd;
             boost_fd = bg_schedboost_fd;
             break;
         case SP_FOREGROUND:
         case SP_AUDIO_APP:
         case SP_AUDIO_SYS:
-            fd = fg_cgroup_fd;
             boost_fd = fg_schedboost_fd;
             break;
         case SP_TOP_APP:
-            fd = fg_cgroup_fd;
             boost_fd = ta_schedboost_fd;
             break;
         default:
-            fd = -1;
             boost_fd = -1;
             break;
         }
 
-        if (fd > 0 && add_tid_to_cgroup(tid, fd) != 0) {
+        if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
             if (errno != ESRCH && errno != ENOENT)
                 return -errno;
         }
 
-        if (schedboost_enabled()) {
-            if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) {
-                if (errno != ESRCH && errno != ENOENT)
-                    return -errno;
-            }
-        }
     } else {
         struct sched_param param;