博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
插件化 学习笔记
阅读量:6244 次
发布时间:2019-06-22

本文共 28397 字,大约阅读时间需要 94 分钟。

插件化需要解决的问题

插件化就是动态加载,包括代码和资源的加载。当加载像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 Creator
CREATOR = 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 Singleton
IActivityManagerSingleton = 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();        }    }    }复制代码

转载地址:http://xspia.baihongyu.com/

你可能感兴趣的文章
计算网速
查看>>
jdk8中HashMap的优化和底层内存的优化
查看>>
js中bind、call、apply函数的用法
查看>>
PHP集群中SESSION共享方案之Redis
查看>>
KVM虚拟化开源高可用方案(三)glusterfs
查看>>
linux中date的用法总结
查看>>
在互联网时代不突破的企业将没有出路
查看>>
linux下新加硬盘
查看>>
Day03 - 挂载、nmcli、yum安装
查看>>
Linux下的qperf测量网络带宽和延迟
查看>>
wxPython 配置环境
查看>>
C的数据类型 关键字
查看>>
Hadoop 2.5.2 HDFS HA+YARN HA 应用配置
查看>>
tomcat远程调试
查看>>
APUE读书笔记-18终端输入输出-05终端选项标记
查看>>
Linux查看系统IO
查看>>
阅后即焚,Python 运维开发99速成
查看>>
Oracle正则表达式(二)
查看>>
oracle导入导出
查看>>
刘宇凡:360搜索来了,百度你怂了吗?
查看>>