Tracking rebase to jb-mr1-release
Change-Id: Ic2ae1a27682cc4152003a68d59068b2c5c5eb09b
diff --git a/src/native/dalvik_system_Zygote.cc b/src/native/dalvik_system_Zygote.cc
index d33c67f..9b995f4 100644
--- a/src/native/dalvik_system_Zygote.cc
+++ b/src/native/dalvik_system_Zygote.cc
@@ -14,15 +14,20 @@
* limitations under the License.
*/
+// 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 <grp.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
-#include <sys/mount.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
+#include "cutils/fs.h"
+#include "cutils/multiuser.h"
#include "cutils/sched_policy.h"
#include "debugger.h"
#include "jni_internal.h"
@@ -53,6 +58,7 @@
MOUNT_EXTERNAL_NONE = 0,
MOUNT_EXTERNAL_SINGLEUSER = 1,
MOUNT_EXTERNAL_MULTIUSER = 2,
+ MOUNT_EXTERNAL_MULTIUSER_ALL = 3,
};
// This signal handler is for zygote mode, since the zygote must reap its children
@@ -303,45 +309,91 @@
}
}
-// 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;
+// Create a private mount namespace and bind mount appropriate emulated
+// storage for the given user.
+static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
+ if (mount_mode == MOUNT_EXTERNAL_NONE) {
+ return true;
}
-#if 0
- userid_t user_id = multiuser_getUserId(uid);
+ // See storage config details at http://source.android.com/tech/storage/
+ userid_t user_id = multiuser_get_user_id(uid);
- // Create private mount namespace for our process.
+ // Create a second private mount namespace for our process
if (unshare(CLONE_NEWNS) == -1) {
- PLOG(FATAL) << "unshare(CLONE_NEWNS) failed";
+ PLOG(WARNING) << "Failed to unshare()";
+ return false;
}
- // 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";
+ // 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) {
+ LOG(WARNING) << "Storage environment undefined; unable to provide external storage";
+ return false;
}
- } 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";
+
+ // Prepare source paths
+
+ // /mnt/shell/emulated/0
+ std::string source_user(StringPrintf("%s/%d", source, user_id));
+ // /mnt/shell/emulated/obb
+ std::string source_obb(StringPrintf("%s/obb", source));
+ // /storage/emulated/0
+ std::string target_user(StringPrintf("%s/%d", target, user_id));
+
+ if (fs_prepare_dir(source_user.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(source_obb.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(target_user.c_str(), 0000, 0, 0) == -1) {
+ return false;
+ }
+
+ if (mount_mode == MOUNT_EXTERNAL_MULTIUSER_ALL) {
+ // Mount entire external storage tree for all users
+ if (mount(source, target, NULL, MS_BIND, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << source << " to " << target;
+ return false;
+ }
+ } else {
+ // Only mount user-specific external storage
+ if (mount(source_user.c_str(), target_user.c_str(), NULL, MS_BIND, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << source_user << " to " << target_user;
+ return false;
+ }
+ }
+
+ // Now that user is mounted, prepare and mount OBB storage
+ // into place for current user
+
+ // /storage/emulated/0/Android
+ std::string target_android(StringPrintf("%s/%d/Android", target, user_id));
+ // /storage/emulated/0/Android/obb
+ std::string target_obb(StringPrintf("%s/%d/Android/obb", target, user_id));
+
+ if (fs_prepare_dir(target_android.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(target_obb.c_str(), 0000, 0, 0) == -1
+ || fs_prepare_dir(legacy, 0000, 0, 0) == -1) {
+ return false;
+ }
+ if (mount(source_obb.c_str(), target_obb.c_str(), NULL, MS_BIND, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << source_obb << " to " << target_obb;
+ return false;
+ }
+
+ // Finally, mount user-specific path into place for legacy users
+ if (mount(target_user.c_str(), legacy, NULL, MS_BIND | MS_REC, NULL) == -1) {
+ PLOG(WARNING) << "Failed to mount " << target_user << " to " << legacy;
+ return false;
}
} else {
- LOG(FATAL) << "Mount mode unsupported: " << mount_external;
+ LOG(WARNING) << "Mount mode " << mount_mode << " unsupported";
+ return false;
}
-#else
- UNUSED(uid);
- UNIMPLEMENTED(FATAL);
-#endif
+
+ return true;
}
#if defined(__linux__)
@@ -397,7 +449,18 @@
DropCapabilitiesBoundingSet();
- MountExternalStorage(uid, mount_external);
+ if (!MountEmulatedStorage(uid, mount_external)) {
+ PLOG(WARNING) << "Failed to mount emulated storage";
+ if (errno == ENOTCONN || errno == EROFS) {
+ // When device is actively encrypting, we get ENOTCONN here
+ // since FUSE was mounted before the framework restarted.
+ // When encrypted device is booting, we get EROFS since
+ // FUSE hasn't been created yet by init.
+ // In either case, continue without external storage.
+ } else {
+ LOG(FATAL) << "Cannot continue without emulated storage";
+ }
+ }
SetGids(env, javaGids);