Merge "Pass all preferred locales to AssetManager" into main
This commit is contained in:
@@ -40,7 +40,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
@@ -195,7 +195,8 @@ public class LocaleConfig implements Parcelable {
|
||||
XmlUtils.beginDocument(parser, TAG_LOCALE_CONFIG);
|
||||
int outerDepth = parser.getDepth();
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
Set<String> localeNames = new HashSet<String>();
|
||||
// LinkedHashSet to preserve insertion order
|
||||
Set<String> localeNames = new LinkedHashSet<>();
|
||||
while (XmlUtils.nextElementWithin(parser, outerDepth)) {
|
||||
if (TAG_LOCALE.equals(parser.getName())) {
|
||||
final TypedArray attributes = res.obtainAttributes(
|
||||
|
||||
@@ -1456,8 +1456,8 @@ public class PackageParser {
|
||||
|
||||
private static AssetManager newConfiguredAssetManager() {
|
||||
AssetManager assetManager = new AssetManager();
|
||||
assetManager.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
Build.VERSION.RESOURCES_SDK_INT);
|
||||
assetManager.setConfiguration(0, 0, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, Build.VERSION.RESOURCES_SDK_INT);
|
||||
return assetManager;
|
||||
}
|
||||
|
||||
@@ -9011,8 +9011,8 @@ public class PackageParser {
|
||||
}
|
||||
|
||||
AssetManager assets = new AssetManager();
|
||||
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setConfiguration(0, 0, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
|
||||
|
||||
mCachedAssetManager = assets;
|
||||
@@ -9086,8 +9086,8 @@ public class PackageParser {
|
||||
|
||||
private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
|
||||
final AssetManager assets = new AssetManager();
|
||||
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setConfiguration(0, 0, null, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
|
||||
return assets;
|
||||
}
|
||||
|
||||
@@ -1480,15 +1480,38 @@ public final class AssetManager implements AutoCloseable {
|
||||
int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
|
||||
int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender,
|
||||
int majorVersion) {
|
||||
synchronized (this) {
|
||||
ensureValidLocked();
|
||||
nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density,
|
||||
if (locale != null) {
|
||||
setConfiguration(mcc, mnc, null, new String[]{locale}, orientation, touchscreen,
|
||||
density, keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
|
||||
smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
|
||||
colorMode, grammaticalGender, majorVersion);
|
||||
} else {
|
||||
setConfiguration(mcc, mnc, null, null, orientation, touchscreen, density,
|
||||
keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
|
||||
smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
|
||||
colorMode, grammaticalGender, majorVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the configuration used when retrieving resources. Not for use by
|
||||
* applications.
|
||||
* @hide
|
||||
*/
|
||||
public void setConfiguration(int mcc, int mnc, String defaultLocale, String[] locales,
|
||||
int orientation, int touchscreen, int density, int keyboard, int keyboardHidden,
|
||||
int navigation, int screenWidth, int screenHeight, int smallestScreenWidthDp,
|
||||
int screenWidthDp, int screenHeightDp, int screenLayout, int uiMode, int colorMode,
|
||||
int grammaticalGender, int majorVersion) {
|
||||
synchronized (this) {
|
||||
ensureValidLocked();
|
||||
nativeSetConfiguration(mObject, mcc, mnc, defaultLocale, locales, orientation,
|
||||
touchscreen, density, keyboard, keyboardHidden, navigation, screenWidth,
|
||||
screenHeight, smallestScreenWidthDp, screenWidthDp, screenHeightDp,
|
||||
screenLayout, uiMode, colorMode, grammaticalGender, majorVersion);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -1572,10 +1595,11 @@ public final class AssetManager implements AutoCloseable {
|
||||
private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
|
||||
boolean invalidateCaches);
|
||||
private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
|
||||
@Nullable String locale, int orientation, int touchscreen, int density, int keyboard,
|
||||
int keyboardHidden, int navigation, int screenWidth, int screenHeight,
|
||||
int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout,
|
||||
int uiMode, int colorMode, int grammaticalGender, int majorVersion);
|
||||
@Nullable String defaultLocale, @NonNull String[] locales, int orientation,
|
||||
int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
|
||||
int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
|
||||
int screenHeightDp, int screenLayout, int uiMode, int colorMode, int grammaticalGender,
|
||||
int majorVersion);
|
||||
private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
|
||||
long ptr, boolean includeOverlays, boolean includeLoaders);
|
||||
|
||||
|
||||
@@ -407,14 +407,12 @@ public class ResourcesImpl {
|
||||
mConfiguration.setLocales(locales);
|
||||
}
|
||||
|
||||
String[] selectedLocales = null;
|
||||
String defaultLocale = null;
|
||||
if ((configChanges & ActivityInfo.CONFIG_LOCALE) != 0) {
|
||||
if (locales.size() > 1) {
|
||||
String[] availableLocales;
|
||||
|
||||
LocaleList localeList = ResourcesManager.getInstance().getLocaleList();
|
||||
if (!localeList.isEmpty()) {
|
||||
availableLocales = localeList.toLanguageTags().split(",");
|
||||
} else {
|
||||
if (ResourcesManager.getInstance().getLocaleList().isEmpty()) {
|
||||
// The LocaleList has changed. We must query the AssetManager's
|
||||
// available Locales and figure out the best matching Locale in the new
|
||||
// LocaleList.
|
||||
@@ -426,16 +424,32 @@ public class ResourcesImpl {
|
||||
availableLocales = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (availableLocales != null) {
|
||||
final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
|
||||
availableLocales);
|
||||
if (bestLocale != null && bestLocale != locales.get(0)) {
|
||||
mConfiguration.setLocales(new LocaleList(bestLocale, locales));
|
||||
if (availableLocales != null) {
|
||||
final Locale bestLocale = locales.getFirstMatchWithEnglishSupported(
|
||||
availableLocales);
|
||||
if (bestLocale != null) {
|
||||
selectedLocales = new String[]{
|
||||
adjustLanguageTag(bestLocale.toLanguageTag())};
|
||||
if (!bestLocale.equals(locales.get(0))) {
|
||||
mConfiguration.setLocales(
|
||||
new LocaleList(bestLocale, locales));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
selectedLocales = locales.getIntersection(
|
||||
ResourcesManager.getInstance().getLocaleList());
|
||||
defaultLocale = ResourcesManager.getInstance()
|
||||
.getLocaleList().get(0).toLanguageTag();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selectedLocales == null) {
|
||||
selectedLocales = new String[locales.size()];
|
||||
for (int i = 0; i < locales.size(); i++) {
|
||||
selectedLocales[i] = adjustLanguageTag(locales.get(i).toLanguageTag());
|
||||
}
|
||||
}
|
||||
|
||||
if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
|
||||
mMetrics.densityDpi = mConfiguration.densityDpi;
|
||||
@@ -470,7 +484,8 @@ public class ResourcesImpl {
|
||||
}
|
||||
|
||||
mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
|
||||
adjustLanguageTag(mConfiguration.getLocales().get(0).toLanguageTag()),
|
||||
defaultLocale,
|
||||
selectedLocales,
|
||||
mConfiguration.orientation,
|
||||
mConfiguration.touchscreen,
|
||||
mConfiguration.densityDpi, mConfiguration.keyboard,
|
||||
|
||||
@@ -30,6 +30,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
@@ -150,6 +151,25 @@ public final class LocaleList implements Parcelable {
|
||||
return mStringRepresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the intersection between this LocaleList and another
|
||||
* @return a String array of the Locales in both LocaleLists
|
||||
* {@hide}
|
||||
*/
|
||||
@NonNull
|
||||
public String[] getIntersection(@NonNull LocaleList other) {
|
||||
List<String> intersection = new ArrayList<>();
|
||||
for (Locale l1 : mList) {
|
||||
for (Locale l2 : other.mList) {
|
||||
if (matchesLanguageAndScript(l2, l1)) {
|
||||
intersection.add(l1.toLanguageTag());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return intersection.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LocaleList}.
|
||||
*
|
||||
|
||||
@@ -347,14 +347,23 @@ static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
|
||||
}
|
||||
|
||||
static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
|
||||
jstring locale, jint orientation, jint touchscreen, jint density,
|
||||
jint keyboard, jint keyboard_hidden, jint navigation,
|
||||
jint screen_width, jint screen_height,
|
||||
jint smallest_screen_width_dp, jint screen_width_dp,
|
||||
jint screen_height_dp, jint screen_layout, jint ui_mode,
|
||||
jint color_mode, jint grammatical_gender, jint major_version) {
|
||||
jstring default_locale, jobjectArray locales, jint orientation,
|
||||
jint touchscreen, jint density, jint keyboard,
|
||||
jint keyboard_hidden, jint navigation, jint screen_width,
|
||||
jint screen_height, jint smallest_screen_width_dp,
|
||||
jint screen_width_dp, jint screen_height_dp, jint screen_layout,
|
||||
jint ui_mode, jint color_mode, jint grammatical_gender,
|
||||
jint major_version) {
|
||||
ATRACE_NAME("AssetManager::SetConfiguration");
|
||||
|
||||
const jsize locale_count = (locales == NULL) ? 0 : env->GetArrayLength(locales);
|
||||
|
||||
// Constants duplicated from Java class android.content.res.Configuration.
|
||||
static const jint kScreenLayoutRoundMask = 0x300;
|
||||
static const jint kScreenLayoutRoundShift = 8;
|
||||
|
||||
std::vector<ResTable_config> configs;
|
||||
|
||||
ResTable_config configuration;
|
||||
memset(&configuration, 0, sizeof(configuration));
|
||||
configuration.mcc = static_cast<uint16_t>(mcc);
|
||||
@@ -375,25 +384,37 @@ static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin
|
||||
configuration.colorMode = static_cast<uint8_t>(color_mode);
|
||||
configuration.grammaticalInflection = static_cast<uint8_t>(grammatical_gender);
|
||||
configuration.sdkVersion = static_cast<uint16_t>(major_version);
|
||||
|
||||
if (locale != nullptr) {
|
||||
ScopedUtfChars locale_utf8(env, locale);
|
||||
CHECK(locale_utf8.c_str() != nullptr);
|
||||
configuration.setBcp47Locale(locale_utf8.c_str());
|
||||
}
|
||||
|
||||
// Constants duplicated from Java class android.content.res.Configuration.
|
||||
static const jint kScreenLayoutRoundMask = 0x300;
|
||||
static const jint kScreenLayoutRoundShift = 8;
|
||||
|
||||
// In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
|
||||
// in C++. We must extract the round qualifier out of the Java screenLayout and put it
|
||||
// into screenLayout2.
|
||||
configuration.screenLayout2 =
|
||||
static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
|
||||
static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
|
||||
|
||||
if (locale_count > 0) {
|
||||
configs.resize(locale_count, configuration);
|
||||
for (int i = 0; i < locale_count; i++) {
|
||||
jstring locale = (jstring)(env->GetObjectArrayElement(locales, i));
|
||||
ScopedUtfChars locale_utf8(env, locale);
|
||||
CHECK(locale_utf8.c_str() != nullptr);
|
||||
configs[i].setBcp47Locale(locale_utf8.c_str());
|
||||
}
|
||||
} else {
|
||||
configs.push_back(configuration);
|
||||
}
|
||||
|
||||
uint32_t default_locale_int = 0;
|
||||
if (default_locale != nullptr) {
|
||||
ResTable_config config;
|
||||
static_assert(std::is_same_v<decltype(config.locale), decltype(default_locale_int)>);
|
||||
ScopedUtfChars locale_utf8(env, default_locale);
|
||||
CHECK(locale_utf8.c_str() != nullptr);
|
||||
config.setBcp47Locale(locale_utf8.c_str());
|
||||
default_locale_int = config.locale;
|
||||
}
|
||||
|
||||
auto assetmanager = LockAndStartAssetManager(ptr);
|
||||
assetmanager->SetConfiguration(configuration);
|
||||
assetmanager->SetConfigurations(configs);
|
||||
assetmanager->SetDefaultLocale(default_locale_int);
|
||||
}
|
||||
|
||||
static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr,
|
||||
@@ -1498,94 +1519,97 @@ static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jl
|
||||
|
||||
// JNI registration.
|
||||
static const JNINativeMethod gAssetManagerMethods[] = {
|
||||
// AssetManager setup methods.
|
||||
{"nativeCreate", "()J", (void*)NativeCreate},
|
||||
{"nativeDestroy", "(J)V", (void*)NativeDestroy},
|
||||
{"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
|
||||
{"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIIII)V",
|
||||
(void*)NativeSetConfiguration},
|
||||
{"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
|
||||
(void*)NativeGetAssignedPackageIdentifiers},
|
||||
// AssetManager setup methods.
|
||||
{"nativeCreate", "()J", (void*)NativeCreate},
|
||||
{"nativeDestroy", "(J)V", (void*)NativeDestroy},
|
||||
{"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
|
||||
{"nativeSetConfiguration", "(JIILjava/lang/String;[Ljava/lang/String;IIIIIIIIIIIIIIII)V",
|
||||
(void*)NativeSetConfiguration},
|
||||
{"nativeGetAssignedPackageIdentifiers", "(JZZ)Landroid/util/SparseArray;",
|
||||
(void*)NativeGetAssignedPackageIdentifiers},
|
||||
|
||||
// AssetManager file methods.
|
||||
{"nativeContainsAllocatedTable", "(J)Z", (void*)ContainsAllocatedTable},
|
||||
{"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
|
||||
{"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
|
||||
{"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
|
||||
(void*)NativeOpenAssetFd},
|
||||
{"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
|
||||
{"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
|
||||
(void*)NativeOpenNonAssetFd},
|
||||
{"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
|
||||
{"nativeOpenXmlAssetFd", "(JILjava/io/FileDescriptor;)J", (void*)NativeOpenXmlAssetFd},
|
||||
// AssetManager file methods.
|
||||
{"nativeContainsAllocatedTable", "(J)Z", (void*)ContainsAllocatedTable},
|
||||
{"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
|
||||
{"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
|
||||
{"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
|
||||
(void*)NativeOpenAssetFd},
|
||||
{"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
|
||||
{"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
|
||||
(void*)NativeOpenNonAssetFd},
|
||||
{"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
|
||||
{"nativeOpenXmlAssetFd", "(JILjava/io/FileDescriptor;)J", (void*)NativeOpenXmlAssetFd},
|
||||
|
||||
// AssetManager resource methods.
|
||||
{"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
|
||||
{"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
|
||||
(void*)NativeGetResourceBagValue},
|
||||
{"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
|
||||
{"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
|
||||
(void*)NativeGetResourceStringArray},
|
||||
{"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
|
||||
{"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
|
||||
{"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
|
||||
{"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
|
||||
{"nativeGetParentThemeIdentifier", "(JI)I",
|
||||
(void*)NativeGetParentThemeIdentifier},
|
||||
// AssetManager resource methods.
|
||||
{"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I",
|
||||
(void*)NativeGetResourceValue},
|
||||
{"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
|
||||
(void*)NativeGetResourceBagValue},
|
||||
{"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
|
||||
{"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
|
||||
(void*)NativeGetResourceStringArray},
|
||||
{"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
|
||||
{"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
|
||||
{"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
|
||||
{"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
|
||||
{"nativeGetParentThemeIdentifier", "(JI)I", (void*)NativeGetParentThemeIdentifier},
|
||||
|
||||
// AssetManager resource name/ID methods.
|
||||
{"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
|
||||
(void*)NativeGetResourceIdentifier},
|
||||
{"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
|
||||
{"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
|
||||
{"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
|
||||
{"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
|
||||
{"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
|
||||
(void*) NativeSetResourceResolutionLoggingEnabled},
|
||||
{"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
|
||||
(void*) NativeGetLastResourceResolution},
|
||||
{"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
|
||||
{"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
|
||||
(void*)NativeGetSizeConfigurations},
|
||||
{"nativeGetSizeAndUiModeConfigurations", "(J)[Landroid/content/res/Configuration;",
|
||||
(void*)NativeGetSizeAndUiModeConfigurations},
|
||||
// AssetManager resource name/ID methods.
|
||||
{"nativeGetResourceIdentifier",
|
||||
"(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
|
||||
(void*)NativeGetResourceIdentifier},
|
||||
{"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
|
||||
{"nativeGetResourcePackageName", "(JI)Ljava/lang/String;",
|
||||
(void*)NativeGetResourcePackageName},
|
||||
{"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
|
||||
{"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
|
||||
{"nativeSetResourceResolutionLoggingEnabled", "(JZ)V",
|
||||
(void*)NativeSetResourceResolutionLoggingEnabled},
|
||||
{"nativeGetLastResourceResolution", "(J)Ljava/lang/String;",
|
||||
(void*)NativeGetLastResourceResolution},
|
||||
{"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
|
||||
{"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
|
||||
(void*)NativeGetSizeConfigurations},
|
||||
{"nativeGetSizeAndUiModeConfigurations", "(J)[Landroid/content/res/Configuration;",
|
||||
(void*)NativeGetSizeAndUiModeConfigurations},
|
||||
|
||||
// Style attribute related methods.
|
||||
{"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
|
||||
{"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
|
||||
{"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
|
||||
{"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
|
||||
// Style attribute related methods.
|
||||
{"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
|
||||
{"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
|
||||
{"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
|
||||
{"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
|
||||
|
||||
// Theme related methods.
|
||||
{"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
|
||||
{"nativeGetThemeFreeFunction", "()J", (void*)NativeGetThemeFreeFunction},
|
||||
{"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
|
||||
{"nativeThemeRebase", "(JJ[I[ZI)V", (void*)NativeThemeRebase},
|
||||
// Theme related methods.
|
||||
{"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
|
||||
{"nativeGetThemeFreeFunction", "()J", (void*)NativeGetThemeFreeFunction},
|
||||
{"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
|
||||
{"nativeThemeRebase", "(JJ[I[ZI)V", (void*)NativeThemeRebase},
|
||||
|
||||
{"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
|
||||
{"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
|
||||
(void*)NativeThemeGetAttributeValue},
|
||||
{"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
|
||||
{"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
|
||||
{"nativeThemeCopy", "(JJJJ)V", (void*)NativeThemeCopy},
|
||||
{"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
|
||||
(void*)NativeThemeGetAttributeValue},
|
||||
{"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
|
||||
{"nativeThemeGetChangingConfigurations", "(J)I",
|
||||
(void*)NativeThemeGetChangingConfigurations},
|
||||
|
||||
// AssetInputStream methods.
|
||||
{"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
|
||||
{"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
|
||||
{"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
|
||||
{"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
|
||||
{"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
|
||||
{"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
|
||||
// AssetInputStream methods.
|
||||
{"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
|
||||
{"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
|
||||
{"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
|
||||
{"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
|
||||
{"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
|
||||
{"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
|
||||
|
||||
// System/idmap related methods.
|
||||
{"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
|
||||
(void*)NativeGetOverlayableMap},
|
||||
{"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
|
||||
(void*)NativeGetOverlayablesToString},
|
||||
// System/idmap related methods.
|
||||
{"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
|
||||
(void*)NativeGetOverlayableMap},
|
||||
{"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
|
||||
(void*)NativeGetOverlayablesToString},
|
||||
|
||||
// Global management/debug methods.
|
||||
{"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
|
||||
{"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
|
||||
{"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
|
||||
// Global management/debug methods.
|
||||
{"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
|
||||
{"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
|
||||
{"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
|
||||
};
|
||||
|
||||
int register_android_content_AssetManager(JNIEnv* env) {
|
||||
|
||||
@@ -91,12 +91,17 @@ struct FindEntryResult {
|
||||
StringPoolRef entry_string_ref;
|
||||
};
|
||||
|
||||
AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration)
|
||||
: configuration_(configuration) {
|
||||
AssetManager2::AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration) {
|
||||
configurations_.push_back(configuration);
|
||||
|
||||
// Don't invalidate caches here as there's nothing cached yet.
|
||||
SetApkAssets(apk_assets, false);
|
||||
}
|
||||
|
||||
AssetManager2::AssetManager2() {
|
||||
configurations_.resize(1);
|
||||
}
|
||||
|
||||
bool AssetManager2::SetApkAssets(ApkAssetsList apk_assets, bool invalidate_caches) {
|
||||
BuildDynamicRefTable(apk_assets);
|
||||
RebuildFilterList();
|
||||
@@ -421,9 +426,16 @@ bool AssetManager2::ContainsAllocatedTable() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
|
||||
const int diff = configuration_.diff(configuration);
|
||||
configuration_ = configuration;
|
||||
void AssetManager2::SetConfigurations(std::vector<ResTable_config> configurations) {
|
||||
int diff = 0;
|
||||
if (configurations_.size() != configurations.size()) {
|
||||
diff = -1;
|
||||
} else {
|
||||
for (int i = 0; i < configurations_.size(); i++) {
|
||||
diff |= configurations_[i].diff(configurations[i]);
|
||||
}
|
||||
}
|
||||
configurations_ = std::move(configurations);
|
||||
|
||||
if (diff) {
|
||||
RebuildFilterList();
|
||||
@@ -620,16 +632,6 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
|
||||
|
||||
auto op = StartOperation();
|
||||
|
||||
// Might use this if density_override != 0.
|
||||
ResTable_config density_override_config;
|
||||
|
||||
// Select our configuration or generate a density override configuration.
|
||||
const ResTable_config* desired_config = &configuration_;
|
||||
if (density_override != 0 && density_override != configuration_.density) {
|
||||
density_override_config = configuration_;
|
||||
density_override_config.density = density_override;
|
||||
desired_config = &density_override_config;
|
||||
}
|
||||
|
||||
// Retrieve the package group from the package id of the resource id.
|
||||
if (UNLIKELY(!is_valid_resid(resid))) {
|
||||
@@ -648,119 +650,160 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
|
||||
}
|
||||
|
||||
const PackageGroup& package_group = package_groups_[package_idx];
|
||||
auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
|
||||
stop_at_first_match, ignore_configuration);
|
||||
if (UNLIKELY(!result.has_value())) {
|
||||
return base::unexpected(result.error());
|
||||
}
|
||||
std::optional<FindEntryResult> final_result;
|
||||
bool final_has_locale = false;
|
||||
bool final_overlaid = false;
|
||||
for (auto & config : configurations_) {
|
||||
// Might use this if density_override != 0.
|
||||
ResTable_config density_override_config;
|
||||
|
||||
bool overlaid = false;
|
||||
if (!stop_at_first_match && !ignore_configuration) {
|
||||
const auto& assets = GetApkAssets(result->cookie);
|
||||
if (!assets) {
|
||||
ALOGE("Found expired ApkAssets #%d for resource ID 0x%08x.", result->cookie, resid);
|
||||
return base::unexpected(std::nullopt);
|
||||
// Select our configuration or generate a density override configuration.
|
||||
const ResTable_config* desired_config = &config;
|
||||
if (density_override != 0 && density_override != config.density) {
|
||||
density_override_config = config;
|
||||
density_override_config.density = density_override;
|
||||
desired_config = &density_override_config;
|
||||
}
|
||||
if (!assets->IsLoader()) {
|
||||
for (const auto& id_map : package_group.overlays_) {
|
||||
auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
|
||||
if (!overlay_entry) {
|
||||
// No id map entry exists for this target resource.
|
||||
continue;
|
||||
}
|
||||
if (overlay_entry.IsInlineValue()) {
|
||||
// The target resource is overlaid by an inline value not represented by a resource.
|
||||
ConfigDescription best_frro_config;
|
||||
Res_value best_frro_value;
|
||||
bool frro_found = false;
|
||||
for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
|
||||
if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
|
||||
&& config.match(*desired_config)) {
|
||||
frro_found = true;
|
||||
best_frro_config = config;
|
||||
best_frro_value = value;
|
||||
}
|
||||
}
|
||||
if (!frro_found) {
|
||||
|
||||
auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
|
||||
stop_at_first_match, ignore_configuration);
|
||||
if (UNLIKELY(!result.has_value())) {
|
||||
return base::unexpected(result.error());
|
||||
}
|
||||
bool overlaid = false;
|
||||
if (!stop_at_first_match && !ignore_configuration) {
|
||||
const auto& assets = GetApkAssets(result->cookie);
|
||||
if (!assets) {
|
||||
ALOGE("Found expired ApkAssets #%d for resource ID 0x%08x.", result->cookie, resid);
|
||||
return base::unexpected(std::nullopt);
|
||||
}
|
||||
if (!assets->IsLoader()) {
|
||||
for (const auto& id_map : package_group.overlays_) {
|
||||
auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
|
||||
if (!overlay_entry) {
|
||||
// No id map entry exists for this target resource.
|
||||
continue;
|
||||
}
|
||||
result->entry = best_frro_value;
|
||||
if (overlay_entry.IsInlineValue()) {
|
||||
// The target resource is overlaid by an inline value not represented by a resource.
|
||||
ConfigDescription best_frro_config;
|
||||
Res_value best_frro_value;
|
||||
bool frro_found = false;
|
||||
for( const auto& [config, value] : overlay_entry.GetInlineValue()) {
|
||||
if ((!frro_found || config.isBetterThan(best_frro_config, desired_config))
|
||||
&& config.match(*desired_config)) {
|
||||
frro_found = true;
|
||||
best_frro_config = config;
|
||||
best_frro_value = value;
|
||||
}
|
||||
}
|
||||
if (!frro_found) {
|
||||
continue;
|
||||
}
|
||||
result->entry = best_frro_value;
|
||||
result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
|
||||
result->cookie = id_map.cookie;
|
||||
|
||||
if (UNLIKELY(logging_enabled)) {
|
||||
last_resolution_.steps.push_back(Resolution::Step{
|
||||
Resolution::Step::Type::OVERLAID_INLINE, result->cookie, String8()});
|
||||
if (auto path = assets->GetPath()) {
|
||||
const std::string overlay_path = path->data();
|
||||
if (IsFabricatedOverlay(overlay_path)) {
|
||||
// FRRO don't have package name so we use the creating package here.
|
||||
String8 frro_name = String8("FRRO");
|
||||
// Get the first part of it since the expected one should be like
|
||||
// {overlayPackageName}-{overlayName}-{4 alphanumeric chars}.frro
|
||||
// under /data/resource-cache/.
|
||||
const std::string name = overlay_path.substr(overlay_path.rfind('/') + 1);
|
||||
const size_t end = name.find('-');
|
||||
if (frro_name.size() != overlay_path.size() && end != std::string::npos) {
|
||||
frro_name.append(base::StringPrintf(" created by %s",
|
||||
name.substr(0 /* pos */,
|
||||
end).c_str()).c_str());
|
||||
}
|
||||
last_resolution_.best_package_name = frro_name;
|
||||
} else {
|
||||
last_resolution_.best_package_name = result->package_name->c_str();
|
||||
}
|
||||
}
|
||||
overlaid = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
|
||||
false /* stop_at_first_match */,
|
||||
false /* ignore_configuration */);
|
||||
if (UNLIKELY(IsIOError(overlay_result))) {
|
||||
return base::unexpected(overlay_result.error());
|
||||
}
|
||||
if (!overlay_result.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!overlay_result->config.isBetterThan(result->config, desired_config)
|
||||
&& overlay_result->config.compare(result->config) != 0) {
|
||||
// The configuration of the entry for the overlay must be equal to or better than the
|
||||
// target configuration to be chosen as the better value.
|
||||
continue;
|
||||
}
|
||||
|
||||
result->cookie = overlay_result->cookie;
|
||||
result->entry = overlay_result->entry;
|
||||
result->config = overlay_result->config;
|
||||
result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
|
||||
result->cookie = id_map.cookie;
|
||||
|
||||
if (UNLIKELY(logging_enabled)) {
|
||||
last_resolution_.steps.push_back(
|
||||
Resolution::Step{Resolution::Step::Type::OVERLAID_INLINE, result->cookie, String8()});
|
||||
if (auto path = assets->GetPath()) {
|
||||
const std::string overlay_path = path->data();
|
||||
if (IsFabricatedOverlay(overlay_path)) {
|
||||
// FRRO don't have package name so we use the creating package here.
|
||||
String8 frro_name = String8("FRRO");
|
||||
// Get the first part of it since the expected one should be like
|
||||
// {overlayPackageName}-{overlayName}-{4 alphanumeric chars}.frro
|
||||
// under /data/resource-cache/.
|
||||
const std::string name = overlay_path.substr(overlay_path.rfind('/') + 1);
|
||||
const size_t end = name.find('-');
|
||||
if (frro_name.size() != overlay_path.size() && end != std::string::npos) {
|
||||
frro_name.append(base::StringPrintf(" created by %s",
|
||||
name.substr(0 /* pos */,
|
||||
end).c_str()).c_str());
|
||||
}
|
||||
last_resolution_.best_package_name = frro_name;
|
||||
} else {
|
||||
last_resolution_.best_package_name = result->package_name->c_str();
|
||||
}
|
||||
}
|
||||
Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->cookie,
|
||||
overlay_result->config.toString()});
|
||||
last_resolution_.best_package_name =
|
||||
overlay_result->package_name->c_str();
|
||||
overlaid = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
|
||||
false /* stop_at_first_match */,
|
||||
false /* ignore_configuration */);
|
||||
if (UNLIKELY(IsIOError(overlay_result))) {
|
||||
return base::unexpected(overlay_result.error());
|
||||
}
|
||||
if (!overlay_result.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!overlay_result->config.isBetterThan(result->config, desired_config)
|
||||
&& overlay_result->config.compare(result->config) != 0) {
|
||||
// The configuration of the entry for the overlay must be equal to or better than the target
|
||||
// configuration to be chosen as the better value.
|
||||
continue;
|
||||
}
|
||||
|
||||
result->cookie = overlay_result->cookie;
|
||||
result->entry = overlay_result->entry;
|
||||
result->config = overlay_result->config;
|
||||
result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
|
||||
|
||||
if (UNLIKELY(logging_enabled)) {
|
||||
last_resolution_.steps.push_back(
|
||||
Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->cookie,
|
||||
overlay_result->config.toString()});
|
||||
last_resolution_.best_package_name =
|
||||
overlay_result->package_name->c_str();
|
||||
overlaid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool has_locale = false;
|
||||
if (result->config.locale == 0) {
|
||||
if (default_locale_ != 0) {
|
||||
ResTable_config conf;
|
||||
conf.locale = default_locale_;
|
||||
// Since we know conf has a locale and only a locale, match will tell us if that locale
|
||||
// matches
|
||||
has_locale = conf.match(config);
|
||||
}
|
||||
} else {
|
||||
has_locale = true;
|
||||
}
|
||||
|
||||
// if we don't have a result yet
|
||||
if (!final_result ||
|
||||
// or this config is better before the locale than the existing result
|
||||
result->config.isBetterThanBeforeLocale(final_result->config, desired_config) ||
|
||||
// or the existing config isn't better before locale and this one specifies a locale
|
||||
// whereas the existing one doesn't
|
||||
(!final_result->config.isBetterThanBeforeLocale(result->config, desired_config)
|
||||
&& has_locale && !final_has_locale)) {
|
||||
final_result = result.value();
|
||||
final_overlaid = overlaid;
|
||||
final_has_locale = has_locale;
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(logging_enabled)) {
|
||||
last_resolution_.cookie = result->cookie;
|
||||
last_resolution_.type_string_ref = result->type_string_ref;
|
||||
last_resolution_.entry_string_ref = result->entry_string_ref;
|
||||
last_resolution_.best_config_name = result->config.toString();
|
||||
if (!overlaid) {
|
||||
last_resolution_.best_package_name = result->package_name->c_str();
|
||||
last_resolution_.cookie = final_result->cookie;
|
||||
last_resolution_.type_string_ref = final_result->type_string_ref;
|
||||
last_resolution_.entry_string_ref = final_result->entry_string_ref;
|
||||
last_resolution_.best_config_name = final_result->config.toString();
|
||||
if (!final_overlaid) {
|
||||
last_resolution_.best_package_name = final_result->package_name->c_str();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return *final_result;
|
||||
}
|
||||
|
||||
base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
|
||||
@@ -778,8 +821,10 @@ base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
|
||||
// If `desired_config` is not the same as the set configuration or the caller will accept a value
|
||||
// from any configuration, then we cannot use our filtered list of types since it only it contains
|
||||
// types matched to the set configuration.
|
||||
const bool use_filtered = !ignore_configuration && &desired_config == &configuration_;
|
||||
|
||||
const bool use_filtered = !ignore_configuration && std::find_if(
|
||||
configurations_.begin(), configurations_.end(),
|
||||
[&desired_config](auto& value) { return &desired_config == &value; })
|
||||
!= configurations_.end();
|
||||
const size_t package_count = package_group.packages_.size();
|
||||
for (size_t pi = 0; pi < package_count; pi++) {
|
||||
const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
|
||||
@@ -934,10 +979,22 @@ std::string AssetManager2::GetLastResourceResolution() const {
|
||||
}
|
||||
|
||||
std::stringstream log_stream;
|
||||
log_stream << base::StringPrintf("Resolution for 0x%08x %s\n"
|
||||
"\tFor config - %s", resid, resource_name_string.c_str(),
|
||||
configuration_.toString().c_str());
|
||||
|
||||
if (configurations_.size() == 1) {
|
||||
log_stream << base::StringPrintf("Resolution for 0x%08x %s\n"
|
||||
"\tFor config - %s", resid, resource_name_string.c_str(),
|
||||
configurations_[0].toString().c_str());
|
||||
} else {
|
||||
ResTable_config conf = configurations_[0];
|
||||
conf.clearLocale();
|
||||
log_stream << base::StringPrintf("Resolution for 0x%08x %s\n\tFor config - %s and locales",
|
||||
resid, resource_name_string.c_str(), conf.toString().c_str());
|
||||
char str[40];
|
||||
str[0] = '\0';
|
||||
for(auto iter = configurations_.begin(); iter < configurations_.end(); iter++) {
|
||||
iter->getBcp47Locale(str);
|
||||
log_stream << base::StringPrintf(" %s%s", str, iter < configurations_.end() ? "," : "");
|
||||
}
|
||||
}
|
||||
for (const Resolution::Step& step : last_resolution_.steps) {
|
||||
constexpr static std::array kStepStrings = {
|
||||
"Found initial",
|
||||
@@ -1427,11 +1484,14 @@ void AssetManager2::RebuildFilterList() {
|
||||
package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
|
||||
FilteredConfigGroup* group = nullptr;
|
||||
for (const auto& type_entry : type_spec.type_entries) {
|
||||
if (type_entry.config.match(configuration_)) {
|
||||
if (!group) {
|
||||
group = &package.filtered_configs_.editItemAt(type_id - 1);
|
||||
for (auto & config : configurations_) {
|
||||
if (type_entry.config.match(config)) {
|
||||
if (!group) {
|
||||
group = &package.filtered_configs_.editItemAt(type_id - 1);
|
||||
}
|
||||
group->type_entries.push_back(&type_entry);
|
||||
break;
|
||||
}
|
||||
group->type_entries.push_back(&type_entry);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -2568,6 +2568,22 @@ bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResTable_config::isBetterThanBeforeLocale(const ResTable_config& o,
|
||||
const ResTable_config* requested) const {
|
||||
if (requested) {
|
||||
if (imsi || o.imsi) {
|
||||
if ((mcc != o.mcc) && requested->mcc) {
|
||||
return (mcc);
|
||||
}
|
||||
|
||||
if ((mnc != o.mnc) && requested->mnc) {
|
||||
return (mnc);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ResTable_config::isBetterThan(const ResTable_config& o,
|
||||
const ResTable_config* requested) const {
|
||||
if (requested) {
|
||||
|
||||
@@ -100,7 +100,7 @@ class AssetManager2 {
|
||||
using ApkAssetsWPtr = wp<const ApkAssets>;
|
||||
using ApkAssetsList = std::span<const ApkAssetsPtr>;
|
||||
|
||||
AssetManager2() = default;
|
||||
AssetManager2();
|
||||
explicit AssetManager2(AssetManager2&& other) = default;
|
||||
AssetManager2(ApkAssetsList apk_assets, const ResTable_config& configuration);
|
||||
|
||||
@@ -156,10 +156,14 @@ class AssetManager2 {
|
||||
|
||||
// Sets/resets the configuration for this AssetManager. This will cause all
|
||||
// caches that are related to the configuration change to be invalidated.
|
||||
void SetConfiguration(const ResTable_config& configuration);
|
||||
void SetConfigurations(std::vector<ResTable_config> configurations);
|
||||
|
||||
inline const ResTable_config& GetConfiguration() const {
|
||||
return configuration_;
|
||||
inline const std::vector<ResTable_config>& GetConfigurations() const {
|
||||
return configurations_;
|
||||
}
|
||||
|
||||
inline void SetDefaultLocale(uint32_t default_locale) {
|
||||
default_locale_ = default_locale;
|
||||
}
|
||||
|
||||
// Returns all configurations for which there are resources defined, or an I/O error if reading
|
||||
@@ -465,9 +469,11 @@ class AssetManager2 {
|
||||
// without taking too much memory.
|
||||
std::array<uint8_t, std::numeric_limits<uint8_t>::max() + 1> package_ids_;
|
||||
|
||||
// The current configuration set for this AssetManager. When this changes, cached resources
|
||||
uint32_t default_locale_;
|
||||
|
||||
// The current configurations set for this AssetManager. When this changes, cached resources
|
||||
// may need to be purged.
|
||||
ResTable_config configuration_ = {};
|
||||
std::vector<ResTable_config> configurations_;
|
||||
|
||||
// Cached set of bags. These are cached because they can inherit keys from parent bags,
|
||||
// which involves some calculation.
|
||||
|
||||
@@ -1375,6 +1375,8 @@ struct ResTable_config
|
||||
// match the requested configuration at all.
|
||||
bool isLocaleBetterThan(const ResTable_config& o, const ResTable_config* requested) const;
|
||||
|
||||
bool isBetterThanBeforeLocale(const ResTable_config& o, const ResTable_config* requested) const;
|
||||
|
||||
String8 toString() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -228,10 +228,12 @@ static void BM_AssetManagerSetConfigurationFramework(benchmark::State& state) {
|
||||
|
||||
ResTable_config config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
std::vector<ResTable_config> configs;
|
||||
configs.push_back(config);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
config.sdkVersion = ~config.sdkVersion;
|
||||
assets.SetConfiguration(config);
|
||||
configs[0].sdkVersion = ~configs[0].sdkVersion;
|
||||
assets.SetConfigurations(configs);
|
||||
}
|
||||
}
|
||||
BENCHMARK(BM_AssetManagerSetConfigurationFramework);
|
||||
|
||||
@@ -113,7 +113,7 @@ TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
|
||||
desired_config.language[1] = 'e';
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({basic_assets_});
|
||||
|
||||
auto value = assetmanager.GetResource(basic::R::string::test1);
|
||||
@@ -137,7 +137,7 @@ TEST_F(AssetManager2Test, FindsResourceFromMultipleApkAssets) {
|
||||
desired_config.language[1] = 'e';
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
|
||||
|
||||
auto value = assetmanager.GetResource(basic::R::string::test1);
|
||||
@@ -466,10 +466,10 @@ TEST_F(AssetManager2Test, ResolveDeepIdReference) {
|
||||
TEST_F(AssetManager2Test, DensityOverride) {
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetApkAssets({basic_assets_, basic_xhdpi_assets_, basic_xxhdpi_assets_});
|
||||
assetmanager.SetConfiguration({
|
||||
assetmanager.SetConfigurations({{
|
||||
.density = ResTable_config::DENSITY_XHIGH,
|
||||
.sdkVersion = 21,
|
||||
});
|
||||
}});
|
||||
|
||||
auto value = assetmanager.GetResource(basic::R::string::density, false /*may_be_bag*/);
|
||||
ASSERT_TRUE(value.has_value());
|
||||
@@ -721,7 +721,7 @@ TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) {
|
||||
ResTable_config desired_config;
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({basic_assets_});
|
||||
assetmanager.SetResourceResolutionLoggingEnabled(false);
|
||||
|
||||
@@ -736,7 +736,7 @@ TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) {
|
||||
ResTable_config desired_config;
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({basic_assets_});
|
||||
|
||||
auto result = assetmanager.GetLastResourceResolution();
|
||||
@@ -751,7 +751,7 @@ TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) {
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetResourceResolutionLoggingEnabled(true);
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({basic_assets_});
|
||||
|
||||
auto value = assetmanager.GetResource(basic::R::string::test1);
|
||||
@@ -774,7 +774,7 @@ TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetResourceResolutionLoggingEnabled(true);
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({basic_assets_, basic_de_fr_assets_});
|
||||
|
||||
auto value = assetmanager.GetResource(basic::R::string::test1);
|
||||
@@ -796,7 +796,7 @@ TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetResourceResolutionLoggingEnabled(true);
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({basic_assets_});
|
||||
|
||||
auto value = assetmanager.GetResource(basic::R::string::test1);
|
||||
@@ -817,7 +817,7 @@ TEST_F(AssetManager2Test, GetOverlayablesToString) {
|
||||
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetResourceResolutionLoggingEnabled(true);
|
||||
assetmanager.SetConfiguration(desired_config);
|
||||
assetmanager.SetConfigurations({desired_config});
|
||||
assetmanager.SetApkAssets({overlayable_assets_});
|
||||
|
||||
const auto map = assetmanager.GetOverlayableMapForPackage(0x7f);
|
||||
|
||||
@@ -66,7 +66,7 @@ void GetResourceBenchmark(const std::vector<std::string>& paths, const ResTable_
|
||||
AssetManager2 assetmanager;
|
||||
assetmanager.SetApkAssets(apk_assets);
|
||||
if (config != nullptr) {
|
||||
assetmanager.SetConfiguration(*config);
|
||||
assetmanager.SetConfigurations({*config});
|
||||
}
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
|
||||
@@ -260,7 +260,7 @@ TEST_F(ThemeTest, ThemeRebase) {
|
||||
ResTable_config night{};
|
||||
night.uiMode = ResTable_config::UI_MODE_NIGHT_YES;
|
||||
night.version = 8u;
|
||||
am_night.SetConfiguration(night);
|
||||
am_night.SetConfigurations({night});
|
||||
|
||||
auto theme = am.NewTheme();
|
||||
{
|
||||
|
||||
@@ -36,7 +36,7 @@ void AConfiguration_delete(AConfiguration* config) {
|
||||
|
||||
void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) {
|
||||
ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(am));
|
||||
ResTable_config config = locked_mgr->GetConfiguration();
|
||||
ResTable_config config = locked_mgr->GetConfigurations()[0];
|
||||
|
||||
// AConfiguration is not a virtual subclass, so we can memcpy.
|
||||
memcpy(out, &config, sizeof(config));
|
||||
|
||||
@@ -17,13 +17,13 @@ package com.android.server.pm.split;
|
||||
|
||||
import android.content.pm.parsing.ApkLiteParseUtils;
|
||||
import android.content.pm.parsing.PackageLite;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
|
||||
import android.content.res.ApkAssets;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Build;
|
||||
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
|
||||
import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
@@ -82,8 +82,8 @@ public class DefaultSplitAssetLoader implements SplitAssetLoader {
|
||||
}
|
||||
|
||||
AssetManager assets = new AssetManager();
|
||||
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
|
||||
|
||||
mCachedAssetManager = assets;
|
||||
|
||||
@@ -80,8 +80,8 @@ public class SplitAssetDependencyLoader extends SplitDependencyLoader<IllegalArg
|
||||
|
||||
private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
|
||||
final AssetManager assets = new AssetManager();
|
||||
assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setConfiguration(0, 0, null, new String[0], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, Build.VERSION.RESOURCES_SDK_INT);
|
||||
assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
|
||||
return assets;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user