blob: 05b8e2f1683620effbc383f50c12dbf457c1ac6b [file] [log] [blame]
// Copyright (c) 2024, 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.metadata.impl;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.keepanno.annotations.AnnotationPattern;
import com.android.tools.r8.keepanno.annotations.FieldAccessFlags;
import com.android.tools.r8.keepanno.annotations.KeepConstraint;
import com.android.tools.r8.keepanno.annotations.KeepItemKind;
import com.android.tools.r8.keepanno.annotations.UsedByReflection;
import com.android.tools.r8.metadata.R8StatsMetadata;
import com.android.tools.r8.shaking.KeepInfo;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
@UsedByReflection(
description = "Keep and preserve @SerializedName for correct (de)serialization",
constraints = {KeepConstraint.LOOKUP},
constrainAnnotations = @AnnotationPattern(constant = SerializedName.class),
kind = KeepItemKind.CLASS_AND_FIELDS,
fieldAccess = {FieldAccessFlags.PRIVATE},
fieldAnnotatedByClassConstant = SerializedName.class)
public class R8StatsMetadataImpl implements R8StatsMetadata {
@Expose
@SerializedName("noObfuscationPercentage")
private final float noObfuscationPercentage;
@Expose
@SerializedName("noOptimizationPercentage")
private final float noOptimizationPercentage;
@Expose
@SerializedName("noShrinkingPercentage")
private final float noShrinkingPercentage;
private R8StatsMetadataImpl(
float noObfuscationPercentage, float noOptimizationPercentage, float noShrinkingPercentage) {
this.noObfuscationPercentage = noObfuscationPercentage;
this.noOptimizationPercentage = noOptimizationPercentage;
this.noShrinkingPercentage = noShrinkingPercentage;
}
public static R8StatsMetadataImpl create(AppView<? extends AppInfoWithClassHierarchy> appView) {
Counters counters = Counters.create(appView);
return new R8StatsMetadataImpl(
counters.getNoObfuscationPercentage(),
counters.getNoOptimizationPercentage(),
counters.getNoShrinkingPercentage());
}
@Override
public float getNoObfuscationPercentage() {
return noObfuscationPercentage;
}
@Override
public float getNoOptimizationPercentage() {
return noOptimizationPercentage;
}
@Override
public float getNoShrinkingPercentage() {
return noShrinkingPercentage;
}
private static class Counters {
private int itemsCount = 0;
private int noObfuscationCount = 0;
private int noOptimizationCount = 0;
private int noShrinkingCount = 0;
private Counters() {}
static Counters create(AppView<? extends AppInfoWithClassHierarchy> appView) {
Counters counters = new Counters();
for (DexProgramClass clazz : appView.appInfo().classes()) {
counters.add(appView, clazz);
clazz.forEachProgramMember(member -> counters.add(appView, member));
}
return counters;
}
private void add(
AppView<? extends AppInfoWithClassHierarchy> appView, ProgramDefinition definition) {
KeepInfo<?, ?> keepInfo = appView.getKeepInfo(definition);
InternalOptions options = appView.options();
itemsCount++;
noObfuscationCount += BooleanUtils.intValue(!keepInfo.isMinificationAllowed(options));
noOptimizationCount += BooleanUtils.intValue(!keepInfo.isOptimizationAllowed(options));
noShrinkingCount += BooleanUtils.intValue(!keepInfo.isShrinkingAllowed(options));
}
float getNoObfuscationPercentage() {
return toPercentageWithTwoDecimals(noObfuscationCount);
}
float getNoOptimizationPercentage() {
return toPercentageWithTwoDecimals(noOptimizationCount);
}
float getNoShrinkingPercentage() {
return toPercentageWithTwoDecimals(noShrinkingCount);
}
float toPercentageWithTwoDecimals(int count) {
// Multiply by 100 twice to get percentage with two decimals.
float number = (float) (count * 100 * 100) / itemsCount;
return (float) Math.round(number) / 100;
}
}
}