Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor ApkDecoder - streamline decode procedure #3109

Merged
merged 2 commits into from
Jun 28, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 60 additions & 83 deletions brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class ApkDecoder {
private final static String SMALI_DIRNAME = "smali";
private final static String UNK_DIRNAME = "unknown";
private final static String[] APK_RESOURCES_FILENAMES = new String[] {
"resources.arsc", "AndroidManifest.xml", "res", "r", "R" };
"resources.arsc", "res", "r", "R" };
iBotPeaches marked this conversation as resolved.
Show resolved Hide resolved
private final static String[] APK_MANIFEST_FILENAMES = new String[] {
"AndroidManifest.xml" };
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
Expand Down Expand Up @@ -101,46 +101,17 @@ public void decode(File outDir) throws AndrolibException, IOException, Directory

LOGGER.info("Using Apktool " + ApktoolProperties.getVersion() + " on " + mApkFile.getName());

if (hasResources()) {
switch (config.decodeResources) {
case Config.DECODE_RESOURCES_NONE:
copyResourcesRaw(mApkFile, outDir);
if (config.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
// done after raw decoding of resources because copyToDir overwrites dest files
if (hasManifest()) {
decodeManifestWithResources(mApkFile, outDir, getResTable());
}
}
break;
case Config.DECODE_RESOURCES_FULL:
if (hasManifest()) {
decodeManifestWithResources(mApkFile, outDir, getResTable());
}
decodeResourcesFull(mApkFile, outDir, getResTable());
break;
}
} else {
// if there's no resources.arsc, decode the manifest without looking
// up attribute references
if (hasManifest()) {
if (config.decodeResources == Config.DECODE_RESOURCES_FULL
|| config.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
decodeManifestFull(mApkFile, outDir, getResTable());
}
else {
copyManifestRaw(mApkFile, outDir);
}
}
}
decodeManifest(outDir);
decodeResources(outDir);

if (hasSources()) {
switch (config.decodeSources) {
case Config.DECODE_SOURCES_NONE:
copySourcesRaw(mApkFile, outDir, "classes.dex");
copySourcesRaw(outDir, "classes.dex");
break;
case Config.DECODE_SOURCES_SMALI:
case Config.DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES:
decodeSourcesSmali(mApkFile, outDir, "classes.dex");
decodeSourcesSmali(outDir, "classes.dex");
break;
}
}
Expand All @@ -153,16 +124,16 @@ public void decode(File outDir) throws AndrolibException, IOException, Directory
if (! file.equalsIgnoreCase("classes.dex")) {
switch(config.decodeSources) {
case Config.DECODE_SOURCES_NONE:
copySourcesRaw(mApkFile, outDir, file);
copySourcesRaw(outDir, file);
break;
case Config.DECODE_SOURCES_SMALI:
decodeSourcesSmali(mApkFile, outDir, file);
decodeSourcesSmali(outDir, file);
break;
case Config.DECODE_SOURCES_SMALI_ONLY_MAIN_CLASSES:
if (file.startsWith("classes") && file.endsWith(".dex")) {
decodeSourcesSmali(mApkFile, outDir, file);
decodeSourcesSmali(outDir, file);
} else {
copySourcesRaw(mApkFile, outDir, file);
copySourcesRaw(outDir, file);
}
break;
}
Expand All @@ -171,11 +142,11 @@ public void decode(File outDir) throws AndrolibException, IOException, Directory
}
}

