Loading tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java +55 −10 Original line number Diff line number Diff line Loading @@ -38,6 +38,10 @@ public class HostTestUtils { private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv( "HOSTTEST_SKIP_METHOD_LOG")); /** If true, we won't print class load log. */ private static final boolean SKIP_CLASS_LOG = "1".equals(System.getenv( "HOSTTEST_SKIP_CLASS_LOG")); /** If true, we won't perform non-stub method direct call check. */ private static final boolean SKIP_NON_STUB_METHOD_CHECK = "1".equals(System.getenv( "HOSTTEST_SKIP_NON_STUB_METHOD_CHECK")); Loading @@ -57,17 +61,34 @@ public class HostTestUtils { } /** * Called from methods with FilterPolicy.Log. * Trampoline method for method-call-hook. */ public static void callMethodCallHook( Class<?> methodClass, String methodName, String methodDescriptor, String callbackMethod ) { callStaticMethodByName(callbackMethod, methodClass, methodName, methodDescriptor); } /** * I can be used as * {@code --default-method-call-hook * com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall}. * * It logs every single methods called. */ public static void logMethodCall( String methodClass, Class<?> methodClass, String methodName, String methodDescriptor ) { if (SKIP_METHOD_LOG) { return; } logPrintStream.println("# " + methodClass + "." + methodName + methodDescriptor); logPrintStream.println("# method called: " + methodClass.getCanonicalName() + "." + methodName + methodDescriptor); } private static final StackWalker sStackWalker = Loading Loading @@ -146,15 +167,19 @@ public class HostTestUtils { logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName() + " calling hook " + callbackMethod); callStaticMethodByName(callbackMethod, loadedClass); } private static void callStaticMethodByName(String classAndMethodName, Object... args) { // Forward the call to callbackMethod. final int lastPeriod = callbackMethod.lastIndexOf("."); final String className = callbackMethod.substring(0, lastPeriod); final String methodName = callbackMethod.substring(lastPeriod + 1); final int lastPeriod = classAndMethodName.lastIndexOf("."); final String className = classAndMethodName.substring(0, lastPeriod); final String methodName = classAndMethodName.substring(lastPeriod + 1); if (lastPeriod < 0 || className.isEmpty() || methodName.isEmpty()) { throw new HostTestException(String.format( "Unable to find class load hook: malformed method name \"%s\"", callbackMethod)); classAndMethodName)); } Class<?> clazz = null; Loading @@ -169,13 +194,19 @@ public class HostTestUtils { "Unable to find class load hook: Class %s must be public", className)); } Class<?>[] argTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { argTypes[i] = args[i].getClass(); } Method method = null; try { method = clazz.getMethod(methodName, Class.class); method = clazz.getMethod(methodName, argTypes); } catch (Exception e) { throw new HostTestException(String.format( "Unable to find class load hook: class %s doesn't have method %s" + " (method must take exactly one parameter of type Class, and public static)", + " (method must take exactly one parameter of type Class," + " and public static)", className, methodName), e); } Loading @@ -186,7 +217,7 @@ public class HostTestUtils { methodName, className)); } try { method.invoke(null, loadedClass); method.invoke(null, args); } catch (Exception e) { throw new HostTestException(String.format( "Unable to invoke class load hook %s.%s", Loading @@ -194,4 +225,18 @@ public class HostTestUtils { methodName), e); } } /** * I can be used as * {@code --default-class-load-hook * com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded}. * * It logs every loaded class. */ public static void logClassLoaded(Class<?> clazz) { if (SKIP_CLASS_LOG) { return; } logPrintStream.println("# class loaded: " + clazz.getCanonicalName()); } } tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt +4 −2 Original line number Diff line number Diff line Loading @@ -6,8 +6,10 @@ --enable-non-stub-method-check # --no-non-stub-method-check # --enable-method-logging #--default-method-call-hook # com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall #--default-class-load-hook # com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded # Standard annotations. # Note, each line is a single argument, so we need newlines after each `--xxx-annotation`. Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +21 −13 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.hoststubgen import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.filters.AnnotationBasedFilter import com.android.hoststubgen.filters.DefaultHookInjectingFilter import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter import com.android.hoststubgen.filters.ConstantFilter import com.android.hoststubgen.filters.FilterPolicy Loading Loading @@ -156,7 +157,14 @@ class HostStubGen(val options: HostStubGenOptions) { // This is used when a member (methods, fields, nested classes) don't get any polices // from upper filters. e.g. when a method has no annotations, then this filter will apply // the class-wide policy, if any. (if not, we'll fall back to the above filter.) val classWidePropagator = ClassWidePolicyPropagatingFilter(filter) filter = ClassWidePolicyPropagatingFilter(filter) // Inject default hooks from options. filter = DefaultHookInjectingFilter( options.defaultClassLoadHook, options.defaultMethodCallHook, filter ) // Next, Java annotation based filter. filter = AnnotationBasedFilter( Loading @@ -171,7 +179,7 @@ class HostStubGen(val options: HostStubGenOptions) { options.substituteAnnotations, options.nativeSubstituteAnnotations, options.classLoadHookAnnotations, classWidePropagator filter ) // Next, "text based" filter, which allows to override polices without touching Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +11 −6 Original line number Diff line number Diff line Loading @@ -48,6 +48,9 @@ class HostStubGenOptions( var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(), var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(), var defaultClassLoadHook: String? = null, var defaultMethodCallHook: String? = null, var intersectStubJars: MutableSet<String> = mutableSetOf(), var policyOverrideFile: String? = null, Loading @@ -63,8 +66,6 @@ class HostStubGenOptions( var enablePreTrace: Boolean = false, var enablePostTrace: Boolean = false, var enableMethodLogging: Boolean = false, var enableNonStubMethodCallDetection: Boolean = true, ) { companion object { Loading Loading @@ -151,6 +152,12 @@ class HostStubGenOptions( ret.classLoadHookAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg)) "--default-class-load-hook" -> ret.defaultClassLoadHook = ai.nextArgRequired(arg) "--default-method-call-hook" -> ret.defaultMethodCallHook = ai.nextArgRequired(arg) "--intersect-stub-jar" -> ret.intersectStubJars += ai.nextArgRequired(arg).ensureFileExists() Loading @@ -167,9 +174,6 @@ class HostStubGenOptions( "--enable-post-trace" -> ret.enablePostTrace = true "--no-post-trace" -> ret.enablePostTrace = false "--enable-method-logging" -> ret.enableMethodLogging = true "--no-method-logging" -> ret.enableMethodLogging = false "--enable-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = true "--no-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = false Loading Loading @@ -290,6 +294,8 @@ class HostStubGenOptions( substituteAnnotations=$substituteAnnotations, nativeSubstituteAnnotations=$nativeSubstituteAnnotations, classLoadHookAnnotations=$classLoadHookAnnotations, defaultClassLoadHook=$defaultClassLoadHook, defaultMethodCallHook=$defaultMethodCallHook, intersectStubJars=$intersectStubJars, policyOverrideFile=$policyOverrideFile, defaultPolicy=$defaultPolicy, Loading @@ -299,7 +305,6 @@ class HostStubGenOptions( enableClassChecker=$enableClassChecker, enablePreTrace=$enablePreTrace, enablePostTrace=$enablePostTrace, enableMethodLogging=$enableMethodLogging, enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection, } """.trimIndent() Loading tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt +20 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,23 @@ fun normalizeTextLine(s: String): String { // Remove surrounding whitespace. return uncommented.trim() } fun <T> addLists(a: List<T>, b: List<T>): List<T> { if (a.isEmpty()) { return b } if (b.isEmpty()) { return a } return a + b } fun <T> addNonNullElement(a: List<T>, b: T?): List<T> { if (b == null) { return a } if (a.isEmpty()) { return listOf(b) } return a + b } No newline at end of file Loading
tools/hoststubgen/hoststubgen/helper-runtime-src/com/android/hoststubgen/hosthelper/HostTestUtils.java +55 −10 Original line number Diff line number Diff line Loading @@ -38,6 +38,10 @@ public class HostTestUtils { private static final boolean SKIP_METHOD_LOG = "1".equals(System.getenv( "HOSTTEST_SKIP_METHOD_LOG")); /** If true, we won't print class load log. */ private static final boolean SKIP_CLASS_LOG = "1".equals(System.getenv( "HOSTTEST_SKIP_CLASS_LOG")); /** If true, we won't perform non-stub method direct call check. */ private static final boolean SKIP_NON_STUB_METHOD_CHECK = "1".equals(System.getenv( "HOSTTEST_SKIP_NON_STUB_METHOD_CHECK")); Loading @@ -57,17 +61,34 @@ public class HostTestUtils { } /** * Called from methods with FilterPolicy.Log. * Trampoline method for method-call-hook. */ public static void callMethodCallHook( Class<?> methodClass, String methodName, String methodDescriptor, String callbackMethod ) { callStaticMethodByName(callbackMethod, methodClass, methodName, methodDescriptor); } /** * I can be used as * {@code --default-method-call-hook * com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall}. * * It logs every single methods called. */ public static void logMethodCall( String methodClass, Class<?> methodClass, String methodName, String methodDescriptor ) { if (SKIP_METHOD_LOG) { return; } logPrintStream.println("# " + methodClass + "." + methodName + methodDescriptor); logPrintStream.println("# method called: " + methodClass.getCanonicalName() + "." + methodName + methodDescriptor); } private static final StackWalker sStackWalker = Loading Loading @@ -146,15 +167,19 @@ public class HostTestUtils { logPrintStream.println("! Class loaded: " + loadedClass.getCanonicalName() + " calling hook " + callbackMethod); callStaticMethodByName(callbackMethod, loadedClass); } private static void callStaticMethodByName(String classAndMethodName, Object... args) { // Forward the call to callbackMethod. final int lastPeriod = callbackMethod.lastIndexOf("."); final String className = callbackMethod.substring(0, lastPeriod); final String methodName = callbackMethod.substring(lastPeriod + 1); final int lastPeriod = classAndMethodName.lastIndexOf("."); final String className = classAndMethodName.substring(0, lastPeriod); final String methodName = classAndMethodName.substring(lastPeriod + 1); if (lastPeriod < 0 || className.isEmpty() || methodName.isEmpty()) { throw new HostTestException(String.format( "Unable to find class load hook: malformed method name \"%s\"", callbackMethod)); classAndMethodName)); } Class<?> clazz = null; Loading @@ -169,13 +194,19 @@ public class HostTestUtils { "Unable to find class load hook: Class %s must be public", className)); } Class<?>[] argTypes = new Class[args.length]; for (int i = 0; i < args.length; i++) { argTypes[i] = args[i].getClass(); } Method method = null; try { method = clazz.getMethod(methodName, Class.class); method = clazz.getMethod(methodName, argTypes); } catch (Exception e) { throw new HostTestException(String.format( "Unable to find class load hook: class %s doesn't have method %s" + " (method must take exactly one parameter of type Class, and public static)", + " (method must take exactly one parameter of type Class," + " and public static)", className, methodName), e); } Loading @@ -186,7 +217,7 @@ public class HostTestUtils { methodName, className)); } try { method.invoke(null, loadedClass); method.invoke(null, args); } catch (Exception e) { throw new HostTestException(String.format( "Unable to invoke class load hook %s.%s", Loading @@ -194,4 +225,18 @@ public class HostTestUtils { methodName), e); } } /** * I can be used as * {@code --default-class-load-hook * com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded}. * * It logs every loaded class. */ public static void logClassLoaded(Class<?> clazz) { if (SKIP_CLASS_LOG) { return; } logPrintStream.println("# class loaded: " + clazz.getCanonicalName()); } }
tools/hoststubgen/hoststubgen/hoststubgen-standard-options.txt +4 −2 Original line number Diff line number Diff line Loading @@ -6,8 +6,10 @@ --enable-non-stub-method-check # --no-non-stub-method-check # --enable-method-logging #--default-method-call-hook # com.android.hoststubgen.hosthelper.HostTestUtils.logMethodCall #--default-class-load-hook # com.android.hoststubgen.hosthelper.HostTestUtils.logClassLoaded # Standard annotations. # Note, each line is a single argument, so we need newlines after each `--xxx-annotation`. Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt +21 −13 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.hoststubgen import com.android.hoststubgen.asm.ClassNodes import com.android.hoststubgen.filters.AnnotationBasedFilter import com.android.hoststubgen.filters.DefaultHookInjectingFilter import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter import com.android.hoststubgen.filters.ConstantFilter import com.android.hoststubgen.filters.FilterPolicy Loading Loading @@ -156,7 +157,14 @@ class HostStubGen(val options: HostStubGenOptions) { // This is used when a member (methods, fields, nested classes) don't get any polices // from upper filters. e.g. when a method has no annotations, then this filter will apply // the class-wide policy, if any. (if not, we'll fall back to the above filter.) val classWidePropagator = ClassWidePolicyPropagatingFilter(filter) filter = ClassWidePolicyPropagatingFilter(filter) // Inject default hooks from options. filter = DefaultHookInjectingFilter( options.defaultClassLoadHook, options.defaultMethodCallHook, filter ) // Next, Java annotation based filter. filter = AnnotationBasedFilter( Loading @@ -171,7 +179,7 @@ class HostStubGen(val options: HostStubGenOptions) { options.substituteAnnotations, options.nativeSubstituteAnnotations, options.classLoadHookAnnotations, classWidePropagator filter ) // Next, "text based" filter, which allows to override polices without touching Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt +11 −6 Original line number Diff line number Diff line Loading @@ -48,6 +48,9 @@ class HostStubGenOptions( var nativeSubstituteAnnotations: MutableSet<String> = mutableSetOf(), var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(), var defaultClassLoadHook: String? = null, var defaultMethodCallHook: String? = null, var intersectStubJars: MutableSet<String> = mutableSetOf(), var policyOverrideFile: String? = null, Loading @@ -63,8 +66,6 @@ class HostStubGenOptions( var enablePreTrace: Boolean = false, var enablePostTrace: Boolean = false, var enableMethodLogging: Boolean = false, var enableNonStubMethodCallDetection: Boolean = true, ) { companion object { Loading Loading @@ -151,6 +152,12 @@ class HostStubGenOptions( ret.classLoadHookAnnotations += ensureUniqueAnnotation(ai.nextArgRequired(arg)) "--default-class-load-hook" -> ret.defaultClassLoadHook = ai.nextArgRequired(arg) "--default-method-call-hook" -> ret.defaultMethodCallHook = ai.nextArgRequired(arg) "--intersect-stub-jar" -> ret.intersectStubJars += ai.nextArgRequired(arg).ensureFileExists() Loading @@ -167,9 +174,6 @@ class HostStubGenOptions( "--enable-post-trace" -> ret.enablePostTrace = true "--no-post-trace" -> ret.enablePostTrace = false "--enable-method-logging" -> ret.enableMethodLogging = true "--no-method-logging" -> ret.enableMethodLogging = false "--enable-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = true "--no-non-stub-method-check" -> ret.enableNonStubMethodCallDetection = false Loading Loading @@ -290,6 +294,8 @@ class HostStubGenOptions( substituteAnnotations=$substituteAnnotations, nativeSubstituteAnnotations=$nativeSubstituteAnnotations, classLoadHookAnnotations=$classLoadHookAnnotations, defaultClassLoadHook=$defaultClassLoadHook, defaultMethodCallHook=$defaultMethodCallHook, intersectStubJars=$intersectStubJars, policyOverrideFile=$policyOverrideFile, defaultPolicy=$defaultPolicy, Loading @@ -299,7 +305,6 @@ class HostStubGenOptions( enableClassChecker=$enableClassChecker, enablePreTrace=$enablePreTrace, enablePostTrace=$enablePostTrace, enableMethodLogging=$enableMethodLogging, enableNonStubMethodCallDetection=$enableNonStubMethodCallDetection, } """.trimIndent() Loading
tools/hoststubgen/hoststubgen/src/com/android/hoststubgen/Utils.kt +20 −0 Original line number Diff line number Diff line Loading @@ -31,3 +31,23 @@ fun normalizeTextLine(s: String): String { // Remove surrounding whitespace. return uncommented.trim() } fun <T> addLists(a: List<T>, b: List<T>): List<T> { if (a.isEmpty()) { return b } if (b.isEmpty()) { return a } return a + b } fun <T> addNonNullElement(a: List<T>, b: T?): List<T> { if (b == null) { return a } if (a.isEmpty()) { return listOf(b) } return a + b } No newline at end of file