Skip to content

Commit c584b65

Browse files
jsharkeyAndroid (Google) Code Review
authored andcommitted
Merge "Multi-user external storage support." into jb-mr1-dev
2 parents a579f79 + 5b1ada2 commit c584b65

File tree

7 files changed

+206
-37
lines changed

7 files changed

+206
-37
lines changed

cmds/installd/commands.c

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,18 +213,30 @@ int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
213213

214214
int delete_persona(uid_t persona)
215215
{
216-
char pkgdir[PKG_PATH_MAX];
216+
char data_path[PKG_PATH_MAX];
217+
if (create_persona_path(data_path, persona)) {
218+
return -1;
219+
}
220+
if (delete_dir_contents(data_path, 1, NULL)) {
221+
return -1;
222+
}
217223

218-
if (create_persona_path(pkgdir, persona))
224+
char media_path[PATH_MAX];
225+
if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
226+
return -1;
227+
}
228+
if (delete_dir_contents(media_path, 1, NULL) == -1) {
219229
return -1;
230+
}
220231

221-
return delete_dir_contents(pkgdir, 1, NULL);
232+
return 0;
222233
}
223234

224235
int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
225236
{
226237
char src_data_dir[PKG_PATH_MAX];
227238
char pkg_path[PKG_PATH_MAX];
239+
char media_path[PATH_MAX];
228240
DIR *d;
229241
struct dirent *de;
230242
struct stat s;
@@ -233,6 +245,9 @@ int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
233245
if (create_persona_path(src_data_dir, src_persona)) {
234246
return -1;
235247
}
248+
if (create_persona_media_path(media_path, (userid_t) target_persona) == -1) {
249+
return -1;
250+
}
236251

237252
d = opendir(src_data_dir);
238253
if (d != NULL) {
@@ -260,6 +275,11 @@ int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
260275
}
261276
closedir(d);
262277
}
278+
279+
// ensure /data/media/<user_id> exists
280+
if (ensure_dir(media_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
281+
return -1;
282+
}
263283
return 0;
264284
}
265285

cmds/installd/installd.c

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -331,37 +331,109 @@ int initialize_globals() {
331331
}
332332

