From 434d72821a6c7a62bbaf59555aa14dfc5478fa66 Mon Sep 17 00:00:00 2001 From: Makoto Onuki <omakoto@google.com> Date: Thu, 25 Apr 2024 11:03:41 -0700 Subject: [PATCH] [Ravenwood] Dump supported APIs to CSV Bug: 292141694 Test: ./ravenwood/scripts/ravenwood-stats-collector.sh and examine the generated files Change-Id: I3ea52f20ca54644f3ab724f23ae3e8f0e08e269f --- Ravenwood.bp | 28 ++++++++++ ravenwood/Android.bp | 2 + .../scripts/ravenwood-stats-collector.sh | 33 +++++++++--- .../com/android/hoststubgen/HostStubGen.kt | 6 ++- .../android/hoststubgen/HostStubGenOptions.kt | 4 ++ .../android/hoststubgen/HostStubGenStats.kt | 54 ++++++++++++++++--- .../src/com/android/hoststubgen/Utils.kt | 7 +++ 7 files changed, 118 insertions(+), 16 deletions(-) diff --git a/Ravenwood.bp b/Ravenwood.bp index 7c7c0e298f3f..74382a6e8d44 100644 --- a/Ravenwood.bp +++ b/Ravenwood.bp @@ -34,6 +34,7 @@ java_genrule { "--debug-log $(location hoststubgen_framework-minus-apex.log) " + "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " + + "--supported-api-list-file $(location hoststubgen_framework-minus-apex_apis.csv) " + "--out-impl-jar $(location ravenwood.jar) " + @@ -58,6 +59,7 @@ java_genrule { "hoststubgen_framework-minus-apex.log", "hoststubgen_framework-minus-apex_stats.csv", + "hoststubgen_framework-minus-apex_apis.csv", ], visibility: ["//visibility:private"], } @@ -90,6 +92,18 @@ genrule { ], } +genrule { + name: "framework-minus-apex.ravenwood.apis", + defaults: ["ravenwood-internal-only-visibility-genrule"], + cmd: "cp $(in) $(out)", + srcs: [ + ":framework-minus-apex.ravenwood-base{hoststubgen_framework-minus-apex_apis.csv}", + ], + out: [ + "hoststubgen_framework-minus-apex_apis.csv", + ], +} + java_library { name: "services.core-for-hoststubgen", installable: false, // host only jar. @@ -108,6 +122,7 @@ java_genrule { "--debug-log $(location hoststubgen_services.core.log) " + "--stats-file $(location hoststubgen_services.core_stats.csv) " + + "--supported-api-list-file $(location hoststubgen_services.core_apis.csv) " + "--out-impl-jar $(location ravenwood.jar) " + @@ -132,6 +147,7 @@ java_genrule { "hoststubgen_services.core.log", "hoststubgen_services.core_stats.csv", + "hoststubgen_services.core_apis.csv", ], visibility: ["//visibility:private"], } @@ -161,6 +177,18 @@ genrule { ], } +genrule { + name: "services.core.ravenwood.apis", + defaults: ["ravenwood-internal-only-visibility-genrule"], + cmd: "cp $(in) $(out)", + srcs: [ + ":services.core.ravenwood-base{hoststubgen_services.core_apis.csv}", + ], + out: [ + "hoststubgen_services.core_apis.csv", + ], +} + java_library { name: "services.core.ravenwood-jarjar", installable: false, diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp index 8905ad3273d8..33374195e674 100644 --- a/ravenwood/Android.bp +++ b/ravenwood/Android.bp @@ -163,6 +163,8 @@ sh_test_host { test_suites: ["general-tests"], data: [ ":framework-minus-apex.ravenwood.stats", + ":framework-minus-apex.ravenwood.apis", ":services.core.ravenwood.stats", + ":services.core.ravenwood.apis", ], } diff --git a/ravenwood/scripts/ravenwood-stats-collector.sh b/ravenwood/scripts/ravenwood-stats-collector.sh index 4dcaa2be5af3..b5843d0fa26b 100755 --- a/ravenwood/scripts/ravenwood-stats-collector.sh +++ b/ravenwood/scripts/ravenwood-stats-collector.sh @@ -17,8 +17,9 @@ set -e -# Output file -out=/tmp/ravenwood-stats-all.csv +# Output files +stats=/tmp/ravenwood-stats-all.csv +apis=/tmp/ravenwood-apis-all.csv # Where the input files are. path=$ANDROID_BUILD_TOP/out/host/linux-x86/testcases/ravenwood-stats-checker/x86_64/ @@ -41,12 +42,28 @@ dump() { sed -e '1d' -e "s/^/$jar,/" $file } -collect() { - echo 'Jar,PackageName,ClassName,SupportedMethods,TotalMethods' - dump "framework-minus-apex" hoststubgen_framework-minus-apex_stats.csv - dump "service.core" hoststubgen_services.core_stats.csv +collect_stats() { + local out="$1" + { + echo 'Jar,PackageName,ClassName,SupportedMethods,TotalMethods' + dump "framework-minus-apex" hoststubgen_framework-minus-apex_stats.csv + dump "service.core" hoststubgen_services.core_stats.csv + } > "$out" + + echo "Stats CVS created at $out" +} + +collect_apis() { + local out="$1" + { + echo 'Jar,PackageName,ClassName,MethodName,Descriptor' + dump "framework-minus-apex" hoststubgen_framework-minus-apex_apis.csv + dump "service.core" hoststubgen_services.core_apis.csv + } > "$out" + + echo "API CVS created at $out" } -collect >$out -echo "Full dump CVS created at $out" +collect_stats $stats +collect_apis $apis diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt index 803dc283b8c7..2f432cc7ac96 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt @@ -85,9 +85,13 @@ class HostStubGen(val options: HostStubGenOptions) { // Dump statistics, if specified. options.statsFile.ifSet { - PrintWriter(it).use { pw -> stats.dump(pw) } + PrintWriter(it).use { pw -> stats.dumpOverview(pw) } log.i("Dump file created at $it") } + options.apiListFile.ifSet { + PrintWriter(it).use { pw -> stats.dumpApis(pw) } + log.i("API list file created at $it") + } } /** diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt index 9ff798a4b5cb..e192516d334d 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt @@ -110,6 +110,8 @@ class HostStubGenOptions( var enableNonStubMethodCallDetection: SetOnce<Boolean> = SetOnce(false), var statsFile: SetOnce<String?> = SetOnce(null), + + var apiListFile: SetOnce<String?> = SetOnce(null), ) { companion object { @@ -255,6 +257,7 @@ class HostStubGenOptions( "--debug-log" -> setLogFile(LogLevel.Debug, nextArg()) "--stats-file" -> ret.statsFile.setNextStringArg() + "--supported-api-list-file" -> ret.apiListFile.setNextStringArg() else -> throw ArgumentsException("Unknown option: $arg") } @@ -392,6 +395,7 @@ class HostStubGenOptions( enablePostTrace=$enablePostTrace, enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection, statsFile=$statsFile, + apiListFile=$apiListFile, } """.trimIndent() } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt index 50518e1ccd9c..da6146911a21 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt @@ -29,8 +29,25 @@ open class HostStubGenStats { private val stats = mutableMapOf<String, Stats>() - fun onVisitPolicyForMethod(fullClassName: String, methodName: String, descriptor: String, - policy: FilterPolicyWithReason, access: Int) { + data class Api( + val fullClassName: String, + val methodName: String, + val methodDesc: String, + ) + + private val apis = mutableListOf<Api>() + + fun onVisitPolicyForMethod( + fullClassName: String, + methodName: String, + descriptor: String, + policy: FilterPolicyWithReason, + access: Int + ) { + if (policy.policy.isSupported) { + apis.add(Api(fullClassName, methodName, descriptor)) + } + // Ignore methods that aren't public if ((access and Opcodes.ACC_PUBLIC) == 0) return // Ignore methods that are abstract @@ -39,7 +56,7 @@ open class HostStubGenStats { if (policy.isIgnoredForStats) return val packageName = resolvePackageName(fullClassName) - val className = resolveClassName(fullClassName) + val className = resolveOuterClassName(fullClassName) // Ignore methods for certain generated code if (className.endsWith("Proto") @@ -60,11 +77,11 @@ open class HostStubGenStats { classStats.total += 1 } - fun dump(pw: PrintWriter) { + fun dumpOverview(pw: PrintWriter) { pw.printf("PackageName,ClassName,SupportedMethods,TotalMethods\n") - stats.forEach { (packageName, packageStats) -> + stats.toSortedMap().forEach { (packageName, packageStats) -> if (packageStats.supported > 0) { - packageStats.children.forEach { (className, classStats) -> + packageStats.children.toSortedMap().forEach { (className, classStats) -> pw.printf("%s,%s,%d,%d\n", packageName, className, classStats.supported, classStats.total) } @@ -72,12 +89,26 @@ open class HostStubGenStats { } } + fun dumpApis(pw: PrintWriter) { + pw.printf("PackageName,ClassName,MethodName,MethodDesc\n") + apis.sortedWith(compareBy({ it.fullClassName }, { it.methodName }, { it.methodDesc })) + .forEach { api -> + pw.printf( + "%s,%s,%s,%s\n", + csvEscape(resolvePackageName(api.fullClassName)), + csvEscape(resolveClassName(api.fullClassName)), + csvEscape(api.methodName), + csvEscape(api.methodDesc), + ) + } + } + private fun resolvePackageName(fullClassName: String): String { val start = fullClassName.lastIndexOf('/') return fullClassName.substring(0, start).toHumanReadableClassName() } - private fun resolveClassName(fullClassName: String): String { + private fun resolveOuterClassName(fullClassName: String): String { val start = fullClassName.lastIndexOf('/') val end = fullClassName.indexOf('$') if (end == -1) { @@ -86,4 +117,13 @@ open class HostStubGenStats { return fullClassName.substring(start + 1, end) } } + + private fun resolveClassName(fullClassName: String): String { + val pos = fullClassName.lastIndexOf('/') + if (pos == -1) { + return fullClassName + } else { + return fullClassName.substring(pos + 1) + } + } } diff --git a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt index aa63d8d9f870..10179eefcb95 100644 --- a/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt +++ b/tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt @@ -89,3 +89,10 @@ class ParseException : Exception, UserErrorException { } } } + +/** + * Escape a string for a CSV field. + */ +fun csvEscape(value: String): String { + return "\"" + value.replace("\"", "\"\"") + "\"" +} -- GitLab