Loading Ravenwood.bp +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ java_genrule { "@$(location ravenwood/ravenwood-standard-options.txt) " + "--debug-log $(location hoststubgen_framework-minus-apex.log) " + "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " + "--out-impl-jar $(location ravenwood.jar) " + Loading @@ -56,6 +57,7 @@ java_genrule { "hoststubgen_dump.txt", "hoststubgen_framework-minus-apex.log", "hoststubgen_framework-minus-apex_stats.csv", ], visibility: ["//visibility:private"], } Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +18 −4 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import java.util.zip.ZipOutputStream class HostStubGen(val options: HostStubGenOptions) { fun run() { val errors = HostStubGenErrors() val stats = HostStubGenStats() // Load all classes. val allClasses = loadClassStructures(options.inJar.get) Loading Loading @@ -80,7 +81,14 @@ class HostStubGen(val options: HostStubGenOptions) { options.enableClassChecker.get, allClasses, errors, stats, ) // Dump statistics, if specified. options.statsFile.ifSet { PrintWriter(it).use { pw -> stats.dump(pw) } log.i("Dump file created at $it") } } /** Loading Loading @@ -237,6 +245,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { log.i("Converting %s into [stub: %s, impl: %s] ...", inJar, outStubJar, outImplJar) log.i("ASM CheckClassAdapter is %s", if (enableChecker) "enabled" else "disabled") Loading @@ -254,7 +263,8 @@ class HostStubGen(val options: HostStubGenOptions) { while (inEntries.hasMoreElements()) { val entry = inEntries.nextElement() convertSingleEntry(inZip, entry, stubOutStream, implOutStream, filter, packageRedirector, enableChecker, classes, errors) filter, packageRedirector, enableChecker, classes, errors, stats) } log.i("Converted all entries.") } Loading Loading @@ -287,6 +297,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { log.d("Entry: %s", entry.name) log.withIndent { Loading @@ -300,7 +311,7 @@ class HostStubGen(val options: HostStubGenOptions) { // If it's a class, convert it. if (name.endsWith(".class")) { processSingleClass(inZip, entry, stubOutStream, implOutStream, filter, packageRedirector, enableChecker, classes, errors) packageRedirector, enableChecker, classes, errors, stats) return } Loading Loading @@ -354,6 +365,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { val classInternalName = entry.name.replaceFirst("\\.class$".toRegex(), "") val classPolicy = filter.getPolicyForClass(classInternalName) Loading @@ -370,7 +382,7 @@ class HostStubGen(val options: HostStubGenOptions) { stubOutStream.putNextEntry(newEntry) convertClass(classInternalName, /*forImpl=*/false, bis, stubOutStream, filter, packageRedirector, enableChecker, classes, errors) errors, stats) stubOutStream.closeEntry() } } Loading @@ -383,7 +395,7 @@ class HostStubGen(val options: HostStubGenOptions) { implOutStream.putNextEntry(newEntry) convertClass(classInternalName, /*forImpl=*/true, bis, implOutStream, filter, packageRedirector, enableChecker, classes, errors) errors, stats) implOutStream.closeEntry() } } Loading @@ -403,6 +415,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { val cr = ClassReader(input) Loading @@ -420,6 +433,7 @@ class HostStubGen(val options: HostStubGenOptions) { enablePostTrace = options.enablePostTrace.get, enableNonStubMethodCallDetection = options.enableNonStubMethodCallDetection.get, errors = errors, stats = stats, ) outVisitor = BaseAdapter.getVisitor(classInternalName, classes, outVisitor, filter, packageRedirector, forImpl, visitorOptions) Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +5 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,8 @@ class HostStubGenOptions( var enablePostTrace: SetOnce<Boolean> = SetOnce(false), var enableNonStubMethodCallDetection: SetOnce<Boolean> = SetOnce(false), var statsFile: SetOnce<String?> = SetOnce(null), ) { companion object { Loading Loading @@ -252,6 +254,8 @@ class HostStubGenOptions( "--verbose-log" -> setLogFile(LogLevel.Verbose, nextArg()) "--debug-log" -> setLogFile(LogLevel.Debug, nextArg()) "--stats-file" -> ret.statsFile.setNextStringArg() else -> throw ArgumentsException("Unknown option: $arg") } } catch (e: SetOnce.SetMoreThanOnceException) { Loading Loading @@ -387,6 +391,7 @@ class HostStubGenOptions( enablePreTrace=$enablePreTrace, enablePostTrace=$enablePostTrace, enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection, statsFile=$statsFile, } """.trimIndent() } Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt 0 → 100644 +74 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.hoststubgen import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.filters.FilterPolicyWithReason import java.io.PrintWriter open class HostStubGenStats { data class Stats( var supported: Int = 0, var total: Int = 0, val children: MutableMap<String, Stats> = mutableMapOf<String, Stats>(), ) private val stats = mutableMapOf<String, Stats>() fun onVisitPolicyForMethod(fullClassName: String, policy: FilterPolicyWithReason) { if (policy.isIgnoredForStats) return val packageName = resolvePackageName(fullClassName) val className = resolveClassName(fullClassName) val packageStats = stats.getOrPut(packageName) { Stats() } val classStats = packageStats.children.getOrPut(className) { Stats() } if (policy.policy.isSupported) { packageStats.supported += 1 classStats.supported += 1 } packageStats.total += 1 classStats.total += 1 } fun dump(pw: PrintWriter) { pw.printf("PackageName,ClassName,SupportedMethods,TotalMethods\n") stats.forEach { (packageName, packageStats) -> if (packageStats.supported > 0) { packageStats.children.forEach { (className, classStats) -> pw.printf("%s,%s,%d,%d\n", packageName, className, classStats.supported, classStats.total) } } } } private fun resolvePackageName(fullClassName: String): String { val start = fullClassName.lastIndexOf('/') return fullClassName.substring(0, start).toHumanReadableClassName() } private fun resolveClassName(fullClassName: String): String { val start = fullClassName.lastIndexOf('/') val end = fullClassName.indexOf('$') if (end == -1) { return fullClassName.substring(start + 1) } else { return fullClassName.substring(start + 1, end) } } } tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt +11 −1 Original line number Diff line number Diff line Loading @@ -111,6 +111,16 @@ enum class FilterPolicy { } } /** Returns whether a policy is considered supported. */ val isSupported: Boolean get() { return when (this) { // TODO: handle native method with no substitution as being unsupported Stub, StubClass, Keep, KeepClass, SubstituteAndStub, SubstituteAndKeep -> true else -> false } } fun getSubstitutionBasePolicy(): FilterPolicy { return when (this) { SubstituteAndKeep -> Keep Loading Loading
Ravenwood.bp +2 −0 Original line number Diff line number Diff line Loading @@ -33,6 +33,7 @@ java_genrule { "@$(location ravenwood/ravenwood-standard-options.txt) " + "--debug-log $(location hoststubgen_framework-minus-apex.log) " + "--stats-file $(location hoststubgen_framework-minus-apex_stats.csv) " + "--out-impl-jar $(location ravenwood.jar) " + Loading @@ -56,6 +57,7 @@ java_genrule { "hoststubgen_dump.txt", "hoststubgen_framework-minus-apex.log", "hoststubgen_framework-minus-apex_stats.csv", ], visibility: ["//visibility:private"], } Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +18 −4 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import java.util.zip.ZipOutputStream class HostStubGen(val options: HostStubGenOptions) { fun run() { val errors = HostStubGenErrors() val stats = HostStubGenStats() // Load all classes. val allClasses = loadClassStructures(options.inJar.get) Loading Loading @@ -80,7 +81,14 @@ class HostStubGen(val options: HostStubGenOptions) { options.enableClassChecker.get, allClasses, errors, stats, ) // Dump statistics, if specified. options.statsFile.ifSet { PrintWriter(it).use { pw -> stats.dump(pw) } log.i("Dump file created at $it") } } /** Loading Loading @@ -237,6 +245,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { log.i("Converting %s into [stub: %s, impl: %s] ...", inJar, outStubJar, outImplJar) log.i("ASM CheckClassAdapter is %s", if (enableChecker) "enabled" else "disabled") Loading @@ -254,7 +263,8 @@ class HostStubGen(val options: HostStubGenOptions) { while (inEntries.hasMoreElements()) { val entry = inEntries.nextElement() convertSingleEntry(inZip, entry, stubOutStream, implOutStream, filter, packageRedirector, enableChecker, classes, errors) filter, packageRedirector, enableChecker, classes, errors, stats) } log.i("Converted all entries.") } Loading Loading @@ -287,6 +297,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { log.d("Entry: %s", entry.name) log.withIndent { Loading @@ -300,7 +311,7 @@ class HostStubGen(val options: HostStubGenOptions) { // If it's a class, convert it. if (name.endsWith(".class")) { processSingleClass(inZip, entry, stubOutStream, implOutStream, filter, packageRedirector, enableChecker, classes, errors) packageRedirector, enableChecker, classes, errors, stats) return } Loading Loading @@ -354,6 +365,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { val classInternalName = entry.name.replaceFirst("\\.class$".toRegex(), "") val classPolicy = filter.getPolicyForClass(classInternalName) Loading @@ -370,7 +382,7 @@ class HostStubGen(val options: HostStubGenOptions) { stubOutStream.putNextEntry(newEntry) convertClass(classInternalName, /*forImpl=*/false, bis, stubOutStream, filter, packageRedirector, enableChecker, classes, errors) errors, stats) stubOutStream.closeEntry() } } Loading @@ -383,7 +395,7 @@ class HostStubGen(val options: HostStubGenOptions) { implOutStream.putNextEntry(newEntry) convertClass(classInternalName, /*forImpl=*/true, bis, implOutStream, filter, packageRedirector, enableChecker, classes, errors) errors, stats) implOutStream.closeEntry() } } Loading @@ -403,6 +415,7 @@ class HostStubGen(val options: HostStubGenOptions) { enableChecker: Boolean, classes: ClassNodes, errors: HostStubGenErrors, stats: HostStubGenStats, ) { val cr = ClassReader(input) Loading @@ -420,6 +433,7 @@ class HostStubGen(val options: HostStubGenOptions) { enablePostTrace = options.enablePostTrace.get, enableNonStubMethodCallDetection = options.enableNonStubMethodCallDetection.get, errors = errors, stats = stats, ) outVisitor = BaseAdapter.getVisitor(classInternalName, classes, outVisitor, filter, packageRedirector, forImpl, visitorOptions) Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +5 −0 Original line number Diff line number Diff line Loading @@ -108,6 +108,8 @@ class HostStubGenOptions( var enablePostTrace: SetOnce<Boolean> = SetOnce(false), var enableNonStubMethodCallDetection: SetOnce<Boolean> = SetOnce(false), var statsFile: SetOnce<String?> = SetOnce(null), ) { companion object { Loading Loading @@ -252,6 +254,8 @@ class HostStubGenOptions( "--verbose-log" -> setLogFile(LogLevel.Verbose, nextArg()) "--debug-log" -> setLogFile(LogLevel.Debug, nextArg()) "--stats-file" -> ret.statsFile.setNextStringArg() else -> throw ArgumentsException("Unknown option: $arg") } } catch (e: SetOnce.SetMoreThanOnceException) { Loading Loading @@ -387,6 +391,7 @@ class HostStubGenOptions( enablePreTrace=$enablePreTrace, enablePostTrace=$enablePostTrace, enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection, statsFile=$statsFile, } """.trimIndent() } Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt 0 → 100644 +74 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.hoststubgen import com.android.hoststubgen.asm.toHumanReadableClassName import com.android.hoststubgen.filters.FilterPolicyWithReason import java.io.PrintWriter open class HostStubGenStats { data class Stats( var supported: Int = 0, var total: Int = 0, val children: MutableMap<String, Stats> = mutableMapOf<String, Stats>(), ) private val stats = mutableMapOf<String, Stats>() fun onVisitPolicyForMethod(fullClassName: String, policy: FilterPolicyWithReason) { if (policy.isIgnoredForStats) return val packageName = resolvePackageName(fullClassName) val className = resolveClassName(fullClassName) val packageStats = stats.getOrPut(packageName) { Stats() } val classStats = packageStats.children.getOrPut(className) { Stats() } if (policy.policy.isSupported) { packageStats.supported += 1 classStats.supported += 1 } packageStats.total += 1 classStats.total += 1 } fun dump(pw: PrintWriter) { pw.printf("PackageName,ClassName,SupportedMethods,TotalMethods\n") stats.forEach { (packageName, packageStats) -> if (packageStats.supported > 0) { packageStats.children.forEach { (className, classStats) -> pw.printf("%s,%s,%d,%d\n", packageName, className, classStats.supported, classStats.total) } } } } private fun resolvePackageName(fullClassName: String): String { val start = fullClassName.lastIndexOf('/') return fullClassName.substring(0, start).toHumanReadableClassName() } private fun resolveClassName(fullClassName: String): String { val start = fullClassName.lastIndexOf('/') val end = fullClassName.indexOf('$') if (end == -1) { return fullClassName.substring(start + 1) } else { return fullClassName.substring(start + 1, end) } } }
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt +11 −1 Original line number Diff line number Diff line Loading @@ -111,6 +111,16 @@ enum class FilterPolicy { } } /** Returns whether a policy is considered supported. */ val isSupported: Boolean get() { return when (this) { // TODO: handle native method with no substitution as being unsupported Stub, StubClass, Keep, KeepClass, SubstituteAndStub, SubstituteAndKeep -> true else -> false } } fun getSubstitutionBasePolicy(): FilterPolicy { return when (this) { SubstituteAndKeep -> Keep Loading