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

Commit 86c95845 authored by Kenny Root's avatar Kenny Root
Browse files

Update installd to allow multiuser

* Add ability to select different personas to generate the path to be
  created.

* Move hardcoded paths to read from init's set environment.

* Add unit tests for all the utility functions that build strings to
  make sure they're correct.

* Fill in persona with "0" all the time now. Will be plumbed through in
  later CL.

Change-Id: I0a7f6e3640cb6b052f8823080886ee79e90b679f
parent 7f5a026d
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
ifneq ($(TARGET_SIMULATOR),true)

LOCAL_PATH := $(call my-dir)

common_src_files := \
    commands.c utils.c

#
# Static library used in testing and executable
#

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
    installd.c commands.c utils.c
    $(common_src_files)

LOCAL_MODULE := libinstalld

LOCAL_MODULE_TAGS := eng tests

#LOCAL_C_INCLUDES := \
#    $(call include-path-for, system-core)/cutils
include $(BUILD_STATIC_LIBRARY)

#
# Executable
#

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
    installd.c \
    $(common_src_files)

LOCAL_SHARED_LIBRARIES := \
    libcutils
+42 −62
Original line number Diff line number Diff line
@@ -17,6 +17,13 @@
#include "installd.h"
#include <diskusage/dirsize.h>

/* Directory records that are used in execution of commands. */
dir_rec_t android_data_dir;
dir_rec_t android_asec_dir;
dir_rec_t android_app_dir;
dir_rec_t android_app_private_dir;
dir_rec_array_t android_system_dirs;

