Skip to content

Conversation

@MarijnS95
Copy link
Member

@MarijnS95 MarijnS95 commented Aug 17, 2025

Bumping the target_sdk_version to 35 results in hitting random asserts inside the ResTable parser. Digging further shows that the parser wasn't that robust after all and happily ignored new fields and flags which should have affected how certain elements are parsed. New changes that Android made since 33:

  • SPARSE lists for Type chunk, instead of storing large arrays with many None elements;
  • reserved field 1 in TypeSpec is now types_count;
  • 16-bit offset indexing for Type chunk;
    • This offset handling was previously ignored because every element "just so happened to be" tightly packed after the offset list, sequential and with no padding in between - those assumptions are also no longer true now;
  • COMPACT Type Entrys are now used for 4-byte values.

Note that this PR only marginally tries to remove data-representation-specific pieces from the public Chunks API. Callers will still have to guess a few fields that really should be handled internally, but since none of this is really actively used internally I did not bother. fn compile_mipmap() seems to spit out mostly bogus though, specifically for ResTablePackageHeader.

The existing tests already cover building and then parsing the table again, and also test all installed SDKs which happen to be the full 28..=35 range on my machine; all succeed successfully.

This still parses Android 33's `android.jar` successfully, but paves
the way towards detecting new fields and flags that influence how newer
resource tables should be parsed, rather than getting stuck reading
random data.
…ype` chunks

The original code was assuming that all non-empty `Type` entries were
stored sequentially, directly after the index list and tightly packed
together with no padding in between.  Previously added assertions
support this case, but this will no longer be fully correct with the
introduction of a sparse `Type` in Android 34, and 16-bit offsets in
Android 35.

Note that a future patch should be removing the unusable index array
that is exposed to the user: this byte-offset is no longer relevant
to them when the elements have been parsed, and is terribly hard and
error-prone to set up manually before serializing.  This however becomes
tedious to deal with in our writer.
The header for `TypeSpec` and `Type`, as well as the "index" mapping
contain byte offsets, reserved fields and flags that are only usable
for the binary parser and writer.  Even though handling these are
cumbersome at writing time (because of jumping back to the header or
offsets array to write accurate byte positions after first serializing
prior elements), that's still a lot more correct than leaving the user
to **guess** what byte offsets to put into the vector/headers.

That is otherwise going to be even more more complicated with the
introduction of a new `SPARSE` `Type` flag in Android 34, and `OFFSET16`
`Type` flag in Android 35.
Android 34 replaced most `Type` chunks with few entries with a new
`SPARSE` list.  Here the offset table is now a combination of a `u16`
array index and a `u16` byte offset, allowing it to take up way less
space in binary form when few elements are set while still reaching
high(er) indexes (typically one or a handful of elements with an index
in the hundreds or thousands).
Reserved field 1 is nog used for a number of types, though it has
no impact on the what we need to parse.
Probably after using only 16-bits for the offset the behind the `SPARSE`
flag, it was realized that 16-bit offsets could also reduce table size
when applied to non-sparse `Type` lists.
Android 35 seemed to be on a quest to reduce resource table sizes
by using smaller types for offsets, building on Android-34's sparse
`Type` lists and now also using less bytes for compact entries
where the value is only 4 bytes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants