diff options
author | 2025-03-21 13:43:43 -0700 | |
---|---|---|
committer | 2025-03-21 16:27:35 -0700 | |
commit | b993f5177d5fe015a1159602d8576946bff90aec (patch) | |
tree | 784f0a1563b3e2415fe17587795617876cbb1521 | |
parent | 364d006c19c6b43d5e1c7cccebf8aeeae6e2a6f1 (diff) |
Update stats CSV for the new dashboard
Created a new dashboard (with the same go link, go/ravenwood-stats)
which is a pivot table that supports drill-down into methods.
Updated the CSV to support it.
Bug: 402797626
Test: Manual test with importing data and browsing go/ravenwood-stats
Flag: EXEMPT host tool change only
Change-Id: Ia23c0fae7fc6a096565e9902fafab0a4a3ea3067
5 files changed, 74 insertions, 83 deletions
diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh index c2bf8d82e272..3b323411fd91 100755 --- a/ravenwood/scripts/ravenwood-stats-collector.sh +++ b/ravenwood/scripts/ravenwood-stats-collector.sh @@ -114,7 +114,7 @@ collect_apis() { collect_stats $stats " (import it as 'ravenwood_stats')" -collect_apis $apis " (import it as 'ravenwood_supported_apis')" +collect_apis $apis " (import it as 'ravenwood_supported_apis2')" cp *keep_all.txt $keep_all_dir echo "Keep all files created at:" @@ -122,4 +122,4 @@ find $keep_all_dir -type f cp *dump.txt $dump_dir echo "Dump files created at:" -find $dump_dir -type f
\ No newline at end of file +find $dump_dir -type f diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt index ea8c25b6833c..4cfc205d5912 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt @@ -24,13 +24,9 @@ import org.objectweb.asm.Opcodes import java.io.PrintWriter /** - * TODO This is for the legacy API coverage stats CSV that shows how many APIs are "supported" - * in each class with some heuristics. We created [ApiDumper] later, which dumpps all methods - * with the "supported" status. We should update the coverage dashboard to use the [ApiDumper] - * output and remove this class, once we port all the heuristics to [ApiDumper] as well. - * (For example, this class ignores non-public and/or abstract methods, but [ApiDumper] shows - * all of them in the same way. We should probably mark them as "Boring" or maybe "Ignore" - * for [ApiDumper]) + * This class is no longer used. It was used for the old ravenwood dashboard. (b/402797626) + * + * TODO: Delete the class. */ open class HostStubGenStats(val classes: ClassNodes) { data class Stats( diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt index 112ef01e20cb..741abe3df638 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt @@ -377,6 +377,10 @@ fun MethodNode.isPublic(): Boolean { return (this.access and Opcodes.ACC_PUBLIC) != 0 } +fun MethodNode.isAbstract(): Boolean { + return (this.access and Opcodes.ACC_ABSTRACT) != 0 +} + fun MethodNode.isNative(): Boolean { return (this.access and Opcodes.ACC_NATIVE) != 0 } diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt index bb8cdccafaa6..6ece17ffa6c2 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt @@ -20,6 +20,8 @@ import com.android.hoststubgen.asm.CTOR_NAME import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.asm.getClassNameFromFullClassName import com.android.hoststubgen.asm.getPackageNameFromFullClassName +import com.android.hoststubgen.asm.isAbstract +import com.android.hoststubgen.asm.isPublic import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.csvEscape import com.android.hoststubgen.filters.FilterPolicy @@ -27,8 +29,8 @@ import com.android.hoststubgen.filters.FilterPolicyWithReason import com.android.hoststubgen.filters.OutputFilter import com.android.hoststubgen.filters.StatsLabel import com.android.hoststubgen.log -import org.objectweb.asm.Type import org.objectweb.asm.tree.ClassNode +import org.objectweb.asm.tree.MethodNode import java.io.PrintWriter /** @@ -45,19 +47,14 @@ class ApiDumper( val descriptor: String, ) - private val javaStandardApiPolicy = FilterPolicy.Keep.withReason( - "Java standard API", - StatsLabel.Supported, - ) - private val shownMethods = mutableSetOf<MethodKey>() /** * Do the dump. */ fun dump() { - pw.printf("PackageName,ClassName,FromSubclass,DeclareClass,MethodName,MethodDesc" + - ",Supported,Policy,Reason,SupportedLabel\n") + pw.printf("PackageName,ClassName,Inherited,DeclareClass,MethodName,MethodDesc" + + ",Supported,Policy,Reason,Boring\n") classes.forEach { classNode -> shownMethods.clear() @@ -72,32 +69,21 @@ class ApiDumper( methodClassName: String, methodName: String, methodDesc: String, - classPolicy: FilterPolicyWithReason, + computedMethodLabel: StatsLabel, methodPolicy: FilterPolicyWithReason, ) { - if (methodPolicy.statsLabel == StatsLabel.Ignored) { - return - } - // Label hack -- if the method is supported, but the class is boring, then the - // method is boring too. - var methodLabel = methodPolicy.statsLabel - if (methodLabel == StatsLabel.SupportedButBoring - && classPolicy.statsLabel == StatsLabel.SupportedButBoring) { - methodLabel = classPolicy.statsLabel - } - pw.printf( - "%s,%s,%d,%s,%s,%s,%d,%s,%s,%s\n", + "%s,%s,%d,%s,%s,%s,%d,%s,%s,%d\n", csvEscape(classPackage), csvEscape(className), if (isSuperClass) { 1 } else { 0 }, csvEscape(methodClassName), csvEscape(methodName), - csvEscape(methodDesc), - methodLabel.statValue, + csvEscape(methodName + methodDesc), + if (computedMethodLabel.isSupported) { 1 } else { 0 }, methodPolicy.policy, csvEscape(methodPolicy.reason), - methodLabel, + if (computedMethodLabel == StatsLabel.SupportedButBoring) { 1 } else { 0 }, ) } @@ -111,6 +97,42 @@ class ApiDumper( return false } + private fun getClassLabel(cn: ClassNode, classPolicy: FilterPolicyWithReason): StatsLabel { + if (!classPolicy.statsLabel.isSupported) { + return classPolicy.statsLabel + } + if (cn.name.endsWith("Proto") + || cn.name.endsWith("ProtoEnums") + || cn.name.endsWith("LogTags") + || cn.name.endsWith("StatsLog")) { + return StatsLabel.SupportedButBoring + } + + return classPolicy.statsLabel + } + + private fun resolveMethodLabel( + mn: MethodNode, + methodPolicy: FilterPolicyWithReason, + classLabel: StatsLabel, + ): StatsLabel { + // Class label will override the method label + if (!classLabel.isSupported) { + return classLabel + } + // If method isn't supported, just use it as-is. + if (!methodPolicy.statsLabel.isSupported) { + return methodPolicy.statsLabel + } + + // Use heuristics to override the label. + if (!mn.isPublic() || mn.isAbstract()) { + return StatsLabel.SupportedButBoring + } + + return methodPolicy.statsLabel + } + private fun dump( dumpClass: ClassNode, methodClass: ClassNode, @@ -120,9 +142,11 @@ class ApiDumper( return } log.d("Class ${dumpClass.name} -- policy $classPolicy") + val classLabel = getClassLabel(dumpClass, classPolicy) - val pkg = getPackageNameFromFullClassName(dumpClass.name).toHumanReadableClassName() - val cls = getClassNameFromFullClassName(dumpClass.name).toHumanReadableClassName() + val humanReadableClassName = dumpClass.name.toHumanReadableClassName() + val pkg = getPackageNameFromFullClassName(humanReadableClassName) + val cls = getClassNameFromFullClassName(humanReadableClassName) val isSuperClass = dumpClass != methodClass @@ -150,8 +174,12 @@ class ApiDumper( val renameTo = filter.getRenameTo(methodClass.name, method.name, method.desc) - dumpMethod(pkg, cls, isSuperClass, methodClass.name.toHumanReadableClassName(), - renameTo ?: method.name, method.desc, classPolicy, methodPolicy) + val methodLabel = resolveMethodLabel(method, methodPolicy, classLabel) + + if (methodLabel != StatsLabel.Ignored) { + dumpMethod(pkg, cls, isSuperClass, methodClass.name.toHumanReadableClassName(), + renameTo ?: method.name, method.desc, methodLabel, methodPolicy) + } } // Dump super class methods. @@ -178,51 +206,6 @@ class ApiDumper( dump(dumpClass, methodClass) return } - - // Dump overriding methods from Java standard classes, except for the Object methods, - // which are obvious. - if (methodClassName.startsWith("java/") || methodClassName.startsWith("javax/")) { - if (methodClassName != "java/lang/Object") { - dumpStandardClass(dumpClass, methodClassName) - } - return - } log.w("Super class or interface $methodClassName (used by ${dumpClass.name}) not found.") } - - /** - * Dump methods from Java standard classes. - */ - private fun dumpStandardClass( - dumpClass: ClassNode, - methodClassName: String, - ) { - val pkg = getPackageNameFromFullClassName(dumpClass.name).toHumanReadableClassName() - val cls = getClassNameFromFullClassName(dumpClass.name).toHumanReadableClassName() - - val methodClassName = methodClassName.toHumanReadableClassName() - - try { - val clazz = Class.forName(methodClassName) - - // Method.getMethods() returns only public methods, but with inherited ones. - // Method.getDeclaredMethods() returns private methods too, but no inherited methods. - // - // Since we're only interested in public ones, just use getMethods(). - clazz.methods.forEach { method -> - val methodName = method.name - val methodDesc = Type.getMethodDescriptor(method) - - // If we already printed the method from a subclass, don't print it. - if (shownAlready(methodName, methodDesc)) { - return@forEach - } - - dumpMethod(pkg, cls, true, methodClassName, - methodName, methodDesc, javaStandardApiPolicy, javaStandardApiPolicy) - } - } catch (e: ClassNotFoundException) { - log.w("JVM type $methodClassName (used by ${dumpClass.name}) not found.") - } - } } diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt index e082bbb0a119..f135c60947b3 100644 --- a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt +++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt @@ -32,7 +32,15 @@ enum class StatsLabel(val statValue: Int, val label: String) { SupportedButBoring(1, "Boring"), /** Entry should be shown as "supported" */ - Supported(2, "Supported"), + Supported(2, "Supported"); + + val isSupported: Boolean + get() { + return when (this) { + SupportedButBoring, Supported -> true + else -> false + } + } } /** |