Themes: Port to CM13 [2/3]

Themes: Forward port installd

Id: I5c03bdca30d55f252d486ddac0355f41623ba8d5

Themes: Remove legacy theme support

Id: I6823a6f2735f07f8e4a25a9c0f6f297577a554ab

Access Themed ResTables from compiled theme apk [2/2]

Before this patch the ResTable for a theme/app was created and
accessed seperate from the compiled APK. Since the compiled APK
has its own copy of the resources.arsc, we can just reuse the table
in the APK instead

Id: Ib7916eba5663db5d077d33fc02623748e8a9f10c

Send target sdk version to aapt [2/2]

If vector drawables are used in a theme we must have a minSdkVersion of 21 passed
to aapt or else aapt will Segfault.

Id: Ib5ffa6d12c91d465f3a603e03b09ab03b02715c7
Change-Id: Ie14322b7efb40b270abd3d4ca1b7c5f97bf4b5ca
This commit is contained in:
Clark Scheff 2014-11-25 12:04:16 -08:00
parent 846c7e9329
commit ea0c03875f
3 changed files with 208 additions and 22 deletions

View File

@ -1601,43 +1601,58 @@ out:
return rc;
}
static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd,
uint32_t target_hash, uint32_t overlay_hash)
{
static const char *IDMAP_BIN = "/system/bin/idmap";
static const size_t MAX_INT_LEN = 32;
char idmap_str[MAX_INT_LEN];
char target_hash_str[MAX_INT_LEN];
char overlay_hash_str[MAX_INT_LEN];
snprintf(idmap_str, sizeof(idmap_str), "%d", idmap_fd);
snprintf(target_hash_str, sizeof(target_hash_str), "%d", target_hash);
snprintf(overlay_hash_str, sizeof(overlay_hash_str), "%d", overlay_hash);
execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str, (char*)NULL);
execl(IDMAP_BIN, IDMAP_BIN, "--fd", target_apk, overlay_apk, idmap_str,
target_hash_str, overlay_hash_str, (char*)NULL);
ALOGE("execl(%s) failed: %s\n", IDMAP_BIN, strerror(errno));
}
// Transform string /a/b/c.apk to (prefix)/a@b@c.apk@(suffix)
// eg /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
/* Prints to idmap_path (prefix)/(flat_target)@(flat_overerlay)@(suffix)
* Note: "Flat" is a string with '/' changed to @
* Example input:
* prefix: /data/resource-cache/
* suffix: idmap
* overlay_path: /data/app/com.theme.apk
* target_path: /data/app/com.target.apk
* Example output:
* idmap_path: /data/resource-cache/data@app@com.target.apk@data@app@theme.apk@idmap
*/
static int flatten_path(const char *prefix, const char *suffix,
const char *overlay_path, char *idmap_path, size_t N)
const char *overlay_path, const char *target_path, char *idmap_path, size_t N)
{
if (overlay_path == NULL || idmap_path == NULL) {
if (overlay_path == NULL || idmap_path == NULL || target_path == NULL) {
return -1;
}
const size_t len_target_path = strlen(target_path);
if (len_target_path < 2 || *target_path != '/') {
return -1;
}
const size_t len_overlay_path = strlen(overlay_path);
// will access overlay_path + 1 further below; requires absolute path
if (len_overlay_path < 2 || *overlay_path != '/') {
return -1;
}
const size_t len_idmap_root = strlen(prefix);
const size_t len_suffix = strlen(suffix);
if (SIZE_MAX - len_idmap_root < len_overlay_path ||
SIZE_MAX - (len_idmap_root + len_overlay_path) < len_suffix) {
// additions below would cause overflow
return -1;
}
if (N < len_idmap_root + len_overlay_path + len_suffix) {
return -1;
}
memset(idmap_path, 0, N);
snprintf(idmap_path, N, "%s%s%s", prefix, overlay_path + 1, suffix);
int len = snprintf(idmap_path, N, "%s%s%s%s", prefix, target_path + 1, overlay_path, suffix);
if (len < 0 || (size_t)len >= N) {
return -1; // error or truncated
}
char *ch = idmap_path + len_idmap_root;
while (*ch != '\0') {
if (*ch == '/') {
@ -1648,14 +1663,15 @@ static int flatten_path(const char *prefix, const char *suffix,
return 0;
}
int idmap(const char *target_apk, const char *overlay_apk, uid_t uid)
int idmap(const char *target_apk, const char *overlay_apk, uid_t uid,
uint32_t target_hash, uint32_t overlay_hash)
{
ALOGV("idmap target_apk=%s overlay_apk=%s uid=%d\n", target_apk, overlay_apk, uid);
int idmap_fd = -1;
char idmap_path[PATH_MAX];
if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk,
if (flatten_path(IDMAP_PREFIX, IDMAP_SUFFIX, overlay_apk, target_apk,
idmap_path, sizeof(idmap_path)) == -1) {
ALOGE("idmap cannot generate idmap path for overlay %s\n", overlay_apk);
goto fail;
@ -1693,7 +1709,7 @@ int idmap(const char *target_apk, const char *overlay_apk, uid_t uid)
exit(1);
}
run_idmap(target_apk, overlay_apk, idmap_fd);
run_idmap(target_apk, overlay_apk, idmap_fd, target_hash, overlay_hash);
exit(1); /* only if exec call to idmap failed */
} else {
int status = wait_child(pid);
@ -1713,6 +1729,161 @@ fail:
return -1;
}
static void run_aapt(const char *source_apk, const char *internal_path,
int resapk_fd, int pkgId, int min_sdk_version, const char *common_res_path)
{
static const char *AAPT_BIN = "/system/bin/aapt";
static const char *MANIFEST = "/data/app/AndroidManifest.xml";
static const char *FRAMEWORK_RES = "/system/framework/framework-res.apk";
static const size_t MAX_INT_LEN = 32;
char resapk_str[MAX_INT_LEN];
char pkgId_str[MAX_INT_LEN];
char minSdkVersion_str[MAX_INT_LEN];
snprintf(resapk_str, sizeof(resapk_str), "%d", resapk_fd);
snprintf(pkgId_str, sizeof(pkgId_str), "%d", pkgId);
snprintf(minSdkVersion_str, sizeof(minSdkVersion_str), "%d", min_sdk_version);
bool hasCommonResources = (common_res_path != NULL && common_res_path[0] != '\0');
if (hasCommonResources) {
execl(AAPT_BIN, AAPT_BIN, "package",
"--min-sdk-version", minSdkVersion_str,
"-M", MANIFEST,
"-S", source_apk,
"-X", internal_path,
"-I", FRAMEWORK_RES,
"-I", common_res_path,
"-r", resapk_str,
"-x", pkgId_str,
(char*)NULL);
} else {
execl(AAPT_BIN, AAPT_BIN, "package",
"--min-sdk-version", minSdkVersion_str,
"-M", MANIFEST,
"-S", source_apk,
"-X", internal_path,
"-I", FRAMEWORK_RES,
"-r", resapk_str,
"-x", pkgId_str,
(char*)NULL);
}
ALOGE("execl(%s) failed: %s\n", AAPT_BIN, strerror(errno));
}
int aapt(const char *source_apk, const char *internal_path, const char *out_restable, uid_t uid,
int pkgId, int min_sdk_version, const char *common_res_path)
{
ALOGD("aapt source_apk=%s internal_path=%s out_restable=%s uid=%d, pkgId=%d, \
min_sdk_version=%d, common_res_path=%s",
source_apk, internal_path, out_restable, uid, pkgId, min_sdk_version, common_res_path);
static const int PARENT_READ_PIPE = 0;
static const int CHILD_WRITE_PIPE = 1;
int resapk_fd = -1;
char restable_path[PATH_MAX];
char resapk_path[PATH_MAX];
int pipefd[2];
pid_t pid = fork();
// get file descriptor for resources.arsc
snprintf(restable_path, PATH_MAX, "%s/resources.arsc", out_restable);
unlink(restable_path);
// get file descriptor for resources.apk
snprintf(resapk_path, PATH_MAX, "%s/resources.apk", out_restable);
unlink(resapk_path);
resapk_fd = open(resapk_path, O_RDWR | O_CREAT | O_EXCL, 0644);
if (resapk_fd < 0) {
ALOGE("aapt cannot open '%s' for output: %s\n", resapk_path, strerror(errno));
goto fail;
}
if (fchown(resapk_fd, AID_SYSTEM, uid) < 0) {
ALOGE("aapt cannot chown '%s'\n", resapk_path);
goto fail;
}
if (fchmod(resapk_fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) < 0) {
ALOGE("aapt cannot chmod '%s'\n", resapk_path);
goto fail;
}
if (pipe(pipefd) != 0) {
pipefd[0] = pipefd[1] = -1;
}
if (pid == 0) {
/* child -- drop privileges before continuing */
if (setgid(uid) != 0) {
ALOGE("setgid(%d) failed during aapt\n", uid);
exit(1);
}
if (setuid(uid) != 0) {
ALOGE("setuid(%d) failed during aapt\n", uid);
exit(1);
}
if (flock(resapk_fd, LOCK_EX | LOCK_NB) != 0) {
ALOGE("flock(%s) failed during aapt: %s\n", out_restable, strerror(errno));
exit(1);
}
if (pipefd[PARENT_READ_PIPE] > 0 && pipefd[CHILD_WRITE_PIPE] > 0) {
close(pipefd[PARENT_READ_PIPE]); // close unused read end
if (dup2(pipefd[CHILD_WRITE_PIPE], STDERR_FILENO) != STDERR_FILENO) {
pipefd[CHILD_WRITE_PIPE] = -1;
}
}
run_aapt(source_apk, internal_path, resapk_fd, pkgId, min_sdk_version, common_res_path);
if (pipefd[CHILD_WRITE_PIPE] > 0) {
close(pipefd[CHILD_WRITE_PIPE]);
}
exit(1); /* only if exec call to idmap failed */
} else {
int status, i;
char buffer[1024];
ssize_t readlen;
if (pipefd[CHILD_WRITE_PIPE] > 0) {
close(pipefd[CHILD_WRITE_PIPE]); // close unused write end
}
if (pipefd[PARENT_READ_PIPE] > 0) {
while ((readlen = read(pipefd[PARENT_READ_PIPE], buffer, sizeof(buffer) - 1)) > 0) {
// in case buffer has more than one string in it, replace '\0' with '\n'
for (i = 0; i < readlen; i++) {
if (buffer[i] == '\0') buffer[i] = '\n';
}
// null terminate buffer at readlen
buffer[readlen] = '\0';
ALOG(LOG_ERROR, "InstallTheme", "%s", buffer);
}
waitpid(pid, &status, 0);
if (pipefd[PARENT_READ_PIPE] > 0) {
close(pipefd[PARENT_READ_PIPE]);
}
} else {
status = wait_child(pid);
}
if (status != 0) {
ALOGE("aapt failed, status=0x%04x\n", status);
goto fail;
}
}
close(resapk_fd);
return 0;
fail:
if (resapk_fd >= 0) {
close(resapk_fd);
unlink(resapk_path);
}
return -1;
}
int restorecon_data(const char* uuid, const char* pkgName,
const char* seinfo, uid_t uid)
{

View File

@ -158,7 +158,17 @@ static int do_linklib(char **arg, char reply[REPLY_MAX] __unused)
static int do_idmap(char **arg, char reply[REPLY_MAX] __unused)
{
return idmap(arg[0], arg[1], atoi(arg[2]));
return idmap(arg[0], arg[1], atoi(arg[2]), atoi(arg[3]), atoi(arg[4]));
}
static int do_aapt(char **arg, char reply[REPLY_MAX] __unused)
{
return aapt(arg[0], arg[1], arg[2], atoi(arg[3]), atoi(arg[4]), atoi(arg[5]), "");
}
static int do_aapt_with_common(char **arg, char reply[REPLY_MAX] __unused)
{
return aapt(arg[0], arg[1], arg[2], atoi(arg[3]), atoi(arg[4]), atoi(arg[5]), arg[6]);
}
static int do_restorecon_data(char **arg, char reply[REPLY_MAX] __attribute__((unused)))
@ -212,7 +222,9 @@ struct cmdinfo cmds[] = {
{ "mkuserdata", 5, do_mk_user_data },
{ "mkuserconfig", 1, do_mk_user_config },
{ "rmuser", 2, do_rm_user },
{ "idmap", 3, do_idmap },
{ "idmap", 5, do_idmap },
{ "aapt", 6, do_aapt },
{ "aapt_with_common", 7, do_aapt_with_common },
{ "restorecondata", 4, do_restorecon_data },
{ "createoatdir", 2, do_create_oat_dir },
{ "rmpackagedir", 1, do_rm_package_dir },

View File

@ -247,7 +247,10 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName,
int mark_boot_complete(const char *instruction_set);
int movefiles();
int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId);
int idmap(const char *target_path, const char *overlay_path, uid_t uid);
int idmap(const char *target_path, const char *overlay_path, uid_t uid,
uint32_t target_hash, uint32_t overlay_hash);
int aapt(const char *source_apk, const char *internal_path, const char *out_restable, uid_t uid,
int pkgId, int min_sdk_version, const char *common_res_path);
int restorecon_data(const char *uuid, const char* pkgName, const char* seinfo, uid_t uid);
int create_oat_dir(const char* oat_dir, const char *instruction_set);
int rm_package_dir(const char* apk_path);