Commit a3349311 authored by Robbie McElrath's avatar Robbie McElrath Committed by Chromium LUCI CQ

[WebLayer] Fix FragmentActivityReplacer with SupportLifecycleFragmentImpl

This fixes a comilation error due to FragmentActivityReplacer's
interaction with SupportLifecycleFragmentImpl.

Bug: 1152898, 1123216
Change-Id: I81de8100f7ddd08310f8a36c8f1c9c62e82c0469
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2566455Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Reviewed-by: default avatarSam Maier <smaier@chromium.org>
Commit-Queue: Robbie McElrath <rmcelrath@chromium.org>
Cr-Commit-Position: refs/heads/master@{#832426}
parent e803d89d
...@@ -21,6 +21,7 @@ import java.io.IOException; ...@@ -21,6 +21,7 @@ import java.io.IOException;
*/ */
public class FragmentActivityReplacer extends ByteCodeRewriter { public class FragmentActivityReplacer extends ByteCodeRewriter {
private static final String GET_ACTIVITY_METHOD_NAME = "getActivity"; private static final String GET_ACTIVITY_METHOD_NAME = "getActivity";
private static final String GET_LIFECYCLE_ACTIVITY_METHOD_NAME = "getLifecycleActivity";
private static final String NEW_METHOD_DESCRIPTOR = "()Landroid/app/Activity;"; private static final String NEW_METHOD_DESCRIPTOR = "()Landroid/app/Activity;";
private static final String OLD_METHOD_DESCRIPTOR = private static final String OLD_METHOD_DESCRIPTOR =
"()Landroidx/fragment/app/FragmentActivity;"; "()Landroidx/fragment/app/FragmentActivity;";
...@@ -44,16 +45,23 @@ public class FragmentActivityReplacer extends ByteCodeRewriter { ...@@ -44,16 +45,23 @@ public class FragmentActivityReplacer extends ByteCodeRewriter {
@Override @Override
protected ClassVisitor getClassVisitorForClass(String classPath, ClassVisitor delegate) { protected ClassVisitor getClassVisitorForClass(String classPath, ClassVisitor delegate) {
ClassVisitor getActivityReplacer = new GetActivityReplacer(delegate); ClassVisitor invocationVisitor = new InvocationReplacer(delegate);
if (classPath.equals("androidx/fragment/app/Fragment.class")) { switch (classPath) {
return new FragmentClassVisitor(getActivityReplacer); case "androidx/fragment/app/Fragment.class":
return new FragmentClassVisitor(invocationVisitor);
case "com/google/android/gms/common/api/internal/SupportLifecycleFragmentImpl.class":
return new SupportLifecycleFragmentImplClassVisitor(invocationVisitor);
default:
return invocationVisitor;
} }
return getActivityReplacer;
} }
/** Updates any Fragment.getActivity/requireActivity() calls to call the replaced method. */ /**
private static class GetActivityReplacer extends ClassVisitor { * Updates any Fragment.getActivity/requireActivity() or getLifecycleActivity() calls to call
private GetActivityReplacer(ClassVisitor baseVisitor) { * the replaced method.
*/
private static class InvocationReplacer extends ClassVisitor {
private InvocationReplacer(ClassVisitor baseVisitor) {
super(Opcodes.ASM7, baseVisitor); super(Opcodes.ASM7, baseVisitor);
} }
...@@ -68,7 +76,8 @@ public class FragmentActivityReplacer extends ByteCodeRewriter { ...@@ -68,7 +76,8 @@ public class FragmentActivityReplacer extends ByteCodeRewriter {
if ((opcode == Opcodes.INVOKEVIRTUAL || opcode == Opcodes.INVOKESPECIAL) if ((opcode == Opcodes.INVOKEVIRTUAL || opcode == Opcodes.INVOKESPECIAL)
&& descriptor.equals(OLD_METHOD_DESCRIPTOR) && descriptor.equals(OLD_METHOD_DESCRIPTOR)
&& (name.equals(GET_ACTIVITY_METHOD_NAME) && (name.equals(GET_ACTIVITY_METHOD_NAME)
|| name.equals(REQUIRE_ACTIVITY_METHOD_NAME))) { || name.equals(REQUIRE_ACTIVITY_METHOD_NAME)
|| name.equals(GET_LIFECYCLE_ACTIVITY_METHOD_NAME))) {
super.visitMethodInsn( super.visitMethodInsn(
opcode, owner, name, NEW_METHOD_DESCRIPTOR, isInterface); opcode, owner, name, NEW_METHOD_DESCRIPTOR, isInterface);
} else { } else {
...@@ -92,16 +101,17 @@ public class FragmentActivityReplacer extends ByteCodeRewriter { ...@@ -92,16 +101,17 @@ public class FragmentActivityReplacer extends ByteCodeRewriter {
int access, String name, String descriptor, String signature, String[] exceptions) { int access, String name, String descriptor, String signature, String[] exceptions) {
// Update the descriptor of getActivity() and requireActivity(). // Update the descriptor of getActivity() and requireActivity().
MethodVisitor baseVisitor; MethodVisitor baseVisitor;
if (name.equals(GET_ACTIVITY_METHOD_NAME) if (descriptor.equals(OLD_METHOD_DESCRIPTOR)
|| name.equals(REQUIRE_ACTIVITY_METHOD_NAME)) { && (name.equals(GET_ACTIVITY_METHOD_NAME)
baseVisitor = super.visitMethod( || name.equals(REQUIRE_ACTIVITY_METHOD_NAME))) {
access & ~Opcodes.ACC_FINAL, name, NEW_METHOD_DESCRIPTOR, null, exceptions); baseVisitor =
super.visitMethod(access, name, NEW_METHOD_DESCRIPTOR, null, exceptions);
} else { } else {
baseVisitor = super.visitMethod(access, name, descriptor, signature, exceptions); baseVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
} }
// Replace getActivity() with `return ContextUtils.activityFromContext(getContext());` // Replace getActivity() with `return ContextUtils.activityFromContext(getContext());`
if (name.equals(GET_ACTIVITY_METHOD_NAME)) { if (name.equals(GET_ACTIVITY_METHOD_NAME) && descriptor.equals(OLD_METHOD_DESCRIPTOR)) {
baseVisitor.visitVarInsn(Opcodes.ALOAD, 0); baseVisitor.visitVarInsn(Opcodes.ALOAD, 0);
baseVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "androidx/fragment/app/Fragment", baseVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "androidx/fragment/app/Fragment",
"getContext", "()Landroid/content/Context;", false); "getContext", "()Landroid/content/Context;", false);
...@@ -123,4 +133,34 @@ public class FragmentActivityReplacer extends ByteCodeRewriter { ...@@ -123,4 +133,34 @@ public class FragmentActivityReplacer extends ByteCodeRewriter {
}); });
} }
} }
/**
* Update SupportLifecycleFragmentImpl.getLifecycleActivity().
*/
private static class SupportLifecycleFragmentImplClassVisitor extends ClassVisitor {
private SupportLifecycleFragmentImplClassVisitor(ClassVisitor baseVisitor) {
super(Opcodes.ASM7, baseVisitor);
}
@Override
public MethodVisitor visitMethod(
int access, String name, String descriptor, String signature, String[] exceptions) {
// SupportLifecycleFragmentImpl has two getActivity methods:
// 1. public FragmentActivity getLifecycleActivity():
// This is what you'll see in the source. This delegates to Fragment.getActivity().
// 2. public Activity getLifecycleActivity():
// This is generated because the class implements LifecycleFragment, which
// declares this method, and delegates to #1.
//
// Here we change the return type of #1 and delete #2.
if (name.equals(GET_LIFECYCLE_ACTIVITY_METHOD_NAME)) {
if (descriptor.equals(OLD_METHOD_DESCRIPTOR)) {
return super.visitMethod(
access, name, NEW_METHOD_DESCRIPTOR, signature, exceptions);
}
return null;
}
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment