summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/res/AssetManager.java17
-rw-r--r--core/java/android/content/res/Resources.java36
-rw-r--r--core/java/android/content/res/ResourcesImpl.java8
-rw-r--r--core/jni/android_util_AssetManager.cpp8
-rw-r--r--libs/androidfw/AssetManager2.cpp21
-rw-r--r--libs/androidfw/include/androidfw/AssetManager2.h6
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.