Merge changes from topic "native process registration"
am: 8106c8e09f
Change-Id: I9b475b9951680bea22307b5a19bd1f5ed76398bb
diff --git a/init/Android.bp b/init/Android.bp
index 776a3a6..d939fcc 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -65,6 +65,7 @@
"libavb",
"libc++fs",
"libcgrouprc_format",
+ "liblmkd_utils",
"libmodprobe",
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
@@ -118,6 +119,7 @@
"init.cpp",
"interface_utils.cpp",
"keychords.cpp",
+ "lmkd_service.cpp",
"modalias_handler.cpp",
"mount_handler.cpp",
"mount_namespace.cpp",
diff --git a/init/init.cpp b/init/init.cpp
index f775d8f..6ea2d00 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -59,6 +59,7 @@
#include "first_stage_mount.h"
#include "import_parser.h"
#include "keychords.h"
+#include "lmkd_service.h"
#include "mount_handler.h"
#include "mount_namespace.h"
#include "property_service.h"
@@ -684,9 +685,15 @@
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
+ // Will handle EPIPE at the time of write by checking the errno
+ signal(SIGPIPE, SIG_IGN);
+
// Set init and its forked children's oom_adj.
- if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
- LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
+ if (auto result =
+ WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST));
+ !result) {
+ LOG(ERROR) << "Unable to write " << DEFAULT_OOM_SCORE_ADJUST
+ << " to /proc/1/oom_score_adj: " << result.error();
}
// Set up a session keyring that all processes will have access to. It
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
new file mode 100644
index 0000000..dd1ab4d
--- /dev/null
+++ b/init/lmkd_service.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 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 "lmkd_service.h"
+
+#include <errno.h>
+
+#include <android-base/logging.h>
+#include <liblmkd_utils.h>
+
+#include "service_list.h"
+
+namespace android {
+namespace init {
+
+enum LmkdRegistrationResult {
+ LMKD_REG_SUCCESS,
+ LMKD_CONN_FAILED,
+ LMKD_REG_FAILED,
+};
+
+static int lmkd_socket = -1;
+
+static LmkdRegistrationResult RegisterProcess(uid_t uid, pid_t pid, int oom_score_adjust) {
+ // connect to lmkd if not already connected
+ if (lmkd_socket < 0) {
+ lmkd_socket = lmkd_connect();
+ if (lmkd_socket < 0) {
+ return LMKD_CONN_FAILED;
+ }
+ }
+
+ // register service with lmkd
+ struct lmk_procprio params;
+ params.pid = pid;
+ params.uid = uid;
+ params.oomadj = oom_score_adjust;
+ params.ptype = PROC_TYPE_SERVICE;
+ if (lmkd_register_proc(lmkd_socket, ¶ms) != 0) {
+ // data transfer failed, reset the connection
+ close(lmkd_socket);
+ lmkd_socket = -1;
+ return LMKD_REG_FAILED;
+ }
+
+ return LMKD_REG_SUCCESS;
+}
+
+static bool UnregisterProcess(pid_t pid) {
+ if (lmkd_socket < 0) {
+ // no connection or it was lost, no need to unregister
+ return false;
+ }
+
+ // unregister service
+ struct lmk_procremove params;
+ params.pid = pid;
+ if (lmkd_unregister_proc(lmkd_socket, ¶ms) != 0) {
+ // data transfer failed, reset the connection
+ close(lmkd_socket);
+ lmkd_socket = -1;
+ return false;
+ }
+
+ return true;
+}
+
+static void RegisterServices(pid_t exclude_pid) {
+ for (const auto& service : ServiceList::GetInstance().services()) {
+ auto svc = service.get();
+ if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
+ // skip if process is excluded or not yet forked (pid==0)
+ if (svc->pid() == exclude_pid || svc->pid() == 0) {
+ continue;
+ }
+ if (RegisterProcess(svc->uid(), svc->pid(), svc->oom_score_adjust()) !=
+ LMKD_REG_SUCCESS) {
+ // a failure here resets the connection, will retry during next registration
+ break;
+ }
+ }
+ }
+}
+
+void LmkdRegister(const std::string& name, uid_t uid, pid_t pid, int oom_score_adjust) {
+ bool new_connection = lmkd_socket == -1;
+ LmkdRegistrationResult result;
+
+ result = RegisterProcess(uid, pid, oom_score_adjust);
+ if (result == LMKD_REG_FAILED) {
+ // retry one time if connection to lmkd was lost
+ result = RegisterProcess(uid, pid, oom_score_adjust);
+ new_connection = result == LMKD_REG_SUCCESS;
+ }
+ switch (result) {
+ case LMKD_REG_SUCCESS:
+ // register existing services once new connection is established
+ if (new_connection) {
+ RegisterServices(pid);
+ }
+ break;
+ case LMKD_CONN_FAILED:
+ PLOG(ERROR) << "lmkd connection failed when " << name << " process got started";
+ break;
+ case LMKD_REG_FAILED:
+ PLOG(ERROR) << "lmkd failed to register " << name << " process";
+ break;
+ }
+}
+
+void LmkdUnregister(const std::string& name, pid_t pid) {
+ if (!UnregisterProcess(pid)) {
+ PLOG(ERROR) << "lmkd failed to unregister " << name << " process";
+ }
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/lmkd_service.h b/init/lmkd_service.h
new file mode 100644
index 0000000..5b51d52
--- /dev/null
+++ b/init/lmkd_service.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+
+#include <string>
+
+namespace android {
+namespace init {
+
+static const int MIN_OOM_SCORE_ADJUST = -1000;
+static const int MAX_OOM_SCORE_ADJUST = 1000;
+// service with default score is unkillable
+static const int DEFAULT_OOM_SCORE_ADJUST = MIN_OOM_SCORE_ADJUST;
+
+#if defined(__ANDROID__)
+
+void LmkdRegister(const std::string& name, uid_t uid, pid_t pid, int oom_score_adjust);
+void LmkdUnregister(const std::string& name, pid_t pid);
+
+#else // defined(__ANDROID__)
+
+static inline void LmkdRegister(const std::string&, uid_t, pid_t, int) {}
+static inline void LmkdUnregister(const std::string&, pid_t) {}
+
+#endif // defined(__ANDROID__)
+
+} // namespace init
+} // namespace android
diff --git a/init/service.cpp b/init/service.cpp
index c8568a0..f8e98a2 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -36,6 +36,7 @@
#include <processgroup/processgroup.h>
#include <selinux/selinux.h>
+#include "lmkd_service.h"
#include "service_list.h"
#include "util.h"
@@ -151,7 +152,7 @@
seclabel_(seclabel),
onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
"onrestart", {}),
- oom_score_adjust_(-1000),
+ oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
start_order_(0),
args_(args) {}
@@ -199,6 +200,10 @@
if (r == 0) process_cgroup_empty_ = true;
}
+
+ if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
+ LmkdUnregister(name_, pid_);
+ }
}
void Service::SetProcessAttributesAndCaps() {
@@ -502,7 +507,7 @@
return ErrnoError() << "Failed to fork";
}
- if (oom_score_adjust_ != -1000) {
+ if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
std::string oom_str = std::to_string(oom_score_adjust_);
std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
if (!WriteStringToFile(oom_str, oom_file)) {
@@ -563,6 +568,10 @@
}
}
+ if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
+ LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_);
+ }
+
NotifyStateChange("running");
reboot_on_failure.Disable();
return {};
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index e6a341d..154d1dd 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -29,6 +29,7 @@
#include <hidl-util/FQName.h>
#include <system/thread_defs.h>
+#include "lmkd_service.h"
#include "rlimit_parser.h"
#include "service_utils.h"
#include "util.h"
@@ -261,8 +262,10 @@
}
Result<void> ServiceParser::ParseOomScoreAdjust(std::vector<std::string>&& args) {
- if (!ParseInt(args[1], &service_->oom_score_adjust_, -1000, 1000)) {
- return Error() << "oom_score_adjust value must be in range -1000 - +1000";
+ if (!ParseInt(args[1], &service_->oom_score_adjust_, MIN_OOM_SCORE_ADJUST,
+ MAX_OOM_SCORE_ADJUST)) {
+ return Error() << "oom_score_adjust value must be in range " << MIN_OOM_SCORE_ADJUST
+ << " - +" << MAX_OOM_SCORE_ADJUST;
}
return {};
}
diff --git a/init/service_test.cpp b/init/service_test.cpp
index c9cc7bd..c158b0a 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -23,6 +23,7 @@
#include <gtest/gtest.h>
+#include "lmkd_service.h"
#include "util.h"
namespace android {
@@ -49,7 +50,7 @@
EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory->ioprio_class());
EXPECT_EQ(0, service_in_old_memory->ioprio_pri());
EXPECT_EQ(0, service_in_old_memory->priority());
- EXPECT_EQ(-1000, service_in_old_memory->oom_score_adjust());
+ EXPECT_EQ(DEFAULT_OOM_SCORE_ADJUST, service_in_old_memory->oom_score_adjust());
EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
for (std::size_t i = 0; i < memory_size; ++i) {
@@ -68,7 +69,7 @@
EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory2->ioprio_class());
EXPECT_EQ(0, service_in_old_memory2->ioprio_pri());
EXPECT_EQ(0, service_in_old_memory2->priority());
- EXPECT_EQ(-1000, service_in_old_memory2->oom_score_adjust());
+ EXPECT_EQ(DEFAULT_OOM_SCORE_ADJUST, service_in_old_memory2->oom_score_adjust());
EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index e037a43..0827247 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -347,6 +347,8 @@
# Start logd before any other services run to ensure we capture all of their logs.
start logd
+ # Start lmkd before any other services run so that it can register them
+ start lmkd
# Start essential services.
start servicemanager