1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.reflect.InvocationHandler; 18 import java.lang.reflect.Method; 19 import java.lang.reflect.Proxy; 20 21 interface TestInterface { method0()22 void method0(); method1(String arg)23 void method1(String arg); method10(String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, String arg7, String arg8, String arg9, String arg10)24 void method10(String arg1, String arg2, String arg3, String arg4, String arg5, 25 String arg6, String arg7, String arg8, String arg9, String arg10); method10Even(byte arg1, String arg2, short arg3, String arg4, int arg5, String arg6, long arg7, String arg8, double arg9, String arg10)26 void method10Even(byte arg1, String arg2, short arg3, String arg4, int arg5, 27 String arg6, long arg7, String arg8, double arg9, String arg10); 28 } 29 30 class TestInvocationHandler implements InvocationHandler { 31 @Override invoke(Object proxy, Method method, Object[] args)32 public Object invoke(Object proxy, Method method, Object[] args) { 33 // Force garbage collection to try to make `proxy` move in memory 34 // (in the case of a moving garbage collector). 35 System.gc(); 36 37 System.out.println("Proxy for " + TestInterface.class + "." + method.getName()); 38 if (method.getName().equals("method0")) { 39 testMethod0(proxy, args); 40 } else if (method.getName().equals("method1")) { 41 testMethod1(proxy, args); 42 } else if (method.getName().equals("method10")) { 43 testMethod10(proxy, args); 44 } else if (method.getName().equals("method10Even")) { 45 testMethod10Even(proxy, args); 46 } 47 return null; 48 } 49 testMethod0(Object proxy, Object[] args)50 private void testMethod0(Object proxy, Object[] args) { 51 // Get argument 0 (method target) from the proxy method frame ($Proxy0.method0 activation). 52 Object arg0 = getProxyMethodArgument(0); 53 System.out.println(" arg0: " + arg0.getClass().getName()); 54 Main.assertEquals(proxy, arg0); 55 } 56 testMethod1(Object proxy, Object[] args)57 private void testMethod1(Object proxy, Object[] args) { 58 // Get argument 0 (method target) from the proxy method frame ($Proxy0.method0 activation). 59 Object arg0 = getProxyMethodArgument(0); 60 System.out.println(" arg0: " + arg0.getClass().getName()); 61 Main.assertEquals(proxy, arg0); 62 // Get argument 1 from the proxy method frame ($Proxy0.method1 activation). 63 String arg1 = (String) getProxyMethodArgument(1); 64 System.out.println(" arg1: " + arg1.getClass().getName() + " \"" + arg1 + "\""); 65 Main.assertEquals(args[0], arg1); 66 } 67 testMethod10(Object proxy, Object[] args)68 private void testMethod10(Object proxy, Object[] args) { 69 // Get argument 0 (method target) from the proxy method frame ($Proxy0.method10 activation). 70 Object arg0 = getProxyMethodArgument(0); 71 System.out.println(" arg0: " + arg0.getClass().getName()); 72 Main.assertEquals(proxy, arg0); 73 // Get argument `i` from the proxy method frame ($Proxy0.method10 activation). 74 for (int i = 0; i < 10; ++i) { 75 int arg_pos = i + 1; 76 String arg = (String) getProxyMethodArgument(arg_pos); 77 System.out.println(" arg" + arg_pos + ": " + arg.getClass().getName() + " \"" + arg + "\""); 78 Main.assertEquals(args[i], arg); 79 } 80 } 81 testMethod10Even(Object proxy, Object[] args)82 private void testMethod10Even(Object proxy, Object[] args) { 83 // Get argument 0 (method target) from the proxy method frame ($Proxy0.method10Even 84 // activation). 85 Object arg0 = getProxyMethodArgument(0); 86 System.out.println(" arg0: " + arg0.getClass().getName()); 87 Main.assertEquals(proxy, arg0); 88 // Get argument `i` from the proxy method frame ($Proxy0.method10Even activation). 89 for (int i = 1; i < 10; i += 2) { 90 int arg_pos = i + 1; 91 String arg = (String) getProxyMethodArgument(arg_pos); 92 System.out.println(" arg" + arg_pos + ": " + arg.getClass().getName() + " \"" + arg + "\""); 93 Main.assertEquals(args[i], arg); 94 } 95 } 96 97 // Get reference argument at position `arg_pos` in proxy frame. 98 // This method should only be called from one of the 99 // `TestInvocationHandler.testMethod*` methods via `TestInvocationHandler.invoke`. getProxyMethodArgument(int arg_pos)100 private Object getProxyMethodArgument(int arg_pos) { 101 // Find proxy frame in stack (from a testMethod* method). 102 // 103 // depth method 104 // ---------------------------------------------------------------------- 105 // 0 TestInvocationHandler.getArgument (outermost frame) 106 // 1 TestInvocationHandler.getProxyMethodArgument 107 // 2 TestInvocationHandler.testMethod* 108 // 3 TestInvocationHandler.invoke 109 // 4 java.lang.reflect.Proxy.invoke 110 // -> 5 TestInterface.method* (proxy method) 111 // 6 Main.main (innermost frame) 112 // 113 int proxy_method_frame_depth = 5; 114 return getArgument(arg_pos, proxy_method_frame_depth); 115 } 116 117 // Get reference argument at position `arg_pos` in frame at depth `frame_depth`. getArgument(int arg_pos, int frame_depth)118 private native Object getArgument(int arg_pos, int frame_depth); 119 } 120 121 public class Main { main(String[] args)122 public static void main(String[] args) { 123 System.loadLibrary(args[0]); 124 125 TestInvocationHandler invocationHandler = new TestInvocationHandler(); 126 TestInterface proxy = (TestInterface) Proxy.newProxyInstance( 127 Main.class.getClassLoader(), 128 new Class<?>[] { TestInterface.class }, 129 invocationHandler); 130 System.out.println("proxy: " + proxy.getClass().getName()); 131 132 proxy.method0(); 133 proxy.method1("a"); 134 proxy.method10("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"); 135 proxy.method10Even((byte) 1, "two", (short) 3, "four", 5, "six", 7L, "eight", 9.0, "ten"); 136 } 137 assertEquals(Object expected, Object actual)138 public static void assertEquals(Object expected, Object actual) { 139 if (expected != actual) { 140 throw new Error("Expected " + expected + ", got " + actual); 141 } 142 } 143 assertEquals(String expected, String actual)144 public static void assertEquals(String expected, String actual) { 145 if (expected != actual) { 146 throw new Error("Expected \"" + expected + "\", got \"" + actual + "\""); 147 } 148 } 149 } 150