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) {