OSDN Git Service

Merge tag 'android-6.0.1_r79' into marshmallow-x86
[android-x86/frameworks-base.git] / core / jni / com_android_internal_os_Zygote.cpp
index 2bfeadb..041ed0c 100644 (file)
 
 #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 <list>
+#include <string>
+
 #include <fcntl.h>
 #include <grp.h>
 #include <inttypes.h>
+#include <mntent.h>
 #include <paths.h>
 #include <signal.h>
 #include <stdlib.h>
@@ -49,6 +55,7 @@
 #include "ScopedLocalRef.h"
 #include "ScopedPrimitiveArray.h"
 #include "ScopedUtfChars.h"
+#include "fd_utils-inl.h"
 
 #include "nativebridge/native_bridge.h"
 
@@ -65,20 +72,34 @@ static jmethodID gCallPostForkChildHooks;
 // Must match values in com.android.internal.os.Zygote.
 enum MountExternalKind {
   MOUNT_EXTERNAL_NONE = 0,
-  MOUNT_EXTERNAL_SINGLEUSER = 1,
-  MOUNT_EXTERNAL_MULTIUSER = 2,
-  MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
+  MOUNT_EXTERNAL_DEFAULT = 1,
+  MOUNT_EXTERNAL_READ = 2,
+  MOUNT_EXTERNAL_WRITE = 3,
 };
 
 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;
   int status;
 
+  // It's necessary to save and restore the errno during this function.
+  // Since errno is stored per thread, changing it here modifies the errno
+  // on the thread on which this signal handler executes. If a signal occurs
+  // between a call and an errno check, it's possible to get the errno set
+  // here.
+  // See b/23572286 for extra information.
+  int saved_errno = errno;
+
   while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
      // Log process-death status that we care about.  In general it is
      // not safe to call LOG(...) from a signal handler because of
@@ -114,6 +135,8 @@ static void SigChldHandler(int /*signal_number*/) {
   if (pid < 0 && errno != ECHILD) {
     ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
   }
+
+  errno = saved_errno;
 }
 
 // Configures the SIGCHLD handler for the zygote process. This is configured
@@ -249,81 +272,76 @@ static void SetSchedulerPolicy(JNIEnv* env) {
   }
 }
 
