From db35f54af6bec48dea867f52b00b7c8254c47a8e Mon Sep 17 00:00:00 2001 From: Benjamin Adolphi Date: Mon, 5 Sep 2016 11:52:58 +0200 Subject: [PATCH] Pass minimum api level to smali library When apktool creates a DexBuilder class, it creates it without specifying a minimum api level. This causes the DexBuilder class to assume api level 20 by default. This is not ideal since in some cases, the concrete minimum api level is required. One such case is in smali's DexWriter class which implements a workaround for a bug in Dalvik that was fixed in Android 4.2 (https://code.google.com/p/android/issues/detail?id=35304) that causes apps that call the Method.getParameterAnnotations api to crash in some cases (see bug report for more details). The workaround that smali implements is only triggered if the minimum api level is below 17 (Android 4.2). But since apktool effectively sets the minimum api level to 20, this code is never triggered causing apktool to create apk files that crash on devices below Android 4.2. This change passes the minimum api level to the smali library. --- .../src/main/java/brut/androlib/Androlib.java | 7 ++++++- .../java/brut/androlib/src/SmaliBuilder.java | 21 ++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java index d2f3ff39..b667b4d4 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/Androlib.java @@ -51,6 +51,7 @@ public class Androlib { private final AndrolibResources mAndRes = new AndrolibResources(); protected final ResUnknownFiles mResUnknownFiles = new ResUnknownFiles(); public ApkOptions apkOptions; + private int mMinSdkVersion = 0; public Androlib(ApkOptions apkOptions) { this.apkOptions = apkOptions; @@ -278,6 +279,10 @@ public class Androlib { mAndRes.setVersionInfo(meta.versionInfo); mAndRes.setSharedLibrary(meta.sharedLibrary); + if (meta.sdkInfo != null && meta.sdkInfo.get("minSdkVersion") != null) { + mMinSdkVersion = Integer.parseInt(meta.sdkInfo.get("minSdkVersion")); + } + if (outFile == null) { String outFileName = meta.apkFileName; outFile = new File(appDir, "dist" + File.separator + (outFileName == null ? "out.apk" : outFileName)); @@ -397,7 +402,7 @@ public class Androlib { if (apkOptions.forceBuildAll || isModified(smaliDir, dex)) { LOGGER.info("Smaling " + folder + " folder into " + filename +"..."); dex.delete(); - SmaliBuilder.build(smaliDir, dex); + SmaliBuilder.build(smaliDir, dex, mMinSdkVersion); } return true; } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java index 4befe544..75fb2e35 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/src/SmaliBuilder.java @@ -26,6 +26,7 @@ import java.util.logging.Logger; import org.antlr.runtime.RecognitionException; import org.apache.commons.io.IOUtils; +import org.jf.dexlib2.Opcodes; import org.jf.dexlib2.writer.builder.DexBuilder; import org.jf.dexlib2.writer.io.FileDataStore; @@ -33,19 +34,28 @@ import org.jf.dexlib2.writer.io.FileDataStore; * @author Ryszard Wiśniewski */ public class SmaliBuilder { - - public static void build(ExtFile smaliDir, File dexFile) throws AndrolibException { - new SmaliBuilder(smaliDir, dexFile).build(); + public static void build(ExtFile smaliDir, File dexFile, int apiLevel) throws AndrolibException { + new SmaliBuilder(smaliDir, dexFile, apiLevel).build(); } - private SmaliBuilder(ExtFile smaliDir, File dexFile) { + public static void build(ExtFile smaliDir, File dexFile) throws AndrolibException { + new SmaliBuilder(smaliDir, dexFile, 0).build(); + } + + private SmaliBuilder(ExtFile smaliDir, File dexFile, int apiLevel) { mSmaliDir = smaliDir; mDexFile = dexFile; + mApiLevel = apiLevel; } private void build() throws AndrolibException { try { - DexBuilder dexBuilder = DexBuilder.makeDexBuilder(); + DexBuilder dexBuilder; + if (mApiLevel > 0) { + dexBuilder = DexBuilder.makeDexBuilder(Opcodes.forApi(mApiLevel)); + } else { + dexBuilder = DexBuilder.makeDexBuilder(); + } for (String fileName : mSmaliDir.getDirectory().getFiles(true)) { buildFile(fileName, dexBuilder); @@ -77,6 +87,7 @@ public class SmaliBuilder { private final ExtFile mSmaliDir; private final File mDexFile; + private int mApiLevel = 0; private final static Logger LOGGER = Logger.getLogger(SmaliBuilder.class.getName()); }