copyRawFiles(mApkFile, outDir);
copyUnknownFiles(mApkFile, outDir);
copyRawFiles(outDir);
copyUnknownFiles(outDir);
mUncompressedFiles = new ArrayList<>();
recordUncompressedFiles(mApkFile, mUncompressedFiles);
copyOriginalFiles(mApkFile, outDir);
recordUncompressedFiles(mUncompressedFiles);
copyOriginalFiles(outDir);
writeMetaFile(outDir);
} finally {
try {
Expand Down Expand Up @@ -276,17 +247,17 @@ private Map<String, String> getMinSdkInfo() {
return sdkInfo;
}

private void copySourcesRaw(ExtFile apkFile, File outDir, String filename)
private void copySourcesRaw(File outDir, String filename)
throws AndrolibException {
try {
LOGGER.info("Copying raw " + filename + " file...");
apkFile.getDirectory().copyToDir(outDir, filename);
mApkFile.getDirectory().copyToDir(outDir, filename);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}

private void decodeSourcesSmali(File apkFile, File outDir, String filename)
private void decodeSourcesSmali(File outDir, String filename)
throws AndrolibException {
try {
File smaliDir;
Expand All @@ -299,7 +270,7 @@ private void decodeSourcesSmali(File apkFile, File outDir, String filename)
//noinspection ResultOfMethodCallIgnored
smaliDir.mkdirs();
LOGGER.info("Baksmaling " + filename + "...");
DexFile dexFile = SmaliDecoder.decode(apkFile, smaliDir, filename,
DexFile dexFile = SmaliDecoder.decode(mApkFile, smaliDir, filename,
config.baksmaliDebugMode, config.apiLevel);
int minSdkVersion = dexFile.getOpcodes().api;
if (mMinSdkVersion == 0 || mMinSdkVersion > minSdkVersion) {
Expand All @@ -310,46 +281,52 @@ private void decodeSourcesSmali(File apkFile, File outDir, String filename)
}
}

private void copyManifestRaw(ExtFile apkFile, File outDir)
throws AndrolibException {
try {
LOGGER.info("Copying raw manifest...");
apkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
private void decodeManifest(File outDir) throws AndrolibException {
if (hasManifest()) {
if (config.decodeResources == Config.DECODE_RESOURCES_FULL ||
config.forceDecodeManifest == Config.FORCE_DECODE_MANIFEST_FULL) {
if (hasResources()) {
mAndRes.decodeManifestWithResources(getResTable(), mApkFile, outDir);
} else {
// if there's no resources.arsc, decode the manifest without looking
// up attribute references
mAndRes.decodeManifest(getResTable(), mApkFile, outDir);
}
}
else {
try {
LOGGER.info("Copying raw manifest...");
mApkFile.getDirectory().copyToDir(outDir, APK_MANIFEST_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
}
}
}

private void decodeManifestFull(ExtFile apkFile, File outDir, ResTable resTable)
throws AndrolibException {
mAndRes.decodeManifest(resTable, apkFile, outDir);
}

private void copyResourcesRaw(ExtFile apkFile, File outDir)
throws AndrolibException {
try {
LOGGER.info("Copying raw resources...");
apkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
private void decodeResources(File outDir) throws AndrolibException {
if (hasResources()) {
switch (config.decodeResources) {
case Config.DECODE_RESOURCES_NONE:
try {
LOGGER.info("Copying raw resources...");
mApkFile.getDirectory().copyToDir(outDir, APK_RESOURCES_FILENAMES);
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
break;
case Config.DECODE_RESOURCES_FULL:
mAndRes.decode(getResTable(), mApkFile, outDir);
break;
}
}
}

private void decodeResourcesFull(ExtFile apkFile, File outDir, ResTable resTable)
throws AndrolibException {
mAndRes.decode(resTable, apkFile, outDir);
}

private void decodeManifestWithResources(ExtFile apkFile, File outDir, ResTable resTable)
throws AndrolibException {
mAndRes.decodeManifestWithResources(resTable, apkFile, outDir);
}

private void copyRawFiles(ExtFile apkFile, File outDir)
private void copyRawFiles(File outDir)
throws AndrolibException {
LOGGER.info("Copying assets and libs...");
try {
Directory in = apkFile.getDirectory();
Directory in = mApkFile.getDirectory();

if (config.decodeAssets == Config.DECODE_ASSETS_FULL) {
if (in.containsDir("assets")) {
Expand Down Expand Up @@ -379,12 +356,12 @@ private boolean isAPKFileNames(String file) {
return false;
}

private void copyUnknownFiles(ExtFile apkFile, File outDir)
private void copyUnknownFiles(File outDir)
throws AndrolibException {
LOGGER.info("Copying unknown files...");
File unknownOut = new File(outDir, UNK_DIRNAME);
try {
Directory unk = apkFile.getDirectory();
Directory unk = mApkFile.getDirectory();

// loop all items in container recursively, ignoring any that are pre-defined by aapt
Set<String> files = unk.getFiles(true);
Expand All @@ -403,7 +380,7 @@ private void copyUnknownFiles(ExtFile apkFile, File outDir)
}
}

private void copyOriginalFiles(ExtFile apkFile, File outDir)
private void copyOriginalFiles(File outDir)
throws AndrolibException {
LOGGER.info("Copying original files...");
File originalDir = new File(outDir, "original");
Expand All @@ -413,7 +390,7 @@ private void copyOriginalFiles(ExtFile apkFile, File outDir)
}

try {
Directory in = apkFile.getDirectory();
Directory in = mApkFile.getDirectory();
if (in.containsFile("AndroidManifest.xml")) {
in.copyToDir(originalDir, "AndroidManifest.xml");
}
Expand All @@ -436,9 +413,9 @@ private void copyOriginalFiles(ExtFile apkFile, File outDir)
}
}

private void recordUncompressedFiles(ExtFile apkFile, Collection<String> uncompressedFilesOrExts) throws AndrolibException {
private void recordUncompressedFiles(Collection<String> uncompressedFilesOrExts) throws AndrolibException {
try {
Directory unk = apkFile.getDirectory();
Directory unk = mApkFile.getDirectory();
Set<String> files = unk.getFiles(true);

for (String file : files) {
Expand Down