From d3ef84c59f4dbbbe6068461372f4215391166e38 Mon Sep 17 00:00:00 2001 From: REAndroid Date: Mon, 13 Mar 2023 14:33:10 -0400 Subject: [PATCH] implement new AndroidFrameworks --- build.gradle | 1 - .../java/com/reandroid/apk/ApkModule.java | 99 ++++++++++++++----- .../reandroid/apk/ApkModuleXmlDecoder.java | 14 +-- .../apk/xmlencoder/EncodeMaterials.java | 19 +++- .../reandroid/apk/xmlencoder/RESEncoder.java | 12 ++- .../apk/xmlencoder/XMLValuesEncoderId.java | 3 +- .../com/reandroid/arsc/chunk/TableBlock.java | 4 +- .../java/com/reandroid/common/Frameworks.java | 14 +-- 8 files changed, 111 insertions(+), 55 deletions(-) diff --git a/build.gradle b/build.gradle index 92900b1..c1ed247 100755 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,6 @@ javadoc { jar { exclude('com/reandroid/test/**') - exclude('com/reandroid/facebook/**') } task fatJar(type: Jar) { diff --git a/src/main/java/com/reandroid/apk/ApkModule.java b/src/main/java/com/reandroid/apk/ApkModule.java index 9ce1aee..9111749 100644 --- a/src/main/java/com/reandroid/apk/ApkModule.java +++ b/src/main/java/com/reandroid/apk/ApkModule.java @@ -33,6 +33,7 @@ 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; import java.io.File; @@ -57,27 +58,31 @@ public class ApkModule implements ApkFile { this.mUncompressedFiles=new UncompressedFiles(); this.mUncompressedFiles.addPath(apkArchive); } - public void initializeAndroidFramework() throws IOException { + public FrameworkApk initializeAndroidFramework() throws IOException { if(!hasTableBlock()){ - return; + return null; } - initializeAndroidFramework(getTableBlock()); + Integer version = getAndroidFrameworkVersion(); + return initializeAndroidFramework(getTableBlock(false), version); } - private void initializeAndroidFramework(TableBlock tableBlock) throws IOException { + private FrameworkApk initializeAndroidFramework(TableBlock tableBlock, Integer version) throws IOException { if(tableBlock == null || isAndroid(tableBlock)){ - return; + return null; } List frameWorkList = tableBlock.getFrameWorks(); for(TableBlock frameWork:frameWorkList){ if(isAndroid(frameWork)){ - return; + ApkFile apkFile = frameWork.getApkFile(); + if(apkFile instanceof FrameworkApk){ + return (FrameworkApk) apkFile; + } + return null; } } logMessage("Initializing android framework ..."); - Integer version = getAndroidFrameworkVersion(); FrameworkApk frameworkApk; if(version==null){ - logMessage("Can not read framework version from manifest, loading latest"); + logMessage("Can not read framework version, loading latest"); frameworkApk = AndroidFrameworks.getLatest(); }else { logMessage("Loading android framework for version: " + version); @@ -86,6 +91,7 @@ public class ApkModule implements ApkFile { FrameworkTable frameworkTable = frameworkApk.getTableBlock(); tableBlock.addFramework(frameworkTable); logMessage("Initialized framework: "+frameworkApk.getName()); + return frameworkApk; } private boolean isAndroid(TableBlock tableBlock){ if(tableBlock instanceof FrameworkTable){ @@ -94,6 +100,60 @@ public class ApkModule implements ApkFile { } return false; } + + public FrameworkApk initializeAndroidFramework(XMLDocument xmlDocument) throws IOException { + TableBlock tableBlock = getTableBlock(false); + if(isAndroidCoreApp(xmlDocument)){ + logMessage("Looks framework itself, skip loading frameworks"); + return null; + } + Integer version = readCompileVersionCode(xmlDocument); + return initializeAndroidFramework(tableBlock, version); + } + private boolean isAndroidCoreApp(XMLDocument manifestDocument){ + XMLElement root = manifestDocument.getDocumentElement(); + if(root == null){ + return false; + } + if(!"android".equals(root.getAttributeValue("package"))){ + return false; + } + String coreApp = root.getAttributeValue("coreApp"); + return "true".equals(coreApp); + } + private Integer readCompileVersionCode(XMLDocument manifestDocument) { + XMLElement root = manifestDocument.getDocumentElement(); + String versionString = readVersionCodeString(root); + if(versionString==null){ + return null; + } + try{ + return Integer.parseInt(versionString); + }catch (NumberFormatException exception){ + logMessage("NumberFormatException on manifest version reading: '" + +versionString+"': "+exception.getMessage()); + return null; + } + } + private String readVersionCodeString(XMLElement manifestRoot){ + String versionString = manifestRoot.getAttributeValue("android:compileSdkVersion"); + if(versionString!=null){ + return versionString; + } + versionString = manifestRoot.getAttributeValue("platformBuildVersionCode"); + if(versionString!=null){ + return versionString; + } + for(XMLElement element:manifestRoot.listChildElements()){ + if(AndroidManifestBlock.TAG_uses_sdk.equals(element.getTagName())){ + versionString = element.getAttributeValue("android:targetSdkVersion"); + if(versionString!=null){ + return versionString; + } + } + } + return null; + } public Integer getAndroidFrameworkVersion(){ if(!hasAndroidManifestBlock()){ return null; @@ -148,16 +208,7 @@ public class ApkModule implements ApkFile { ResXmlDocument resXmlDocument = loadResXmlDocument(path); AndroidManifestBlock manifestBlock = getAndroidManifestBlock(); int pkgId = manifestBlock.guessCurrentPackageId(); - return resXmlDocument.decodeToXml(getTableEntryStore(), pkgId); - } - private TableEntryStore getTableEntryStore() throws IOException { - if(mEntryStore!=null){ - return mEntryStore; - } - mEntryStore = new TableEntryStore(); - mEntryStore.add(getTableBlock()); - mEntryStore.add(Frameworks.getAndroid()); - return mEntryStore; + return resXmlDocument.decodeToXml(getTableBlock(), pkgId); } public List listDexFiles(){ List results=new ArrayList<>(); @@ -436,16 +487,16 @@ public class ApkModule implements ApkFile { } return mManifestBlock; } - @Override - public TableBlock getTableBlock() { + public TableBlock getTableBlock(boolean initFramework) { if(mTableBlock==null){ if(!hasTableBlock()){ return null; } try { mTableBlock = loadTableBlock(); - if(loadDefaultFramework){ - initializeAndroidFramework(mTableBlock); + if(initFramework && loadDefaultFramework){ + Integer version = getAndroidFrameworkVersion(); + initializeAndroidFramework(mTableBlock, version); } } catch (IOException exception) { throw new IllegalArgumentException(exception); @@ -454,6 +505,10 @@ public class ApkModule implements ApkFile { return mTableBlock; } @Override + public TableBlock getTableBlock() { + return getTableBlock(true); + } + @Override public ResXmlDocument loadResXmlDocument(String path) throws IOException{ InputSource inputSource = getApkArchive().getInputSource(path); if(inputSource==null){ diff --git a/src/main/java/com/reandroid/apk/ApkModuleXmlDecoder.java b/src/main/java/com/reandroid/apk/ApkModuleXmlDecoder.java index f09c412..b25c59f 100644 --- a/src/main/java/com/reandroid/apk/ApkModuleXmlDecoder.java +++ b/src/main/java/com/reandroid/apk/ApkModuleXmlDecoder.java @@ -27,8 +27,6 @@ import com.reandroid.arsc.container.SpecTypePair; import com.reandroid.arsc.decoder.ValueDecoder; import com.reandroid.arsc.value.*; import com.reandroid.common.EntryStore; -import com.reandroid.common.Frameworks; -import com.reandroid.common.TableEntryStore; import com.reandroid.json.JSONObject; import com.reandroid.xml.XMLAttribute; import com.reandroid.xml.XMLDocument; @@ -55,27 +53,25 @@ import java.util.*; this.decodedEntries.clear(); logMessage("Decoding ..."); decodeUncompressedFiles(outDir); - TableEntryStore entryStore=new TableEntryStore(); - entryStore.add(Frameworks.getAndroid()); + apkModule.initializeAndroidFramework(); TableBlock tableBlock=apkModule.getTableBlock(); - entryStore.add(tableBlock); decodePackageInfo(outDir, tableBlock); - xmlBagDecoder=new XMLBagDecoder(entryStore); + xmlBagDecoder=new XMLBagDecoder(tableBlock); decodePublicXml(tableBlock, outDir); - decodeAndroidManifest(entryStore, outDir); + decodeAndroidManifest(tableBlock, outDir); addDecodedPath(TableBlock.FILE_NAME); logMessage("Decoding resource files ..."); List resFileList=apkModule.listResFiles(); for(ResFile resFile:resFileList){ - decodeResFile(entryStore, outDir, resFile); + decodeResFile(tableBlock, outDir, resFile); } - decodeValues(entryStore, outDir, tableBlock); + decodeValues(tableBlock, outDir, tableBlock); extractRootFiles(outDir); } diff --git a/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java b/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java index ade89c8..6677b10 100644 --- a/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java +++ b/src/main/java/com/reandroid/apk/xmlencoder/EncodeMaterials.java @@ -16,6 +16,7 @@ package com.reandroid.apk.xmlencoder; import com.reandroid.apk.APKLogger; + import com.reandroid.apk.FrameworkApk; import com.reandroid.apk.ResourceIds; import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.chunk.TableBlock; @@ -282,6 +283,12 @@ this.currentPackage = currentPackage; return this; } + public EncodeMaterials addFramework(FrameworkApk frameworkApk) { + if(frameworkApk!=null){ + addFramework(frameworkApk.getTableBlock()); + } + return this; + } public EncodeMaterials addFramework(FrameworkTable frameworkTable) { frameworkTable.loadResourceNameMap(); this.frameworkTables.add(frameworkTable); @@ -333,10 +340,16 @@ ResourceIds resourceIds = new ResourceIds(); resourceIds.loadPackageBlock(packageBlock); ResourceIds.Table.Package packageId = resourceIds.getTable().listPackages().get(0); - return new EncodeMaterials() + EncodeMaterials encodeMaterials = new EncodeMaterials() .addPackageIds(packageId) - .setCurrentPackage(packageBlock) - .addFramework(Frameworks.getAndroid()); + .setCurrentPackage(packageBlock); + TableBlock tableBlock = packageBlock.getTableBlock(); + for(TableBlock frameworkTable:tableBlock.getFrameWorks()){ + if(frameworkTable instanceof FrameworkTable){ + encodeMaterials.addFramework((FrameworkTable) frameworkTable); + } + } + return encodeMaterials; } } diff --git a/src/main/java/com/reandroid/apk/xmlencoder/RESEncoder.java b/src/main/java/com/reandroid/apk/xmlencoder/RESEncoder.java index 9a9ee0f..3b8c69b 100644 --- a/src/main/java/com/reandroid/apk/xmlencoder/RESEncoder.java +++ b/src/main/java/com/reandroid/apk/xmlencoder/RESEncoder.java @@ -20,7 +20,6 @@ import com.reandroid.arsc.chunk.PackageBlock; import com.reandroid.arsc.chunk.TableBlock; import com.reandroid.arsc.chunk.xml.AndroidManifestBlock; - import com.reandroid.common.Frameworks; import com.reandroid.xml.XMLDocument; import com.reandroid.xml.XMLException; import com.reandroid.xml.source.XMLFileSource; @@ -162,12 +161,18 @@ List pubXmlFileList, EncodeMaterials encodeMaterials) throws IOException, XMLException { + encodeMaterials.setAPKLogger(apkLogger); + Map results = new HashMap<>(); String packageName=null; for(File pubXmlFile:pubXmlFileList){ if(packageName==null){ - packageName=readManifestPackageName(toAndroidManifest(pubXmlFile)); + File manifestFile = toAndroidManifest(pubXmlFile); + packageName=readManifestPackageName(manifestFile); + FrameworkApk frameworkApk = getApkModule() + .initializeAndroidFramework(XMLDocument.load(manifestFile)); + encodeMaterials.addFramework(frameworkApk); } ResourceIds resourceIds=new ResourceIds(); resourceIds.fromXml(pubXmlFile); @@ -184,8 +189,7 @@ results.put(pubXmlFile, pkg); } - encodeMaterials.addFramework(Frameworks.getAndroid()) - .setAPKLogger(apkLogger); + encodeMaterials.setAPKLogger(apkLogger); return results; } private String readManifestPackageName(File manifestFile) throws XMLException { diff --git a/src/main/java/com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java b/src/main/java/com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java index e894f6a..9c257d3 100644 --- a/src/main/java/com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java +++ b/src/main/java/com/reandroid/apk/xmlencoder/XMLValuesEncoderId.java @@ -15,6 +15,7 @@ */ package com.reandroid.apk.xmlencoder; +import com.reandroid.arsc.decoder.ValueDecoder; import com.reandroid.arsc.value.ValueHeader; import com.reandroid.arsc.value.Entry; @@ -25,7 +26,7 @@ import com.reandroid.arsc.value.Entry; @Override void encodeStringValue(Entry entry, String value){ - throw new EncodeException("Unexpected value for id: "+value); + entry.setValueAsString(ValueDecoder.unEscapeSpecialCharacter(value)); } @Override void encodeNullValue(Entry entry){ diff --git a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java index d08dda3..2288349 100755 --- a/src/main/java/com/reandroid/arsc/chunk/TableBlock.java +++ b/src/main/java/com/reandroid/arsc/chunk/TableBlock.java @@ -281,9 +281,7 @@ import java.util.*; @Deprecated public static TableBlock loadWithAndroidFramework(InputStream inputStream) throws IOException{ - TableBlock tableBlock=load(inputStream); - tableBlock.addFramework(Frameworks.getAndroid()); - return tableBlock; + return load(inputStream); } public static TableBlock load(File file) throws IOException{ return load(new FileInputStream(file)); diff --git a/src/main/java/com/reandroid/common/Frameworks.java b/src/main/java/com/reandroid/common/Frameworks.java index ea8c5f9..f3fd9c2 100755 --- a/src/main/java/com/reandroid/common/Frameworks.java +++ b/src/main/java/com/reandroid/common/Frameworks.java @@ -26,6 +26,7 @@ import java.io.InputStream; public class Frameworks { private static FrameworkTable android_table; private static boolean load_once; + @Deprecated public static FrameworkTable getAndroid(){ if(android_table!=null || load_once){ return android_table; @@ -33,21 +34,10 @@ public class Frameworks { load_once=true; FrameworkTable frameworkTable=null; try { - frameworkTable = loadFramework(ANDROID_FRAMEWORK_33); + frameworkTable = AndroidFrameworks.getLatest().getTableBlock(); } catch (IOException e) { } android_table=frameworkTable; return android_table; } - private static FrameworkTable loadFramework(String name) throws IOException { - InputStream inputStream= Frameworks.class.getResourceAsStream(name); - if(inputStream==null){ - return null; - } - FrameworkTable frameworkTable=new FrameworkTable(); - frameworkTable.readBytes(inputStream); - return frameworkTable; - } - - private static final String ANDROID_FRAMEWORK_33 = "/fwk/android_resources_33.arsc"; }