X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=core%2Fjni%2Fcom_android_internal_os_Zygote.cpp;h=041ed0c611b6c7dcbdb8b0b1bed92b8e28da84cb;hb=b2fa297fdb3bb0cc15093fdb43e68a6005d4afa6;hp=b431a3f487fad4711822dde707f9a5b5cb2a082e;hpb=70c958c414204b195d4195cdcafe33932087e6b1;p=android-x86%2Fframeworks-base.git diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index b431a3f487fa..041ed0c611b6 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 + // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc #include #include @@ -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; @@ -303,9 +312,6 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode, 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"; @@ -439,6 +445,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 +462,36 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra 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) { @@ -462,27 +501,58 @@ 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."); + } + + 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)); @@ -515,8 +585,16 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra 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); @@ -594,11 +672,11 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra } 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; } @@ -647,12 +725,24 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( 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) {