#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);
}
DropCapabilitiesBoundingSet(env);
-
+#ifdef _COMPATIBILITY_ENHANCEMENT_PACKAGE_
+ bool use_native_bridge = !is_system_server && android::NativeBridgeAvailable();
+#else
bool use_native_bridge = !is_system_server && (instructionSet != NULL)
- && android::NativeBridgeAvailable();
+ && android::NativeBridgeAvailable();
+#endif
if (use_native_bridge) {
+#ifdef _COMPATIBILITY_ENHANCEMENT_PACKAGE_
+ if (instructionSet != NULL) {
+ ScopedUtfChars isa_string(env, instructionSet);
+ use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
+ } else {
+ use_native_bridge = android::NeedsNativeBridge(NULL);
+ instructionSet = env->NewStringUTF("arm"
+#ifdef __LP64__
+ "64"
+#endif
+ );
+ }
+#else
ScopedUtfChars isa_string(env, instructionSet);
use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
- }
+#endif
+ }
+
+#ifndef _COMPATIBILITY_ENHANCEMENT_PACKAGE_
if (use_native_bridge && dataDir == NULL) {
- // dataDir should never be null if we need to use a native bridge.
- // In general, dataDir will never be null for normal applications. It can only happen in
- // special cases (for isolated processes which are not associated with any app). These are
- // launched by the framework and should not be emulated anyway.
- use_native_bridge = false;
- ALOGW("Native bridge will not be used because dataDir == NULL.");
+ // dataDir should never be null if we need to use a native bridge.
+ // In general, dataDir will never be null for normal applications. It can only happen in
+ // special cases (for isolated processes which are not associated with any app). These are
+ // launched by the framework and should not be emulated anyway.
+ use_native_bridge = false;
+ ALOGW("Native bridge will not be used because dataDir == NULL.");
}
+#endif
if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) {
ALOGW("Failed to mount emulated storage: %s", strerror(errno));
if (use_native_bridge) {
ScopedUtfChars isa_string(env, instructionSet);
- ScopedUtfChars data_dir(env, dataDir);
- android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
+#ifdef _COMPATIBILITY_ENHANCEMENT_PACKAGE_
+ if (dataDir != NULL) {
+#endif
+ ScopedUtfChars data_dir(env, dataDir);
+ android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
+#ifdef _COMPATIBILITY_ENHANCEMENT_PACKAGE_
+ } else {
+ android::PreInitializeNativeBridge(NULL, isa_string.c_str());
+ }
+#endif
}
int rc = setresgid(gid, gid, gid);
} 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) {