diff options
author | Gustav Sennton <gsennton@google.com> | 2018-02-14 15:45:25 +0000 |
---|---|---|
committer | Gustav Sennton <gsennton@google.com> | 2018-02-14 20:20:20 +0000 |
commit | 7b527a9a1cda7903e47bad9f2c8894dae3f5837a (patch) | |
tree | 1c764c01c6c0bee2e5937f81a9706c19343a4e2d | |
parent | 88584778845fa3dfda8ed3a2e8202e48ed5e852a (diff) | |
download | webview_support_interfaces-7b527a9a1cda7903e47bad9f2c8894dae3f5837a.tar.gz |
[Boundary interfaces] Add utility methods for support library boundary
The WebView support library (in the Android Support Library) and the
WebView support library glue (in Chromium) will both need methods for
mapping a class loaded in some ClassLoader into a class loaded in the
current ClassLoader.
In this CL we put that utility in the boundary interface directory to
avoid duplicating this Class-conversion functionality in both the
Android Support Library and Chromium (instead this functionality will be
mirrored from Chromium into the support library).
Bug: 788177
Change-Id: Icea382115bedd53d1b255d3a115fff03fcdb15ba
Reviewed-on: https://chromium-review.googlesource.com/919062
Reviewed-by: Richard Coles <torne@chromium.org>
Commit-Queue: Gustav Sennton <gsennton@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#536720}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: e5f7a795c810e53cf9d0bfa6b7c31fd21c3b3e1c
-rw-r--r-- | BUILD.gn | 1 | ||||
-rw-r--r-- | src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java | 70 |
2 files changed, 71 insertions, 0 deletions
@@ -7,6 +7,7 @@ import("//build/config/android/rules.gni") android_library("boundary_interface_java") { java_files = [ + "src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java", "src/org/chromium/support_lib_boundary/VisualStateCallbackBoundaryInterface.java", "src/org/chromium/support_lib_boundary/WebSettingsBoundaryInterface.java", "src/org/chromium/support_lib_boundary/WebViewProviderBoundaryInterface.java", diff --git a/src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java b/src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java new file mode 100644 index 0000000..caf7277 --- /dev/null +++ b/src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java @@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +package org.chromium.support_lib_boundary; + +import android.annotation.TargetApi; +import android.os.Build; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * A set of utility methods used for calling across the support library boundary. + */ +public class BoundaryInterfaceReflectionUtil { + /** + * Utility method for fetching a method from the current classloader, with the same signature + * (package + class + method name + parameters) as a given method defined in another + * classloader. + */ + public static Method dupeMethod(Method method) + throws ClassNotFoundException, NoSuchMethodException { + Class<?> declaringClass = Class.forName(method.getDeclaringClass().getName()); + Class[] otherSideParameterClasses = method.getParameterTypes(); + Class[] parameterClasses = new Class[otherSideParameterClasses.length]; + for (int n = 0; n < parameterClasses.length; n++) { + Class<?> clazz = otherSideParameterClasses[n]; + // Primitive classes are shared between the classloaders - so we can use the same + // primitive class declarations on either side. Non-primitive classes must be looked up + // by name. + parameterClasses[n] = clazz.isPrimitive() ? clazz : Class.forName(clazz.getName()); + } + return declaringClass.getDeclaredMethod(method.getName(), parameterClasses); + } + + /** + * Returns an implementation of the boundary interface named clazz, by delegating method calls + * to the {@link InvocationHandler} invocationHandler. + */ + public static <T> T castToSuppLibClass(Class<T> clazz, InvocationHandler invocationHandler) { + return clazz.cast( + Proxy.newProxyInstance(BoundaryInterfaceReflectionUtil.class.getClassLoader(), + new Class[] {clazz}, invocationHandler)); + } + + /** + * Create an {@link java.lang.reflect.InvocationHandler} that delegates method calls to + * {@param delegate}, making sure that the {@link java.lang.reflect.Method} and parameters being + * passed to {@param delegate} exist in the same {@link java.lang.ClassLoader} as {@param + * delegate}. + */ + @TargetApi(Build.VERSION_CODES.KITKAT) + public static InvocationHandler createInvocationHandlerFor(final Object delegate) { + return new InvocationHandler() { + @Override + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + try { + return dupeMethod(method).invoke(delegate, objects); + } catch (InvocationTargetException e) { + // If something went wrong, ensure we throw the original exception. + throw e.getTargetException(); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Reflection failed for method " + method, e); + } + } + }; + } +} |