插件化離不開代理與反射,反射我們已經(jīng)很熟悉了,我們可以在各種各樣的三方庫(kù)中找到類似的使用,但是代理卻感覺是一個(gè)抽象的概念。
代理模式
為其他對(duì)象提供一種代理,以控制對(duì)這個(gè)對(duì)象的訪問。代理對(duì)象在客戶端和目標(biāo)對(duì)象之間起到中介的作用(結(jié)構(gòu)型)。
使用代理可以屏蔽內(nèi)部實(shí)現(xiàn)細(xì)節(jié),后續(xù)內(nèi)部有變動(dòng)對(duì)于外部調(diào)用者來(lái)說(shuō)是封閉的,符合開放-封閉原則。用戶可以放心地請(qǐng)求代理,他只關(guān)心是否能得到想要的結(jié)果。在任何使用本體的地方都可以替換成使用代理,從而實(shí)現(xiàn)實(shí)現(xiàn)和調(diào)用松耦合。
換句話說(shuō),就是讓別人幫我們?nèi)ネ瓿晌覀兿肴ネ瓿傻氖虑椤?/p>
在代理模式又可以分為動(dòng)態(tài)代理和靜態(tài)代理,我們以java層的代理來(lái)說(shuō)明兩種形式
需求: 通過(guò)使用代理,在點(diǎn)擊事件的前后,加入我們需要的log信息
既然要通過(guò)代理模式,那么我們是不能直接去修改onClick回調(diào)的,所以我們先吧固定的點(diǎn)擊事件準(zhǔn)備好:
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));
}
});
在完成需求之前 ,我們要考慮以下幾個(gè)問題
- 我要代理這個(gè)對(duì)象的什么方法
- 怎么將我們自己的代理對(duì)象塞進(jìn)去
首先,點(diǎn)擊事件的公共入口都是View.OnclickListener 接口,在為View設(shè)置點(diǎn)擊事件的接口時(shí),View對(duì)象會(huì)將當(dāng)前的點(diǎn)擊事件保存下來(lái)
public void setOnClickListener(@Nullable OnClickListener l) {
if (!isClickable()) {
setClickable(true);
}
// 跟進(jìn)getListenerInfo()
getListenerInfo().mOnClickListener = l;
}
//.........
// getListenerInfo為一個(gè)單例,返回了ListenerInfo 的對(duì)象
ListenerInfo getListenerInfo() {
if (mListenerInfo != null) {
return mListenerInfo;
}
mListenerInfo = new ListenerInfo();
return mListenerInfo;
}
// .........
// ListenerInfo就是一個(gè)靜態(tài)類,保存了所有關(guān)于事件的變量.
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;
}
所以 , 我們可以得出結(jié)論
- hook的目標(biāo)為
View.setOnclickListener(View.OnClickListener listener)這個(gè)方法.這個(gè)方法本質(zhì)調(diào)用了getListenerInfo().mOnClickListener=listener,我們可以拿到View的實(shí)例后獲取該方法. - 如何賦值,通過(guò)反射的
filed.set(target,proxy)完成,其中,target為getListenerInfo().mOnClickListener,proxy為我們代理的函數(shù)。
接下來(lái)我們使用兩種形式的代理模式來(lái)完成需求
靜態(tài)代理
// 先拿到ListenerInfo對(duì)象, 再對(duì)對(duì)象中的mOnClickListener賦值
public static void hook(Context context, final View v) {
try {
//首先獲取getListenerInfo , 獲取到實(shí)際的復(fù)制對(duì)象ListenerInfo
// 反射執(zhí)行View類的getListenerInfo()方法,拿到v的mListenerInfo對(duì)象,這個(gè)對(duì)象就是點(diǎn)擊事件的持有者
Method method = View.class.getDeclaredMethod("getListenerInfo");
method.setAccessible(true);//由于getListenerInfo()方法并不是public的,所以要加這個(gè)代碼來(lái)保證訪問權(quán)限
//調(diào)用method方法 , 返回ListenerInfo的實(shí)例
Object mListenerInfo = method.invoke(v);//這里拿到的就是mListenerInfo對(duì)象,也就是點(diǎn)擊事件的持有者
//要從這里面拿到當(dāng)前的點(diǎn)擊事件對(duì)象
Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");// 這是內(nèi)部類的表示方法
Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo);//取得真實(shí)的mOnClickListener對(duì)象
//2. 創(chuàng)建我們自己的點(diǎn)擊事件代理類
ProxyOnClickListener proxyOnClickListener = new ProxyOnClickListener(onClickListenerInstance);
//3. 用我們自己的點(diǎn)擊事件代理類,設(shè)置到"持有者"中
field.set(mListenerInfo, proxyOnClickListener);
//完成
} catch (Exception e) {
e.printStackTrace();
}
}
// 自定義代理類 , 實(shí)現(xiàn)了對(duì) View.OnClickListener 的onClick的代理 , 我們可以在這里進(jìn)行l(wèi)og的輸出
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", "點(diǎn)擊事件被hook到了");
if (oriLis != null) {
oriLis.onClick(v);
}
}
}

