Port multi-user support to art.

Disabled for now, but will blow up in the right place as soon as our
tree has the rest of the support.

Change-Id: I668176784a2a855c3d22236dc57df53b7fd3ae67
diff --git a/src/native/dalvik_system_Zygote.cc b/src/native/dalvik_system_Zygote.cc
index 4fb8397..fbd0d10 100644
--- a/src/native/dalvik_system_Zygote.cc
+++ b/src/native/dalvik_system_Zygote.cc
@@ -18,6 +18,7 @@
 #include <paths.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <sys/mount.h>
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
@@ -47,6 +48,13 @@
 
 static pid_t gSystemServerPid = 0;
 
+// Must match values in dalvik.system.Zygote.
+enum MountExternalKind {
+  MOUNT_EXTERNAL_NONE = 0,
+  MOUNT_EXTERNAL_SINGLEUSER = 1,
+  MOUNT_EXTERNAL_MULTIUSER = 2,
+};
+
 static void Zygote_nativeExecShell(JNIEnv* env, jclass, jstring javaCommand) {
   ScopedUtfChars command(env, javaCommand);
   if (command.c_str() == NULL) {
@@ -288,10 +296,52 @@
   }
 }
 
+// Create private mount space for this process and mount SD card
+// into it, based on the active user.
+static void MountExternalStorage(uid_t uid, jint mount_external) {
+  if (mount_external == MOUNT_EXTERNAL_NONE) {
+    return;
+  }
+
+#if 0
+  userid_t user_id = multiuser_getUserId(uid);
+
+  // Create private mount namespace for our process.
+  if (unshare(CLONE_NEWNS) == -1) {
+    PLOG(FATAL) << "unshare(CLONE_NEWNS) failed";
+  }
+
+  // Mark rootfs as being a slave in our process so that changes
+  // from parent namespace flow into our process.
+  if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) {
+    PLOG(FATAL) << "mount(\"rootfs\", \"/\", NULL, (MS_SLAVE | MS_REC), NULL) failed";
+  }
+
+  // Create bind mount from specific path.
+  if (mount_external == MOUNT_EXTERNAL_SINGLEUSER) {
+    if (mount(EXTERNAL_STORAGE_SYSTEM, EXTERNAL_STORAGE_APP, "none", MS_BIND, NULL) == -1) {
+      PLOG(FATAL) << "mount(\"" << EXTERNAL_STORAGE_SYSTEM << "\", \"" << EXTERNAL_STORAGE_APP << "\", \"none\", MS_BIND, NULL) failed";
+    }
+  } else if (mount_external == MOUNT_EXTERNAL_MULTIUSER) {
+    // Assume path has already been created by installd.
+    std::string source_path(StringPrintf("%s/%d", EXTERNAL_STORAGE_SYSTEM, user_id));
+    if (mount(source_path.c_str(), EXTERNAL_STORAGE_APP, "none", MS_BIND, NULL) == -1) {
+      PLOG(FATAL) << "mount(\"" << source_path.c_str() << "\", \"" << EXTERNAL_STORAGE_APP << "\", \"none\", MS_BIND, NULL) failed";
+    }
+  } else {
+    LOG(FATAL) << "Mount mode unsupported: " << mount_external;
+  }
+#else
+  UNUSED(uid);
+  UNIMPLEMENTED(FATAL);
+#endif
+}
+
 // 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,
                                      jlong permittedCapabilities, jlong effectiveCapabilities,
+                                     jint mount_external,
                                      jstring java_se_info, jstring java_se_name, bool is_system_server) {
   Runtime* runtime = Runtime::Current();
   CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
@@ -316,6 +366,8 @@
       EnableKeepCapabilities();
     }
 
+    MountExternalStorage(uid, mount_external);
+
     SetGids(env, javaGids);
 
     SetRLimits(env, javaRlimits);
@@ -376,9 +428,9 @@
 }
 
 static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
-                                           jint debug_flags, jobjectArray rlimits,
+                                           jint debug_flags, jobjectArray rlimits, jint mount_external,
                                            jstring se_info, jstring se_name) {
-  return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, se_info, se_name, false);
+  return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external, se_info, se_name, false);
 }
 
 static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
@@ -386,7 +438,8 @@
                                           jlong permittedCapabilities, jlong effectiveCapabilities) {
   pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
                                       debug_flags, rlimits,
-                                      permittedCapabilities, effectiveCapabilities, NULL, NULL, true);
+                                      permittedCapabilities, effectiveCapabilities,
+                                      MOUNT_EXTERNAL_NONE, NULL, NULL, true);
   if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       LOG(INFO) << "System server process " << pid << " has been created";
@@ -405,7 +458,7 @@
 static JNINativeMethod gMethods[] = {
   NATIVE_METHOD(Zygote, nativeExecShell, "(Ljava/lang/String;)V"),
   //NATIVE_METHOD(Zygote, nativeFork, "()I"),
-  NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[ILjava/lang/String;Ljava/lang/String;)I"),
+  NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[IILjava/lang/String;Ljava/lang/String;)I"),
   NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
 };