Optimize to reduce memory consumption

This commit is contained in:
ZaneYork 2021-01-29 17:34:44 +08:00
parent 3094c600de
commit c69a1f1e8d
2 changed files with 40 additions and 36 deletions

View File

@ -34,6 +34,7 @@ import net.fornwall.apksigner.KeyStoreFileManager;
import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.NotImplementedException;
import org.zeroturnaround.zip.ZipUtil; import org.zeroturnaround.zip.ZipUtil;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -242,7 +243,7 @@ public class ApkPatcher {
byte[] bytes = ByteStreams.toByteArray(in); byte[] bytes = ByteStreams.toByteArray(in);
ZipUtils.ZipEntrySource source; ZipUtils.ZipEntrySource source;
if (entry.isXALZ()) { if (entry.isXALZ()) {
source = new ZipUtils.ZipEntrySource(entry.getTargetPath() + filename, entry.getCompression(), () -> ZipUtils.decompressXALZ(bytes)); source = new ZipUtils.ZipEntrySource(entry.getTargetPath() + filename, entry.getCompression(), () -> new ByteArrayInputStream(ZipUtils.decompressXALZ(bytes)));
} else { } else {
source = new ZipUtils.ZipEntrySource(entry.getTargetPath() + filename, bytes, entry.getCompression()); source = new ZipUtils.ZipEntrySource(entry.getTargetPath() + filename, bytes, entry.getCompression());
} }
@ -253,7 +254,13 @@ public class ApkPatcher {
} else { } else {
return Stream.of(context.getAssets().list(path)) return Stream.of(context.getAssets().list(path))
.filter(filename -> StringUtils.wildCardMatch(filename, pattern)) .filter(filename -> StringUtils.wildCardMatch(filename, pattern))
.map(filename -> new ZipUtils.ZipEntrySource(entry.getTargetPath() + filename, entry.getCompression(), () -> FileUtils.getAssetBytes(context, path + "/" + filename))) .map(filename -> new ZipUtils.ZipEntrySource(entry.getTargetPath() + filename, entry.getCompression(), () -> {
try {
return FileUtils.getLocalAsset(context, path + "/" + filename);
} catch (IOException ignored) {
}
return null;
}))
.toArray(ZipUtils.ZipEntrySource[]::new); .toArray(ZipUtils.ZipEntrySource[]::new);
} }
} catch (IOException ignored) { } catch (IOException ignored) {
@ -264,22 +271,25 @@ public class ApkPatcher {
if (entry.getOrigin() == 1) { if (entry.getOrigin() == 1) {
byte[] unpackEntryBytes = ZipUtil.unpackEntry(apkFile, entry.getAssetPath()); byte[] unpackEntryBytes = ZipUtil.unpackEntry(apkFile, entry.getAssetPath());
if (entry.isXALZ()) { if (entry.isXALZ()) {
source = new ZipUtils.ZipEntrySource(entry.getTargetPath(), entry.getCompression(), () -> ZipUtils.decompressXALZ(unpackEntryBytes)); source = new ZipUtils.ZipEntrySource(entry.getTargetPath(), entry.getCompression(), () -> new ByteArrayInputStream(ZipUtils.decompressXALZ(unpackEntryBytes)));
} else { } else {
source = new ZipUtils.ZipEntrySource(entry.getTargetPath(), unpackEntryBytes, entry.getCompression()); source = new ZipUtils.ZipEntrySource(entry.getTargetPath(), unpackEntryBytes, entry.getCompression());
} }
} else { } else {
source = new ZipUtils.ZipEntrySource(entry.getTargetPath(), entry.getCompression(), () -> { source = new ZipUtils.ZipEntrySource(entry.getTargetPath(), entry.getCompression(), () -> {
byte[] bytes; InputStream inputStream = null;
if (entry.isExternal()) { try {
bytes = FileUtils.getAssetBytes(context, apkFilesManifest.getBasePath() + entry.getAssetPath()); if (entry.isExternal()) {
} else { inputStream = FileUtils.getLocalAsset(context, apkFilesManifest.getBasePath() + entry.getAssetPath());
bytes = FileUtils.getAssetBytes(context, entry.getAssetPath()); } else {
inputStream = FileUtils.getLocalAsset(context, entry.getAssetPath());
}
} catch (IOException ignored) {
} }
if (StringUtils.isNoneBlank(entry.getPatchCrc())) { if (StringUtils.isNoneBlank(entry.getPatchCrc())) {
throw new NotImplementedException("bs patch mode is not supported anymore."); throw new NotImplementedException("bs patch mode is not supported anymore.");
} }
return bytes; return inputStream;
}); });
} }
return new ZipUtils.ZipEntrySource[]{source}; return new ZipUtils.ZipEntrySource[]{source};

View File

@ -8,13 +8,15 @@ import net.fornwall.apksigner.zipio.ZioEntry;
import net.fornwall.apksigner.zipio.ZipInput; import net.fornwall.apksigner.zipio.ZipInput;
import net.fornwall.apksigner.zipio.ZipOutput; import net.fornwall.apksigner.zipio.ZipOutput;
import net.jpountz.lz4.LZ4Factory; import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.io.Streams;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -24,21 +26,17 @@ import java.util.function.Supplier;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
/** /**
* @author Zane * @author Zane
*/ */
public class ZipUtils { public class ZipUtils {
public static byte[] decompressXALZ(byte[] bytes){ public static byte[] decompressXALZ(byte[] bytes) {
if("XALZ".equals(new String(ByteUtils.subArray(bytes, 0, 4), StandardCharsets.ISO_8859_1))) { if ("XALZ".equals(new String(ByteUtils.subArray(bytes, 0, 4), StandardCharsets.ISO_8859_1))) {
LZ4Factory factory = LZ4Factory.fastestInstance();
LZ4FastDecompressor lz4FastDecompressor = factory.fastDecompressor();
byte[] length = ByteUtils.subArray(bytes, 8, 12); byte[] length = ByteUtils.subArray(bytes, 8, 12);
int len = (length[0] & 0xff) | ((length[1] & 0xff) << 8) | ((length[2] & 0xff) << 16) | ((length[3] & 0xff) << 24); int len = (length[0] & 0xff) | ((length[1] & 0xff) << 8) | ((length[2] & 0xff) << 16) | ((length[3] & 0xff) << 24);
bytes = lz4FastDecompressor.decompress(bytes, 12, len); bytes = LZ4Factory.fastestJavaInstance().fastDecompressor().decompress(bytes, 12, len);
} }
return bytes; return bytes;
} }
@ -61,14 +59,16 @@ public class ZipUtils {
ZipEntrySource source = entryMap.get(inEntry.getName()); ZipEntrySource source = entryMap.get(inEntry.getName());
ZioEntry zioEntry = new ZioEntry(inEntry.getName()); ZioEntry zioEntry = new ZioEntry(inEntry.getName());
zioEntry.setCompression(source.getCompressionMethod()); zioEntry.setCompression(source.getCompressionMethod());
zioEntry.getOutputStream().write(source.getData()); try (InputStream inputStream = source.getDataStream()) {
Streams.pipeAll(inputStream, zioEntry.getOutputStream());
}
zipOutput.write(zioEntry); zipOutput.write(zioEntry);
replacedFileSet.add(inEntry.getName()); replacedFileSet.add(inEntry.getName());
} else { } else {
zipOutput.write(inEntry); zipOutput.write(inEntry);
} }
index++; index++;
if(index % reportInterval == 0) { if (index % reportInterval == 0) {
progressCallback.accept((int) (index * 95.0 / size)); progressCallback.accept((int) (index * 95.0 / size));
} }
} }
@ -78,9 +78,11 @@ public class ZipUtils {
ZipEntrySource source = entryMap.get(name); ZipEntrySource source = entryMap.get(name);
ZioEntry zioEntry = new ZioEntry(name); ZioEntry zioEntry = new ZioEntry(name);
zioEntry.setCompression(source.getCompressionMethod()); zioEntry.setCompression(source.getCompressionMethod());
zioEntry.getOutputStream().write(source.getData()); try (InputStream inputStream = source.getDataStream()) {
Streams.pipeAll(inputStream, zioEntry.getOutputStream());
}
zipOutput.write(zioEntry); zipOutput.write(zioEntry);
progressCallback.accept(95 + (int)(index * 5.0 / difference.size())); progressCallback.accept(95 + (int) (index * 5.0 / difference.size()));
} }
progressCallback.accept(100); progressCallback.accept(100);
} }
@ -103,7 +105,7 @@ public class ZipUtils {
zipOutput.write(inEntry); zipOutput.write(inEntry);
} }
index++; index++;
if(index % reportInterval == 0) { if (index % reportInterval == 0) {
progressCallback.accept((int) (index * 100.0 / size)); progressCallback.accept((int) (index * 100.0 / size));
} }
} }
@ -113,31 +115,23 @@ public class ZipUtils {
} }
@Data @Data
@RequiredArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode(of = "path") @EqualsAndHashCode(of = "path")
public static class ZipEntrySource { public static class ZipEntrySource {
@NonNull
private String path; private String path;
@NonNull
private byte[] data;
@NonNull
private int compressionMethod; private int compressionMethod;
private Supplier<byte[]> dataSupplier; private Supplier<InputStream> dataSupplier;
public ZipEntrySource(@NonNull String path, @NonNull int compressionMethod, Supplier<byte[]> dataSupplier) { public ZipEntrySource(String path, byte[] bytes, int compressionMethod) {
this.path = path; this.path = path;
this.compressionMethod = compressionMethod; this.compressionMethod = compressionMethod;
this.dataSupplier = dataSupplier; this.dataSupplier = () -> new ByteArrayInputStream(bytes);
} }
private byte[] getData() { private InputStream getDataStream() {
if(data != null) {
return data;
}
// Optimize: read only once // Optimize: read only once
if(dataSupplier != null) { if (dataSupplier != null) {
byte[] bytes = dataSupplier.get(); InputStream bytes = dataSupplier.get();
dataSupplier = null; dataSupplier = null;
return bytes; return bytes;
} }