int install(const char *pkgname, uid_t uid, gid_t gid)
{
    char pkgdir[PKG_PATH_MAX];
@@ -27,10 +34,15 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
        return -1;
    }

    if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX))
    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
        LOGE("cannot create package path\n");
        return -1;
    if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX))
    }

    if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
        LOGE("cannot create package lib path\n");
        return -1;
    }

    if (mkdir(pkgdir, 0751) < 0) {
        LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
@@ -59,7 +71,7 @@ int uninstall(const char *pkgname)
{
    char pkgdir[PKG_PATH_MAX];

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

        /* delete contents AND directory, no exceptions */
@@ -71,9 +83,9 @@ int renamepkg(const char *oldpkgname, const char *newpkgname)
    char oldpkgdir[PKG_PATH_MAX];
    char newpkgdir[PKG_PATH_MAX];

    if (create_pkg_path(oldpkgdir, PKG_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX))
    if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
        return -1;
    if (create_pkg_path(newpkgdir, PKG_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX))
    if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
        return -1;

    if (rename(oldpkgdir, newpkgdir) < 0) {
@@ -87,7 +99,7 @@ int delete_user_data(const char *pkgname)
{
    char pkgdir[PKG_PATH_MAX];

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

        /* delete contents, excluding "lib", but not the directory itself */
@@ -98,7 +110,7 @@ int delete_cache(const char *pkgname)
{
    char cachedir[PKG_PATH_MAX];

    if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX))
    if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
        return -1;

        /* delete contents, not the directory, no exceptions */
@@ -108,10 +120,10 @@ int delete_cache(const char *pkgname)
static int64_t disk_free()
{
    struct statfs sfs;
    if (statfs(PKG_DIR_PREFIX, &sfs) == 0) {
    if (statfs(android_data_dir.path, &sfs) == 0) {
        return sfs.f_bavail * sfs.f_bsize;
    } else {
        LOGE("Couldn't statfs " PKG_DIR_PREFIX ": %s\n", strerror(errno));
        LOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
        return -1;
    }
}
@@ -137,9 +149,9 @@ int free_cache(int64_t free_size)
    LOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
    if (avail >= free_size) return 0;

    d = opendir(PKG_DIR_PREFIX);
    d = opendir(android_data_dir.path);
    if (d == NULL) {
        LOGE("cannot open %s: %s\n", PKG_DIR_PREFIX, strerror(errno));
        LOGE("cannot open %s: %s\n", android_data_dir.path, strerror(errno));
        return -1;
    }
    dfd = dirfd(d);
@@ -172,43 +184,13 @@ int free_cache(int64_t free_size)
    return -1;
}

/* used by move_dex, rm_dex, etc to ensure that the provided paths
 * don't point anywhere other than at the APK_DIR_PREFIX
 */
static int is_valid_apk_path(const char *path)
{
    int len = strlen(APK_DIR_PREFIX);
int nosubdircheck = 0;
    if (strncmp(path, APK_DIR_PREFIX, len)) {
        len = strlen(PROTECTED_DIR_PREFIX);
        if (strncmp(path, PROTECTED_DIR_PREFIX, len)) {
            len = strlen(SDCARD_DIR_PREFIX);
            if (strncmp(path, SDCARD_DIR_PREFIX, len)) {
                LOGE("invalid apk path '%s' (bad prefix)\n", path);
                return 0;
            } else {
                nosubdircheck = 1;
            }
        }
    }
    if ((nosubdircheck != 1) && strchr(path + len, '/')) {
        LOGE("invalid apk path '%s' (subdir?)\n", path);
        return 0;
    }
    if (path[len] == '.') {
        LOGE("invalid apk path '%s' (trickery)\n", path);
        return 0;
    }
    return 1;
}

int move_dex(const char *src, const char *dst)
{
    char src_dex[PKG_PATH_MAX];
    char dst_dex[PKG_PATH_MAX];

    if (!is_valid_apk_path(src)) return -1;
    if (!is_valid_apk_path(dst)) return -1;
    if (validate_apk_path(src)) return -1;
    if (validate_apk_path(dst)) return -1;

    if (create_cache_path(src_dex, src)) return -1;
    if (create_cache_path(dst_dex, dst)) return -1;
@@ -226,7 +208,7 @@ int rm_dex(const char *path)
{
    char dex_path[PKG_PATH_MAX];

    if (!is_valid_apk_path(path)) return -1;
    if (validate_apk_path(path)) return -1;
    if (create_cache_path(dex_path, path)) return -1;

    LOGI("unlink %s\n", dex_path);
@@ -245,7 +227,7 @@ int protect(char *pkgname, gid_t gid)

    if (gid < AID_SYSTEM) return -1;

    if (create_pkg_path(pkgpath, PROTECTED_DIR_PREFIX, pkgname, ".apk"))
    if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
        return -1;

    if (stat(pkgpath, &s) < 0) return -1;
@@ -280,8 +262,8 @@ int get_size(const char *pkgname, const char *apkpath,
        /* count the source apk as code -- but only if it's not
         * on the /system partition and its not on the sdcard.
         */
    if (strncmp(apkpath, "/system", 7) != 0 &&
            strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) {
    if (validate_system_app_path(apkpath) &&
            strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
        if (stat(apkpath, &s) == 0) {
            codesize += stat_size(&s);
        }
@@ -300,7 +282,7 @@ int get_size(const char *pkgname, const char *apkpath,
        }
    }

    if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) {
    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
        goto done;
    }

@@ -544,15 +526,15 @@ fail:
}

int create_move_path(char path[PKG_PATH_MAX],
    const char* prefix,
    const char* pkgname,
    const char* leaf)
    const char* leaf,
    uid_t persona)
{
    if ((strlen(prefix) + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) {
    if ((android_data_dir.len + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) {
        return -1;
    }
    
    sprintf(path, "%s%s/%s", prefix, pkgname, leaf);
    sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf);
    return 0;
}

@@ -720,8 +702,8 @@ int movefiles()
                            // Skip -- source package no longer exists.
                        } else {
                            LOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
                            if (!create_move_path(srcpath, PKG_DIR_PREFIX, srcpkg, buf+bufp) &&
                                    !create_move_path(dstpath, PKG_DIR_PREFIX, dstpkg, buf+bufp)) {
                            if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
                                    !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
                                movefileordir(srcpath, dstpath,
                                        strlen(dstpath)-strlen(buf+bufp),
                                        dstuid, dstgid, &s);
@@ -750,8 +732,7 @@ int movefiles()
                                        UPDATE_COMMANDS_DIR_PREFIX, name, div);
                            }
                            if (srcpkg[0] != 0) {
                                if (!create_pkg_path(srcpath, PKG_DIR_PREFIX, srcpkg,
                                        PKG_DIR_POSTFIX)) {
                                if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
                                    if (lstat(srcpath, &s) < 0) {
                                        // Package no longer exists -- skip.
                                        srcpkg[0] = 0;
@@ -762,8 +743,7 @@ int movefiles()
                                            div, UPDATE_COMMANDS_DIR_PREFIX, name);
                                }
                                if (srcpkg[0] != 0) {
                                    if (!create_pkg_path(dstpath, PKG_DIR_PREFIX, dstpkg,
                                            PKG_DIR_POSTFIX)) {
                                    if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
                                        if (lstat(dstpath, &s) == 0) {
                                            dstuid = s.st_uid;
                                            dstgid = s.st_gid;
+66 −2
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@
#define TOKEN_MAX     8     /* max number of arguments in buffer */
#define REPLY_MAX     256   /* largest reply allowed */


static int do_ping(char **arg, char reply[REPLY_MAX])
{
    return 0;
@@ -235,12 +234,77 @@ done:
    return 0;
}

/**
 * Initialize all the global variables that are used elsewhere. Returns 0 upon
 * success and -1 on error.
 */
void free_globals() {
    size_t i;

    for (i = 0; i < android_system_dirs.count; i++) {
        if (android_system_dirs.dirs[i].path != NULL) {
            free(android_system_dirs.dirs[i].path);
        }
    }

    free(android_system_dirs.dirs);
}

int initialize_globals() {
    // Get the android data directory.
    if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) {
        return -1;
    }

    // Get the android app directory.
    if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
        return -1;
    }

    // Get the android protected app directory.
    if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
        return -1;
    }

    // Get the sd-card ASEC mount point.
    if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) {
        return -1;
    }

    // Take note of the system and vendor directories.
    android_system_dirs.count = 2;

    android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t));
    if (android_system_dirs.dirs == NULL) {
        LOGE("Couldn't allocate array for dirs; aborting\n");
        return -1;
    }

    // system
    if (get_path_from_env(&android_system_dirs.dirs[0], "ANDROID_ROOT") < 0) {
        free_globals();
        return -1;
    }

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

    return 0;
}

int main(const int argc, const char *argv[]) {
    char buf[BUFFER_MAX];
    struct sockaddr addr;
    socklen_t alen;
    int lsocket, s, count;

    if (initialize_globals() < 0) {
        LOGE("Could not initialize globals; 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));
+45 −10
Original line number Diff line number Diff line
@@ -49,21 +49,20 @@

/* elements combined with a valid package name to form paths */

#define PKG_DIR_PREFIX         "/data/data/"
#define PRIMARY_USER_PREFIX    "data/"
#define SECONDARY_USER_PREFIX  "user/"

#define PKG_DIR_POSTFIX        ""

#define PKG_LIB_PREFIX         "/data/data/"
#define PKG_LIB_POSTFIX        "/lib"

#define CACHE_DIR_PREFIX       "/data/data/"
#define CACHE_DIR_POSTFIX      "/cache"

#define APK_DIR_PREFIX         "/data/app/"
#define APP_SUBDIR             "app/" // sub-directory under ANDROID_DATA

/* other handy constants */

#define PROTECTED_DIR_PREFIX  "/data/app-private/"
#define SDCARD_DIR_PREFIX  getenv("ASEC_MOUNTPOINT")
#define PRIVATE_APP_SUBDIR     "app-private/" // sub-directory under ANDROID_DATA

#define DALVIK_CACHE_PREFIX    "/data/dalvik-cache/"
#define DALVIK_CACHE_POSTFIX   "/classes.dex"
@@ -73,14 +72,38 @@
#define PKG_NAME_MAX  128   /* largest allowed package name */
#define PKG_PATH_MAX  256   /* max size of any path we use */

/* data structures */

typedef struct {
    char* path;
    size_t len;
} dir_rec_t;

typedef struct {
    size_t count;
    dir_rec_t* dirs;
} dir_rec_array_t;

extern dir_rec_t android_app_dir;
extern dir_rec_t android_app_private_dir;
extern dir_rec_t android_data_dir;
extern dir_rec_t android_asec_dir;
extern dir_rec_array_t android_system_dirs;

/* util.c */

int create_pkg_path(char path[PKG_PATH_MAX],
                    const char *prefix,
int create_pkg_path_in_dir(char path[PKG_PATH_MAX],
                                const dir_rec_t* dir,
                                const char* pkgname,
                                const char* postfix);

int create_pkg_path(char path[PKG_PATH_MAX],
                    const char *pkgname,
                    const char *postfix,
                    uid_t persona);

int is_valid_package_name(const char* pkgname);

int create_cache_path(char path[PKG_PATH_MAX], const char *src);

int delete_dir_contents(const char *pathname,
@@ -89,6 +112,18 @@ int delete_dir_contents(const char *pathname,

int delete_dir_contents_fd(int dfd, const char *name);

int validate_system_app_path(const char* path);

int get_path_from_env(dir_rec_t* rec, const char* var);

int get_path_from_string(dir_rec_t* rec, const char* path);

int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);

int validate_apk_path(const char *path);

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

/* commands.c */

int install(const char *pkgname, uid_t uid, gid_t gid);
+42 −0
Original line number Diff line number Diff line
# Build the unit tests for installd
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

ifneq ($(TARGET_SIMULATOR),true)

# Build the unit tests.
test_src_files := \
    installd_utils_test.cpp

shared_libraries := \
    libutils \
    libcutils \
    libstlport

static_libraries := \
    libinstalld \
    libdiskusage \
    libgtest \
    libgtest_main

c_includes := \
    frameworks/base/cmds/installd \
    bionic \
    bionic/libstdc++/include \
    external/gtest/include \
    external/stlport/stlport

module_tags := eng tests

$(foreach file,$(test_src_files), \
    $(eval include $(CLEAR_VARS)) \
    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
    $(eval LOCAL_SRC_FILES := $(file)) \
    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
    $(eval include $(BUILD_EXECUTABLE)) \
)

endif
Loading