* refactor: ExtDataInput rework, source layout and formatting
Refactor ExtDataInput classes: ExtDataInput is now the extended interface,
ExtDataInputStream is an easy-to-use FilterInputStream implementing ExtDataInput
with static creator methods for big-endian and little-endian wrappers.
Refactor AaptManager class: unify aapt-related verifications to one class.
Replace Apache Commons' deprecated CountingInputStream with Google Guava's
equivalent with the same name. Apache's BoundedInputStream is an overkill
for our use case and its constructors are deprecated as well.
Normalize source layout to have a common and somewhat more standard order:
Static fields first, instance fields after, methods last.
Fix some formatting, like empty spaces or extra spaces and exception messages.
Renamed ResXmlPatcher to ResXmlUtils, as it has more purposes than just patching.
Renamed DirUtil to DirUtils, to match other utility classes naming convention.
Moved "properties/apktool.properties" to jar's root, to match smali/baksmali.
Moved Android Framework to "prebuilt", as it is just a prebuilt, looks out of
place among .class files.
@SuppressWarnings removed from Duo as there are quite a few unsafe assignments
of raw Duo[] instances to parameterized Duo<> variables in the project, this is
just Java being the primitive boilerplate it is, no point in fighting it.
No end-user changes.
Tested against a full ROM decompile/recompile, no issues found.
* small tweak
* last refinement
* missed a stream
* add user, system certificate in existing network security config rather than creating a fresh config
* prevent deleting existing network security config to modify the existing one
* modified test case for certificate check.
Rather than comparing exact string, parse and check if user and system certificate exist
Use BrutIO where possible to improve and simplify stream handling.
Ensure streams are closed when no longer needed.
Some minor formatting tweaks and naming consistency.
No functionality changes.
Recording feature flags moved to ResourcesDecoder to fix
an issue where raw AndroidManifest is attempted to be
parsed even when decoding without resources.
Replaced remaining usages of FileInputStream/FileInputStream
with their NIO equivalents for consistency with rest of code.
Minor redundancy and format tweaks.
* refactor: clean up external pull parser and introduce brut.j.xml
We have no need for an XML pull parser in the project,
it was only used for testing, which is now done with XPath.
The external xpp3 library from org.ogce is obsolete and has
the issue of including javax.xml.namespace.QName which conflicts
with the JRE implementation that exists for a very long time now.
This makes direct usages of QName produce very obscure NPEs that
took me hours to figure out. This patch will allow further
optimization that is WIP.
The external library was replaced by the basic xmlpull API.
The MXSerializer has been cleaned and the features used by apktool
have been integrated into the custom implementation, now part of
a separate module called brut.j.xml.
Writing has been optimized by buffering write operations, inspired
by KXmlSerializer used by Android itself.
A class XmlPullUtils also written that allows copying from a
XmlPullParser into a XmlSerializer with or without an EventHandler.
We use it for AndroidManifestPullStreamDecoder (with EventHandler,
to allow omitting the uses-sdk tag), and for ResXmlPullStreamDecoder
(direct copy, without EventHandler).
saveDocument in ResXmlPatcher was tweaked to output proper output -
a new line after declaration and a new line after root element's
end tag.
TL;DR mostly behind the scene refactor, no end user changes.
Pretty straightforward change. The motivation is to reproduce the original
structure of the source APK. If it's built with compact resource entries -
then rebuild with compact resource entries.
* fix: decoding APK with many compact entries and unknown uses-sdk attrs
This fixes 2 new issues with a stock APK sourced from an Android 15 ROM.
https://drive.google.com/file/d/1x9udLN4W5I7chyGp1ZY8Cyfhu1vXezU9/view
1) mIn.readShort() for size in readEntryData is incorrect and the size < 0 check is not possible.
Entry size is stored by AAPT2 as an unsigned short and thus will never be negative.
Reading it as a signed short will cause negative entry sizes in compactly packed entries in
very large string pools and will result in a lot of "APKTOOL_DUMMYVAL_" values.
2) sdkInfo isn't stored properly for APKs with unexpected properties in uses-sdk tag.
As far as I can tell, these attributes serve no purpose and can be ignored.
In the given APK, additional "android:versionCode" and "android:versionName" attributes appear
in the uses-sdk tag, purpose unknown and they don't represent the actual version of the app.
E: uses-sdk (line=26)
A: http://schemas.android.com/apk/res/android:minSdkVersion(0x0101020c)=35
A: http://schemas.android.com/apk/res/android:versionCode(0x0101021b)=31
A: http://schemas.android.com/apk/res/android:versionName(0x0101021c)="3.1"
A: http://schemas.android.com/apk/res/android:targetSdkVersion(0x01010270)=35
* test: add assertion for issue 3705
---------
Co-authored-by: Connor Tumbleson <connor.tumbleson@gmail.com>
Co-authored-by: Connor Tumbleson <iBotPeaches@users.noreply.github.com>
* new: featureFlags support for SDK 35 apps
This records all featureFlag attrs that were enabled when the APK was originally built.
This is now required by AAPT2 to pass these flags and their enabled/disabled state if
they are used in AndroidManifest.xml.
The flags are recorded to apktool.yml and can be configured, if so desired.
In normal usage, all flags should remain set to true (i.e. enabled).
Sample APK sourced from AOSP Android 15.
https://drive.google.com/file/d/1av7Ih7-YUXi73Hf0E3xlPv-V-nE_sXdt/view
* test: adapt testapp for featureFlag
* refactor: ApkDecoder & ApkBuilder overhaul
A major rewrite of ApkDecoder and ApkBuilder classes to make them managable.
Removed many instances of redundancy and improved syntaxed and indentation.
Modifying the stock Apktool source to our needs have become too difficult,
so I'm pushing the general (not specific to our needs) changes upstream.
I'd change a lot more, but I wanted to make sure all tests pass as expected,
despite some of them being wierd, outdated or unnecessary.
This also fixes certain files in META-INF being lost during recompile
when the -c/--copy-original option isn't used.
This has been tweaked and tested for several days and I vouch for its stablity.
* style: fix more redundancy
* style: fix more redundancy
* tweak: consistent case-sensitivity for cmd and options
* refactor: tracking unknownFiles via apkInfo is redundant
1) We take advantage of the fact that doNotCompress already tracks uncompressed files,
including those separated into "unknown".
With this change the "unknownFiles" is simply ignored, so it's backward-compatible
with existing decoded APK dirs.
Tweaked a few tests to match the removal of "unknownFiles".
2) Passing doNotCompress to AAPT is redundant, Apktool extracts the temp APK packed by
AAPT to build/apk and then repackages it anyway, so it serves no purpose.
* refactor: fix minSdkVersion from baksmali + clean up more redundancy
* Regression: minSdkVersion inferred from baksmali was not stored properly.
* The arsc extension can be generalized for simplicity as seen in AOSP source.
https://cs.android.com/android/platform/superproject/main/+/main:external/deqp/scripts/android/build_apk.py;l=644?q=apk%20pack&ss=android%2Fplatform%2Fsuperproject%2Fmain:external%2F
Note:
NO_COMPRESS_EXT_PATTERN only collapses paths to a common extension.
It does NOT force these extensions to be always uncompressed.
doNotCompress is the one determining files/extensions that should be uncompressed.
(no funcionality was changed)
* resourcesAreCompressed in apkInfo is redundant. It was only used in invokeAapt,
but not ApkBuilder. Its value is also never set by Apktool, only read.
Like with doNotCompress, passing any kind of compression rules to AAPT is pointless,
since we don't use the temp APK packed by AAPT directly - it's extracted and repacked
by ApkBuilder, where doNotCompress already determines whether resources.arsc should
or should not be compressed in the final APK.
(no funcionality was changed)
* style: optional args come after required args
* style: optional args come after required args
* style: sdkInfo as a normal field for consistency
* style: some formatting tweaks
* fix: support API 35 as Vanilla Ice Cream
* feat: update internal framework to API 35 preview (Vanilla Ice Cream)
* chore: SDK_CUR_DEVELOPMENT is 10,000
This lets us assemble classes.dex in a reproducible manner.
Test:
apktool d test.apk > /dev/null
apktool b test > /dev/null
sha1sum test/build/apk/classes.dex
apktool -f d test.apk > /dev/null
apktool b test > /dev/null
sha1sum test/build/apk/classes.dex
If th zip entry for resources.arsc is not found an exception is
thrown, but the ZipFile is not closed. Using try-with-resources
means that the ZipFile will always be closed irrespective of how
the code block exits.