-// Create a private mount namespace and bind mount appropriate emulated
-// storage for the given user.
-static bool MountEmulatedStorage(uid_t uid, jint mount_mode, bool force_mount_namespace) {
-  if (mount_mode == MOUNT_EXTERNAL_NONE && !force_mount_namespace) {
-    return true;
-  }
-
-  // Create a second private mount namespace for our process
-  if (unshare(CLONE_NEWNS) == -1) {
-      ALOGW("Failed to unshare(): %s", strerror(errno));
-      return false;
-  }
+static int UnmountTree(const char* path) {
+    size_t path_len = strlen(path);
 
-  if (mount_mode == MOUNT_EXTERNAL_NONE) {
-    return true;
-  }
-
-  // See storage config details at http://source.android.com/tech/storage/
-  userid_t user_id = multiuser_get_user_id(uid);
+    FILE* fp = setmntent("/proc/mounts", "r");
+    if (fp == NULL) {
+        ALOGE("Error opening /proc/mounts: %s", strerror(errno));
+        return -errno;
+    }
 
-  // Create bind mounts to expose external storage
-  if (mount_mode == MOUNT_EXTERNAL_MULTIUSER || mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
-    // These paths must already be created by init.rc
-    const char* source = getenv("EMULATED_STORAGE_SOURCE");
-    const char* target = getenv("EMULATED_STORAGE_TARGET");
-    const char* legacy = getenv("EXTERNAL_STORAGE");
-    if (source == NULL || target == NULL || legacy == NULL) {
-      ALOGW("Storage environment undefined; unable to provide external storage");
-      return false;
+    // Some volumes can be stacked on each other, so force unmount in
+    // reverse order to give us the best chance of success.
+    std::list<std::string> toUnmount;
+    mntent* mentry;
+    while ((mentry = getmntent(fp)) != NULL) {
+        if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
+            toUnmount.push_front(std::string(mentry->mnt_dir));
+        }
     }
+    endmntent(fp);
 
-    // Prepare source paths
+    for (auto path : toUnmount) {
+        if (umount2(path.c_str(), MNT_DETACH)) {
+            ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
+        }
+    }
+    return 0;
+}
 
-    // /mnt/shell/emulated/0
-    const String8 source_user(String8::format("%s/%d", source, user_id));
-    // /storage/emulated/0
-    const String8 target_user(String8::format("%s/%d", target, user_id));
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
+        bool force_mount_namespace) {
+    // See storage config details at http://source.android.com/tech/storage/
 
-    if (fs_prepare_dir(source_user.string(), 0000, 0, 0) == -1
-        || fs_prepare_dir(target_user.string(), 0000, 0, 0) == -1) {
-      return false;
+    // Create a second private mount namespace for our process
+    if (unshare(CLONE_NEWNS) == -1) {
+        ALOGW("Failed to unshare(): %s", strerror(errno));
+        return false;
     }
 
-    if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
-      // Mount entire external storage tree for all users
-      if (TEMP_FAILURE_RETRY(mount(source, target, NULL, MS_BIND, NULL)) == -1) {
-        ALOGW("Failed to mount %s to %s: %s", source, target, strerror(errno));
-        return false;
-      }
+    String8 storageSource;
+    if (mount_mode == MOUNT_EXTERNAL_DEFAULT) {
+        storageSource = "/mnt/runtime/default";
+    } else if (mount_mode == MOUNT_EXTERNAL_READ) {
+        storageSource = "/mnt/runtime/read";
+    } else if (mount_mode == MOUNT_EXTERNAL_WRITE) {
+        storageSource = "/mnt/runtime/write";
     } else {
-      // Only mount user-specific external storage
-      if (TEMP_FAILURE_RETRY(mount(source_user.string(), target_user.string(), NULL,
-                                   MS_BIND, NULL)) == -1) {
-        ALOGW("Failed to mount %s to %s: %s", source_user.string(), target_user.string(),
-              strerror(errno));
+        // Sane default of no storage visible
+        return true;
+    }
+    if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
+            NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
+        ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
         return false;
-      }
     }
 
-    if (fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+    // Mount user-specific symlink helper into place
+    userid_t user_id = multiuser_get_user_id(uid);
+    const String8 userSource(String8::format("/mnt/user/%d", user_id));
+    if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
         return false;
     }
-
-    // Finally, mount user-specific path into place for legacy users
-    if (TEMP_FAILURE_RETRY(
-            mount(target_user.string(), legacy, NULL, MS_BIND | MS_REC, NULL)) == -1) {
-      ALOGW("Failed to mount %s to %s: %s", target_user.string(), legacy, strerror(errno));
-      return false;
+    if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
+            NULL, MS_BIND, NULL)) == -1) {
+        ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno));
+        return false;
     }
-  } else {
-    ALOGW("Mount mode %d unsupported", mount_mode);
-    return false;
-  }
 
-  return true;
+    return true;
 }
 
 static bool NeedsNoRandomizeWorkaround() {
@@ -406,6 +424,30 @@ void SetThreadName(const char* thread_name) {
   }
 }
 
+#ifdef ENABLE_SCHED_BOOST
+static void SetForkLoad(bool boost) {
+  // set scheduler knob to boost forked processes
+  pid_t currentPid = getpid();
+  // fits at most "/proc/XXXXXXX/sched_init_task_load\0"
+  char schedPath[35];
+  snprintf(schedPath, sizeof(schedPath), "/proc/%u/sched_init_task_load", currentPid);
+  int schedBoostFile = open(schedPath, O_WRONLY);
+  if (schedBoostFile < 0) {
+    ALOGW("Unable to set zygote scheduler boost");
+    return;
+  }
+  if (boost) {
+    write(schedBoostFile, "100\0", 4);
+  } else {
+    write(schedBoostFile, "0\0", 2);
+  }
+  close(schedBoostFile);
+}
+#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,
@@ -416,6 +458,40 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
                                      jstring instructionSet, jstring dataDir) {
   SetSigChldHandler();
 
+#ifdef ENABLE_SCHED_BOOST
+  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) {
@@ -425,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));
@@ -478,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);
@@ -556,6 +671,12 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra
     }
   } else if (pid > 0) {
     // the parent process
+
+    // 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;
 }
@@ -586,7 +707,7 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer(
   pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                       debug_flags, rlimits,
                                       permittedCapabilities, effectiveCapabilities,
-                                      MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
+                                      MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true, NULL,
                                       NULL, NULL);
   if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
@@ -604,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) {