Home | History | Annotate | Download | only in util
      1 // Copyright 2018 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 package org.chromium.support_lib_boundary.util;
      5 
      6 import android.annotation.TargetApi;
      7 import android.os.Build;
      8 
      9 import java.lang.reflect.InvocationHandler;
     10 import java.lang.reflect.InvocationTargetException;
     11 import java.lang.reflect.Method;
     12 import java.lang.reflect.Proxy;
     13 
     14 /**
     15  * A set of utility methods used for calling across the support library boundary.
     16  */
     17 public class BoundaryInterfaceReflectionUtil {
     18     /**
     19      * Utility method for fetching a method from {@param delegateLoader}, with the same signature
     20      * (package + class + method name + parameters) as a given method defined in another
     21      * classloader.
     22      */
     23     public static Method dupeMethod(Method method, ClassLoader delegateLoader)
     24             throws ClassNotFoundException, NoSuchMethodException {
     25         Class<?> declaringClass =
     26                 Class.forName(method.getDeclaringClass().getName(), true, delegateLoader);
     27         Class[] otherSideParameterClasses = method.getParameterTypes();
     28         Class[] parameterClasses = new Class[otherSideParameterClasses.length];
     29         for (int n = 0; n < parameterClasses.length; n++) {
     30             Class<?> clazz = otherSideParameterClasses[n];
     31             // Primitive classes are shared between the classloaders - so we can use the same
     32             // primitive class declarations on either side. Non-primitive classes must be looked up
     33             // by name.
     34             parameterClasses[n] = clazz.isPrimitive()
     35                     ? clazz
     36                     : Class.forName(clazz.getName(), true, delegateLoader);
     37         }
     38         return declaringClass.getDeclaredMethod(method.getName(), parameterClasses);
     39     }
     40 
     41     /**
     42      * Returns an implementation of the boundary interface named clazz, by delegating method calls
     43      * to the {@link InvocationHandler} invocationHandler.
     44      */
     45     public static <T> T castToSuppLibClass(Class<T> clazz, InvocationHandler invocationHandler) {
     46         return clazz.cast(
     47                 Proxy.newProxyInstance(BoundaryInterfaceReflectionUtil.class.getClassLoader(),
     48                         new Class[] {clazz}, invocationHandler));
     49     }
     50 
     51     /**
     52      * Create an {@link java.lang.reflect.InvocationHandler} that delegates method calls to
     53      * {@param delegate}, making sure that the {@link java.lang.reflect.Method} and parameters being
     54      * passed to {@param delegate} exist in the same {@link java.lang.ClassLoader} as {@param
     55      * delegate}.
     56      */
     57     @TargetApi(Build.VERSION_CODES.KITKAT)
     58     public static InvocationHandler createInvocationHandlerFor(final Object delegate) {
     59         final ClassLoader delegateLoader = delegate.getClass().getClassLoader();
     60         return new InvocationHandler() {
     61             @Override
     62             public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
     63                 try {
     64                     return dupeMethod(method, delegateLoader).invoke(delegate, objects);
     65                 } catch (InvocationTargetException e) {
     66                     // If something went wrong, ensure we throw the original exception.
     67                     throw e.getTargetException();
     68                 } catch (ReflectiveOperationException e) {
     69                     throw new RuntimeException("Reflection failed for method " + method, e);
     70                 }
     71             }
     72         };
     73     }
     74 }
     75