From 0a74de4ab025c196e5747c9e4e38cfc24710401c Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Sun, 8 Mar 2015 14:31:21 -0500 Subject: [PATCH 1/3] Shared Library Rebuilding Support - handles references with shared resources - adds support for --shared-lib - update unit-tests --- .../src/main/java/brut/androlib/Androlib.java | 1 + .../src/main/java/brut/androlib/ApkDecoder.java | 5 +++++ .../brut/androlib/res/AndrolibResources.java | 11 ++++++++++- .../main/java/brut/androlib/res/data/ResID.java | 2 +- .../java/brut/androlib/res/data/ResTable.java | 16 ++++++++++++++++ .../brut/androlib/res/decoder/ARSCDecoder.java | 1 + .../resources/brut/apktool/testapp/apktool.yml | 1 + .../resources/brut/apktool/testjar/apktool.yml | 1 + 8 files changed, 36 insertions(+), 2 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 8899d904..9b77bed1 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 @@ -270,6 +270,7 @@ public class Androlib { mAndRes.setPackageId((Map) meta.get("packageInfo")); mAndRes.setPackageInfo((Map) meta.get("packageInfo")); mAndRes.setVersionInfo((Map) meta.get("versionInfo")); + mAndRes.setSharedLibrary((boolean) meta.get("sharedLibrary")); if (outFile == null) { String outFileName = (String) meta.get("apkFileName"); diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java index 474aafec..4efabc9e 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java @@ -320,6 +320,7 @@ public class ApkDecoder { putPackageInfo(meta); putVersionInfo(meta); putCompressionInfo(meta); + putSharedLibraryInfo(meta); } putUnknownInfo(meta); @@ -393,6 +394,10 @@ public class ApkDecoder { meta.put("compressionType", getCompressionType()); } + private void putSharedLibraryInfo(Map meta) throws AndrolibException { + meta.put("sharedLibrary", mResTable.getSharedLibrary()); + } + private boolean getCompressionType() { return mCompressResources; } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java index 1f68d172..a034d5fb 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/AndrolibResources.java @@ -379,6 +379,10 @@ final public class AndrolibResources { } } + public void setSharedLibrary(boolean flag) { + mSharedLibrary = flag; + } + public void aaptPackage(File apkFile, File manifest, File resDir, File rawDir, File assetDir, File[] include) throws AndrolibException { @@ -428,10 +432,13 @@ final public class AndrolibResources { // force package id so that some frameworks build with correct id // disable if user adds own aapt (can't know if they have this feature) - if (mPackageId != null && ! customAapt) { + if (mPackageId != null && ! customAapt && ! mSharedLibrary) { cmd.add("--forced-package-id"); cmd.add(mPackageId); } + if (mSharedLibrary) { + cmd.add("--shared-lib"); + } if (mMinSdkVersion != null) { cmd.add("--min-sdk-version"); cmd.add(mMinSdkVersion); @@ -847,6 +854,8 @@ final public class AndrolibResources { private String mPackageOriginal = null; private String mPackageId = null; + private boolean mSharedLibrary = false; + private File mAaptBinary = null; private final static String[] IGNORED_PACKAGES = new String[] { diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResID.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResID.java index 21372fb0..593d28b9 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResID.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResID.java @@ -35,7 +35,7 @@ public class ResID { } public ResID(int package_, int type, int entry, int id) { - this.package_ = package_; + this.package_ = (package_ == 0) ? 2 : package_; this.type = type; this.entry = entry; this.id = id; diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java index 411a2672..15bdb0ca 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/data/ResTable.java @@ -37,6 +37,7 @@ public class ResTable { private String mPackageOriginal; private int mPackageId; private boolean mAnalysisMode = false; + private boolean mSharedLibrary = false; private Map mSdkInfo = new LinkedHashMap(); private Map mVersionInfo = new LinkedHashMap(); @@ -50,6 +51,13 @@ public class ResTable { } public ResResSpec getResSpec(int resID) throws AndrolibException { + // The pkgId is 0x00. That means a shared library is using its + // own resource, so lie to the caller replacing with its own + // packageId + if (resID >> 24 == 0) { + int pkgId = (mPackageId == 0 ? 2 : mPackageId); + resID = (0xFF000000 & (pkgId << 24)) | resID; + } return getResSpec(new ResID(resID)); } @@ -158,6 +166,10 @@ public class ResTable { mPackageId = id; } + public void setSharedLibrary(boolean flag) { + mSharedLibrary = flag; + } + public void clearSdkInfo() { mSdkInfo.clear(); } @@ -193,4 +205,8 @@ public class ResTable { public int getPackageId() { return mPackageId; } + + public boolean getSharedLibrary() { + return mSharedLibrary; + } } diff --git a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java index 57caf4ad..d1af5654 100644 --- a/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java +++ b/brut.apktool/apktool-lib/src/main/java/brut/androlib/res/decoder/ARSCDecoder.java @@ -90,6 +90,7 @@ public class ARSCDecoder { // for Apktool's use we need a non-zero packageId. // AOSP indicates 0x02 is next, as 0x01 is system and 0x7F is private. id = 2; + mResTable.setSharedLibrary(true); } String name = mIn.readNullEndedString(128, true); diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml index 51536bc9..967ade59 100644 --- a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml @@ -10,6 +10,7 @@ versionInfo: versionCode: '1' versionName: '1.0' compressionType: false +sharedLibrary: false unknownFiles: hidden.file: '8' unk_folder/unknown_file: '8' diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml index 92bc2cf6..f2ad0b25 100644 --- a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml @@ -1,2 +1,3 @@ version: 2.0.0 apkFileName: testjar.jar +sharedLibrary: false From fac43a62b83ddf0282c02a584783624673068c59 Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Sat, 14 Mar 2015 08:20:00 -0500 Subject: [PATCH 2/3] remove dependency on sharedLibrary in apktool.yml --- .../apktool-lib/src/main/java/brut/androlib/Androlib.java | 2 +- .../src/test/resources/brut/apktool/testapp/apktool.yml | 1 - .../src/test/resources/brut/apktool/testjar/apktool.yml | 3 +-- 3 files changed, 2 insertions(+), 4 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 9b77bed1..d380e093 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 @@ -270,7 +270,7 @@ public class Androlib { mAndRes.setPackageId((Map) meta.get("packageInfo")); mAndRes.setPackageInfo((Map) meta.get("packageInfo")); mAndRes.setVersionInfo((Map) meta.get("versionInfo")); - mAndRes.setSharedLibrary((boolean) meta.get("sharedLibrary")); + mAndRes.setSharedLibrary((boolean) (meta.get("sharedLibrary") == null ? false : meta.get("sharedLibrary"))); if (outFile == null) { String outFileName = (String) meta.get("apkFileName"); diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml index 967ade59..51536bc9 100644 --- a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testapp/apktool.yml @@ -10,7 +10,6 @@ versionInfo: versionCode: '1' versionName: '1.0' compressionType: false -sharedLibrary: false unknownFiles: hidden.file: '8' unk_folder/unknown_file: '8' diff --git a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml index f2ad0b25..f0d049ba 100644 --- a/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml +++ b/brut.apktool/apktool-lib/src/test/resources/brut/apktool/testjar/apktool.yml @@ -1,3 +1,2 @@ version: 2.0.0 -apkFileName: testjar.jar -sharedLibrary: false +apkFileName: testjar.jar \ No newline at end of file From 39fea5fa2cd6b8410953675a21babbda9b2bead5 Mon Sep 17 00:00:00 2001 From: Connor Tumbleson Date: Sat, 14 Mar 2015 08:20:18 -0500 Subject: [PATCH 3/3] [tests] add test for shared library rebuild --- .../java/brut/androlib/SharedLibraryTest.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/brut.apktool/apktool-lib/src/test/java/brut/androlib/SharedLibraryTest.java b/brut.apktool/apktool-lib/src/test/java/brut/androlib/SharedLibraryTest.java index 7e30486d..2006a2d3 100644 --- a/brut.apktool/apktool-lib/src/test/java/brut/androlib/SharedLibraryTest.java +++ b/brut.apktool/apktool-lib/src/test/java/brut/androlib/SharedLibraryTest.java @@ -70,29 +70,42 @@ public class SharedLibraryTest { } @Test - public void isSharedResourceDecodingWorking() throws IOException, BrutException { - String framework = "library.apk"; + public void isSharedResourceDecodingAndRebuildingWorking() throws IOException, BrutException { + String library = "library.apk"; String client = "client.apk"; - + // setup apkOptions ApkOptions apkOptions = new ApkOptions(); apkOptions.frameworkFolderLocation = sTmpDir.getAbsolutePath(); apkOptions.frameworkTag = "shared"; - new Androlib(apkOptions).installFramework(new File(sTmpDir + File.separator + framework)); - + // install library/framework + new Androlib(apkOptions).installFramework(new File(sTmpDir + File.separator + library)); assertTrue(fileExists("2-shared.apk")); + // decode client.apk ApkDecoder apkDecoder = new ApkDecoder(new File(sTmpDir + File.separator + client)); apkDecoder.setOutDir(new File(sTmpDir + File.separator + client + ".out")); apkDecoder.setFrameworkDir(apkOptions.frameworkFolderLocation); apkDecoder.setFrameworkTag(apkOptions.frameworkTag); apkDecoder.decode(); - ExtFile testApk = new ExtFile(sTmpDir, client + ".out"); - new Androlib(apkOptions).build(testApk, null); + // decode library.apk + ApkDecoder libraryDecoder = new ApkDecoder(new File(sTmpDir + File.separator + library)); + libraryDecoder.setOutDir(new File(sTmpDir + File.separator + library + ".out")); + libraryDecoder.setFrameworkDir(apkOptions.frameworkFolderLocation); + libraryDecoder.setFrameworkTag(apkOptions.frameworkTag); + libraryDecoder.decode(); + // build client.apk + ExtFile clientApk = new ExtFile(sTmpDir, client + ".out"); + new Androlib(apkOptions).build(clientApk, null); assertTrue(fileExists(client + ".out" + File.separator + "dist" + File.separator + client)); + + // build library.apk (shared library) + ExtFile libraryApk = new ExtFile(sTmpDir, library + ".out"); + new Androlib(apkOptions).build(libraryApk, null); + assertTrue(fileExists(library + ".out" + File.separator + "dist" + File.separator + library)); } private boolean fileExists(String filepath) {