am c584b65b: Merge "Multi-user external storage support." into jb-mr1-dev
* commit 'c584b65b2093396c9a0c9303dab6ff6cb81ac315': Multi-user external storage support.
This commit is contained in:
@@ -213,18 +213,30 @@ int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
|
|||||||
|
|
||||||
int delete_persona(uid_t persona)
|
int delete_persona(uid_t persona)
|
||||||
{
|
{
|
||||||
char pkgdir[PKG_PATH_MAX];
|
char data_path[PKG_PATH_MAX];
|
||||||
|
if (create_persona_path(data_path, persona)) {
|
||||||
if (create_persona_path(pkgdir, persona))
|
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
if (delete_dir_contents(data_path, 1, NULL)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return delete_dir_contents(pkgdir, 1, NULL);
|
char media_path[PATH_MAX];
|
||||||
|
if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (delete_dir_contents(media_path, 1, NULL) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
|
int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
|
||||||
{
|
{
|
||||||
char src_data_dir[PKG_PATH_MAX];
|
char src_data_dir[PKG_PATH_MAX];
|
||||||
char pkg_path[PKG_PATH_MAX];
|
char pkg_path[PKG_PATH_MAX];
|
||||||
|
char media_path[PATH_MAX];
|
||||||
DIR *d;
|
DIR *d;
|
||||||
struct dirent *de;
|
struct dirent *de;
|
||||||
struct stat s;
|
struct stat s;
|
||||||
@@ -233,6 +245,9 @@ int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
|
|||||||
if (create_persona_path(src_data_dir, src_persona)) {
|
if (create_persona_path(src_data_dir, src_persona)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (create_persona_media_path(media_path, (userid_t) target_persona) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
d = opendir(src_data_dir);
|
d = opendir(src_data_dir);
|
||||||
if (d != NULL) {
|
if (d != NULL) {
|
||||||
@@ -260,6 +275,11 @@ int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
|
|||||||
}
|
}
|
||||||
closedir(d);
|
closedir(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure /data/media/<user_id> exists
|
||||||
|
if (ensure_dir(media_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -331,37 +331,109 @@ int initialize_globals() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int initialize_directories() {
|
int initialize_directories() {
|
||||||
|
int res = -1;
|
||||||
|
int version = 0;
|
||||||
|
FILE* file;
|
||||||
|
|
||||||
|
// Read current filesystem layout version to handle upgrade paths
|
||||||
|
char version_path[PATH_MAX];
|
||||||
|
if (snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path) > PATH_MAX) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
file = fopen(version_path, "r");
|
||||||
|
if (file != NULL) {
|
||||||
|
fscanf(file, "%d", &version);
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
// /data/user
|
// /data/user
|
||||||
char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
|
char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
|
||||||
// /data/data
|
// /data/data
|
||||||
char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
|
char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
|
||||||
// /data/user/0
|
// /data/user/0
|
||||||
char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX,
|
char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0");
|
||||||
"0");
|
if (!user_data_dir || !legacy_data_dir || !primary_data_dir) {
|
||||||
int ret = -1;
|
goto fail;
|
||||||
if (user_data_dir != NULL && primary_data_dir != NULL && legacy_data_dir != NULL) {
|
|
||||||
ret = 0;
|
|
||||||
// Make the /data/user directory if necessary
|
|
||||||
if (access(user_data_dir, R_OK) < 0) {
|
|
||||||
if (mkdir(user_data_dir, 0711) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (chmod(user_data_dir, 0711) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Make the /data/user/0 symlink to /data/data if necessary
|
|
||||||
if (access(primary_data_dir, R_OK) < 0) {
|
|
||||||
ret = symlink(legacy_data_dir, primary_data_dir);
|
|
||||||
}
|
|
||||||
free(user_data_dir);
|
|
||||||
free(legacy_data_dir);
|
|
||||||
free(primary_data_dir);
|
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
// Make the /data/user directory if necessary
|
||||||
|
if (access(user_data_dir, R_OK) < 0) {
|
||||||
|
if (mkdir(user_data_dir, 0711) < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (chmod(user_data_dir, 0711) < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make the /data/user/0 symlink to /data/data if necessary
|
||||||
|
if (access(primary_data_dir, R_OK) < 0) {
|
||||||
|
if (symlink(legacy_data_dir, primary_data_dir)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /data/media/0
|
||||||
|
char owner_media_dir[PATH_MAX];
|
||||||
|
create_persona_media_path(owner_media_dir, 0);
|
||||||
|
|
||||||
|
if (version == 0) {
|
||||||
|
// Introducing multi-user, so migrate /data/media contents into /data/media/0
|
||||||
|
ALOGD("Migrating /data/media for multi-user");
|
||||||
|
|
||||||
|
// /data/media.tmp
|
||||||
|
char media_tmp_dir[PATH_MAX];
|
||||||
|
snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path);
|
||||||
|
|
||||||
|
// Only copy when upgrade not already in progress
|
||||||
|
if (access(media_tmp_dir, F_OK) == -1) {
|
||||||
|
if (rename(android_media_dir.path, media_tmp_dir) == -1) {
|
||||||
|
ALOGE("Failed to move legacy media path: %s", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create /data/media again
|
||||||
|
if (ensure_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move any owner data into place
|
||||||
|
if (access(media_tmp_dir, F_OK) == 0) {
|
||||||
|
if (rename(media_tmp_dir, owner_media_dir) == -1) {
|
||||||
|
ALOGE("Failed to move owner media path: %s", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
version = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure /data/media/0 is always ready
|
||||||
|
if (ensure_dir(owner_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persist our current version
|
||||||
|
file = fopen(version_path, "w");
|
||||||
|
if (file != NULL) {
|
||||||
|
fprintf(file, "%d", version);
|
||||||
|
fsync(fileno(file));
|
||||||
|
fclose(file);
|
||||||
|
} else {
|
||||||
|
ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(user_data_dir);
|
||||||
|
free(legacy_data_dir);
|
||||||
|
free(primary_data_dir);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(const int argc, const char *argv[]) {
|
int main(const int argc, const char *argv[]) {
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <cutils/sockets.h>
|
#include <cutils/sockets.h>
|
||||||
#include <cutils/log.h>
|
#include <cutils/log.h>
|
||||||
#include <cutils/properties.h>
|
#include <cutils/properties.h>
|
||||||
|
#include <cutils/multiuser.h>
|
||||||
|
|
||||||
#include <private/android_filesystem_config.h>
|
#include <private/android_filesystem_config.h>
|
||||||
|
|
||||||
@@ -138,6 +139,8 @@ int create_pkg_path(char path[PKG_PATH_MAX],
|
|||||||
int create_persona_path(char path[PKG_PATH_MAX],
|
int create_persona_path(char path[PKG_PATH_MAX],
|
||||||
uid_t persona);
|
uid_t persona);
|
||||||
|
|
||||||
|
int create_persona_media_path(char path[PKG_PATH_MAX], userid_t userid);
|
||||||
|
|
||||||
int create_move_path(char path[PKG_PATH_MAX],
|
int create_move_path(char path[PKG_PATH_MAX],
|
||||||
const char* pkgname,
|
const char* pkgname,
|
||||||
const char* leaf,
|
const char* leaf,
|
||||||
@@ -180,6 +183,8 @@ int append_and_increment(char** dst, const char* src, size_t* dst_size);
|
|||||||
char *build_string2(char *s1, char *s2);
|
char *build_string2(char *s1, char *s2);
|
||||||
char *build_string3(char *s1, char *s2, char *s3);
|
char *build_string3(char *s1, char *s2, char *s3);
|
||||||
|
|
||||||
|
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
|
||||||
/* commands.c */
|
/* commands.c */
|
||||||
|
|
||||||
int install(const char *pkgname, uid_t uid, gid_t gid);
|
int install(const char *pkgname, uid_t uid, gid_t gid);
|
||||||
|
|||||||
@@ -137,6 +137,17 @@ int create_persona_path(char path[PKG_PATH_MAX],
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the path name for media for a certain persona.
|
||||||
|
* Returns 0 on success, and -1 on failure.
|
||||||
|
*/
|
||||||
|
int create_persona_media_path(char path[PATH_MAX], userid_t userid) {
|
||||||
|
if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int create_move_path(char path[PKG_PATH_MAX],
|
int create_move_path(char path[PKG_PATH_MAX],
|
||||||
const char* pkgname,
|
const char* pkgname,
|
||||||
const char* leaf,
|
const char* leaf,
|
||||||
@@ -979,3 +990,42 @@ char *build_string3(char *s1, char *s2, char *s3) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensure that directory exists with given mode and owners. */
|
||||||
|
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
|
||||||
|
// Check if path needs to be created
|
||||||
|
struct stat sb;
|
||||||
|
if (stat(path, &sb) == -1) {
|
||||||
|
if (errno == ENOENT) {
|
||||||
|
goto create;
|
||||||
|
} else {
|
||||||
|
ALOGE("Failed to stat(%s): %s", path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exists, verify status
|
||||||
|
if (sb.st_mode == mode || sb.st_uid == uid || sb.st_gid == gid) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
goto fixup;
|
||||||
|
}
|
||||||
|
|
||||||
|
create:
|
||||||
|
if (mkdir(path, mode) == -1) {
|
||||||
|
ALOGE("Failed to mkdir(%s): %s", path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fixup:
|
||||||
|
if (chown(path, uid, gid) == -1) {
|
||||||
|
ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (chmod(path, mode) == -1) {
|
||||||
|
ALOGE("Failed to chown(%s, %d): %s", path, mode, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -376,12 +376,13 @@ public class Process {
|
|||||||
public static final ProcessStartResult start(final String processClass,
|
public static final ProcessStartResult start(final String processClass,
|
||||||
final String niceName,
|
final String niceName,
|
||||||
int uid, int gid, int[] gids,
|
int uid, int gid, int[] gids,
|
||||||
int debugFlags, int targetSdkVersion,
|
int debugFlags, int mountExternal,
|
||||||
|
int targetSdkVersion,
|
||||||
String seInfo,
|
String seInfo,
|
||||||
String[] zygoteArgs) {
|
String[] zygoteArgs) {
|
||||||
try {
|
try {
|
||||||
return startViaZygote(processClass, niceName, uid, gid, gids,
|
return startViaZygote(processClass, niceName, uid, gid, gids,
|
||||||
debugFlags, targetSdkVersion, seInfo, zygoteArgs);
|
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
|
||||||
} catch (ZygoteStartFailedEx ex) {
|
} catch (ZygoteStartFailedEx ex) {
|
||||||
Log.e(LOG_TAG,
|
Log.e(LOG_TAG,
|
||||||
"Starting VM process through Zygote failed");
|
"Starting VM process through Zygote failed");
|
||||||
@@ -553,7 +554,8 @@ public class Process {
|
|||||||
final String niceName,
|
final String niceName,
|
||||||
final int uid, final int gid,
|
final int uid, final int gid,
|
||||||
final int[] gids,
|
final int[] gids,
|
||||||
int debugFlags, int targetSdkVersion,
|
int debugFlags, int mountExternal,
|
||||||
|
int targetSdkVersion,
|
||||||
String seInfo,
|
String seInfo,
|
||||||
String[] extraArgs)
|
String[] extraArgs)
|
||||||
throws ZygoteStartFailedEx {
|
throws ZygoteStartFailedEx {
|
||||||
@@ -580,6 +582,11 @@ public class Process {
|
|||||||
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
|
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
|
||||||
argsForZygote.add("--enable-assert");
|
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);
|
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
|
||||||
|
|
||||||
//TODO optionally enable debuger
|
//TODO optionally enable debuger
|
||||||
|
|||||||
@@ -18,16 +18,14 @@ package com.android.internal.os;
|
|||||||
|
|
||||||
import android.net.Credentials;
|
import android.net.Credentials;
|
||||||
import android.net.LocalSocket;
|
import android.net.LocalSocket;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
|
import android.os.SELinux;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import dalvik.system.PathClassLoader;
|
import dalvik.system.PathClassLoader;
|
||||||
import dalvik.system.Zygote;
|
import dalvik.system.Zygote;
|
||||||
|
|
||||||
import android.os.SELinux;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
@@ -234,9 +232,9 @@ class ZygoteConnection {
|
|||||||
ZygoteInit.setCloseOnExec(serverPipeFd, true);
|
ZygoteInit.setCloseOnExec(serverPipeFd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
|
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
|
||||||
parsedArgs.gids, parsedArgs.debugFlags, rlimits,
|
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
|
||||||
parsedArgs.seInfo, parsedArgs.niceName);
|
parsedArgs.niceName);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logAndPrintError(newStderr, "Exception creating pipe", ex);
|
logAndPrintError(newStderr, "Exception creating pipe", ex);
|
||||||
} catch (ErrnoException ex) {
|
} catch (ErrnoException ex) {
|
||||||
@@ -341,6 +339,9 @@ class ZygoteConnection {
|
|||||||
*/
|
*/
|
||||||
int debugFlags;
|
int debugFlags;
|
||||||
|
|
||||||
|
/** From --mount-external */
|
||||||
|
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
|
||||||
|
|
||||||
/** from --target-sdk-version. */
|
/** from --target-sdk-version. */
|
||||||
int targetSdkVersion;
|
int targetSdkVersion;
|
||||||
boolean targetSdkVersionSpecified;
|
boolean targetSdkVersionSpecified;
|
||||||
@@ -526,6 +527,10 @@ class ZygoteConnection {
|
|||||||
"Duplicate arg specified");
|
"Duplicate arg specified");
|
||||||
}
|
}
|
||||||
niceName = arg.substring(arg.indexOf('=') + 1);
|
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 {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1980,10 +1980,20 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
int uid = app.uid;
|
int uid = app.uid;
|
||||||
|
|
||||||
int[] gids = null;
|
int[] gids = null;
|
||||||
|
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
|
||||||
if (!app.isolated) {
|
if (!app.isolated) {
|
||||||
try {
|
try {
|
||||||
gids = mContext.getPackageManager().getPackageGids(
|
final PackageManager pm = mContext.getPackageManager();
|
||||||
app.info.packageName);
|
gids = pm.getPackageGids(app.info.packageName);
|
||||||
|
if (pm.checkPermission(
|
||||||
|
android.Manifest.permission.READ_EXTERNAL_STORAGE, app.info.packageName)
|
||||||
|
== PERMISSION_GRANTED) {
|
||||||
|
if (Environment.isExternalStorageEmulated()) {
|
||||||
|
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
|
||||||
|
} else {
|
||||||
|
mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
Slog.w(TAG, "Unable to retrieve gids", e);
|
Slog.w(TAG, "Unable to retrieve gids", e);
|
||||||
}
|
}
|
||||||
@@ -2025,7 +2035,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
|||||||
// Start the process. It will either succeed and return a result containing
|
// Start the process. It will either succeed and return a result containing
|
||||||
// the PID of the new process, or else throw a RuntimeException.
|
// the PID of the new process, or else throw a RuntimeException.
|
||||||
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
|
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
|
||||||
app.processName, uid, uid, gids, debugFlags,
|
app.processName, uid, uid, gids, debugFlags, mountExternal,
|
||||||
app.info.targetSdkVersion, null, null);
|
app.info.targetSdkVersion, null, null);
|
||||||
|
|
||||||
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
|
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
|
||||||
|
|||||||
Reference in New Issue
Block a user