[AI] feat: support feature flag structures for API 37 (cinnamon bun) - #4217
[AI] feat: support feature flag structures for API 37 (cinnamon bun)#4217iBotPeaches wants to merge 11 commits into
Conversation
Bumps [gradle-wrapper](https://github.com/gradle/gradle) from 9.7.0 to 9.7.1. - [Release notes](https://github.com/gradle/gradle/releases) - [Commits](gradle/gradle@v9.7.0...v9.7.1) --- updated-dependencies: - dependency-name: gradle-wrapper dependency-version: 9.7.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
enum ResXMLTreeExtDescriptor : uint8_t {
PADDING = 0x00,
FLAG_INFO = 0x01,
};
struct ResXMLTreeFlagExt {
// defines the type of the extended element structure
ResXMLTreeExtDescriptor descriptor;
// if the flag condition is negated
bool flag_negated;
// a hole for 4-byte alignment
uint16_t reserved;
// The reference into the string pool that the flag name is stored at
ResStringPool_ref flag_name;
};
/**
* A container for other chunks all of whose values are behind a given flag.
*
* The flag_name_index is the index of the flag name in the value string pool.
*
* When the android runtime encounters this chunk it will check the flag against its current value.
* If the flag is enabled and flag_negated is false or it is disabled and flag_negated is true, the
* runtime will then process all of the chunks inside of it normally. Otherwise the entire chunk is
* skipped.
*
* Currently this is chunk should be contained in a ResTable_typeSpec and contain any number of
* ResTable_type.
*/
struct ResTable_flagged {
struct ResChunk_header header;
ResStringPool_ref flag_name_index;
bool flag_negated;
uint8_t padding[3];
};
/**
* A chunk that contains a list of the names of all the read/write flags used by the
* ResTable_flagged chunks in the file. Specifically, all data after the header is an array of
* ResStringPool_ref objects for the flag names in no specific order. References use the global
* values stringpool.
*/
struct ResTable_flag_list {
struct ResChunk_header header;
}; |
|
The question/comments now is a few things.
|
#4216) Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.6.0-jre to 33.7.1-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-version: 33.7.1-jre dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
626cd6c to
2ca6a7a
Compare
Adds support for the new feature flag related structures in the API 37 ResourceTypes.h spec: - RES_TABLE_FLAGGED (0x0207) and RES_TABLE_FLAG_LIST (0x0208) chunk types. Flagged chunks are parsed and their contained types merged with the default values (with a warning), instead of being dropped as unexpected chunks. - ResXMLTreeFlagExt in binary XML start elements. aapt2 strips the android:featureFlag attribute when flattening read/write flagged elements and stores it as a flag ext, so restore the attribute on decode and record the flag so it can be passed back to aapt on build via --feature-flags. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Wgc8zmgm5ETg1WYAxJswS
Single dispatch loop over package-level chunk types, shared by parsePackage, parseFlagged and the type spec trailing scan instead of each doing their own nextChunk loop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Wgc8zmgm5ETg1WYAxJswS
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Wgc8zmgm5ETg1WYAxJswS
af0c248 to
d53e8d3
Compare
|
cc @IgorEisberg - been messing with this. It seems the XML Tree encodes the information about the flags. Can't really find any real documentation about this feature since its use-cases seem odd to me. If it was a build time flag - why even keep the resources? So it must be a runtime flag you can change that is only affected during launch/unpack of app? Ever stumbled upon any docs/cases for this feature? Closest thing I found was this FlaggedResourcesTest test in AOSP. |
|
Ah so thats an aspect I missed. You have control whether the feature flag is build-time or runtime (readonly). I'll have to make some POC samples to learn more. |
|
|
Yeah so a readonly flag makes no sense to persist the chunk if false. Just strip it at build time, but based on your image it survived build time. |
Exactly.
Nope. Based on my image, the only flag that survived was |
|
What's even more interesting is the nesting on this thing. |
|
This is going to take a while to plan properly. The thing is that like feature flags create a duplicate type with the same typeId, under the same package, and entries with flags can have the same name as an unflagged one, or with a different flag name or value, like in this AOSP example: So this is a whole another |
|
Support is ready in |
|
Its weird they nested more chunks within |
|
Aha, so the problem is here: Which looks like an official aapt2 bug. The FlaggedXmlVersioner gets no chance to run, at least the non-versioning part:https://cs.android.com/android/platform/superproject/+/android-latest-release:frameworks/base/tools/aapt2/cmd/Link.cpp;l=489-508 This block only does post-processing without any auto-versioning and should always run regardless of --no-auto-version:https://cs.android.com/android/platform/superproject/+/android-latest-release:frameworks/base/tools/aapt2/link/FlaggedXmlVersioner.cpp;l=82-91 While this block does both post-processing and auto-versioning so it should consider --no-auto-version:https://cs.android.com/android/platform/superproject/+/android-latest-release:frameworks/base/tools/aapt2/link/FlaggedXmlVersioner.cpp;l=93-103 Results with this option removed:
Source res/layout/flags.xml: Verbose log of decoding the built APK: While versioning happens only if I set minSdkVersion to lower than 37 in yaml (technically, should be lower than 36.1, but we can't pass minor version to aapt2), and splits into res/layout/flags.xml (featureFlags attributes stripped, elements with negated flags are kept and non-negated removed, basically treats the flags as if they were read-only and their value set to false) and res/layout-v36.1/flags.xml (processed with FlagExt blocks). |
|
Nice find. I vaguely remember seeing an aosp change to actually stamp the minor version into arsc, since it had been 0 forever. So the version constraint to a minor may be possible on 37+ |
Yeah, it works now and it's one of the changes I made in So, this FlagExt block injection doesn't get a chance to run as long as This can only be changed by patching aapt2. Other than that, my changes work as expected, now that I got the chance to test it. |
|
aapt/2 team was always pretty responsive on bugs, just not maybe in the speed of fixing them :) - https://issuetracker.google.com/issues?q=componentid:190923%2B%20status:open%20aapt2 |
|
Closing for #4220 |

Adds support for the new feature flag related structures in the API 37 ResourceTypes.h spec:
Figured giving AI AOSP and saying add the missing changes would help. It gave me this.