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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user