插件化离不开代理与反射,反射我们已经很熟悉了,我们可以在各种各样的三方库中找到类似的使用,但是代理却感觉是一个抽象的概念。
代理模式
为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用(结构型)。
使用代理可以屏蔽内部实现细节,后续内部有变动对于外部调用者来说是封闭的,符合开放-封闭原则。用户可以放心地请求代理,他只关心是否能得到想要的结果。在任何使用本体的地方都可以替换成使用代理,从而实现实现和调用松耦合。
换句话说,就是让别人帮我们去完成我们想去完成的事情。
在代理模式又可以分为动态代理和静态代理,我们以java层的代理来说明两种形式
需求: 通过使用代理,在点击事件的前后,加入我们需要的log信息
既然要通过代理模式,那么我们是不能直接去修改onClick回调的,所以我们先吧固定的点击事件准备好:
btn1 = findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("onClick", ":onClick ");
startActivity(new Intent(MainActivity.this, TestActivity.class));
}
});
在完成需求之前 ,我们要考虑以下几个问题
- 我要代理这个对象的什么方法
- 怎么将我们自己的代理对象塞进去
首先,点击事件的公共入口都是View.OnclickListener 接口,在为View设置点击事件的接口时,View对象会将当前的点击事件保存下来
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
// 跟进getListenerInfo()
getListenerInfo().mOnClickListener = l;
}
//.........
// getListenerInfo为一个单例,返回了ListenerInfo 的对象
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
// .........
// ListenerInfo就是一个静态类,保存了所有关于事件的变量.
static class ListenerInfo {
protected OnFocusChangeListener mOnFocusChangeListener;
private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
protected OnScrollChangeListener mOnScrollChangeListener;
private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
public OnClickListener mOnClickListener;
protected OnLongClickListener mOnLongClickListener;
protected OnContextClickListener mOnContextClickListener;
protected OnCreateContextMenuListener mOnCreateContextMenuListener;
private OnKeyListener mOnKeyListener;
private OnTouchListener mOnTouchListener;
private OnHoverListener mOnHoverListener;
private OnGenericMotionListener mOnGenericMotionListener;
private OnDragListener mOnDragListener;
private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
OnCapturedPointerListener mOnCapturedPointerListener;
private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
}
所以 , 我们可以得出结论
- hook的目标为
View.setOnclickListener(View.OnClickListener listener)
这个方法.这个方法本质调用了getListenerInfo().mOnClickListener=listener
,我们可以拿到View的实例后获取该方法. - 如何赋值,通过反射的
filed.set(target,proxy)
完成,其中,target为getListenerInfo().mOnClickListener,proxy为我们代理的函数。
接下来我们使用两种形式的代理模式来完成需求
静态代理
// 先拿到ListenerInfo对象, 再对对象中的mOnClickListener赋值
public static void hook(Context context, final View v) {
try {
//首先获取getListenerInfo , 获取到实际的复制对象ListenerInfo
// 反射执行View类的getListenerInfo()方法,拿到v的mListenerInfo对象,这个对象就是点击事件的持有者
Method method = View.class.getDeclaredMethod("getListenerInfo");
method.setAccessible(true);//由于getListenerInfo()方法并不是public的,所以要加这个代码来保证访问权限
//调用method方法 , 返回ListenerInfo的实例
Object mListenerInfo = method.invoke(v);//这里拿到的就是mListenerInfo对象,也就是点击事件的持有者
//要从这里面拿到当前的点击事件对象
Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");// 这是内部类的表示方法
Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo);//取得真实的mOnClickListener对象
//2. 创建我们自己的点击事件代理类
ProxyOnClickListener proxyOnClickListener = new ProxyOnClickListener(onClickListenerInstance);
//3. 用我们自己的点击事件代理类,设置到"持有者"中
field.set(mListenerInfo, proxyOnClickListener);
//完成
} catch (Exception e) {
e.printStackTrace();
}
}
// 自定义代理类 , 实现了对 View.OnClickListener 的onClick的代理 , 我们可以在这里进行log的输出
static class ProxyOnClickListener implements View.OnClickListener {
View.OnClickListener oriLis;
ProxyOnClickListener(View.OnClickListener oriLis) {
this.oriLis = oriLis;
}
@Override
public void onClick(View v) {
Log.d("ProxyOnClickListener", "点击事件被hook到了");
if (oriLis != null) {
oriLis.onClick(v);
}
}
}
点击事件执行结果
动态代理
如果每一个需要代理的地方都需要去写一个代理类岂不是很麻烦么 ,java提供了Proxy这个类来辅助我们去创建代理类,接下来我们用动态代理去完成上面的需求
public static void hook(Context context, final View v) {//
try {
//首先获取getListenerInfo , 获取到实际的复制对象ListenerInfo
// 反射执行View类的getListenerInfo()方法,拿到v的mListenerInfo对象,这个对象就是点击事件的持有者
Method method = View.class.getDeclaredMethod("getListenerInfo");
method.setAccessible(true);//由于getListenerInfo()方法并不是public的,所以要加这个代码来保证访问权限
//调用method方法 , 返回ListenerInfo的实例
Object mListenerInfo = method.invoke(v);//这里拿到的就是mListenerInfo对象,也就是点击事件的持有者
//要从这里面拿到当前的点击事件对象
Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");// 这是内部类的表示方法
Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo);//取得真实的mOnClickListener对象
//2. 创建我们自己的点击事件代理类
// 方式2:由于View.OnClickListener是一个接口,所以可以直接用动态代理模式
// Proxy.newProxyInstance的3个参数依次分别是:
Object proxyOnClickListener = Proxy.newProxyInstance(
context.getClass().getClassLoader(), // 本地的类加载器;
new Class[]{View.OnClickListener.class},// 代理类的对象所继承的接口(用Class数组表示,支持多个接口)
new InvocationHandler() { // 代理类的实际逻辑,当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
/**
* @param proxy 被代理对象
* @param method 被代理的方法
* @param args 参数表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d("HookSetOnClickListener", "点击事件被hook到了");//加入自己的逻辑
return method.invoke(onClickListenerInstance, args);//执行被代理的对象的逻辑
}
});
Log.e("hook: getClass ", proxyOnClickListener.getClass().toString());
Log.e("hook: getInterfaces", proxyOnClickListener.getClass().getInterfaces().toString());
Log.e("hook: getMethods ", proxyOnClickListener.getClass().getMethods().toString());
// //3. 用我们自己的点击事件代理类,设置到"持有者"中
field.set(mListenerInfo, proxyOnClickListener);
//完成
} catch (Exception e) {
e.printStackTrace();
}
}
前面获取被代理的函数步骤都是一样的,区别在于我们的代理对象的创建,是通过
Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
来完成,其中第二个参数是interfaces的数组,也就是说被代理类可以多实现。但是这里为什么只能是一个接口呢?这个问题我们后文继续讨论。
第三个参数InvocationHandler是一个创建代理类的接口,接口回调中的参数已经在代码中标出.
在中间我们获取了代理类的实例后,我打印了一些类的信息,来辅助分析。
代理类的部分信息
这个代理类居然是$Proxy0? 我们并没有创建这个代理类啊,这个代理类究竟被创建到了什么地方?
动态代理分析:
- 为什么动态代理只能代理接口实现类而不是任意类呢?
- 动态代理的类放在那里?这个类是怎么凭空产生的?
准备工作: 谷歌翻译 AndroidXRef
首先,我们跟进Proxy.newInstance()的源码,看看官方对于这个参数的解释
@param interfaces the list of interfaces for the proxy class to implement
这里已经说明了这个参数必须是接口数组。我们不能就这么死心吧?我们直接换一个非接口实现类来试试用动态代理去代理它
这里参考了[欢哥的博客 - 初识-hook-机制]https://zhaomenghuan.js.org/blog/android-plugin-framework-proxy-hook.html#%E5%88%9D%E8%AF%86-hook-%E6%9C%BA%E5%88%B6) , 借用他对于startActivityForResult的静态代理 , 我们使用动态代理来分析一波.
public static void hookInstrumentation(MainActivity mainActivity) {
try {
// 拿到原始的 mInstrumentation字段
Field mInstrumentationField = Activity.class.getDeclaredField("mInstrumentation");
mInstrumentationField.setAccessible(true);
final Instrumentation originalInstrumentation = (Instrumentation) mInstrumentationField.get(mainActivity);
Object proxyIns = Proxy.newProxyInstance(
mainActivity.getClass().getClassLoader(), // 本地的类加载器;
new Class[]{originalInstrumentation.getClass()},// 代理类的对象所继承的接口(用Class数组表示,支持多个接口)
new InvocationHandler() { // 代理类的实际逻辑,当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
/**
* @param proxy 被代理对象
* @param method 被代理的方法
* @param args 参数表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d("Instrumentation", "Instrumentation事件被hook到了");//加入自己的逻辑
return method.invoke(originalInstrumentation, args);//执行被代理的对象的逻辑
}
});
//3. 用我们自己的点击事件代理类,设置到"持有者"中
mInstrumentationField.set(mainActivity, proxyIns);
} catch (Exception e) {
Log.e("hookInstrumentation", e.toString());
}
}
我们点击跳转之后, 并没有输出我们想要的log信息, 网上追踪logcat ,发现我们在调用这个静态方法的时候就已经报错;
E/hookInstrumentation: java.lang.IllegalArgumentException: android.app.Instrumentation is not an interface
看来动态代理只能对接口实现类使用 , 而非接口实现类, 如Instrumentation 只能使用静态代理了.
接下来我们带着上面的问题来扒一波源码
API: < Android API 28 Platform >
public static Object newProxyInstance(
ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException{
// 对InvocationHandler 判空
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
// 这个注释我们能看出来 , 这个版本对于之前版本做过一些修改:移除代理的安全校验
// Android-removed: SecurityManager calls
/*
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
*/
// 查找或生成指定的代理类。
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
// Android-removed: SecurityManager / permission checks.
/*
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
*/
// 拿到代理类的构造函数
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
// 返回创造完成的代理类的实例
return cons.newInstance(new Object[]{h});
} catch (Exception e) {
......
}
}
在这个方法中 , 仅仅是一局getProxyClass0(loader, intfs);
就完成了代理类的创建.我们跟进代码
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 接口数量上限控制
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
简单翻译一下:
如果由实现了给定接口的给定加载器定义的代理类存在,则将简单地返回缓存的副本; 否则,它将通过ProxyClassFactory创建代理类。虽然是一个get的操作 , 但总是不为空的。首先我们开搞清楚这是个什么东西
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
有点懵? 猜一下 , 像是一个缓存 , 这里我暂时不去深究了, 有兴趣的大佬可以去研究一波https://www.iteye.com/blog/xiaoxiaoher-2372315
。初始化时会传入两个工厂:KeyFactory和ProxyClassFactory。
在上面的方法中,第一个参数对应了classLoader,第二个参数为Interfaces ,为了尽快接近我们提出的问题1 ,我们先来看看第二个工厂类ProxyClassFactory。
又要贴出长长的代码了,这里我把代码分成两个部分来看。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 所有代理类名称的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 下一个用于生成唯一代理类名称的数字
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 验证指定的类加载器(loader)加载接口所得到的Class对象(interfaceClass)是否与intf对象相同
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 验证传入的class对象是不是接口 , 由此,我们的第一个问题得以解决: 因为SDK里面不让我们这么传 - -
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());
}
}
我们的第一个问题的答案就在这里找到了, 动态代理传入的Class[]对象在内部会进行类型检查, 如果不是接口则会抛出异常。
其实我们也可以这么来理解:java是单继承多实现的 ,既然我们代理类的生成结果都是继承了Proxy类,然后再去实现了其他接口,那么必然不能直接传一个非接口对象,要不然和java的单继承就相悖了。我们继续看接下来的代码
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use the default package.
proxyPkg = "";
}
{
// Android-changed: Generate the proxy directly instead of calling
// through to 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();
// 拼接代理类的类名,我们大致能看到的样子就是 xxxx$proxy0.class
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成代理类
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
最够追到生成代理类的代码 ,却发现这是一个调用了JNI的函数
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
ClassLoader loader, Method[] methods,
Class<?>[][] exceptions);
在AndroidXRef中搜索 , 可以看到改JNI函数位于java_lang_reflect_Proxy.cc中
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();
return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
soa, name, interfaces, loader, methods, throws));
}
跟进class_linker->CreateProxyClass()
这个函数 , 位于class_linker.cc中
ps:这个类比较大,用网页加载直接死掉了,建议下载下来再看。
由于鄙人对于C层的代码基本没怎么看过,所以只能以注释为主先来宏观理解一下了,欢迎有经验的前辈们指教。
这里贴出简(汉)化后的代码
mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
jstring name,
jobjectArray interfaces,
jobject loader,
jobjectArray methods,
jobjectArray throws) {
Thread* self = soa.Self();
StackHandleScope<10> hs(self);
MutableHandle<mirror::Class> temp_klass(hs.NewHandle(
AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
if (temp_klass == nullptr) {
CHECK(self->IsExceptionPending()); // OOME.
return nullptr;
}
DCHECK(temp_klass->GetClass() != nullptr);
temp_klass->SetObjectSize(sizeof(mirror::Proxy));
// 设置包含类的访问标志AccessFlags,可以看到代理类是public final的
temp_klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader));
DCHECK_EQ(temp_klass->GetPrimitiveType(), Primitive::kPrimNot);
temp_klass->SetName(soa.Decode<mirror::String>(name));
temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
// Object有一个空的 iftable, 所以这里直接拷贝.
temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusIdx, self);
std::string descriptor(GetDescriptorForProxy(temp_klass.Get()));
const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
// 在插入类之前需要先设置好内存分配器。
LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(temp_klass->GetClassLoader());
// 在加载字段之前插入类,因为仅从类表访问字段根ArtField :: declaring_class_)
// 所以插入类和设置下面的字段数组之间不能有任何暂停点。
ObjPtr<mirror::Class> existing = InsertClass(descriptor.c_str(), temp_klass.Get(), hash);
CHECK(existing == nullptr);
// 实例字段是继承的,但是我们添加了两个静态字段...
const size_t num_fields = 2;
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields);
temp_klass->SetSFieldsPtr(sfields);
// 1.创建一个静态字段“ interfaces”,其中包含由_declared_接口实现的
// 我们的代理,因此Class.getInterfaces不返回展开的集合。
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);
// 代理类会有一个直接方法, 即构造函数
const size_t num_direct_methods = 1;
// 它们具有与数组一样多的虚拟方法
auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods));
DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass())
<< mirror::Class::PrettyClass(h_methods->GetClass());
const size_t num_virtual_methods = h_methods->GetLength();
// 创建方法数组.
LengthPrefixedArray<ArtMethod>* proxy_class_methods = AllocArtMethodArray(
self, allocator, num_direct_methods + num_virtual_methods);
// 当前,AllocArtMethodArray不能返回null,但是OOM逻辑保留在那里,以防将来我们要抛出OOM。
if (UNLIKELY(proxy_class_methods == nullptr)) {
self->AssertPendingOOMException();
return nullptr;
}
temp_klass->SetMethodsPtr(proxy_class_methods, num_direct_methods, num_virtual_methods);
// 创建一个直接方法
CreateProxyConstructor(temp_klass, temp_klass->GetDirectMethodUnchecked(0, image_pointer_size_));
// 使用指定的原型创建虚拟方法。
// TODO These should really use the iterators.
for (size_t i = 0; i < num_virtual_methods; ++i) {
auto* virtual_method = temp_klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
auto* prototype = h_methods->Get(i)->GetArtMethod();
CreateProxyMethod(temp_klass, prototype, virtual_method);
DCHECK(virtual_method->GetDeclaringClass() != nullptr);
DCHECK(prototype->GetDeclaringClass() != nullptr);
}
// 父类是 java.lang.reflect.Proxy
temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy));
// 现在有效地处于加载状态.
mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusLoaded, self);
self->AssertNoPendingException();
// 此时,该类已加载。 发布一个ClassLoad事件。
// 注意:这可能是临时类。需要监听者去处理。
Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(temp_klass);
MutableHandle<mirror::Class> klass = hs.NewHandle<mirror::Class>(nullptr);
{
// 处理时加锁
ObjectLock<mirror::Class> resolution_lock(self, temp_klass);
// Link the fields and virtual methods, creating vtable and iftables.
// The new class will replace the old one in the class table.
Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
if (!LinkClass(self, descriptor.c_str(), temp_klass, h_interfaces, &klass)) {
mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusErrorUnresolved, self);
return nullptr;
}
}
CHECK(temp_klass->IsRetired());
CHECK_NE(temp_klass.Get(), klass.Get());
CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get());
interfaces_sfield.SetObject<false>(
klass.Get(),
soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces));
CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get());
throws_sfield.SetObject<false>(
klass.Get(),
soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws));
Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(temp_klass, klass);
{
//释放对klass的锁定。 锁定新的类对象。
ObjectLock<mirror::Class> initialization_lock(self, klass);
mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self);
}
// 健全性检查
if (kIsDebugBuild) {
CHECK(klass->GetIFieldsPtr() == nullptr);
CheckProxyConstructor(klass->GetDirectMethod(0, image_pointer_size_));
for (size_t i = 0; i < num_virtual_methods; ++i) {
auto* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
auto* prototype = h_methods->Get(i++)->GetArtMethod();
CheckProxyMethod(virtual_method, prototype);
}
StackHandleScope<1> hs2(self);
Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String>(name));
std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces",
decoded_name->ToModifiedUtf8().c_str()));
CHECK_EQ(ArtField::PrettyField(klass->GetStaticField(0)), interfaces_field_name);
std::string throws_field_name(StringPrintf("java.lang.Class[][] %s.throws",
decoded_name->ToModifiedUtf8().c_str()));
CHECK_EQ(ArtField::PrettyField(klass->GetStaticField(1)), throws_field_name);
CHECK_EQ(klass.Get()->GetProxyInterfaces(),
soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces));
CHECK_EQ(klass.Get()->GetProxyThrows(),
soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws));
}
return klass.Get();
}
朦朦胧胧的通过注释, 大概理清楚了创建一个类需要的成分以及步骤. 也大致对类所包含的元素有了个更深的概念,如AccessFlags ,iftable, MethodArray等,以后用到了这部分的东西再回过头来补全吧。勉强解决我们了的第二个问题。
参考:
https://zhaomenghuan.js.org/blog/android-plugin-framework-proxy-hook.html
https://www.cnblogs.com/MOBIN/p/5597215.html
http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/
网友评论