Offer to move both code and data together.

We now move code under /data/app/com.example when a complete move
is requested.  This really only works for new cluster-style installs
that also have native libraries and OAT contained inside.

Teach measuring code about cluster-style installs when measuring
app footprint.  Also offer to measure private data space for all
users.

Bug: 19993667, 20275578
Change-Id: I6df7b947cb5cc8a4552f56f4b64a661e8512389f
This commit is contained in:
Jeff Sharkey 2015-04-30 15:58:19 -07:00
parent 7a6c586161
commit d792118c49
5 changed files with 201 additions and 98 deletions

View File

@ -50,7 +50,7 @@ int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const c
return -1;
}
std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
@ -80,7 +80,7 @@ int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const c
int uninstall(const char *uuid, const char *pkgname, userid_t userid)
{
std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
remove_profile_file(pkgname);
@ -115,7 +115,7 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid)
return -1;
}
std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (stat(pkgdir, &s) < 0) return -1;
@ -141,7 +141,7 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid)
int delete_user_data(const char *uuid, const char *pkgname, userid_t userid)
{
std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
return delete_dir_contents(pkgdir, 0, NULL);
@ -149,7 +149,7 @@ int delete_user_data(const char *uuid, const char *pkgname, userid_t userid)
int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
{
std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
@ -177,15 +177,48 @@ int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t us
return 0;
}
int move_user_data(const char *from_uuid, const char *to_uuid,
const char *package_name, appid_t appid, const char* seinfo) {
int move_complete_app(const char *from_uuid, const char *to_uuid,
const char *package_name, const char *data_app_name, appid_t appid,
const char* seinfo) {
std::vector<userid_t> users = get_known_users(from_uuid);
// Copy package private data for all known users
// Copy app
{
std::string from(create_data_app_package_path(from_uuid, data_app_name));
std::string to(create_data_app_package_path(to_uuid, data_app_name));
std::string to_parent(create_data_app_path(to_uuid));
char *argv[] = {
(char*) kCpPath,
(char*) "-F", /* delete any existing destination file first (--remove-destination) */
(char*) "-p", /* preserve timestamps, ownership, and permissions */
(char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
(char*) "-P", /* Do not follow symlinks [default] */
(char*) "-d", /* don't dereference symlinks */
(char*) from.c_str(),
(char*) to_parent.c_str()
};
LOG(DEBUG) << "Copying " << from << " to " << to;
int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
if (rc != 0) {
LOG(ERROR) << "Failed copying " << from << " to " << to
<< ": status " << rc;
goto fail;
}
if (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
LOG(ERROR) << "Failed to restorecon " << to;
goto fail;
}
}
// Copy private data for all known users
for (auto user : users) {
std::string from(create_package_data_path(from_uuid, package_name, user));
std::string to(create_package_data_path(to_uuid, package_name, user));
std::string to_user(create_data_user_path(to_uuid, user));
std::string from(create_data_user_package_path(from_uuid, user, package_name));
std::string to(create_data_user_package_path(to_uuid, user, package_name));
std::string to_parent(create_data_user_path(to_uuid, user));
// Data source may not exist for all users; that's okay
if (access(from.c_str(), F_OK) != 0) {
@ -213,7 +246,7 @@ int move_user_data(const char *from_uuid, const char *to_uuid,
(char*) "-P", /* Do not follow symlinks [default] */
(char*) "-d", /* don't dereference symlinks */
(char*) from.c_str(),
(char*) to_user.c_str()
(char*) to_parent.c_str()
};
LOG(DEBUG) << "Copying " << from << " to " << to;
@ -231,9 +264,15 @@ int move_user_data(const char *from_uuid, const char *to_uuid,
}
}
// Copy successful, so delete old data
// Delete old app and data
{
std::string from(create_data_app_package_path(from_uuid, data_app_name));
if (delete_dir_contents(from.c_str(), 1, NULL) != 0) {
LOG(WARNING) << "Failed to delete " << from;
}
}
for (auto user : users) {
std::string from(create_package_data_path(from_uuid, package_name, user));
std::string from(create_data_user_package_path(from_uuid, user, package_name));
if (delete_dir_contents(from.c_str(), 1, NULL) != 0) {
LOG(WARNING) << "Failed to delete " << from;
}
@ -242,8 +281,14 @@ int move_user_data(const char *from_uuid, const char *to_uuid,
fail:
// Nuke everything we might have already copied
{
std::string to(create_data_app_package_path(to_uuid, data_app_name));
if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
}
for (auto user : users) {
std::string to(create_package_data_path(to_uuid, package_name, user));
std::string to(create_data_user_package_path(to_uuid, user, package_name));
if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
@ -289,7 +334,7 @@ int delete_user(const char *uuid, userid_t userid)
int delete_cache(const char *uuid, const char *pkgname, userid_t userid)
{
std::string _cachedir(
create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
create_data_user_package_path(uuid, userid, pkgname) + CACHE_DIR_POSTFIX);
const char* cachedir = _cachedir.c_str();
/* delete contents, not the directory, no exceptions */
@ -299,7 +344,7 @@ int delete_cache(const char *uuid, const char *pkgname, userid_t userid)
int delete_code_cache(const char *uuid, const char *pkgname, userid_t userid)
{
std::string _codecachedir(
create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
create_data_user_package_path(uuid, userid, pkgname) + CACHE_DIR_POSTFIX);
const char* codecachedir = _codecachedir.c_str();
struct stat s;
@ -454,7 +499,7 @@ int rm_dex(const char *path, const char *instruction_set)
}
}
int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath,
int get_size(const char *uuid, const char *pkgname, int userid, const char *apkpath,
const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath,
const char *instruction_set, int64_t *_codesize, int64_t *_datasize,
int64_t *_cachesize, int64_t* _asecsize)
@ -470,30 +515,38 @@ int get_size(const char *uuid, const char *pkgname, userid_t userid, const char
int64_t cachesize = 0;
int64_t asecsize = 0;
/* count the source apk as code -- but only if it's not
* on the /system partition and its not on the sdcard.
*/
/* count the source apk as code -- but only if it's not
* on the /system partition and its not on the sdcard. */
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);
if (S_ISDIR(s.st_mode)) {
d = opendir(apkpath);
if (d != NULL) {
dfd = dirfd(d);
codesize += calculate_dir_size(dfd);
closedir(d);
}
}
}
}
/* count the forward locked apk as code if it is given
*/
/* count the forward locked apk as code if it is given */
if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
if (stat(fwdlock_apkpath, &s) == 0) {
codesize += stat_size(&s);
}
}
/* count the cached dexfile as code */
/* count the cached dexfile as code */
if (!create_cache_path(path, apkpath, instruction_set)) {
if (stat(path, &s) == 0) {
codesize += stat_size(&s);
}
}
/* add in size of any libraries */
/* add in size of any libraries */
if (libdirpath != NULL && libdirpath[0] != '!') {
d = opendir(libdirpath);
if (d != NULL) {
@ -503,68 +556,76 @@ int get_size(const char *uuid, const char *pkgname, userid_t userid, const char
}
}
/* compute asec size if it is given
*/
/* compute asec size if it is given */
if (asecpath != NULL && asecpath[0] != '!') {
if (stat(asecpath, &s) == 0) {
asecsize += stat_size(&s);
}
}
std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
const char* pkgdir = _pkgdir.c_str();
d = opendir(pkgdir);
if (d == NULL) {
goto done;
std::vector<userid_t> users;
if (userid == -1) {
users = get_known_users(uuid);
} else {
users.push_back(userid);
}
dfd = dirfd(d);
/* most stuff in the pkgdir is data, except for the "cache"
* directory and below, which is cache, and the "lib" directory
* and below, which is code...
*/
while ((de = readdir(d))) {
const char *name = de->d_name;
for (auto user : users) {
std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (de->d_type == DT_DIR) {
int subfd;
int64_t statsize = 0;
int64_t dirsize = 0;
/* always skip "." and ".." */
if (name[0] == '.') {
if (name[1] == 0) continue;
if ((name[1] == '.') && (name[2] == 0)) continue;
}
if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
statsize = stat_size(&s);
}
subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
if (subfd >= 0) {
dirsize = calculate_dir_size(subfd);
}
if(!strcmp(name,"lib")) {
codesize += dirsize + statsize;
} else if(!strcmp(name,"cache")) {
cachesize += dirsize + statsize;
d = opendir(pkgdir);
if (d == NULL) {
PLOG(WARNING) << "Failed to open " << pkgdir;
continue;
}
dfd = dirfd(d);
/* most stuff in the pkgdir is data, except for the "cache"
* directory and below, which is cache, and the "lib" directory
* and below, which is code...
*/
while ((de = readdir(d))) {
const char *name = de->d_name;
if (de->d_type == DT_DIR) {
int subfd;
int64_t statsize = 0;
int64_t dirsize = 0;
/* always skip "." and ".." */
if (name[0] == '.') {
if (name[1] == 0) continue;
if ((name[1] == '.') && (name[2] == 0)) continue;
}
if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
statsize = stat_size(&s);
}
subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
if (subfd >= 0) {
dirsize = calculate_dir_size(subfd);
}
if(!strcmp(name,"lib")) {
codesize += dirsize + statsize;
} else if(!strcmp(name,"cache")) {
cachesize += dirsize + statsize;
} else {
datasize += dirsize + statsize;
}
} else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
// This is the symbolic link to the application's library
// code. We'll count this as code instead of data, since
// it is not something that the app creates.
if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
codesize += stat_size(&s);
}
} else {
datasize += dirsize + statsize;
}
} else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
// This is the symbolic link to the application's library
// code. We'll count this as code instead of data, since
// it is not something that the app creates.
if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
codesize += stat_size(&s);
}
} else {
if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
datasize += stat_size(&s);
if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
datasize += stat_size(&s);
}
}
}
closedir(d);
}
closedir(d);
done:
*_codesize = codesize;
*_datasize = datasize;
*_cachesize = cachesize;
@ -1448,7 +1509,7 @@ int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int u
struct stat s, libStat;
int rc = 0;
std::string _pkgdir(create_package_data_path(uuid, pkgname, userId));
std::string _pkgdir(create_data_user_package_path(uuid, userId, pkgname));
std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
const char* pkgdir = _pkgdir.c_str();
@ -1639,7 +1700,7 @@ int restorecon_data(const char* uuid, const char* pkgName,
// Special case for owner on internal storage
if (uuid == nullptr) {
std::string path(create_package_data_path(nullptr, pkgName, 0));
std::string path(create_data_user_package_path(nullptr, 0, pkgName));
if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) {
PLOG(ERROR) << "restorecon failed for " << path;

View File

@ -124,10 +124,10 @@ static int do_rm_user_data(char **arg, char reply[REPLY_MAX] __unused)
return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
static int do_mv_user_data(char **arg, char reply[REPLY_MAX] __unused)
static int do_mv_complete_app(char **arg, char reply[REPLY_MAX] __unused)
{
// from_uuid, to_uuid, pkgname, appid, seinfo
return move_user_data(parse_null(arg[0]), parse_null(arg[1]), arg[2], atoi(arg[3]), arg[4]);
// from_uuid, to_uuid, package_name, data_app_name, appid, seinfo
return move_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3], atoi(arg[4]), arg[5]);
}
static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused)
@ -200,7 +200,7 @@ struct cmdinfo cmds[] = {
{ "rmcodecache", 3, do_rm_code_cache },
{ "getsize", 8, do_get_size },
{ "rmuserdata", 3, do_rm_user_data },
{ "mvuserdata", 5, do_mv_user_data },
{ "mvcompleteapp", 6, do_mv_complete_app },
{ "movefiles", 0, do_movefiles },
{ "linklib", 4, do_linklib },
{ "mkuserdata", 5, do_mk_user_data },

View File

@ -142,10 +142,6 @@ typedef struct {
/* util.c */
// TODO: rename to create_data_user_package_path
std::string create_package_data_path(const char* volume_uuid,
const char* package_name, userid_t user);
int create_pkg_path(char path[PKG_PATH_MAX],
const char *pkgname,
const char *postfix,
@ -153,8 +149,15 @@ int create_pkg_path(char path[PKG_PATH_MAX],
std::string create_data_path(const char* volume_uuid);
std::string create_data_app_path(const char* volume_uuid);
std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
std::string create_data_user_path(const char* volume_uuid, userid_t userid);
std::string create_data_user_package_path(const char* volume_uuid,
userid_t user, const char* package_name);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
std::vector<userid_t> get_known_users(const char* volume_uuid);
@ -221,8 +224,9 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid);
int delete_user_data(const char *uuid, const char *pkgname, userid_t userid);
int make_user_data(const char *uuid, const char *pkgname, uid_t uid,
userid_t userid, const char* seinfo);
int move_user_data(const char* from_uuid, const char *to_uuid,
const char *package_name, appid_t appid, const char* seinfo);
int move_complete_app(const char* from_uuid, const char *to_uuid,
const char *package_name, const char *data_app_name, appid_t appid,
const char* seinfo);
int make_user_config(userid_t userid);
int delete_user(const char *uuid, userid_t userid);
int delete_cache(const char *uuid, const char *pkgname, userid_t userid);
@ -230,9 +234,11 @@ int delete_code_cache(const char *uuid, const char *pkgname, userid_t userid);
int move_dex(const char *src, const char *dst, const char *instruction_set);
int rm_dex(const char *path, const char *instruction_set);
int protect(char *pkgname, gid_t gid);
int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath,
const char *fwdlock_apkpath, const char *asecpath, const char *instruction_set,
int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
int get_size(const char *uuid, const char *pkgname, int userid,
const char *apkpath, const char *libdirpath,
const char *fwdlock_apkpath, const char *asecpath,
const char *instruction_set, int64_t *codesize, int64_t *datasize,
int64_t *cachesize, int64_t *asecsize);
int free_cache(const char *uuid, int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName,
const char *instruction_set, int dexopt_needed, bool vm_safe_mode,

View File

@ -455,6 +455,13 @@ TEST_F(UtilsTest, CreateDataPath) {
create_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
}
TEST_F(UtilsTest, CreateDataAppPath) {
EXPECT_EQ("/data/app", create_data_app_path(nullptr));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app",
create_data_app_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
}
TEST_F(UtilsTest, CreateDataUserPath) {
EXPECT_EQ("/data/data", create_data_user_path(nullptr, 0));
EXPECT_EQ("/data/user/10", create_data_user_path(nullptr, 10));
@ -475,14 +482,21 @@ TEST_F(UtilsTest, CreateDataMediaPath) {
create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
}
TEST_F(UtilsTest, CreatePackageDataPath) {
EXPECT_EQ("/data/data/com.example", create_package_data_path(nullptr, "com.example", 0));
EXPECT_EQ("/data/user/10/com.example", create_package_data_path(nullptr, "com.example", 10));
TEST_F(UtilsTest, CreateDataAppPackagePath) {
EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example"));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example",
create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example"));
}
TEST_F(UtilsTest, CreateDataUserPackagePath) {
EXPECT_EQ("/data/data/com.example", create_data_user_package_path(nullptr, 0, "com.example"));
EXPECT_EQ("/data/user/10/com.example", create_data_user_package_path(nullptr, 10, "com.example"));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0/com.example",
create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 0));
create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10/com.example",
create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 10));
create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
}
}

View File

@ -36,17 +36,32 @@ static bool is_valid_filename(const std::string& name) {
}
}
/**
* Create the path name where package app contents should be stored for
* the given volume UUID and package name. An empty UUID is assumed to
* be internal storage.
*/
std::string create_data_app_package_path(const char* volume_uuid,
const char* package_name) {
CHECK(is_valid_filename(package_name));
CHECK(is_valid_package_name(package_name) == 0);
return StringPrintf("%s/%s",
create_data_app_path(volume_uuid).c_str(), package_name);
}
/**
* Create the path name where package data should be stored for the given
* volume UUID, package name, and user ID. An empty UUID is assumed to be
* internal storage.
*/
std::string create_package_data_path(const char* volume_uuid,
const char* package_name, userid_t user) {
std::string create_data_user_package_path(const char* volume_uuid,
userid_t user, const char* package_name) {
CHECK(is_valid_filename(package_name));
CHECK(is_valid_package_name(package_name) == 0);
return StringPrintf("%s/%s", create_data_user_path(volume_uuid, user).c_str(), package_name);
return StringPrintf("%s/%s",
create_data_user_path(volume_uuid, user).c_str(), package_name);
}
int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
@ -56,7 +71,7 @@ int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
return -1;
}
std::string _tmp(create_package_data_path(nullptr, pkgname, userid) + postfix);
std::string _tmp(create_data_user_package_path(nullptr, userid, pkgname) + postfix);
const char* tmp = _tmp.c_str();
if (strlen(tmp) >= PKG_PATH_MAX) {
path[0] = '\0';
@ -76,6 +91,13 @@ std::string create_data_path(const char* volume_uuid) {
}
}
/**
* Create the path name for app data.
*/
std::string create_data_app_path(const char* volume_uuid) {
return StringPrintf("%s/app", create_data_path(volume_uuid).c_str());
}
/**
* Create the path name for user data for a certain userid.
*/