Merge "DO NOT MERGE: Add support to send notification from Zygote to system_server" am: 54469bf6ff am: 07dc8cd0f8

Change-Id: I5181c73e996f86853fa354b44a64a76bac3ea388
This commit is contained in:
Automerger Merge Worker
2020-01-17 22:19:40 +00:00
3 changed files with 241 additions and 4 deletions

View File

@@ -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;
@@ -969,4 +970,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);
}

View File

@@ -63,6 +63,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;
/**
* The maximum value that the gUSAPPoolSizeMax variable may take. This value
* is a mirror of ZygoteServer.USAP_POOL_SIZE_MAX_LIMIT
@@ -314,6 +321,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);
@@ -323,8 +350,37 @@ 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;
@@ -338,6 +394,8 @@ 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,
@@ -411,8 +469,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));
@@ -967,6 +1024,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);
}
@@ -1146,6 +1206,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);
@@ -1391,6 +1455,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) {
@@ -1416,6 +1485,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,
@@ -1483,6 +1557,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);
@@ -1490,6 +1567,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);
@@ -1590,6 +1670,7 @@ static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jc
ALOGE("Unable to fetch USAP pool socket file descriptor");
}
initUnsolSocketToSystemServer();
/*
* Security Initialization
*/
@@ -1733,6 +1814,44 @@ 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;)I",
@@ -1769,7 +1888,9 @@ static const JNINativeMethod gMethods[] = {
{ "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) {

View File

@@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO;
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;
@@ -57,6 +58,8 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
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;
@@ -74,6 +77,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
import android.system.Os;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.EventLog;
@@ -102,6 +106,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;
@@ -245,6 +250,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
//
@@ -388,6 +397,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.
@@ -643,6 +674,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);
}
}
}
@@ -3265,4 +3303,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;
}
}