Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 25641ca1 authored by Amith Yamasani's avatar Amith Yamasani Committed by Android (Google) Code Review
Browse files

Merge "Plumbing in PackageManager and installd for multi-user support."

parents 08d1f937 0b285499
Loading
Loading
Loading
Loading
+38 −7
Original line number Diff line number Diff line
@@ -78,15 +78,15 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
    return 0;
}

int uninstall(const char *pkgname)
int uninstall(const char *pkgname, uid_t persona)
{
    char pkgdir[PKG_PATH_MAX];

    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0))
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
        return -1;

    /* delete contents AND directory, no exceptions */
    return delete_dir_contents(pkgdir, 1, 0);
    return delete_dir_contents(pkgdir, 1, NULL);
}

int renamepkg(const char *oldpkgname, const char *newpkgname)
@@ -106,17 +106,48 @@ int renamepkg(const char *oldpkgname, const char *newpkgname)
    return 0;
}

int delete_user_data(const char *pkgname)
int delete_user_data(const char *pkgname, uid_t persona)
{
    char pkgdir[PKG_PATH_MAX];

    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0))
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
        return -1;

    /* delete contents, excluding "lib", but not the directory itself */
    return delete_dir_contents(pkgdir, 0, "lib");
}

int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
{
    char pkgdir[PKG_PATH_MAX];
    char real_libdir[PKG_PATH_MAX];

    // Create the data dir for the package
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
        return -1;
    }
    if (mkdir(pkgdir, 0751) < 0) {
        LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
        return -errno;
    }
    if (chown(pkgdir, uid, uid) < 0) {
        LOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
        unlink(pkgdir);
        return -errno;
    }
    return 0;
}

int delete_persona(uid_t persona)
{
    char pkgdir[PKG_PATH_MAX];

    if (create_persona_path(pkgdir, persona))
        return -1;

    return delete_dir_contents(pkgdir, 1, NULL);
}

int delete_cache(const char *pkgname)
{
    char cachedir[PKG_PATH_MAX];
+58 −5
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@ static int do_rm_dex(char **arg, char reply[REPLY_MAX])

static int do_remove(char **arg, char reply[REPLY_MAX])
{
    return uninstall(arg[0]); /* pkgname */
    return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */
}

static int do_rename(char **arg, char reply[REPLY_MAX])
@@ -92,7 +92,17 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])

static int do_rm_user_data(char **arg, char reply[REPLY_MAX])
{
    return delete_user_data(arg[0]); /* pkgname */
    return delete_user_data(arg[0], atoi(arg[1])); /* pkgname, userid */
}

static int do_mk_user_data(char **arg, char reply[REPLY_MAX])
{
    return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, userid */
}

static int do_rm_user(char **arg, char reply[REPLY_MAX])
{
    return delete_persona(atoi(arg[0])); /* userid */
}

static int do_movefiles(char **arg, char reply[REPLY_MAX])
@@ -122,16 +132,18 @@ struct cmdinfo cmds[] = {
    { "dexopt",               3, do_dexopt },
    { "movedex",              2, do_move_dex },
    { "rmdex",                1, do_rm_dex },
    { "remove",               1, do_remove },
    { "remove",               2, do_remove },
    { "rename",               2, do_rename },
    { "freecache",            1, do_free_cache },
    { "rmcache",              1, do_rm_cache },
    { "protect",              2, do_protect },
    { "getsize",              3, do_get_size },
    { "rmuserdata",           1, do_rm_user_data },
    { "rmuserdata",           2, do_rm_user_data },
    { "movefiles",            0, do_movefiles },
    { "linklib",              2, do_linklib },
    { "unlinklib",            1, do_unlinklib },
    { "mkuserdata",           3, do_mk_user_data },
    { "rmuser",               1, do_rm_user },
};

