Skip to content

Commit 2ae7930

Browse files
committed
fix(core): BroadcastReceiver不再以Wrapper方式支持
Shadow对于BroadcastReceiver所需的处理只涉及onReceive方法传回的参数。 由于插件的BroadcastReceiver是通过正常的Context对象直接注册到系统中的, 所以对于系统来说这些BroadcastReceiver和宿主的其他BroadcastReceiver 没有什么区别。系统回调onReceive方法时传回的Context和Intent也都是宿主的。 其中需要把Context换回ShadowContext,Intent中的ClassLoader换回插件的。 Tencent#865#issuecomment-1134246493指出:系统控件 ViewFlipper 在 onAttachedToWindow() 方法中使用 Contenxt.registerReceiverAsUser 方法进行广播注册;在 onDetachedFromWindow() 方法中使用 Context.unregisterReceiver 方法进行取消广播注册。 本地提交改为通过Transform修改插件中的onReceive方法,在BroadcastReceiver 内部进行参数转换。从而避免引入新的类型,同时也不依赖如何注册和反注册Receiver。 fix Tencent#865 close Tencent#1105
1 parent 8d9c7a7 commit 2ae7930

File tree

13 files changed

+403
-93
lines changed

13 files changed

+403
-93
lines changed

projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/BroadcastReceiverWrapper.java

-23
This file was deleted.

projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowApplication.java

-31
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,6 @@ public class ShadowApplication extends ShadowContext {
5050

5151
public boolean isCallOnCreate;
5252

53-
/**
54-
* BroadcastReceiver到BroadcastReceiverWrapper对象到映射关系
55-
* <p>
56-
* 采用WeakHashMap<BroadcastReceiver, WeakReference<BroadcastReceiverWrapper>>
57-
* 使key和value都采用弱引用持有,以保持原本BroadcastReceiver的GC回收时机。
58-
* <p>
59-
* BroadcastReceiver由原有业务代码强持有(也可能不持有),BroadcastReceiver原本在registerReceiver
60-
* 之后交由系统持有,现在由BroadcastReceiverWrapper代替它被系统强持有。
61-
* 所以BroadcastReceiverWrapper强引用持有BroadcastReceiver,保持了系统强引用BroadcastReceiver的关系。
62-
* <p>
63-
* 如果业务原本没有持有BroadcastReceiver,也就不会再有unregisterReceiver调用来,
64-
* 也就不需要Map中有wrapper对应关系,所以用弱引用持有此关系没有影响。
65-
*/
66-
final private Map<BroadcastReceiver, WeakReference<BroadcastReceiverWrapper>>
67-
mReceiverWrapperMap = new WeakHashMap<>();
68-
6953
@Override
7054
public Context getApplicationContext() {
7155
return this;
@@ -196,19 +180,4 @@ public static String getProcessName() {
196180
return Application.getProcessName();
197181
}
198182

199-
public BroadcastReceiverWrapper receiverToWrapper(BroadcastReceiver receiver) {
200-
if (receiver == null) {
201-
return null;
202-
}
203-
synchronized (mReceiverWrapperMap) {
204-
WeakReference<BroadcastReceiverWrapper> weakReference
205-
= mReceiverWrapperMap.get(receiver);
206-
BroadcastReceiverWrapper wrapper = weakReference == null ? null : weakReference.get();
207-
if (wrapper == null) {
208-
wrapper = new BroadcastReceiverWrapper(receiver, this);
209-
mReceiverWrapperMap.put(receiver, new WeakReference<>(wrapper));
210-
}
211-
return wrapper;
212-
}
213-
}
214183
}

projects/sdk/core/runtime/src/main/java/com/tencent/shadow/core/runtime/ShadowContext.java

-38
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,15 @@
1818

1919
package com.tencent.shadow.core.runtime;
2020

21-
import android.content.BroadcastReceiver;
2221
import android.content.ComponentName;
2322
import android.content.Context;
2423
import android.content.Intent;
25-
import android.content.IntentFilter;
2624
import android.content.ServiceConnection;
2725
import android.content.pm.ApplicationInfo;
2826
import android.content.res.AssetManager;
2927
import android.content.res.Resources;
3028
import android.os.Build;
3129
import android.os.Bundle;
32-
import android.os.Handler;
3330
import android.text.TextUtils;
3431
import android.util.Pair;
3532
import android.view.LayoutInflater;
@@ -234,44 +231,9 @@ public String getPackageName() {
234231
return mApplicationInfo.packageName;
235232
}
236233

237-
238-
@Override
239-
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
240-
return super.registerReceiver(receiverToWrapper(receiver), filter);
241-
}
242-
243-
@Override
244-
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
245-
return super.registerReceiver(receiverToWrapper(receiver), filter, flags);
246-
}
247-
248-
@Override
249-
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) {
250-
return super.registerReceiver(receiverToWrapper(receiver), filter, broadcastPermission, scheduler);
251-
}
252-
253-
@Override
254-
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
255-
return super.registerReceiver(receiverToWrapper(receiver), filter, broadcastPermission, scheduler, flags);
256-
}
257-
258-
@Override
259-
public void unregisterReceiver(BroadcastReceiver receiver) {
260-
BroadcastReceiverWrapper wrapper = receiverToWrapper(receiver);
261-
if (wrapper != null) {
262-
super.unregisterReceiver(wrapper);
263-
} else {
264-
super.unregisterReceiver(receiver);
265-
}
266-
}
267-
268234
@Override
269235
public String getPackageCodePath() {
270236
PluginPartInfo pluginInfo = PluginPartInfoManager.getPluginInfo(getClassLoader());
271237
return pluginInfo.packageManager.getArchiveFilePath();
272238
}
273-
274-
private BroadcastReceiverWrapper receiverToWrapper(BroadcastReceiver receiver) {
275-
return mShadowApplication.receiverToWrapper(receiver);
276-
}
277239
}

projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/TransformManager.kt

+1
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@ class TransformManager(
5656
LayoutInflaterTransform(),
5757
KeepHostContextTransform(useHostContext()),
5858
ActivityOptionsSupportTransform(),
59+
ReceiverSupportTransform(),
5960
)
6061
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Tencent is pleased to support the open source community by making Tencent Shadow available.
3+
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
4+
*
5+
* Licensed under the BSD 3-Clause License (the "License"); you may not use
6+
* this file except in compliance with the License. You may obtain a copy of
7+
* the License at
8+
*
9+
* https://opensource.org/licenses/BSD-3-Clause
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*/
18+
19+
package com.tencent.shadow.core.transform.specific
20+
21+
import com.tencent.shadow.core.transform_kit.SpecificTransform
22+
import com.tencent.shadow.core.transform_kit.TransformStep
23+
import javassist.*
24+
import javassist.compiler.Javac.CtFieldWithInit
25+
26+
/**
27+
* 系统回调BroadcastReceiver的onReceive(Context context, Intent intent)方法时:
28+
* 1. 传回的context是宿主的,需要修改为插件的。
29+
* 2. intent的ExtrasClassLoader是宿主的,需要改为插件的。
30+
*
31+
* 如果是系统类的BroadcastReceiver,它也不会和插件的context或classloader有什么联系,
32+
* 所以我们只需要修改插件代码中的BroadcastReceiver。
33+
*
34+
* 把原本插件的onReceive方法改个名字,再统一添加一个onReceive方法。
35+
* 在新增的onReceive方法中修改收到的系统回调参数,再转调被改名了的原本插件的onReceive方法。
36+
*/
37+
class ReceiverSupportTransform : SpecificTransform() {
38+
39+
companion object {
40+
const val AndroidBroadcastReceiverClassname = "android.content.BroadcastReceiver"
41+
const val AndroidContextClassname = "android.content.Context"
42+
const val AndroidIntentClassname = "android.content.Intent"
43+
}
44+
45+
private fun CtClass.isReceiver(): Boolean = isClassOf(AndroidBroadcastReceiverClassname)
46+
47+
override fun setup(allInputClass: Set<CtClass>) {
48+
mClassPool.importPackage("android.content")
49+
mClassPool.importPackage("com.tencent.shadow.core.runtime")
50+
51+
val androidContext = mClassPool[AndroidContextClassname]
52+
val androidIntent = mClassPool[AndroidIntentClassname]
53+
54+
/**
55+
* 收集覆盖了onReceive方法的Receiver作为修改目标
56+
*/
57+
val targetReceivers = mutableSetOf<CtClass>()
58+
newStep(object : TransformStep {
59+
override fun filter(allInputClass: Set<CtClass>) = allInputClass
60+
.filter { it.isReceiver() }
61+
.toSet()
62+
63+
override fun transform(ctClass: CtClass) {
64+
val onReceiveMethod: CtMethod? =
65+
try {
66+
ctClass.getDeclaredMethod(
67+
"onReceive",
68+
arrayOf(androidContext, androidIntent)
69+
)
70+
} catch (e: NotFoundException) {
71+
null
72+
}
73+
if (onReceiveMethod != null) {
74+
targetReceivers.add(ctClass)
75+
}
76+
}
77+
})
78+
79+
/**
80+
* 对原本的onReceive方法改名,并添加新的onReceive方法。
81+
*/
82+
newStep(object : TransformStep {
83+
override fun filter(allInputClass: Set<CtClass>) = targetReceivers
84+
85+
override fun transform(ctClass: CtClass) {
86+
ctClass.defrost()
87+
88+
// 改名
89+
val originalOnReceiveMethod: CtMethod =
90+
ctClass.getDeclaredMethod(
91+
"onReceive",
92+
arrayOf(androidContext, androidIntent)
93+
)
94+
originalOnReceiveMethod.name = "onReceiveShadowContext"
95+
originalOnReceiveMethod.modifiers =
96+
Modifier.setPrivate(originalOnReceiveMethod.modifiers)
97+
98+
// 声明两个域变量保存onReceive收到的原始参数,供调用super方法时使用。
99+
// the compiler embedded in Javassist does not support generics
100+
arrayOf(
101+
CtFieldWithInit.make(
102+
"ThreadLocal originalOnReceiveContext = new ThreadLocal();",
103+
ctClass
104+
),
105+
CtFieldWithInit.make(
106+
"ThreadLocal originalOnReceiveIntent = new ThreadLocal();",
107+
ctClass
108+
),
109+
).forEach {
110+
ctClass.addField(it)
111+
}
112+
113+
// 添加新onReceive方法
114+
val newOnReceiveMethod = CtMethod.make(
115+
"""
116+
public void onReceive(Context context, Intent intent) {
117+
try{
118+
//保存收到的参数
119+
originalOnReceiveContext.set(context);
120+
originalOnReceiveIntent.set(intent);
121+
122+
//通过当前插件类ClassLoader找到相关的插件Application
123+
ClassLoader cl = this.getClass().getClassLoader();
124+
PluginPartInfo info = PluginPartInfoManager.getPluginInfo(cl);
125+
Context shadowContext = info.application;
126+
Intent intentCopy = new Intent(intent);//不修改原本的intent
127+
intentCopy.setExtrasClassLoader(cl);
128+
129+
//调用原本的onReceive方法
130+
onReceiveShadowContext(shadowContext, intentCopy);
131+
}finally {
132+
originalOnReceiveContext.remove();
133+
originalOnReceiveIntent.remove();
134+
}
135+
}
136+
""".trimIndent(), ctClass
137+
)
138+
ctClass.addMethod(newOnReceiveMethod)
139+
140+
// 定义superOnReceiveMethod方法
141+
val newSuperMethod = CtMethod.make(
142+
"""
143+
private void superOnReceive(Context context, Intent intent) {
144+
context = (Context)originalOnReceiveContext.get();
145+
intent = (Intent)originalOnReceiveIntent.get();
146+
super.onReceive(context, intent);
147+
}
148+
""".trimIndent(), ctClass
149+
)
150+
151+
//转调super.onReceive方法
152+
val superMethod: CtMethod =
153+
ctClass.superclass.getMethod(
154+
"onReceive",
155+
"(Landroid/content/Context;Landroid/content/Intent;)V"
156+
)
157+
158+
if (Modifier.isAbstract(superMethod.modifiers).not()) {
159+
val codeConverter = CodeConverter()
160+
codeConverter.redirectMethodCall(superMethod, newSuperMethod)
161+
try {
162+
ctClass.instrument(codeConverter)
163+
} catch (e: Exception) {
164+
System.err.println("处理" + ctClass.name + "时出错:" + e)
165+
throw e
166+
}
167+
ctClass.addMethod(newSuperMethod)
168+
}
169+
}
170+
171+
})
172+
}
173+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package android.content;
2+
3+
public abstract class BroadcastReceiver {
4+
public abstract void onReceive(Context context, Intent intent);
5+
}
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
package android.content;
22

33
public class Intent {
4+
public Intent() {
5+
}
6+
7+
public Intent(Intent intent) {
8+
}
9+
10+
public void setExtrasClassLoader(ClassLoader loader) {
11+
}
412
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.tencent.shadow.core.runtime;
2+
3+
public class PluginPartInfo {
4+
public ShadowApplication application = new ShadowApplication();
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.tencent.shadow.core.runtime;
2+
3+
public class PluginPartInfoManager {
4+
public static PluginPartInfo getPluginInfo(ClassLoader classLoader) {
5+
return new PluginPartInfo();
6+
}
7+
}

projects/sdk/core/transform/src/test/java/com/tencent/shadow/core/runtime/ShadowApplication.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.tencent.shadow.core.runtime;
22

3-
public class ShadowApplication {
3+
public class ShadowApplication extends ShadowContext {
44

55
public void onCreate() {
66
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.tencent.shadow.core.runtime;
2+
3+
import android.content.Context;
4+
5+
public class ShadowContext extends Context {
6+
}

0 commit comments

Comments
 (0)