深入理解Android的Proxy实现原理

背景

既然是深入理解,那么需要深入理解到什么程度呢?我觉得至少需要理解到:

  1. 理解怎样为目标接口生成代理类的
  2. 在使用者调用代理对象的任何一个方法时,怎么实现让调用都走到 InvocationHandler 的 invoke 方法的

后面的部分会涉及到 Java 中类在底层的表现形式以及一点汇编代码。

动态代理

在动态代理中,使用 Java 提供的 java.lang.reflect.Proxy 可以实现在运行时为一个或多个接口生成一个实现类,然后在调用接口的任何一个方法时都会调用 InvocationHandler 的 invoke 方法。在 invoke 方法中开发者就可以自己做一些事情。

阅读 java.lang.reflect.Proxy 的文档可知,Proxy 提供了静态方法去创建动态代理类和实例,并且创建的动态代理类的父类就是 Proxy.

比如创建一个 Foo 接口的代理:

1
2
3
4
5
6
7
InvocationHandler handler = new InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) {
//...
}
};
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);

简化版本:

1
2
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), 
new Class<?>[] { Foo.class }, handler);

代理类的生成

Java 层流程

获取代理类

通过调用 Proxy#newProxyInstance获取代理类实例对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) {
final Class<?>[] intfs = interfaces.clone();
// 获取实现了代理接口的代理类
Class<?> cl = getProxyClass0(loader, intfs);
try {
// 获取代理类的构造方法
final Constructor<?> cons = cl.getConstructor(new Class<?>[]{ InvocationHandler.class});
final InvocationHandler ih = h;
// 调用构造方法时把 InvocationHandler 注入
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
//...
}
}

由于动态代理生成的代理类,都会继承在 Proxy 类,所以每一个动态生成的代理类都会有持有一个 InvocationHandler 且都是在构造函数注入:

1
2
3
4
5
6
7
protected InvocationHandler h;

// 通过构造函数注入 InvocationHandler
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}

Proxy#getProxyClass0 方法负责获取代理类:

1
2
3
4
5
6
7
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 优先从缓存中获取, 缓存中没有再生成
return proxyClassCache.get(loader, interfaces);
}

运行时生成的代理类都会被缓存在 Proxy 的类变量中,获取代理类的缓存规则有2层字典:

  • 第一层字典的键类型是: ClassLoader;值是第二层字典
  • 第二层字典的键类型是: ClassLoader&&Class[],表示代理的接口数组;值类型是: Class, 表示生成的代理类。

缓存规则

生成代理类

如果没有命中缓存, 则调用 ProxyClassFactory#apply 去执行生成代理类的操作:

1
2
3
4
5
6
/* ProxyClassFactory 中定义2个类变量 */

// 代理类的类名前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 代理类的全局计数
private static final AtomicLong nextUniqueNumber = new AtomicLong();

要生成代理类时会调用 apply(ClassLoader loader, Class<?>[] interfaces) 方法, apply 方法主要做了以下工作:

  1. 验证代理的类是否是接口, 验证是否存在重复的接口

因为无论在 Java 代码中编写的是类还是接口,编译之后都是以类的形式存在的。
类和接口编译之后的区别在于:接口生成的类是抽象类,并且接口生成的抽象类的标记(accessFlags)会表明类是由接口生成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);

for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) { }
// 验证找到的类信息是否是接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(interfaceClass.getName() + " is not an interface");
}
// 验证是否传入了重复的接口
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException("repeated interface: " + interfaceClass.getName());
}
}
  1. 生成代理类的包名
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;

// 如果代理的接口中存在非 public 访问权限的, 则需要所有非 public 的接口都在同一个包中
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) { // 如果接口不是 public 的
accessFlags = Modifier.FINAL;
String name = intf.getName(); // 获取接口名字比如 com.example.app.InterfaceA
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1)); // 获取 com.example.app
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}

// 如果没有非 public 访问权限的接口
if (proxyPkg == null) {
proxyPkg = "";
}
  1. 获取将要代理的方法,以及方法中声明的异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/** Android 在实现上的改变: 直接生成代理类而不是通过调用 ProxyGenerator */
// 获取接口的方法, 并根据签名和类型排序
List<Method> methods = getMethods(interfaces);
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
validateReturnTypes(methods);

// 获取声明的异常
List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);

// 转变为用数组存储
Method[] methodsArray = methods.toArray(new Method[methods.size()]);
Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);

// 获取并增加全局的计数
long num = nextUniqueNumber.getAndIncrement();
// 代理类的包名: proxyPkg + $Proxy + num
String proxyName = proxyPkg + proxyClassNamePrefix + num;
  1. 调用底层方法
1
2
// generateProxy 为 JNI 方法
return generateProxy(proxyName, interfaces, loader, methodsArray, exceptionsArray);

