summaryrefslogtreecommitdiffstats
path: root/core/jni/com_android_internal_os_Zygote.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/jni/com_android_internal_os_Zygote.cpp')
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp34
1 files changed, 34 insertions, 0 deletions
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b431a3f..a1fef4a 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -16,6 +16,8 @@
#define LOG_TAG "Zygote"
+#include <sstream>
+
// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
#include <sys/mount.h>
#include <linux/fs.h>
@@ -53,6 +55,7 @@
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
+#include "fd_utils-inl.h"
#include "nativebridge/native_bridge.h"
@@ -78,6 +81,12 @@ static void RuntimeAbort(JNIEnv* env) {
env->FatalError("RuntimeAbort");
}
+static void RuntimeAbort(JNIEnv* env, int line, const char* msg) {
+ std::ostringstream oss;
+ oss << __FILE__ << ":" << line << ": " << msg;
+ env->FatalError(oss.str().c_str());
+}
+
// This signal handler is for zygote mode, since the zygote must reap its children
static void SigChldHandler(int /*signal_number*/) {
pid_t pid;
@@ -439,6 +448,9 @@ static void SetForkLoad(bool boost) {
}
#endif
+// The list of open zygote file descriptors.
+static FileDescriptorTable* gOpenFdTable = NULL;
+
// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags, jobjectArray javaRlimits,
@@ -453,6 +465,22 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
SetForkLoad(true);
#endif
+ // Close any logging related FDs before we start evaluating the list of
+ // file descriptors.
+ __android_log_close();
+
+ // If this is the first fork for this zygote, create the open FD table.
+ // If it isn't, we just need to check whether the list of open files has
+ // changed (and it shouldn't in the normal case).
+ if (gOpenFdTable == NULL) {
+ gOpenFdTable = FileDescriptorTable::Create();
+ if (gOpenFdTable == NULL) {
+ RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
+ }
+ } else if (!gOpenFdTable->Restat()) {
+ RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
+ }
+
pid_t pid = fork();
if (pid == 0) {
@@ -462,6 +490,12 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fdsToClose);
+ // Re-open all remaining open file descriptors so that they aren't shared
+ // with the zygote across a fork.
+ if (!gOpenFdTable->ReopenOrDetach()) {
+ RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
+ }
+
// Keep capabilities across UID change, unless we're staying root.
if (uid != 0) {
EnableKeepCapabilities(env);