Multi-user external storage support.

Emulated external storage always has multi-user support using paths
like "/data/media/<user_id>".  Creates and destroys these paths along
with user data.  Uses new ensure_dir() to create directories while
always ensuring permissions.

Add external storage mount mode to zygote, supporting both single-
and multi-user devices.  For example, devices with physical SD cards
are treated as single-user.  Begin migrating to mount mode instead
of relying on sdcard_r GID to enforce READ_EXTERNAL_STORAGE.

Bug: 6925012
Change-Id: I9b872ded992cd078e2c013567d59f9f0032ec02b
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 93860aa..a3b665a 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -376,12 +376,13 @@
     public static final ProcessStartResult start(final String processClass,
                                   final String niceName,
                                   int uid, int gid, int[] gids,
-                                  int debugFlags, int targetSdkVersion,
+                                  int debugFlags, int mountExternal,
+                                  int targetSdkVersion,
                                   String seInfo,
                                   String[] zygoteArgs) {
         try {
             return startViaZygote(processClass, niceName, uid, gid, gids,
-                    debugFlags, targetSdkVersion, seInfo, zygoteArgs);
+                    debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -553,7 +554,8 @@
                                   final String niceName,
                                   final int uid, final int gid,
                                   final int[] gids,
-                                  int debugFlags, int targetSdkVersion,
+                                  int debugFlags, int mountExternal,
+                                  int targetSdkVersion,
                                   String seInfo,
                                   String[] extraArgs)
                                   throws ZygoteStartFailedEx {
@@ -580,6 +582,11 @@
             if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                 argsForZygote.add("--enable-assert");
             }
+            if (mountExternal == Zygote.MOUNT_EXTERNAL_SINGLEUSER) {
+                argsForZygote.add("--mount-external-singleuser");
+            } else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
+                argsForZygote.add("--mount-external-multiuser");
+            }
             argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
 
             //TODO optionally enable debuger
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index b016e99..1e268c4 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -18,16 +18,14 @@
 
 import android.net.Credentials;
 import android.net.LocalSocket;
-import android.os.Build;
 import android.os.Process;
+import android.os.SELinux;
 import android.os.SystemProperties;
 import android.util.Log;
 
 import dalvik.system.PathClassLoader;
 import dalvik.system.Zygote;
 
-import android.os.SELinux;
-
 import java.io.BufferedReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -234,9 +232,9 @@
                 ZygoteInit.setCloseOnExec(serverPipeFd, true);
             }
 
-            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
-                    parsedArgs.gids, parsedArgs.debugFlags, rlimits,
-                    parsedArgs.seInfo, parsedArgs.niceName);
+            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
+                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
+                    parsedArgs.niceName);
         } catch (IOException ex) {
             logAndPrintError(newStderr, "Exception creating pipe", ex);
         } catch (ErrnoException ex) {
@@ -341,6 +339,9 @@
          */
         int debugFlags;
 
+        /** From --mount-external */
+        int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
+
         /** from --target-sdk-version. */
         int targetSdkVersion;
         boolean targetSdkVersionSpecified;
@@ -526,6 +527,10 @@
                                 "Duplicate arg specified");
                     }
                     niceName = arg.substring(arg.indexOf('=') + 1);
+                } else if (arg.equals("--mount-external-singleuser")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
+                } else if (arg.equals("--mount-external-multiuser")) {
+                    mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
                 } else {
                     break;
                 }