Add support to send notification from Zygote to system_server
Zygote will send message to system_server on SIGCHILD now.
Bug: 136036078
Test: atest CtsWebkitTestCases
Test: atest CtsHostsideWebViewTests
Test: atest CtsAppTestCases
Change-Id: Ifb385d907018bbe76b2aa81eb09209a77ea9224d
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 05b573a..c238565 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -67,6 +67,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/un.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -163,6 +164,12 @@
*/
static int gUsapPoolEventFD = -1;
+/**
+ * The socket file descriptor used to send notifications to the
+ * system_server.
+ */
+static int gSystemServerSocketFd = -1;
+
static constexpr int DEFAULT_DATA_DIR_PERMISSION = 0751;
/**
@@ -344,6 +351,26 @@
PROFILE_FROM_SHELL = 1 << 15,
};
+enum UnsolicitedZygoteMessageTypes : uint32_t {
+ UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED = 0,
+ UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD = 1,
+};
+
+struct UnsolicitedZygoteMessageSigChld {
+ struct {
+ UnsolicitedZygoteMessageTypes type;
+ } header;
+ struct {
+ pid_t pid;
+ uid_t uid;
+ int status;
+ } payload;
+};
+
+// Keep sync with services/core/java/com/android/server/am/ProcessList.java
+static constexpr struct sockaddr_un kSystemServerSockAddr =
+ {.sun_family = AF_LOCAL, .sun_path = "/data/system/unsolzygotesocket"};
+
// Forward declaration so we don't have to move the signal handler.
static bool RemoveUsapTableEntry(pid_t usap_pid);
@@ -353,74 +380,107 @@
env->FatalError(oss.str().c_str());
}
+// Create the socket which is going to be used to send unsolicited message
+// to system_server, the socket will be closed post forking a child process.
+// It's expected to be called at each zygote's initialization.
+static void initUnsolSocketToSystemServer() {
+ gSystemServerSocketFd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+ if (gSystemServerSocketFd >= 0) {
+ ALOGV("Zygote:systemServerSocketFD = %d", gSystemServerSocketFd);
+ } else {
+ ALOGE("Unable to create socket file descriptor to connect to system_server");
+ }
+}
+
+static void sendSigChildStatus(const pid_t pid, const uid_t uid, const int status) {
+ int socketFd = gSystemServerSocketFd;
+ if (socketFd >= 0) {
+ // fill the message buffer
+ struct UnsolicitedZygoteMessageSigChld data =
+ {.header = {.type = UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD},
+ .payload = {.pid = pid, .uid = uid, .status = status}};
+ if (TEMP_FAILURE_RETRY(
+ sendto(socketFd, &data, sizeof(data), 0,
+ reinterpret_cast<const struct sockaddr*>(&kSystemServerSockAddr),
+ sizeof(kSystemServerSockAddr))) == -1) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Zygote failed to write to system_server FD: %s",
+ strerror(errno));
+ }
+ }
+}
+
// This signal handler is for zygote mode, since the zygote must reap its children
-static void SigChldHandler(int /*signal_number*/) {
- pid_t pid;
- int status;
- int64_t usaps_removed = 0;
+static void SigChldHandler(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
+ pid_t pid;
+ int status;
+ int64_t usaps_removed = 0;
- // It's necessary to save and restore the errno during this function.
- // Since errno is stored per thread, changing it here modifies the errno
- // on the thread on which this signal handler executes. If a signal occurs
- // between a call and an errno check, it's possible to get the errno set
- // here.
- // See b/23572286 for extra information.
- int saved_errno = errno;
+ // It's necessary to save and restore the errno during this function.
+ // Since errno is stored per thread, changing it here modifies the errno
+ // on the thread on which this signal handler executes. If a signal occurs
+ // between a call and an errno check, it's possible to get the errno set
+ // here.
+ // See b/23572286 for extra information.
+ int saved_errno = errno;
- while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
- // Log process-death status that we care about.
- if (WIFEXITED(status)) {
- async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
- "Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+ // Notify system_server that we received a SIGCHLD
+ sendSigChildStatus(pid, info->si_uid, status);
+ // Log process-death status that we care about.
+ if (WIFEXITED(status)) {
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, "Process %d exited cleanly (%d)", pid,
+ WEXITSTATUS(status));
- // Check to see if the PID is in the USAP pool and remove it if it is.
- if (RemoveUsapTableEntry(pid)) {
- ++usaps_removed;
- }
- } else if (WIFSIGNALED(status)) {
- async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
- "Process %d exited due to signal %d (%s)%s", pid,
- WTERMSIG(status), strsignal(WTERMSIG(status)),
- WCOREDUMP(status) ? "; core dumped" : "");
+ // Check to see if the PID is in the USAP pool and remove it if it is.
+ if (RemoveUsapTableEntry(pid)) {
+ ++usaps_removed;
+ }
+ } else if (WIFSIGNALED(status)) {
+ async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+ "Process %d exited due to signal %d (%s)%s", pid,
+ WTERMSIG(status), strsignal(WTERMSIG(status)),
+ WCOREDUMP(status) ? "; core dumped" : "");
- // If the process exited due to a signal other than SIGTERM, check to see
- // if the PID is in the USAP pool and remove it if it is. If the process
- // was closed by the Zygote using SIGTERM then the USAP pool entry will
- // have already been removed (see nativeEmptyUsapPool()).
- if (WTERMSIG(status) != SIGTERM && RemoveUsapTableEntry(pid)) {
- ++usaps_removed;
- }
+ // If the process exited due to a signal other than SIGTERM, check to see
+ // if the PID is in the USAP pool and remove it if it is. If the process
+ // was closed by the Zygote using SIGTERM then the USAP pool entry will
+ // have already been removed (see nativeEmptyUsapPool()).
+ if (WTERMSIG(status) != SIGTERM && RemoveUsapTableEntry(pid)) {
+ ++usaps_removed;
+ }
+ }
+
+ // If the just-crashed process is the system_server, bring down zygote
+ // so that it is restarted by init and system server will be restarted
+ // from there.
+ if (pid == gSystemServerPid) {
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Exit zygote because system server (pid %d) has terminated", pid);
+ kill(getpid(), SIGKILL);
+ }
}
- // If the just-crashed process is the system_server, bring down zygote
- // so that it is restarted by init and system server will be restarted
- // from there.
- if (pid == gSystemServerPid) {
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
- "Exit zygote because system server (pid %d) has terminated", pid);
- kill(getpid(), SIGKILL);
+ // Note that we shouldn't consider ECHILD an error because
+ // the secondary zygote might have no children left to wait for.
+ if (pid < 0 && errno != ECHILD) {
+ async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Zygote SIGCHLD error in waitpid: %s",
+ strerror(errno));
}
- }
- // Note that we shouldn't consider ECHILD an error because
- // the secondary zygote might have no children left to wait for.
- if (pid < 0 && errno != ECHILD) {
- async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG,
- "Zygote SIGCHLD error in waitpid: %s", strerror(errno));
- }
-
- if (usaps_removed > 0) {
- if (TEMP_FAILURE_RETRY(write(gUsapPoolEventFD, &usaps_removed, sizeof(usaps_removed))) == -1) {
- // If this write fails something went terribly wrong. We will now kill
- // the zygote and let the system bring it back up.
- async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
- "Zygote failed to write to USAP pool event FD: %s",
- strerror(errno));
- kill(getpid(), SIGKILL);
+ if (usaps_removed > 0) {
+ if (TEMP_FAILURE_RETRY(write(gUsapPoolEventFD, &usaps_removed, sizeof(usaps_removed))) ==
+ -1) {
+ // If this write fails something went terribly wrong. We will now kill
+ // the zygote and let the system bring it back up.
+ async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+ "Zygote failed to write to USAP pool event FD: %s",
+ strerror(errno));
+ kill(getpid(), SIGKILL);
+ }
}
- }
- errno = saved_errno;
+ errno = saved_errno;
}
// Configures the SIGCHLD/SIGHUP handlers for the zygote process. This is
@@ -441,12 +501,11 @@
// This ends up being called repeatedly before each fork(), but there's
// no real harm in that.
static void SetSignalHandlers() {
- struct sigaction sig_chld = {};
- sig_chld.sa_handler = SigChldHandler;
+ struct sigaction sig_chld = {.sa_flags = SA_SIGINFO, .sa_sigaction = SigChldHandler};
- if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) {
- ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
- }
+ if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) {
+ ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
+ }
struct sigaction sig_hup = {};
sig_hup.sa_handler = SIG_IGN;
@@ -1049,6 +1108,9 @@
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
+
+ // Reset the fd to the unsolicited zygote socket
+ gSystemServerSocketFd = -1;
} else {
ALOGD("Forked child process %d", pid);
}
@@ -1608,6 +1670,10 @@
}
}
+ if (is_child_zygote) {
+ initUnsolSocketToSystemServer();
+ }
+
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
is_system_server, is_child_zygote, managed_instruction_set);
@@ -1873,6 +1939,11 @@
fds_to_ignore.push_back(gUsapPoolEventFD);
}
+ if (gSystemServerSocketFd != -1) {
+ fds_to_close.push_back(gSystemServerSocketFd);
+ fds_to_ignore.push_back(gSystemServerSocketFd);
+ }
+
pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true);
if (pid == 0) {
@@ -1899,6 +1970,11 @@
fds_to_ignore.push_back(gUsapPoolEventFD);
}
+ if (gSystemServerSocketFd != -1) {
+ fds_to_close.push_back(gSystemServerSocketFd);
+ fds_to_ignore.push_back(gSystemServerSocketFd);
+ }
+
pid_t pid = ForkCommon(env, true,
fds_to_close,
fds_to_ignore,
@@ -1969,6 +2045,9 @@
fds_to_close.push_back(gZygoteSocketFD);
fds_to_close.push_back(gUsapPoolEventFD);
fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end());
+ if (gSystemServerSocketFd != -1) {
+ fds_to_close.push_back(gSystemServerSocketFd);
+ }
fds_to_ignore.push_back(gZygoteSocketFD);
fds_to_ignore.push_back(gUsapPoolSocketFD);
@@ -1976,6 +2055,9 @@
fds_to_ignore.push_back(read_pipe_fd);
fds_to_ignore.push_back(write_pipe_fd);
fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end());
+ if (gSystemServerSocketFd != -1) {
+ fds_to_ignore.push_back(gSystemServerSocketFd);
+ }
pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore,
is_priority_fork == JNI_TRUE);
@@ -2074,6 +2156,8 @@
ALOGE("Unable to fetch USAP pool socket file descriptor");
}
+ initUnsolSocketToSystemServer();
+
/*
* Security Initialization
*/
@@ -2200,43 +2284,81 @@
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
}
+static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclass, jbyteArray in,
+ jint length, jintArray out) {
+ if (length != sizeof(struct UnsolicitedZygoteMessageSigChld)) {
+ // Apparently it's not the message we are expecting.
+ return -1;
+ }
+ if (in == nullptr || out == nullptr) {
+ // Invalid parameter
+ jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
+ return -1;
+ }
+ ScopedByteArrayRO source(env, in);
+ if (source.size() < length) {
+ // Invalid parameter
+ jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
+ return -1;
+ }
+ const struct UnsolicitedZygoteMessageSigChld* msg =
+ reinterpret_cast<const struct UnsolicitedZygoteMessageSigChld*>(source.get());
+
+ switch (msg->header.type) {
+ case UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD: {
+ ScopedIntArrayRW buf(env, out);
+ if (buf.size() != 3) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", nullptr);
+ return UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED;
+ }
+ buf[0] = msg->payload.pid;
+ buf[1] = msg->payload.uid;
+ buf[2] = msg->payload.status;
+ return 3;
+ }
+ default:
+ break;
+ }
+ return -1;
+}
+
static const JNINativeMethod gMethods[] = {
- { "nativeForkAndSpecialize",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)I",
- (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
- { "nativeForkSystemServer", "(II[II[[IJJ)I",
- (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
- { "nativeAllowFileAcrossFork", "(Ljava/lang/String;)V",
- (void *) com_android_internal_os_Zygote_nativeAllowFileAcrossFork },
- { "nativePreApplicationInit", "()V",
- (void *) com_android_internal_os_Zygote_nativePreApplicationInit },
- { "nativeInstallSeccompUidGidFilter", "(II)V",
- (void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter },
- { "nativeForkUsap", "(II[IZ)I",
- (void *) com_android_internal_os_Zygote_nativeForkUsap },
- { "nativeSpecializeAppProcess",
- "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Z[Ljava/lang/String;)V",
- (void *) com_android_internal_os_Zygote_nativeSpecializeAppProcess },
- { "nativeInitNativeState", "(Z)V",
- (void *) com_android_internal_os_Zygote_nativeInitNativeState },
- { "nativeGetUsapPipeFDs", "()[I",
- (void *) com_android_internal_os_Zygote_nativeGetUsapPipeFDs },
- { "nativeRemoveUsapTableEntry", "(I)Z",
- (void *) com_android_internal_os_Zygote_nativeRemoveUsapTableEntry },
- { "nativeGetUsapPoolEventFD", "()I",
- (void *) com_android_internal_os_Zygote_nativeGetUsapPoolEventFD },
- { "nativeGetUsapPoolCount", "()I",
- (void *) com_android_internal_os_Zygote_nativeGetUsapPoolCount },
- { "nativeEmptyUsapPool", "()V",
- (void *) com_android_internal_os_Zygote_nativeEmptyUsapPool },
- { "nativeDisableExecuteOnly", "()Z",
- (void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly },
- { "nativeBlockSigTerm", "()V",
- (void* ) com_android_internal_os_Zygote_nativeBlockSigTerm },
- { "nativeUnblockSigTerm", "()V",
- (void* ) com_android_internal_os_Zygote_nativeUnblockSigTerm },
- { "nativeBoostUsapPriority", "()V",
- (void* ) com_android_internal_os_Zygote_nativeBoostUsapPriority }
+ {"nativeForkAndSpecialize",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/"
+ "String;Z[Ljava/lang/String;)I",
+ (void*)com_android_internal_os_Zygote_nativeForkAndSpecialize},
+ {"nativeForkSystemServer", "(II[II[[IJJ)I",
+ (void*)com_android_internal_os_Zygote_nativeForkSystemServer},
+ {"nativeAllowFileAcrossFork", "(Ljava/lang/String;)V",
+ (void*)com_android_internal_os_Zygote_nativeAllowFileAcrossFork},
+ {"nativePreApplicationInit", "()V",
+ (void*)com_android_internal_os_Zygote_nativePreApplicationInit},
+ {"nativeInstallSeccompUidGidFilter", "(II)V",
+ (void*)com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter},
+ {"nativeForkUsap", "(II[IZ)I", (void*)com_android_internal_os_Zygote_nativeForkUsap},
+ {"nativeSpecializeAppProcess",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/"
+ "String;Z[Ljava/lang/String;)V",
+ (void*)com_android_internal_os_Zygote_nativeSpecializeAppProcess},
+ {"nativeInitNativeState", "(Z)V",
+ (void*)com_android_internal_os_Zygote_nativeInitNativeState},
+ {"nativeGetUsapPipeFDs", "()[I",
+ (void*)com_android_internal_os_Zygote_nativeGetUsapPipeFDs},
+ {"nativeRemoveUsapTableEntry", "(I)Z",
+ (void*)com_android_internal_os_Zygote_nativeRemoveUsapTableEntry},
+ {"nativeGetUsapPoolEventFD", "()I",
+ (void*)com_android_internal_os_Zygote_nativeGetUsapPoolEventFD},
+ {"nativeGetUsapPoolCount", "()I",
+ (void*)com_android_internal_os_Zygote_nativeGetUsapPoolCount},
+ {"nativeEmptyUsapPool", "()V", (void*)com_android_internal_os_Zygote_nativeEmptyUsapPool},
+ {"nativeDisableExecuteOnly", "()Z",
+ (void*)com_android_internal_os_Zygote_nativeDisableExecuteOnly},
+ {"nativeBlockSigTerm", "()V", (void*)com_android_internal_os_Zygote_nativeBlockSigTerm},
+ {"nativeUnblockSigTerm", "()V", (void*)com_android_internal_os_Zygote_nativeUnblockSigTerm},
+ {"nativeBoostUsapPriority", "()V",
+ (void*)com_android_internal_os_Zygote_nativeBoostUsapPriority},
+ {"nativeParseSigChld", "([BI[I)I",
+ (void*)com_android_internal_os_Zygote_nativeParseSigChld},
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {