Skip to content
18 changes: 10 additions & 8 deletions src/main/java/com/reandroid/apk/ApkBundle.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public ApkModule mergeModules(boolean force) throws IOException {
if(base == null){
base = getLargestTableModule();
}
result.merge(base, force);
result.merge(base, force, false);
AndroidManifestBlockMerger manifestMerger = getManifestMerger();
if (manifestMerger != null) {
manifestMerger.reset();
Expand All @@ -69,7 +69,7 @@ public ApkModule mergeModules(boolean force) throws IOException {
if(signatureBlock == null){
signatureBlock = asb;
}
result.merge(module, force);
result.merge(module, force, false);
if (manifestMerger != null) {
manifestMerger.merge(module.getAndroidManifest());
}
Expand Down Expand Up @@ -107,17 +107,19 @@ private String generateMergedModuleName(){
}
return name;
}
private ApkModule getLargestTableModule(){
private ApkModule getLargestTableModule() throws IOException {
// Compared by entry size, so the tables are not all parsed just to pick one
ApkModule apkModule=null;
int chunkSize=0;
long largest=0;
for(ApkModule module:getApkModuleList()){
if(!module.hasTableBlock()){
continue;
}
TableBlock tableBlock=module.getTableBlock();
int size=tableBlock.getHeaderBlock().getChunkSize();
if(apkModule==null || size>chunkSize){
chunkSize=size;
TableBlock loaded=module.getLoadedTableBlock();
long size=loaded != null ? loaded.getHeaderBlock().getChunkSize()
: module.getInputSource(TableBlock.FILE_NAME).getLength();
if(apkModule==null || size>largest){
largest=size;
apkModule=module;
}
}
Expand Down
67 changes: 54 additions & 13 deletions src/main/java/com/reandroid/apk/ApkModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -1154,9 +1154,7 @@ TableBlock loadTableBlock() throws IOException {
tableBlock = (TableBlock) ((BlockInputSource<?>) inputSource).getBlock();
} else {
setTableOriginalSource(inputSource);
InputStream inputStream = inputSource.openStream();
tableBlock = TableBlock.load(inputStream);
inputStream.close();
tableBlock = parseTableBlock(inputSource);
}
BlockInputSource<TableBlock> blockInputSource = new BlockInputSource<>(
inputSource.getName(), tableBlock);
Expand Down Expand Up @@ -1220,13 +1218,20 @@ public void merge(ApkModule module) throws IOException {
merge(module, false);
}
public void merge(ApkModule module, boolean force) throws IOException {
merge(module, force, true);
}
/**
* @param refreshTable whether to refresh the merged table afterwards. {@link ApkBundle}
* merges every module first and refreshes the table once at the end.
*/
void merge(ApkModule module, boolean force, boolean refreshTable) throws IOException {
if (module == null || module == this) {
return;
}
logMessage("Merging: " + module.getModuleName());
validateMerge(module, force);
mergeDexFiles(module);
mergeTable(module);
mergeTable(module, refreshTable);
mergeFiles(module);
getUncompressedFiles().merge(module.getUncompressedFiles());
mergeFusedModules(module);
Expand Down Expand Up @@ -1291,20 +1296,50 @@ private void validateMerge(ApkModule apkModule, boolean force) throws IOExceptio
}
logMessage(msg);
}
private void mergeTable(ApkModule module) {
private void mergeTable(ApkModule module, boolean refresh) throws IOException {
if (!module.hasTableBlock()) {
return;
}
TableBlock coming = module.getLoadedTableBlock();
if (coming == null) {
// Parsed for this merge only, so nothing else holds it: it can become the merged
// table as is, or be dropped once merged
coming = module.loadDetachedTableBlock();
if (coming != null && !hasTableBlock()) {
addInputSource(new BlockInputSource<>(TableBlock.FILE_NAME, coming));
return;
}
if (coming == null) {
coming = module.getTableBlock();
}
}
TableBlock exist;
if (!hasTableBlock()) {
exist=new TableBlock();
BlockInputSource<TableBlock> inputSource=new BlockInputSource<>(TableBlock.FILE_NAME, exist);
addInputSource(inputSource);
exist = new TableBlock();
addInputSource(new BlockInputSource<>(TableBlock.FILE_NAME, exist));
} else {
exist=getTableBlock();
exist = getTableBlock();
}
exist.merge(coming, refresh);
}
/**
* Parses resources.arsc without caching it on this module, or returns null when the
* table source is already a block rather than an archive entry.
*/
private TableBlock loadDetachedTableBlock() throws IOException {
InputSource inputSource = getInputSource(TableBlock.FILE_NAME);
if (inputSource == null || inputSource instanceof BlockInputSource) {
return null;
}
return parseTableBlock(inputSource);
}
private static TableBlock parseTableBlock(InputSource inputSource) throws IOException {
InputStream inputStream = inputSource.openStream();
try {
return TableBlock.load(inputStream);
} finally {
inputStream.close();
}
TableBlock coming=module.getTableBlock();
exist.merge(coming);
}
private void mergeFiles(ApkModule module) {
ZipEntryMap entryMapExist = getZipEntryMap();
Expand All @@ -1328,7 +1363,8 @@ private void mergeFiles(ApkModule module) {
}
}
private void mergeDexFiles(ApkModule module) {
UncompressedFiles uncompressedFiles = module.getUncompressedFiles();
UncompressedFiles comingUncompressed = module.getUncompressedFiles();
UncompressedFiles uncompressed = getUncompressedFiles();
List<DexFileInputSource> existList = listDexFiles();
List<DexFileInputSource> comingList = module.listDexFiles();
ZipEntryMap zipEntryMap = getZipEntryMap();
Expand All @@ -1342,8 +1378,13 @@ private void mergeDexFiles(ApkModule module) {
}
}
for (DexFileInputSource source : comingList) {
uncompressedFiles.removePath(source.getAlias());
String name = DexFileInputSource.getDexName(index);
if (comingUncompressed.isUncompressed(source.getAlias())) {
// Keep a stored dex stored under its new name, so it is copied as is
// instead of being deflated while writing
uncompressed.addPath(name);
}
comingUncompressed.removePath(source.getAlias());
DexFileInputSource add = new DexFileInputSource(name, source.getInputSource());
zipEntryMap.add(add);
logMessage("Added [" + module.getModuleName() +"] "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ private void encodeValues(List<File> pubXmlFileList) throws IOException, XmlPull
filePathEncoder.encodePackageResDir(packageBlock, resDir);

packageBlock.sortTypes();
packageBlock.refresh();
}
}
private void encodeAttrs(List<File> pubXmlFileList) throws IOException, XmlPullParserException {
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/com/reandroid/arsc/chunk/TableBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -795,12 +795,21 @@ public void fromJson(JSONObject json) {
refresh();
}
public void merge(TableBlock tableBlock){
merge(tableBlock, true);
}
/**
* @param refresh whether to refresh this table afterwards. A caller merging several tables
* can skip it for all but the last, as refreshing a large table is costly.
*/
public void merge(TableBlock tableBlock, boolean refresh){
if(tableBlock == null || tableBlock == this){
return;
}
getStringPool().merge(tableBlock.getStringPool());
getPackageArray().merge(tableBlock.getPackageArray());
refresh();
if(refresh){
refresh();
}
}
@Override
public byte[] getBytes(){
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/com/reandroid/arsc/chunk/TypeBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,6 @@ public SpecTypePair getParentSpecTypePair() {
return getParent(SpecTypePair.class);
}
public Entry getOrCreateDefinedEntry(String name) {
Entry entry = getEntry(name);
if (entry != null) {
return entry;
}
PackageBlock packageBlock = getPackageBlock();
if (packageBlock == null) {
return null;
Expand All @@ -198,6 +194,21 @@ public Entry getOrCreateDefinedEntry(String name) {
if (id == 0) {
return null;
}
Entry entry = getEntry(id & 0xffff);
if (entry != null) {
String entryName = entry.getName();
if (name.equals(entryName)) {
return entry;
}
if (entryName != null && !entry.isNull()) {
// The defined id holds a different name; fall back to
// scanning this type block by name.
Entry existing = getEntry(name);
if (existing != null) {
return existing;
}
}
}
SpecStringPool stringPool = packageBlock.getSpecStringPool();
SpecString specString = stringPool.getOrCreate(name);
entry = getOrCreateEntry(id & 0xffff);
Expand Down
13 changes: 2 additions & 11 deletions src/main/java/com/reandroid/arsc/container/BlockList.java
Original file line number Diff line number Diff line change
Expand Up @@ -198,19 +198,10 @@ public void destroy() {
onChanged();
}
public boolean sort(Comparator<? super T> comparator) {
if (size() < 2) {
if (!needsSort(comparator)) {
return false;
}
boolean sorted = mItems.sort(comparator, (i, j) -> {
T item1 = get(i);
T item2 = get(j);
if (item1 != null) {
item1.setIndex(i);
}
if (item2 != null) {
item2.setIndex(j);
}
});
boolean sorted = mItems.sortItems(comparator);
if (sorted) {
updateIndex();
}
Expand Down
Loading