blob: 8c29ca8f81ee9c1944ed020e679a9dafa93fd3cc [file] [log] [blame]
// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
import com.android.tools.r8.DexIndexedConsumer.DirectoryConsumer;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.ApplicationWriter;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.FeatureClassMapping;
import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
public class DexSplitterHelper {
public static void run(
D8Command command,
FeatureClassMapping featureClassMapping,
String output,
String proguardMap)
throws IOException, CompilationException, ExecutionException {
InternalOptions options = command.getInternalOptions();
options.enableDesugaring = false;
options.enableMainDexListCheck = false;
options.minimalMainDex = false;
options.enableMinification = false;
options.enableInlining = false;
options.outline.enabled = false;
ExecutorService executor = ThreadUtils.getExecutorService(ThreadUtils.NOT_SPECIFIED);
try {
try {
Timing timing = new Timing("DexSplitter");
DexApplication app =
new ApplicationReader(command.getInputApp(), options, timing).read(null, executor);
ClassNameMapper mapper = null;
if (proguardMap != null) {
mapper = ClassNameMapper.mapperFromFile(Paths.get(proguardMap));
}
Map<String, Builder> applications = getDistribution(app, featureClassMapping, mapper);
for (Entry<String, Builder> entry : applications.entrySet()) {
DexApplication featureApp = entry.getValue().build();
// We use the same factory, reset sorting.
featureApp.dexItemFactory.resetSortedIndices();
assert !options.hasMethodsFilter();
// Run d8 optimize to ensure jumbo strings are handled.
AppInfo appInfo = new AppInfo(featureApp);
featureApp = D8.optimize(featureApp, appInfo, options, timing, executor);
// We create a specific consumer for each split.
Path outputDir = Paths.get(output).resolve(entry.getKey());
if (!Files.exists(outputDir)) {
Files.createDirectory(outputDir);
}
DexIndexedConsumer consumer = new DirectoryConsumer(outputDir);
try {
Marker marker = D8.getMarker(options);
new ApplicationWriter(
featureApp,
options,
marker == null ? null : Collections.singletonList(marker),
null,
NamingLens.getIdentityLens(),
null,
null,
consumer)
.write(executor);
options.printWarnings();
} finally {
consumer.finished(options.reporter);
}
}
} catch (ExecutionException e) {
R8.unwrapExecutionException(e);
throw new AssertionError(e); // unwrapping method should have thrown
} catch (FeatureMappingException e) {
options.reporter.error(e.getMessage());
} finally {
options.signalFinishedToProgramConsumer();
}
} finally {
executor.shutdown();
}
}
private static Map<String, Builder> getDistribution(
DexApplication app, FeatureClassMapping featureClassMapping, ClassNameMapper mapper)
throws FeatureMappingException {
Map<String, Builder> applications = new HashMap<>();
for (DexProgramClass clazz : app.classes()) {
String clazzName =
mapper != null ? mapper.deobfuscateClassName(clazz.toString()) : clazz.toString();
String feature = featureClassMapping.featureForClass(clazzName);
Builder featureApplication = applications.get(feature);
if (featureApplication == null) {
featureApplication = DexApplication.builder(app.dexItemFactory, app.timing);
applications.put(feature, featureApplication);
}
featureApplication.addProgramClass(clazz);
}
return applications;
}
}