Skip to content

Commit

Permalink
refactor: Config/Tests/misc rework (#3746)
Browse files Browse the repository at this point in the history
* refactor: Config/Tests/misc rework

Config is now propagated to ResValue instead of being a globally
accessible instance that gets set each time a new Config is instantiated.
The old way violted every principle of an instance and even a singleton.
This caused working with Tests extremely error-prone, because the Config
had to be carefully reset to default for each Test to get the expected
behavior, and ResValue was only aware of the global instance.
Now, only Main and BaseTest are calling new Config().
BaseTest provides a fresh Config for every Test which turns the boilerplate
into something shorter, predictable and more robust.

Config class is now encapsulated to give control over the values passed
to it. Having both publically-modifyable fields and setters with the
verfications was more of a dirty hack than proper coding principles.

General-purpose XML utilities extracted from ResXmlUtils into XmlUtils
in the brut.xml library. It contains Document creation, parsing and saving.
In addition, it has a generic evaluateXPath method that's now used more
widely wherever manual looping over nodes was used, like in some tests.

ResXmlUtils reworked and cleaned, now takes advantage of XmlUtils.
ResXmlUtils only retains methods relevant specifically to resource XMLs
and Android Manifest.

Minor tweaks and code cleanup in various classed like ApktoolProperties
and the main work classes (Framework, ApkDecoder, ApkBuilder, etc.),
as well as utility classes like AaptInvoker and OS.

Fixed locks being held by certain ExtFiles to zips with loaded Directory,
which prevented proper temp file cleanup during Test stage.

ExternalEntityTest resources ("doctype") moved to aapt1 as it's an
aapt1-only test.

Overall, mainly a code refactor with no end-user changes,
to make development less prone to errors.

* fix framework parent check

* make sure frameworkDirectory is never null

* make sure frameworkDirectory is never null

* style

* retrieve Config only in ResBagValue and misc tweaks

We actually don't need to pass Config explicitly to all ResValue subtypes.
It's only needed by 3 subtypes of ResBagValue, so we get the Config
via ResBagValue's mParent.getPackage().getConfig().

Encapsulate ResConfigFlags.

Encapsulate ResID and make it a numeric and comparable type.

Sort resource specs by resource ID in generatePublicXml.

Duo is redundant, replace with Apache Common's Pair.

ResIdValue is redundant, it's never actually instantiated.

Tweak equals and hashCode overrides to standard formats.

Misc style and variable name tweaks.

* redundant explicit toString calls

* Objects.hash is safer
  • Loading branch information
IgorEisberg authored Dec 29, 2024
1 parent 70a99d2 commit f6d568b
Show file tree
Hide file tree
Showing 115 changed files with 2,664 additions and 3,233 deletions.
79 changes: 38 additions & 41 deletions brut.apktool/apktool-cli/src/main/java/brut/apktool/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@
import brut.androlib.exceptions.OutDirExistsException;
import brut.androlib.res.Framework;
import brut.common.BrutException;
import brut.directory.DirectoryException;
import brut.directory.ExtFile;
import brut.util.AaptManager;
import brut.util.OSDetection;
import org.apache.commons.cli.*;

Expand Down Expand Up @@ -73,8 +71,8 @@ public static void main(String[] args) throws BrutException {
try {
commandLine = parser.parse(allOptions, args, false);

if (! OSDetection.is64Bit()) {
System.err.println("32 bit support is deprecated. Apktool will not support 32bit on v3.0.0.");
if (!OSDetection.is64Bit()) {
System.err.println("32-bit support is deprecated and will be removed in 3.0.0.");
}
} catch (ParseException ex) {
System.err.println(ex.getMessage());
Expand All @@ -96,7 +94,7 @@ public static void main(String[] args) throws BrutException {
setAdvanceMode();
}

Config config = Config.getDefaultConfig();
Config config = new Config();
initConfig(commandLine, config);

boolean cmdFound = false;
Expand Down Expand Up @@ -145,16 +143,16 @@ public static void main(String[] args) throws BrutException {

private static void initConfig(CommandLine cli, Config config) {
if (cli.hasOption("p") || cli.hasOption("frame-path")) {
config.frameworkDirectory = cli.getOptionValue("p");
config.setFrameworkDirectory(cli.getOptionValue("p"));
}
if (cli.hasOption("t") || cli.hasOption("tag")) {
config.frameworkTag = cli.getOptionValue("t");
config.setFrameworkTag(cli.getOptionValue("t"));
}
if (cli.hasOption("api") || cli.hasOption("api-level")) {
config.apiLevel = Integer.parseInt(cli.getOptionValue("api"));
config.setApiLevel(Integer.parseInt(cli.getOptionValue("api")));
}
if (cli.hasOption("j") || cli.hasOption("jobs")) {
config.jobs = Integer.parseInt(cli.getOptionValue("j"));
config.setJobs(Integer.parseInt(cli.getOptionValue("j")));
}
}

Expand All @@ -166,17 +164,21 @@ private static void cmdDecode(CommandLine cli, Config config) throws AndrolibExc
config.setDecodeSources(Config.DECODE_SOURCES_NONE);
}
if (cli.hasOption("only-main-classes")) {
config.setDecodeSources(Config.DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES);
if (cli.hasOption("s") || cli.hasOption("no-src")) {
System.err.println("--only-main-classes cannot be paired with -s/--no-src. Ignoring.");
} else {
config.setDecodeSources(Config.DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES);
}
}
if (cli.hasOption("d") || cli.hasOption("debug")) {
System.err.println("SmaliDebugging has been removed in 2.1.0 onward. Please see: https://github.com/iBotPeaches/Apktool/issues/1061");
System.exit(1);
}
if (cli.hasOption("b") || cli.hasOption("no-debug-info")) {
config.baksmaliDebugMode = false;
config.setBaksmaliDebugMode(false);
}
if (cli.hasOption("f") || cli.hasOption("force")) {
config.forceDelete = true;
config.setForceDelete(true);
}
if (cli.hasOption("r") || cli.hasOption("no-res")) {
config.setDecodeResources(Config.DECODE_RESOURCES_NONE);
Expand All @@ -188,10 +190,10 @@ private static void cmdDecode(CommandLine cli, Config config) throws AndrolibExc
config.setDecodeAssets(Config.DECODE_ASSETS_NONE);
}
if (cli.hasOption("k") || cli.hasOption("keep-broken-res")) {
config.keepBrokenResources = true;
config.setKeepBrokenResources(true);
}
if (cli.hasOption("m") || cli.hasOption("match-original")) {
config.analysisMode = true;
config.setAnalysisMode(true);
}
if (cli.hasOption("resm") || cli.hasOption("res-mode") || cli.hasOption("resolve-resources-mode")) {
String mode = cli.getOptionValue("resm");
Expand Down Expand Up @@ -266,16 +268,16 @@ private static void cmdBuild(CommandLine cli, Config config) throws AndrolibExce

// check for build options
if (cli.hasOption("f") || cli.hasOption("force-all")) {
config.forceBuildAll = true;
config.setForceBuildAll(true);
}
if (cli.hasOption("d") || cli.hasOption("debug")) {
config.debugMode = true;
config.setDebugMode(true);
}
if (cli.hasOption("n") || cli.hasOption("net-sec-conf")) {
config.netSecConf = true;
config.setNetSecConf(true);
}
if (cli.hasOption("v") || cli.hasOption("verbose")) {
config.verbose = true;
config.setVerbose(true);
}
if (cli.hasOption("a") || cli.hasOption("aapt")) {
if (cli.hasOption("use-aapt1") || cli.hasOption("use-aapt2")) {
Expand All @@ -284,8 +286,7 @@ private static void cmdBuild(CommandLine cli, Config config) throws AndrolibExce
}

try {
config.aaptBinary = new File(cli.getOptionValue("a"));
config.aaptVersion = AaptManager.getAaptVersion(config.aaptBinary);
config.setAaptBinary(new File(cli.getOptionValue("a")));
} catch (BrutException ex) {
System.err.println(ex.getMessage());
System.exit(1);
Expand All @@ -296,42 +297,38 @@ private static void cmdBuild(CommandLine cli, Config config) throws AndrolibExce
System.exit(1);
}

config.aaptVersion = 1;
config.setAaptVersion(1);
}
if (cli.hasOption("c") || cli.hasOption("copy-original")) {
config.copyOriginalFiles = true;
config.setCopyOriginalFiles(true);
}
if (cli.hasOption("nc") || cli.hasOption("no-crunch")) {
config.noCrunch = true;
config.setNoCrunch(true);
}
if (cli.hasOption("na") || cli.hasOption("no-apk")) {
config.noApk = true;
config.setNoApk(true);
}

File outFile;
if (cli.hasOption("o") || cli.hasOption("output")) {
outFile = new File(cli.getOptionValue("o"));
} else {
outFile = null;
}

if (config.netSecConf && config.aaptVersion == 1) {
if (config.isNetSecConf() && config.getAaptVersion() == 1) {
System.err.println("-n / --net-sec-conf is not supported with legacy aapt.");
System.exit(1);
}

File outFile = cli.hasOption("o") || cli.hasOption("output")
? new File(cli.getOptionValue("o")) : null;

ExtFile apkDir = new ExtFile(apkDirName);
ApkBuilder builder = new ApkBuilder(apkDir, config);
builder.build(outFile);
}

private static void cmdInstallFramework(CommandLine cli, Config config) throws AndrolibException {
String apkName = getLastArg(cli);
new Framework(config).installFramework(new File(apkName));
new Framework(config).install(new File(apkName));
}

private static void cmdListFrameworks(CommandLine cli, Config config) throws AndrolibException {
new Framework(config).listFrameworkDirectory();
new Framework(config).listDirectory();
}

private static void cmdPublicizeResources(CommandLine cli, Config config) throws AndrolibException {
Expand All @@ -341,9 +338,9 @@ private static void cmdPublicizeResources(CommandLine cli, Config config) throws

private static void cmdEmptyFrameworkDirectory(CommandLine cli, Config config) throws AndrolibException {
if (cli.hasOption("f") || cli.hasOption("force")) {
config.forceDeleteFramework = true;
config.setForceDeleteFramework(true);
}
new Framework(config).emptyFrameworkDirectory();
new Framework(config).emptyDirectory();
}

private static String getLastArg(CommandLine cli) {
Expand Down Expand Up @@ -638,11 +635,11 @@ private static void usage() {

// print out license info prior to formatter.
System.out.println(
"Apktool " + ApktoolProperties.getVersion() + " - a tool for reengineering Android apk files\n" +
"with smali v" + ApktoolProperties.get("smaliVersion") +
" and baksmali v" + ApktoolProperties.get("baksmaliVersion") + "\n" +
"Copyright 2010 Ryszard Wiśniewski <[email protected]>\n" +
"Copyright 2010 Connor Tumbleson <[email protected]>" );
"Apktool " + ApktoolProperties.getVersion() + " - a tool for reengineering Android apk files\n" +
"with smali " + ApktoolProperties.getSmaliVersion() +
" and baksmali " + ApktoolProperties.getBaksmaliVersion() + "\n" +
"Copyright 2010 Ryszard Wiśniewski <[email protected]>\n" +
"Copyright 2010 Connor Tumbleson <[email protected]>");
if (isAdvanceMode()) {
System.out.println("Apache License 2.0 (https://www.apache.org/licenses/LICENSE-2.0)\n");
}else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,9 @@ public class TypedValue {

private static final float MANTISSA_MULT = 1.0f / (1 << TypedValue.COMPLEX_MANTISSA_SHIFT);
private static final float[] RADIX_MULTS = {
MANTISSA_MULT, 1.0f / (1 << 7) * MANTISSA_MULT,
1.0f / (1 << 15) * MANTISSA_MULT, 1.0f / (1 << 23) * MANTISSA_MULT };
MANTISSA_MULT, 1.0f / (1 << 7) * MANTISSA_MULT,
1.0f / (1 << 15) * MANTISSA_MULT, 1.0f / (1 << 23) * MANTISSA_MULT
};

/**
* Retrieve the base value from a complex data integer. This uses the
Expand Down
Loading

0 comments on commit f6d568b

Please sign in to comment.