插件化需要解决的问题
插件化就是动态加载,包括代码和资源的加载。当加载像Activity这样的代码时还需要解决生命周期的问题。
插件化 Binder机制
Binder从IPC的角度看是一种通信机制,时android的framework层中各种ServiceManager的链接桥梁。ServiceManager与我们APP不在同一个进程,Binder的存在为跨进程通信提供了支撑,我们可以通过AIDL进行跨进程交互。
IPC通讯过程
- 客户端要链接服务端
- 服务端会返回一个客户端的对象(代理对象)
- 客户端使用这个代理对象其中的方法时,系统会先调用服务端的方法,然后将运算的结果返回给客户端(要知道其实并不是用了这个对象的方法,而是去服务端里运算,然后在返回给客户端的)
我们通过创建AIDL的文件来看一下如何与ServiceManager进行交互。
// IMyAidlInterface.aidlpackage com.zpw.plugin;// Declare any non-default types here with import statementsimport com.zpw.plugin.bean.TestAIDLBean;interface IMyAidlInterface { /** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); String getS(in TestAIDLBean s); TestAIDLBean getBean(out TestAIDLBean bean);}复制代码
//TestAIDLBean.aidlpackage com.zpw.plugin.bean;parcelable TestAIDLBean;复制代码
//TestAIDLBean.javapackage com.zpw.plugin.bean;import android.os.Parcel;import android.os.Parcelable;/** * Created by zpw on 2018/6/5. */public class TestAIDLBean implements Parcelable { public TestAIDLBean() { } protected TestAIDLBean(Parcel in) { } public void readFromParcel(Parcel in){ } @Override public void writeToParcel(Parcel dest, int flags) { } @Override public int describeContents() { return 0; } public static final CreatorCREATOR = new Creator () { @Override public TestAIDLBean createFromParcel(Parcel in) { return new TestAIDLBean(in); } @Override public TestAIDLBean[] newArray(int size) { return new TestAIDLBean[size]; } };}复制代码
对应的目录结构为:
然后编译项目,会生成/build/generated/source/aidl/debug/com.zpw.plugin.IMyAidlInterface文件:package com.zpw.plugin;public interface IMyAidlInterface extends android.os.IInterface{/** Local-side IPC implementation stub class. */public static abstract class Stub extends android.os.Binder implements com.zpw.plugin.IMyAidlInterface{private static final java.lang.String DESCRIPTOR = "com.zpw.plugin.IMyAidlInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}/** * Cast an IBinder object into an com.zpw.plugin.IMyAidlInterface interface, * generating a proxy if needed. */public static com.zpw.plugin.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.zpw.plugin.IMyAidlInterface))) {return ((com.zpw.plugin.IMyAidlInterface)iin);}return new com.zpw.plugin.IMyAidlInterface.Stub.Proxy(obj);}@Override public android.os.IBinder asBinder(){return this;}@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{switch (code){case INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_basicTypes:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();long _arg1;_arg1 = data.readLong();boolean _arg2;_arg2 = (0!=data.readInt());float _arg3;_arg3 = data.readFloat();double _arg4;_arg4 = data.readDouble();java.lang.String _arg5;_arg5 = data.readString();this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);reply.writeNoException();return true;}case TRANSACTION_getS:{data.enforceInterface(DESCRIPTOR);com.zpw.plugin.bean.TestAIDLBean _arg0;if ((0!=data.readInt())) {_arg0 = com.zpw.plugin.bean.TestAIDLBean.CREATOR.createFromParcel(data);}else {_arg0 = null;}java.lang.String _result = this.getS(_arg0);reply.writeNoException();reply.writeString(_result);return true;}case TRANSACTION_getBean:{data.enforceInterface(DESCRIPTOR);com.zpw.plugin.bean.TestAIDLBean _arg0;_arg0 = new com.zpw.plugin.bean.TestAIDLBean();com.zpw.plugin.bean.TestAIDLBean _result = this.getBean(_arg0);reply.writeNoException();if ((_result!=null)) {reply.writeInt(1);_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}if ((_arg0!=null)) {reply.writeInt(1);_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}return true;}}return super.onTransact(code, data, reply, flags);}private static class Proxy implements com.zpw.plugin.IMyAidlInterface{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}@Override public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}/** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(anInt);_data.writeLong(aLong);_data.writeInt(((aBoolean)?(1):(0)));_data.writeFloat(aFloat);_data.writeDouble(aDouble);_data.writeString(aString);mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}@Override public java.lang.String getS(com.zpw.plugin.bean.TestAIDLBean s) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);if ((s!=null)) {_data.writeInt(1);s.writeToParcel(_data, 0);}else {_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_getS, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}@Override public com.zpw.plugin.bean.TestAIDLBean getBean(com.zpw.plugin.bean.TestAIDLBean bean) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();com.zpw.plugin.bean.TestAIDLBean _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getBean, _data, _reply, 0);_reply.readException();if ((0!=_reply.readInt())) {_result = com.zpw.plugin.bean.TestAIDLBean.CREATOR.createFromParcel(_reply);}else {_result = null;}if ((0!=_reply.readInt())) {bean.readFromParcel(_reply);}}finally {_reply.recycle();_data.recycle();}return _result;}}static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_getS = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);static final int TRANSACTION_getBean = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);}/** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;public java.lang.String getS(com.zpw.plugin.bean.TestAIDLBean s) throws android.os.RemoteException;public com.zpw.plugin.bean.TestAIDLBean getBean(com.zpw.plugin.bean.TestAIDLBean bean) throws android.os.RemoteException;}复制代码
- 编译时创建的类为IMyAidlInterface接口,继承自android.os.IInterface:
package android.os;/** * Base class for Binder interfaces. When defining a new interface, * you must derive it from IInterface. */public interface IInterface{ /** * Retrieve the Binder object associated with this interface. * You must use this instead of a plain cast, so that proxy objects * can return the correct result. */ public IBinder asBinder();}复制代码
接口中声明了三个方法:
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;public java.lang.String getS(com.zpw.plugin.bean.TestAIDLBean s) throws android.os.RemoteException;public com.zpw.plugin.bean.TestAIDLBean getBean(com.zpw.plugin.bean.TestAIDLBean bean) throws android.os.RemoteException;复制代码
- 内部类Stub继承android.os.Binder,并实现了编译时创建的接口com.zpw.plugin.IMyAidlInterface。 首先实现了android.os.IInterface的asBinder()方法:
@Override public android.os.IBinder asBinder(){return this;}复制代码
构造方法调用了父类的构造方法:
private static final java.lang.String DESCRIPTOR = "com.zpw.plugin.IMyAidlInterface";/** Construct the stub at attach it to the interface. */public Stub(){this.attachInterface(this, DESCRIPTOR);}复制代码
看看android.os.Binder中实现的方法:
/** * Convenience method for associating a specific interface with the Binder. * After calling, queryLocalInterface() will be implemented for you * to return the given owner IInterface when the corresponding * descriptor is requested. */ public void attachInterface(IInterface owner, String descriptor) { mOwner = owner; mDescriptor = descriptor; }复制代码
asInterface方法中判断如果ServiceManager与APP不是一个进程会返回代理类:
/** * Cast an IBinder object into an com.zpw.plugin.IMyAidlInterface interface, * generating a proxy if needed. */public static com.zpw.plugin.IMyAidlInterface asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.zpw.plugin.IMyAidlInterface))) {return ((com.zpw.plugin.IMyAidlInterface)iin);}return new com.zpw.plugin.IMyAidlInterface.Stub.Proxy(obj);}复制代码
每个方法都对应一个id,用于在跨进程访问时确定访问的是哪个方法,通过transact方法再调用服务端的onTransact方法:
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException{switch (code){case INTERFACE_TRANSACTION:{reply.writeString(DESCRIPTOR);return true;}case TRANSACTION_basicTypes:{data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();long _arg1;_arg1 = data.readLong();boolean _arg2;_arg2 = (0!=data.readInt());float _arg3;_arg3 = data.readFloat();double _arg4;_arg4 = data.readDouble();java.lang.String _arg5;_arg5 = data.readString();this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);reply.writeNoException();return true;}case TRANSACTION_getS:{data.enforceInterface(DESCRIPTOR);com.zpw.plugin.bean.TestAIDLBean _arg0;if ((0!=data.readInt())) {_arg0 = com.zpw.plugin.bean.TestAIDLBean.CREATOR.createFromParcel(data);}else {_arg0 = null;}java.lang.String _result = this.getS(_arg0);reply.writeNoException();reply.writeString(_result);return true;}case TRANSACTION_getBean:{data.enforceInterface(DESCRIPTOR);com.zpw.plugin.bean.TestAIDLBean _arg0;_arg0 = new com.zpw.plugin.bean.TestAIDLBean();com.zpw.plugin.bean.TestAIDLBean _result = this.getBean(_arg0);reply.writeNoException();if ((_result!=null)) {reply.writeInt(1);_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}if ((_arg0!=null)) {reply.writeInt(1);_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}return true;}}return super.onTransact(code, data, reply, flags);}复制代码
这里面对应了很多实现Parcelable接口需要实现的方法。需要在对应的Bean中实现。 每个方法对应的id时递增的:
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);static final int TRANSACTION_getS = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);static final int TRANSACTION_getBean = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);复制代码
生成的代理类将数据包装好传递给远端的Binder的transact()方法处理。然后会在服务端调用到上面实现的onTransact()方法。
private static class Proxy implements com.zpw.plugin.IMyAidlInterface{private android.os.IBinder mRemote;Proxy(android.os.IBinder remote){mRemote = remote;}@Override public android.os.IBinder asBinder(){return mRemote;}public java.lang.String getInterfaceDescriptor(){return DESCRIPTOR;}/** * Demonstrates some basic types that you can use as parameters * and return values in AIDL. */@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();try {_data.writeInterfaceToken(DESCRIPTOR);_data.writeInt(anInt);_data.writeLong(aLong);_data.writeInt(((aBoolean)?(1):(0)));_data.writeFloat(aFloat);_data.writeDouble(aDouble);_data.writeString(aString);mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);_reply.readException();}finally {_reply.recycle();_data.recycle();}}@Override public java.lang.String getS(com.zpw.plugin.bean.TestAIDLBean s) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();java.lang.String _result;try {_data.writeInterfaceToken(DESCRIPTOR);if ((s!=null)) {_data.writeInt(1);s.writeToParcel(_data, 0);}else {_data.writeInt(0);}mRemote.transact(Stub.TRANSACTION_getS, _data, _reply, 0);_reply.readException();_result = _reply.readString();}finally {_reply.recycle();_data.recycle();}return _result;}@Override public com.zpw.plugin.bean.TestAIDLBean getBean(com.zpw.plugin.bean.TestAIDLBean bean) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();com.zpw.plugin.bean.TestAIDLBean _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getBean, _data, _reply, 0);_reply.readException();if ((0!=_reply.readInt())) {_result = com.zpw.plugin.bean.TestAIDLBean.CREATOR.createFromParcel(_reply);}else {_result = null;}if ((0!=_reply.readInt())) {bean.readFromParcel(_reply);}}finally {_reply.recycle();_data.recycle();}return _result;}}复制代码
看看APP如何与ServiceManager交互。ActivityManager其实是ActivityManagerService在我们进程中的一个代理包装类,他内部全部使用 ActivityManagerNative.getDefault()去进程操作
/** * @hide */ public static IActivityManager getService() { return IActivityManagerSingleton.get(); } private static final SingletonIActivityManagerSingleton = new Singleton () { @Override protected IActivityManager create() { final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE); final IActivityManager am = IActivityManager.Stub.asInterface(b); return am; } };复制代码
asInterface():
/** {@hide} */public abstract class ActivityManagerNative extends Binder implements IActivityManager{ /** * Cast a Binder object into an activity manager interface, generating * a proxy if needed. */ static public IActivityManager asInterface(IBinder obj) { if (obj == null) { return null; } IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor); if (in != null) { return in; } return new ActivityManagerProxy(obj); }复制代码
onTransact():
@Overridepublic boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case START_ACTIVITY_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); IApplicationThread app = ApplicationThreadNative.asInterface(b); String callingPackage = data.readString(); Intent intent = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); IBinder resultTo = data.readStrongBinder(); String resultWho = data.readString(); int requestCode = data.readInt(); int startFlags = data.readInt(); ProfilerInfo profilerInfo = data.readInt() != 0 ? ProfilerInfo.CREATOR.createFromParcel(data) : null; Bundle options = data.readInt() != 0 ? Bundle.CREATOR.createFromParcel(data) : null; int result = startActivity(app, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options); reply.writeNoException(); reply.writeInt(result); return true; }复制代码
虽然叫做ActivityManagerNative,其实他就是我们自己写的aidl里的内部类Stub。
AILD的运行流程
如果是远程的话返回了代理对象,我们看代理对象的方法:
@Override public com.zpw.plugin.bean.TestAIDLBean getBean(com.zpw.plugin.bean.TestAIDLBean bean) throws android.os.RemoteException{android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.Parcel.obtain();com.zpw.plugin.bean.TestAIDLBean _result;try {_data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(Stub.TRANSACTION_getBean, _data, _reply, 0);_reply.readException();if ((0!=_reply.readInt())) {_result = com.zpw.plugin.bean.TestAIDLBean.CREATOR.createFromParcel(_reply);}else {_result = null;}if ((0!=_reply.readInt())) {bean.readFromParcel(_reply);}}finally {_reply.recycle();_data.recycle();}return _result;}复制代码
客户端发起请求:
- 首先创建输出类型data
- 创建接受类型reply
- 创建需要的参数
- 将参数写入data中
- 发起远程调用,当前线程挂起调用mRemote.transact()方法,这个方法的实现在Binder中,他会调用服务端的onTransact方法,直到有返回结果
- 从 _result中取回返回结果 _result
服务端接到请求会走到onTransact方法,这个方法运行在服务端的Binder线程池中:
case TRANSACTION_getBean:{data.enforceInterface(DESCRIPTOR);com.zpw.plugin.bean.TestAIDLBean _arg0;_arg0 = new com.zpw.plugin.bean.TestAIDLBean();com.zpw.plugin.bean.TestAIDLBean _result = this.getBean(_arg0);reply.writeNoException();if ((_result!=null)) {reply.writeInt(1);_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}if ((_arg0!=null)) {reply.writeInt(1);_arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);}else {reply.writeInt(0);}return true;}复制代码
- 通过id确定访问哪个方法
- 然后从目标参数data取出需要的参数
- 然后调用请求的相应方法
- 将返回值写入reply
- 返回true,这里需要说一下,如果返回false,代表客户端访问失败,我们实际当中可根据这个特性来做远程的校检,毕竟我们的远程方法并是不想让任何人都可以访问的。 ,通过id确定访问哪个方法,然后从目标参数data取出需要的参数,然后调用相应方法,将返回值写入reply,
插件化如何支持activity
通过反射替换 Instrumentation
Activity 启动过程
startActivity()最终都会调用到startActivityForResult(),然后调用Instrument.execStartActivity()。
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode, @Nullable Bundle options) { //从Launcher启动应用时requestCode为-1代表不需要返回结果 if (mParent == null) { //mToken: 数据类型为IBinder. //通过mMainThread.getApplicationThread()方法获取数据类型为ApplicationThread. Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); } ... }复制代码
再由ActivityManagerNative.startActivity() 通过 IPC AMS所在进程,ActivityManagerService.startActivity()。
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) {//启动应用的Activity的路线 IApplicationThread whoThread = (IApplicationThread) contextThread; try { intent.migrateExtraStreamToClipData(); intent.prepareToLeaveProcess(who); //ActivityManagerNative.getDefault返回ActivityManagerService的远程接口,即ActivityManagerProxy接口 int result = ActivityManagerNative.getDefault() .startActivity(whoThread, //当前应用的ApplicationThread对象mAppThread; who.getBasePackageName(), //调用当前ContextImpl.getBasePackageName(),获取当前Activity所在包名; intent,//启动Activity时,传递过来的参数; intent.resolveTypeIfNeeded(who.getContentResolver()),//调用intent.resolveTypeIfNeeded而获取; token, //当前Activity.mToken target != null ? target.mEmbeddedID : null,//当前Activity.mEmbeddedID requestCode, //-1; 0, null, options//null; );//这里实际会调用到ActivityManagerService类的startActivity方法 //检查activity是否启动成功 checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; }复制代码
最后 ActivityStackSupervisor.realStartActivityLocked(),权限以及安全检查mService.checkPermission。Activity如果不注册就会在这个检查时返回一个没有注册的错误,最后回到应用进程的时候抛出这个没注册的异常。
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { ... //开始执行创建Activity的流程 app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo); ... }复制代码
安全校验完成以后,会调用ApplicationThread.scheduleLaunchActivity()。
case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); final ActivityClientRecord r = (ActivityClientRecord) msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null, "LAUNCH_ACTIVITY"); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break;复制代码
handleLaunchActivity()又调用了performLaunchActivity(r, customIntent);
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ... //通过反射实例化Activity java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); ...}复制代码
在这里创建了Activity,所以可以判断这边适合作为hook点。
替换Activity加载过程
通过替换掉Instrumentation类来加载我们插件中的Activity。
// 先获取到当前的ActivityThread对象Class activityThreadClass = Class.forName("android.app.ActivityThread");Method currentActivityThreadMethod = activityThreadClass.getDeclaredMethod("currentActivityThread");currentActivityThreadMethod.setAccessible(true);Object currentActivityThread = currentActivityThreadMethod.invoke(null);// 拿到原始的 mInstrumentation字段Field mInstrumentationField = activityThreadClass.getDeclaredField("mInstrumentation");mInstrumentationField.setAccessible(true);Instrumentation mInstrumentation = (Instrumentation) mInstrumentationField.get(currentActivityThread);//如果没有注入过,就执行替换if (!(mInstrumentation instanceof PluginInstrumentation)) { PluginInstrumentation pluginInstrumentation = new PluginInstrumentation(mInstrumentation); mInstrumentationField.set(currentActivityThread, pluginInstrumentation);}复制代码
而在Instrumentation中,有一个方法叫newActivity() 这个方法就是实际创建Activity的方法,它的返回值就是我们应用中实际使用的 activity。 我们就可以在这里,判断到如果即将加载的 className 是一个插件中的Activity,那么就通过 ClassLoader.load(className).newInstance(); 创建插件 Activity 并返回来替换掉原本系统要创建的 Activity 了。
@Overridepublic Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { if (intent != null) { isPlugin = intent.getBooleanExtra(HJPlugin.FLAG_ACTIVITY_FROM_PLUGIN, false); } if (isPlugin && intent != null) { className = intent.getStringExtra(HJPlugin.FLAG_ACTIVITY_CLASS_NAME); } else { isPlugin = HJPlugin.getInstance().getPluginAtySet().contains(className); } return super.newActivity(cl, className, intent);}复制代码
### 通过java动态代理Ibinder中的ActivityManager,通过反射设置Handler的mCallback,预埋Activity,使用Activity代理
Class ActivityManagerNativeClss = Class.forName("android.app.ActivityManagerNative"); Field defaultFiled = ActivityManagerNativeClss.getDeclaredField("gDefault"); defaultFiled.setAccessible(true); Object defaultValue = defaultFiled.get(null); //反射SingleTon Class SingletonClass = Class.forName("android.util.Singleton"); Field mInstance = SingletonClass.getDeclaredField("mInstance"); mInstance.setAccessible(true); //到这里已经拿到ActivityManager对象 Object iActivityManagerObject = mInstance.get(defaultValue); //开始动态代理,用代理对象替换掉真实的ActivityManager,瞒天过海 Class IActivityManagerIntercept = Class.forName("android.app.IActivityManager"); AmsInvocationHandler handler = new AmsInvocationHandler(iActivityManagerObject); Object proxy = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class []{IActivityManagerIntercept}, handler); //现在替换掉这个对象 mInstance.set(defaultValue, proxy);复制代码
private class AmsInvocationHandler implements InvocationHandler { private Object iActivityManagerObject; private AmsInvocationHandler(Object iActivityManagerObject) { this.iActivityManagerObject = iActivityManagerObject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Log.i("HookUtil", method.getName()); //我要在这里搞点事情 if ("startActivity".contains(method.getName())) { Log.e("HookUtil", "Activity已经开始启动"); //替换Intent 先找到原始的intent,然后直接伪造一个Intent 给AMS Intent intent = null; int index = 0; for (int i = 0; i < args.length; i++) { Object arg = args[i]; if (arg instanceof Intent) { //说明找到了startActivity的Intent参数 intent = (Intent) args[i]; //这个意图是不能被启动的,因为Acitivity没有在清单文件中注册 index = i; } } Intent proxyIntent = new Intent(); ComponentName componentName = new ComponentName(context, proxyActivity); proxyIntent.setComponent(componentName); proxyIntent.putExtra(DLConstants.EXTRA_CLASS, intent.getStringExtra(DLConstants.EXTRA_CLASS)); proxyIntent.putExtra(DLConstants.EXTRA_PACKAGE, intent.getStringExtra(DLConstants.EXTRA_PACKAGE)); proxyIntent.putExtra("oldIntent", intent); args[index] = proxyIntent; } return method.invoke(iActivityManagerObject, args); } }复制代码
给ActivityThread中的H设置mCallback。你就可以拦截message拿到其中的msg.obj,然后修改里面的值。
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }复制代码
这段代码说明mCallback的执行在handleMessage之前,那么就可以给Handler设置mCallback来实现拦截消息的效果。
try { Class activityThreadClass = Class.forName("android.app.ActivityThread"); Method currentActivityThread = activityThreadClass.getDeclaredMethod("currentActivityThread"); currentActivityThread.setAccessible(true); //获取主线程对象 Object activityThread = currentActivityThread.invoke(null); Field mH = activityThreadClass.getDeclaredField("mH"); mH.setAccessible(true); Handler handler = (Handler) mH.get(activityThread); Field mActivityThreadHandler = Handler.class.getField("mCallback"); mActivityThreadHandler.setAccessible(true); //设置自己实现的CallBack mActivityThreadHandler.set(handler, new ActivityThreadHandlerCallback(handler)); } catch (Exception e) { e.printStackTrace(); }复制代码
class ActivityThreadHandlerCallback implements Handler.Callback { @Override public boolean handleMessage(Message msg) { //代表ActivityThread mH中的launch_activity if(msg.what == 100){ handleLaunchActivity(msg); } handler.handleMessage(msg); return true; } private void handleLaunchActivity(Message msg) { //ActivityClientRecord Object obj = msg.obj; try { Field intentField = obj.getClass().getDeclaredField("intent"); intentField .setAccessible(true); Intent proxyInent = (Intent) intentField.get(obj); Intent realIntent = proxyInent.getParcelableExtra("oldIntent"); if (realIntent != null) { proxyInent.setComponent(realIntent.getComponent()); } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }复制代码