diff options
author | 2016-04-11 20:03:01 -0700 | |
---|---|---|
committer | 2016-04-18 15:06:50 -0700 | |
commit | b7e1ce07756aaca829828c2053eca0d66dd4d440 (patch) | |
tree | 5e985290e92e597d7aa7409915688d73d2352080 | |
parent | 9d1d006cb3fb85304d1002b0d71c1b9fa11ad2f6 (diff) |
Optimize ResTable::getLocales() to improve bindApplication performance
Change from linear searching for uniqueness to binary search.
Bug:27198799
Change-Id: I1ccb6e93cc213810848f07d631d9d8de7c719803
-rw-r--r-- | core/java/android/app/ResourcesManager.java | 400 | ||||
-rw-r--r-- | libs/androidfw/AssetManager.cpp | 17 | ||||
-rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 39 | ||||
-rw-r--r-- | libs/androidfw/tests/ResTable_test.cpp | 33 | ||||
-rw-r--r-- | libs/androidfw/tests/TestHelpers.h | 2 | ||||
-rw-r--r-- | libs/androidfw/tests/data/system/R.h | 6 | ||||
-rw-r--r-- | libs/androidfw/tests/data/system/res/values-sv/values.xml | 20 | ||||
-rw-r--r-- | libs/androidfw/tests/data/system/system_arsc.h | 69 |
8 files changed, 343 insertions, 243 deletions
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<Resources> 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<Resources> 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 <utils/String8.h> #include <utils/threads.h> #include <utils/Timers.h> -#ifdef __ANDROID__ -#include <cutils/trace.h> -#endif +#include <utils/Trace.h> #include <assert.h> #include <dirent.h> @@ -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 <stdlib.h> #include <string.h> +#include <algorithm> #include <limits> #include <memory> #include <type_traits> @@ -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<ResTable_config>* configs, bool ignoreMipmap, bool ignoreAndroidPackage, bool includeSystemConfigs) const { const size_t packageCount = mPackageGroups.size(); @@ -5840,17 +5845,11 @@ void ResTable::getConfigurations(Vector<ResTable_config>* 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<ResTable_config>* configs, bool ignoreMi } } +static bool compareString8AndCString(const String8& str, const char* cStr) { + return strcmp(str.string(), cStr) < 0; +} + void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const { Vector<ResTable_config> configs; @@ -5872,15 +5875,11 @@ void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) c char locale[RESTABLE_MAX_LOCALE_LEN]; for (size_t i=0; i<I; i++) { configs[i].getBcp47Locale(locale); - const size_t J = locales->size(); - size_t j; - for (j=0; j<J; j++) { - if (0 == strcmp(locale, (*locales)[j].string())) { - break; - } - } - if (j == J) { - locales->add(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<ResTable_config> configs; + table.getConfigurations(&configs); + + EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv)); + + Vector<String8> 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 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<resources> + <public type="integer" name="number" id="0x01030000" /> + <integer name="number">1</integer> +</resources> 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; |