333333
int initialize_directories() {
334+
int res = -1;
335+
int version = 0;
336+
FILE* file;
337+
338+
// Read current filesystem layout version to handle upgrade paths
339+
char version_path[PATH_MAX];
340+
if (snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path) > PATH_MAX) {
341+
return -1;
342+
}
343+
file = fopen(version_path, "r");
344+
if (file != NULL) {
345+
fscanf(file, "%d", &version);
346+
fclose(file);
347+
}
348+
334349
// /data/user
335350
char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
336351
// /data/data
337352
char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
338353
// /data/user/0
339-
char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX,
340-
"0");
341-
int ret = -1;
342-
if (user_data_dir != NULL && primary_data_dir != NULL && legacy_data_dir != NULL) {
343-
ret = 0;
344-
// Make the /data/user directory if necessary
345-
if (access(user_data_dir, R_OK) < 0) {
346-
if (mkdir(user_data_dir, 0711) < 0) {
347-
return -1;
348-
}
349-
if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
350-
return -1;
351-
}
352-
if (chmod(user_data_dir, 0711) < 0) {
353-
return -1;
354+
char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0");
355+
if (!user_data_dir || !legacy_data_dir || !primary_data_dir) {
356+
goto fail;
357+
}
358+
359+
// Make the /data/user directory if necessary
360+
if (access(user_data_dir, R_OK) < 0) {
361+
if (mkdir(user_data_dir, 0711) < 0) {
362+
goto fail;
363+
}
364+
if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
365+
goto fail;
366+
}
367+
if (chmod(user_data_dir, 0711) < 0) {
368+
goto fail;
369+
}
370+
}
371+
// Make the /data/user/0 symlink to /data/data if necessary
372+
if (access(primary_data_dir, R_OK) < 0) {
373+
if (symlink(legacy_data_dir, primary_data_dir)) {
374+
goto fail;
375+
}
376+
}
377+
378+
// /data/media/0
379+
char owner_media_dir[PATH_MAX];
380+
create_persona_media_path(owner_media_dir, 0);
381+
382+
if (version == 0) {
383+
// Introducing multi-user, so migrate /data/media contents into /data/media/0
384+
ALOGD("Migrating /data/media for multi-user");
385+
386+
// /data/media.tmp
387+
char media_tmp_dir[PATH_MAX];
388+
snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path);
389+
390+
// Only copy when upgrade not already in progress
391+
if (access(media_tmp_dir, F_OK) == -1) {
392+
if (rename(android_media_dir.path, media_tmp_dir) == -1) {
393+
ALOGE("Failed to move legacy media path: %s", strerror(errno));
394+
goto fail;
354395
}
355396
}
356-
// Make the /data/user/0 symlink to /data/data if necessary
357-
if (access(primary_data_dir, R_OK) < 0) {
358-
ret = symlink(legacy_data_dir, primary_data_dir);
397+
398+
// Create /data/media again
399+
if (ensure_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
400+
goto fail;
401+
}
402+
403+
// Move any owner data into place
404+
if (access(media_tmp_dir, F_OK) == 0) {
405+
if (rename(media_tmp_dir, owner_media_dir) == -1) {
406+
ALOGE("Failed to move owner media path: %s", strerror(errno));
407+
goto fail;
408+
}
359409
}
360-
free(user_data_dir);
361-
free(legacy_data_dir);
362-
free(primary_data_dir);
410+
version = 1;
363411
}
364-
return ret;
412+
413+
// Ensure /data/media/0 is always ready
414+
if (ensure_dir(owner_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
415+
goto fail;
416+
}
417+
418+
// Persist our current version
419+
file = fopen(version_path, "w");
420+
if (file != NULL) {
421+
fprintf(file, "%d", version);
422+
fsync(fileno(file));
423+
fclose(file);
424+
} else {
425+
ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
426+
goto fail;
427+
}
428+
429+
// Success!
430+
res = 0;
431+
432+
fail:
433+
free(user_data_dir);
434+
free(legacy_data_dir);
435+
free(primary_data_dir);
436+
return res;
365437
}
366438

367439
int main(const int argc, const char *argv[]) {

cmds/installd/installd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <cutils/sockets.h>
3636
#include <cutils/log.h>
3737
#include <cutils/properties.h>
38+
#include <cutils/multiuser.h>
3839

3940
#include <private/android_filesystem_config.h>
4041

@@ -138,6 +139,8 @@ int create_pkg_path(char path[PKG_PATH_MAX],
138139
int create_persona_path(char path[PKG_PATH_MAX],
139140
uid_t persona);
140141

142+
int create_persona_media_path(char path[PKG_PATH_MAX], userid_t userid);
143+
141144
int create_move_path(char path[PKG_PATH_MAX],
142145
const char* pkgname,
143146
const char* leaf,
@@ -180,6 +183,8 @@ int append_and_increment(char** dst, const char* src, size_t* dst_size);
180183
char *build_string2(char *s1, char *s2);
181184
char *build_string3(char *s1, char *s2, char *s3);
182185

186+
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
187+
183188
/* commands.c */
184189

185190
int install(const char *pkgname, uid_t uid, gid_t gid);

cmds/installd/utils.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,17 @@ int create_persona_path(char path[PKG_PATH_MAX],
137137
return 0;
138138
}
139139

140+
/**
141+
* Create the path name for media for a certain persona.
142+
* Returns 0 on success, and -1 on failure.
143+
*/
144+
int create_persona_media_path(char path[PATH_MAX], userid_t userid) {
145+
if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) {
146+
return -1;
147+
}
148+
return 0;
149+
}
150+
140151
int create_move_path(char path[PKG_PATH_MAX],
141152
const char* pkgname,
142153
const char* leaf,
@@ -979,3 +990,42 @@ char *build_string3(char *s1, char *s2, char *s3) {
979990

980991
return result;
981992
}
993+
994+
/* Ensure that directory exists with given mode and owners. */
995+
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
996+
// Check if path needs to be created
997+
struct stat sb;
998+
if (stat(path, &sb) == -1) {
999+
if (errno == ENOENT) {
1000+
goto create;
1001+
} else {
1002+
ALOGE("Failed to stat(%s): %s", path, strerror(errno));
1003+
return -1;
1004+
}
1005+
}
1006+
1007+
// Exists, verify status
1008+
if (sb.st_mode == mode || sb.st_uid == uid || sb.st_gid == gid) {
1009+
return 0;
1010+
} else {
1011+
goto fixup;
1012+
}
1013+
1014+
create:
1015+
if (mkdir(path, mode) == -1) {
1016+
ALOGE("Failed to mkdir(%s): %s", path, strerror(errno));
1017+
return -1;
1018+
}
1019+
1020+
fixup:
1021+
if (chown(path, uid, gid) == -1) {
1022+
ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno));
1023+
return -1;
1024+
}
1025+
if (chmod(path, mode) == -1) {
1026+
ALOGE("Failed to chown(%s, %d): %s", path, mode, strerror(errno));
1027+
return -1;
1028+
}
1029+
1030+
return 0;
1031+
}

core/java/android/os/Process.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,13 @@ public class Process {
376376
public static final ProcessStartResult start(final String processClass,
377377
final String niceName,
378378
int uid, int gid, int[] gids,
379-
int debugFlags, int targetSdkVersion,
379+
int debugFlags, int mountExternal,
380+
int targetSdkVersion,
380381
String seInfo,
381382
String[] zygoteArgs) {
382383
try {
383384
return startViaZygote(processClass, niceName, uid, gid, gids,
384-
debugFlags, targetSdkVersion, seInfo, zygoteArgs);
385+
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
385386
} catch (ZygoteStartFailedEx ex) {
386387
Log.e(LOG_TAG,
387388
"Starting VM process through Zygote failed");
@@ -553,7 +554,8 @@ private static ProcessStartResult startViaZygote(final String processClass,
553554
final String niceName,
554555
final int uid, final int gid,
555556
final int[] gids,
556-
int debugFlags, int targetSdkVersion,
557+
int debugFlags, int mountExternal,
558+
int targetSdkVersion,
557559
String seInfo,
558560
String[] extraArgs)
559561
throws ZygoteStartFailedEx {
@@ -580,6 +582,11 @@ private static ProcessStartResult startViaZygote(final String processClass,
580582
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
581583
argsForZygote.add("--enable-assert");
582584
}
585+
if (mountExternal == Zygote.MOUNT_EXTERNAL_SINGLEUSER) {
586+
argsForZygote.add("--mount-external-singleuser");
587+
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
588+
argsForZygote.add("--mount-external-multiuser");
589+
}
583590
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
584591

585592
//TODO optionally enable debuger

core/java/com/android/internal/os/ZygoteConnection.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,14 @@
1818

1919
import android.net.Credentials;
2020
import android.net.LocalSocket;
21-
import android.os.Build;
2221
import android.os.Process;
22+
import android.os.SELinux;
2323
import android.os.SystemProperties;
2424
import android.util.Log;
2525

2626
import dalvik.system.PathClassLoader;
2727
import dalvik.system.Zygote;
2828

29-
import android.os.SELinux;
30-
3129
import java.io.BufferedReader;
3230
import java.io.DataInputStream;
3331
import java.io.DataOutputStream;
@@ -234,9 +232,9 @@ boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
234232
ZygoteInit.setCloseOnExec(serverPipeFd, true);
235233
}
236234

237-
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
238-
parsedArgs.gids, parsedArgs.debugFlags, rlimits,
239-
parsedArgs.seInfo, parsedArgs.niceName);
235+
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
236+
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
237+
parsedArgs.niceName);
240238
} catch (IOException ex) {
241239
logAndPrintError(newStderr, "Exception creating pipe", ex);
242240
} catch (ErrnoException ex) {
@@ -341,6 +339,9 @@ static class Arguments {
341339
*/
342340
int debugFlags;
343341

342+
/** From --mount-external */
343+
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
344+
344345
/** from --target-sdk-version. */
345346
int targetSdkVersion;
346347
boolean targetSdkVersionSpecified;
@@ -526,6 +527,10 @@ private void parseArgs(String args[])
526527
"Duplicate arg specified");
527528
}
528529
niceName = arg.substring(arg.indexOf('=') + 1);
530+
} else if (arg.equals("--mount-external-singleuser")) {
531+
mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
532+
} else if (arg.equals("--mount-external-multiuser")) {
533+
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
529534
} else {
530535
break;
531536
}