Java 层做的事情主要是:

  1. 尝试从缓存中获取代理类
  2. 为 native 生成代理类做参数准备
    • 检查代理的接口的访问权限是否满足要求
    • 获取代理的接口声明的所有方法
    • 获取代理的接口声明的所有异常
  3. 调用 native 方法 generateProxy 创建代理类
  4. 创建代理类的实例, 并在创建时注入 InvocationHandler

Native 层流程

走完 Java 层的流程之后, 程序将通过 generateProxy 调用走到 native 层. generateProxy 对应的 native 方法位于 art/runtime/native/java_lang_reflect_Proxy.cc 中的 Proxy_generateProxy. 整体流程如下:

Proxy_generateProxy:

1
2
3
4
5
6
7
8
9
static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
jobject loader, jobjectArray methods, jobjectArray throws) {
ScopedFastNativeObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// 调用 ClassLinker#CreateProxyClass
// 传递的参数为: 将要生成的类的类名, 代理的目标接口数组, 类加载器, 方法数组, 异常数组
return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
soa, name, interfaces, loader, methods, throws));
}

CreateProxyClass:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114

ObjPtr<mirror::Class> ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
jstring name,
jobjectArray interfaces,
jobject loader,
jobjectArray methods,
jobjectArray throws) {
Thread* self = soa.Self();
//...
StackHandleScope<10> hs(self);
// 创建一个临时的 Class 实例 temp_klass
MutableHandle<mirror::Class> temp_klass(hs.NewHandle(
AllocClass(self, GetClassRoot<mirror::Class>(this), sizeof(mirror::Class))));
// 设置实例大小为 Proxy 类的大小
temp_klass->SetObjectSize(sizeof(mirror::Proxy));
// 设置类的访问标志为: isProxy, public, final
temp_klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
// 设置类的 ClassLoader 为传入的 ClassLoader
temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader));
// 设置类名
temp_klass->SetName(soa.Decode<mirror::String>(name));
// 设置 DexCache
temp_klass->SetDexCache(GetClassRoot<mirror::Proxy>(this)->GetDexCache());
// 拷贝 Object 类的空的接口表到临时类
temp_klass->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
mirror::Class::SetStatus(temp_klass, ClassStatus::kIdx, self);
// 获取类的描述符
std::string storage;
const char* descriptor = temp_klass->GetDescriptor(&storage);
// 根据描述符计算一个哈希值
const size_t hash = ComputeModifiedUtf8Hash(descriptor);

// Needs to be before we insert the class so that the allocator field is set.
LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(temp_klass->GetClassLoader());

// 在加载字段之前插入类, 因为字段根(ArtField::declaring_class_) 仅能从 class Table 中访问.
// 插入创建的 temp_klass 到 temp_klass 的 ClassLoader 对应的 class Table 中.
ObjPtr<mirror::Class> existing = InsertClass(descriptor, temp_klass.Get(), hash);

// 实例字段是继承的, 但这里添加了两个静态字段
const size_t num_fields = 2;
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields);
temp_klass->SetSFieldsPtr(sfields);

// 1. 上面创建的静态字段的第一个(interfaces), 会持有被代理实现的接口
ArtField& interfaces_sfield = sfields->At(0);
interfaces_sfield.SetDexFieldIndex(0);
interfaces_sfield.SetDeclaringClass(temp_klass.Get());
interfaces_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);

// 2. 上面创建的静态字段的第二个(throws), 会持有方法声明的异常
ArtField& throws_sfield = sfields->At(1);
throws_sfield.SetDexFieldIndex(1);
throws_sfield.SetDeclaringClass(temp_klass.Get());
throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);

// 代理类只有一个 direct methods, 就是它们的构造函数
const size_t num_direct_methods = 1;

// 代理类有多个 virtual methods(代理类代理的接口们声明的方法)
auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods));
const size_t num_virtual_methods = h_methods->GetLength();

// 创建方法数组
LengthPrefixedArray<ArtMethod>* proxy_class_methods = AllocArtMethodArray(
self, allocator, num_direct_methods + num_virtual_methods);
temp_klass->SetMethodsPtr(proxy_class_methods, num_direct_methods, num_virtual_methods);

// 创建唯一的 direct method, 即代理类的构造函数
CreateProxyConstructor(temp_klass, temp_klass->GetDirectMethodUnchecked(0, image_pointer_size_));

// 创建 virtual method
for (size_t i = 0; i < num_virtual_methods; ++i) {
// 获取 temp_klass 的虚方法
auto* virtual_method = temp_klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
// 获取 代理的接口声明的方法对应的 ArtMethod 作为原型
auto* prototype = h_methods->Get(i)->GetArtMethod();
// 创建代理方法, 然后设置到 temp_klass 上
CreateProxyMethod(temp_klass, prototype, virtual_method);
}

