转载请注明出处:https://blog.csdn.net/llew2011/article/details/85923036
在上篇文章:Android 源码系列之<二十>通过反射解决在HuaWei手机出现Register too many Broadcast Receivers的crash 的文章中,我们分析了在HuaWei手机Android 8.1及以下版本中动态注册BroadcastReceiver的数量超过500个会引发应用crash的原因,然后又通过反射技术解决了该问题(不清楚原因的小伙伴可以看下上篇文章)。后来有小伙伴反馈说在HuaWei手机Android 9.0版本上使用反射技术也会抛出新的异常:Too many receivers, total of 1000……
收到小伙伴的反馈信息后,我在云测上对HuaWei Android 9.0的手机远程真机调试,结果也是出现了Too many receivers,total of 1000的异常,结合上篇文章的解决方案来看猜测是HuaWei在Android 9.0上对注册BroadcasterReceiver的数量做了更为严格的限制:即使应用添加进了白名单也不允许其注册超过1000个广播接收器。为了验证这个猜测我把上篇文章中用到的Demo的包名改成了微信的包名在HuaWei手机9.0上跑了一下,果然抛出最多只能注册1000个BroadcastReceiver的异常……
既然在HuaWei手机Android 9.0版本上不能注册超过1000个BroadcastReceiver,那么在HuaWei手机系统中可能有个类A,它的职责之一就是校验当前应用注册BroadcastReceiver的数量是否超过阀值a,如果超过阀值a则类A就抛出一个异常。我顺着这个思路并根据异常日志开始尝试寻找这个类A,如果找到了类A并且类A里恰好定义了阀值a那么我们就可以通过反射修改这个类A里阀值a的值,然而我尝试了多次都没有找到~~~~(>_<)~~~~
由于目前没办法找到类A,我们只能换一种思路来解决这个问题。既然在9.0版本上不能注册超过1000个BroadcastReceiver,那么我们可以拦截注册广播接收器的函数registerReceiver()和反注册广播接收器的函数unregisterReceiver()来做一个计数器,如果注册一个BroadcastReceiver就把计数器累加1,反注册一个BroadcastReceiver我们就把计数器减去1;要是计数器超过了1000就不再执行注册BroadcastReceiver的操作并给调用者一个回调来通知调用者注册的广播接收器已经达到上限了……
要拦截registerReceiver()和unregisterReceiver()方法最简单的方式是定义基类,在基类中做计数器功能,然后把这些基类开放给开发者继承,考虑到开发者的应用可能有的是继承第三方的基类等各种情况,定义基类这种做法是不妥当的,为了能找到一种更好的解决方案,我们先从源码分析一下注册BroadcastReceiver的流程,看看从方法调用链上能不能找到Hook点,测试代码如下:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.llew.huawei.verifier.demo.R.layout.activity_main);
}
public void register(View view) {
for (int i = 1; i <= 2000; i++) {
IntentFilter filter = new IntentFilter();
filter.addAction("hook index : " + i);
registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
}
}, filter);
Log.e(getClass().getName(), "index:" + i);
}
}
}
在MainActivity中我们直接调用了registerReceiver()方法,该方法是Context中定义的并在Context的子类ContextWrapper中做了实现,知道Activity继承关系的小伙伴都清楚Activity也是间接继承了ContextWrapper,所以我们直接去ContextWrapper类里看看registerReceiver()方法的具体实现,源码如下:
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
ContextWrapper类中的registerReceiver()方法中直接调用mBase的registerReceiver()方法,mBase是ContextWrapper的大管家,它也是Context类型,它负责ContextWrapper的所有方法的实现。因此我们可以认为Activity的registerReceiver()方法最终委托给了大管家mBase,把任务都交给mBase去完成,自己只接收mBase的执行结果就行了(这种模式熟悉不?(*^__^*) ……),mBase的具体实现类是ContextImpl其registerReceiver()方法源码如下:
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
int flags) {
return registerReceiver(receiver, filter, null, null, flags);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler, int flags) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), flags);
}
@Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, user.getIdentifier(),
filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
ContextImpl中的registerReceiver()方法最终调用的是registerReceiverInternal()方法,源码如下:
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
// if语句块的作用是尝试初始化rd
// 省略初始化代码......
}
try {
// 最终的实现在ActivityManager.getService()里边
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
registerReceiverInternal()方法里首先尝试去初始化rd,最后把注册广播接收器的任务交给了ActivityManager.getService()的返回对象来实现,getService()是ActivityManager的静态方法,getService()的源码如下:
/**
* @hide
*/
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
ActivityManager的getService()方法是hide的,它返回的是IActivityManager类型的实例对象,IActivityManager的定义在这里 ,它是一个AIDL文件,里边定义了registerReceiver()等众多方法。对进程间通信比较熟悉的小伙伴应该对AIDL不陌生哈,AIDL最终会被编译器编译成一个继承了android.os.IInterface接口的接口类IActivityManager。由此可得出ActivityManager的getService()方法返回的实例对象是实现了IActivityManager接口的,而该实例对象又是通过调用IActivityManagerSingleton的get()方法返回的,IActivityManagerSingleton是ActivityManager的一个内部静态属性,它的定义如下:
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
// 获取Binder
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
// 获取IActivityManger并返回
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
IActivityManagerSingleton是Singleton类型的静态属性并且使用了final修饰符,Singleton的定义如下:
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
Singleton是个抽象类,当调用get()方法时如果属性mInstance为null就调用create()方法初始化mInstance属性,在后续继续调用get()方法时就直接返回mInstance,这是一种常见的单例懒加载模式。根据Singleton的定义,ActivityManger的getService()方法内调用了IActivityManagerSingleton的get()方法,get()方法又会调用到create()方法,而create()方法的返回值是存储在mInstance中的,因此mInstance就是IActivityManager接口的实例对象……
通过对源码层层分析,我们知道Activity的registerReceiver()方法最终的实现是委托给了IActivityManager接口的实现类,而该实现类恰好是Singleton的实例对象IActivityManagerSingleton的mInstance属性值,因此我们可以通过反射拿到IActivityManager的具体实现类mInstance。现在有了IActivityManager接口,又有了该接口的实现类mInstance,如果想要对IActivityManager接口中的方法做拦截,恰好可以使用设计模式中的动态代理模式来实现。Java中实现动态代理非常简单,直接使用JDK提供的Proxy类和InvocationHandler接口就行了。
我们先定义实现InvocationHandler接口的实现类,代码如下:
public class AmsInvocationHandler implements InvocationHandler {
private Object mTargetObject;
private int mBroadcastCount;
private AmsInvocationHandler(Object target) {
this.mTargetObject = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
if (TextUtils.equals("registerReceiver", methodName)) {
if (mBroadcastCount >= 1000) {
return null;
}
mBroadcastCount++;
} else if (TextUtils.equals("unregisterReceiver", methodName)) {
mBroadcastCount--;
mBroadcastCount = mBroadcastCount < 0 ? 0 : mBroadcastCount;
}
return method.invoke(mTargetObject, args);
}
}
AmsInvocationHandler实现了InvocationHandler接口,定义了一个Object类型的mTargetObject属性(该值就是我们一会需要通过反射获取到的IActivityManager的实现类mInstance),mBroadcastCount表示当前已经注册了多少个广播接收器的计数器,在实现的invoke()方法中我们通过判断method的name是否是注册或者反注册广播接收器来做计数器的增减,如果计数器超过1000就直接返回null否则执行method的invoke()方法。
实现了InvocationHandler接口后就可以使用Proxy类实现动态代理功能了,代码如下:
private void hookActivityManagerService(ClassLoader loader) {
try {
// 读取ActivityManager的静态属性IActivityManagerSingleton的值
Object IActivityManagerSingletonObject = FieldUtils.readStaticField(ActivityManager.class.getName(), "IActivityManagerSingleton");
if (null != IActivityManagerSingletonObject) {
// 读取mInstance的值,该值是IActivityManager接口的实现类
Object IActivityManagerObject = FieldUtils.readField(IActivityManagerSingletonObject, "mInstance");
if (null != IActivityManagerObject) {
// 根据IActivityManagerObject创建一个AmsInvocationHandler对象
AmsInvocationHandler handler = new AmsInvocationHandler(IActivityManagerObject);
// 获取IActivityManagerClass类类
Class<?> IActivityManagerClass = Class.forName("android.app.IActivityManager");
// 调用Proxy的newProxyInstance()方法
Object proxy = Proxy.newProxyInstance(loader, new Class<?>[]{IActivityManagerClass}, handler);
// 把IActivityManagerSingletonObject中的mInstance对象替换成proxy对象
FieldUtils.writeField(IActivityManagerSingletonObject, "mInstance", proxy);
}
}
} catch (Throwable ignored) {
// ignore it
}
}
hookActivityManagerService()方法中的注解写的很清楚,先通过反射获取到ActivityManager中的静态属性IActivityManagerSingleton的值IActivityManagerSingletonObject,然后再利用反射拿到该IActivityManagerSingletonObject的mInstance值IActivityManagerObject并根据该值创建了AmsInvocationHandler对象,最后调用了Proxy的newProxyInstance()方法生成了一个Object类型的proxy对象,最后一步是利用反射替换掉了原来的mInstance的值为新生成的proxy对象,替换之后就实现了对IActivityManager接口中所有方法的拦截操作,完整代码如下所示或见这里:
public final class LoadedApkHuaWei {
private static final HuaWeiVerifier IMPL;
static {
final int version = android.os.Build.VERSION.SDK_INT;
if (version >= 28) {
IMPL = new V28VerifierImpl();
} else if (version >= 26) {
IMPL = new V26VerifierImpl();
} else if (version >= 24) {
IMPL = new V24VerifierImpl();
} else {
IMPL = new BaseVerifierImpl();
}
}
public static void hookHuaWeiVerifier(Application application) {
hookHuaWeiVerifier(application, null);
}
public static void hookHuaWeiVerifier(Application application, TooManyBroadcastCallback callback) {
try {
if (null != application) {
IMPL.verifier(application.getBaseContext(), callback);
} else {
Log.w(LoadedApkHuaWei.class.getSimpleName(), "application is null !!!");
}
} catch (Throwable ignored) {
// ignore it
}
}
private static class V28VerifierImpl extends V26VerifierImpl {
private static final int MAX_BROADCAST_COUNT = 1000;
private static final String REGISTER_RECEIVER = "registerReceiver";
private static final String UNREGISTER_RECEIVER = "unregisterReceiver";
private static final String ACTIVITY_MANAGER = "android.app.IActivityManager";
@Override
public boolean verifier(Context baseContext, TooManyBroadcastCallback callback) throws Throwable {
final boolean verified = super.verifier(baseContext, callback);
if (verified) {
hookActivityManagerService(baseContext.getClassLoader(), callback);
}
return verified;
}
private void hookActivityManagerService(ClassLoader loader, TooManyBroadcastCallback callback) {
try {
Object IActivityManagerSingletonObject = FieldUtils.readStaticField(ActivityManager.class.getName(), "IActivityManagerSingleton");
if (null != IActivityManagerSingletonObject) {
Object IActivityManagerObject = FieldUtils.readField(IActivityManagerSingletonObject, "mInstance");
if (null != IActivityManagerObject) {
AmsInvocationHandler handler = new AmsInvocationHandler(IActivityManagerObject, callback);
Class<?> IActivityManagerClass = Class.forName(ACTIVITY_MANAGER);
Object proxy = Proxy.newProxyInstance(loader, new Class<?>[]{IActivityManagerClass}, handler);
FieldUtils.writeField(IActivityManagerSingletonObject, "mInstance", proxy);
}
}
} catch (Throwable ignored) {
// ignore it
}
}
private static class AmsInvocationHandler implements InvocationHandler {
private Object mIActivityManagerObject;
private TooManyBroadcastCallback mCallback;
private volatile int mCurrentBroadcastCount;
private AmsInvocationHandler(Object mIActivityManagerObject, TooManyBroadcastCallback callback) {
this.mCallback = callback;
this.mIActivityManagerObject = mIActivityManagerObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String methodName = method.getName();
if (TextUtils.equals(REGISTER_RECEIVER, methodName)) {
if (mCurrentBroadcastCount >= MAX_BROADCAST_COUNT) {
if (null != mCallback) {
mCallback.tooManyBroadcast(mCurrentBroadcastCount, MAX_BROADCAST_COUNT);
}
return null;
}
mCurrentBroadcastCount++;
if (null != mCallback) {
mCallback.tooManyBroadcast(mCurrentBroadcastCount, MAX_BROADCAST_COUNT);
}
} else if (TextUtils.equals(UNREGISTER_RECEIVER, methodName)) {
mCurrentBroadcastCount--;
mCurrentBroadcastCount = mCurrentBroadcastCount < 0 ? 0 : mCurrentBroadcastCount;
if (null != mCallback) {
mCallback.tooManyBroadcast(mCurrentBroadcastCount, MAX_BROADCAST_COUNT);
}
}
return method.invoke(mIActivityManagerObject, args);
}
}
}
private static class V26VerifierImpl extends BaseVerifierImpl {
private static final String WHITE_LIST = "mWhiteListMap";
@Override
public boolean verifier(Context baseContext, TooManyBroadcastCallback callback) throws Throwable {
Object whiteListMapObject = getWhiteListObject(baseContext, WHITE_LIST);
if (whiteListMapObject instanceof Map) {
Map whiteListMap = (Map) whiteListMapObject;
List whiteList = (List) whiteListMap.get(0);
if (null == whiteList) {
whiteList = new ArrayList<>();
whiteListMap.put(0, whiteList);
}
whiteList.add(baseContext.getPackageName());
return true;
}
return false;
}
}
private static class V24VerifierImpl extends BaseVerifierImpl {
private static final String WHITE_LIST = "mWhiteList";
@Override
public boolean verifier(Context baseContext, TooManyBroadcastCallback callback) throws Throwable {
Object whiteListObject = getWhiteListObject(baseContext, WHITE_LIST);
if (whiteListObject instanceof List) {
List whiteList = (List) whiteListObject;
whiteList.add(baseContext.getPackageName());
return true;
}
return false;
}
}
private static class BaseVerifierImpl implements HuaWeiVerifier {
private static final String WHITE_LIST = "mWhiteList";
@Override
public boolean verifier(Context baseContext, TooManyBroadcastCallback callback) throws Throwable {
Object receiverResourceObject = getReceiverResourceObject(baseContext);
Object whiteListObject = getWhiteListObject(receiverResourceObject, WHITE_LIST);
if (whiteListObject instanceof String[]) {
String[] whiteList = (String[]) whiteListObject;
List<String> newWhiteList = new ArrayList<>();
newWhiteList.add(baseContext.getPackageName());
Collections.addAll(newWhiteList, whiteList);
FieldUtils.writeField(receiverResourceObject, WHITE_LIST, newWhiteList.toArray(new String[newWhiteList.size()]));
return true;
} else {
if (null != receiverResourceObject) {
FieldUtils.writeField(receiverResourceObject, "mResourceConfig", null);
}
}
return false;
}
Object getWhiteListObject(Context baseContext, String whiteList) {
return getWhiteListObject(getReceiverResourceObject(baseContext), whiteList);
}
private Object getWhiteListObject(Object receiverResourceObject, String whiteList) {
try {
if (null != receiverResourceObject) {
return FieldUtils.readField(receiverResourceObject, whiteList);
}
} catch (Throwable ignored) {
}
return null;
}
private Object getReceiverResourceObject(Context baseContext) {
try {
Field receiverResourceField = FieldUtils.getDeclaredField("android.app.LoadedApk", "mReceiverResource", true);
if (null != receiverResourceField) {
Field packageInfoField = FieldUtils.getDeclaredField("android.app.ContextImpl", "mPackageInfo", true);
if (null != packageInfoField) {
Object packageInfoObject = FieldUtils.readField(packageInfoField, baseContext);
if (null != packageInfoObject) {
return FieldUtils.readField(receiverResourceField, packageInfoObject, true);
}
}
}
} catch (Throwable ignored) {
}
return null;
}
}
private interface HuaWeiVerifier {
boolean verifier(Context baseContext, TooManyBroadcastCallback callback) throws Throwable;
}
public interface TooManyBroadcastCallback {
void tooManyBroadcast(int registedCount, int totalCount);
}
}
好了,到这里我们通过动态代理的方式规避了在HuaWei手机Android 9.0版本上注册BroadcastReceiver的数量超过1000就会引发应用crash的问题,但这并不是解决问题的根本。我们在应用开发中尽量避免采用BroadcastReceiver的方式做消息传递,在之前的两篇文章Android 源码系列之<二>从安全的角度深入理解BroadcastReceiver(上)和Android 源码系列之<二>从安全的角度深入理解BroadcastReceiver(下)中讲解了为什么不建议使用注册BroadcastReceiver的原因,感兴趣的小伙伴可以阅读一下。
另外需要注意的是从Android 9.0版本后Google开始限制非公开API的调用,如果调用了被严格限制的API系统就会抛异常,限制的API可参照这里:https://android.googlesource.com/platform/frameworks/base/+/master/config/,目前我在9.0版本上测试了一下是OK的,如果后续出现了问题再想办法解决吧……
现在我们通过动态代理的方式实现了对方法的拦截操作,或许有的小伙伴们对此很疑惑,我们仅通过Proxy和InvocationHandler就实现了方法的拦截,这是怎么做到的呢?InvocationHandler接口定义的invoke(Object proxy, Method method, Object args[])方法中这这些参数分别是什么?Proxy又是何方神圣,它的newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)方法返回一个Object类型的实例对象,这个实例对象是谁?具体又是什么类型了?这一系列的疑问就是我们今天这篇文章要讲解的重点,上边用了大量篇幅也是为了引入这篇文章要讲解的核心:动态代理。
由于篇幅原因,我将要在下篇文章Android 源码系列之《二十二》从源码的角度深入理解Java的动态代理机制(下)通过阅读源码的方式为大家讲解Java中的动态代理机制,敬请期待(*^__^*) ……