services/java/com/android/server/am/ActivityManagerService.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1980,10 +1980,20 @@ private final void startProcessLocked(ProcessRecord app,
19801980
int uid = app.uid;
19811981

19821982
int[] gids = null;
1983+
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
19831984
if (!app.isolated) {
19841985
try {
1985-
gids = mContext.getPackageManager().getPackageGids(
1986-
app.info.packageName);
1986+
final PackageManager pm = mContext.getPackageManager();
1987+
gids = pm.getPackageGids(app.info.packageName);
1988+
if (pm.checkPermission(
1989+
android.Manifest.permission.READ_EXTERNAL_STORAGE, app.info.packageName)
1990+
== PERMISSION_GRANTED) {
1991+
if (Environment.isExternalStorageEmulated()) {
1992+
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
1993+
} else {
1994+
mountExternal = Zygote.MOUNT_EXTERNAL_SINGLEUSER;
1995+
}
1996+
}
19871997
} catch (PackageManager.NameNotFoundException e) {
19881998
Slog.w(TAG, "Unable to retrieve gids", e);
19891999
}
@@ -2025,7 +2035,7 @@ private final void startProcessLocked(ProcessRecord app,
20252035
// Start the process. It will either succeed and return a result containing
20262036
// the PID of the new process, or else throw a RuntimeException.
20272037
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
2028-
app.processName, uid, uid, gids, debugFlags,
2038+
app.processName, uid, uid, gids, debugFlags, mountExternal,
20292039
app.info.targetSdkVersion, null, null);
20302040

20312041
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();

0 commit comments

Comments
 (0)