Skip to content

Commit bc73940

Browse files
authored
Android 14 Support (Partial) (#3206)
* fix: prevent over-reading config flags * feat: add grammatical inflection * fix: add natural requirement for U * fix: UpsideDownCake is now 34 * test: test for grammatical inflection * fix: add detection for compact resources * fix: add detection for offset16 table types * Revert "test: test for grammatical inflection" This reverts commit fa08cef. * refactor: use enum instead of magic numbers
1 parent 91a5863 commit bc73940

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

brut.apktool/apktool-lib/src/main/java/brut/androlib/apk/ApkInfo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ private int mapSdkShorthandToVersion(String sdkVersion) {
191191
return ResConfigFlags.SDK_TIRAMISU;
192192
case "UPSIDEDOWNCAKE":
193193
case "UPSIDE_DOWN_CAKE":
194+
return ResConfigFlags.SDK_UPSIDEDOWN_CAKE;
194195
case "VANILLAICECREAM":
195196
case "VANILLA_ICE_CREAM":
196197
return ResConfigFlags.SDK_DEVELOPMENT;

brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResConfigFlags.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public class ResConfigFlags {
3232
public final byte keyboard;
3333
public final byte navigation;
3434
public final byte inputFlags;
35+
public final byte grammaticalInflection;
3536

3637
public final short screenWidth;
3738
public final short screenHeight;
@@ -70,6 +71,7 @@ public ResConfigFlags() {
7071
keyboard = KEYBOARD_ANY;
7172
navigation = NAVIGATION_ANY;
7273
inputFlags = KEYSHIDDEN_ANY | NAVHIDDEN_ANY;
74+
grammaticalInflection = GRAMMATICAL_GENDER_ANY;
7375
screenWidth = 0;
7476
screenHeight = 0;
7577
sdkVersion = 0;
@@ -91,7 +93,7 @@ public ResConfigFlags() {
9193
public ResConfigFlags(short mcc, short mnc, char[] language,
9294
char[] region, byte orientation,
9395
byte touchscreen, int density, byte keyboard, byte navigation,
94-
byte inputFlags, short screenWidth, short screenHeight,
96+
byte inputFlags, byte grammaticalInflection, short screenWidth, short screenHeight,
9597
short sdkVersion, byte screenLayout, byte uiMode,
9698
short smallestScreenWidthDp, short screenWidthDp,
9799
short screenHeightDp, char[] localeScript, char[] localeVariant,
@@ -149,6 +151,7 @@ public ResConfigFlags(short mcc, short mnc, char[] language,
149151
this.keyboard = keyboard;
150152
this.navigation = navigation;
151153
this.inputFlags = inputFlags;
154+
this.grammaticalInflection = grammaticalInflection;
152155
this.screenWidth = screenWidth;
153156
this.screenHeight = screenHeight;
154157
this.sdkVersion = sdkVersion;
@@ -198,6 +201,18 @@ private String generateQualifiers() {
198201
}
199202
ret.append(getLocaleString());
200203

204+
switch (grammaticalInflection) {
205+
case GRAMMATICAL_GENDER_NEUTER:
206+
ret.append("-neuter");
207+
break;
208+
case GRAMMATICAL_GENDER_FEMININE:
209+
ret.append("-feminine");
210+
break;
211+
case GRAMMATICAL_GENDER_MASCULINE:
212+
ret.append("-masculine");
213+
break;
214+
}
215+
201216
switch (screenLayout & MASK_LAYOUTDIR) {
202217
case SCREENLAYOUT_LAYOUTDIR_RTL:
203218
ret.append("-ldrtl");
@@ -421,6 +436,9 @@ private String generateQualifiers() {
421436
}
422437

423438
private short getNaturalSdkVersionRequirement() {
439+
if (grammaticalInflection != 0) {
440+
return SDK_UPSIDEDOWN_CAKE;
441+
}
424442
if ((uiMode & MASK_UI_MODE_TYPE) == UI_MODE_TYPE_VR_HEADSET || (colorMode & COLOR_WIDE_MASK) != 0 || ((colorMode & COLOR_HDR_MASK) != 0)) {
425443
return SDK_OREO;
426444
}
@@ -550,6 +568,7 @@ public int hashCode() {
550568
public final static byte SDK_S = 31;
551569
public final static byte SDK_S_V2 = 32;
552570
public final static byte SDK_TIRAMISU = 33;
571+
public final static byte SDK_UPSIDEDOWN_CAKE = 34;
553572

554573
// AOSP has this as 10,000 for dev purposes.
555574
// platform_frameworks_base/commit/c7a1109a1fe0771d4c9b572dcf178e2779fc4f2d
@@ -590,6 +609,11 @@ public int hashCode() {
590609
public final static short SCREENLAYOUT_ROUND_NO = 0x1;
591610
public final static short SCREENLAYOUT_ROUND_YES = 0x2;
592611

612+
public final static byte GRAMMATICAL_GENDER_ANY = 0;
613+
public final static byte GRAMMATICAL_GENDER_NEUTER = 1;
614+
public final static byte GRAMMATICAL_GENDER_FEMININE = 2;
615+
public final static byte GRAMMATICAL_GENDER_MASCULINE = 3;
616+
593617
public final static byte KEYBOARD_ANY = 0;
594618
public final static byte KEYBOARD_NOKEYS = 1;
595619
public final static byte KEYBOARD_QWERTY = 2;

brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,13 +282,18 @@ private ResType readTableType() throws IOException, AndrolibException {
282282

283283
// Be sure we don't poison mResTable by marking the application as sparse
284284
// Only flag the ResTable as sparse if the main package is not loaded.
285-
if ((typeFlags & 0x01) != 0 && !mResTable.isMainPkgLoaded()) {
285+
if ((typeFlags & TABLE_TYPE_FLAG_SPARSE) != 0 && !mResTable.isMainPkgLoaded()) {
286286
mResTable.setSparseResources(true);
287287
}
288288

289+
if ((typeFlags & TABLE_TYPE_FLAG_OFFSET16) != 0) {
290+
LOGGER.warning("Please report this application to Apktool for a fix: https://github.com/iBotPeaches/Apktool/issues/3367");
291+
throw new AndrolibException("Unexpected TYPE_FLAG_OFFSET16");
292+
}
293+
289294
HashMap<Integer, Integer> entryOffsetMap = new LinkedHashMap<>();
290295
for (int i = 0; i < entryCount; i++) {
291-
if ((typeFlags & 0x01) != 0) {
296+
if ((typeFlags & TABLE_TYPE_FLAG_SPARSE) != 0) {
292297
entryOffsetMap.put(mIn.readUnsignedShort(), mIn.readUnsignedShort());
293298
} else {
294299
entryOffsetMap.put(i, mIn.readInt());
@@ -352,7 +357,15 @@ private EntryData readEntryData() throws IOException, AndrolibException {
352357
return null;
353358
}
354359

355-
ResValue value = (flags & ENTRY_FLAG_COMPLEX) == 0 ? readValue() : readComplexEntry();
360+
boolean isComplex = (flags & ENTRY_FLAG_COMPLEX) != 0;
361+
boolean isCompact = (flags & ENTRY_FLAG_COMPACT) != 0;
362+
363+
if (isCompact) {
364+
LOGGER.warning("Please report this application to Apktool for a fix: https://github.com/iBotPeaches/Apktool/issues/3366");
365+
throw new AndrolibException("Unexpected entry type: compact");
366+
}
367+
368+
ResValue value = isComplex ? readComplexEntry() : readValue();
356369
// #2824 - In some applications the res entries are duplicated with the 2nd being malformed.
357370
// AOSP skips this, so we will do the same.
358371
if (value == null) {
@@ -483,11 +496,12 @@ private ResConfigFlags readConfigFlags() throws IOException, AndrolibException {
483496
byte keyboard = 0;
484497
byte navigation = 0;
485498
byte inputFlags = 0;
499+
byte grammaticalInflection = 0;
486500
if (size >= 20) {
487501
keyboard = mIn.readByte();
488502
navigation = mIn.readByte();
489503
inputFlags = mIn.readByte();
490-
mIn.skipBytes(1); // inputPad0
504+
grammaticalInflection = mIn.readByte();
491505
read = 20;
492506
}
493507

@@ -545,6 +559,7 @@ private ResConfigFlags readConfigFlags() throws IOException, AndrolibException {
545559
}
546560

547561
int exceedingKnownSize = size - KNOWN_CONFIG_BYTES;
562+
548563
if (exceedingKnownSize > 0) {
549564
byte[] buf = new byte[exceedingKnownSize];
550565
read += exceedingKnownSize;
@@ -569,7 +584,7 @@ private ResConfigFlags readConfigFlags() throws IOException, AndrolibException {
569584

570585
return new ResConfigFlags(mcc, mnc, language, country,
571586
orientation, touchscreen, density, keyboard, navigation,
572-
inputFlags, screenWidth, screenHeight, sdkVersion,
587+
inputFlags, grammaticalInflection, screenWidth, screenHeight, sdkVersion,
573588
screenLayout, uiMode, smallestScreenWidthDp, screenWidthDp,
574589
screenHeightDp, localeScript, localeVariant, screenLayout2,
575590
colorMode, localeNumberingSystem, isInvalid, size);
@@ -663,6 +678,10 @@ private void checkChunkType(int expectedType) throws AndrolibException {
663678
private final static short ENTRY_FLAG_COMPLEX = 0x0001;
664679
private final static short ENTRY_FLAG_PUBLIC = 0x0002;
665680
private final static short ENTRY_FLAG_WEAK = 0x0004;
681+
private final static short ENTRY_FLAG_COMPACT = 0x0008;
682+
683+
private final static short TABLE_TYPE_FLAG_SPARSE = 0x01;
684+
private final static short TABLE_TYPE_FLAG_OFFSET16 = 0x02;
666685

667686
private static final int KNOWN_CONFIG_BYTES = 64;
668687

0 commit comments

Comments
 (0)