Reading framework files from hard disk.

This commit is contained in:
Ryszard Wiśniewski 2010-06-02 00:09:38 +02:00
parent 43797e0c0d
commit d2fdeb5a73
5 changed files with 169 additions and 39 deletions

View File

@ -42,7 +42,6 @@ public class Androlib {
private final AndrolibResources mAndRes = new AndrolibResources(); private final AndrolibResources mAndRes = new AndrolibResources();
public ResTable getResTable(ExtFile apkFile) throws AndrolibException { public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
LOGGER.info("Decoding resource table...");
return mAndRes.getResTable(apkFile); return mAndRes.getResTable(apkFile);
} }

View File

@ -125,9 +125,17 @@ public class ApkDecoder {
mForceDelete = forceDelete; mForceDelete = forceDelete;
} }
public void setFrameworkTag(String tag) {
mFrameTag = tag;
if (mResTable != null) {
mResTable.setFrameTag(tag);
}
}
public ResTable getResTable() throws AndrolibException { public ResTable getResTable() throws AndrolibException {
if (mResTable == null) { if (mResTable == null) {
mResTable = mAndrolib.getResTable(mApkFile); mResTable = mAndrolib.getResTable(mApkFile);
mResTable.setFrameTag(mFrameTag);
} }
return mResTable; return mResTable;
} }
@ -157,4 +165,5 @@ public class ApkDecoder {
private short mDecodeResources = DECODE_RESOURCES_FULL; private short mDecodeResources = DECODE_RESOURCES_FULL;
private boolean mDebug = false; private boolean mDebug = false;
private boolean mForceDelete = false; private boolean mForceDelete = false;
private String mFrameTag;
} }

View File

@ -0,0 +1,40 @@
/*
* Copyright 2010 Ryszard Wiśniewski <brut.alll@gmail.com>.
*
* 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 <brut.alll@gmail.com>
*/
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;
}

View File

@ -18,6 +18,7 @@
package brut.androlib.res; package brut.androlib.res;
import brut.androlib.AndrolibException; import brut.androlib.AndrolibException;
import brut.androlib.err.CantFindFrameworkResException;
import brut.androlib.res.data.*; import brut.androlib.res.data.*;
import brut.androlib.res.data.value.ResXmlSerializable; import brut.androlib.res.data.value.ResXmlSerializable;
import brut.androlib.res.decoder.*; import brut.androlib.res.decoder.*;
@ -27,8 +28,7 @@ import brut.common.BrutException;
import brut.directory.*; import brut.directory.*;
import brut.util.*; import brut.util.*;
import java.io.*; import java.io.*;
import java.util.Arrays; import java.util.*;
import java.util.Iterator;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.xmlpull.v1.XmlSerializer; import org.xmlpull.v1.XmlSerializer;
@ -38,17 +38,54 @@ import org.xmlpull.v1.XmlSerializer;
*/ */
final public class AndrolibResources { final public class AndrolibResources {
public ResTable getResTable(ExtFile apkFile) throws AndrolibException { public ResTable getResTable(ExtFile apkFile) throws AndrolibException {
ResTable resTable = new ResTable(); ResTable resTable = new ResTable(this);
decodeArsc(resTable, apkFile, true); loadMainPkg(resTable, apkFile);
if (! resTable.hasPackage(1)) {
decodeArsc(resTable, new ExtFile(getAndroidResourcesFile()), false);
}
if (! resTable.hasPackage(2)) {
decodeArsc(resTable, new ExtFile(getHtcResourcesFile()), false);
}
return resTable; 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) public void decode(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException { throws AndrolibException {
Duo<ResFileDecoder, ResAttrDecoder> duo = getResFileDecoder(); Duo<ResFileDecoder, ResAttrDecoder> duo = getResFileDecoder();
@ -246,37 +283,69 @@ final public class AndrolibResources {
} }
} }
private void decodeArsc(ResTable resTable, ExtFile apkFile, boolean main) private ResPackage[] getResPackagesFromApk(ExtFile apkFile,
throws AndrolibException { ResTable resTable) throws AndrolibException {
try { try {
loadArsc(resTable, apkFile.getDirectory() return ARSCDecoder.decode(
.getFileInput("resources.arsc"), main); apkFile.getDirectory().getFileInput("resources.arsc"),
resTable);
} catch (DirectoryException ex) { } catch (DirectoryException ex) {
throw new AndrolibException( throw new AndrolibException(
"Could not load resources.arsc from file: " + apkFile, ex); "Could not load resources.arsc from file: " + apkFile, ex);
} }
} }
private void loadArsc(ResTable resTable, InputStream arscStream, private File getFrameworkApk(int id, String frameTag)
boolean main) throws AndrolibException { throws AndrolibException {
ResPackage[] groups = ARSCDecoder.decode(arscStream, resTable); File dir = getFrameworkDir();
if (groups.length == 0) { File apk = new File(dir, String.valueOf(id) + '-' + frameTag + ".apk");
throw new AndrolibException( if (apk.exists()) {
"Arsc file with zero package groups"); 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 if (id == 1) {
&& "android".equals(groups[i].getName())) { InputStream in = null;
LOGGER.warning("Skipping \"android\" package group"); OutputStream out = null;
continue; 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 { private File getAndroidResourcesFile() throws AndrolibException {

View File

@ -19,16 +19,16 @@ package brut.androlib.res.data;
import brut.androlib.AndrolibException; import brut.androlib.AndrolibException;
import brut.androlib.err.UndefinedResObject; import brut.androlib.err.UndefinedResObject;
import brut.androlib.res.AndrolibResources;
import brut.androlib.res.data.value.ResValue; import brut.androlib.res.data.value.ResValue;
import java.util.HashMap; import java.util.*;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/** /**
* @author Ryszard Wiśniewski <brut.alll@gmail.com> * @author Ryszard Wiśniewski <brut.alll@gmail.com>
*/ */
public class ResTable { public class ResTable {
private final AndrolibResources mAndRes;
private final Map<Integer, ResPackage> mPackagesById = private final Map<Integer, ResPackage> mPackagesById =
new HashMap<Integer, ResPackage>(); new HashMap<Integer, ResPackage>();
private final Map<String, ResPackage> mPackagesByName = private final Map<String, ResPackage> mPackagesByName =
@ -36,7 +36,14 @@ public class ResTable {
private final Set<ResPackage> mMainPackages = private final Set<ResPackage> mMainPackages =
new LinkedHashSet<ResPackage>(); new LinkedHashSet<ResPackage>();
private String mFrameTag;
public ResTable() { public ResTable() {
mAndRes = null;
}
public ResTable(AndrolibResources andRes) {
mAndRes = andRes;
} }
public ResResSpec getResSpec(int resID) throws AndrolibException { public ResResSpec getResSpec(int resID) throws AndrolibException {
@ -53,11 +60,13 @@ public class ResTable {
public ResPackage getPackage(int id) throws AndrolibException { public ResPackage getPackage(int id) throws AndrolibException {
ResPackage pkg = mPackagesById.get(id); ResPackage pkg = mPackagesById.get(id);
if (pkg == null) { if (pkg != null) {
throw new UndefinedResObject(String.format( return pkg;
"package: id=%d", id));
} }
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 { public ResPackage getPackage(String name) throws AndrolibException {
@ -100,4 +109,8 @@ public class ResTable {
mMainPackages.add(pkg); mMainPackages.add(pkg);
} }
} }
public void setFrameTag(String tag) {
mFrameTag = tag;
}
} }