diff --git a/src/main/java/com/reandroid/apk/ApkModule.java b/src/main/java/com/reandroid/apk/ApkModule.java index f24db3b..5181403 100644 --- a/src/main/java/com/reandroid/apk/ApkModule.java +++ b/src/main/java/com/reandroid/apk/ApkModule.java @@ -24,14 +24,13 @@ import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; import com.reandroid.arsc.chunk.xml.ResXmlDocument; import com.reandroid.arsc.container.SpecTypePair; +import com.reandroid.arsc.decoder.Decoder; import com.reandroid.arsc.group.StringGroup; import com.reandroid.arsc.item.TableString; import com.reandroid.arsc.pool.TableStringPool; import com.reandroid.arsc.util.FrameworkTable; import com.reandroid.arsc.value.Entry; import com.reandroid.arsc.value.ResConfig; -import com.reandroid.common.Frameworks; -import com.reandroid.common.TableEntryStore; import com.reandroid.xml.XMLDocument; import com.reandroid.xml.XMLElement; import com.reandroid.xml.XMLException; @@ -47,17 +46,25 @@ public class ApkModule implements ApkFile { private final String moduleName; private final APKArchive apkArchive; private boolean loadDefaultFramework = true; + private boolean mDisableLoadFramework = false; private TableBlock mTableBlock; private AndroidManifestBlock mManifestBlock; private final UncompressedFiles mUncompressedFiles; private APKLogger apkLogger; - private TableEntryStore mEntryStore; + private Decoder mDecoder; + private ApkType mApkType; public ApkModule(String moduleName, APKArchive apkArchive){ this.moduleName=moduleName; this.apkArchive=apkArchive; this.mUncompressedFiles=new UncompressedFiles(); this.mUncompressedFiles.addPath(apkArchive); } + public String getSplit(){ + if(!hasAndroidManifestBlock()){ + return null; + } + return getAndroidManifestBlock().getSplit(); + } public FrameworkApk initializeAndroidFramework() throws IOException { if(!hasTableBlock()){ return null; @@ -485,11 +492,15 @@ public class ApkModule implements ApkFile { archive.add(blockInputSource); manifestBlock.setApkFile(this); mManifestBlock = manifestBlock; + onManifestBlockLoaded(manifestBlock); } catch (IOException exception) { throw new IllegalArgumentException(exception); } return mManifestBlock; } + private void onManifestBlockLoaded(AndroidManifestBlock manifestBlock){ + initializeApkType(manifestBlock); + } public TableBlock getTableBlock(boolean initFramework) { if(mTableBlock==null){ if(!hasTableBlock()){ @@ -509,7 +520,7 @@ public class ApkModule implements ApkFile { } @Override public TableBlock getTableBlock() { - return getTableBlock(true); + return getTableBlock(!mDisableLoadFramework); } @Override public ResXmlDocument loadResXmlDocument(String path) throws IOException{ @@ -522,6 +533,38 @@ public class ApkModule implements ApkFile { resXmlDocument.readBytes(inputSource.openStream()); return resXmlDocument; } + @Override + public Decoder getDecoder(){ + return mDecoder; + } + @Override + public void setDecoder(Decoder decoder){ + this.mDecoder = decoder; + } + public ApkType getApkType(){ + if(mApkType!=null){ + return mApkType; + } + return initializeApkType(mManifestBlock); + } + public void setApkType(ApkType apkType){ + this.mApkType = apkType; + } + private ApkType initializeApkType(AndroidManifestBlock manifestBlock){ + if(mApkType!=null){ + return mApkType; + } + ApkType apkType = null; + if(manifestBlock!=null){ + apkType = manifestBlock.guessApkType(); + } + if(apkType != null){ + mApkType = apkType; + }else { + apkType = ApkType.UNKNOWN; + } + return apkType; + } // If we need TableStringPool only, this loads pool without // loading packages and other chunk blocks for faster and less memory usage @@ -574,6 +617,7 @@ public class ApkModule implements ApkFile { } public void setLoadDefaultFramework(boolean loadDefaultFramework) { this.loadDefaultFramework = loadDefaultFramework; + this.mDisableLoadFramework = !loadDefaultFramework; } public void merge(ApkModule module) throws IOException { diff --git a/src/main/java/com/reandroid/arsc/ApkFile.java b/src/main/java/com/reandroid/arsc/ApkFile.java index eacdbc9..afb664d 100644 --- a/src/main/java/com/reandroid/arsc/ApkFile.java +++ b/src/main/java/com/reandroid/arsc/ApkFile.java @@ -18,6 +18,7 @@ package com.reandroid.arsc; import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; import com.reandroid.arsc.chunk.xml.ResXmlDocument; +import com.reandroid.arsc.decoder.Decoder; import java.io.IOException; @@ -25,4 +26,13 @@ public interface ApkFile { AndroidManifestBlock getAndroidManifestBlock(); TableBlock getTableBlock(); ResXmlDocument loadResXmlDocument(String path) throws IOException; + Decoder getDecoder(); + void setDecoder(Decoder decoder); + + enum ApkType { + BASE, + SPLIT, + CORE, + UNKNOWN + } } diff --git a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java index 8e3daa4..e40f89d 100755 --- a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java @@ -227,6 +227,17 @@ import java.util.*; public List getFrameWorks(){ return mFrameWorks; } + public boolean isAndroid(){ + PackageBlock packageBlock = pickOne(); + if(packageBlock == null){ + return false; + } + return "android".equals(packageBlock.getName()) + && packageBlock.getId() == 0x01; + } + public boolean hasFramework(){ + return getFrameWorks().size() != 0; + } public void addFramework(TableBlock tableBlock){ if(tableBlock==null||tableBlock==this){ return; diff --git a/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java b/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java index 39c1e8f..e492ffe 100644 --- a/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/xml/AndroidManifestBlock.java @@ -15,6 +15,7 @@ */ package com.reandroid.arsc.chunk.xml; +import com.reandroid.arsc.ApkFile; import com.reandroid.arsc.value.ValueType; import java.io.File; @@ -30,6 +31,33 @@ public class AndroidManifestBlock extends ResXmlDocument { super(); super.getStringPool().setUtf8(false); } + public ApkFile.ApkType guessApkType(){ + if(isSplit()){ + return ApkFile.ApkType.SPLIT; + } + Boolean core = isCoreApp(); + if(core!=null && core){ + return ApkFile.ApkType.CORE; + } + if(getMainActivity()!=null){ + return ApkFile.ApkType.BASE; + } + return null; + } + public Boolean isCoreApp(){ + ResXmlElement manifest = getManifestElement(); + if(manifest == null){ + return null; + } + ResXmlAttribute attribute = manifest.searchAttributeByName(NAME_coreApp); + if(attribute == null){ + return null; + } + if(attribute.getValueType() != ValueType.INT_BOOLEAN){ + return null; + } + return attribute.getValueAsBoolean(); + } public boolean isSplit(){ ResXmlElement manifest = getManifestElement(); if(manifest == null){ diff --git a/src/main/java/com/reandroid/arsc/decoder/Decoder.java b/src/main/java/com/reandroid/arsc/decoder/Decoder.java index 15396a5..e11485e 100644 --- a/src/main/java/com/reandroid/arsc/decoder/Decoder.java +++ b/src/main/java/com/reandroid/arsc/decoder/Decoder.java @@ -35,6 +35,7 @@ import java.io.IOException; public class Decoder { private final EntryStore entryStore; private int currentPackageId; + private ApkFile mApkFile; public Decoder(EntryStore entryStore, int currentPackageId){ this.entryStore = entryStore; this.currentPackageId = currentPackageId; @@ -83,6 +84,15 @@ public class Decoder { public void setCurrentPackageId(int currentPackageId) { this.currentPackageId = currentPackageId; } + public ApkFile getApkFile(){ + return mApkFile; + } + public void setApkFile(ApkFile apkFile) { + this.mApkFile = apkFile; + } + public boolean isNullDecoder(){ + return false; + } public static Decoder create(ResXmlDocument resXmlDocument){ MainChunk mainChunk = resXmlDocument.getMainChunk(); @@ -107,7 +117,7 @@ public class Decoder { return create(tableBlock); } public static Decoder create(TableBlock tableBlock){ - if(tableBlock.getFrameWorks().size()==0){ + if(!tableBlock.hasFramework() && !tableBlock.isAndroid()){ tableBlock.addFramework(getFramework()); } int currentPackageId; @@ -121,7 +131,7 @@ public class Decoder { return create(tableBlock, currentPackageId); } public static Decoder create(TableBlock tableBlock, int currentPackageId){ - if(tableBlock.getFrameWorks().size()==0){ + if(!tableBlock.hasFramework() && !tableBlock.isAndroid()){ TableBlock framework = getFramework(); if(framework!=null){ PackageBlock packageBlock = framework.pickOne(); @@ -151,10 +161,19 @@ public class Decoder { return NULL_ENTRY_STORE_DECODER; } synchronized (Decoder.class){ - Decoder decoder = new Decoder(getFramework(), 0x7f); + NullEntryDecoder decoder = new NullEntryDecoder(getFramework(), 0x7f); NULL_ENTRY_STORE_DECODER = decoder; return decoder; } } - private static Decoder NULL_ENTRY_STORE_DECODER; + static class NullEntryDecoder extends Decoder{ + public NullEntryDecoder(EntryStore entryStore, int currentPackageId) { + super(entryStore, currentPackageId); + } + @Override + public boolean isNullDecoder(){ + return true; + } + } + private static NullEntryDecoder NULL_ENTRY_STORE_DECODER; }