forked from Tencent/Shadow
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Showing
12 changed files
with
402 additions
and
93 deletions.
There are no files selected for viewing
23 changes: 0 additions & 23 deletions
23
.../core/runtime/src/main/java/com/tencent/shadow/core/runtime/BroadcastReceiverWrapper.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
173 changes: 173 additions & 0 deletions
173
...rm/src/main/kotlin/com/tencent/shadow/core/transform/specific/ReceiverSupportTransform.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/* | ||
* Tencent is pleased to support the open source community by making Tencent Shadow available. | ||
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. | ||
* | ||
* Licensed under the BSD 3-Clause License (the "License"); you may not use | ||
* this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* https://opensource.org/licenses/BSD-3-Clause | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
* | ||
*/ | ||
|
||
package com.tencent.shadow.core.transform.specific | ||
|
||
import com.tencent.shadow.core.transform_kit.SpecificTransform | ||
import com.tencent.shadow.core.transform_kit.TransformStep | ||
import javassist.* | ||
import javassist.compiler.Javac.CtFieldWithInit | ||
|
||
/** | ||
* 系统回调BroadcastReceiver的onReceive(Context context, Intent intent)方法时: | ||
* 1. 传回的context是宿主的,需要修改为插件的。 | ||
* 2. intent的ExtrasClassLoader是宿主的,需要改为插件的。 | ||
* | ||
* 如果是系统类的BroadcastReceiver,它也不会和插件的context或classloader有什么联系, | ||
* 所以我们只需要修改插件代码中的BroadcastReceiver。 | ||
* | ||
* 把原本插件的onReceive方法改个名字,再统一添加一个onReceive方法。 | ||
* 在新增的onReceive方法中修改收到的系统回调参数,再转调被改名了的原本插件的onReceive方法。 | ||
*/ | ||
class ReceiverSupportTransform : SpecificTransform() { | ||
|
||
companion object { | ||
const val AndroidBroadcastReceiverClassname = "android.content.BroadcastReceiver" | ||
const val AndroidContextClassname = "android.content.Context" | ||
const val AndroidIntentClassname = "android.content.Intent" | ||
} | ||
|
||
private fun CtClass.isReceiver(): Boolean = isClassOf(AndroidBroadcastReceiverClassname) | ||
|
||
override fun setup(allInputClass: Set<CtClass>) { | ||
mClassPool.importPackage("android.content") | ||
mClassPool.importPackage("com.tencent.shadow.core.runtime") | ||
|
||
val androidContext = mClassPool[AndroidContextClassname] | ||
val androidIntent = mClassPool[AndroidIntentClassname] | ||
|
||
/** | ||
* 收集覆盖了onReceive方法的Receiver作为修改目标 | ||
*/ | ||
val targetReceivers = mutableSetOf<CtClass>() | ||
newStep(object : TransformStep { | ||
override fun filter(allInputClass: Set<CtClass>) = allInputClass | ||
.filter { it.isReceiver() } | ||
.toSet() | ||
|
||
override fun transform(ctClass: CtClass) { | ||
val onReceiveMethod: CtMethod? = | ||
try { | ||
ctClass.getDeclaredMethod( | ||
"onReceive", | ||
arrayOf(androidContext, androidIntent) | ||
) | ||
} catch (e: NotFoundException) { | ||
null | ||
} | ||
if (onReceiveMethod != null) { | ||
targetReceivers.add(ctClass) | ||
} | ||
} | ||
}) | ||
|
||
/** | ||
* 对原本的onReceive方法改名,并添加新的onReceive方法。 | ||
*/ | ||
newStep(object : TransformStep { | ||
override fun filter(allInputClass: Set<CtClass>) = targetReceivers | ||
|
||
override fun transform(ctClass: CtClass) { | ||
ctClass.defrost() | ||
|
||
// 改名 | ||
val originalOnReceiveMethod: CtMethod = | ||
ctClass.getDeclaredMethod( | ||
"onReceive", | ||
arrayOf(androidContext, androidIntent) | ||
) | ||
originalOnReceiveMethod.name = "onReceiveShadowContext" | ||
originalOnReceiveMethod.modifiers = | ||
Modifier.setPrivate(originalOnReceiveMethod.modifiers) | ||
|
||
// 声明两个域变量保存onReceive收到的原始参数,供调用super方法时使用。 | ||
// the compiler embedded in Javassist does not support generics | ||
arrayOf( | ||
CtFieldWithInit.make( | ||
"ThreadLocal originalOnReceiveContext = new ThreadLocal();", | ||
ctClass | ||
), | ||
CtFieldWithInit.make( | ||
"ThreadLocal originalOnReceiveIntent = new ThreadLocal();", | ||
ctClass | ||
), | ||
).forEach { | ||
ctClass.addField(it) | ||
} | ||
|
||
// 添加新onReceive方法 | ||
val newOnReceiveMethod = CtMethod.make( | ||
""" | ||
public void onReceive(Context context, Intent intent) { | ||
try{ | ||
//保存收到的参数 | ||
originalOnReceiveContext.set(context); | ||
originalOnReceiveIntent.set(intent); | ||
//通过当前插件类ClassLoader找到相关的插件Application | ||
ClassLoader cl = this.getClass().getClassLoader(); | ||
PluginPartInfo info = PluginPartInfoManager.getPluginInfo(cl); | ||
Context shadowContext = info.application; | ||
Intent intentCopy = new Intent(intent);//不修改原本的intent | ||
intentCopy.setExtrasClassLoader(cl); | ||
//调用原本的onReceive方法 | ||
onReceiveShadowContext(shadowContext, intentCopy); | ||
}finally { | ||
originalOnReceiveContext.remove(); | ||
originalOnReceiveIntent.remove(); | ||
} | ||
} | ||
""".trimIndent(), ctClass | ||
) | ||
ctClass.addMethod(newOnReceiveMethod) | ||
|
||
// 定义superOnReceiveMethod方法 | ||
val newSuperMethod = CtMethod.make( | ||
""" | ||
private void superOnReceive(Context context, Intent intent) { | ||
context = (Context)originalOnReceiveContext.get(); | ||
intent = (Intent)originalOnReceiveIntent.get(); | ||
super.onReceive(context, intent); | ||
} | ||
""".trimIndent(), ctClass | ||
) | ||
|
||
//转调super.onReceive方法 | ||
val superMethod: CtMethod = | ||
ctClass.superclass.getMethod( | ||
"onReceive", | ||
"(Landroid/content/Context;Landroid/content/Intent;)V" | ||
) | ||
|
||
if (Modifier.isAbstract(superMethod.modifiers).not()) { | ||
val codeConverter = CodeConverter() | ||
codeConverter.redirectMethodCall(superMethod, newSuperMethod) | ||
try { | ||
ctClass.instrument(codeConverter) | ||
} catch (e: Exception) { | ||
System.err.println("处理" + ctClass.name + "时出错:" + e) | ||
throw e | ||
} | ||
ctClass.addMethod(newSuperMethod) | ||
} | ||
} | ||
|
||
}) | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
projects/sdk/core/transform/src/test/java/android/content/BroadcastReceiver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package android.content; | ||
|
||
public abstract class BroadcastReceiver { | ||
public abstract void onReceive(Context context, Intent intent); | ||
} |
8 changes: 8 additions & 0 deletions
8
projects/sdk/core/transform/src/test/java/android/content/Intent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,12 @@ | ||
package android.content; | ||
|
||
public class Intent { | ||
public Intent() { | ||
} | ||
|
||
public Intent(Intent intent) { | ||
} | ||
|
||
public void setExtrasClassLoader(ClassLoader loader) { | ||
} | ||
} |
5 changes: 5 additions & 0 deletions
5
...ects/sdk/core/transform/src/test/java/com/tencent/shadow/core/runtime/PluginPartInfo.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.tencent.shadow.core.runtime; | ||
|
||
public class PluginPartInfo { | ||
public ShadowApplication application = new ShadowApplication(); | ||
} |
7 changes: 7 additions & 0 deletions
7
...k/core/transform/src/test/java/com/tencent/shadow/core/runtime/PluginPartInfoManager.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.tencent.shadow.core.runtime; | ||
|
||
public class PluginPartInfoManager { | ||
public static PluginPartInfo getPluginInfo(ClassLoader classLoader) { | ||
return new PluginPartInfo(); | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...s/sdk/core/transform/src/test/java/com/tencent/shadow/core/runtime/ShadowApplication.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
projects/sdk/core/transform/src/test/java/com/tencent/shadow/core/runtime/ShadowContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.tencent.shadow.core.runtime; | ||
|
||
import android.content.Context; | ||
|
||
public class ShadowContext extends Context { | ||
} |
Oops, something went wrong.