Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e29afc9b authored by Jing Ji's avatar Jing Ji
Browse files

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
parent e2e63a57
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.system.ErrnoException;
import android.system.Os;
import android.util.Log;

import dalvik.annotation.optimization.FastNative;
import dalvik.system.ZygoteHooks;

import libcore.io.IoUtils;
@@ -1018,4 +1019,19 @@ public final class Zygote {
            command.append(" '").append(arg.replace("'", "'\\''")).append("'");
        }
    }

    /**
     * Parse the given unsolicited zygote message as type SIGCHLD,
     * extract the payload information into the given output buffer.
     *
     * @param in The unsolicited zygote message to be parsed
     * @param length The number of bytes in the message
     * @param out The output buffer where the payload information will be placed
     * @return Number of elements being place into output buffer, or -1 if
     *         either the message is malformed or not the type as expected here.
     *
     * @hide
     */
    @FastNative
    public static native int nativeParseSigChld(byte[] in, int length, int[] out);
}
+224 −102
Original line number Diff line number Diff line
@@ -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 std::atomic_uint32_t gUsapPoolCount = 0;
 */
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 @@ enum RuntimeFlags : uint32_t {
  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,8 +380,38 @@ static void RuntimeAbort(JNIEnv* env, int line, const char* msg) {
  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*/) {
static void SigChldHandler(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) {
    pid_t pid;
    int status;
    int64_t usaps_removed = 0;
@@ -368,10 +425,12 @@ static void SigChldHandler(int /*signal_number*/) {
    int saved_errno = errno;

    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));
            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)) {
@@ -405,12 +464,13 @@ static void SigChldHandler(int /*signal_number*/) {
    // 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));
        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 (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,
@@ -441,8 +501,7 @@ static void SigChldHandler(int /*signal_number*/) {
// 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));
@@ -1049,6 +1108,9 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server,

    // 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 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids,
    }
  }

  if (is_child_zygote) {
      initUnsolSocketToSystemServer();
  }

  env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
                            is_system_server, is_child_zygote, managed_instruction_set);

@@ -1873,6 +1939,11 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
      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 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
    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 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
  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 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env,
  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 @@ static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jc
    ALOGE("Unable to fetch USAP pool socket file descriptor");
  }

  initUnsolSocketToSystemServer();

  /*
   * Security Initialization
   */
@@ -2200,9 +2284,48 @@ static void com_android_internal_os_Zygote_nativeBoostUsapPriority(JNIEnv* env,
  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",
         "(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},
@@ -2212,10 +2335,10 @@ static const JNINativeMethod gMethods[] = {
         (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 },
        {"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",
         "(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},
@@ -2227,16 +2350,15 @@ static const JNINativeMethod gMethods[] = {
         (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 },
        {"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 },
        {"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 }
         (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) {
+99 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
import static android.os.Process.SYSTEM_UID;
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static android.os.Process.getFreeMemory;
@@ -62,6 +63,8 @@ import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.res.Resources;
import android.graphics.Point;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.AppZygote;
import android.os.Binder;
import android.os.Build;
@@ -113,6 +116,7 @@ import com.android.server.wm.WindowManagerService;
import dalvik.system.VMRuntime;

import java.io.File;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
@@ -282,6 +286,10 @@ public final class ProcessList {
    private static final String PROPERTY_USE_APP_IMAGE_STARTUP_CACHE =
            "persist.device_config.runtime_native.use_app_image_startup_cache";

    // The socket path for zygote to send unsolicited msg.
    // Must keep sync with com_android_internal_os_Zygote.cpp.
    private static final String UNSOL_ZYGOTE_MSG_SOCKET_PATH = "/data/system/unsolzygotesocket";

    // Low Memory Killer Daemon command codes.
    // These must be kept in sync with lmk_cmd definitions in lmkd.h
    //
@@ -439,6 +447,28 @@ public final class ProcessList {

    private PlatformCompat mPlatformCompat = null;

    /**
     * The server socket in system_server, zygote will connect to it
     * in order to send unsolicited messages to system_server.
     */
    private LocalSocket mSystemServerSocketForZygote;

    /**
     * Maximum number of bytes that an incoming unsolicited zygote message could be.
     * To be updated if new message type needs to be supported.
     */
    private static final int MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE = 16;

    /**
     * The buffer to be used to receive the incoming unsolicited zygote message.
     */
    private final byte[] mZygoteUnsolicitedMessage = new byte[MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE];

    /**
     * The buffer to be used to receive the SIGCHLD data, it includes pid/uid/status.
     */
    private final int[] mZygoteSigChldMessage = new int[3];

    interface LmkdKillListener {
        /**
         * Called when there is a process kill by lmkd.
@@ -702,6 +732,13 @@ public final class ProcessList {
                        }
                    }
            );
            // Start listening on incoming connections from zygotes.
            mSystemServerSocketForZygote = createSystemServerSocketForZygote();
            if (mSystemServerSocketForZygote != null) {
                sKillHandler.getLooper().getQueue().addOnFileDescriptorEventListener(
                        mSystemServerSocketForZygote.getFileDescriptor(),
                        EVENT_INPUT, this::handleZygoteMessages);
            }
        }
    }

@@ -3560,4 +3597,66 @@ public final class ProcessList {
            }
        }
    }

    private void handleZygoteSigChld(int pid, int uid, int status) {
        // Just log it now.
        if (DEBUG_PROCESSES) {
            Slog.i(TAG, "Got SIGCHLD from zygote: pid=" + pid + ", uid=" + uid
                    + ", status=" + Integer.toHexString(status));
        }
    }

    /**
     * Create a server socket in system_server, zygote will connect to it
     * in order to send unsolicited messages to system_server.
     */
    private LocalSocket createSystemServerSocketForZygote() {
        // The file system entity for this socket is created with 0666 perms, owned
        // by system:system. selinux restricts things so that only zygotes can
        // access it.
        final File socketFile = new File(UNSOL_ZYGOTE_MSG_SOCKET_PATH);
        if (socketFile.exists()) {
            socketFile.delete();
        }

        LocalSocket serverSocket = null;
        try {
            serverSocket = new LocalSocket(LocalSocket.SOCKET_DGRAM);
            serverSocket.bind(new LocalSocketAddress(
                    UNSOL_ZYGOTE_MSG_SOCKET_PATH, LocalSocketAddress.Namespace.FILESYSTEM));
            Os.chmod(UNSOL_ZYGOTE_MSG_SOCKET_PATH, 0666);
        } catch (Exception e) {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException ex) {
                }
                serverSocket = null;
            }
        }
        return serverSocket;
    }

    /**
     * Handle the unsolicited message from zygote.
     */
    private int handleZygoteMessages(FileDescriptor fd, int events) {
        final int eventFd = fd.getInt$();
        if ((events & EVENT_INPUT) != 0) {
            // An incoming message from zygote
            try {
                final int len = Os.read(fd, mZygoteUnsolicitedMessage, 0,
                        mZygoteUnsolicitedMessage.length);
                if (len > 0 && mZygoteSigChldMessage.length == Zygote.nativeParseSigChld(
                        mZygoteUnsolicitedMessage, len, mZygoteSigChldMessage)) {
                    handleZygoteSigChld(mZygoteSigChldMessage[0] /* pid */,
                            mZygoteSigChldMessage[1] /* uid */,
                            mZygoteSigChldMessage[2] /* status */);
                }
            } catch (Exception e) {
                Slog.w(TAG, "Exception in reading unsolicited zygote message: " + e);
            }
        }
        return EVENT_INPUT;
    }
}