Skip to content

Commit

Permalink
Do not use invoke/invokeExact directly but from generated code to avo…
Browse files Browse the repository at this point in the history
…id breaking Android builds which cannot process these methods.
  • Loading branch information
raphw committed Aug 17, 2020
1 parent d42221c commit ec659f4
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@

@Retention(RetentionPolicy.CLASS)
@Documented
public @interface SuppressSignatureCheck { }
public @interface SuppressSignatureCheck {}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ class InstrumentationMemberAccessor implements MemberAccessor {
"setAccessible", boolean.class))
.onArgument(0)
.withArgument(1))
.method(named("invokeWithArguments"))
.intercept(
MethodCall.invoke(
MethodHandle.class.getMethod(
"invokeWithArguments", Object[].class))
.onArgument(0)
.withArgument(1))
.make()
.load(
InstrumentationMemberAccessor.class.getClassLoader(),
Expand Down Expand Up @@ -146,17 +153,20 @@ public Object newInstance(Constructor<?> constructor, Object... arguments)
}
assureArguments(constructor, null, null, arguments, constructor.getParameterTypes());
try {
Object module = getModule.bindTo(constructor.getDeclaringClass()).invokeWithArguments();
Object module =
DISPATCHER.invokeWithArguments(
getModule.bindTo(constructor.getDeclaringClass()));
String packageName = constructor.getDeclaringClass().getPackage().getName();
assureOpen(module, packageName);
MethodHandle handle =
((MethodHandles.Lookup)
privateLookupIn.invokeExact(
DISPATCHER.invokeWithArguments(
privateLookupIn,
constructor.getDeclaringClass(),
DISPATCHER.getLookup()))
.unreflectConstructor(constructor);
try {
return handle.invokeWithArguments(arguments);
return DISPATCHER.invokeWithArguments(handle, arguments);
} catch (Throwable t) {
throw new InvocationTargetException(t);
}
Expand All @@ -182,19 +192,22 @@ public Object invoke(Method method, Object target, Object... arguments)
arguments,
method.getParameterTypes());
try {
Object module = getModule.bindTo(method.getDeclaringClass()).invokeWithArguments();
Object module =
DISPATCHER.invokeWithArguments(getModule.bindTo(method.getDeclaringClass()));
String packageName = method.getDeclaringClass().getPackage().getName();
assureOpen(module, packageName);
MethodHandle handle =
((MethodHandles.Lookup)
privateLookupIn.invokeExact(
method.getDeclaringClass(), DISPATCHER.getLookup()))
DISPATCHER.invokeWithArguments(
privateLookupIn,
method.getDeclaringClass(),
DISPATCHER.getLookup()))
.unreflect(method);
if (!Modifier.isStatic(method.getModifiers())) {
handle = handle.bindTo(target);
}
try {
return handle.invokeWithArguments(arguments);
return DISPATCHER.invokeWithArguments(handle, arguments);
} catch (Throwable t) {
throw new InvocationTargetException(t);
}
Expand All @@ -221,18 +234,21 @@ public Object get(Field field, Object target) {
new Object[0],
new Class<?>[0]);
try {
Object module = getModule.bindTo(field.getDeclaringClass()).invokeWithArguments();
Object module =
DISPATCHER.invokeWithArguments(getModule.bindTo(field.getDeclaringClass()));
String packageName = field.getDeclaringClass().getPackage().getName();
assureOpen(module, packageName);
MethodHandle handle =
((MethodHandles.Lookup)
privateLookupIn.invokeExact(
field.getDeclaringClass(), DISPATCHER.getLookup()))
DISPATCHER.invokeWithArguments(
privateLookupIn,
field.getDeclaringClass(),
DISPATCHER.getLookup()))
.unreflectGetter(field);
if (!Modifier.isStatic(field.getModifiers())) {
handle = handle.bindTo(target);
}
return handle.invokeWithArguments();
return DISPATCHER.invokeWithArguments(handle);
} catch (Throwable t) {
throw new IllegalStateException("Could not read " + field + " on " + target, t);
}
Expand All @@ -248,7 +264,8 @@ public void set(Field field, Object target, Object value) throws IllegalAccessEx
new Class<?>[] {field.getType()});
boolean illegalAccess = false;
try {
Object module = getModule.bindTo(field.getDeclaringClass()).invokeWithArguments();
Object module =
DISPATCHER.invokeWithArguments(getModule.bindTo(field.getDeclaringClass()));
String packageName = field.getDeclaringClass().getPackage().getName();
assureOpen(module, packageName);
// Method handles do not allow setting final fields where setAccessible(true)
Expand All @@ -270,13 +287,15 @@ public void set(Field field, Object target, Object value) throws IllegalAccessEx
try {
MethodHandle handle =
((MethodHandles.Lookup)
privateLookupIn.invokeExact(
field.getDeclaringClass(), DISPATCHER.getLookup()))
DISPATCHER.invokeWithArguments(
privateLookupIn,
field.getDeclaringClass(),
DISPATCHER.getLookup()))
.unreflectSetter(field);
if (!Modifier.isStatic(field.getModifiers())) {
handle = handle.bindTo(target);
}
handle.invokeWithArguments(value);
DISPATCHER.invokeWithArguments(handle, value);
} finally {
if (isFinal) {
DISPATCHER.setAccessible(field, false);
Expand All @@ -292,17 +311,18 @@ public void set(Field field, Object target, Object value) throws IllegalAccessEx
}

private void assureOpen(Object module, String packageName) throws Throwable {
if (!(Boolean) isOpen.invokeWithArguments(module, packageName, DISPATCHER.getModule())) {
redefineModule
.bindTo(INSTRUMENTATION)
.invokeWithArguments(
module,
Collections.emptySet(),
Collections.emptyMap(),
Collections.singletonMap(
packageName, Collections.singleton(DISPATCHER.getModule())),
Collections.emptySet(),
Collections.emptyMap());
if (!(Boolean)
DISPATCHER.invokeWithArguments(
isOpen, module, packageName, DISPATCHER.getModule())) {
DISPATCHER.invokeWithArguments(
redefineModule.bindTo(INSTRUMENTATION),
module,
Collections.emptySet(),
Collections.emptyMap(),
Collections.singletonMap(
packageName, Collections.singleton(DISPATCHER.getModule())),
Collections.emptySet(),
Collections.emptyMap());
}
}

Expand Down Expand Up @@ -361,5 +381,10 @@ public interface Dispatcher {
Object getModule();

void setAccessible(AccessibleObject target, boolean value);

// Used to avoid invoke/invokeExact being exposed to Android where this class should
// never be loaded. Since the invocation happens from the generated code, the Android
// build pipeline does not fail.
Object invokeWithArguments(MethodHandle handle, Object... arguments) throws Throwable;
}
}

0 comments on commit ec659f4

Please sign in to comment.