AssetManager: update to use v2 of libandroidfw C api

This commit is contained in:
Mis012 2025-02-21 00:54:55 +01:00
parent ca39c81224
commit d97c3ee048
3 changed files with 179 additions and 143 deletions

View file

@ -27,6 +27,9 @@ enum {
}; };
#undef JAVA_ENUM_CLASS #undef JAVA_ENUM_CLASS
#define JAVA_COOKIE(cookie) (cookie != -1 ? (jint)(cookie + 1) : -1)
#define NATIVE_COOKIE(cookie) (cookie != -1 ? (ApkAssetsCookie)(cookie - 1) : -1)
#define ASSET_DIR "assets/" #define ASSET_DIR "assets/"
char *get_app_data_dir(); char *get_app_data_dir();
@ -114,37 +117,48 @@ JNIEXPORT void JNICALL Java_android_content_res_AssetManager_init(JNIEnv *env, j
.density = /*ACONFIGURATION_DENSITY_MEDIUM*/ 160, .density = /*ACONFIGURATION_DENSITY_MEDIUM*/ 160,
.sdkVersion = 24, .sdkVersion = 24,
}; };
AssetManager_setConfiguration(asset_manager, &config, NULL); AssetManager_setConfiguration(asset_manager, &config);
_SET_LONG_FIELD(this, "mObject", _INTPTR(asset_manager)); _SET_LONG_FIELD(this, "mObject", _INTPTR(asset_manager));
} }
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_addAssetPathNative(JNIEnv *env, jobject this, jstring path) JNIEXPORT void JNICALL Java_android_content_res_AssetManager_native_1setApkAssets(JNIEnv *env, jobject this, jobjectArray paths, int num_assets)
{ {
int32_t cookie;
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
AssetManager_addAssetPath(asset_manager, _CSTRING(path), &cookie, false, false); const struct ApkAssets* apk_assets[num_assets];
return cookie; for (int i = 0; i < num_assets; i++) {
jstring path_jstr = (jstring)((*env)->GetObjectArrayElement(env, paths, i));
const char *path = (*env)->GetStringUTFChars(env, path_jstr, NULL);
if(path[strlen(path) - 1] == '/')
apk_assets[i] = ApkAssets_loadDir(strdup(path));
else
apk_assets[i] = ApkAssets_load(strdup(path), false);
(*env)->ReleaseStringUTFChars(env, path_jstr, path);
}
AssetManager_setApkAssets(asset_manager, apk_assets, num_assets, true, true);
} }
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceValue(JNIEnv *env, jobject this, jint ident, jshort density, jobject outValue, jboolean resolve) JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceValue(JNIEnv *env, jobject this, jint ident, jshort density, jobject outValue, jboolean resolve)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true);
uint32_t resId = ident; uint32_t resId = ident;
struct Res_value value; struct Res_value value;
uint32_t outSpecFlags; uint32_t outSpecFlags;
struct ResTable_config outConfig; struct ResTable_config outConfig;
ssize_t block = ResTable_getResource(res_table, resId, &value, false, density, &outSpecFlags, &outConfig); uint32_t ref;
ApkAssetsCookie cookie = AssetManager_getResource(asset_manager, resId, false, density,
&value, &outConfig, &outSpecFlags);
if (resolve) { if (resolve) {
block = ResTable_resolveReference(res_table, &value, block, &resId, &outSpecFlags, &outConfig); cookie = AssetManager_resolveReference(asset_manager, cookie,
&value, &outConfig,
&outSpecFlags, &ref);
} }
if (block >= 0) { if (cookie >= 0) {
_SET_INT_FIELD(outValue, "type", value.dataType); _SET_INT_FIELD(outValue, "type", value.dataType);
_SET_INT_FIELD(outValue, "data", value.data); _SET_INT_FIELD(outValue, "data", value.data);
_SET_INT_FIELD(outValue, "resourceId", resId); _SET_INT_FIELD(outValue, "resourceId", resId);
_SET_INT_FIELD(outValue, "assetCookie", block); _SET_INT_FIELD(outValue, "assetCookie", JAVA_COOKIE(cookie));
if (value.dataType == TYPE_STRING) { if (value.dataType == TYPE_STRING) {
const struct ResStringPool *string_pool = ResTable_getTableStringBlock(res_table, block); const struct ResStringPool *string_pool = AssetManager_getStringPoolForCookie(asset_manager, cookie);
size_t len; size_t len;
const char16_t *string = ResStringPool_stringAt(string_pool, value.data, &len); const char16_t *string = ResStringPool_stringAt(string_pool, value.data, &len);
_SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", (*env)->NewString(env, string, len)); _SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", (*env)->NewString(env, string, len));
@ -152,22 +166,25 @@ JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceValue(J
_SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", NULL); _SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", NULL);
} }
} }
return block; return JAVA_COOKIE(cookie);
} }
JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_getArrayStringResource(JNIEnv *env, jobject this, jint ident) JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_getArrayStringResource(JNIEnv *env, jobject this, jint ident)
{ {
int i;
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true); const struct ResolvedBag* bag = AssetManager_getBag(asset_manager, ident);
const struct bag_entry *bag; jobjectArray array = (*env)->NewObjectArray(env, bag->entry_count, (*env)->FindClass(env, "java/lang/String"), NULL);
int bag_count = ResTable_lockBag(res_table, ident, &bag); for (int i = 0; i < bag->entry_count; i++) {
jobjectArray array = (*env)->NewObjectArray(env, bag_count, (*env)->FindClass(env, "java/lang/String"), NULL); const struct ResolvedBag_Entry entry = bag->entries[i];
for (i = 0; i < bag_count; i++) { struct Res_value value = entry.value;
struct Res_value value = bag[i].map.value; struct ResTable_config outConfig;
ssize_t block = ResTable_resolveReference(res_table, &value, bag[i].stringBlock, NULL, NULL, NULL); uint32_t outSpecFlags;
uint32_t ref;
ApkAssetsCookie cookie = AssetManager_resolveReference(asset_manager, entry.cookie,
&value, &outConfig,
&outSpecFlags, &ref);
if (value.dataType == TYPE_STRING) { if (value.dataType == TYPE_STRING) {
const struct ResStringPool *string_pool = ResTable_getTableStringBlock(res_table, block); const struct ResStringPool *string_pool = AssetManager_getStringPoolForCookie(asset_manager, cookie);
if (string_pool == NULL) if (string_pool == NULL)
continue; continue;
size_t len; size_t len;
@ -176,49 +193,38 @@ JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_getArrayStr
} }
} }
ResTable_unlockBag(res_table, bag);
return array; return array;
} }
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_getResourceIdentifier(JNIEnv *env, jobject this, jstring name, jstring defType, jstring defPackage) JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_getResourceIdentifier(JNIEnv *env, jobject this, jstring name_jstr, jstring type_jstr, jstring package_jstr)
{ {
const char16_t *name16 = NULL; const char *name = "";
const char16_t *defType16 = NULL; const char *type = "";
const char16_t *defPackage16 = NULL; const char *package = "";
int name_len = 0; uint32_t ret;
int defType_len = 0;
int defPackage_len = 0;
int ret;
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true); if (name_jstr)
if (name) { name = (*env)->GetStringUTFChars(env, name_jstr, NULL);
name16 = (*env)->GetStringChars(env, name, NULL); if (type_jstr)
name_len = (*env)->GetStringLength(env, name); type = (*env)->GetStringUTFChars(env, type_jstr, NULL);
} if (package_jstr)
if (defType) { package = (*env)->GetStringUTFChars(env, package_jstr, NULL);
defType16 = (*env)->GetStringChars(env, defType, NULL);
defType_len = (*env)->GetStringLength(env, defType); ret = AssetManager_getResourceId(asset_manager, name, type, package);
} if (name_jstr)
if (defPackage) { (*env)->ReleaseStringUTFChars(env, name_jstr, name);
defPackage16 = (*env)->GetStringChars(env, defPackage, NULL); if (type_jstr)
defPackage_len = (*env)->GetStringLength(env, defPackage); (*env)->ReleaseStringUTFChars(env, type_jstr, type);
} if (package_jstr)
ret = ResTable_identifierForName(res_table, name16, name_len, defType16, defType_len, defPackage16, defPackage_len, NULL); (*env)->ReleaseStringUTFChars(env, package_jstr, package);
if (name)
(*env)->ReleaseStringChars(env, name, name16);
if (defType)
(*env)->ReleaseStringChars(env, defType, defType16);
if (defPackage)
(*env)->ReleaseStringChars(env, defPackage, defPackage16);
return ret; return ret;
} }
JNIEXPORT jobject JNICALL Java_android_content_res_AssetManager_getPooledString(JNIEnv *env, jobject this, jint block, jint index) JNIEXPORT jobject JNICALL Java_android_content_res_AssetManager_getPooledString(JNIEnv *env, jobject this, jint cookie, jint index)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true); const struct ResStringPool *string_pool = AssetManager_getStringPoolForCookie(asset_manager, NATIVE_COOKIE(cookie));
const struct ResStringPool *string_pool = ResTable_getTableStringBlock(res_table, block);
size_t len; size_t len;
const char16_t *string = ResStringPool_stringAt(string_pool, index, &len); const char16_t *string = ResStringPool_stringAt(string_pool, index, &len);
return (*env)->NewString(env, string, len); return (*env)->NewString(env, string, len);
@ -227,7 +233,7 @@ JNIEXPORT jobject JNICALL Java_android_content_res_AssetManager_getPooledString(
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_newTheme(JNIEnv *env, jobject this) JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_newTheme(JNIEnv *env, jobject this)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
struct Theme *theme = Theme_new(AssetManager_getResources(asset_manager, true)); struct Theme *theme = AssetManager_newTheme(asset_manager);
return _INTPTR(theme); return _INTPTR(theme);
} }
@ -244,23 +250,24 @@ JNIEXPORT void JNICALL Java_android_content_res_AssetManager_applyThemeStyle(JNI
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadThemeAttributeValue(JNIEnv *env, jobject this, jlong theme_ptr, jint ident, jobject outValue, jboolean resolve) JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadThemeAttributeValue(JNIEnv *env, jobject this, jlong theme_ptr, jint ident, jobject outValue, jboolean resolve)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true);
struct Theme *theme = _PTR(theme_ptr); struct Theme *theme = _PTR(theme_ptr);
uint32_t resId = 0;
struct Res_value value; struct Res_value value;
uint32_t outSpecFlags; uint32_t outSpecFlags;
struct ResTable_config outConfig; struct ResTable_config outConfig;
int block = Theme_getAttribute(theme, ident, &value, &outSpecFlags); uint32_t ref;
int cookie = Theme_getAttribute(theme, ident, &value, &outSpecFlags);
if (resolve) { if (resolve) {
block = Theme_resolveAttributeReference(theme, &value, block, &resId, &outSpecFlags, &outConfig); cookie = AssetManager_resolveReference(asset_manager, cookie,
&value, &outConfig,
&outSpecFlags, &ref);
} }
if (block >= 0) { if (cookie >= 0) {
_SET_INT_FIELD(outValue, "type", value.dataType); _SET_INT_FIELD(outValue, "type", value.dataType);
_SET_INT_FIELD(outValue, "data", value.data); _SET_INT_FIELD(outValue, "data", value.data);
_SET_INT_FIELD(outValue, "resourceId", resId); _SET_INT_FIELD(outValue, "resourceId", ref);
_SET_INT_FIELD(outValue, "assetCookie", block); _SET_INT_FIELD(outValue, "assetCookie", JAVA_COOKIE(cookie));
if (value.dataType == TYPE_STRING) { if (value.dataType == TYPE_STRING) {
const struct ResStringPool *string_pool = ResTable_getTableStringBlock(res_table, block); const struct ResStringPool *string_pool = AssetManager_getStringPoolForCookie(asset_manager, cookie);
size_t len; size_t len;
const char16_t *string = ResStringPool_stringAt(string_pool, value.data, &len); const char16_t *string = ResStringPool_stringAt(string_pool, value.data, &len);
_SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", (*env)->NewString(env, string, len)); _SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", (*env)->NewString(env, string, len));
@ -268,7 +275,7 @@ JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadThemeAttributeV
_SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", NULL); _SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", NULL);
} }
} }
return block; return JAVA_COOKIE(cookie);
} }
/* function ported from AOSP - Copyright 2006, The Android Open Source Project */ /* function ported from AOSP - Copyright 2006, The Android Open Source Project */
@ -345,86 +352,120 @@ JNIEXPORT jboolean JNICALL Java_android_content_res_AssetManager_resolveAttrs(JN
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_getArraySize(JNIEnv *env, jobject this, jint ident) JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_getArraySize(JNIEnv *env, jobject this, jint ident)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true); const struct ResolvedBag* bag = AssetManager_getBag(asset_manager, ident);
const struct bag_entry *bag; return bag->entry_count;
int bag_count = ResTable_lockBag(res_table, ident, &bag);
ResTable_unlockBag(res_table, bag);
return bag_count;
} }
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_retrieveArray(JNIEnv *env, jobject this, jint ident, jintArray outArray) JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_retrieveArray(JNIEnv *env, jobject this, jint ident, jintArray outArray)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true);
const struct bag_entry *bag;
int i;
jint *array = (*env)->GetIntArrayElements(env, outArray, NULL); jint *array = (*env)->GetIntArrayElements(env, outArray, NULL);
int bag_count = ResTable_lockBag(res_table, ident, &bag); const struct ResolvedBag* bag = AssetManager_getBag(asset_manager, ident);
for (i = 0; i < bag_count; i++) { for (int i = 0; i < bag->entry_count; i++) {
struct Res_value value = bag[i].map.value; const struct ResolvedBag_Entry entry = bag->entries[i];
uint32_t resId = 0; struct Res_value value = entry.value;
ssize_t block = ResTable_resolveReference(res_table, &value, bag[i].stringBlock, &resId, NULL, NULL); struct ResTable_config outConfig;
uint32_t outSpecFlags;
uint32_t ref;
ApkAssetsCookie cookie = AssetManager_resolveReference(asset_manager, entry.cookie,
&value, &outConfig,
&outSpecFlags, &ref);
array[i*STYLE_NUM_ENTRIES + STYLE_TYPE] = value.dataType; array[i*STYLE_NUM_ENTRIES + STYLE_TYPE] = value.dataType;
array[i*STYLE_NUM_ENTRIES + STYLE_DATA] = value.data; array[i*STYLE_NUM_ENTRIES + STYLE_DATA] = value.data;
array[i*STYLE_NUM_ENTRIES + STYLE_ASSET_COOKIE] = block; array[i*STYLE_NUM_ENTRIES + STYLE_ASSET_COOKIE] = JAVA_COOKIE(cookie);
array[i*STYLE_NUM_ENTRIES + STYLE_RESOURCE_ID] = resId; array[i*STYLE_NUM_ENTRIES + STYLE_RESOURCE_ID] = ref;
} }
ResTable_unlockBag(res_table, bag);
(*env)->ReleaseIntArrayElements(env, outArray, array, 0); (*env)->ReleaseIntArrayElements(env, outArray, array, 0);
return bag_count; return bag->entry_count;
}
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceName(JNIEnv *env, jobject this, jint ident)
{
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
struct resource_name res_name;
gchar *type8 = NULL;
gchar *entry8 = NULL;
bool ret = AssetManager_getResourceName(asset_manager, ident, &res_name);
if(!ret)
return NULL;
if(!res_name.type)
type8 = g_utf16_to_utf8(res_name.type16, res_name.type_len, NULL, NULL, NULL);
if(!res_name.entry)
entry8 = g_utf16_to_utf8(res_name.entry16, res_name.entry_len, NULL, NULL, NULL);
gchar *result = g_strdup_printf("%.*s:%.*s/%.*s",
res_name.package ? (int)res_name.package_len : 0,
res_name.package ?: "",
(res_name.type || type8) ? (int)res_name.type_len : 0,
res_name.type ?: type8 ?: "",
(res_name.entry || entry8) ? (int)res_name.entry_len : 0,
res_name.entry ?: entry8 ?: "");
jstring result_jstr = _JSTRING(result);
free(result);
return result_jstr;
} }
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourcePackageName(JNIEnv *env, jobject this, jint ident) JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourcePackageName(JNIEnv *env, jobject this, jint ident)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true);
struct resource_name res_name; struct resource_name res_name;
bool ret = ResTable_getResourceName(res_table, ident, false, &res_name); bool ret = AssetManager_getResourceName(asset_manager, ident, &res_name);
return (ret && res_name.package) ? (*env)->NewString(env, res_name.package, res_name.packageLen) : NULL; return (ret && res_name.package) ? (*env)->NewStringUTF(env, res_name.package) : NULL;
} }
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceTypeName(JNIEnv *env, jobject this, jint ident) JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceTypeName(JNIEnv *env, jobject this, jint ident)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true);
struct resource_name res_name; struct resource_name res_name;
bool ret = ResTable_getResourceName(res_table, ident, false, &res_name); bool ret = AssetManager_getResourceName(asset_manager, ident, &res_name);
return (ret && res_name.type) ? (*env)->NewString(env, res_name.type, res_name.typeLen) : NULL; if(!ret)
return NULL;
return res_name.type ? (*env)->NewStringUTF(env, res_name.type) :
res_name.type16 ? (*env)->NewString(env, res_name.type16, res_name.type_len) : NULL;
} }
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceEntryName(JNIEnv *env, jobject this, jint ident) JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceEntryName(JNIEnv *env, jobject this, jint ident)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true);
struct resource_name res_name; struct resource_name res_name;
bool ret = ResTable_getResourceName(res_table, ident, false, &res_name); bool ret = AssetManager_getResourceName(asset_manager, ident, &res_name);
return (ret && res_name.name) ? (*env)->NewString(env, res_name.name, res_name.nameLen) : NULL; if(!ret)
return NULL;
return res_name.entry ? (*env)->NewStringUTF(env, res_name.entry) :
res_name.entry16 ? (*env)->NewString(env, res_name.entry16, res_name.entry_len) : NULL;
} }
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceBagValue(JNIEnv *env, jobject this, jint ident, jint bagEntryId, jobject outValue, jboolean resolve) JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceBagValue(JNIEnv *env, jobject this, jint ident, jint bagEntryId, jobject outValue, jboolean resolve)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
const struct ResTable *res_table = AssetManager_getResources(asset_manager, true); ApkAssetsCookie cookie = -1;
const struct bag_entry *bag;
int i;
ssize_t block = -1;
int bag_count = ResTable_lockBag(res_table, ident, &bag); const struct ResolvedBag* bag = AssetManager_getBag(asset_manager, ident);
for (i = 0; i < bag_count; i++) { if(!bag)
if (bag[i].map.name.ident == bagEntryId) { return -1;
struct Res_value value = bag[i].map.value; for (int i = 0; i < bag->entry_count; i++) {
uint32_t resId = 0; const struct ResolvedBag_Entry entry = bag->entries[i];
block = ResTable_resolveReference(res_table, &value, bag[i].stringBlock, &resId, NULL, NULL); if (entry.key == bagEntryId) {
struct Res_value value = entry.value;
struct ResTable_config outConfig;
uint32_t outSpecFlags;
uint32_t ref;
cookie = AssetManager_resolveReference(asset_manager, entry.cookie,
&value, &outConfig,
&outSpecFlags, &ref);
_SET_INT_FIELD(outValue, "type", value.dataType); _SET_INT_FIELD(outValue, "type", value.dataType);
_SET_INT_FIELD(outValue, "data", value.data); _SET_INT_FIELD(outValue, "data", value.data);
_SET_INT_FIELD(outValue, "resourceId", resId); _SET_INT_FIELD(outValue, "resourceId", ref);
_SET_INT_FIELD(outValue, "assetCookie", block); _SET_INT_FIELD(outValue, "assetCookie", JAVA_COOKIE(cookie));
if (value.dataType == TYPE_STRING) { if (value.dataType == TYPE_STRING) {
const struct ResStringPool *string_pool = ResTable_getTableStringBlock(res_table, block); const struct ResStringPool *string_pool = AssetManager_getStringPoolForCookie(asset_manager, cookie);
size_t len; size_t len;
const char16_t *string = ResStringPool_stringAt(string_pool, value.data, &len); const char16_t *string = ResStringPool_stringAt(string_pool, value.data, &len);
_SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", (*env)->NewString(env, string, len)); _SET_OBJ_FIELD(outValue, "string", "Ljava/lang/CharSequence;", (*env)->NewString(env, string, len));
@ -435,8 +476,7 @@ JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceBagValu
} }
} }
ResTable_unlockBag(res_table, bag); return JAVA_COOKIE(cookie);
return block;
} }
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_copyTheme(JNIEnv *env, jclass class, jlong dest, jlong src) JNIEXPORT void JNICALL Java_android_content_res_AssetManager_copyTheme(JNIEnv *env, jclass class, jlong dest, jlong src)
@ -469,7 +509,7 @@ JNIEXPORT void JNICALL Java_android_content_res_AssetManager_setConfiguration(
.uiMode = uiMode, .uiMode = uiMode,
.sdkVersion = majorVersion .sdkVersion = majorVersion
}; };
AssetManager_setConfiguration(asset_manager, &config, NULL); AssetManager_setConfiguration(asset_manager, &config);
} }
JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_list(JNIEnv *env, jobject this, jstring _path) JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_list(JNIEnv *env, jobject this, jstring _path)
@ -528,7 +568,7 @@ JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_openXmlAssetNative
JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_getLocales(JNIEnv *env, jobject this) JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_getLocales(JNIEnv *env, jobject this)
{ {
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject")); struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
char **locales = AssetManager_getLocales(asset_manager, true); char **locales = AssetManager_getLocales(asset_manager, false, true);
int i = 0; int i = 0;
while (locales[i] != NULL) i++; while (locales[i] != NULL) i++;
jobjectArray array = (*env)->NewObjectArray(env, i, (*env)->FindClass(env, "java/lang/String"), NULL); jobjectArray array = (*env)->NewObjectArray(env, i, (*env)->FindClass(env, "java/lang/String"), NULL);

View file

@ -97,6 +97,14 @@ JNIEXPORT void JNICALL Java_android_content_res_AssetManager_setConfiguration
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_getResourceIdentifier JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_getResourceIdentifier
(JNIEnv *, jobject, jstring, jstring, jstring); (JNIEnv *, jobject, jstring, jstring, jstring);
/*
* Class: android_content_res_AssetManager
* Method: getResourceName
* Signature: (I)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceName
(JNIEnv *, jobject, jint);
/* /*
* Class: android_content_res_AssetManager * Class: android_content_res_AssetManager
* Method: getResourcePackageName * Method: getResourcePackageName
@ -353,6 +361,14 @@ JNIEXPORT jintArray JNICALL Java_android_content_res_AssetManager_getArrayString
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_init JNIEXPORT void JNICALL Java_android_content_res_AssetManager_init
(JNIEnv *, jobject); (JNIEnv *, jobject);
/*
* Class: android_content_res_AssetManager
* Method: native_setApkAssets
* Signature: ([Ljava/lang/Object;I)V
*/
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_native_1setApkAssets
(JNIEnv *, jobject, jobjectArray, jint);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -21,6 +21,7 @@ import android.os.Environment;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.util.Slog;
import android.util.TypedValue; import android.util.TypedValue;
import java.io.FileDescriptor; import java.io.FileDescriptor;
@ -91,6 +92,9 @@ public final class AssetManager {
private boolean mOpen = true; private boolean mOpen = true;
private HashMap<Integer, RuntimeException> mRefStacks; private HashMap<Integer, RuntimeException> mRefStacks;
private ArrayList<String> asset_paths = new ArrayList<String>();
/** /**
* Create a new AssetManager containing only the basic system assets. * Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the * Applications will not generally use this method, instead retrieving the
@ -99,7 +103,6 @@ public final class AssetManager {
* {@hide} * {@hide}
*/ */
public AssetManager() { public AssetManager() {
// FIXME: evaluate if this can be axed
synchronized (this) { synchronized (this) {
if (DEBUG_REFS) { if (DEBUG_REFS) {
mNumRefs = 0; mNumRefs = 0;
@ -124,13 +127,15 @@ public final class AssetManager {
for (String path : paths) { for (String path : paths) {
if (path != null) { if (path != null) {
path = path.substring(path.indexOf("file:") + 5, path.indexOf("!/AndroidManifest.xml")); path = path.substring(path.indexOf("file:") + 5, path.indexOf("!/AndroidManifest.xml"));
addAssetPath(path); asset_paths.add(path);
} }
} }
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "failed to load resources.arsc" + e); Log.e(TAG, "failed to load resources.arsc" + e);
} }
addAssetPath(android.os.Environment.getExternalStorageDirectory().getAbsolutePath()); asset_paths.add(android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/");
/*String*/Object[] asset_paths_arr = asset_paths.toArray();
native_setApkAssets(asset_paths_arr, asset_paths_arr.length);
} }
} }
@ -598,33 +603,15 @@ public final class AssetManager {
* the cookie of the added asset, or 0 on failure. * the cookie of the added asset, or 0 on failure.
* {@hide} * {@hide}
*/ */
public final int addAssetPath(String path) { /* this is not particularly efficient, avoid if possible */
int res = addAssetPathNative(path); public final void addAssetPath(String path) {
return res; asset_paths.add(path);
/*String*/Object[] asset_paths_arr = asset_paths.toArray();
native_setApkAssets(asset_paths_arr, asset_paths_arr.length);
} }
private native final int addAssetPathNative(String path); private native final int addAssetPathNative(String path);
/**
* Add multiple sets of assets to the asset manager at once. See
* {@link #addAssetPath(String)} for more information. Returns array of
* cookies for each added asset with 0 indicating failure, or null if
* the input array of paths is null.
* {@hide}
*/
public final int[] addAssetPaths(String[] paths) {
if (paths == null) {
return null;
}
int[] cookies = new int[paths.length];
for (int i = 0; i < paths.length; i++) {
cookies[i] = addAssetPath(paths[i]);
}
return cookies;
}
public static void extractFromAPK(String path, String target) throws IOException { public static void extractFromAPK(String path, String target) throws IOException {
if (path.endsWith("/")) { // directory if (path.endsWith("/")) { // directory
try (JarFile apk = new JarFile(Context.this_application.getPackageCodePath())) { try (JarFile apk = new JarFile(Context.this_application.getPackageCodePath())) {
@ -685,16 +672,7 @@ public final class AssetManager {
*/ */
/*package*/ native final int getResourceIdentifier(String name, String type, String defPackage); /*package*/ native final int getResourceIdentifier(String name, String type, String defPackage);
public /*native*/ final String getResourceName(int resid) { public native final String getResourceName(int resid);
String name = getResourcePackageName(resid);
String type = getResourceTypeName(resid);
if (type != null)
name += ':' + type;
String entry = getResourceEntryName(resid);
if (entry != null)
name += '/' + entry;
return name;
}
/*package*/ native final String getResourcePackageName(int resid); /*package*/ native final String getResourcePackageName(int resid);
/*package*/ native final String getResourceTypeName(int resid); /*package*/ native final String getResourceTypeName(int resid);
/*package*/ native final String getResourceEntryName(int resid); /*package*/ native final String getResourceEntryName(int resid);
@ -872,7 +850,7 @@ public final class AssetManager {
private native final void init(); private native final void init();
private /*native*/ final void destroy() { private /*native*/ final void destroy() {
System.out.println("AssetManager.destroy(): STUB"); Slog.w(TAG, "AssetManager.destroy(): STUB");
} }
private final void incRefsLocked(int id) { private final void incRefsLocked(int id) {
@ -898,4 +876,6 @@ public final class AssetManager {
destroy(); destroy();
} }
} }
private native final void native_setApkAssets(/*String*/Object[] paths, int num_assets);
} }