動(dòng)態(tài)代理
如果每一個(gè)需要代理的地方都需要去寫一個(gè)代理類豈不是很麻煩么 ,java提供了Proxy這個(gè)類來(lái)輔助我們?nèi)?chuàng)建代理類,接下來(lái)我們用動(dòng)態(tài)代理去完成上面的需求
public static void hook(Context context, final View v) {//
try {
//首先獲取getListenerInfo , 獲取到實(shí)際的復(fù)制對(duì)象ListenerInfo
// 反射執(zhí)行View類的getListenerInfo()方法,拿到v的mListenerInfo對(duì)象,這個(gè)對(duì)象就是點(diǎn)擊事件的持有者
Method method = View.class.getDeclaredMethod("getListenerInfo");
method.setAccessible(true);//由于getListenerInfo()方法并不是public的,所以要加這個(gè)代碼來(lái)保證訪問權(quán)限
//調(diào)用method方法 , 返回ListenerInfo的實(shí)例
Object mListenerInfo = method.invoke(v);//這里拿到的就是mListenerInfo對(duì)象,也就是點(diǎn)擊事件的持有者
//要從這里面拿到當(dāng)前的點(diǎn)擊事件對(duì)象
Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");// 這是內(nèi)部類的表示方法
Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo);//取得真實(shí)的mOnClickListener對(duì)象
//2. 創(chuàng)建我們自己的點(diǎn)擊事件代理類
// 方式2:由于View.OnClickListener是一個(gè)接口,所以可以直接用動(dòng)態(tài)代理模式
// Proxy.newProxyInstance的3個(gè)參數(shù)依次分別是:
Object proxyOnClickListener = Proxy.newProxyInstance(
context.getClass().getClassLoader(), // 本地的類加載器;
new Class[]{View.OnClickListener.class},// 代理類的對(duì)象所繼承的接口(用Class數(shù)組表示,支持多個(gè)接口)
new InvocationHandler() { // 代理類的實(shí)際邏輯,當(dāng)我這個(gè)動(dòng)態(tài)代理對(duì)象在調(diào)用方法的時(shí)候,會(huì)關(guān)聯(lián)到哪一個(gè)InvocationHandler對(duì)象上
/**
* @param proxy 被代理對(duì)象
* @param method 被代理的方法
* @param args 參數(shù)表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d("HookSetOnClickListener", "點(diǎn)擊事件被hook到了");//加入自己的邏輯
return method.invoke(onClickListenerInstance, args);//執(zhí)行被代理的對(duì)象的邏輯
}
});
Log.e("hook: getClass ", proxyOnClickListener.getClass().toString());
Log.e("hook: getInterfaces", proxyOnClickListener.getClass().getInterfaces().toString());
Log.e("hook: getMethods ", proxyOnClickListener.getClass().getMethods().toString());
// //3. 用我們自己的點(diǎn)擊事件代理類,設(shè)置到"持有者"中
field.set(mListenerInfo, proxyOnClickListener);
//完成
} catch (Exception e) {
e.printStackTrace();
}
}
前面獲取被代理的函數(shù)步驟都是一樣的,區(qū)別在于我們的代理對(duì)象的創(chuàng)建,是通過(guò)
Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)來(lái)完成,其中第二個(gè)參數(shù)是interfaces的數(shù)組,也就是說(shuō)被代理類可以多實(shí)現(xiàn)。但是這里為什么只能是一個(gè)接口呢?這個(gè)問題我們后文繼續(xù)討論。
第三個(gè)參數(shù)InvocationHandler是一個(gè)創(chuàng)建代理類的接口,接口回調(diào)中的參數(shù)已經(jīng)在代碼中標(biāo)出.
在中間我們獲取了代理類的實(shí)例后,我打印了一些類的信息,來(lái)輔助分析。


這個(gè)代理類居然是$Proxy0? 我們并沒有創(chuàng)建這個(gè)代理類啊,這個(gè)代理類究竟被創(chuàng)建到了什么地方?
動(dòng)態(tài)代理分析:
- 為什么動(dòng)態(tài)代理只能代理接口實(shí)現(xiàn)類而不是任意類呢?
- 動(dòng)態(tài)代理的類放在那里?這個(gè)類是怎么憑空產(chǎn)生的?
準(zhǔn)備工作: 谷歌翻譯 AndroidXRef
首先,我們跟進(jìn)Proxy.newInstance()的源碼,看看官方對(duì)于這個(gè)參數(shù)的解釋
@param interfaces the list of interfaces for the proxy class to implement
這里已經(jīng)說(shuō)明了這個(gè)參數(shù)必須是接口數(shù)組。我們不能就這么死心吧?我們直接換一個(gè)非接口實(shí)現(xiàn)類來(lái)試試用動(dòng)態(tài)代理去代理它
這里參考了[歡哥的博客 - 初識(shí)-hook-機(jī)制]https://zhaomenghuan.js.org/blog/android-plugin-framework-proxy-hook.html#%E5%88%9D%E8%AF%86-hook-%E6%9C%BA%E5%88%B6) , 借用他對(duì)于startActivityForResult的靜態(tài)代理 , 我們使用動(dòng)態(tài)代理來(lái)分析一波.
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()},// 代理類的對(duì)象所繼承的接口(用Class數(shù)組表示,支持多個(gè)接口)
new InvocationHandler() { // 代理類的實(shí)際邏輯,當(dāng)我這個(gè)動(dòng)態(tài)代理對(duì)象在調(diào)用方法的時(shí)候,會(huì)關(guān)聯(lián)到哪一個(gè)InvocationHandler對(duì)象上
/**
* @param proxy 被代理對(duì)象
* @param method 被代理的方法
* @param args 參數(shù)表
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d("Instrumentation", "Instrumentation事件被hook到了");//加入自己的邏輯
return method.invoke(originalInstrumentation, args);//執(zhí)行被代理的對(duì)象的邏輯
}
});
//3. 用我們自己的點(diǎn)擊事件代理類,設(shè)置到"持有者"中
mInstrumentationField.set(mainActivity, proxyIns);
} catch (Exception e) {
Log.e("hookInstrumentation", e.toString());
}
}
我們點(diǎn)擊跳轉(zhuǎn)之后, 并沒有輸出我們想要的log信息, 網(wǎng)上追蹤logcat ,發(fā)現(xiàn)我們?cè)谡{(diào)用這個(gè)靜態(tài)方法的時(shí)候就已經(jīng)報(bào)錯(cuò);
E/hookInstrumentation: java.lang.IllegalArgumentException: android.app.Instrumentation is not an interface
看來(lái)動(dòng)態(tài)代理只能對(duì)接口實(shí)現(xiàn)類使用 , 而非接口實(shí)現(xiàn)類, 如Instrumentation 只能使用靜態(tài)代理了.
接下來(lái)我們帶著上面的問題來(lái)扒一波源碼
API: < Android API 28 Platform >
public static Object newProxyInstance(
ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException{
// 對(duì)InvocationHandler 判空
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
// 這個(gè)注釋我們能看出來(lái) , 這個(gè)版本對(duì)于之前版本做過(guò)一些修改:移除代理的安全校驗(yàn)
// 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);
}
*/
// 拿到代理類的構(gòu)造函數(shù)
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
// 返回創(chuàng)造完成的代理類的實(shí)例
return cons.newInstance(new Object[]{h});
} catch (Exception e) {
......
}
}
在這個(gè)方法中 , 僅僅是一局getProxyClass0(loader, intfs);就完成了代理類的創(chuàng)建.我們跟進(jìn)代碼
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 接口數(shù)量上限控制
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);
}
簡(jiǎn)單翻譯一下:
如果由實(shí)現(xiàn)了給定接口的給定加載器定義的代理類存在,則將簡(jiǎn)單地返回緩存的副本; 否則,它將通過(guò)ProxyClassFactory創(chuàng)建代理類。雖然是一個(gè)get的操作 , 但總是不為空的。首先我們開搞清楚這是個(gè)什么東西
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
有點(diǎn)懵? 猜一下 , 像是一個(gè)緩存 , 這里我暫時(shí)不去深究了, 有興趣的大佬可以去研究一波https://www.iteye.com/blog/xiaoxiaoher-2372315
。初始化時(shí)會(huì)傳入兩個(gè)工廠:KeyFactory和ProxyClassFactory。
在上面的方法中,第一個(gè)參數(shù)對(duì)應(yīng)了classLoader,第二個(gè)參數(shù)為Interfaces ,為了盡快接近我們提出的問題1 ,我們先來(lái)看看第二個(gè)工廠類ProxyClassFactory。
又要貼出長(zhǎng)長(zhǎng)的代碼了,這里我把代碼分成兩個(gè)部分來(lái)看。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 所有代理類名稱的前綴
private static final String proxyClassNamePrefix = "$Proxy";
// 下一個(gè)用于生成唯一代理類名稱的數(shù)字
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) {
// 驗(yàn)證指定的類加載器(loader)加載接口所得到的Class對(duì)象(interfaceClass)是否與intf對(duì)象相同
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");
}
// 驗(yàn)證傳入的class對(duì)象是不是接口 , 由此,我們的第一個(gè)問題得以解決: 因?yàn)镾DK里面不讓我們這么傳 - -
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 驗(yàn)證接口是否重復(fù)
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
我們的第一個(gè)問題的答案就在這里找到了, 動(dòng)態(tài)代理傳入的Class[]對(duì)象在內(nèi)部會(huì)進(jìn)行類型檢查, 如果不是接口則會(huì)拋出異常。
其實(shí)我們也可以這么來(lái)理解:java是單繼承多實(shí)現(xiàn)的 ,既然我們代理類的生成結(jié)果都是繼承了Proxy類,然后再去實(shí)現(xiàn)了其他接口,那么必然不能直接傳一個(gè)非接口對(duì)象,要不然和java的單繼承就相悖了。我們繼續(xù)看接下來(lái)的代碼
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()][]);
// 代理類的計(jì)數(shù)器加一
long num = nextUniqueNumber.getAndIncrement();
// 拼接代理類的類名,我們大致能看到的樣子就是 xxxx$proxy0.class
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成代理類
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
最夠追到生成代理類的代碼 ,卻發(fā)現(xiàn)這是一個(gè)調(diào)用了JNI的函數(shù)
private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
ClassLoader loader, Method[] methods,
Class<?>[][] exceptions);
在AndroidXRef中搜索 , 可以看到改JNI函數(shù)位于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));
}
跟進(jìn)class_linker->CreateProxyClass()這個(gè)函數(shù) , 位于class_linker.cc中
ps:這個(gè)類比較大,用網(wǎng)頁(yè)加載直接死掉了,建議下載下來(lái)再看。
由于鄙人對(duì)于C層的代碼基本沒怎么看過(guò),所以只能以注釋為主先來(lái)宏觀理解一下了,歡迎有經(jīng)驗(yàn)的前輩們指教。
這里貼出簡(jiǎn)(漢)化后的代碼
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));
// 設(shè)置包含類的訪問標(biāo)志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有一個(gè)空的 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());
// 在插入類之前需要先設(shè)置好內(nèi)存分配器。
LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(temp_klass->GetClassLoader());
// 在加載字段之前插入類,因?yàn)閮H從類表訪問字段根ArtField :: declaring_class_)
// 所以插入類和設(shè)置下面的字段數(shù)組之間不能有任何暫停點(diǎn)。
ObjPtr<mirror::Class> existing = InsertClass(descriptor.c_str(), temp_klass.Get(), hash);
CHECK(existing == nullptr);
// 實(shí)例字段是繼承的,但是我們添加了兩個(gè)靜態(tài)字段...
const size_t num_fields = 2;
LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields);
temp_klass->SetSFieldsPtr(sfields);
// 1.創(chuàng)建一個(gè)靜態(tài)字段“ interfaces”,其中包含由_declared_接口實(shí)現(xiàn)的
// 我們的代理,因此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.創(chuàng)建一個(gè)靜態(tài)字段“ throws”,其中包含我們的方法拋出的異常。
ArtField& throws_sfield = sfields->At(1);
throws_sfield.SetDexFieldIndex(1);
throws_sfield.SetDeclaringClass(temp_klass.Get());
throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
// 代理類會(huì)有一個(gè)直接方法, 即構(gòu)造函數(shù)
const size_t num_direct_methods = 1;
// 它們具有與數(shù)組一樣多的虛擬方法
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();
// 創(chuàng)建方法數(shù)組.
LengthPrefixedArray<ArtMethod>* proxy_class_methods = AllocArtMethodArray(
self, allocator, num_direct_methods + num_virtual_methods);
// 當(dāng)前,AllocArtMethodArray不能返回null,但是OOM邏輯保留在那里,以防將來(lái)我們要拋出OOM。
if (UNLIKELY(proxy_class_methods == nullptr)) {
self->AssertPendingOOMException();
return nullptr;
}
temp_klass->SetMethodsPtr(proxy_class_methods, num_direct_methods, num_virtual_methods);
// 創(chuàng)建一個(gè)直接方法
CreateProxyConstructor(temp_klass, temp_klass->GetDirectMethodUnchecked(0, image_pointer_size_));
// 使用指定的原型創(chuàng)建虛擬方法。
// 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));
// 現(xiàn)在有效地處于加載狀態(tài).
mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusLoaded, self);
self->AssertNoPendingException();
// 此時(shí),該類已加載。 發(fā)布一個(gè)ClassLoad事件。
// 注意:這可能是臨時(shí)類。需要監(jiān)聽者去處理。
Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(temp_klass);
MutableHandle<mirror::Class> klass = hs.NewHandle<mirror::Class>(nullptr);
{
// 處理時(shí)加鎖
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);
{
//釋放對(duì)klass的鎖定。 鎖定新的類對(duì)象。
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();
}
朦朦朧朧的通過(guò)注釋, 大概理清楚了創(chuàng)建一個(gè)類需要的成分以及步驟. 也大致對(duì)類所包含的元素有了個(gè)更深的概念,如AccessFlags ,iftable, MethodArray等,以后用到了這部分的東西再回過(guò)頭來(lái)補(bǔ)全吧。勉強(qiáng)解決我們了的第二個(gè)問題。
參考:
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/