From d2fdeb5a73f7a3563481eda3606bd9654fe522a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ryszard=20Wi=C5=9Bniewski?= Date: Wed, 2 Jun 2010 00:09:38 +0200 Subject: [PATCH] Reading framework files from hard disk. --- src/brut/androlib/Androlib.java | 1 - src/brut/androlib/ApkDecoder.java | 9 ++ .../err/CantFindFrameworkResException.java | 40 ++++++ src/brut/androlib/res/AndrolibResources.java | 129 ++++++++++++++---- src/brut/androlib/res/data/ResTable.java | 29 ++-- 5 files changed, 169 insertions(+), 39 deletions(-) create mode 100644 src/brut/androlib/err/CantFindFrameworkResException.java diff --git a/src/brut/androlib/Androlib.java b/src/brut/androlib/Androlib.java index 2ea7c220..8d4e616e 100644 --- a/src/brut/androlib/Androlib.java +++ b/src/brut/androlib/Androlib.java @@ -42,7 +42,6 @@ public class Androlib { private final AndrolibResources mAndRes = new AndrolibResources(); public ResTable getResTable(ExtFile apkFile) throws AndrolibException { - LOGGER.info("Decoding resource table..."); return mAndRes.getResTable(apkFile); } diff --git a/src/brut/androlib/ApkDecoder.java b/src/brut/androlib/ApkDecoder.java index 168b6bdc..c126e723 100644 --- a/src/brut/androlib/ApkDecoder.java +++ b/src/brut/androlib/ApkDecoder.java @@ -125,9 +125,17 @@ public class ApkDecoder { mForceDelete = forceDelete; } + public void setFrameworkTag(String tag) { + mFrameTag = tag; + if (mResTable != null) { + mResTable.setFrameTag(tag); + } + } + public ResTable getResTable() throws AndrolibException { if (mResTable == null) { mResTable = mAndrolib.getResTable(mApkFile); + mResTable.setFrameTag(mFrameTag); } return mResTable; } @@ -157,4 +165,5 @@ public class ApkDecoder { private short mDecodeResources = DECODE_RESOURCES_FULL; private boolean mDebug = false; private boolean mForceDelete = false; + private String mFrameTag; } diff --git a/src/brut/androlib/err/CantFindFrameworkResException.java b/src/brut/androlib/err/CantFindFrameworkResException.java new file mode 100644 index 00000000..fa705e2d --- /dev/null +++ b/src/brut/androlib/err/CantFindFrameworkResException.java @@ -0,0 +1,40 @@ +/* + * Copyright 2010 Ryszard Wiśniewski . + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * under the License. + */ +package brut.androlib.err; + +import brut.androlib.AndrolibException; + +/** + * @author Ryszard Wiśniewski + */ +public class CantFindFrameworkResException extends AndrolibException { + + public CantFindFrameworkResException(Throwable cause, int id) { + super(cause); + mPkgId = id; + } + + public CantFindFrameworkResException(int id) { + mPkgId = id; + } + + public int getPkgId() { + return mPkgId; + } + + private final int mPkgId; +} diff --git a/src/brut/androlib/res/AndrolibResources.java b/src/brut/androlib/res/AndrolibResources.java index b9a75c3f..ac16160d 100644 --- a/src/brut/androlib/res/AndrolibResources.java +++ b/src/brut/androlib/res/AndrolibResources.java @@ -18,6 +18,7 @@ package brut.androlib.res; import brut.androlib.AndrolibException; +import brut.androlib.err.CantFindFrameworkResException; import brut.androlib.res.data.*; import brut.androlib.res.data.value.ResXmlSerializable; import brut.androlib.res.decoder.*; @@ -27,8 +28,7 @@ import brut.common.BrutException; import brut.directory.*; import brut.util.*; import java.io.*; -import java.util.Arrays; -import java.util.Iterator; +import java.util.*; import java.util.logging.Logger; import org.apache.commons.io.IOUtils; import org.xmlpull.v1.XmlSerializer; @@ -38,17 +38,54 @@ import org.xmlpull.v1.XmlSerializer; */ final public class AndrolibResources { public ResTable getResTable(ExtFile apkFile) throws AndrolibException { - ResTable resTable = new ResTable(); - decodeArsc(resTable, apkFile, true); - if (! resTable.hasPackage(1)) { - decodeArsc(resTable, new ExtFile(getAndroidResourcesFile()), false); - } - if (! resTable.hasPackage(2)) { - decodeArsc(resTable, new ExtFile(getHtcResourcesFile()), false); - } + ResTable resTable = new ResTable(this); + loadMainPkg(resTable, apkFile); return resTable; } + public ResPackage loadMainPkg(ResTable resTable, ExtFile apkFile) + throws AndrolibException { + LOGGER.info("Loading resource table..."); + ResPackage[] pkgs = getResPackagesFromApk(apkFile, resTable); + ResPackage pkg = null; + + switch (pkgs.length) { + case 1: + pkg = pkgs[0]; + break; + case 2: + if (pkgs[0].getName().equals("android")) { + LOGGER.warning("Skipping \"android\" package group"); + pkg = pkgs[1]; + } + break; + } + + if (pkg == null) { + throw new AndrolibException( + "Arsc files with zero or multiple packages"); + } + + resTable.addPackage(pkg, true); + return pkg; + } + + public ResPackage loadFrameworkPkg(ResTable resTable, int id, + String frameTag) throws AndrolibException { + File apk = getFrameworkApk(id, frameTag); + + LOGGER.info("Loading resource table from file: " + apk); + ResPackage[] pkgs = getResPackagesFromApk(new ExtFile(apk), resTable); + + if (pkgs.length != 1) { + throw new AndrolibException( + "Arsc files with zero or multiple packages"); + } + + resTable.addPackage(pkgs[0], false); + return pkgs[0]; + } + public void decode(ResTable resTable, ExtFile apkFile, File outDir) throws AndrolibException { Duo duo = getResFileDecoder(); @@ -246,37 +283,69 @@ final public class AndrolibResources { } } - private void decodeArsc(ResTable resTable, ExtFile apkFile, boolean main) - throws AndrolibException { + private ResPackage[] getResPackagesFromApk(ExtFile apkFile, + ResTable resTable) throws AndrolibException { try { - loadArsc(resTable, apkFile.getDirectory() - .getFileInput("resources.arsc"), main); + return ARSCDecoder.decode( + apkFile.getDirectory().getFileInput("resources.arsc"), + resTable); } catch (DirectoryException ex) { throw new AndrolibException( "Could not load resources.arsc from file: " + apkFile, ex); } - } - private void loadArsc(ResTable resTable, InputStream arscStream, - boolean main) throws AndrolibException { - ResPackage[] groups = ARSCDecoder.decode(arscStream, resTable); - - if (groups.length == 0) { - throw new AndrolibException( - "Arsc file with zero package groups"); + private File getFrameworkApk(int id, String frameTag) + throws AndrolibException { + File dir = getFrameworkDir(); + + File apk = new File(dir, String.valueOf(id) + '-' + frameTag + ".apk"); + if (apk.exists()) { + return apk; } - if (groups.length > 1) { - LOGGER.warning("Arsc file with multiple package groups"); + + apk = new File(dir, String.valueOf(id) + ".apk"); + if (apk.exists()) { + return apk; } - for (int i = 0; i < groups.length; i++) { - if (groups.length != 1 && i == 0 - && "android".equals(groups[i].getName())) { - LOGGER.warning("Skipping \"android\" package group"); - continue; + + if (id == 1) { + InputStream in = null; + OutputStream out = null; + try { + in = AndrolibResources.class.getResourceAsStream( + "/brut/androlib/android-framework.jar"); + out = new FileOutputStream(apk); + IOUtils.copy(in, out); + return apk; + } catch (IOException ex) { + throw new AndrolibException(ex); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ex) {} + } + if (out != null) { + try { + out.close(); + } catch (IOException ex) {} + } } - resTable.addPackage(groups[i], main); } + + throw new CantFindFrameworkResException(id); + } + + private File getFrameworkDir() throws AndrolibException { + File dir = new File(System.getProperty("user.home") + + File.separatorChar + "apktool" + File.separatorChar + "framework"); + if (! dir.exists()) { + if (! dir.mkdirs()) { + throw new AndrolibException("Can't create directory: " + dir); + } + } + return dir; } private File getAndroidResourcesFile() throws AndrolibException { diff --git a/src/brut/androlib/res/data/ResTable.java b/src/brut/androlib/res/data/ResTable.java index 17b8641e..98b81866 100644 --- a/src/brut/androlib/res/data/ResTable.java +++ b/src/brut/androlib/res/data/ResTable.java @@ -19,16 +19,16 @@ package brut.androlib.res.data; import brut.androlib.AndrolibException; import brut.androlib.err.UndefinedResObject; +import brut.androlib.res.AndrolibResources; import brut.androlib.res.data.value.ResValue; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * @author Ryszard Wiśniewski */ public class ResTable { + private final AndrolibResources mAndRes; + private final Map mPackagesById = new HashMap(); private final Map mPackagesByName = @@ -36,7 +36,14 @@ public class ResTable { private final Set mMainPackages = new LinkedHashSet(); + private String mFrameTag; + public ResTable() { + mAndRes = null; + } + + public ResTable(AndrolibResources andRes) { + mAndRes = andRes; } public ResResSpec getResSpec(int resID) throws AndrolibException { @@ -53,11 +60,13 @@ public class ResTable { public ResPackage getPackage(int id) throws AndrolibException { ResPackage pkg = mPackagesById.get(id); - if (pkg == null) { - throw new UndefinedResObject(String.format( - "package: id=%d", id)); + if (pkg != null) { + return pkg; } - return pkg; + if (mAndRes != null) { + return mAndRes.loadFrameworkPkg(this, id, mFrameTag); + } + throw new UndefinedResObject(String.format("package: id=%d", id)); } public ResPackage getPackage(String name) throws AndrolibException { @@ -100,4 +109,8 @@ public class ResTable { mMainPackages.add(pkg); } } + + public void setFrameTag(String tag) { + mFrameTag = tag; + } }