// 设置父类是 java.lang.reflect.Proxy
temp_klass->SetSuperClass(GetClassRoot<mirror::Proxy>(this));

// 到这里代理类就已经算被加载了, 发出一个 ClassLoad 事件
Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(temp_klass);

// 创建一个新的 Class 实例
MutableHandle<mirror::Class> klass = hs.NewHandle<mirror::Class>(nullptr);
{
// Must hold lock on object when resolved.
ObjectLock<mirror::Class> resolution_lock(self, temp_klass);
// 链接字段和虚方法,创建 vtable 和 iftables
// 新的 class 将替换 class table 中的 temp_class
Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
if (!LinkClass(self, descriptor, temp_klass, h_interfaces, &klass)) {
mirror::Class::SetStatus(temp_klass, ClassStatus::kErrorUnresolved, self);
return nullptr;
}
}
// 设置持有接口的静态字段的所属类和值
interfaces_sfield.SetObject<false>(
klass.Get(),
soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces));
// 设置持有异常的静态字段的所属类和值
throws_sfield.SetObject<false>(
klass.Get(),
soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws));
// 进行类的准备工作
Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(temp_klass, klass);

return klass.Get();
}
CreateProxyConstructor

创建代理类的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) {
// 找到 java.lang.Proxy 类的实例构造函数(<init>(InvocationHandler)V 方法) 在内存中对应的 ArtMethod
ArtMethod* proxy_constructor =
jni::DecodeArtMethod(WellKnownClasses::java_lang_reflect_Proxy_init);

// 将找到的 ArtMethod 拷贝到 out 方法
out->CopyFrom(proxy_constructor, image_pointer_size_);
// 设置方法的访问标记
out->SetAccessFlags((out->GetAccessFlags() & ~kAccProtected) |
kAccPublic |
kAccCompileDontBother);
// 设置方法属于的类
out->SetDeclaringClass(klass.Get());

/*
* 设置方法指针占用的字节数,用来设置指针在原始数据中的偏移量
* image_pointer_size_ 的值是 kRuntimePointerSize, 而 kRuntimePointerSize 4 或 8 字节
* static constexpr PointerSize kRuntimePointerSize = sizeof(void*) == 8U ? PointerSize::k64 : PointerSize::k32;
* enum class PointerSize : size_t {
* k32 = 4,
* k64 = 8
* };
*/
out->SetDataPtrSize(proxy_constructor, image_pointer_size_);
}

可以看到为代理类创建构造函数其实就是将已有的 java.lang.Proxy 类的构造函数对应的 ArtMethod 拷贝给创建的代理类的构造函数。

CreateProxyMethod

为接口方法创建代理方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype,
ArtMethod* out) {
// 将传入的方法作为原型拷贝给输出方法
out->CopyFrom(prototype, image_pointer_size_);

// 设置声明该方法的类为代理类
out->SetDeclaringClass(klass.Get());

// 删除接口方法的一些标记: abstract、default、kAccDefaultConflict(表示default冲突)
const uint32_t kRemoveFlags = kAccAbstract | kAccDefault | kAccDefaultConflict;
// 增加标记: final、kAccCompileDontBother(不为该方法获取 JIT 采样)
const uint32_t kAddFlags = kAccFinal | kAccCompileDontBother;
out->SetAccessFlags((out->GetAccessFlags() & ~kRemoveFlags) | kAddFlags);

// 设置 dex_code_item_offset_(代码数据在 ArtMethod 结构中的偏移量) 为0, 因为代理的接口的方法的方法体是没有代码的
out->SetCodeItemOffset(0);
out->SetDataPtrSize(prototype, image_pointer_size_);
// 设置方法的执行入口, 这里设置的是 AOT 预编译之后的代码的入口
out->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
}

GetQuickProxyInvokeHandler 方法在 art/runtime/entrypoints/runtime_asm_entrypoints.h 中定义:

1
2
3
4
5
6
7
extern "C" void art_quick_proxy_invoke_handler();

static inline const void* GetQuickProxyInvokeHandler() {
// 返回了 art_quick_proxy_invoke_handler 方法的指针,
// 那么就要看 art_quick_proxy_invoke_handler 方法在哪里实现的
return reinterpret_cast<const void*>(art_quick_proxy_invoke_handler);
}

