Multiple Dex Support - part 2

- CS fixes
 - adds support for building multiple dex
 - prevents extra dex from being unknown and extra dex
 - adds unit-test
This commit is contained in:
Connor Tumbleson 2014-08-16 08:29:57 -05:00
parent 70eaab9971
commit c476ce16be
3 changed files with 64 additions and 36 deletions

View File

@ -185,11 +185,11 @@ public class Androlib {
// loop all items in container recursively, ignoring any that are pre-defined by aapt // loop all items in container recursively, ignoring any that are pre-defined by aapt
Set<String> files = unk.getFiles(true); Set<String> files = unk.getFiles(true);
for (String file : files) { for (String file : files) {
if (!isAPKFileNames(file)) { if (!isAPKFileNames(file) && !file.endsWith(".dex")) {
// copy file out of archive into special "unknown" folder // copy file out of archive into special "unknown" folder
// to be re-included on build // to be re-included on build
unk.copyToDir(unknownOut,file); unk.copyToDir(unknownOut, file);
try { try {
// ignore encryption // ignore encryption
apkZipFile.getEntry(file).getGeneralPurposeBit().useEncryption(false); apkZipFile.getEntry(file).getGeneralPurposeBit().useEncryption(false);
@ -309,6 +309,7 @@ public class Androlib {
new File(appDir, APK_DIRNAME).mkdirs(); new File(appDir, APK_DIRNAME).mkdirs();
buildSources(appDir, flags); buildSources(appDir, flags);
buildNonDefaultSources(appDir, flags);
buildResources(appDir, flags, (Map<String, Object>) meta.get("usesFramework")); buildResources(appDir, flags, (Map<String, Object>) meta.get("usesFramework"));
buildLib(appDir, flags); buildLib(appDir, flags);
buildCopyOriginalFiles(appDir, flags); buildCopyOriginalFiles(appDir, flags);
@ -321,44 +322,61 @@ public class Androlib {
public void buildSources(File appDir, HashMap<String, Boolean> flags) public void buildSources(File appDir, HashMap<String, Boolean> flags)
throws AndrolibException { throws AndrolibException {
if (!buildSourcesRaw(appDir, flags) if (!buildSourcesRaw(appDir, "classes.dex", flags) && !buildSourcesSmali(appDir, "smali", "classes.dex", flags) && !buildSourcesJava(appDir, flags)) {
&& !buildSourcesSmali(appDir, flags)
&& !buildSourcesJava(appDir, flags)) {
LOGGER.warning("Could not find sources"); LOGGER.warning("Could not find sources");
} }
} }
public boolean buildSourcesRaw(File appDir, HashMap<String, Boolean> flags) public void buildNonDefaultSources(ExtFile appDir, HashMap<String, Boolean> flags)
throws AndrolibException { throws AndrolibException {
try { try {
File working = new File(appDir, "classes.dex"); Map<String, Directory> dirs = appDir.getDirectory().getDirs();
if (!working.exists()) { for (Map.Entry<String, Directory> directory : dirs.entrySet()) {
return false; String name = directory.getKey();
if (name.startsWith("smali_")) {
String filename = name.substring(name.indexOf("_") + 1) + ".dex";
if (!buildSourcesRaw(appDir, filename, flags) && !buildSourcesSmali(appDir, name, filename, flags) && !buildSourcesJava(appDir, flags)) {
LOGGER.warning("Could not find sources");
}
}
} }
File stored = new File(appDir, APK_DIRNAME + "/classes.dex"); } catch(DirectoryException ex) {
if (flags.get("forceBuildAll") || isModified(working, stored)) {
LOGGER.info("Copying classes.dex file...");
BrutIO.copyAndClose(new FileInputStream(working),
new FileOutputStream(stored));
}
return true;
} catch (IOException ex) {
throw new AndrolibException(ex); throw new AndrolibException(ex);
} }
} }
public boolean buildSourcesSmali(File appDir, HashMap<String, Boolean> flags) public boolean buildSourcesRaw(File appDir, String filename, HashMap<String, Boolean> flags)
throws AndrolibException { throws AndrolibException {
ExtFile smaliDir = new ExtFile(appDir, "smali"); File working = new File(appDir, filename);
if (!working.exists()) {
return false;
}
File stored = new File(appDir, APK_DIRNAME + "/" + filename);
if (flags.get("forceBuildAll") || isModified(working, stored)) {
LOGGER.info("Copying " + appDir.toString() + " " + filename + " file...");
try {
BrutIO.copyAndClose(new FileInputStream(working), new FileOutputStream(stored));
return true;
} catch (IOException ex) {
throw new AndrolibException(ex);
}
}
return true;
}
public boolean buildSourcesSmali(File appDir, String folder, String filename, HashMap<String, Boolean> flags)
throws AndrolibException {
ExtFile smaliDir = new ExtFile(appDir, folder);
if (!smaliDir.exists()) { if (!smaliDir.exists()) {
return false; return false;
} }
File dex = new File(appDir, APK_DIRNAME + "/classes.dex"); File dex = new File(appDir, APK_DIRNAME + "/" + filename);
if (!flags.get("forceBuildAll")) { if (!flags.get("forceBuildAll")) {
LOGGER.info("Checking whether sources has changed..."); LOGGER.info("Checking whether sources has changed...");
} }
if (flags.get("forceBuildAll") || isModified(smaliDir, dex)) { if (flags.get("forceBuildAll") || isModified(smaliDir, dex)) {
LOGGER.info("Smaling..."); LOGGER.info("Smaling " + folder + " folder into " + filename +"...");
dex.delete(); dex.delete();
SmaliBuilder.build(smaliDir, dex, flags); SmaliBuilder.build(smaliDir, dex, flags);
} }
@ -385,8 +403,7 @@ public class Androlib {
public void buildResources(ExtFile appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework) public void buildResources(ExtFile appDir, HashMap<String, Boolean> flags, Map<String, Object> usesFramework)
throws BrutException { throws BrutException {
if (!buildResourcesRaw(appDir, flags) if (!buildResourcesRaw(appDir, flags) && !buildResourcesFull(appDir, flags, usesFramework)
&& !buildResourcesFull(appDir, flags, usesFramework)
&& !buildManifest(appDir, flags, usesFramework)) { && !buildManifest(appDir, flags, usesFramework)) {
LOGGER.warning("Could not find resources"); LOGGER.warning("Could not find resources");
} }
@ -727,8 +744,7 @@ public class Androlib {
private String mAaptPath = null; private String mAaptPath = null;
private Path mPath = null; private Path mPath = null;
private final static Logger LOGGER = Logger.getLogger(Androlib.class private final static Logger LOGGER = Logger.getLogger(Androlib.class.getName());
.getName());
private final static String SMALI_DIRNAME = "smali"; private final static String SMALI_DIRNAME = "smali";
private final static String APK_DIRNAME = "build/apk"; private final static String APK_DIRNAME = "build/apk";
@ -742,5 +758,5 @@ public class Androlib {
private final static String[] APK_MANIFEST_FILENAMES = new String[] { private final static String[] APK_MANIFEST_FILENAMES = new String[] {
"AndroidManifest.xml" }; "AndroidManifest.xml" };
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] { private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
"classes.dex", "AndroidManifest.xml", "resources.arsc","res","lib", "libs","assets","META-INF" }; "classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "lib", "libs", "assets", "META-INF" };
} }

View File

@ -36,13 +36,12 @@ import org.jf.dexlib2.writer.io.FileDataStore;
*/ */
public class SmaliBuilder { public class SmaliBuilder {
public static void build(ExtFile smaliDir, File dexFile, public static void build(ExtFile smaliDir, File dexFile, HashMap<String, Boolean> flags)
HashMap<String, Boolean> flags) throws AndrolibException { throws AndrolibException {
new SmaliBuilder(smaliDir, dexFile, flags).build(); new SmaliBuilder(smaliDir, dexFile, flags).build();
} }
private SmaliBuilder(ExtFile smaliDir, File dexFile, private SmaliBuilder(ExtFile smaliDir, File dexFile, HashMap<String, Boolean> flags) {
HashMap<String, Boolean> flags) {
mSmaliDir = smaliDir; mSmaliDir = smaliDir;
mDexFile = dexFile; mDexFile = dexFile;
mFlags = flags; mFlags = flags;
@ -61,8 +60,8 @@ public class SmaliBuilder {
} }
} }
private void buildFile(String fileName, DexBuilder dexBuilder) throws AndrolibException, private void buildFile(String fileName, DexBuilder dexBuilder)
IOException { throws AndrolibException, IOException {
File inFile = new File(mSmaliDir, fileName); File inFile = new File(mSmaliDir, fileName);
InputStream inStream = new FileInputStream(inFile); InputStream inStream = new FileInputStream(inFile);
@ -96,8 +95,7 @@ public class SmaliBuilder {
out.append(".source \"").append(inFile.getName()).append("\"\n"); out.append(".source \"").append(inFile.getName()).append("\"\n");
while (it.hasNext()) { while (it.hasNext()) {
String line = it.next().split("//", 2)[1].trim(); String line = it.next().split("//", 2)[1].trim();
if (line.isEmpty() || line.charAt(0) == '#' if (line.isEmpty() || line.charAt(0) == '#' || line.startsWith(".source")) {
|| line.startsWith(".source")) {
continue; continue;
} }
if (line.startsWith(".method ")) { if (line.startsWith(".method ")) {
@ -123,6 +121,5 @@ public class SmaliBuilder {
private final File mDexFile; private final File mDexFile;
private final HashMap<String, Boolean> mFlags; private final HashMap<String, Boolean> mFlags;
private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class.getName());
.getName());
} }

View File

@ -0,0 +1,15 @@
.class public LHelloDualDexSupport;
.super Ljava/lang/Object;
.method public static main([Ljava/lang/String;)V
.registers 2
sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
const/high16 v1, 0x7f020000
invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
return-void
.end method