Allow setting oom_score_adj for services spawned from init

(cherry picked from commit f7adf8e4739812a2a4f194b17f84f4b9df42d04b)

Bug: 29831602
Change-Id: I4d24264bb6e879935a0b2adbb2e49ddf458980cf
diff --git a/init/readme.txt b/init/readme.txt
index 56918f6..bc3874a 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -191,6 +191,10 @@
 namespace <pid|mnt>
   Enter a new PID or mount namespace when forking the service.
 
+oom_score_adjust <value>
+   Sets the child's /proc/self/oom_score_adj to the specified value,
+   which must range from -1000 to 1000.
+
 
 Triggers
 --------
diff --git a/init/service.cpp b/init/service.cpp
index 32aafd6..1caf7c6 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -163,7 +163,7 @@
     : name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
       time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0),
       seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
-      priority_(0), args_(args) {
+      priority_(0), oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -176,7 +176,7 @@
       time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid),
       supp_gids_(supp_gids), namespace_flags_(namespace_flags),
       seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
-      priority_(0), args_(args) {
+      priority_(0), oom_score_adjust_(-1000), args_(args) {
     onrestart_.InitSingleTrigger("onrestart");
 }
 
@@ -419,6 +419,18 @@
     return true;
 }
 
+bool Service::ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err) {
+    oom_score_adjust_ = std::stol(args[1], 0, 10);
+
+    if (oom_score_adjust_ < -1000 || oom_score_adjust_ > 1000) {
+        *err = "oom_score_adjust value must be in range -1000 - +1000";
+        return false;
+    }
+
+    return true;
+}
+
+
 bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
     seclabel_ = args[1];
     return true;
@@ -476,6 +488,8 @@
         {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
         {"oneshot",     {0,     0,    &Service::ParseOneshot}},
         {"onrestart",   {1,     kMax, &Service::ParseOnrestart}},
+        {"oom_score_adjust",
+                        {1,     1,    &Service::ParseOomScoreAdjust}},
         {"namespace",   {1,     2,    &Service::ParseNamespace}},
         {"seclabel",    {1,     1,    &Service::ParseSeclabel}},
         {"setenv",      {2,     2,    &Service::ParseSetenv}},
@@ -611,6 +625,14 @@
         return false;
     }
 
+    if (oom_score_adjust_ != -1000) {
+        std::string oom_str = StringPrintf("%d", oom_score_adjust_);
+        std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
+        if (!WriteStringToFile(oom_str, oom_file)) {
+            PLOG(ERROR) << "couldn't write oom_score_adj: " << strerror(errno);
+        }
+    }
+
     time_started_ = gettime();
     pid_ = pid;
     flags_ |= SVC_RUNNING;
diff --git a/init/service.h b/init/service.h
index fb03a07..4a3412c 100644
--- a/init/service.h
+++ b/init/service.h
@@ -126,6 +126,7 @@
     bool ParseKeycodes(const std::vector<std::string>& args, std::string* err);
     bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
     bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
+    bool ParseOomScoreAdjust(const std::vector<std::string>& args, std::string* err);
     bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
     bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
     bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
@@ -165,6 +166,8 @@
     int ioprio_pri_;
     int priority_;
 
+    int oom_score_adjust_;
+
     std::vector<std::string> args_;
 };