summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustav Sennton <gsennton@google.com>2018-02-15 01:23:20 +0000
committerandroid-build-merger <android-build-merger@google.com>2018-02-15 01:23:20 +0000
commit1d2bd4f8882002be806e99a7d278de5c3cf243dc (patch)
tree1c764c01c6c0bee2e5937f81a9706c19343a4e2d
parent9da0293c494e289d75b36e6486c1cb2843c47ab4 (diff)
parentb127c8d137b5d0a156300967186df65d3dfebb6f (diff)
downloadwebview_support_interfaces-1d2bd4f8882002be806e99a7d278de5c3cf243dc.tar.gz
[Boundary interfaces] Add utility methods for support library boundary am: 7b527a9a1c am: 5177c1d7ef
am: b127c8d137 Change-Id: I2156a1fcddd7cc3676f58d599b6d6a2b236ea8a5
-rw-r--r--BUILD.gn1
-rw-r--r--src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java70
2 files changed, 71 insertions, 0 deletions
diff --git a/BUILD.gn b/BUILD.gn
index a69d3d5..0a73e73 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -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);
+ }
+ }
+ };
+ }
+}