hsiafan/apk-parser

Bug: when parsing APK that requires split APKs, it doesn't set "isSplitRequired" to true

Opened this issue · 1 comments

v2.6.10

I've now tested YouTube APK, and it seems that even though in the manifest XML content that it gets, I can see android:isSplitRequired="true" , when checking the apkMeta instance, it's actually false.

If you wish, this is the manifest XML content taken from it:

youtube manifest.zip

And attached here the APK that I've tested on:

youtube base.zip

Tested on Android 9, library v 2.6.10

Took me time, but I think I know where it occurs. Just don't know why.

Seems that in BinaryXmlParser.readXmlNodeStartTag , it goes over the attributes of the "manifest" tag to search for "isSplitRequired", but the library actually puts this attribute into the "application" tag instead:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1511902656" android:versionName="15.14.33" android:compileSdkVersion="29" android:compileSdkVersionCodename="R" package="com.google.android.youtube" platformBuildVersionCode="29" platformBuildVersionName="R">
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29" />
...
	<application android:theme="resourceId:0x7f140408" android:label="YouTube" android:icon="res/CGK.png" android:name="com.google.android.apps.youtube.app.YouTubeApplication" android:backupAgent="com.google.android.apps.youtube.app.application.backup.YouTubeBackupAgent" android:allowBackup="true" android:restoreAnyVersion="true" android:logo="res/d8V.png" android:hardwareAccelerated="true" android:largeHeap="true" android:supportsRtl="true" android:networkSecurityConfig="res/4uC.xml" android:roundIcon="res/C9M.png" android:isSplitRequired="true" android:requestLegacyExternalStorage="true">

For comparison, this is the whole manifest of a split APK file, that I get from the library:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1511902656" configForSplit="" package="com.google.android.youtube" split="config.armeabi_v7a">
	<application android:hasCode="false">
		<meta-data android:name="com.android.vending.derived.apk.id" android:value="1" />
	</application>
</manifest>

Here I can see the "split" attribute in the "manifest" tag.

The parsing is correct : it's supposed to be in the "manifest" tag. But for some reason it didn't get there, but into the "application" tag instead.
Seems there might be other such attributes to moved from one place to another, too.
So, either the parsing need to be flexible and check on both, or that before, there is some bug causing it.

However, if you run these online tools, for example, you will notice that it's going into the "application" tag, too:
https://www.sisik.eu/apk-tool
http://www.javadecompilers.com/

So, for now, a workaround is as such:

        switch (xmlNodeStartTag.getName()) {
            case "application":
                if (apkMetaBuilder.split == null)
                    apkMetaBuilder.setSplit(attributes.getString("split"));
                if (apkMetaBuilder.configForSplit == null)
                    apkMetaBuilder.setConfigForSplit(attributes.getString("configForSplit"));
                if (!apkMetaBuilder.isFeatureSplit)
                    apkMetaBuilder.setIsFeatureSplit(attributes.getBoolean("isFeatureSplit", false));
                if (!apkMetaBuilder.isSplitRequired)
                    apkMetaBuilder.setIsSplitRequired(attributes.getBoolean("isSplitRequired", false));
                if (!apkMetaBuilder.isolatedSplits)
                    apkMetaBuilder.setIsolatedSplits(attributes.getBoolean("isolatedSplits", false));
...
            case "manifest":
                apkMetaBuilder.setPackageName(attributes.getString("package"));
                apkMetaBuilder.setVersionName(attributes.getString("versionName"));
                apkMetaBuilder.setRevisionCode(attributes.getLong("revisionCode"));
                apkMetaBuilder.setSharedUserId(attributes.getString("sharedUserId"));
                apkMetaBuilder.setSharedUserLabel(attributes.getString("sharedUserLabel"));
                if (apkMetaBuilder.split == null)
                    apkMetaBuilder.setSplit(attributes.getString("split"));
                if (apkMetaBuilder.configForSplit == null)
                    apkMetaBuilder.setConfigForSplit(attributes.getString("configForSplit"));
                if (!apkMetaBuilder.isFeatureSplit)
                    apkMetaBuilder.setIsFeatureSplit(attributes.getBoolean("isFeatureSplit", false));
                if (!apkMetaBuilder.isSplitRequired)
                    apkMetaBuilder.setIsSplitRequired(attributes.getBoolean("isSplitRequired", false));
                if (!apkMetaBuilder.isolatedSplits)
                    apkMetaBuilder.setIsolatedSplits(attributes.getBoolean("isolatedSplits", false));

The reason is that I suspect the split attributes might appear in either of those.

Here's a sample project to test on Android with the workaround :

https://github.com/AndroidDeveloperLB/apk-parser