From c796ad0a8be6df4a3b354690dfe5ce1df8136c09 Mon Sep 17 00:00:00 2001 From: Yusuke Sato Date: Thu, 25 Jun 2015 17:47:35 -0700 Subject: Clean up AssetManager::scanAndMergeZipLocked Now that ZipFileRO::startIteration supports prefix/suffix matching, we can pass dirName to the function for simpler code and slightly better performance. Change-Id: Ia93c3ab3fa688ce013dd9febbf0f4bd3ee1f3e5e --- libs/androidfw/AssetManager.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 2dc1c96259c0..1c39ffef6fd4 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -1545,7 +1545,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector* pMerg */ int dirNameLen = dirName.length(); void *iterationCookie; - if (!pZip->startIteration(&iterationCookie)) { + if (!pZip->startIteration(&iterationCookie, dirName.string(), NULL)) { ALOGW("ZipFileRO::startIteration returned false"); return false; } @@ -1560,9 +1560,7 @@ bool AssetManager::scanAndMergeZipLocked(SortedVector* pMerg continue; } //printf("Comparing %s in %s?\n", nameBuf, dirName.string()); - if (dirNameLen == 0 || - (strncmp(nameBuf, dirName.string(), dirNameLen) == 0 && - nameBuf[dirNameLen] == '/')) + if (dirNameLen == 0 || nameBuf[dirNameLen] == '/') { const char* cp; const char* nextSlash; -- cgit v1.2.3-59-g8ed1b From a6d7e3fb9c9233b9ae46b702d17433854c43d6a0 Mon Sep 17 00:00:00 2001 From: Tao Bai Date: Tue, 1 Sep 2015 18:49:54 -0700 Subject: Load app resource as shared library. - Added aapt command line flag --app-as-shared-lib to build app resources that could be loaded as shared lib at runtime. - Added new method AssetManager.addAssetPathAsSharedLibrary() to load an app resource as shared library. Bug 22487604 Change-Id: Ib9b33c35f9c2b7129f3ba205de03d4564623ea39 --- core/java/android/content/res/AssetManager.java | 18 ++++++++- core/jni/android_util_AssetManager.cpp | 6 +-- include/androidfw/AssetManager.h | 7 ++-- include/androidfw/ResourceTypes.h | 12 +++--- libs/androidfw/AssetManager.cpp | 8 ++-- libs/androidfw/ResourceTypes.cpp | 52 ++++++++++++++---------- libs/androidfw/tests/Android.mk | 1 + libs/androidfw/tests/AppAsLib_test.cpp | 53 +++++++++++++++++++++++++ libs/androidfw/tests/data/appaslib/R.h | 38 ++++++++++++++++++ tools/aapt/Bundle.h | 4 ++ tools/aapt/Command.cpp | 6 +-- tools/aapt/Main.cpp | 6 +++ 12 files changed, 169 insertions(+), 42 deletions(-) create mode 100644 libs/androidfw/tests/AppAsLib_test.cpp create mode 100644 libs/androidfw/tests/data/appaslib/R.h (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index c248a9ee9b21..04c690b8334b 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -610,14 +610,28 @@ public final class AssetManager implements AutoCloseable { * {@hide} */ public final int addAssetPath(String path) { + return addAssetPathInternal(path, false); + } + + /** + * Add an application assets to the asset manager and loading it as shared library. + * This can be either a directory or ZIP file. Not for use by applications. Returns + * the cookie of the added asset, or 0 on failure. + * {@hide} + */ + public final int addAssetPathAsSharedLibrary(String path) { + return addAssetPathInternal(path, true); + } + + private final int addAssetPathInternal(String path, boolean appAsLib) { synchronized (this) { - int res = addAssetPathNative(path); + int res = addAssetPathNative(path, appAsLib); makeStringBlocks(mStringBlocks); return res; } } - private native final int addAssetPathNative(String path); + private native final int addAssetPathNative(String path, boolean appAsLib); /** * Add a set of assets to overlay an already added set of assets. diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 9aa544fb4e9d..7ca0654f9656 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -510,7 +510,7 @@ static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, j } static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz, - jstring path) + jstring path, jboolean appAsLib) { ScopedUtfChars path8(env, path); if (path8.c_str() == NULL) { @@ -523,7 +523,7 @@ static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz } int32_t cookie; - bool res = am->addAssetPath(String8(path8.c_str()), &cookie); + bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib); return (res) ? static_cast(cookie) : 0; } @@ -2138,7 +2138,7 @@ static JNINativeMethod gAssetManagerMethods[] = { (void*) android_content_AssetManager_getAssetLength }, { "getAssetRemainingLength", "(J)J", (void*) android_content_AssetManager_getAssetRemainingLength }, - { "addAssetPathNative", "(Ljava/lang/String;)I", + { "addAssetPathNative", "(Ljava/lang/String;Z)I", (void*) android_content_AssetManager_addAssetPath }, { "addOverlayPathNative", "(Ljava/lang/String;)I", (void*) android_content_AssetManager_addOverlayPath }, diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h index 0cfd2b103d23..3d4e47d84c65 100644 --- a/include/androidfw/AssetManager.h +++ b/include/androidfw/AssetManager.h @@ -93,13 +93,14 @@ public: * look in multiple places for assets. It can be either a directory (for * finding assets as raw files on the disk) or a ZIP file. This newly * added asset path will be examined first when searching for assets, - * before any that were previously added. + * before any that were previously added, the assets are added as shared + * library if appAsLib is true. * * Returns "true" on success, "false" on failure. If 'cookie' is non-NULL, * then on success, *cookie is set to the value corresponding to the * newly-added asset source. */ - bool addAssetPath(const String8& path, int32_t* cookie); + bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false); bool addOverlayPath(const String8& path, int32_t* cookie); /* @@ -280,7 +281,7 @@ private: const ResTable* getResTable(bool required = true) const; void setLocaleLocked(const char* locale); void updateResourceParamsLocked() const; - bool appendPathToResTable(const asset_path& ap) const; + bool appendPathToResTable(const asset_path& ap, bool appAsLib=false) const; Asset* openIdmapLocked(const struct asset_path& ap) const; diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index eff1f5f4e7d4..49b6333e8a4d 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -1505,7 +1505,7 @@ struct ResTable_lib_entry class DynamicRefTable { public: - DynamicRefTable(uint8_t packageId); + DynamicRefTable(uint8_t packageId, bool appAsLib); // Loads an unmapped reference table from the package. status_t load(const ResTable_lib_header* const header); @@ -1530,6 +1530,7 @@ private: const uint8_t mAssignedPackageId; uint8_t mLookupTable[256]; KeyedVector mEntries; + bool mAppAsLib; }; bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue); @@ -1547,10 +1548,11 @@ public: status_t add(const void* data, size_t size, const int32_t cookie=-1, bool copyData=false); status_t add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize, - const int32_t cookie=-1, bool copyData=false); + const int32_t cookie=-1, bool copyData=false, bool appAsLib=false); status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false); - status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false); + status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false, + bool appAsLib=false); status_t add(ResTable* src); status_t addEmpty(const int32_t cookie); @@ -1858,7 +1860,7 @@ private: typedef Vector TypeList; status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize, - const int32_t cookie, bool copyData); + bool appAsLib, const int32_t cookie, bool copyData); ssize_t getResourcePackageIndex(uint32_t resID) const; @@ -1871,7 +1873,7 @@ private: size_t nameLen, uint32_t* outTypeSpecFlags) const; status_t parsePackage( - const ResTable_package* const pkg, const Header* const header); + const ResTable_package* const pkg, const Header* const header, bool appAsLib); void print_value(const Package* pkg, const Res_value& value) const; diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 623ea896626b..8a03b94492d8 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -176,7 +176,7 @@ AssetManager::~AssetManager(void) delete[] mVendor; } -bool AssetManager::addAssetPath(const String8& path, int32_t* cookie) +bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib) { AutoMutex _l(mLock); @@ -238,7 +238,7 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie) #endif if (mResources != NULL) { - appendPathToResTable(ap); + appendPathToResTable(ap, appAsLib); } return true; @@ -610,7 +610,7 @@ FileType AssetManager::getFileType(const char* fileName) return kFileTypeRegular; } -bool AssetManager::appendPathToResTable(const asset_path& ap) const { +bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const { // skip those ap's that correspond to system overlays if (ap.isSystemOverlay) { return true; @@ -685,7 +685,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap) const { mResources->add(sharedRes); } else { ALOGV("Parsing resources for %s", ap.path.string()); - mResources->add(ass, idmap, nextEntryIdx + 1, !shared); + mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib); } onlyEmptyResources = false; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 37de89ac53b6..21b543eefa01 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -3080,13 +3080,13 @@ struct ResTable::Package // table that defined the package); the ones after are skins on top of it. struct ResTable::PackageGroup { - PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id) + PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib) : owner(_owner) , name(_name) , id(_id) , largestTypeId(0) , bags(NULL) - , dynamicRefTable(static_cast(_id)) + , dynamicRefTable(static_cast(_id), appAsLib) { } ~PackageGroup() { @@ -3532,7 +3532,7 @@ ResTable::ResTable(const void* data, size_t size, const int32_t cookie, bool cop { memset(&mParams, 0, sizeof(mParams)); memset(mPackageMap, 0, sizeof(mPackageMap)); - addInternal(data, size, NULL, 0, cookie, copyData); + addInternal(data, size, NULL, 0, false, cookie, copyData); LOG_FATAL_IF(mError != NO_ERROR, "Error parsing resource table"); if (kDebugTableSuperNoisy) { ALOGI("Creating ResTable %p\n", this); @@ -3553,12 +3553,12 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const } status_t ResTable::add(const void* data, size_t size, const int32_t cookie, bool copyData) { - return addInternal(data, size, NULL, 0, cookie, copyData); + return addInternal(data, size, NULL, 0, false, cookie, copyData); } status_t ResTable::add(const void* data, size_t size, const void* idmapData, size_t idmapDataSize, - const int32_t cookie, bool copyData) { - return addInternal(data, size, idmapData, idmapDataSize, cookie, copyData); + const int32_t cookie, bool copyData, bool appAsLib) { + return addInternal(data, size, idmapData, idmapDataSize, appAsLib, cookie, copyData); } status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) { @@ -3568,10 +3568,12 @@ status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) { return UNKNOWN_ERROR; } - return addInternal(data, static_cast(asset->getLength()), NULL, 0, cookie, copyData); + return addInternal(data, static_cast(asset->getLength()), NULL, false, 0, cookie, + copyData); } -status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData) { +status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData, + bool appAsLib) { const void* data = asset->getBuffer(true); if (data == NULL) { ALOGW("Unable to get buffer of resource asset file"); @@ -3590,7 +3592,7 @@ status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bo } return addInternal(data, static_cast(asset->getLength()), - idmapData, idmapSize, cookie, copyData); + idmapData, idmapSize, appAsLib, cookie, copyData); } status_t ResTable::add(ResTable* src) @@ -3603,7 +3605,7 @@ status_t ResTable::add(ResTable* src) for (size_t i=0; imPackageGroups.size(); i++) { PackageGroup* srcPg = src->mPackageGroups[i]; - PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id); + PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false); for (size_t j=0; jpackages.size(); j++) { pg->packages.add(srcPg->packages[j]); } @@ -3644,7 +3646,7 @@ status_t ResTable::addEmpty(const int32_t cookie) { } status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize, - const int32_t cookie, bool copyData) + bool appAsLib, const int32_t cookie, bool copyData) { if (!data) { return NO_ERROR; @@ -3747,7 +3749,7 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id return (mError=BAD_TYPE); } - if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) { + if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) { return mError; } curPackage++; @@ -5935,7 +5937,7 @@ status_t ResTable::getEntry( } status_t ResTable::parsePackage(const ResTable_package* const pkg, - const Header* const header) + const Header* const header, bool appAsLib) { const uint8_t* base = (const uint8_t*)pkg; status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset), @@ -5983,7 +5985,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, if (id >= 256) { LOG_ALWAYS_FATAL("Package id out of range"); return NO_ERROR; - } else if (id == 0) { + } else if (id == 0 || appAsLib) { // This is a library so assign an ID id = mNextPackageId++; } @@ -6016,7 +6018,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])]; strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0])); - group = new PackageGroup(this, String16(tmpName), id); + group = new PackageGroup(this, String16(tmpName), id, appAsLib); if (group == NULL) { delete package; return (mError=NO_MEMORY); @@ -6228,8 +6230,9 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, return NO_ERROR; } -DynamicRefTable::DynamicRefTable(uint8_t packageId) +DynamicRefTable::DynamicRefTable(uint8_t packageId, bool appAsLib) : mAssignedPackageId(packageId) + , mAppAsLib(appAsLib) { memset(mLookupTable, 0, sizeof(mLookupTable)); @@ -6314,16 +6317,18 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const { uint32_t res = *resId; size_t packageId = Res_GETPACKAGE(res) + 1; - if (packageId == APP_PACKAGE_ID) { + if (packageId == APP_PACKAGE_ID && !mAppAsLib) { // No lookup needs to be done, app package IDs are absolute. return NO_ERROR; } - if (packageId == 0) { + if (packageId == 0 || (packageId == APP_PACKAGE_ID && mAppAsLib)) { // The package ID is 0x00. That means that a shared library is accessing - // its own local resource, so we fix up the resource with the calling - // package ID. - *resId |= ((uint32_t) mAssignedPackageId) << 24; + // its own local resource. + // Or if app resource is loaded as shared library, the resource which has + // app package Id is local resources. + // so we fix up those resources with the calling package ID. + *resId = (0xFFFFFF & (*resId)) | (((uint32_t) mAssignedPackageId) << 24); return NO_ERROR; } @@ -6345,7 +6350,10 @@ status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const { } status_t DynamicRefTable::lookupResourceValue(Res_value* value) const { - if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE) { + if (value->dataType != Res_value::TYPE_DYNAMIC_REFERENCE && + (value->dataType != Res_value::TYPE_REFERENCE || !mAppAsLib)) { + // If the package is loaded as shared library, the resource reference + // also need to be fixed. return NO_ERROR; } diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk index a353575b4073..2bc026b79ca2 100644 --- a/libs/androidfw/tests/Android.mk +++ b/libs/androidfw/tests/Android.mk @@ -21,6 +21,7 @@ LOCAL_PATH:= $(call my-dir) testFiles := \ + AppAsLib_test.cpp \ AttributeFinder_test.cpp \ ByteBucketArray_test.cpp \ Config_test.cpp \ diff --git a/libs/androidfw/tests/AppAsLib_test.cpp b/libs/androidfw/tests/AppAsLib_test.cpp new file mode 100644 index 000000000000..bdb0c3d38f6f --- /dev/null +++ b/libs/androidfw/tests/AppAsLib_test.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "data/basic/R.h" +#include "data/appaslib/R.h" + +#include + +using namespace android; + +namespace { + +#include "data/basic/basic_arsc.h" + +TEST(AppAsLibTest, loadedAsApp) { + ResTable table; + ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); + + Res_value val; + ssize_t block = table.getResource(base::R::integer::number2, &val); + ASSERT_GE(block, 0); + ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType); + ASSERT_EQ(base::R::array::integerArray1, val.data); +} + +TEST(AppAsLibTest, loadedAsSharedLib) { + ResTable table; + // Load as shared library. + ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len, NULL, 0, -1, false, true)); + + Res_value val; + ssize_t block = table.getResource(appaslib::R::integer::number2, &val); + ASSERT_GE(block, 0); + ASSERT_EQ(Res_value::TYPE_REFERENCE, val.dataType); + ASSERT_EQ(appaslib::R::array::integerArray1, val.data); +} + +} diff --git a/libs/androidfw/tests/data/appaslib/R.h b/libs/androidfw/tests/data/appaslib/R.h new file mode 100644 index 000000000000..f89d4bfdd15e --- /dev/null +++ b/libs/androidfw/tests/data/appaslib/R.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __APPASLIB_R_H +#define __APPASLIB_R_H + +namespace appaslib { +namespace R { + +namespace integer { + enum { + number2 = 0x02040001, // default + }; +} + +namespace array { + enum { + integerArray1 = 0x02060000, // default + }; +} + +} // namespace R +} // namespace appaslib + +#endif // __APPASLIB_R_H diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h index cbe7c5dacc1e..c29bb482c159 100644 --- a/tools/aapt/Bundle.h +++ b/tools/aapt/Bundle.h @@ -66,6 +66,7 @@ public: mErrorOnMissingConfigEntry(false), mOutputTextSymbols(NULL), mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL), mBuildSharedLibrary(false), + mBuildAppAsSharedLibrary(false), mArgc(0), mArgv(NULL) {} ~Bundle(void) {} @@ -206,6 +207,8 @@ public: void setSingleCrunchOutputFile(const char* val) { mSingleCrunchOutputFile = val; } bool getBuildSharedLibrary() const { return mBuildSharedLibrary; } void setBuildSharedLibrary(bool val) { mBuildSharedLibrary = val; } + bool getBuildAppAsSharedLibrary() const { return mBuildAppAsSharedLibrary; } + void setBuildAppAsSharedLibrary(bool val) { mBuildAppAsSharedLibrary = val; } void setNoVersionVectors(bool val) { mNoVersionVectors = val; } bool getNoVersionVectors() const { return mNoVersionVectors; } @@ -327,6 +330,7 @@ private: const char* mSingleCrunchInputFile; const char* mSingleCrunchOutputFile; bool mBuildSharedLibrary; + bool mBuildAppAsSharedLibrary; android::String8 mPlatformVersionCode; android::String8 mPlatformVersionName; diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index d12ab3b725c8..21f47bc28ff3 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -2395,11 +2395,11 @@ int doPackage(Bundle* bundle) // Write the R.java file into the appropriate class directory // e.g. gen/com/foo/app/R.java err = writeResourceSymbols(bundle, assets, assets->getPackage(), true, - bundle->getBuildSharedLibrary()); + bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary()); } else { const String8 customPkg(bundle->getCustomPackage()); err = writeResourceSymbols(bundle, assets, customPkg, true, - bundle->getBuildSharedLibrary()); + bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary()); } if (err < 0) { goto bail; @@ -2414,7 +2414,7 @@ int doPackage(Bundle* bundle) while (packageString != NULL) { // Write the R.java file out with the correct package name err = writeResourceSymbols(bundle, assets, String8(packageString), true, - bundle->getBuildSharedLibrary()); + bundle->getBuildSharedLibrary() || bundle->getBuildAppAsSharedLibrary()); if (err < 0) { goto bail; } diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp index bcf0d5e53c07..64112867a4b4 100644 --- a/tools/aapt/Main.cpp +++ b/tools/aapt/Main.cpp @@ -200,6 +200,9 @@ void usage(void) " --shared-lib\n" " Make a shared library resource package that can be loaded by an application\n" " at runtime to access the libraries resources. Implies --non-constant-id.\n" + " --app-as-shared-lib\n" + " Make an app resource package that also can be loaded as shared library at runtime.\n" + " Implies --non-constant-id.\n" " --error-on-failed-insert\n" " Forces aapt to return an error if it fails to insert values into the manifest\n" " with --debug-mode, --min-sdk-version, --target-sdk-version --version-code\n" @@ -668,6 +671,9 @@ int main(int argc, char* const argv[]) } else if (strcmp(cp, "-shared-lib") == 0) { bundle.setNonConstantId(true); bundle.setBuildSharedLibrary(true); + } else if (strcmp(cp, "-app-as-shared-lib") == 0) { + bundle.setNonConstantId(true); + bundle.setBuildAppAsSharedLibrary(true); } else if (strcmp(cp, "-no-crunch") == 0) { bundle.setUseCrunchCache(true); } else if (strcmp(cp, "-ignore-assets") == 0) { -- cgit v1.2.3-59-g8ed1b From 1c686f2ce6cbfa3fdb598f452aa31d38f3eb2320 Mon Sep 17 00:00:00 2001 From: Roozbeh Pournader Date: Fri, 18 Dec 2015 14:22:14 -0800 Subject: Avoid matching system locales in locale negotiation Also: 1. Add AssetManager method for finding non-system locales: This is used in per-app locale negotiation. (Normally, AssetManager#getLocales() returns both system and non-system locales.) 2. Match pseudolocales correctly in locale negotiation. Bug: 25800576 Bug: 26236938 Change-Id: I116caf3a91c290deb4ad68b291c65b7035b18dd4 --- core/java/android/content/res/AssetManager.java | 12 ++++++ core/java/android/content/res/Resources.java | 16 +++++++- core/java/android/util/LocaleList.java | 41 +++++++++++++++++++- core/jni/android_util_AssetManager.cpp | 16 +++++++- include/androidfw/AssetManager.h | 17 +++++---- include/androidfw/ResourceTypes.h | 15 ++++---- libs/androidfw/AssetManager.cpp | 15 +++++--- libs/androidfw/ResourceTypes.cpp | 50 ++++++++++++++++--------- 8 files changed, 141 insertions(+), 41 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 7669053cc803..ee6aec2910aa 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -698,6 +698,18 @@ public final class AssetManager implements AutoCloseable { */ public native final String[] getLocales(); + /** + * Same as getLocales(), except that locales that are only provided by the system (i.e. those + * present in framework-res.apk or its overlays) will not be listed. + * + * For example, if the "system" assets support English, French, and German, and the additional + * assets support Cherokee and French, getLocales() would return + * [Cherokee, English, French, German], while getNonSystemLocales() would return + * [Cherokee, French]. + * {@hide} + */ + public native final String[] getNonSystemLocales(); + /** {@hide} */ public native final Configuration[] getSizeConfigurations(); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 60c6e825e1be..c460746ba514 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1976,7 +1976,21 @@ public class Resources { if (setLocalesToDefault || mResolvedLocale == null || (configChanges & Configuration.NATIVE_CONFIG_LOCALE) != 0) { - mResolvedLocale = locales.getFirstMatch(mAssets.getLocales()); + if (locales.size() == 1) { + // This is an optimization to avoid the JNI call(s) when the result of + // getFirstMatch() does not depend on the supported locales. + mResolvedLocale = locales.getPrimary(); + } else { + String[] supportedLocales = mAssets.getNonSystemLocales(); + if (LocaleList.isPseudoLocalesOnly(supportedLocales)) { + // We fallback to all locales (including system locales) if there was no + // locale specifically supported by the assets. This is to properly support + // apps that only rely on the shared system assets and don't need assets of + // their own. + supportedLocales = mAssets.getLocales(); + } + mResolvedLocale = locales.getFirstMatch(supportedLocales); + } } mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc, adjustLanguageTag(mResolvedLocale.toLanguageTag()), diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java index 1becfb4a0e23..65a436b89818 100644 --- a/core/java/android/util/LocaleList.java +++ b/core/java/android/util/LocaleList.java @@ -219,6 +219,20 @@ public final class LocaleList implements Parcelable { } } + private static final String STRING_EN_XA = "en-XA"; + private static final String STRING_AR_XB = "ar-XB"; + private static final Locale LOCALE_EN_XA = new Locale("en", "XA"); + private static final Locale LOCALE_AR_XB = new Locale("ar", "XB"); + private static final int NUM_PSEUDO_LOCALES = 2; + + private static boolean isPseudoLocale(String locale) { + return STRING_EN_XA.equals(locale) || STRING_AR_XB.equals(locale); + } + + private static boolean isPseudoLocale(Locale locale) { + return LOCALE_EN_XA.equals(locale) || LOCALE_AR_XB.equals(locale); + } + private static int matchScore(Locale supported, Locale desired) { if (supported.equals(desired)) { return 1; // return early so we don't do unnecessary computation @@ -226,6 +240,11 @@ public final class LocaleList implements Parcelable { if (!supported.getLanguage().equals(desired.getLanguage())) { return 0; } + if (isPseudoLocale(supported) || isPseudoLocale(desired)) { + // The locales are not the same, but the languages are the same, and one of the locales + // is a pseudo-locale. So this is not a match. + return 0; + } // There is no match if the two locales use different scripts. This will most imporantly // take care of traditional vs simplified Chinese. final String supportedScr = getLikelyScript(supported); @@ -247,7 +266,6 @@ public final class LocaleList implements Parcelable { if (mList.length == 0) { // empty locale list return null; } - // TODO: Figure out what to if en-XA or ar-XB are in the locale list int bestIndex = Integer.MAX_VALUE; for (String tag : supportedLocales) { final Locale supportedLocale = Locale.forLanguageTag(tag); @@ -271,6 +289,27 @@ public final class LocaleList implements Parcelable { } } + /** + * Returns true if the array of locale tags only contains empty locales and pseudolocales. + * Assumes that there is no repetition in the input. + * {@hide} + */ + public static boolean isPseudoLocalesOnly(String[] supportedLocales) { + if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) { + // This is for optimization. Since there's no repetition in the input, if we have more + // than the number of pseudo-locales plus one for the empty string, it's guaranteed + // that we have some meaninful locale in the list, so the list is not "practically + // empty". + return false; + } + for (String locale : supportedLocales) { + if (!locale.isEmpty() && !isPseudoLocale(locale)) { + return false; + } + } + return true; + } + private final static Object sLock = new Object(); @GuardedBy("sLock") diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 90606a35b5a2..3473d9dab732 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -578,7 +578,7 @@ static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject cla return am->isUpToDate() ? JNI_TRUE : JNI_FALSE; } -static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz) +static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales) { Vector locales; @@ -587,7 +587,7 @@ static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject return NULL; } - am->getLocales(&locales); + am->getLocales(&locales, includeSystemLocales); const int N = locales.size(); @@ -608,6 +608,16 @@ static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject return result; } +static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz) +{ + return getLocales(env, clazz, true /* include system locales */); +} + +static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz) +{ + return getLocales(env, clazz, false /* don't include system locales */); +} + static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) { jobject result = env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor); @@ -2154,6 +2164,8 @@ static const JNINativeMethod gAssetManagerMethods[] = { // Resources. { "getLocales", "()[Ljava/lang/String;", (void*) android_content_AssetManager_getLocales }, + { "getNonSystemLocales", "()[Ljava/lang/String;", + (void*) android_content_AssetManager_getNonSystemLocales }, { "getSizeConfigurations", "()[Landroid/content/res/Configuration;", (void*) android_content_AssetManager_getSizeConfigurations }, { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V", diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h index 3d4e47d84c65..914ac3d52421 100644 --- a/include/androidfw/AssetManager.h +++ b/include/androidfw/AssetManager.h @@ -100,16 +100,17 @@ public: * then on success, *cookie is set to the value corresponding to the * newly-added asset source. */ - bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false); + bool addAssetPath(const String8& path, int32_t* cookie, + bool appAsLib=false, bool isSystemAsset=false); bool addOverlayPath(const String8& path, int32_t* cookie); - /* + /* * Convenience for adding the standard system assets. Uses the * ANDROID_ROOT environment variable to find them. */ bool addDefaultAssets(); - /* + /* * Iterate over the asset paths in this manager. (Previously * added via addAssetPath() and addDefaultAssets().) On first call, * 'cookie' must be 0, resulting in the first cookie being returned. @@ -118,7 +119,7 @@ public: */ int32_t nextAssetPath(const int32_t cookie) const; - /* + /* * Return an asset path in the manager. 'which' must be between 0 and * countAssetPaths(). */ @@ -221,11 +222,11 @@ public: * the current data. */ bool isUpToDate(); - + /** * Get the known locales for this asset manager object. */ - void getLocales(Vector* locales) const; + void getLocales(Vector* locales, bool includeSystemLocales=true) const; /** * Generate idmap data to translate resources IDs between a package and a @@ -237,11 +238,13 @@ public: private: struct asset_path { - asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false) {} + asset_path() : path(""), type(kFileTypeRegular), idmap(""), + isSystemOverlay(false), isSystemAsset(false) {} String8 path; FileType type; String8 idmap; bool isSystemOverlay; + bool isSystemAsset; }; Asset* openInPathLocked(const char* fileName, AccessMode mode, diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index 49b6333e8a4d..428a2b831e1a 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -1552,9 +1552,9 @@ public: status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false); status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false, - bool appAsLib=false); + bool appAsLib=false, bool isSystemAsset=false); - status_t add(ResTable* src); + status_t add(ResTable* src, bool isSystemAsset=false); status_t addEmpty(const int32_t cookie); status_t getError() const; @@ -1822,9 +1822,9 @@ public: // Return the configurations (ResTable_config) that we know about void getConfigurations(Vector* configs, bool ignoreMipmap=false, - bool ignoreAndroidPackage=false) const; + bool ignoreAndroidPackage=false, bool includeSystemConfigs=true) const; - void getLocales(Vector* locales) const; + void getLocales(Vector* locales, bool includeSystemLocales=true) const; // Generate an idmap. // @@ -1860,7 +1860,7 @@ private: typedef Vector TypeList; status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize, - bool appAsLib, const int32_t cookie, bool copyData); + bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false); ssize_t getResourcePackageIndex(uint32_t resID) const; @@ -1873,10 +1873,11 @@ private: size_t nameLen, uint32_t* outTypeSpecFlags) const; status_t parsePackage( - const ResTable_package* const pkg, const Header* const header, bool appAsLib); + const ResTable_package* const pkg, const Header* const header, + bool appAsLib, bool isSystemAsset); void print_value(const Package* pkg, const Res_value& value) const; - + mutable Mutex mLock; status_t mError; diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 8a03b94492d8..6913f43a87c3 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -176,7 +176,8 @@ AssetManager::~AssetManager(void) delete[] mVendor; } -bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib) +bool AssetManager::addAssetPath( + const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset) { AutoMutex _l(mLock); @@ -222,6 +223,7 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAs } delete manifestAsset; + ap.isSystemAsset = isSystemAsset; mAssetPaths.add(ap); // new paths are always added at the end @@ -233,6 +235,7 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAs // Load overlays, if any asset_path oap; for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) { + oap.isSystemAsset = isSystemAsset; mAssetPaths.add(oap); } #endif @@ -340,7 +343,7 @@ bool AssetManager::addDefaultAssets() String8 path(root); path.appendPath(kSystemAssets); - return addAssetPath(path, NULL); + return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */); } int32_t AssetManager::nextAssetPath(const int32_t cookie) const @@ -682,10 +685,10 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con ALOGV("Installing resource asset %p in to table %p\n", ass, mResources); if (sharedRes != NULL) { ALOGV("Copying existing resources for %s", ap.path.string()); - mResources->add(sharedRes); + mResources->add(sharedRes, ap.isSystemAsset); } else { ALOGV("Parsing resources for %s", ap.path.string()); - mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib); + mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset); } onlyEmptyResources = false; @@ -831,11 +834,11 @@ bool AssetManager::isUpToDate() return mZipSet.isUpToDate(); } -void AssetManager::getLocales(Vector* locales) const +void AssetManager::getLocales(Vector* locales, bool includeSystemLocales) const { ResTable* res = mResources; if (res != NULL) { - res->getLocales(locales); + res->getLocales(locales, includeSystemLocales); } const size_t numLocales = locales->size(); diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 21b543eefa01..44f92c7bf3d6 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -3080,13 +3080,16 @@ struct ResTable::Package // table that defined the package); the ones after are skins on top of it. struct ResTable::PackageGroup { - PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib) + PackageGroup( + ResTable* _owner, const String16& _name, uint32_t _id, + bool appAsLib, bool _isSystemAsset) : owner(_owner) , name(_name) , id(_id) , largestTypeId(0) , bags(NULL) , dynamicRefTable(static_cast(_id), appAsLib) + , isSystemAsset(_isSystemAsset) { } ~PackageGroup() { @@ -3178,6 +3181,10 @@ struct ResTable::PackageGroup // by having these tables in a per-package scope rather than // per-package-group. DynamicRefTable dynamicRefTable; + + // If the package group comes from a system asset. Used in + // determining non-system locales. + const bool isSystemAsset; }; struct ResTable::bag_set @@ -3572,8 +3579,9 @@ status_t ResTable::add(Asset* asset, const int32_t cookie, bool copyData) { copyData); } -status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData, - bool appAsLib) { +status_t ResTable::add( + Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData, + bool appAsLib, bool isSystemAsset) { const void* data = asset->getBuffer(true); if (data == NULL) { ALOGW("Unable to get buffer of resource asset file"); @@ -3592,20 +3600,21 @@ status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bo } return addInternal(data, static_cast(asset->getLength()), - idmapData, idmapSize, appAsLib, cookie, copyData); + idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset); } -status_t ResTable::add(ResTable* src) +status_t ResTable::add(ResTable* src, bool isSystemAsset) { mError = src->mError; - for (size_t i=0; imHeaders.size(); i++) { + for (size_t i=0; i < src->mHeaders.size(); i++) { mHeaders.add(src->mHeaders[i]); } - for (size_t i=0; imPackageGroups.size(); i++) { + for (size_t i=0; i < src->mPackageGroups.size(); i++) { PackageGroup* srcPg = src->mPackageGroups[i]; - PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false); + PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, + false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset); for (size_t j=0; jpackages.size(); j++) { pg->packages.add(srcPg->packages[j]); } @@ -3646,7 +3655,7 @@ status_t ResTable::addEmpty(const int32_t cookie) { } status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize, - bool appAsLib, const int32_t cookie, bool copyData) + bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset) { if (!data) { return NO_ERROR; @@ -3749,7 +3758,8 @@ status_t ResTable::addInternal(const void* data, size_t dataSize, const void* id return (mError=BAD_TYPE); } - if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) { + if (parsePackage( + (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) { return mError; } curPackage++; @@ -5663,7 +5673,7 @@ const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) con } void ResTable::getConfigurations(Vector* configs, bool ignoreMipmap, - bool ignoreAndroidPackage) const { + bool ignoreAndroidPackage, bool includeSystemConfigs) const { const size_t packageCount = mPackageGroups.size(); String16 android("android"); for (size_t i = 0; i < packageCount; i++) { @@ -5671,6 +5681,9 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi if (ignoreAndroidPackage && android == packageGroup->name) { continue; } + if (!includeSystemConfigs && packageGroup->isSystemAsset) { + continue; + } const size_t typeCount = packageGroup->types.size(); for (size_t j = 0; j < typeCount; j++) { const TypeList& typeList = packageGroup->types[j]; @@ -5707,11 +5720,14 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi } } -void ResTable::getLocales(Vector* locales) const +void ResTable::getLocales(Vector* locales, bool includeSystemLocales) const { Vector configs; ALOGV("calling getConfigurations"); - getConfigurations(&configs); + getConfigurations(&configs, + false /* ignoreMipmap */, + false /* ignoreAndroidPackage */, + includeSystemLocales /* includeSystemConfigs */); ALOGV("called getConfigurations size=%d", (int)configs.size()); const size_t I = configs.size(); @@ -5937,7 +5953,7 @@ status_t ResTable::getEntry( } status_t ResTable::parsePackage(const ResTable_package* const pkg, - const Header* const header, bool appAsLib) + const Header* const header, bool appAsLib, bool isSystemAsset) { const uint8_t* base = (const uint8_t*)pkg; status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset), @@ -5985,8 +6001,8 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, if (id >= 256) { LOG_ALWAYS_FATAL("Package id out of range"); return NO_ERROR; - } else if (id == 0 || appAsLib) { - // This is a library so assign an ID + } else if (id == 0 || appAsLib || isSystemAsset) { + // This is a library or a system asset, so assign an ID id = mNextPackageId++; } @@ -6018,7 +6034,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])]; strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0])); - group = new PackageGroup(this, String16(tmpName), id, appAsLib); + group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset); if (group == NULL) { delete package; return (mError=NO_MEMORY); -- cgit v1.2.3-59-g8ed1b From 5520581b5f043fb858b5b2044ff33ad8545a6d38 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 11 Apr 2016 20:03:01 -0700 Subject: Optimize ResTable::getLocales() to improve bindApplication performance Change from linear searching for uniqueness to binary search. Bug:27198799 Change-Id: Ifa4672929df286c4693ab1f77716f08945941b0c --- core/java/android/app/ResourcesManager.java | 400 +++++++++++---------- libs/androidfw/AssetManager.cpp | 17 +- libs/androidfw/ResourceTypes.cpp | 39 +- libs/androidfw/tests/ResTable_test.cpp | 33 ++ libs/androidfw/tests/TestHelpers.h | 2 +- libs/androidfw/tests/data/system/R.h | 6 + .../tests/data/system/res/values-sv/values.xml | 20 ++ libs/androidfw/tests/data/system/system_arsc.h | 69 ++-- 8 files changed, 343 insertions(+), 243 deletions(-) create mode 100644 libs/androidfw/tests/data/system/res/values-sv/values.xml (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 4c4f128216f4..aef92cf21711 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -29,6 +29,7 @@ import android.content.res.ResourcesImpl; import android.content.res.ResourcesKey; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; +import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.LocaleList; @@ -430,37 +431,44 @@ public class ResourcesManager { @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) { - final ResourcesKey key = new ResourcesKey( - resDir, - splitResDirs, - overlayDirs, - libDirs, - displayId, - overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy - compatInfo); - classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#createBaseActivityResources"); + final ResourcesKey key = new ResourcesKey( + resDir, + splitResDirs, + overlayDirs, + libDirs, + displayId, + overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy + compatInfo); + classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); - if (DEBUG) { - Slog.d(TAG, "createBaseActivityResources activity=" + activityToken - + " with key=" + key); - } + if (DEBUG) { + Slog.d(TAG, "createBaseActivityResources activity=" + activityToken + + " with key=" + key); + } - synchronized (this) { - final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( - activityToken); + synchronized (this) { + final ActivityResources activityResources = + getOrCreateActivityResourcesStructLocked( + activityToken); - if (overrideConfig != null) { - activityResources.overrideConfig.setTo(overrideConfig); - } else { - activityResources.overrideConfig.setToDefaults(); + if (overrideConfig != null) { + activityResources.overrideConfig.setTo(overrideConfig); + } else { + activityResources.overrideConfig.setToDefaults(); + } } - } - // Update any existing Activity Resources references. - updateResourcesForActivity(activityToken, overrideConfig); + // Update any existing Activity Resources references. + updateResourcesForActivity(activityToken, overrideConfig); - // Now request an actual Resources object. - return getOrCreateResources(activityToken, key, classLoader); + // Now request an actual Resources object. + return getOrCreateResources(activityToken, key, classLoader); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } } /** @@ -490,8 +498,8 @@ public class ResourcesManager { } if (activityToken != null) { - final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( - activityToken); + final ActivityResources activityResources = + getOrCreateActivityResourcesStructLocked(activityToken); // Clean up any dead references so they don't pile up. ArrayUtils.unstableRemoveIf(activityResources.activityResources, @@ -539,6 +547,7 @@ public class ResourcesManager { final String[] systemLocales = findSystemLocales ? AssetManager.getSystem().getLocales() : null; final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales(); + // Avoid checking for non-pseudo-locales if we already know there were some from a previous // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter, // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be @@ -613,16 +622,21 @@ public class ResourcesManager { @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) { - final ResourcesKey key = new ResourcesKey( - resDir, - splitResDirs, - overlayDirs, - libDirs, - displayId, - overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy - compatInfo); - classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); - return getOrCreateResources(activityToken, key, classLoader); + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources"); + final ResourcesKey key = new ResourcesKey( + resDir, + splitResDirs, + overlayDirs, + libDirs, + displayId, + overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy + compatInfo); + classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); + return getOrCreateResources(activityToken, key, classLoader); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } } /** @@ -636,93 +650,104 @@ public class ResourcesManager { */ public void updateResourcesForActivity(@NonNull IBinder activityToken, @Nullable Configuration overrideConfig) { - synchronized (this) { - final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( - activityToken); - - if (Objects.equals(activityResources.overrideConfig, overrideConfig)) { - // They are the same, no work to do. - return; - } - - // Grab a copy of the old configuration so we can create the delta's of each - // Resources object associated with this Activity. - final Configuration oldConfig = new Configuration(activityResources.overrideConfig); - - // Update the Activity's base override. - if (overrideConfig != null) { - activityResources.overrideConfig.setTo(overrideConfig); - } else { - activityResources.overrideConfig.setToDefaults(); - } - - if (DEBUG) { - Throwable here = new Throwable(); - here.fillInStackTrace(); - Slog.d(TAG, "updating resources override for activity=" + activityToken - + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig) - + " to newConfig=" - + Configuration.resourceQualifierString(activityResources.overrideConfig), - here); - } - - final boolean activityHasOverrideConfig = - !activityResources.overrideConfig.equals(Configuration.EMPTY); - - // Rebase each Resources associated with this Activity. - final int refCount = activityResources.activityResources.size(); - for (int i = 0; i < refCount; i++) { - WeakReference weakResRef = activityResources.activityResources.get(i); - Resources resources = weakResRef.get(); - if (resources == null) { - continue; + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#updateResourcesForActivity"); + synchronized (this) { + final ActivityResources activityResources = + getOrCreateActivityResourcesStructLocked(activityToken); + + if (Objects.equals(activityResources.overrideConfig, overrideConfig)) { + // They are the same, no work to do. + return; } - // Extract the ResourcesKey that was last used to create the Resources for this - // activity. - final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl()); - if (oldKey == null) { - Slog.e(TAG, "can't find ResourcesKey for resources impl=" - + resources.getImpl()); - continue; - } + // Grab a copy of the old configuration so we can create the delta's of each + // Resources object associated with this Activity. + final Configuration oldConfig = new Configuration(activityResources.overrideConfig); - // Build the new override configuration for this ResourcesKey. - final Configuration rebasedOverrideConfig = new Configuration(); + // Update the Activity's base override. if (overrideConfig != null) { - rebasedOverrideConfig.setTo(overrideConfig); + activityResources.overrideConfig.setTo(overrideConfig); + } else { + activityResources.overrideConfig.setToDefaults(); } - if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) { - // Generate a delta between the old base Activity override configuration and - // the actual final override configuration that was used to figure out the real - // delta this Resources object wanted. - Configuration overrideOverrideConfig = Configuration.generateDelta( - oldConfig, oldKey.mOverrideConfiguration); - rebasedOverrideConfig.updateFrom(overrideOverrideConfig); + if (DEBUG) { + Throwable here = new Throwable(); + here.fillInStackTrace(); + Slog.d(TAG, "updating resources override for activity=" + activityToken + + " from oldConfig=" + + Configuration.resourceQualifierString(oldConfig) + + " to newConfig=" + + Configuration.resourceQualifierString( + activityResources.overrideConfig), + here); } - // Create the new ResourcesKey with the rebased override config. - final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs, - oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId, - rebasedOverrideConfig, oldKey.mCompatInfo); + final boolean activityHasOverrideConfig = + !activityResources.overrideConfig.equals(Configuration.EMPTY); + + // Rebase each Resources associated with this Activity. + final int refCount = activityResources.activityResources.size(); + for (int i = 0; i < refCount; i++) { + WeakReference weakResRef = activityResources.activityResources.get( + i); + Resources resources = weakResRef.get(); + if (resources == null) { + continue; + } - if (DEBUG) { - Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey - + " to newKey=" + newKey); - } + // Extract the ResourcesKey that was last used to create the Resources for this + // activity. + final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl()); + if (oldKey == null) { + Slog.e(TAG, "can't find ResourcesKey for resources impl=" + + resources.getImpl()); + continue; + } - ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey); - if (resourcesImpl == null) { - resourcesImpl = createResourcesImpl(newKey); - mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl)); - } + // Build the new override configuration for this ResourcesKey. + final Configuration rebasedOverrideConfig = new Configuration(); + if (overrideConfig != null) { + rebasedOverrideConfig.setTo(overrideConfig); + } + + if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) { + // Generate a delta between the old base Activity override configuration and + // the actual final override configuration that was used to figure out the + // real delta this Resources object wanted. + Configuration overrideOverrideConfig = Configuration.generateDelta( + oldConfig, oldKey.mOverrideConfiguration); + rebasedOverrideConfig.updateFrom(overrideOverrideConfig); + } + + // Create the new ResourcesKey with the rebased override config. + final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, + oldKey.mSplitResDirs, + oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId, + rebasedOverrideConfig, oldKey.mCompatInfo); + + if (DEBUG) { + Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey + + " to newKey=" + newKey); + } - if (resourcesImpl != resources.getImpl()) { - // Set the ResourcesImpl, updating it for all users of this Resources object. - resources.setImpl(resourcesImpl); + ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey); + if (resourcesImpl == null) { + resourcesImpl = createResourcesImpl(newKey); + mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl)); + } + + if (resourcesImpl != resources.getImpl()) { + // Set the ResourcesImpl, updating it for all users of this Resources + // object. + resources.setImpl(resourcesImpl); + } } } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } } @@ -745,86 +770,95 @@ public class ResourcesManager { public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { - if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { - if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" - + mResConfiguration.seq + ", newSeq=" + config.seq); - return false; - } - int changes = mResConfiguration.updateFrom(config); - // Things might have changed in display manager, so clear the cached displays. - mDisplays.clear(); - DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); - - if (compat != null && (mResCompatibilityInfo == null || - !mResCompatibilityInfo.equals(compat))) { - mResCompatibilityInfo = compat; - changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT - | ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; - } + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#applyConfigurationToResourcesLocked"); + + if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { + if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" + + mResConfiguration.seq + ", newSeq=" + config.seq); + return false; + } + int changes = mResConfiguration.updateFrom(config); + // Things might have changed in display manager, so clear the cached displays. + mDisplays.clear(); + DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); + + if (compat != null && (mResCompatibilityInfo == null || + !mResCompatibilityInfo.equals(compat))) { + mResCompatibilityInfo = compat; + changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + } - Configuration localeAdjustedConfig = config; - final LocaleList configLocales = config.getLocales(); - if (!configLocales.isEmpty()) { - setDefaultLocalesLocked(configLocales); - final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); - if (adjustedLocales != configLocales) { // has the same result as .equals() in this case - // The first locale in the list was not chosen. So we create a modified - // configuration with the adjusted locales (which moves the chosen locale to the - // front). - localeAdjustedConfig = new Configuration(); - localeAdjustedConfig.setTo(config); - localeAdjustedConfig.setLocales(adjustedLocales); - // Also adjust the locale list in mResConfiguration, so that the Resources created - // later would have the same locale list. - if (!mResConfiguration.getLocales().equals(adjustedLocales)) { - mResConfiguration.setLocales(adjustedLocales); - changes |= ActivityInfo.CONFIG_LOCALE; + Configuration localeAdjustedConfig = config; + final LocaleList configLocales = config.getLocales(); + if (!configLocales.isEmpty()) { + setDefaultLocalesLocked(configLocales); + final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); + if (adjustedLocales + != configLocales) { // has the same result as .equals() in this case + // The first locale in the list was not chosen. So we create a modified + // configuration with the adjusted locales (which moves the chosen locale to the + // front). + localeAdjustedConfig = new Configuration(); + localeAdjustedConfig.setTo(config); + localeAdjustedConfig.setLocales(adjustedLocales); + // Also adjust the locale list in mResConfiguration, so that the Resources + // created later would have the same locale list. + if (!mResConfiguration.getLocales().equals(adjustedLocales)) { + mResConfiguration.setLocales(adjustedLocales); + changes |= ActivityInfo.CONFIG_LOCALE; + } } } - } - Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat); - - ApplicationPackageManager.configurationChanged(); - //Slog.i(TAG, "Configuration changed in " + currentPackageName()); - - Configuration tmpConfig = null; - - for (int i = mResourceImpls.size() - 1; i >= 0; i--) { - ResourcesKey key = mResourceImpls.keyAt(i); - ResourcesImpl r = mResourceImpls.valueAt(i).get(); - if (r != null) { - if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " - + r + " config to: " + localeAdjustedConfig); - int displayId = key.mDisplayId; - boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); - DisplayMetrics dm = defaultDisplayMetrics; - final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); - if (!isDefaultDisplay || hasOverrideConfiguration) { - if (tmpConfig == null) { - tmpConfig = new Configuration(); - } - tmpConfig.setTo(localeAdjustedConfig); - if (!isDefaultDisplay) { - dm = getDisplayMetrics(displayId); - applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); - } - if (hasOverrideConfiguration) { - tmpConfig.updateFrom(key.mOverrideConfiguration); + Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, + compat); + + ApplicationPackageManager.configurationChanged(); + //Slog.i(TAG, "Configuration changed in " + currentPackageName()); + + Configuration tmpConfig = null; + + for (int i = mResourceImpls.size() - 1; i >= 0; i--) { + ResourcesKey key = mResourceImpls.keyAt(i); + ResourcesImpl r = mResourceImpls.valueAt(i).get(); + if (r != null) { + if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + + r + " config to: " + localeAdjustedConfig); + int displayId = key.mDisplayId; + boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + DisplayMetrics dm = defaultDisplayMetrics; + final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); + if (!isDefaultDisplay || hasOverrideConfiguration) { + if (tmpConfig == null) { + tmpConfig = new Configuration(); + } + tmpConfig.setTo(localeAdjustedConfig); + if (!isDefaultDisplay) { + dm = getDisplayMetrics(displayId); + applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); + } + if (hasOverrideConfiguration) { + tmpConfig.updateFrom(key.mOverrideConfiguration); + } + r.updateConfiguration(tmpConfig, dm, compat); + } else { + r.updateConfiguration(localeAdjustedConfig, dm, compat); } - r.updateConfiguration(tmpConfig, dm, compat); + //Slog.i(TAG, "Updated app resources " + v.getKey() + // + " " + r + ": " + r.getConfiguration()); } else { - r.updateConfiguration(localeAdjustedConfig, dm, compat); + //Slog.i(TAG, "Removing old resources " + v.getKey()); + mResourceImpls.removeAt(i); } - //Slog.i(TAG, "Updated app resources " + v.getKey() - // + " " + r + ": " + r.getConfiguration()); - } else { - //Slog.i(TAG, "Removing old resources " + v.getKey()); - mResourceImpls.removeAt(i); } - } - return changes != 0; + return changes != 0; + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } } } diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 6913f43a87c3..715c875d064d 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -34,9 +34,7 @@ #include #include #include -#ifdef __ANDROID__ -#include -#endif +#include #include #include @@ -54,14 +52,6 @@ _rc; }) #endif -#ifdef __ANDROID__ -#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x) -#define MY_TRACE_END() ATRACE_END() -#else -#define MY_TRACE_BEGIN(x) -#define MY_TRACE_END() -#endif - using namespace android; static const bool kIsDebug = false; @@ -623,7 +613,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con ResTable* sharedRes = NULL; bool shared = true; bool onlyEmptyResources = true; - MY_TRACE_BEGIN(ap.path.string()); + ATRACE_NAME(ap.path.string()); Asset* idmap = openIdmapLocked(ap); size_t nextEntryIdx = mResources->getTableCount(); ALOGV("Looking for resource asset in '%s'\n", ap.path.string()); @@ -703,8 +693,6 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con if (idmap != NULL) { delete idmap; } - MY_TRACE_END(); - return onlyEmptyResources; } @@ -752,6 +740,7 @@ const ResTable* AssetManager::getResTable(bool required) const void AssetManager::updateResourceParamsLocked() const { + ATRACE_CALL(); ResTable* res = mResources; if (!res) { return; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 1ccc59a6a348..15cb684ee08e 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -5810,6 +5811,10 @@ const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) con return NULL; } +static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) { + return a.compare(b) < 0; +} + void ResTable::getConfigurations(Vector* configs, bool ignoreMipmap, bool ignoreAndroidPackage, bool includeSystemConfigs) const { const size_t packageCount = mPackageGroups.size(); @@ -5840,17 +5845,11 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi ResTable_config cfg; memset(&cfg, 0, sizeof(ResTable_config)); cfg.copyFromDtoH(config->config); - // only insert unique - const size_t N = configs->size(); - size_t n; - for (n = 0; n < N; n++) { - if (0 == (*configs)[n].compare(cfg)) { - break; - } - } - // if we didn't find it - if (n == N) { - configs->add(cfg); + + auto iter = std::lower_bound(configs->begin(), configs->end(), cfg, + compareResTableConfig); + if (iter == configs->end() || iter->compare(cfg) != 0) { + configs->insertAt(cfg, std::distance(configs->begin(), iter)); } } } @@ -5858,6 +5857,10 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi } } +static bool compareString8AndCString(const String8& str, const char* cStr) { + return strcmp(str.string(), cStr) < 0; +} + void ResTable::getLocales(Vector* locales, bool includeSystemLocales) const { Vector configs; @@ -5872,15 +5875,11 @@ void ResTable::getLocales(Vector* locales, bool includeSystemLocales) c char locale[RESTABLE_MAX_LOCALE_LEN]; for (size_t i=0; isize(); - size_t j; - for (j=0; jadd(String8(locale)); + + auto iter = std::lower_bound(locales->begin(), locales->end(), locale, + compareString8AndCString); + if (iter == locales->end() || strcmp(iter->string(), locale) != 0) { + locales->insertAt(String8(locale), std::distance(locales->begin(), iter)); } } } diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp index 7cd7fb5cd711..b8b46259f0d1 100644 --- a/libs/androidfw/tests/ResTable_test.cpp +++ b/libs/androidfw/tests/ResTable_test.cpp @@ -39,8 +39,20 @@ namespace { */ #include "data/basic/basic_arsc.h" +/** + * Include a binary library resource table. + * + * Package: com.android.test.basic + */ #include "data/lib/lib_arsc.h" +/** + * Include a system resource table. + * + * Package: android + */ +#include "data/system/system_arsc.h" + TEST(ResTableTest, shouldLoadSuccessfully) { ResTable table; ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); @@ -324,4 +336,25 @@ TEST(ResTableTest, ShareButDontModifyResTable) { ASSERT_EQ(uint32_t(600), val.data); } +TEST(ResTableTest, GetConfigurationsReturnsUniqueList) { + ResTable table; + ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len)); + ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); + + ResTable_config configSv; + memset(&configSv, 0, sizeof(configSv)); + configSv.language[0] = 's'; + configSv.language[1] = 'v'; + + Vector configs; + table.getConfigurations(&configs); + + EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv)); + + Vector locales; + table.getLocales(&locales); + + EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv"))); +} + } // namespace diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h index ac80d8868090..ff9be164dbb0 100644 --- a/libs/androidfw/tests/TestHelpers.h +++ b/libs/androidfw/tests/TestHelpers.h @@ -21,7 +21,7 @@ namespace android { enum { MAY_NOT_BE_BAG = false }; static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) { - return memcmp(&a, &b, sizeof(a)) == 0; + return a.compare(b) == 0; } static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) { diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h index 27f25fec0d01..6a31fb8ff088 100644 --- a/libs/androidfw/tests/data/system/R.h +++ b/libs/androidfw/tests/data/system/R.h @@ -33,6 +33,12 @@ namespace style { }; } +namespace integer { + enum { + number = 0x01030000, // sv + }; +} + } // namespace R } // namespace android diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml new file mode 100644 index 000000000000..b97bdb68aca7 --- /dev/null +++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml @@ -0,0 +1,20 @@ + + + + + + 1 + diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h index 215ecae552c5..b0dab6b357e9 100644 --- a/libs/androidfw/tests/data/system/system_arsc.h +++ b/libs/androidfw/tests/data/system/system_arsc.h @@ -1,8 +1,8 @@ unsigned char system_arsc[] = { - 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -25,26 +25,33 @@ unsigned char system_arsc[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, - 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00, + 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00, + 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, - 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -55,15 +62,27 @@ unsigned char system_arsc[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, - 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01, + 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -unsigned int system_arsc_len = 792; +unsigned int system_arsc_len = 1016; -- cgit v1.2.3-59-g8ed1b From 98e80076c6c4e31f04c580c8774eeea4036d32c1 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Thu, 14 Apr 2016 15:44:35 -0700 Subject: Revert "Optimize ResTable::getLocales() to improve bindApplication performance" This reverts commit 5520581b5f043fb858b5b2044ff33ad8545a6d38. bug 28189634 Change-Id: I2d2b859f6d9bd44434fa901cce990583f514980c --- core/java/android/app/ResourcesManager.java | 400 ++++++++++----------- libs/androidfw/AssetManager.cpp | 17 +- libs/androidfw/ResourceTypes.cpp | 39 +- libs/androidfw/tests/ResTable_test.cpp | 33 -- libs/androidfw/tests/TestHelpers.h | 2 +- libs/androidfw/tests/data/system/R.h | 6 - .../tests/data/system/res/values-sv/values.xml | 20 -- libs/androidfw/tests/data/system/system_arsc.h | 69 ++-- 8 files changed, 243 insertions(+), 343 deletions(-) delete mode 100644 libs/androidfw/tests/data/system/res/values-sv/values.xml (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index aef92cf21711..4c4f128216f4 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -29,7 +29,6 @@ import android.content.res.ResourcesImpl; import android.content.res.ResourcesKey; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; -import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.LocaleList; @@ -431,44 +430,37 @@ public class ResourcesManager { @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) { - try { - Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, - "ResourcesManager#createBaseActivityResources"); - final ResourcesKey key = new ResourcesKey( - resDir, - splitResDirs, - overlayDirs, - libDirs, - displayId, - overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy - compatInfo); - classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); + final ResourcesKey key = new ResourcesKey( + resDir, + splitResDirs, + overlayDirs, + libDirs, + displayId, + overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy + compatInfo); + classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); - if (DEBUG) { - Slog.d(TAG, "createBaseActivityResources activity=" + activityToken - + " with key=" + key); - } + if (DEBUG) { + Slog.d(TAG, "createBaseActivityResources activity=" + activityToken + + " with key=" + key); + } - synchronized (this) { - final ActivityResources activityResources = - getOrCreateActivityResourcesStructLocked( - activityToken); + synchronized (this) { + final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( + activityToken); - if (overrideConfig != null) { - activityResources.overrideConfig.setTo(overrideConfig); - } else { - activityResources.overrideConfig.setToDefaults(); - } + if (overrideConfig != null) { + activityResources.overrideConfig.setTo(overrideConfig); + } else { + activityResources.overrideConfig.setToDefaults(); } + } - // Update any existing Activity Resources references. - updateResourcesForActivity(activityToken, overrideConfig); + // Update any existing Activity Resources references. + updateResourcesForActivity(activityToken, overrideConfig); - // Now request an actual Resources object. - return getOrCreateResources(activityToken, key, classLoader); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); - } + // Now request an actual Resources object. + return getOrCreateResources(activityToken, key, classLoader); } /** @@ -498,8 +490,8 @@ public class ResourcesManager { } if (activityToken != null) { - final ActivityResources activityResources = - getOrCreateActivityResourcesStructLocked(activityToken); + final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( + activityToken); // Clean up any dead references so they don't pile up. ArrayUtils.unstableRemoveIf(activityResources.activityResources, @@ -547,7 +539,6 @@ public class ResourcesManager { final String[] systemLocales = findSystemLocales ? AssetManager.getSystem().getLocales() : null; final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales(); - // Avoid checking for non-pseudo-locales if we already know there were some from a previous // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter, // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be @@ -622,21 +613,16 @@ public class ResourcesManager { @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) { - try { - Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources"); - final ResourcesKey key = new ResourcesKey( - resDir, - splitResDirs, - overlayDirs, - libDirs, - displayId, - overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy - compatInfo); - classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); - return getOrCreateResources(activityToken, key, classLoader); - } finally { - Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); - } + final ResourcesKey key = new ResourcesKey( + resDir, + splitResDirs, + overlayDirs, + libDirs, + displayId, + overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy + compatInfo); + classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); + return getOrCreateResources(activityToken, key, classLoader); } /** @@ -650,104 +636,93 @@ public class ResourcesManager { */ public void updateResourcesForActivity(@NonNull IBinder activityToken, @Nullable Configuration overrideConfig) { - try { - Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, - "ResourcesManager#updateResourcesForActivity"); - synchronized (this) { - final ActivityResources activityResources = - getOrCreateActivityResourcesStructLocked(activityToken); - - if (Objects.equals(activityResources.overrideConfig, overrideConfig)) { - // They are the same, no work to do. - return; - } + synchronized (this) { + final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( + activityToken); - // Grab a copy of the old configuration so we can create the delta's of each - // Resources object associated with this Activity. - final Configuration oldConfig = new Configuration(activityResources.overrideConfig); + if (Objects.equals(activityResources.overrideConfig, overrideConfig)) { + // They are the same, no work to do. + return; + } - // Update the Activity's base override. - if (overrideConfig != null) { - activityResources.overrideConfig.setTo(overrideConfig); - } else { - activityResources.overrideConfig.setToDefaults(); - } + // Grab a copy of the old configuration so we can create the delta's of each + // Resources object associated with this Activity. + final Configuration oldConfig = new Configuration(activityResources.overrideConfig); - if (DEBUG) { - Throwable here = new Throwable(); - here.fillInStackTrace(); - Slog.d(TAG, "updating resources override for activity=" + activityToken - + " from oldConfig=" - + Configuration.resourceQualifierString(oldConfig) - + " to newConfig=" - + Configuration.resourceQualifierString( - activityResources.overrideConfig), - here); - } + // Update the Activity's base override. + if (overrideConfig != null) { + activityResources.overrideConfig.setTo(overrideConfig); + } else { + activityResources.overrideConfig.setToDefaults(); + } - final boolean activityHasOverrideConfig = - !activityResources.overrideConfig.equals(Configuration.EMPTY); - - // Rebase each Resources associated with this Activity. - final int refCount = activityResources.activityResources.size(); - for (int i = 0; i < refCount; i++) { - WeakReference weakResRef = activityResources.activityResources.get( - i); - Resources resources = weakResRef.get(); - if (resources == null) { - continue; - } + if (DEBUG) { + Throwable here = new Throwable(); + here.fillInStackTrace(); + Slog.d(TAG, "updating resources override for activity=" + activityToken + + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig) + + " to newConfig=" + + Configuration.resourceQualifierString(activityResources.overrideConfig), + here); + } - // Extract the ResourcesKey that was last used to create the Resources for this - // activity. - final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl()); - if (oldKey == null) { - Slog.e(TAG, "can't find ResourcesKey for resources impl=" - + resources.getImpl()); - continue; - } + final boolean activityHasOverrideConfig = + !activityResources.overrideConfig.equals(Configuration.EMPTY); - // Build the new override configuration for this ResourcesKey. - final Configuration rebasedOverrideConfig = new Configuration(); - if (overrideConfig != null) { - rebasedOverrideConfig.setTo(overrideConfig); - } + // Rebase each Resources associated with this Activity. + final int refCount = activityResources.activityResources.size(); + for (int i = 0; i < refCount; i++) { + WeakReference weakResRef = activityResources.activityResources.get(i); + Resources resources = weakResRef.get(); + if (resources == null) { + continue; + } - if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) { - // Generate a delta between the old base Activity override configuration and - // the actual final override configuration that was used to figure out the - // real delta this Resources object wanted. - Configuration overrideOverrideConfig = Configuration.generateDelta( - oldConfig, oldKey.mOverrideConfiguration); - rebasedOverrideConfig.updateFrom(overrideOverrideConfig); - } + // Extract the ResourcesKey that was last used to create the Resources for this + // activity. + final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl()); + if (oldKey == null) { + Slog.e(TAG, "can't find ResourcesKey for resources impl=" + + resources.getImpl()); + continue; + } - // Create the new ResourcesKey with the rebased override config. - final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, - oldKey.mSplitResDirs, - oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId, - rebasedOverrideConfig, oldKey.mCompatInfo); + // Build the new override configuration for this ResourcesKey. + final Configuration rebasedOverrideConfig = new Configuration(); + if (overrideConfig != null) { + rebasedOverrideConfig.setTo(overrideConfig); + } - if (DEBUG) { - Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey - + " to newKey=" + newKey); - } + if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) { + // Generate a delta between the old base Activity override configuration and + // the actual final override configuration that was used to figure out the real + // delta this Resources object wanted. + Configuration overrideOverrideConfig = Configuration.generateDelta( + oldConfig, oldKey.mOverrideConfiguration); + rebasedOverrideConfig.updateFrom(overrideOverrideConfig); + } - ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey); - if (resourcesImpl == null) { - resourcesImpl = createResourcesImpl(newKey); - mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl)); - } + // Create the new ResourcesKey with the rebased override config. + final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs, + oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId, + rebasedOverrideConfig, oldKey.mCompatInfo); - if (resourcesImpl != resources.getImpl()) { - // Set the ResourcesImpl, updating it for all users of this Resources - // object. - resources.setImpl(resourcesImpl); - } + if (DEBUG) { + Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey + + " to newKey=" + newKey); + } + + ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey); + if (resourcesImpl == null) { + resourcesImpl = createResourcesImpl(newKey); + mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl)); + } + + if (resourcesImpl != resources.getImpl()) { + // Set the ResourcesImpl, updating it for all users of this Resources object. + resources.setImpl(resourcesImpl); } } - } finally { - Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } } @@ -770,95 +745,86 @@ public class ResourcesManager { public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { - try { - Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, - "ResourcesManager#applyConfigurationToResourcesLocked"); - - if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { - if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" - + mResConfiguration.seq + ", newSeq=" + config.seq); - return false; - } - int changes = mResConfiguration.updateFrom(config); - // Things might have changed in display manager, so clear the cached displays. - mDisplays.clear(); - DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); - - if (compat != null && (mResCompatibilityInfo == null || - !mResCompatibilityInfo.equals(compat))) { - mResCompatibilityInfo = compat; - changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT - | ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; - } + if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { + if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" + + mResConfiguration.seq + ", newSeq=" + config.seq); + return false; + } + int changes = mResConfiguration.updateFrom(config); + // Things might have changed in display manager, so clear the cached displays. + mDisplays.clear(); + DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); + + if (compat != null && (mResCompatibilityInfo == null || + !mResCompatibilityInfo.equals(compat))) { + mResCompatibilityInfo = compat; + changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + } - Configuration localeAdjustedConfig = config; - final LocaleList configLocales = config.getLocales(); - if (!configLocales.isEmpty()) { - setDefaultLocalesLocked(configLocales); - final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); - if (adjustedLocales - != configLocales) { // has the same result as .equals() in this case - // The first locale in the list was not chosen. So we create a modified - // configuration with the adjusted locales (which moves the chosen locale to the - // front). - localeAdjustedConfig = new Configuration(); - localeAdjustedConfig.setTo(config); - localeAdjustedConfig.setLocales(adjustedLocales); - // Also adjust the locale list in mResConfiguration, so that the Resources - // created later would have the same locale list. - if (!mResConfiguration.getLocales().equals(adjustedLocales)) { - mResConfiguration.setLocales(adjustedLocales); - changes |= ActivityInfo.CONFIG_LOCALE; - } + Configuration localeAdjustedConfig = config; + final LocaleList configLocales = config.getLocales(); + if (!configLocales.isEmpty()) { + setDefaultLocalesLocked(configLocales); + final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); + if (adjustedLocales != configLocales) { // has the same result as .equals() in this case + // The first locale in the list was not chosen. So we create a modified + // configuration with the adjusted locales (which moves the chosen locale to the + // front). + localeAdjustedConfig = new Configuration(); + localeAdjustedConfig.setTo(config); + localeAdjustedConfig.setLocales(adjustedLocales); + // Also adjust the locale list in mResConfiguration, so that the Resources created + // later would have the same locale list. + if (!mResConfiguration.getLocales().equals(adjustedLocales)) { + mResConfiguration.setLocales(adjustedLocales); + changes |= ActivityInfo.CONFIG_LOCALE; } } + } - Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, - compat); - - ApplicationPackageManager.configurationChanged(); - //Slog.i(TAG, "Configuration changed in " + currentPackageName()); - - Configuration tmpConfig = null; - - for (int i = mResourceImpls.size() - 1; i >= 0; i--) { - ResourcesKey key = mResourceImpls.keyAt(i); - ResourcesImpl r = mResourceImpls.valueAt(i).get(); - if (r != null) { - if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " - + r + " config to: " + localeAdjustedConfig); - int displayId = key.mDisplayId; - boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); - DisplayMetrics dm = defaultDisplayMetrics; - final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); - if (!isDefaultDisplay || hasOverrideConfiguration) { - if (tmpConfig == null) { - tmpConfig = new Configuration(); - } - tmpConfig.setTo(localeAdjustedConfig); - if (!isDefaultDisplay) { - dm = getDisplayMetrics(displayId); - applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); - } - if (hasOverrideConfiguration) { - tmpConfig.updateFrom(key.mOverrideConfiguration); - } - r.updateConfiguration(tmpConfig, dm, compat); - } else { - r.updateConfiguration(localeAdjustedConfig, dm, compat); + Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat); + + ApplicationPackageManager.configurationChanged(); + //Slog.i(TAG, "Configuration changed in " + currentPackageName()); + + Configuration tmpConfig = null; + + for (int i = mResourceImpls.size() - 1; i >= 0; i--) { + ResourcesKey key = mResourceImpls.keyAt(i); + ResourcesImpl r = mResourceImpls.valueAt(i).get(); + if (r != null) { + if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + + r + " config to: " + localeAdjustedConfig); + int displayId = key.mDisplayId; + boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + DisplayMetrics dm = defaultDisplayMetrics; + final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); + if (!isDefaultDisplay || hasOverrideConfiguration) { + if (tmpConfig == null) { + tmpConfig = new Configuration(); + } + tmpConfig.setTo(localeAdjustedConfig); + if (!isDefaultDisplay) { + dm = getDisplayMetrics(displayId); + applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); + } + if (hasOverrideConfiguration) { + tmpConfig.updateFrom(key.mOverrideConfiguration); } - //Slog.i(TAG, "Updated app resources " + v.getKey() - // + " " + r + ": " + r.getConfiguration()); + r.updateConfiguration(tmpConfig, dm, compat); } else { - //Slog.i(TAG, "Removing old resources " + v.getKey()); - mResourceImpls.removeAt(i); + r.updateConfiguration(localeAdjustedConfig, dm, compat); } + //Slog.i(TAG, "Updated app resources " + v.getKey() + // + " " + r + ": " + r.getConfiguration()); + } else { + //Slog.i(TAG, "Removing old resources " + v.getKey()); + mResourceImpls.removeAt(i); } - - return changes != 0; - } finally { - Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } + + return changes != 0; } } diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 715c875d064d..6913f43a87c3 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -34,7 +34,9 @@ #include #include #include -#include +#ifdef __ANDROID__ +#include +#endif #include #include @@ -52,6 +54,14 @@ _rc; }) #endif +#ifdef __ANDROID__ +#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x) +#define MY_TRACE_END() ATRACE_END() +#else +#define MY_TRACE_BEGIN(x) +#define MY_TRACE_END() +#endif + using namespace android; static const bool kIsDebug = false; @@ -613,7 +623,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con ResTable* sharedRes = NULL; bool shared = true; bool onlyEmptyResources = true; - ATRACE_NAME(ap.path.string()); + MY_TRACE_BEGIN(ap.path.string()); Asset* idmap = openIdmapLocked(ap); size_t nextEntryIdx = mResources->getTableCount(); ALOGV("Looking for resource asset in '%s'\n", ap.path.string()); @@ -693,6 +703,8 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con if (idmap != NULL) { delete idmap; } + MY_TRACE_END(); + return onlyEmptyResources; } @@ -740,7 +752,6 @@ const ResTable* AssetManager::getResTable(bool required) const void AssetManager::updateResourceParamsLocked() const { - ATRACE_CALL(); ResTable* res = mResources; if (!res) { return; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 15cb684ee08e..1ccc59a6a348 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -24,7 +24,6 @@ #include #include -#include #include #include #include @@ -5811,10 +5810,6 @@ const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) con return NULL; } -static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) { - return a.compare(b) < 0; -} - void ResTable::getConfigurations(Vector* configs, bool ignoreMipmap, bool ignoreAndroidPackage, bool includeSystemConfigs) const { const size_t packageCount = mPackageGroups.size(); @@ -5845,11 +5840,17 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi ResTable_config cfg; memset(&cfg, 0, sizeof(ResTable_config)); cfg.copyFromDtoH(config->config); - - auto iter = std::lower_bound(configs->begin(), configs->end(), cfg, - compareResTableConfig); - if (iter == configs->end() || iter->compare(cfg) != 0) { - configs->insertAt(cfg, std::distance(configs->begin(), iter)); + // only insert unique + const size_t N = configs->size(); + size_t n; + for (n = 0; n < N; n++) { + if (0 == (*configs)[n].compare(cfg)) { + break; + } + } + // if we didn't find it + if (n == N) { + configs->add(cfg); } } } @@ -5857,10 +5858,6 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi } } -static bool compareString8AndCString(const String8& str, const char* cStr) { - return strcmp(str.string(), cStr) < 0; -} - void ResTable::getLocales(Vector* locales, bool includeSystemLocales) const { Vector configs; @@ -5875,11 +5872,15 @@ void ResTable::getLocales(Vector* locales, bool includeSystemLocales) c char locale[RESTABLE_MAX_LOCALE_LEN]; for (size_t i=0; ibegin(), locales->end(), locale, - compareString8AndCString); - if (iter == locales->end() || strcmp(iter->string(), locale) != 0) { - locales->insertAt(String8(locale), std::distance(locales->begin(), iter)); + const size_t J = locales->size(); + size_t j; + for (j=0; jadd(String8(locale)); } } } diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp index b8b46259f0d1..7cd7fb5cd711 100644 --- a/libs/androidfw/tests/ResTable_test.cpp +++ b/libs/androidfw/tests/ResTable_test.cpp @@ -39,20 +39,8 @@ namespace { */ #include "data/basic/basic_arsc.h" -/** - * Include a binary library resource table. - * - * Package: com.android.test.basic - */ #include "data/lib/lib_arsc.h" -/** - * Include a system resource table. - * - * Package: android - */ -#include "data/system/system_arsc.h" - TEST(ResTableTest, shouldLoadSuccessfully) { ResTable table; ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); @@ -336,25 +324,4 @@ TEST(ResTableTest, ShareButDontModifyResTable) { ASSERT_EQ(uint32_t(600), val.data); } -TEST(ResTableTest, GetConfigurationsReturnsUniqueList) { - ResTable table; - ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len)); - ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); - - ResTable_config configSv; - memset(&configSv, 0, sizeof(configSv)); - configSv.language[0] = 's'; - configSv.language[1] = 'v'; - - Vector configs; - table.getConfigurations(&configs); - - EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv)); - - Vector locales; - table.getLocales(&locales); - - EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv"))); -} - } // namespace diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h index ff9be164dbb0..ac80d8868090 100644 --- a/libs/androidfw/tests/TestHelpers.h +++ b/libs/androidfw/tests/TestHelpers.h @@ -21,7 +21,7 @@ namespace android { enum { MAY_NOT_BE_BAG = false }; static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) { - return a.compare(b) == 0; + return memcmp(&a, &b, sizeof(a)) == 0; } static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) { diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h index 6a31fb8ff088..27f25fec0d01 100644 --- a/libs/androidfw/tests/data/system/R.h +++ b/libs/androidfw/tests/data/system/R.h @@ -33,12 +33,6 @@ namespace style { }; } -namespace integer { - enum { - number = 0x01030000, // sv - }; -} - } // namespace R } // namespace android diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml deleted file mode 100644 index b97bdb68aca7..000000000000 --- a/libs/androidfw/tests/data/system/res/values-sv/values.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - 1 - diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h index b0dab6b357e9..215ecae552c5 100644 --- a/libs/androidfw/tests/data/system/system_arsc.h +++ b/libs/androidfw/tests/data/system/system_arsc.h @@ -1,8 +1,8 @@ unsigned char system_arsc[] = { - 0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -25,33 +25,26 @@ unsigned char system_arsc[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, - 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00, - 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00, - 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, + 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, + 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, - 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, - 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, + 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -62,27 +55,15 @@ unsigned char system_arsc[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, - 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, - 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01, - 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, - 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, + 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff }; -unsigned int system_arsc_len = 1016; +unsigned int system_arsc_len = 792; -- cgit v1.2.3-59-g8ed1b From b7e1ce07756aaca829828c2053eca0d66dd4d440 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Mon, 11 Apr 2016 20:03:01 -0700 Subject: Optimize ResTable::getLocales() to improve bindApplication performance Change from linear searching for uniqueness to binary search. Bug:27198799 Change-Id: I1ccb6e93cc213810848f07d631d9d8de7c719803 --- core/java/android/app/ResourcesManager.java | 400 +++++++++++---------- libs/androidfw/AssetManager.cpp | 17 +- libs/androidfw/ResourceTypes.cpp | 39 +- libs/androidfw/tests/ResTable_test.cpp | 33 ++ libs/androidfw/tests/TestHelpers.h | 2 +- libs/androidfw/tests/data/system/R.h | 6 + .../tests/data/system/res/values-sv/values.xml | 20 ++ libs/androidfw/tests/data/system/system_arsc.h | 69 ++-- 8 files changed, 343 insertions(+), 243 deletions(-) create mode 100644 libs/androidfw/tests/data/system/res/values-sv/values.xml (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 4c4f128216f4..aef92cf21711 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -29,6 +29,7 @@ import android.content.res.ResourcesImpl; import android.content.res.ResourcesKey; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; +import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; import android.util.LocaleList; @@ -430,37 +431,44 @@ public class ResourcesManager { @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) { - final ResourcesKey key = new ResourcesKey( - resDir, - splitResDirs, - overlayDirs, - libDirs, - displayId, - overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy - compatInfo); - classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#createBaseActivityResources"); + final ResourcesKey key = new ResourcesKey( + resDir, + splitResDirs, + overlayDirs, + libDirs, + displayId, + overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy + compatInfo); + classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); - if (DEBUG) { - Slog.d(TAG, "createBaseActivityResources activity=" + activityToken - + " with key=" + key); - } + if (DEBUG) { + Slog.d(TAG, "createBaseActivityResources activity=" + activityToken + + " with key=" + key); + } - synchronized (this) { - final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( - activityToken); + synchronized (this) { + final ActivityResources activityResources = + getOrCreateActivityResourcesStructLocked( + activityToken); - if (overrideConfig != null) { - activityResources.overrideConfig.setTo(overrideConfig); - } else { - activityResources.overrideConfig.setToDefaults(); + if (overrideConfig != null) { + activityResources.overrideConfig.setTo(overrideConfig); + } else { + activityResources.overrideConfig.setToDefaults(); + } } - } - // Update any existing Activity Resources references. - updateResourcesForActivity(activityToken, overrideConfig); + // Update any existing Activity Resources references. + updateResourcesForActivity(activityToken, overrideConfig); - // Now request an actual Resources object. - return getOrCreateResources(activityToken, key, classLoader); + // Now request an actual Resources object. + return getOrCreateResources(activityToken, key, classLoader); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } } /** @@ -490,8 +498,8 @@ public class ResourcesManager { } if (activityToken != null) { - final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( - activityToken); + final ActivityResources activityResources = + getOrCreateActivityResourcesStructLocked(activityToken); // Clean up any dead references so they don't pile up. ArrayUtils.unstableRemoveIf(activityResources.activityResources, @@ -539,6 +547,7 @@ public class ResourcesManager { final String[] systemLocales = findSystemLocales ? AssetManager.getSystem().getLocales() : null; final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales(); + // Avoid checking for non-pseudo-locales if we already know there were some from a previous // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter, // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be @@ -613,16 +622,21 @@ public class ResourcesManager { @Nullable Configuration overrideConfig, @NonNull CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) { - final ResourcesKey key = new ResourcesKey( - resDir, - splitResDirs, - overlayDirs, - libDirs, - displayId, - overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy - compatInfo); - classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); - return getOrCreateResources(activityToken, key, classLoader); + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources"); + final ResourcesKey key = new ResourcesKey( + resDir, + splitResDirs, + overlayDirs, + libDirs, + displayId, + overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy + compatInfo); + classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); + return getOrCreateResources(activityToken, key, classLoader); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } } /** @@ -636,93 +650,104 @@ public class ResourcesManager { */ public void updateResourcesForActivity(@NonNull IBinder activityToken, @Nullable Configuration overrideConfig) { - synchronized (this) { - final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( - activityToken); - - if (Objects.equals(activityResources.overrideConfig, overrideConfig)) { - // They are the same, no work to do. - return; - } - - // Grab a copy of the old configuration so we can create the delta's of each - // Resources object associated with this Activity. - final Configuration oldConfig = new Configuration(activityResources.overrideConfig); - - // Update the Activity's base override. - if (overrideConfig != null) { - activityResources.overrideConfig.setTo(overrideConfig); - } else { - activityResources.overrideConfig.setToDefaults(); - } - - if (DEBUG) { - Throwable here = new Throwable(); - here.fillInStackTrace(); - Slog.d(TAG, "updating resources override for activity=" + activityToken - + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig) - + " to newConfig=" - + Configuration.resourceQualifierString(activityResources.overrideConfig), - here); - } - - final boolean activityHasOverrideConfig = - !activityResources.overrideConfig.equals(Configuration.EMPTY); - - // Rebase each Resources associated with this Activity. - final int refCount = activityResources.activityResources.size(); - for (int i = 0; i < refCount; i++) { - WeakReference weakResRef = activityResources.activityResources.get(i); - Resources resources = weakResRef.get(); - if (resources == null) { - continue; + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#updateResourcesForActivity"); + synchronized (this) { + final ActivityResources activityResources = + getOrCreateActivityResourcesStructLocked(activityToken); + + if (Objects.equals(activityResources.overrideConfig, overrideConfig)) { + // They are the same, no work to do. + return; } - // Extract the ResourcesKey that was last used to create the Resources for this - // activity. - final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl()); - if (oldKey == null) { - Slog.e(TAG, "can't find ResourcesKey for resources impl=" - + resources.getImpl()); - continue; - } + // Grab a copy of the old configuration so we can create the delta's of each + // Resources object associated with this Activity. + final Configuration oldConfig = new Configuration(activityResources.overrideConfig); - // Build the new override configuration for this ResourcesKey. - final Configuration rebasedOverrideConfig = new Configuration(); + // Update the Activity's base override. if (overrideConfig != null) { - rebasedOverrideConfig.setTo(overrideConfig); + activityResources.overrideConfig.setTo(overrideConfig); + } else { + activityResources.overrideConfig.setToDefaults(); } - if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) { - // Generate a delta between the old base Activity override configuration and - // the actual final override configuration that was used to figure out the real - // delta this Resources object wanted. - Configuration overrideOverrideConfig = Configuration.generateDelta( - oldConfig, oldKey.mOverrideConfiguration); - rebasedOverrideConfig.updateFrom(overrideOverrideConfig); + if (DEBUG) { + Throwable here = new Throwable(); + here.fillInStackTrace(); + Slog.d(TAG, "updating resources override for activity=" + activityToken + + " from oldConfig=" + + Configuration.resourceQualifierString(oldConfig) + + " to newConfig=" + + Configuration.resourceQualifierString( + activityResources.overrideConfig), + here); } - // Create the new ResourcesKey with the rebased override config. - final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs, - oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId, - rebasedOverrideConfig, oldKey.mCompatInfo); + final boolean activityHasOverrideConfig = + !activityResources.overrideConfig.equals(Configuration.EMPTY); + + // Rebase each Resources associated with this Activity. + final int refCount = activityResources.activityResources.size(); + for (int i = 0; i < refCount; i++) { + WeakReference weakResRef = activityResources.activityResources.get( + i); + Resources resources = weakResRef.get(); + if (resources == null) { + continue; + } - if (DEBUG) { - Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey - + " to newKey=" + newKey); - } + // Extract the ResourcesKey that was last used to create the Resources for this + // activity. + final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl()); + if (oldKey == null) { + Slog.e(TAG, "can't find ResourcesKey for resources impl=" + + resources.getImpl()); + continue; + } - ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey); - if (resourcesImpl == null) { - resourcesImpl = createResourcesImpl(newKey); - mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl)); - } + // Build the new override configuration for this ResourcesKey. + final Configuration rebasedOverrideConfig = new Configuration(); + if (overrideConfig != null) { + rebasedOverrideConfig.setTo(overrideConfig); + } + + if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) { + // Generate a delta between the old base Activity override configuration and + // the actual final override configuration that was used to figure out the + // real delta this Resources object wanted. + Configuration overrideOverrideConfig = Configuration.generateDelta( + oldConfig, oldKey.mOverrideConfiguration); + rebasedOverrideConfig.updateFrom(overrideOverrideConfig); + } + + // Create the new ResourcesKey with the rebased override config. + final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, + oldKey.mSplitResDirs, + oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId, + rebasedOverrideConfig, oldKey.mCompatInfo); + + if (DEBUG) { + Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey + + " to newKey=" + newKey); + } - if (resourcesImpl != resources.getImpl()) { - // Set the ResourcesImpl, updating it for all users of this Resources object. - resources.setImpl(resourcesImpl); + ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey); + if (resourcesImpl == null) { + resourcesImpl = createResourcesImpl(newKey); + mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl)); + } + + if (resourcesImpl != resources.getImpl()) { + // Set the ResourcesImpl, updating it for all users of this Resources + // object. + resources.setImpl(resourcesImpl); + } } } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); } } @@ -745,86 +770,95 @@ public class ResourcesManager { public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, @Nullable CompatibilityInfo compat) { - if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { - if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" - + mResConfiguration.seq + ", newSeq=" + config.seq); - return false; - } - int changes = mResConfiguration.updateFrom(config); - // Things might have changed in display manager, so clear the cached displays. - mDisplays.clear(); - DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); - - if (compat != null && (mResCompatibilityInfo == null || - !mResCompatibilityInfo.equals(compat))) { - mResCompatibilityInfo = compat; - changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT - | ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; - } + try { + Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, + "ResourcesManager#applyConfigurationToResourcesLocked"); + + if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { + if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" + + mResConfiguration.seq + ", newSeq=" + config.seq); + return false; + } + int changes = mResConfiguration.updateFrom(config); + // Things might have changed in display manager, so clear the cached displays. + mDisplays.clear(); + DisplayMetrics defaultDisplayMetrics = getDisplayMetrics(); + + if (compat != null && (mResCompatibilityInfo == null || + !mResCompatibilityInfo.equals(compat))) { + mResCompatibilityInfo = compat; + changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT + | ActivityInfo.CONFIG_SCREEN_SIZE + | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + } - Configuration localeAdjustedConfig = config; - final LocaleList configLocales = config.getLocales(); - if (!configLocales.isEmpty()) { - setDefaultLocalesLocked(configLocales); - final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); - if (adjustedLocales != configLocales) { // has the same result as .equals() in this case - // The first locale in the list was not chosen. So we create a modified - // configuration with the adjusted locales (which moves the chosen locale to the - // front). - localeAdjustedConfig = new Configuration(); - localeAdjustedConfig.setTo(config); - localeAdjustedConfig.setLocales(adjustedLocales); - // Also adjust the locale list in mResConfiguration, so that the Resources created - // later would have the same locale list. - if (!mResConfiguration.getLocales().equals(adjustedLocales)) { - mResConfiguration.setLocales(adjustedLocales); - changes |= ActivityInfo.CONFIG_LOCALE; + Configuration localeAdjustedConfig = config; + final LocaleList configLocales = config.getLocales(); + if (!configLocales.isEmpty()) { + setDefaultLocalesLocked(configLocales); + final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); + if (adjustedLocales + != configLocales) { // has the same result as .equals() in this case + // The first locale in the list was not chosen. So we create a modified + // configuration with the adjusted locales (which moves the chosen locale to the + // front). + localeAdjustedConfig = new Configuration(); + localeAdjustedConfig.setTo(config); + localeAdjustedConfig.setLocales(adjustedLocales); + // Also adjust the locale list in mResConfiguration, so that the Resources + // created later would have the same locale list. + if (!mResConfiguration.getLocales().equals(adjustedLocales)) { + mResConfiguration.setLocales(adjustedLocales); + changes |= ActivityInfo.CONFIG_LOCALE; + } } } - } - Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat); - - ApplicationPackageManager.configurationChanged(); - //Slog.i(TAG, "Configuration changed in " + currentPackageName()); - - Configuration tmpConfig = null; - - for (int i = mResourceImpls.size() - 1; i >= 0; i--) { - ResourcesKey key = mResourceImpls.keyAt(i); - ResourcesImpl r = mResourceImpls.valueAt(i).get(); - if (r != null) { - if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " - + r + " config to: " + localeAdjustedConfig); - int displayId = key.mDisplayId; - boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); - DisplayMetrics dm = defaultDisplayMetrics; - final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); - if (!isDefaultDisplay || hasOverrideConfiguration) { - if (tmpConfig == null) { - tmpConfig = new Configuration(); - } - tmpConfig.setTo(localeAdjustedConfig); - if (!isDefaultDisplay) { - dm = getDisplayMetrics(displayId); - applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); - } - if (hasOverrideConfiguration) { - tmpConfig.updateFrom(key.mOverrideConfiguration); + Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, + compat); + + ApplicationPackageManager.configurationChanged(); + //Slog.i(TAG, "Configuration changed in " + currentPackageName()); + + Configuration tmpConfig = null; + + for (int i = mResourceImpls.size() - 1; i >= 0; i--) { + ResourcesKey key = mResourceImpls.keyAt(i); + ResourcesImpl r = mResourceImpls.valueAt(i).get(); + if (r != null) { + if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources " + + r + " config to: " + localeAdjustedConfig); + int displayId = key.mDisplayId; + boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY); + DisplayMetrics dm = defaultDisplayMetrics; + final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); + if (!isDefaultDisplay || hasOverrideConfiguration) { + if (tmpConfig == null) { + tmpConfig = new Configuration(); + } + tmpConfig.setTo(localeAdjustedConfig); + if (!isDefaultDisplay) { + dm = getDisplayMetrics(displayId); + applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); + } + if (hasOverrideConfiguration) { + tmpConfig.updateFrom(key.mOverrideConfiguration); + } + r.updateConfiguration(tmpConfig, dm, compat); + } else { + r.updateConfiguration(localeAdjustedConfig, dm, compat); } - r.updateConfiguration(tmpConfig, dm, compat); + //Slog.i(TAG, "Updated app resources " + v.getKey() + // + " " + r + ": " + r.getConfiguration()); } else { - r.updateConfiguration(localeAdjustedConfig, dm, compat); + //Slog.i(TAG, "Removing old resources " + v.getKey()); + mResourceImpls.removeAt(i); } - //Slog.i(TAG, "Updated app resources " + v.getKey() - // + " " + r + ": " + r.getConfiguration()); - } else { - //Slog.i(TAG, "Removing old resources " + v.getKey()); - mResourceImpls.removeAt(i); } - } - return changes != 0; + return changes != 0; + } finally { + Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); + } } } diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 6913f43a87c3..715c875d064d 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -34,9 +34,7 @@ #include #include #include -#ifdef __ANDROID__ -#include -#endif +#include #include #include @@ -54,14 +52,6 @@ _rc; }) #endif -#ifdef __ANDROID__ -#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x) -#define MY_TRACE_END() ATRACE_END() -#else -#define MY_TRACE_BEGIN(x) -#define MY_TRACE_END() -#endif - using namespace android; static const bool kIsDebug = false; @@ -623,7 +613,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con ResTable* sharedRes = NULL; bool shared = true; bool onlyEmptyResources = true; - MY_TRACE_BEGIN(ap.path.string()); + ATRACE_NAME(ap.path.string()); Asset* idmap = openIdmapLocked(ap); size_t nextEntryIdx = mResources->getTableCount(); ALOGV("Looking for resource asset in '%s'\n", ap.path.string()); @@ -703,8 +693,6 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con if (idmap != NULL) { delete idmap; } - MY_TRACE_END(); - return onlyEmptyResources; } @@ -752,6 +740,7 @@ const ResTable* AssetManager::getResTable(bool required) const void AssetManager::updateResourceParamsLocked() const { + ATRACE_CALL(); ResTable* res = mResources; if (!res) { return; diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 1ccc59a6a348..15cb684ee08e 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -5810,6 +5811,10 @@ const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) con return NULL; } +static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) { + return a.compare(b) < 0; +} + void ResTable::getConfigurations(Vector* configs, bool ignoreMipmap, bool ignoreAndroidPackage, bool includeSystemConfigs) const { const size_t packageCount = mPackageGroups.size(); @@ -5840,17 +5845,11 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi ResTable_config cfg; memset(&cfg, 0, sizeof(ResTable_config)); cfg.copyFromDtoH(config->config); - // only insert unique - const size_t N = configs->size(); - size_t n; - for (n = 0; n < N; n++) { - if (0 == (*configs)[n].compare(cfg)) { - break; - } - } - // if we didn't find it - if (n == N) { - configs->add(cfg); + + auto iter = std::lower_bound(configs->begin(), configs->end(), cfg, + compareResTableConfig); + if (iter == configs->end() || iter->compare(cfg) != 0) { + configs->insertAt(cfg, std::distance(configs->begin(), iter)); } } } @@ -5858,6 +5857,10 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi } } +static bool compareString8AndCString(const String8& str, const char* cStr) { + return strcmp(str.string(), cStr) < 0; +} + void ResTable::getLocales(Vector* locales, bool includeSystemLocales) const { Vector configs; @@ -5872,15 +5875,11 @@ void ResTable::getLocales(Vector* locales, bool includeSystemLocales) c char locale[RESTABLE_MAX_LOCALE_LEN]; for (size_t i=0; isize(); - size_t j; - for (j=0; jadd(String8(locale)); + + auto iter = std::lower_bound(locales->begin(), locales->end(), locale, + compareString8AndCString); + if (iter == locales->end() || strcmp(iter->string(), locale) != 0) { + locales->insertAt(String8(locale), std::distance(locales->begin(), iter)); } } } diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp index 7cd7fb5cd711..b8b46259f0d1 100644 --- a/libs/androidfw/tests/ResTable_test.cpp +++ b/libs/androidfw/tests/ResTable_test.cpp @@ -39,8 +39,20 @@ namespace { */ #include "data/basic/basic_arsc.h" +/** + * Include a binary library resource table. + * + * Package: com.android.test.basic + */ #include "data/lib/lib_arsc.h" +/** + * Include a system resource table. + * + * Package: android + */ +#include "data/system/system_arsc.h" + TEST(ResTableTest, shouldLoadSuccessfully) { ResTable table; ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); @@ -324,4 +336,25 @@ TEST(ResTableTest, ShareButDontModifyResTable) { ASSERT_EQ(uint32_t(600), val.data); } +TEST(ResTableTest, GetConfigurationsReturnsUniqueList) { + ResTable table; + ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len)); + ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); + + ResTable_config configSv; + memset(&configSv, 0, sizeof(configSv)); + configSv.language[0] = 's'; + configSv.language[1] = 'v'; + + Vector configs; + table.getConfigurations(&configs); + + EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv)); + + Vector locales; + table.getLocales(&locales); + + EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv"))); +} + } // namespace diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h index ac80d8868090..ff9be164dbb0 100644 --- a/libs/androidfw/tests/TestHelpers.h +++ b/libs/androidfw/tests/TestHelpers.h @@ -21,7 +21,7 @@ namespace android { enum { MAY_NOT_BE_BAG = false }; static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) { - return memcmp(&a, &b, sizeof(a)) == 0; + return a.compare(b) == 0; } static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) { diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h index 27f25fec0d01..6a31fb8ff088 100644 --- a/libs/androidfw/tests/data/system/R.h +++ b/libs/androidfw/tests/data/system/R.h @@ -33,6 +33,12 @@ namespace style { }; } +namespace integer { + enum { + number = 0x01030000, // sv + }; +} + } // namespace R } // namespace android diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml new file mode 100644 index 000000000000..b97bdb68aca7 --- /dev/null +++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml @@ -0,0 +1,20 @@ + + + + + + 1 + diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h index 215ecae552c5..b0dab6b357e9 100644 --- a/libs/androidfw/tests/data/system/system_arsc.h +++ b/libs/androidfw/tests/data/system/system_arsc.h @@ -1,8 +1,8 @@ unsigned char system_arsc[] = { - 0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -25,26 +25,33 @@ unsigned char system_arsc[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, - 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, - 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00, + 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00, + 0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, - 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, - 0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -55,15 +62,27 @@ unsigned char system_arsc[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00, - 0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, - 0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01, + 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -unsigned int system_arsc_len = 792; +unsigned int system_arsc_len = 1016; -- cgit v1.2.3-59-g8ed1b From 76da37e1cf5c1381d9ccbaca86463fca52bd40f5 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Thu, 19 May 2016 18:25:28 -0700 Subject: Performance improvements in AssetManager Change the implementation of getLocales() to iterate the set of configurations using a templated method, instead of using the result of getConfigurations(). Also remove the check for AndroidManifest.xml when adding an asset path. This is unneccessary. Bug:28625993 Change-Id: I16de5da598d0c371421d1dc8eee054dce9baf53a --- include/androidfw/ResourceTypes.h | 4 +++ libs/androidfw/AssetManager.cpp | 11 -------- libs/androidfw/ResourceTypes.cpp | 58 +++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 37 deletions(-) (limited to 'libs/androidfw/AssetManager.cpp') diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index cf4ff8201b8c..12a6b0f9a4ec 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -1924,6 +1924,10 @@ private: void print_value(const Package* pkg, const Res_value& value) const; + template + void forEachConfiguration(bool ignoreMipmap, bool ignoreAndroidPackage, + bool includeSystemConfigs, const Func& f) const; + mutable Mutex mLock; // Mutex that controls access to the list of pre-filtered configurations diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 715c875d064d..f50cff4387d2 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -66,7 +66,6 @@ static const char* kAssetsRoot = "assets"; static const char* kAppZipName = NULL; //"classes.jar"; static const char* kSystemAssets = "framework/framework-res.apk"; static const char* kResourceCache = "resource-cache"; -static const char* kAndroidManifest = "AndroidManifest.xml"; static const char* kExcludeExtension = ".EXCLUDE"; @@ -203,16 +202,6 @@ bool AssetManager::addAssetPath( ALOGV("In %p Asset %s path: %s", this, ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string()); - // Check that the path has an AndroidManifest.xml - Asset* manifestAsset = const_cast(this)->openNonAssetInPathLocked( - kAndroidManifest, Asset::ACCESS_BUFFER, ap); - if (manifestAsset == NULL) { - // This asset path does not contain any resources. - delete manifestAsset; - return false; - } - delete manifestAsset; - ap.isSystemAsset = isSystemAsset; mAssetPaths.add(ap); diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 36b1f4b664c2..d447a38c9b90 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -5822,10 +5822,11 @@ static bool compareResTableConfig(const ResTable_config& a, const ResTable_confi return a.compare(b) < 0; } -void ResTable::getConfigurations(Vector* configs, bool ignoreMipmap, - bool ignoreAndroidPackage, bool includeSystemConfigs) const { +template +void ResTable::forEachConfiguration(bool ignoreMipmap, bool ignoreAndroidPackage, + bool includeSystemConfigs, const Func& f) const { const size_t packageCount = mPackageGroups.size(); - String16 android("android"); + const String16 android("android"); for (size_t i = 0; i < packageCount; i++) { const PackageGroup* packageGroup = mPackageGroups[i]; if (ignoreAndroidPackage && android == packageGroup->name) { @@ -5853,42 +5854,47 @@ void ResTable::getConfigurations(Vector* configs, bool ignoreMi memset(&cfg, 0, sizeof(ResTable_config)); cfg.copyFromDtoH(config->config); - auto iter = std::lower_bound(configs->begin(), configs->end(), cfg, - compareResTableConfig); - if (iter == configs->end() || iter->compare(cfg) != 0) { - configs->insertAt(cfg, std::distance(configs->begin(), iter)); - } + f(cfg); } } } } } +void ResTable::getConfigurations(Vector* configs, bool ignoreMipmap, + bool ignoreAndroidPackage, bool includeSystemConfigs) const { + auto func = [&](const ResTable_config& cfg) { + const auto beginIter = configs->begin(); + const auto endIter = configs->end(); + + auto iter = std::lower_bound(beginIter, endIter, cfg, compareResTableConfig); + if (iter == endIter || iter->compare(cfg) != 0) { + configs->insertAt(cfg, std::distance(beginIter, iter)); + } + }; + forEachConfiguration(ignoreMipmap, ignoreAndroidPackage, includeSystemConfigs, func); +} + static bool compareString8AndCString(const String8& str, const char* cStr) { return strcmp(str.string(), cStr) < 0; } -void ResTable::getLocales(Vector* locales, bool includeSystemLocales) const -{ - Vector configs; - ALOGV("calling getConfigurations"); - getConfigurations(&configs, - false /* ignoreMipmap */, - false /* ignoreAndroidPackage */, - includeSystemLocales /* includeSystemConfigs */); - ALOGV("called getConfigurations size=%d", (int)configs.size()); - const size_t I = configs.size(); - +void ResTable::getLocales(Vector* locales, bool includeSystemLocales) const { char locale[RESTABLE_MAX_LOCALE_LEN]; - for (size_t i=0; ibegin(), locales->end(), locale, - compareString8AndCString); - if (iter == locales->end() || strcmp(iter->string(), locale) != 0) { - locales->insertAt(String8(locale), std::distance(locales->begin(), iter)); + forEachConfiguration(false, false, includeSystemLocales, [&](const ResTable_config& cfg) { + if (cfg.locale != 0) { + cfg.getBcp47Locale(locale); + + const auto beginIter = locales->begin(); + const auto endIter = locales->end(); + + auto iter = std::lower_bound(beginIter, endIter, locale, compareString8AndCString); + if (iter == endIter || strcmp(iter->string(), locale) != 0) { + locales->insertAt(String8(locale), std::distance(beginIter, iter)); + } } - } + }); } StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index) -- cgit v1.2.3-59-g8ed1b