From 68349a8634db3a240a19b72aea99176bc5260e29 Mon Sep 17 00:00:00 2001 From: Gustav Sennton Date: Mon, 5 Mar 2018 10:23:12 +0000 Subject: [android_webview] Save boundary interfaces from proguard obfuscation We need to keep the names of all boundary interface classes and methods used by the support library and chromium to ensure their names are the same in the support library as in the WebView APK. However, utility classes in the boundary interface package can be obfuscated just fine since they are not part of the boundary interface API. Ideally then, we will put everything that is part of the boundary interface API in one specific package, and keep utility methods in a sub-package, to allow for simple proguard rules (and avoid bugs where we incorrectly keep/remove new boundary interfaces). Bug: 809471 Change-Id: I7a700fcc50998d83bf3bfa799196477289bedb3e Reviewed-on: https://chromium-review.googlesource.com/943504 Reviewed-by: agrieve Reviewed-by: Richard Coles Commit-Queue: Gustav Sennton Cr-Original-Commit-Position: refs/heads/master@{#540800} Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src Cr-Mirrored-Commit: 0a6e992e64dcf503e038e34a0c7952172b29d9a9 --- BUILD.gn | 4 +- proguard.flags | 9 +++ .../BoundaryInterfaceReflectionUtil.java | 70 ---------------------- .../util/BoundaryInterfaceReflectionUtil.java | 70 ++++++++++++++++++++++ 4 files changed, 82 insertions(+), 71 deletions(-) create mode 100644 proguard.flags delete mode 100644 src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java create mode 100644 src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java diff --git a/BUILD.gn b/BUILD.gn index 6f08b1d..bc1fcb3 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -7,15 +7,17 @@ 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/StaticsBoundaryInterface.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", "src/org/chromium/support_lib_boundary/WebViewProviderFactoryBoundaryInterface.java", "src/org/chromium/support_lib_boundary/WebkitToCompatConverterBoundaryInterface.java", + "src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java", ] + proguard_configs = [ "proguard.flags" ] + # We can't use ANY deps here, the support library should be able to build # these interfaces without any other chromium dependencies. deps = [] diff --git a/proguard.flags b/proguard.flags new file mode 100644 index 0000000..4a0d580 --- /dev/null +++ b/proguard.flags @@ -0,0 +1,9 @@ +# 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. + +# We need to avoid obfuscating the support library boundary interface because +# this API is shared with the Android Support Library. +# Note that we only 'keep' the package org.chromium.support_lib_boundary itself, +# any sub-packages of that package can still be obfuscated. +-keep public class org.chromium.support_lib_boundary.* { public *; } diff --git a/src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java b/src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java deleted file mode 100644 index caf7277..0000000 --- a/src/org/chromium/support_lib_boundary/BoundaryInterfaceReflectionUtil.java +++ /dev/null @@ -1,70 +0,0 @@ -// 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 castToSuppLibClass(Class 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); - } - } - }; - } -} diff --git a/src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java b/src/org/chromium/support_lib_boundary/util/BoundaryInterfaceReflectionUtil.java new file mode 100644 index 0000000..5a772c5 --- /dev/null +++ b/src/org/chromium/support_lib_boundary/util/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.util; + +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 castToSuppLibClass(Class 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); + } + } + }; + } +} -- cgit v1.2.3