static int readx(int s, void *_buf, int count)
@@ -286,14 +298,50 @@ int initialize_globals() {
        return -1;
    }

    // append "app/" to dirs[0]
    char *system_app_path = build_string2(android_system_dirs.dirs[0].path, APP_SUBDIR);
    android_system_dirs.dirs[0].path = system_app_path;
    android_system_dirs.dirs[0].len = strlen(system_app_path);

    // vendor
    // TODO replace this with an environment variable (doesn't exist yet)
    android_system_dirs.dirs[1].path = "/vendor/";
    android_system_dirs.dirs[1].path = "/vendor/app/";
    android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);

    return 0;
}

int initialize_directories() {
    // /data/user
    char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
    // /data/data
    char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
    // /data/user/0
    char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX,
            "0");
    int ret = -1;
    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, 0755) < 0) {
                return -1;
            }
            if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 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;
}

int main(const int argc, const char *argv[]) {
    char buf[BUFFER_MAX];
    struct sockaddr addr;
@@ -305,6 +353,11 @@ int main(const int argc, const char *argv[]) {
        exit(1);
    }

    if (initialize_directories() < 0) {
        LOGE("Could not create directories; exiting.\n");
        exit(1);
    }

    lsocket = android_get_control_socket(SOCKET_PATH);
    if (lsocket < 0) {
        LOGE("Failed to get socket from environment: %s\n", strerror(errno));
+10 −2
Original line number Diff line number Diff line
@@ -102,6 +102,9 @@ int create_pkg_path(char path[PKG_PATH_MAX],
                    const char *postfix,
                    uid_t persona);

int create_persona_path(char path[PKG_PATH_MAX],
                    uid_t persona);

int is_valid_package_name(const char* pkgname);

int create_cache_path(char path[PKG_PATH_MAX], const char *src);
@@ -124,12 +127,17 @@ int validate_apk_path(const char *path);

int append_and_increment(char** dst, const char* src, size_t* dst_size);

char *build_string2(char *s1, char *s2);
char *build_string3(char *s1, char *s2, char *s3);

/* commands.c */

int install(const char *pkgname, uid_t uid, gid_t gid);
int uninstall(const char *pkgname);
int uninstall(const char *pkgname, uid_t persona);
int renamepkg(const char *oldpkgname, const char *newpkgname);
int delete_user_data(const char *pkgname);
int delete_user_data(const char *pkgname, uid_t persona);
int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
int delete_persona(uid_t persona);
int delete_cache(const char *pkgname);
int move_dex(const char *src, const char *dst);
int rm_dex(const char *path);
+72 −0
Original line number Diff line number Diff line
@@ -95,6 +95,46 @@ int create_pkg_path(char path[PKG_PATH_MAX],
    return create_pkg_path_in_dir(path, &dir, pkgname, postfix);
}

/**
 * Create the path name for user data for a certain persona.
 * Returns 0 on success, and -1 on failure.
 */
int create_persona_path(char path[PKG_PATH_MAX],
                    uid_t persona)
{
    size_t uid_len;
    char* persona_prefix;
    if (persona == 0) {
        persona_prefix = PRIMARY_USER_PREFIX;
        uid_len = 0;
    } else {
        persona_prefix = SECONDARY_USER_PREFIX;
        uid_len = snprintf(NULL, 0, "%d", persona);
    }

    char *dst = path;
    size_t dst_size = PKG_PATH_MAX;

    if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
            || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
        LOGE("Error building prefix for user path");
        return -1;
    }

    if (persona != 0) {
        if (dst_size < uid_len + 1) {
            LOGE("Error building user path");
            return -1;
        }
        int ret = snprintf(dst, dst_size, "%d", persona);
        if (ret < 0 || (size_t) ret != uid_len) {
            LOGE("Error appending persona id to path");
            return -1;
        }
    }
    return 0;
}

/**
 * Checks whether the package name is valid. Returns -1 on error and
 * 0 on success.
@@ -408,3 +448,35 @@ int append_and_increment(char** dst, const char* src, size_t* dst_size) {
    *dst_size -= ret;
    return 0;
}

char *build_string2(char *s1, char *s2) {
    if (s1 == NULL || s2 == NULL) return NULL;

    int len_s1 = strlen(s1);
    int len_s2 = strlen(s2);
    int len = len_s1 + len_s2 + 1;
    char *result = malloc(len);
    if (result == NULL) return NULL;

    strcpy(result, s1);
    strcpy(result + len_s1, s2);

    return result;
}

char *build_string3(char *s1, char *s2, char *s3) {
    if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;

    int len_s1 = strlen(s1);
    int len_s2 = strlen(s2);
    int len_s3 = strlen(s3);
    int len = len_s1 + len_s2 + len_s3 + 1;
    char *result = malloc(len);
    if (result == NULL) return NULL;

    strcpy(result, s1);
    strcpy(result + len_s1, s2);
    strcpy(result + len_s1 + len_s2, s3);

    return result;
}
+71 −1
Original line number Diff line number Diff line
@@ -35,9 +35,9 @@ import android.content.pm.PermissionInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.provider.Settings;

import java.io.File;
import java.lang.reflect.Field;
@@ -60,6 +60,7 @@ public final class Pm {

    private static final String PM_NOT_RUNNING_ERR =
        "Error: Could not access the Package Manager.  Is the system running?";
    private static final int ROOT_UID = 0;

    public static void main(String[] args) {
        new Pm().run(args);
@@ -127,6 +128,16 @@ public final class Pm {
            return;
        }

        if ("createUser".equals(op)) {
            runCreateUser();
            return;
        }

        if ("removeUser".equals(op)) {
            runRemoveUser();
            return;
        }

        try {
            if (args.length == 1) {
                if (args[0].equalsIgnoreCase("-l")) {
@@ -763,6 +774,63 @@ public final class Pm {
        }
    }

    public void runCreateUser() {
        // Need to be run as root
        if (Process.myUid() != ROOT_UID) {
            System.err.println("Error: createUser must be run as root");
            return;
        }
        String name;
        String arg = nextArg();
        if (arg == null) {
            System.err.println("Error: no user name specified.");
            showUsage();
            return;
        }
        name = arg;
        try {
            if (mPm.createUser(name, 0) == null) {
                System.err.println("Error: couldn't create user.");
                showUsage();
            }
        } catch (RemoteException e) {
            System.err.println(e.toString());
            System.err.println(PM_NOT_RUNNING_ERR);
        }

    }

    public void runRemoveUser() {
        // Need to be run as root
        if (Process.myUid() != ROOT_UID) {
            System.err.println("Error: removeUser must be run as root");
            return;
        }
        int userId;
        String arg = nextArg();
        if (arg == null) {
            System.err.println("Error: no user id specified.");
            showUsage();
            return;
        }
        try {
            userId = Integer.parseInt(arg);
        } catch (NumberFormatException e) {
            System.err.println("Error: user id has to be a number.");
            showUsage();
            return;
        }
        try {
            if (!mPm.removeUser(userId)) {
                System.err.println("Error: couldn't remove user.");
                showUsage();
            }
        } catch (RemoteException e) {
            System.err.println(e.toString());
            System.err.println(PM_NOT_RUNNING_ERR);
        }
    }

    class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
        boolean finished;
        boolean result;
@@ -1006,6 +1074,8 @@ public final class Pm {
        System.err.println("       pm enable PACKAGE_OR_COMPONENT");
        System.err.println("       pm disable PACKAGE_OR_COMPONENT");
        System.err.println("       pm setInstallLocation [0/auto] [1/internal] [2/external]");
        System.err.println("       pm createUser USER_NAME");
        System.err.println("       pm removeUser USER_ID");
        System.err.println("");
        System.err.println("The list packages command prints all packages, optionally only");
        System.err.println("those whose package name contains the text in FILTER.  Options:");
Loading