通过在 cs.android.com 搜索才找到相关的地方 art/runtime/arch/arm/quick_entrypoints_arm.S,
quick_entrypoints_arm.S 为 arm 平台下的汇编代码, 下面为与动态代理有关的部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
ENTRY art_quick_proxy_invoke_handler
push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves and args.
.cfi_adjust_cfa_offset 40
.cfi_rel_offset r1, 0
.cfi_rel_offset r2, 4
.cfi_rel_offset r3, 8
.cfi_rel_offset r5, 12
.cfi_rel_offset r6, 16
.cfi_rel_offset r7, 20
.cfi_rel_offset r8, 24
.cfi_rel_offset r10, 28
.cfi_rel_offset r11, 32
.cfi_rel_offset lr, 36
vpush {s0-s15} @ 16 words of float args.
.cfi_adjust_cfa_offset 64
sub sp, #8 @ 2 words of space, alignment padding and Method*
.cfi_adjust_cfa_offset 8
str r0, [sp, #0] @ Store ArtMethod* to bottom of stack.
str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame.
mov r2, rSELF @ pass Thread::Current
mov r3, sp @ 将 sp 存到 r3 寄存器
blx artQuickProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP)
ldr r2, [rSELF, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_
// Tear down the callee-save frame. Skip arg registers.
add sp, #(FRAME_SIZE_SAVE_REFS_AND_ARGS - FRAME_SIZE_SAVE_REFS_ONLY)
.cfi_adjust_cfa_offset -(FRAME_SIZE_SAVE_REFS_AND_ARGS - FRAME_SIZE_SAVE_REFS_ONLY)
RESTORE_SAVE_REFS_ONLY_FRAME
REFRESH_MARKING_REGISTER
cbnz r2, 1f @ success if no exception is pending
vmov d0, r0, r1 @ store into fpr, for when it's a fpr return...
bx lr @ return on success
1:
DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler

上面的汇编代码, 执行时的情况是当调用代理的接口的方法时,实际的方法执行入口将是上面的汇编代码。汇编代码里又会调用到 artQuickProxyInvokeHandler 方法。

artQuickProxyInvokeHandler 方法的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* 下面方法的大概注释 */
// 代理方法调用的处理程序。
// 在进入时,将存在一个代理对象方法的框架,该框架负责记录被调用者保存寄存器。
// 我们显式地将传入的引用参数放入jobject中(以便它们在GC中幸存下来)。
// 我们调用 InvocationHandler,InvocationHandler 是代理对象内的一个字段,它将装箱原始参数并处理错误情况。
extern "C" uint64_t artQuickProxyInvokeHandler(ArtMethod* proxy_method, mirror::Object* receiver, Thread* self, ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
// proxy_method: 代理类的方法, 通过判断 Method 的 DeclaringClass 是否是 Proxy 来判断是否是代理方法
// receiver: 代理类的实例对象
// sp: 被调用的接口方法
// Register the top of the managed stack, making stack crawlable.
DCHECK_EQ((*sp), proxy_method) << proxy_method->PrettyMethod();
self->VerifyStack();
// Start new JNI local reference state.
JNIEnvExt* env = self->GetJniEnv();
ScopedObjectAccessUnchecked soa(env);
ScopedJniEnvLocalRefState env_state(env);
// Create local ref. copies of proxy method and the receiver.
jobject rcvr_jobj = soa.AddLocalReference<jobject>(receiver);

// Placing arguments into args vector and remove the receiver.
ArtMethod* non_proxy_method = proxy_method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
CHECK(!non_proxy_method->IsStatic()) << proxy_method->PrettyMethod() << " "
<< non_proxy_method->PrettyMethod();
std::vector<jvalue> args;
uint32_t shorty_len = 0;
const char* shorty = non_proxy_method->GetShorty(&shorty_len);
BuildQuickArgumentVisitor local_ref_visitor(
sp, /* is_static= */ false, shorty, shorty_len, &soa, &args);

local_ref_visitor.VisitArguments();
DCHECK_GT(args.size(), 0U) << proxy_method->PrettyMethod();
args.erase(args.begin());

// 将代理方法转变为期望的接口方法
ArtMethod* interface_method = proxy_method->FindOverriddenMethod(kRuntimePointerSize);
DCHECK(interface_method != nullptr) << proxy_method->PrettyMethod();
DCHECK(!interface_method->IsProxyMethod()) << interface_method->PrettyMethod();
DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
DCHECK(!Runtime::Current()->IsActiveTransaction());
ObjPtr<mirror::Method> interface_reflect_method =
mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), interface_method);
if (interface_reflect_method == nullptr) {
soa.Self()->AssertPendingOOMException();
return 0;
}
jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_reflect_method);

// All naked Object*s should now be in jobjects, so its safe to go into the main invoke code
// that performs allocations or instrumentation events.
instrumentation::Instrumentation* instr = Runtime::Current()->GetInstrumentation();
if (instr->HasMethodEntryListeners()) {
instr->MethodEnterEvent(soa.Self(),
soa.Decode<mirror::Object>(rcvr_jobj),
proxy_method,
0);
if (soa.Self()->IsExceptionPending()) {
instr->MethodUnwindEvent(self,
soa.Decode<mirror::Object>(rcvr_jobj),
proxy_method,
0);
return 0;
}
}
// 调用 InvocationHandler
JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args);
//...
return result.GetJ();
}
LinkClass

Welcome to my other publishing channels