Home | History | Annotate | Download | only in src
      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 {
     22   void method0();
     23   void method1(String arg);
     24   void method10(String arg1, String arg2, String arg3, String arg4, String arg5,
     25                 String arg6, String arg7, String arg8, String 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
     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 
     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 
     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 
     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 
     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`.
    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`.
    118   private native Object getArgument(int arg_pos, int frame_depth);
    119 }
    120 
    121 public class Main {
    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 
    138   public static void assertEquals(Object expected, Object actual) {
    139     if (expected != actual) {
    140       throw new Error("Expected " + expected  + ", got " + actual);
    141     }
    142   }
    143 
    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