#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>
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
+#include "fd_utils-inl.h"
#include "nativebridge/native_bridge.h"
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;
return false;
}
- // Unmount storage provided by root namespace and mount requested view
- UnmountTree("/storage");
-
String8 storageSource;
if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
storageSource = "/mnt/runtime/default";
}
#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,
SetForkLoad(true);
#endif
+ sigset_t sigchld;
+ sigemptyset(&sigchld);
+ sigaddset(&sigchld, SIGCHLD);
+
+ // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
+ // log, which would result in the logging FDs we close being reopened.
+ // This would cause failures because the FDs are not whitelisted.
+ //
+ // Note that the zygote process is single threaded at this point.
+ if (sigprocmask(SIG_BLOCK, &sigchld, NULL) == -1) {
+ ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
+ }
+
+ // 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) {
// 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.");
+ }
+
+ if (sigprocmask(SIG_UNBLOCK, &sigchld, NULL) == -1) {
+ ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+ }
+
// Keep capabilities across UID change, unless we're staying root.
if (uid != 0) {
EnableKeepCapabilities(env);
} else if (pid > 0) {
// the parent process
-#ifdef ENABLE_SCHED_BOOST
- // unset scheduler knob
- SetForkLoad(false);
-#endif
-
+ // We blocked SIGCHLD prior to a fork, we unblock it here.
+ if (sigprocmask(SIG_UNBLOCK, &sigchld, NULL) == -1) {
+ ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
+ RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+ }
}
return pid;
}
return pid;
}
+static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) {
+ // Zygote process unmount root storage space initially before every child processes are forked.
+ // Every forked child processes (include SystemServer) only mount their own root storage space
+ // And no need unmount storage operation in MountEmulatedStorage method.
+ // Zygote process does not utilize root storage spaces and unshared its mount namespace from the ART.
+
+ UnmountTree("/storage");
+ return;
+}
+
static JNINativeMethod gMethods[] = {
{ "nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
- (void *) com_android_internal_os_Zygote_nativeForkSystemServer }
+ (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
+ { "nativeUnmountStorageOnInit", "()V",
+ (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit }
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {