use of com.android.ide.common.internal.WaitableExecutor in project atlas by alibaba.
the class ResourcesShrinker method splitAction.
@Nullable
public File splitAction(@NonNull ApkData apkData, @Nullable File uncompressedResourceFile, TransformInvocation invocation, SplitList splitList) {
if (uncompressedResourceFile == null) {
return null;
}
List<File> classes = new ArrayList<>();
classes.addAll(AtlasBuildContext.atlasMainDexHelperMap.get(variantContext.getVariantName()).getInputDirs());
classes.addAll(AtlasBuildContext.atlasMainDexHelperMap.get(variantContext.getVariantName()).getAllMainDexJars());
AppVariantOutputContext appVariantOutputContext = variantContext.getAppVariantOutputContext(apkData);
for (AwbTransform awbTransform : appVariantOutputContext.getAwbTransformMap().values()) {
classes.addAll(awbTransform.getInputLibraries());
if (awbTransform.getInputDirs() != null && awbTransform.getInputDirs().size() > 0) {
classes.addAll(awbTransform.getInputDirs());
}
}
WaitableExecutor executor = WaitableExecutor.useGlobalSharedThreadPool();
Collection<BuildOutput> mergedManifests = BuildOutputs.load(ResourcesShrinker.this.mergedManifests);
BuildOutput mergedManifest = OutputScope.getOutput(mergedManifests, TaskOutputHolder.TaskOutputType.MERGED_MANIFESTS, apkData);
File mappingFile = mappingFileSrc != null ? mappingFileSrc.getSingleFile() : null;
ForkJoinTask<File> task = executor.execute(() -> {
File reportFile = null;
if (mappingFile != null) {
File logDir = mappingFile.getParentFile();
if (logDir != null) {
reportFile = new File(logDir, "resources.txt");
}
}
File compressedResourceFile = new File(compressedResources, "resources-" + apkData.getBaseName() + "-stripped.ap_");
FileUtils.mkdirs(compressedResourceFile.getParentFile());
if (mergedManifest == null) {
try {
FileUtils.copyFile(uncompressedResourceFile, compressedResourceFile);
} catch (IOException e) {
logger.error("Failed to copy uncompressed resource file :", e);
throw new RuntimeException("Failed to copy uncompressed resource file", e);
}
return compressedResourceFile;
}
// Analyze resources and usages and strip out unused
ResourceUsageAnalyzer analyzer = new ResourceUsageAnalyzer(sourceDir, classes, mergedManifest.getOutputFile(), mappingFile, resourceDir.getSingleFile(), reportFile);
try {
analyzer.setVerbose(logger.isEnabled(LogLevel.INFO));
analyzer.setDebug(logger.isEnabled(LogLevel.DEBUG));
analyzer.analyze();
// Just rewrite the .ap_ file to strip out the res/ files for unused resources
analyzer.rewriteResourceZip(uncompressedResourceFile, compressedResourceFile);
// Dump some stats
int unused = analyzer.getUnusedResourceCount();
if (unused > 0) {
StringBuilder sb = new StringBuilder(200);
sb.append("Removed unused resources");
// This is a bit misleading until we can strip out all resource types:
// int total = analyzer.getTotalResourceCount()
// sb.append("(" + unused + "/" + total + ")")
long before = uncompressedResourceFile.length();
long after = compressedResourceFile.length();
long percent = (int) ((before - after) * 100 / before);
sb.append(": Binary resource data reduced from ").append(toKbString(before)).append("KB to ").append(toKbString(after)).append("KB: Removed ").append(percent).append("%");
if (!ourWarned) {
ourWarned = true;
String name = variantData.getVariantConfiguration().getBuildType().getName();
sb.append("\n").append("Note: If necessary, you can disable resource shrinking by adding\n").append("android {\n").append(" buildTypes {\n").append(" ").append(name).append(" {\n").append(" shrinkResources false\n").append(" }\n").append(" }\n").append("}");
}
System.out.println(sb.toString());
}
} catch (Exception e) {
logger.quiet("Failed to shrink resources: ignoring", e);
} finally {
analyzer.dispose();
}
return compressedResourceFile;
});
for (AwbTransform awbTransform : appVariantOutputContext.getAwbTransformMap().values()) {
AwbBundle awbBundle = awbTransform.getAwbBundle();
File compressedBundleResourceFile = appVariantOutputContext.getAwbCompressResourcePackageOutputFile(awbBundle);
File unCompressedBundleResourceFile = appVariantOutputContext.getAwbProcessResourcePackageOutputFile(awbBundle);
File awbResDir = appVariantOutputContext.getAwbMergedResourceDir(variantContext.getVariantConfiguration(), awbBundle);
File reportFile = new File(uncompressedResourceFile.getParentFile(), "resources.txt");
File bundleSourceDir = appVariantOutputContext.getAwbRClassSourceOutputDir(variantContext.getVariantConfiguration(), awbBundle);
executor.execute(() -> {
ResourceUsageAnalyzer analyzer = new ResourceUsageAnalyzer(bundleSourceDir, classes, mergedManifest.getOutputFile(), mappingFile, awbResDir, reportFile);
try {
analyzer.setVerbose(logger.isEnabled(LogLevel.INFO));
analyzer.setDebug(logger.isEnabled(LogLevel.DEBUG));
analyzer.analyze();
// Just rewrite the .ap_ file to strip out the res/ files for unused resources
analyzer.rewriteResourceZip(unCompressedBundleResourceFile, compressedBundleResourceFile);
// Dump some stats
int unused = analyzer.getUnusedResourceCount();
if (unused > 0) {
StringBuilder sb = new StringBuilder(200);
sb.append("Removed awb bundle" + awbBundle.getName() + " unused resources");
// This is a bit misleading until we can strip out all resource types:
// int total = analyzer.getTotalResourceCount()
// sb.append("(" + unused + "/" + total + ")")
long before = unCompressedBundleResourceFile.length();
long after = compressedBundleResourceFile.length();
long percent = (int) ((before - after) * 100 / before);
sb.append(": Binary resource data reduced from ").append(toKbString(before)).append("KB to ").append(toKbString(after)).append("KB: Removed ").append(percent).append("%");
if (!ourWarned) {
ourWarned = true;
String name = variantData.getVariantConfiguration().getBuildType().getName();
sb.append("\n").append("Note: If necessary, you can disable resource shrinking by adding\n").append("android {\n").append(" buildTypes {\n").append(" ").append(name).append(" {\n").append(" shrinkResources false\n").append(" }\n").append(" }\n").append("}");
}
System.out.println(sb.toString());
}
} catch (Exception e) {
logger.quiet("Failed to shrink resources: ignoring", e);
} finally {
analyzer.dispose();
}
return compressedBundleResourceFile;
});
}
try {
List<WaitableExecutor.TaskResult<File>> taskResults = executor.waitForAllTasks();
taskResults.forEach(taskResult -> {
if (taskResult.getException() != null) {
throw new BuildException(taskResult.getException().getMessage(), taskResult.getException());
}
});
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
return task.join();
}
use of com.android.ide.common.internal.WaitableExecutor in project atlas by alibaba.
the class AwbDataBindingRenameTask method createAwbPackages.
/**
* Directory of so
*/
@TaskAction
void createAwbPackages() throws ExecutionException, InterruptedException {
WaitableExecutor workerExecutor = WaitableExecutor.useGlobalSharedThreadPool();
AtlasDependencyTree atlasDependencyTree = AtlasBuildContext.androidDependencyTrees.get(getVariantName());
if (null == atlasDependencyTree) {
return;
}
ExecutorServicesHelper executorServicesHelper = new ExecutorServicesHelper(taskName, getLogger(), 0);
for (final AwbBundle awbBundle : atlasDependencyTree.getAwbBundles()) {
if (!appVariantContext.getAtlasExtension().getTBuildConfig().getDataBindingBundles().contains(awbBundle.getPackageName())) {
continue;
}
if (!awbBundle.isDataBindEnabled() || awbBundle.isMBundle) {
continue;
}
workerExecutor.execute(new Callable() {
@Override
public Object call() {
try {
File dataBindingClazzFolder = appVariantOutputContext.getVariantContext().getJAwbavaOutputDir(awbBundle);
String packageName = awbBundle.getPackageName();
String appName = awbBundle.getPackageName() + "._bundleapp_";
// Remove classes that already exist
File dataMapperClazz = new File(dataBindingClazzFolder, "android/databinding/DataBinderMapper.class");
if (!dataMapperClazz.exists()) {
throw new GradleException("missing datamapper class");
}
File dataBindComponentClazz = new File(dataBindingClazzFolder, "android/databinding/DataBindingComponent.class");
if (!dataBindComponentClazz.exists()) {
throw new GradleException("missing dataBindComponent.class");
}
File dataBindDynamicUtilsClazz = new File(dataBindingClazzFolder, "android/databinding/DynamicUtil.class");
if (!dataBindDynamicUtilsClazz.exists()) {
throw new GradleException("missing dataBindDynamicUtils.class");
}
ClassNameRenamer.rewriteDataBinderMapper(dataBindingClazzFolder, "android/databinding/DataBinderMapper", packageName.replace(".", "/") + "/DataBinderMapper", dataMapperClazz);
ClassNameRenamer.rewriteDataBinderMapper(dataBindingClazzFolder, "android/databinding/DataBindingComponent", packageName.replace(".", "/") + "/DataBindingComponent", dataBindComponentClazz);
ClassNameRenamer.rewriteDataBinderMapper(dataBindingClazzFolder, "android/databinding/dataBindDynamicUtils", packageName.replace(".", "/") + "/dataBindDynamicUtils", dataBindDynamicUtilsClazz);
FileUtils.deleteDirectory(new File(dataBindingClazzFolder, "android/databinding"));
// FileUtils.deleteDirectory(new File(dataBindingClazzFolder, packageName.replace(".", "/") +
// "/_bundleapp_" ));
File appDir = new File(dataBindingClazzFolder, appName.replace(".", "/"));
if (appDir.exists()) {
File[] files = appDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile() && !pathname.isDirectory();
}
});
for (File tmp : files) {
FileUtils.forceDelete(tmp);
}
}
// rename DataBindUtils
AwbTransform awbTransform = appVariantOutputContext.getAwbTransformMap().get(awbBundle.getName());
List<File> files = awbTransform.getInputLibraries();
Map<String, String> replaceMap = new HashMap<>();
replaceMap.put("android/databinding/DataBindingUtil", "android/databinding/AtlasDataBindingUtil");
List<File> newLibrarys = new ArrayList<>();
for (File inputJar : files) {
File outputJar = new File(appVariantContext.getAwbLibraryDirForDataBinding(awbBundle), FileNameUtils.getUniqueJarName(inputJar) + ".jar");
outputJar.delete();
outputJar.getParentFile().mkdirs();
outputJar.createNewFile();
new ClazzReplacer(inputJar, outputJar, replaceMap).execute();
newLibrarys.add(outputJar);
awbTransform.getFileTransform().put(inputJar, outputJar);
}
awbTransform.setInputLibraries(newLibrarys);
} catch (Throwable e) {
e.printStackTrace();
throw new GradleException("databinding awb failed", e);
}
return null;
}
});
}
workerExecutor.waitForTasksWithQuickFail(true);
}
use of com.android.ide.common.internal.WaitableExecutor in project atlas by alibaba.
the class TaobaoExtractJarsTransform method transform.
@Override
public void transform(TransformInvocation transformInvocation) throws IOException, TransformException, InterruptedException {
TransformOutputProvider outputProvider = transformInvocation.getOutputProvider();
boolean isIncremental = transformInvocation.isIncremental();
checkNotNull(outputProvider, "Missing output object for transform " + getName());
// as_input transform and no referenced scopes, all the inputs will in InputOutputStreams.
final boolean extractCode = contentTypes.contains(QualifiedContent.DefaultContentType.CLASSES);
if (!isIncremental) {
outputProvider.deleteAll();
}
try {
WaitableExecutor executor = WaitableExecutor.useGlobalSharedThreadPool();
AtlasBuildContext.atlasMainDexHelperMap.get(variantContext.getVariantName()).getInputDirs().clear();
for (File jarFile : AtlasBuildContext.atlasMainDexHelperMap.get(variantContext.getVariantName()).getAllMainDexJars()) {
// final File jarFile = jarInput.getFile();
JarInput jarInput = makeJarInput(jarFile);
LOGGER.warn("input JarFile:" + jarFile.getAbsolutePath());
// create an output folder for this jar, keeping its type and scopes.
final File outJarFolder = outputProvider.getContentLocation(jarInput.getName(), jarInput.getContentTypes(), jarInput.getScopes(), Format.DIRECTORY);
FileUtils.mkdirs(outJarFolder);
LOGGER.warn("outJar Folder:" + outJarFolder.getAbsolutePath());
AtlasBuildContext.atlasMainDexHelperMap.get(variantContext.getVariantName()).getInputDirs().add(outJarFolder);
if (!isIncremental) {
executor.execute(() -> {
extractJar(outJarFolder, jarFile, extractCode);
return null;
});
} else {
switch(jarInput.getStatus()) {
case CHANGED:
executor.execute(() -> {
FileUtils.cleanOutputDir(outJarFolder);
extractJar(outJarFolder, jarFile, extractCode);
return null;
});
break;
case ADDED:
executor.execute(() -> {
extractJar(outJarFolder, jarFile, extractCode);
return null;
});
break;
case REMOVED:
executor.execute(() -> {
FileUtils.cleanOutputDir(outJarFolder);
return null;
});
break;
case NOTCHANGED:
break;
}
}
}
AtlasBuildContext.atlasMainDexHelperMap.get(variantContext.getVariantName()).addMainDexJars(Sets.newHashSet());
for (AwbTransform awbTransform : variantOutputContext.getAwbTransformMap().values()) {
File outJarFolder = variantOutputContext.getAwbExtractJarsFolder(awbTransform.getAwbBundle());
awbTransform.getInputFiles().forEach(file -> executor.execute(() -> {
LOGGER.warn("ExtractAwbJar[" + awbTransform.getAwbBundle().getPackageName() + "]---------------------" + file.getAbsolutePath());
extractJar(outJarFolder, file, extractCode);
return null;
}));
awbTransform.getInputLibraries().forEach(file -> executor.execute(() -> {
LOGGER.warn("ExtractAwbJar[" + awbTransform.getAwbBundle().getPackageName() + "]---------------------" + file.getAbsolutePath());
extractJar(outJarFolder, file, extractCode);
return null;
}));
awbTransform.addDir(outJarFolder);
awbTransform.getInputFiles().clear();
}
executor.waitForTasksWithQuickFail(true);
} catch (InterruptedException e) {
throw e;
} catch (Exception e) {
throw new TransformException(e);
}
}
Aggregations