diff options
author | Michael Hoisie <hoisie@google.com> | 2023-04-15 00:40:56 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-04-15 00:40:56 +0000 |
commit | f2fbfa6f4d67efe462c04f61f6a3f6968b151d47 (patch) | |
tree | dc13305431607b52ee92bb3cd769a4421e5324f5 | |
parent | 306dcff66b09a437e5061bb3a17998a1d09a537c (diff) | |
parent | a34ed98affc9aca29cb597fc036336ffe0cd640b (diff) | |
download | robolectric-shadows-f2fbfa6f4d67efe462c04f61f6a3f6968b151d47.tar.gz |
Add support for ARSC resource table compact encoding am: f32fe4dd1b am: 83392eab4f am: a34ed98aff
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/robolectric-shadows/+/22653635
Change-Id: I86d4db5b411da2c5a5044d36d223838e2d40162c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
3 files changed, 60 insertions, 14 deletions
diff --git a/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java b/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java index 33bf96aa9..0f5affb0a 100644 --- a/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java +++ b/resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java @@ -760,7 +760,7 @@ public class CppAssetManager2 { out_entry_.type_flags = type_flags; out_entry_.type_string_ref = new StringPoolRef(best_package.GetTypeStringPool(), best_type.id - 1); out_entry_.entry_string_ref = - new StringPoolRef(best_package.GetKeyStringPool(), best_entry.key.index); + new StringPoolRef(best_package.GetKeyStringPool(), best_entry.getKeyIndex()); out_entry_.dynamic_ref_table = package_group.dynamic_ref_table; out_entry.set(out_entry_); return best_cookie; diff --git a/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java b/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java index b79f70a62..0c41714f6 100644 --- a/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java +++ b/resources/src/main/java/org/robolectric/res/android/LoadedArsc.java @@ -238,7 +238,9 @@ public class LoadedArsc { // Make sure that there is enough room for the entry offsets. int offsets_offset = dtohs(header.header.headerSize); int entries_offset = dtohl(header.entriesStart); - int offsets_length = 4 * entry_count; + int offsets_length = isTruthy(header.flags & ResTable_type.FLAG_OFFSET16) + ? 2 * entry_count + : 4 * entry_count; if (offsets_offset > entries_offset || entries_offset - offsets_offset < offsets_length) { logError("RES_TABLE_TYPE_TYPE entry offsets overlap actual entry data."); @@ -285,7 +287,7 @@ public class LoadedArsc { // reinterpret_cast<uint8_t*>(type) + entry_offset); ResTable_entry entry = new ResTable_entry(type.myBuf(), type.myOffset() + entry_offset); - int entry_size = dtohs(entry.size); + int entry_size = entry.isCompact() ? 8 : dtohs(entry.size); // if (entry_size < sizeof(*entry)) { if (entry_size < ResTable_entry.SIZEOF) { logError("ResTable_entry size " + entry_size + " at offset " + entry_offset @@ -299,6 +301,10 @@ public class LoadedArsc { return false; } + if (entry.isCompact()) { + return true; + } + if (entry_size < ResTable_map_entry.BASE_SIZEOF) { // There needs to be room for one Res_value struct. if (entry_offset + entry_size > chunk_size - Res_value.SIZEOF) { @@ -309,8 +315,7 @@ public class LoadedArsc { // Res_value value = // reinterpret_cast<Res_value*>(reinterpret_cast<uint8_t*>(entry) + entry_size); - Res_value value = - new Res_value(entry.myBuf(), entry.myOffset() + ResTable_entry.SIZEOF); + Res_value value = entry.getResValue(); int value_size = dtohs(value.size); if (value_size < Res_value.SIZEOF) { logError("Res_value at offset " + entry_offset + " is too small."); @@ -532,7 +537,7 @@ public class LoadedArsc { ResTable_entry entry = new ResTable_entry(type.myBuf(), type.myOffset() + dtohl(type.entriesStart) + offset); - if (dtohl(entry.key.index) == key_idx) { + if (dtohl(entry.getKeyIndex()) == key_idx) { // The package ID will be overridden by the caller (due to runtime assignment of package // IDs for shared libraries). return make_resid((byte) 0x00, (byte) (type_idx + type_id_offset_ + 1), (short) entry_idx); diff --git a/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java b/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java index 7e802e12d..5438f33cb 100644 --- a/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java +++ b/resources/src/main/java/org/robolectric/res/android/ResourceTypes.java @@ -340,7 +340,7 @@ public class ResourceTypes { } public Res_value(byte dataType, int data) { - this.size = 0; + this.size = SIZEOF; // this.res0 = 0; this.dataType = dataType; this.data = data; @@ -1167,6 +1167,11 @@ public static class ResTable_ref // Mark any types that use this with a v26 qualifier to prevent runtime issues on older // platforms. public static final int FLAG_SPARSE = 0x01; + + // If set, the offsets to the entries are encoded in 16-bit, real_offset = offset * 4u + // An 16-bit offset of 0xffffu means a NO_ENTRY + public static final int FLAG_OFFSET16 = 0x02; + // }; final byte flags; @@ -1208,13 +1213,21 @@ public static class ResTable_ref int entryOffset(int entryIndex) { ByteBuffer byteBuffer = myBuf(); int offset = myOffset(); - + boolean isOffset16 = (flags & ResTable_type.FLAG_OFFSET16) == ResTable_type.FLAG_OFFSET16; + if (isOffset16) { + short off16 = byteBuffer.getShort(offset + header.headerSize + entryIndex * 2); + if (off16 == -1) { + return -1; + } + return dtohs(off16) == 0xffff ? ResTable_type.NO_ENTRY : dtohs(off16) * 4; + } else { + return byteBuffer.getInt(offset + header.headerSize + entryIndex * 4); + } // from ResTable cpp: // const uint32_t* const eindex = reinterpret_cast<const uint32_t*>( // reinterpret_cast<const uint8_t*>(thisType) + dtohs(thisType->header.headerSize)); // // uint32_t thisOffset = dtohl(eindex[realEntryIndex]); - return byteBuffer.getInt(offset + header.headerSize + entryIndex * 4); } private int entryNameIndex(int entryIndex) { @@ -1282,7 +1295,7 @@ public static class ResTable_ref public static final int SIZEOF = 4 + ResStringPool_ref.SIZEOF; // Number of bytes in this structure. - final short size; + short size; //enum { // If set, this is a complex entry, holding a set of name/value @@ -1295,18 +1308,41 @@ public static class ResTable_ref // resources of the same name/type. This is only useful during // linking with other resource tables. public static final int FLAG_WEAK = 0x0004; + + public static final int FLAG_COMPACT = 0x0008; // }; final short flags; // Reference into ResTable_package::keyStrings identifying this entry. - final ResStringPool_ref key; + ResStringPool_ref key; + + int compactData; + short compactKey; ResTable_entry(ByteBuffer buf, int offset) { super(buf, offset); - size = buf.getShort(offset); flags = buf.getShort(offset + 2); - key = new ResStringPool_ref(buf, offset + 4); + + if (isCompact()) { + compactKey = buf.getShort(offset); + compactData = buf.getInt(offset + 4); + } else { + size = buf.getShort(offset); + key = new ResStringPool_ref(buf, offset + 4); + } + } + + public boolean isCompact() { + return (flags & FLAG_COMPACT) == FLAG_COMPACT; + } + + public int getKeyIndex() { + if (isCompact()) { + return dtohs(compactKey); + } else { + return key.index; + } } public Res_value getResValue() { @@ -1315,7 +1351,12 @@ public static class ResTable_ref // final Res_value device_value = reinterpret_cast<final Res_value>( // reinterpret_cast<final byte*>(entry) + dtohs(entry.size)); - return new Res_value(myBuf(), myOffset() + dtohs(size)); + if (isCompact()) { + byte type = (byte)(dtohs(flags) >> 8); + return new Res_value((byte)(dtohs(flags) >> 8), compactData); + } else { + return new Res_value(myBuf(), myOffset() + dtohs(size)); + } } } |