feat: use MemoryDataStore instead of FileDataStore

This commit is contained in:
oSumAtrIX 2023-08-11 02:10:46 +02:00
parent ac410e52eb
commit 89a3a37f1d
No known key found for this signature in database
GPG Key ID: A9B3094ACDB604B4
2 changed files with 30 additions and 36 deletions

View File

@ -17,6 +17,7 @@ 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;
@ -31,7 +32,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.FileDataStore; import com.android.tools.smali.dexlib2.writer.io.MemoryDataStore;
import com.android.tools.smali.dexlib2.writer.pool.DexPool; import com.android.tools.smali.dexlib2.writer.pool.DexPool;
public class DexIO { public class DexIO {
@ -65,18 +66,14 @@ public class DexIO {
dexPool.writeTo(dataStore); dexPool.writeTo(dataStore);
} }
static void writeMultiDexDirectorySingleThread(boolean multiDex, File directory, DexFileNameIterator nameIterator, static void writeMultiDexDirectorySingleThread(Map<String, MemoryDataStore> output, 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(directory, nameIterator, Iterators.peekingIterator(classes.iterator()), writeMultiDexDirectoryCommon(output, nameIterator, Iterators.peekingIterator(classes.iterator()),
minMainDexClassCount, minimalMainDex, dexFile.getOpcodes(), maxDexPoolSize, logger, lock); minMainDexClassCount, minimalMainDex, dexFile.getOpcodes(), maxDexPoolSize, logger, lock);
} }
} }
@ -85,7 +82,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 File directory, static void writeMultiDexDirectoryMultiThread(int threadCount, final Map<String, MemoryDataStore> output,
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();
@ -99,7 +96,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(directory, nameIterator, batchedIterator, 0, false, writeMultiDexDirectoryCommon(output, nameIterator, batchedIterator, 0, false,
dexFile.getOpcodes(), maxDexPoolSize, logger, lock); dexFile.getOpcodes(), maxDexPoolSize, logger, lock);
return null; return null;
} }
@ -130,7 +127,7 @@ public class DexIO {
// Common Code // Common Code
private static void writeMultiDexDirectoryCommon(File directory, DexFileNameIterator nameIterator, private static void writeMultiDexDirectoryCommon(Map<String, MemoryDataStore> output, 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 {
@ -149,17 +146,17 @@ public class DexIO {
classIterator.next(); classIterator.next();
fileClassCount++; fileClassCount++;
} }
File file; String dexName;
MemoryDataStore memoryDataStore = new MemoryDataStore();
//noinspection SynchronizationOnLocalVariableOrMethodParameter //noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (lock) { synchronized (lock) {
String name = nameIterator.next(); dexName = 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(new FileDataStore(file)); dexPool.writeTo(memoryDataStore);
output.put(dexName, memoryDataStore);
minMainDexClassCount = 0; minMainDexClassCount = 0;
minimalMainDex = false; minimalMainDex = false;
} while (classIterator.hasNext()); } while (classIterator.hasNext());

View File

@ -14,11 +14,13 @@ 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 {
@ -65,51 +67,46 @@ public class MultiDexIO {
// Write // Write
public static int writeDexFile(boolean multiDex, File file, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, Map<String, MemoryDataStore> output, DexFileNamer namer, DexFile dexFile,
int maxDexPoolSize, DexIO.Logger logger) throws IOException { int maxDexPoolSize, DexIO.Logger logger) throws IOException {
return writeDexFile(multiDex, 1, file, namer, dexFile, maxDexPoolSize, logger); return writeDexFile(multiDex, 1, output, namer, dexFile, maxDexPoolSize, logger);
} }
public static int writeDexFile(boolean multiDex, int threadCount, File file, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, int threadCount, Map<String, MemoryDataStore> output, DexFileNamer namer, DexFile dexFile,
int maxDexPoolSize, DexIO.Logger logger) throws IOException { int maxDexPoolSize, DexIO.Logger logger) throws IOException {
return writeDexFile(multiDex, threadCount, file, namer, dexFile, 0, false, maxDexPoolSize, logger); return writeDexFile(multiDex, threadCount, output, namer, dexFile, 0, false, maxDexPoolSize, logger);
} }
public static int writeDexFile(boolean multiDex, File file, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, Map<String, MemoryDataStore> output, 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, file, namer, dexFile, minMainDexClassCount, minimalMainDex, maxDexPoolSize, return writeDexFile(multiDex, 1, output, namer, dexFile, minMainDexClassCount, minimalMainDex, maxDexPoolSize,
logger); logger);
} }
public static int writeDexFile(boolean multiDex, int threadCount, File file, DexFileNamer namer, DexFile dexFile, public static int writeDexFile(boolean multiDex, int threadCount, Map<String, MemoryDataStore> output, 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 (file.isDirectory()) { if (!multiDex) throw new UnsupportedOperationException(
return writeMultiDexDirectory(multiDex, threadCount, file, namer, dexFile, minMainDexClassCount, "Non-multidex is no longer supported, please use the official multidexlib2 for that."
);
return writeMultiDexDirectory(threadCount, output, namer, dexFile, minMainDexClassCount,
minimalMainDex, maxDexPoolSize, logger); minimalMainDex, maxDexPoolSize, logger);
} else {
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(boolean multiDex, int threadCount, File directory, DexFileNamer namer, public static int writeMultiDexDirectory(int threadCount, Map<String, MemoryDataStore> output, 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 && multiDex && minMainDexClassCount == 0 && !minimalMainDex) { if (threadCount > 1 && minMainDexClassCount == 0 && !minimalMainDex) {
DexIO.writeMultiDexDirectoryMultiThread(threadCount, directory, nameIterator, dexFile, maxDexPoolSize, DexIO.writeMultiDexDirectoryMultiThread(threadCount, output, nameIterator, dexFile, maxDexPoolSize,
logger); logger);
} else { } else {
DexIO.writeMultiDexDirectorySingleThread(multiDex, directory, nameIterator, dexFile, minMainDexClassCount, DexIO.writeMultiDexDirectorySingleThread(output, nameIterator, dexFile, minMainDexClassCount,
minimalMainDex, maxDexPoolSize, logger); minimalMainDex, maxDexPoolSize, logger);
} }
return nameIterator.getCount(); return nameIterator.getCount();