diff options
| -rw-r--r-- | core/java/android/content/res/AssetManager.java | 17 | ||||
| -rw-r--r-- | core/java/android/content/res/Resources.java | 36 | ||||
| -rw-r--r-- | core/java/android/content/res/ResourcesImpl.java | 8 | ||||
| -rw-r--r-- | core/jni/android_util_AssetManager.cpp | 8 | ||||
| -rw-r--r-- | libs/androidfw/AssetManager2.cpp | 21 | ||||
| -rw-r--r-- | libs/androidfw/include/androidfw/AssetManager2.h | 6 |
6 files changed, 94 insertions, 2 deletions
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 24c6a5a12178..bfd9fd0a4ef9 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -792,6 +792,21 @@ public final class AssetManager implements AutoCloseable { } /** + * To get the parent theme resource id according to the parameter theme resource id. + * @param resId theme resource id. + * @return the parent theme resource id. + * @hide + */ + @StyleRes + int getParentThemeIdentifier(@StyleRes int resId) { + synchronized (this) { + ensureValidLocked(); + // name is checked in JNI. + return nativeGetParentThemeIdentifier(mObject, resId); + } + } + + /** * Enable resource resolution logging to track the steps taken to resolve the last resource * entry retrieved. Stores the configuration and package names for each step. * @@ -1600,6 +1615,8 @@ public final class AssetManager implements AutoCloseable { private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag, String prefix); static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr); + @StyleRes + private static native int nativeGetParentThemeIdentifier(long ptr, @StyleRes int styleId); // AssetInputStream related native methods. private static native void nativeAssetDestroy(long assetPtr); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index b5d4f09144ee..cb53a2a7a7b8 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -1508,6 +1508,12 @@ public class Resources { * retrieve XML attributes with style and theme information applied. */ public final class Theme { + /** + * To trace parent themes needs to prevent a cycle situation. + * e.x. A's parent is B, B's parent is C, and C's parent is A. + */ + private static final int MAX_NUMBER_OF_TRACING_PARENT_THEME = 100; + private final Object mLock = new Object(); @GuardedBy("mLock") @@ -1801,6 +1807,13 @@ public class Resources { } } + @StyleRes + /*package*/ int getParentThemeIdentifier(@StyleRes int resId) { + synchronized (mLock) { + return mThemeImpl.getParentThemeIdentifier(resId); + } + } + /** * @hide */ @@ -1948,8 +1961,27 @@ public class Resources { public String toString() { final StringBuilder sb = new StringBuilder(); sb.append('{'); - sb.append("id=0x").append(Integer.toHexString(getAppliedStyleResId())).append(", "); - sb.append("themes=").append(Arrays.deepToString(getTheme())); + int themeResId = getAppliedStyleResId(); + int i = 0; + sb.append("InheritanceMap=["); + while (themeResId > 0) { + if (i > MAX_NUMBER_OF_TRACING_PARENT_THEME) { + sb.append(",..."); + break; + } + + if (i > 0) { + sb.append(", "); + } + sb.append("id=0x").append(Integer.toHexString(themeResId)); + sb.append(getResourcePackageName(themeResId)) + .append(":").append(getResourceTypeName(themeResId)) + .append("/").append(getResourceEntryName(themeResId)); + + i++; + themeResId = getParentThemeIdentifier(themeResId); + } + sb.append("], Themes=").append(Arrays.deepToString(getTheme())); sb.append('}'); return sb.toString(); } diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index b9f93b85f0bf..4d850b0ccfd5 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -1310,6 +1310,14 @@ public class ResourcesImpl { return mThemeResId; } + @StyleRes + /*package*/ int getParentThemeIdentifier(@StyleRes int resId) { + if (resId > 0) { + return mAssets.getParentThemeIdentifier(resId); + } + return 0; + } + void applyStyle(int resId, boolean force) { mAssets.applyStyleToTheme(mTheme, resId, force); mThemeResId = resId; diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 86d781033e5e..8c23b214b8fe 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -881,6 +881,12 @@ static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jin return static_cast<jint>(bag->entry_count); } +static jint NativeGetParentThemeIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) { + ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); + const auto parentThemeResId = assetmanager->GetParentThemeResourceId(resid); + return parentThemeResId.value_or(0); +} + static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name, jstring def_type, jstring def_package) { ScopedUtfChars name_utf8(env, name); @@ -1464,6 +1470,8 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"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", diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index 22904a0528d5..136fc6ca4e2a 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -902,6 +902,27 @@ std::string AssetManager2::GetLastResourceResolution() const { return log_stream.str(); } +base::expected<uint32_t, NullOrIOError> AssetManager2::GetParentThemeResourceId(uint32_t resid) +const { + auto entry = FindEntry(resid, 0u /* density_override */, + false /* stop_at_first_match */, + false /* ignore_configuration */); + if (!entry.has_value()) { + return base::unexpected(entry.error()); + } + + auto entry_map = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&entry->entry); + if (entry_map == nullptr) { + // Not a bag, nothing to do. + return base::unexpected(std::nullopt); + } + + auto map = *entry_map; + const uint32_t parent_resid = dtohl(map->parent.ident); + + return parent_resid; +} + base::expected<AssetManager2::ResourceName, NullOrIOError> AssetManager2::GetResourceName( uint32_t resid) const { auto result = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */, diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index a3b42df12da9..1bde792da2ba 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -192,6 +192,12 @@ class AssetManager2 { std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie, Asset::AccessMode mode) const; + // Returns the resource id of parent style of the specified theme. + // + // Returns a null error if the name is missing/corrupt, or an I/O error if reading resource data + // failed. + base::expected<uint32_t, NullOrIOError> GetParentThemeResourceId(uint32_t resid) const; + // Returns the resource name of the specified resource ID. // // Utf8 strings are preferred, and only if they are unavailable are the Utf16 variants populated. |