feat: Use FileDataStore instead of MemoryDataStore

This reverts commit 1dbfaa5921c23df7b9111e874b2f97d58ab3ec2a.
Memory usage was too high.
This commit is contained in:
oSumAtrIX 2023-10-09 04:06:29 +02:00
parent 89a3a37f1d
commit 9833e732a0
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
2 changed files with 36 additions and 30 deletions

View File

@ -17,7 +17,6 @@ import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -32,7 +31,7 @@ import com.android.tools.smali.dexlib2.iface.ClassDef;
import com.android.tools.smali.dexlib2.iface.DexFile; import com.android.tools.smali.dexlib2.iface.DexFile;
import com.android.tools.smali.dexlib2.writer.DexWriter; import com.android.tools.smali.dexlib2.writer.DexWriter;
import com.android.tools.smali.dexlib2.writer.io.DexDataStore; import com.android.tools.smali.dexlib2.writer.io.DexDataStore;
import com.android.tools.smali.dexlib2.writer.io.MemoryDataStore; import com.android.tools.smali.dexlib2.writer.io.FileDataStore;
import com.android.tools.smali.dexlib2.writer.pool.DexPool; import com.android.tools.smali.dexlib2.writer.pool.DexPool;
public class DexIO { public class DexIO {
@ -66,14 +65,18 @@ public class DexIO {
dexPool.writeTo(dataStore); dexPool.writeTo(dataStore);
} }
static void writeMultiDexDirectorySingleThread(Map<String, MemoryDataStore> output, DexFileNameIterator nameIterator, static void writeMultiDexDirectorySingleThread(boolean multiDex, File directory, DexFileNameIterator nameIterator,
DexFile dexFile, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, DexIO.Logger logger) DexFile dexFile, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, DexIO.Logger logger)
throws IOException { throws IOException {
Set<? extends ClassDef> classes = dexFile.getClasses(); Set<? extends ClassDef> classes = dexFile.getClasses();
if (!multiDex) {
minMainDexClassCount = classes.size();
minimalMainDex = false;
}
Object lock = new Object(); Object lock = new Object();
//noinspection SynchronizationOnLocalVariableOrMethodParameter //noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (lock) { // avoid multiple synchronizations in single-threaded mode synchronized (lock) { // avoid multiple synchronizations in single-threaded mode
writeMultiDexDirectoryCommon(output, nameIterator, Iterators.peekingIterator(classes.iterator()), writeMultiDexDirectoryCommon(directory, nameIterator, Iterators.peekingIterator(classes.iterator()),
minMainDexClassCount, minimalMainDex, dexFile.getOpcodes(), maxDexPoolSize, logger, lock); minMainDexClassCount, minimalMainDex, dexFile.getOpcodes(), maxDexPoolSize, logger, lock);
} }
} }
@ -82,7 +85,7 @@ public class DexIO {
private static final int PER_THREAD_BATCH_SIZE = 100; private static final int PER_THREAD_BATCH_SIZE = 100;
static void writeMultiDexDirectoryMultiThread(int threadCount, final Map<String, MemoryDataStore> output, static void writeMultiDexDirectoryMultiThread(int threadCount, final File directory,
final DexFileNameIterator nameIterator, final DexFile dexFile, final int maxDexPoolSize, final DexFileNameIterator nameIterator, final DexFile dexFile, final int maxDexPoolSize,
final DexIO.Logger logger) throws IOException { final DexIO.Logger logger) throws IOException {
Iterator<? extends ClassDef> classIterator = dexFile.getClasses().iterator(); Iterator<? extends ClassDef> classIterator = dexFile.getClasses().iterator();
@ -96,7 +99,7 @@ public class DexIO {
callables.add(new Callable<Void>() { callables.add(new Callable<Void>() {
@Override @Override
public Void call() throws IOException { public Void call() throws IOException {
writeMultiDexDirectoryCommon(output, nameIterator, batchedIterator, 0, false, writeMultiDexDirectoryCommon(directory, nameIterator, batchedIterator, 0, false,
dexFile.getOpcodes(), maxDexPoolSize, logger, lock); dexFile.getOpcodes(), maxDexPoolSize, logger, lock);
return null; return null;
} }
@ -127,7 +130,7 @@ public class DexIO {
// Common Code // Common Code
private static void writeMultiDexDirectoryCommon(Map<String, MemoryDataStore> output, DexFileNameIterator nameIterator, private static void writeMultiDexDirectoryCommon(File directory, DexFileNameIterator nameIterator,
PeekingIterator<? extends ClassDef> classIterator, int minMainDexClassCount, boolean minimalMainDex, PeekingIterator<? extends ClassDef> classIterator, int minMainDexClassCount, boolean minimalMainDex,
Opcodes opcodes, int maxDexPoolSize, DexIO.Logger logger, Object lock) throws IOException { Opcodes opcodes, int maxDexPoolSize, DexIO.Logger logger, Object lock) throws IOException {
do { do {
@ -146,17 +149,17 @@ public class DexIO {
classIterator.next(); classIterator.next();
fileClassCount++; fileClassCount++;
} }
String dexName; File file;
MemoryDataStore memoryDataStore = new MemoryDataStore();
//noinspection SynchronizationOnLocalVariableOrMethodParameter //noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (lock) { synchronized (lock) {
dexName = nameIterator.next(); String name = nameIterator.next();
file = new File(directory, name);
if (logger != null) logger.log(directory, name, fileClassCount);
if (classIterator instanceof BatchedIterator) { if (classIterator instanceof BatchedIterator) {
((BatchedIterator<?>) classIterator).preloadBatch(); ((BatchedIterator<?>) classIterator).preloadBatch();
} }
} }
dexPool.writeTo(memoryDataStore); dexPool.writeTo(new FileDataStore(file));
output.put(dexName, memoryDataStore);
minMainDexClassCount = 0; minMainDexClassCount = 0;
minimalMainDex = false; minimalMainDex = false;
} while (classIterator.hasNext()); } while (classIterator.hasNext());

View File

@ -14,13 +14,11 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map;
import com.android.tools.smali.dexlib2.Opcodes; import com.android.tools.smali.dexlib2.Opcodes;
import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile; import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
import com.android.tools.smali.dexlib2.iface.DexFile; import com.android.tools.smali.dexlib2.iface.DexFile;
import com.android.tools.smali.dexlib2.iface.MultiDexContainer; import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
import com.android.tools.smali.dexlib2.writer.io.MemoryDataStore;
public class MultiDexIO { public class MultiDexIO {
@ -67,46 +65,51 @@ public class MultiDexIO {
// Write // Write
public static int writeDexFile(boolean multiDex, Map<String, MemoryDataStore> output, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, File file, DexFileNamer namer, DexFile dexFile,
int maxDexPoolSize, DexIO.Logger logger) throws IOException { int maxDexPoolSize, DexIO.Logger logger) throws IOException {
return writeDexFile(multiDex, 1, output, namer, dexFile, maxDexPoolSize, logger); return writeDexFile(multiDex, 1, file, namer, dexFile, maxDexPoolSize, logger);
} }
public static int writeDexFile(boolean multiDex, int threadCount, Map<String, MemoryDataStore> output, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, int threadCount, File file, DexFileNamer namer, DexFile dexFile,
int maxDexPoolSize, DexIO.Logger logger) throws IOException { int maxDexPoolSize, DexIO.Logger logger) throws IOException {
return writeDexFile(multiDex, threadCount, output, namer, dexFile, 0, false, maxDexPoolSize, logger); return writeDexFile(multiDex, threadCount, file, namer, dexFile, 0, false, maxDexPoolSize, logger);
} }
public static int writeDexFile(boolean multiDex, Map<String, MemoryDataStore> output, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, File file, DexFileNamer namer, DexFile dexFile,
int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize,
DexIO.Logger logger) throws IOException { DexIO.Logger logger) throws IOException {
return writeDexFile(multiDex, 1, output, namer, dexFile, minMainDexClassCount, minimalMainDex, maxDexPoolSize, return writeDexFile(multiDex, 1, file, namer, dexFile, minMainDexClassCount, minimalMainDex, maxDexPoolSize,
logger); logger);
} }
public static int writeDexFile(boolean multiDex, int threadCount, Map<String, MemoryDataStore> output, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, int threadCount, File file, DexFileNamer namer, DexFile dexFile,
int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize,
DexIO.Logger logger) throws IOException { DexIO.Logger logger) throws IOException {
if (!multiDex) throw new UnsupportedOperationException( if (file.isDirectory()) {
"Non-multidex is no longer supported, please use the official multidexlib2 for that." return writeMultiDexDirectory(multiDex, threadCount, file, namer, dexFile, minMainDexClassCount,
); minimalMainDex, maxDexPoolSize, logger);
return writeMultiDexDirectory(threadCount, output, namer, dexFile, minMainDexClassCount, } else {
minimalMainDex, maxDexPoolSize, logger); if (multiDex) throw new UnsupportedOperationException(
"Must output to a directory if multi-dex mode is enabled");
RawDexIO.writeRawDexFile(file, dexFile, maxDexPoolSize, logger);
return 1;
}
} }
public static int writeMultiDexDirectory(int threadCount, Map<String, MemoryDataStore> output, DexFileNamer namer, public static int writeMultiDexDirectory(boolean multiDex, int threadCount, File directory, DexFileNamer namer,
DexFile dexFile, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, DexIO.Logger logger) DexFile dexFile, int minMainDexClassCount, boolean minimalMainDex, int maxDexPoolSize, DexIO.Logger logger)
throws IOException { throws IOException {
purgeMultiDexDirectory(multiDex, directory, namer);
DexFileNameIterator nameIterator = new DexFileNameIterator(namer); DexFileNameIterator nameIterator = new DexFileNameIterator(namer);
if (threadCount <= 0) { if (threadCount <= 0) {
threadCount = Runtime.getRuntime().availableProcessors(); threadCount = Runtime.getRuntime().availableProcessors();
if (threadCount > DEFAULT_MAX_THREADS) threadCount = DEFAULT_MAX_THREADS; if (threadCount > DEFAULT_MAX_THREADS) threadCount = DEFAULT_MAX_THREADS;
} }
if (threadCount > 1 && minMainDexClassCount == 0 && !minimalMainDex) { if (threadCount > 1 && multiDex && minMainDexClassCount == 0 && !minimalMainDex) {
DexIO.writeMultiDexDirectoryMultiThread(threadCount, output, nameIterator, dexFile, maxDexPoolSize, DexIO.writeMultiDexDirectoryMultiThread(threadCount, directory, nameIterator, dexFile, maxDexPoolSize,
logger); logger);
} else { } else {
DexIO.writeMultiDexDirectorySingleThread(output, nameIterator, dexFile, minMainDexClassCount, DexIO.writeMultiDexDirectorySingleThread(multiDex, directory, nameIterator, dexFile, minMainDexClassCount,
minimalMainDex, maxDexPoolSize, logger); minimalMainDex, maxDexPoolSize, logger);
} }
return nameIterator.getCount(); return nameIterator.getCount();