aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hoisie <hoisie@google.com>2023-04-15 00:40:56 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-04-15 00:40:56 +0000
commitf2fbfa6f4d67efe462c04f61f6a3f6968b151d47 (patch)
treedc13305431607b52ee92bb3cd769a4421e5324f5
parent306dcff66b09a437e5061bb3a17998a1d09a537c (diff)
parenta34ed98affc9aca29cb597fc036336ffe0cd640b (diff)
downloadrobolectric-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>
-rw-r--r--resources/src/main/java/org/robolectric/res/android/CppAssetManager2.java2
-rw-r--r--resources/src/main/java/org/robolectric/res/android/LoadedArsc.java15
-rw-r--r--resources/src/main/java/org/robolectric/res/android/ResourceTypes.java57
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));
+ }
}
}