use of com.android.build.gradle.tasks.ResourceUsageAnalyzer 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.build.gradle.tasks.ResourceUsageAnalyzer in project bazel by bazelbuild.
the class ResourceShrinkerAction method main.
public static void main(String[] args) throws Exception {
final Stopwatch timer = Stopwatch.createStarted();
// Parse arguments.
OptionsParser optionsParser = OptionsParser.newOptionsParser(Options.class, AaptConfigOptions.class);
optionsParser.parseAndExitUponError(args);
aaptConfigOptions = optionsParser.getOptions(AaptConfigOptions.class);
options = optionsParser.getOptions(Options.class);
AndroidResourceProcessor resourceProcessor = new AndroidResourceProcessor(stdLogger);
// Setup temporary working directories.
try (ScopedTemporaryDirectory scopedTmp = new ScopedTemporaryDirectory("resource_shrinker_tmp")) {
Path working = scopedTmp.getPath();
final Path resourceFiles = working.resolve("resource_files");
final Path shrunkResources = working.resolve("shrunk_resources");
// Gather package list from manifests.
Set<String> resourcePackages = getManifestPackages(options.primaryManifest, options.dependencyManifests);
resourcePackages.addAll(options.resourcePackages);
// Expand resource files zip into working directory.
try (ZipInputStream zin = new ZipInputStream(new FileInputStream(options.resourcesZip.toFile()))) {
ZipEntry entry;
while ((entry = zin.getNextEntry()) != null) {
if (!entry.isDirectory()) {
Path output = resourceFiles.resolve(entry.getName());
Files.createDirectories(output.getParent());
try (FileOutputStream fos = new FileOutputStream(output.toFile())) {
ByteStreams.copy(zin, fos);
}
}
}
}
// Shrink resources.
ResourceUsageAnalyzer resourceShrinker = new ResourceUsageAnalyzer(resourcePackages, options.rTxt, options.shrunkJar, options.primaryManifest, options.proguardMapping, resourceFiles.resolve("res"), options.log);
resourceShrinker.shrink(shrunkResources);
logger.fine(String.format("Shrinking resources finished at %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
Path generatedSources = null;
if (options.rTxtOutput != null) {
generatedSources = working.resolve("generated_resources");
}
// Build ap_ with shrunk resources.
resourceProcessor.processResources(aaptConfigOptions.aapt, aaptConfigOptions.androidJar, aaptConfigOptions.buildToolsVersion, VariantType.DEFAULT, aaptConfigOptions.debug, null, /* packageForR */
new FlagAaptOptions(aaptConfigOptions), aaptConfigOptions.resourceConfigs, aaptConfigOptions.splits, new MergedAndroidData(shrunkResources, resourceFiles.resolve("assets"), options.primaryManifest), ImmutableList.<DependencyAndroidData>of(), /* libraries */
generatedSources, options.shrunkApk, null, /* proguardOutput */
null, /* mainDexProguardOutput */
null, /* publicResourcesOut */
null);
if (options.shrunkResources != null) {
AndroidResourceOutputs.createResourcesZip(shrunkResources, resourceFiles.resolve("assets"), options.shrunkResources, false);
}
if (options.rTxtOutput != null) {
AndroidResourceOutputs.copyRToOutput(generatedSources, options.rTxtOutput, options.packageType == VariantType.LIBRARY);
}
logger.fine(String.format("Packing resources finished at %sms", timer.elapsed(TimeUnit.MILLISECONDS)));
} catch (Exception e) {
logger.log(Level.SEVERE, "Error shrinking resources", e);
throw e;
} finally {
resourceProcessor.shutdown();
}
}
Aggregations