代理模式及对startActivity的Hook应用

定义

简而言之,就是让代理类和目标类(被代理类)实现同一个接口,并让代理类持有一个目标类的对象,这样对代理类的访问,可以转移到目标类的访问中去。我们可以在不修改目标类的情况下,在代理类中实现一些功能的增强,从而间接的增强了目标类的功能。

UML图如下:
在这里插入图片描述
基本代码实现:

public interface Subject {
    void request()
}

===================================================================================
public class RealSubject implements Subject {
    @Override
    public void request() {
        // 完成一些事情
    }
}

===================================================================================\
public class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(RealSubject subject) {
        this.realSubject = subject;
    }

    @Override
    public void request() {
        realSubject.request();
    }
}

代理模式的几种应用方式:

  1. 远程代理(AIDL)
    在这里插入图片描述

Proxy中的add方法把参数写入到data中,通过mRemote的transact方法,把data和reply发送到AIDL的另一端,在AIDL的另一端通过Stub类的onTransact方法把参数从data中取出来,计算完得到结果,再把结果通过reply这个回调函数传递回来。

  1. 保护代理(权限控制)
    老板出差期间把自己审核请假的权限临时授予秘书。

  2. 虚代理(图片占位)
    比如:微信图片查看,网络不好时,先用模糊的小图占位,等大图下载完成再替换之前的小图
    在这里插入图片描述
    4.协作开发(Mock Class)
    A要用到B中的方法,但是B还没有开发完,那么B就提供一个假的方法,返回写死的值,等开发完成再替换掉

5.添加日志
Class1中有一个doSomething方法,我们想在doSomething的执行前和执行后记录一行日志,我们可以设计一个Class1Proxy来做这个功能,这样就不会影响到Class1。

public interface Class1Interface {
    public void doSomething();
}
public class Class1 implements Class1Interface{
    @Override
    public void doSomething() {
        System.out.println("class1 doSomething");
    }
}
public class Class1Proxy implements Class1Interface{
    Class1 class1 = new Class1();

    @Override
    public void doSomething() {
        System.out.println("Begin log.");
        class1.doSomething();
        System.out.println("End log.");
    }
}

接下来,我们就可以用Class1Proxy来代替Class1了

Class1Proxy proxy = new Class1Proxy();
proxy.doSomething();

上述的实现方法是静态代理模式,它的缺点在于

  1. 静态代理如果接口新增一个方法,除了所有实现类(真实主题类)需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
  2. 代理对象只服务于一种类型的对象,如果要服务多类型的对象。必须要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。

比如如果我们需要在Class2的doSomething的执行前打印日志,就需要再实现一个Class2Proxy类,Proxy类的数量会很多。

动态代理

上面我们所讲的静态代理,在代码运行前就已经存在了代理类的class文件;而动态代理则是在代码运行时通过发射来动态的生成代理类的对象,并确定到底来代理谁。
也就是说我们在编码阶段并不知道要代理谁,到底代理谁我们将在代码运行时决定。
Java提供了Proxy类的newProxyInstance方法来生成代理对象,也提供了动态的代理接口InvocationHandler来中转需要代理实现的方法。
我们来看看newProxyInstance方法的声明:

static Object newProxyInstance(
	ClassLoader loader,
	Class<?>[] interfaces,
	InvocationHandler h)

参数说明:

  • loader 设置为目标对象(被代理对象)对应的classLoader
  • interfaces 设置为目标对象(被代理对象)所实现的接口类型
  • h 设置为一个实现了InvocationHandler接口的类对象,我们通过它的构造函数把目标对象注入。
 Class1Interface class1 = new Class1();
 Class1Interface class1Proxy = (Class1Interface) Proxy.newProxyInstance(class1.getClass().getClassLoader(), class1.getClass().getInterfaces(), new InvocationHandlerForTest(class1));
 class1Proxy.doSomething();

================================================================================
public class InvocationHandlerForTest implements InvocationHandler {
    private Object realSubject; // 真实的主题对象

    public InvocationHandlerForTest(Object realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("日志开始");
        Object result = method.invoke(realSubject,args);
        System.out.println("日志结束");
        return result;
    }
}

通过Proxy.newProxyInstance方法创建的对象,是一个实现了Class1Interface接口的对象,如此我们就实现了Class1的代理对象,如果我们现在需要代理Class2,那么我们可以直接:

Class2Interface class2 = new Class2();
Class2Interface class2Proxy = (Class2Interface) Proxy.newProxyInstance(class2.getClass().getClassLoader(), class2.getClass().getInterfaces(), new InvocationHandlerForTest(class2));
class2Proxy.work();

注意,method.invoke(target,objects)这行代码,target就是class1对象,objects是class1的doSomthing方法所需要的参数,接下来调用class1Proxy的doSomething方法,就会调用class1类的doSomething方法。

动态代理的优点
  1. 可以通过一个代理类完成全部的代理功能,接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。当接口方法数量较多时,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
  2. 动态代理的应用使我们的类职责更加单一,复用性更强。
动态代理的缺点

不能对类进行代理,只能对接口进行代理,如果我们的类没有实现任何接口,那么就不能使用这种方式进行动态代理(因为$Proxy()这个类集成了Proxy,Java的集成不允许出现多个父类)。

我们可以利用动态代理Proxy.newProxyInstance方法生成的代理对象来替换掉原来的对象,这个技术在插件化中被称为Hook技术。

Hook应用

我们假设在MainActivity中启动一个SecondActivity,但是最终启动的却是ThirdActivity。
我们首先需要知道的是,Activity中执行startActivity的基本流程。

startActivity 方法的两种形式:

  1. 使用 Activity 自带的 startActivity
Intent intent= new Intent(MainActivity.this ,,SecondActivity.class) ;
startActivity(intent);
  1. 使用Context的startActivity 方法
Intent intent= new Intent(MainActivity.this ,,SecondActivity.class) ;
startActivity(intent);

两种方法殊途同归,都会执行到ActivitystartActivityForResult方法中,最终通过mInstrumentation.execStartActivity来调用,在execStartActivity方法中又交给了ActivityTaskManager.getService().startActivity来处理。
这是startActivity的上半场:

MainActivity通知ATMS,要启动SecondActivity

ATMS接受到MainActivity传过来的请求,然后通过mService.getLifecycleManager().scheduleTransaction方法回到APP进程,发送ActivityThread.H.EXECUTE_TRANSACTION消息,执行到ActivityThreadhandleLaunchActivity()方法,最终执行到ActivityThreadmInstrumentation.callActivityOnCreate();,在这个方法里面调用SecondActivityonCreate()完成启动。
这是startActivity的下半场:

ATMS通知APP进程启动SecondActivity

我们在上半场可以Hook的地方包括:

  • ActivitystartActivityForResult方法;
  • ActivitymInstrumentation字段;
  • ActivityTaskManager.getService()方法获取到的对象

在下半场可以Hook的地方包括:

  • ActivityThread的mInstrumentation对象,对应的newActivity方法和callActivityOnCreate方法。
重写Activity的startActivityForResult

为App的所有Activity创建一个基类Activity-BaseActivity,在BaseActivity中重写startActivityForResult方法

对Activity的mInstrumentation字段进行Hook

Activity中有一个mInstrumentation字段,Activity的startActivityForResult方法会调用mInstrumentation的executeStartActivity方法:

# Activity.java
private Instrumentation mInstrumentation;

public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
    if(this.mParent == null) {
        ActivityResult ar = this.mInstrumentation.execStartActivity(this, this.mMainThread.getApplicationThread(), this.mToken, this, intent, requestCode, options);
        if(ar != null) {
            this.mMainThread.sendActivityResult(this.mToken, this.mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData());
        }

        if(requestCode >= 0) {
            this.mStartedActivity = true;
        }
    } else if(options != null) {
        this.mParent.startActivityFromChild(this, intent, requestCode, options);
    } else {
        this.mParent.startActivityFromChild(this, intent, requestCode);
    }

}

首先我们通过反射来获取这一私有变量。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 获取Activity中的Instrumentation对象,私有变量,通过反射获取
        Instrumentation instrumentation = (Instrumentation) RefInvoke.getFieldObject(Activity.class,this,"mInstrumentation");
        // 创建Instrumentation代理对象
        InstrumentationProxy instrumentationProxy = new InstrumentationProxy(instrumentation);
        // 替换掉MainActivity中的mInstrumentation对象为代理对象
        RefInvoke.setFieldObject(Activity.class,this,"mInstrumentation",instrumentationProxy);

        setContentView(R.layout.activity_main);
        findViewById(R.id.turn_to_other_activity).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}
public class InstrumentationProxy extends Instrumentation {
    private static final String TAG = InstrumentationProxy.class.getSimpleName();
    private Instrumentation mInstrumentation;

    public InstrumentationProxy(Instrumentation mInstrumentation) {
        this.mInstrumentation = mInstrumentation;
    }

    public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,
                                            Intent intent, int requestCode, Bundle options){
        Log.d(TAG, "XXX到此一游!");
        ComponentName componentName = intent.getComponent();
        String className = componentName.getClassName();
        // 判断目标activity是不是SecondActivity,替换SecondActivity为ThirdActivity
        if(className.equals("com.chinatsp.hookstartactivity.SecondActivity")){
            intent.setClassName(who,ThirdActivity.class.getCanonicalName());
        }
      
        // 由于这个方法是隐藏的,因此需要使用反射调用;
        Class[] p1 = {Context.class, IBinder.class,
                IBinder.class, Activity.class,
                Intent.class, int.class, Bundle.class};
        Object[] v1 = {who, contextThread, token, target,
                intent, requestCode, options};
        return (ActivityResult) RefInvoke.invokeInstanceMethod(
                mInstrumentation, "execStartActivity", p1, v1);
    }
}

这样我们就成功的Hook了startActivity方法,因为mInstrumentation是一个对象,所以这里采用静态代理的模式。

对ATMS的getService进行Hook

InstrumentaionexecStartActivity方法最终会走到ActivityTaskManager.getService().startActivity方法:

# Instrumentation.java

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, Activity target,
        Intent intent, int requestCode, Bundle options) {
   ...

    try {
		// 流程就从Launcher进程进入到AMS所在的SystemServer进程了
        int result = ActivityTaskManager.getService().startActivity(whoThread,
                who.getBasePackageName(), who.getAttributionTag(), intent,
                intent.resolveTypeIfNeeded(who.getContentResolver()), token,
                target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
       ...
    }
    return null;
}

//=========ActivityTaskManager.java=========
public static IActivityTaskManager getService() {
    return IActivityTaskManagerSingleton.get();
}

@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() {
    @Override
    protected IActivityTaskManager create() {
        final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
        return IActivityTaskManager.Stub.asInterface(b);
    }
};


//=================Singleton.java=========
        /**
         * Singleton helper class for lazily initialization.
         * ......
         */
        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;
                }
            }
        }

ATMS的getService方法返回一个IActivityTaskManager类型,这是一个接口,我们可以使用Proxy.newProxyInstance方法把这个IActivityTaskManager接口类型的对象Hook成我们自定义的代理类AMSProxy.class生成的对象:

public class AMSHookHelper {
    private static final String TAG = AMSHookHelper.class.getSimpleName();

    public static void hookAMS() throws ClassNotFoundException,ClassCastException{
        Object singletonObject = null;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
            singletonObject = RefInvoke.getStaticFieldObject("android.app.ActivityTaskManager","IActivityTaskManagerSingleton");
        }else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            singletonObject = RefInvoke.getStaticFieldObject("android.app.ActivityTaskManager","IActivityManagerSingleton");
        }else{
            // 获取AMN的gDefault单例,gDefault是final静态的
            singletonObject = RefInvoke.getStaticFieldObject("android.app.ActivityManagerNative","gDefault");
        }

        // singletonObject 是一个android.util.Singleton<T>对象; 我们取出这个单例里面的mInstance字段
        Object mInstance = RefInvoke.getFieldObject("android.util.Singleton", singletonObject, "mInstance");

        // 创建一个这个对象的代理对象MockClass1, 然后替换这个字段, 让我们的代理对象帮忙干活
        Class<?> activityManagerInterface;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
            activityManagerInterface = Class.forName("android.app.IActivityTaskManager");
        }else {
            activityManagerInterface = Class.forName("android.app.IActivityManager");
        }

        // getInterfaces()方法和Java的反射机制有关。它能够获得这个对象所实现的接口。activityManager 本身就是activityManagerInterface 的Class
        Object activityManagerProxy = Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[]{ activityManagerInterface },
                new AMSProxy(mInstance));

        RefInvoke.setFieldObject("android.util.Singleton", singletonObject,"mInstance",activityManagerProxy);
        Log.d(TAG, "hook activity manager success");

    }
}

public class AMSProxy implements InvocationHandler {
    private static final String TAG = AMSProxy.class.getSimpleName();

    private Object mAMSProxy;

    public AMSProxy(Object mAMSProxy) {
        this.mAMSProxy = mAMSProxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log.d(TAG,"hey, baby,you are hooked!!");
        Log.d(TAG,"method:"+method.getName()+" called with args:" + Arrays.toString(args));
        if("startActivity".equals(method.getName())){
            int index = 0;
            for (int i = 0; i < args.length; i++) {
                if (args[i] instanceof Intent) {
                    index = i;
                    break;
                }
            }
            // 原来的intent
            Intent intent = (Intent) args[index];
            Intent proxyIntent = new Intent(intent);
            // 实际跳转的页面Activity
            proxyIntent.setClassName("com.chinatsp.hookstartactivityamn", ThirdActivity.class.getCanonicalName());
            args[index] = proxyIntent;

            return method.invoke(mAMSProxy,args);
        }

        return method.invoke(mAMSProxy,args);
    }
}

最后在MainActivityattachBaseContext方法中执行AMSHookHelper.hookAMS方法:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        try {
           AMSHookHelper.hookAMN();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.turn_to_other_activity).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}

对ActivityThread的Instrumentation字段进行Hook

在Activity内部,有一个mInstrumentation字段,我们通过替换它为自定义的InstrumentationProxy类来实现Hook。

ActivityThread内部也有一个mInstrumentation字段,ActivityThread会调用mInstrumentation的newActivity方法生成Activity对象,然后调用mInstrumentation的callActivityOnCreate方法来启动这个activity。因此我们也可以替换这个mInstrumentation为自定义的代理对象来实现Hook。

public class InstrumentationInActivityThreadHookHelper {
    private static final String TAG = InstrumentationInActivityHookHelper.class.getSimpleName();
    public static void hookInstrumentationInActivity() throws ClassNotFoundException{
        // 先获取到当前的ActivityThread
        Object currentActivityThread = RefInvoke.invokeStaticMethod("android.app.ActivityThread","currentActivityThread");
        // 拿到原始的Instrumentation字段
        Instrumentation instrumentation = (Instrumentation) RefInvoke.getFieldObject(currentActivityThread,"mInstrumentation");
        // 创建代理对象
        InstrumentationProxy instrumentationProxy = new InstrumentationProxy(instrumentation);
        // 替换ActivityThread中的instrumentation为代理对象
        RefInvoke.setFieldObject(currentActivityThread,"mInstrumentation",instrumentationProxy);
    }
}
public class InstrumentationProxy extends Instrumentation {
    private static final String TAG = InstrumentationProxy.class.getSimpleName();
    // ActivityThread中原始的Instrumentation对象, 保存起来
    private Instrumentation mBase;

    public InstrumentationProxy(Instrumentation mBase) {
        this.mBase = mBase;
    }

    public Activity newActivity(ClassLoader cl, String className,
                                Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        // 原来的intent
        ComponentName componentName = intent.getComponent();
        Log.d(TAG, "到此一游!cl:"+cl+" ,className="+className
                + " ,component_packageName="+componentName.getPackageName()
                + " ,component_className="+componentName.getClassName());

        if("com.chinatsp.hookstartactivityamn.SecondActivity".equals(componentName.getClassName())){
            // 如果是跳转到SecondActivity,就替换为ThirdActivity
            className = ThirdActivity.class.getCanonicalName();
            intent.setComponent(new ComponentName(componentName.getPackageName(),"com.chinatsp.hookstartactivityamn.ThirdActivity"));
        }
        return mBase.newActivity(cl, className, intent);
    }

    public void callActivityOnCreate(Activity activity, Bundle bundle) {
        Log.d(TAG, "到此一游! bundle = " + bundle);

//        Class[] p1 = {Activity.class, Bundle.class};
//        Object[] v1 = {activity, bundle};
//        RefInvoke.invokeInstanceMethod(
//                mBase, "callActivityOnCreate", p1, v1);
        mBase.callActivityOnCreate(activity,bundle);
    }
}

callActivityOnCreate方法没有变动,主要的变动在于newActivity方法。

启动没有在AndroidManifest中声明的Activity

再回想一下启动Activity的时序图
在这里插入图片描述
在正常的流程当中,如果APP启动了一个没有在AndroidManifest中声明的Activity,AMS就会抛出一个Activity Not Found的异常。
AMS对Activity是否在AndroidManifest文件中声明的检查,是在第二步中完成的。基本思路:

  1. 在第一步中,发送要启动的Activity信息之前,把这个Activity替换为一个在AndroidManifest文件中声明过的StubActivity,这样就能绕过AMS的检查,在替换的过程中,要把原来的Activity信息存放在Bundle中。
  2. 在第五步中,AMS通知APP启动StubActivity时,我们将StubActivity替换为原先的Activity。原先的Activity信息存放在Bundle中,取出来即可。

第一步的代码实现,其实就是上节中Hook startActivity流程上半场时的几种方法都可以,这里选择HookATMS的方式:

public class AMSHookHelper {
    private static final String TAG = AMSHookHelper.class.getSimpleName();
    public static final String EXTRA_TARGET_INTENT = "extra_target_intent";

    /**
     * Hook AMS
     * 主要完成的操作是: 把真正要启动的Activity临时替换为在AndroidManifest.xml中声明好的Activity,进而骗过AMS
     */
    public static void hookAMN() throws ClassNotFoundException,NoSuchMethodException{
        // 获取AMN的gDefault对象实例
        Object singletonObject = null;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
            singletonObject = RefInvoke.getStaticFieldObject("android.app.ActivityTaskManager","IActivityTaskManagerSingleton");
        }else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            singletonObject = RefInvoke.getStaticFieldObject("android.app.ActivityTaskManager","IActivityManagerSingleton");
        }else{
            // 获取AMN的gDefault单例,gDefault是final静态的
            singletonObject = RefInvoke.getStaticFieldObject("android.app.ActivityManagerNative","gDefault");
        }

        // singletonObject 是一个 android.util.Singleton<T>对象; 我们取出这个单例里面的mInstance字段
        Object mInstance = RefInvoke.getFieldObject("android.util.Singleton", singletonObject, "mInstance");

        // 创建一个这个对象的代理对象MockClass1, 然后替换这个字段, 让我们的代理对象帮忙干活
        Class<?> activityManagerInterface;
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P){
            activityManagerInterface = Class.forName("android.app.IActivityTaskManager");
        }else {
            activityManagerInterface = Class.forName("android.app.IActivityManager");
        }

        Object proxy = Proxy.newProxyInstance(
                Thread.currentThread().getContextClassLoader(),
                new Class[]{ activityManagerInterface },
                new AMSProxy(mInstance));

        RefInvoke.setFieldObject("android.util.Singleton", singletonObject, "mInstance",proxy);
    }
}

public class AMSProxy implements InvocationHandler {
    private static final String TAG = AMSProxy.class.getSimpleName();
    private Object mActivityManager;

    public AMSProxy(Object mActivityManager) {
        this.mActivityManager = mActivityManager;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log.d(TAG,method.getName());
        if("startActivity".equals(method.getName())){
            // 只拦截这个方法
            // 替换参数
            Intent raw;
            int index = 0;
            for(int i = 0;i<args.length;i++){
                if(args[i] instanceof Intent){
                    index = i;
                    break;
                }
            }
            raw = (Intent) args[index];
            Intent newIntent = new Intent();
            // 替身Activity的包名
            String stubPackage = raw.getComponent().getPackageName();
            // 把启动的Activity替换为StubActivity
            ComponentName componentName = new ComponentName(stubPackage, StubActivity.class.getName());
            newIntent.setComponent(componentName);

            // 把我们原始要启动的TargetActivity存起来
            newIntent.putExtra(AMSHookHelper.EXTRA_TARGET_INTENT,raw);
            // 替换掉intent
            args[index] = newIntent;
            Log.d(TAG,"hook success");
            return method.invoke(mActivityManager,args);
        }
        return method.invoke(mActivityManager,args);
    }
}

AMSProxy主要的工作是拦截startActivity方法,从参数中取出原有的Intent,替换为启动StubActivity的newIntent,同时把原有的Intent保存在newIntent中,后面把StubActivity换为TargetActivity需要用到。

第二步的实现代码,就是Hook startActivity 流程的下半场的方式,这里选择Hook ActivityThread的mInstrumentation对象:

public class AMSHookHelper {
    private static final String TAG = AMSHookHelper.class.getSimpleName();
    public static final String EXTRA_TARGET_INTENT = "extra_target_intent";
	...
    public static void hookInstrumentation(){
        // 先获取到当前的ActivityThread
        Object currentActivityThread = RefInvoke.invokeStaticMethod("android.app.ActivityThread","currentActivityThread");
        // 拿到原始的Instrumentation字段
        Instrumentation instrumentation = (Instrumentation) RefInvoke.getFieldObject(currentActivityThread,"mInstrumentation");
        // 创建代理对象
        InstrumentationProxy instrumentationProxy = new InstrumentationProxy(instrumentation);
        // 替换ActivityThread中的instrumentation为代理对象
        RefInvoke.setFieldObject(currentActivityThread,"mInstrumentation",instrumentationProxy);
    }
}
public class InstrumentationProxy extends Instrumentation {
    private static final String TAG = InstrumentationProxy.class.getSimpleName();
    // ActivityThread中原始的Instrumentation对象, 保存起来
    private Instrumentation mBase;

    public InstrumentationProxy(Instrumentation mBase) {
        this.mBase = mBase;
    }

    public Activity newActivity(ClassLoader cl, String className,
                                Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        // 原来的intent
        ComponentName componentName = intent.getComponent();
        Log.d(TAG, "到此一游!cl:"+cl+" ,className="+className
                + " ,component_packageName="+componentName.getPackageName()
                + " ,component_className="+componentName.getClassName());
        // 获取存入的targetIntent,也就是本来要启动的intent
        Intent targetIntent = intent.getParcelableExtra(AMSHookHelper.EXTRA_TARGET_INTENT);
        // 为空则说明要启动的是一个在AndroidManifest中声明过的Activity,走正常流程
        if(targetIntent==null){
            return mBase.newActivity(cl,className,intent);
        }
       String newClassName = targetIntent.getComponent().getClassName();
        return mBase.newActivity(cl, newClassName, targetIntent);
    }

    public void callActivityOnCreate(Activity activity, Bundle bundle) {
        Log.d(TAG, "到此一游! bundle = " + bundle);

//        Class[] p1 = {Activity.class, Bundle.class};
//        Object[] v1 = {activity, bundle};
//        RefInvoke.invokeInstanceMethod(
//                mBase, "callActivityOnCreate", p1, v1);
        mBase.callActivityOnCreate(activity,bundle);
    }

}

InstrumentationProxy主要的工作是拦截newActivity方法,因为callActivityOnCreate方法中没有Intent参数,从Intent参数中取出原有的Intent,替换className和Intent参数为我们本来要启动的TargetActivity的className和Intent对象。

最后在MainActivity中的attachBaseContext方法中执行AMSHookHelper.hookAMN();AMSHookHelper.hookInstrumentation();

public class MainActivity extends AppCompatActivity {
    @Override
    protected void attachBaseContext(Context newBase) {
        super.attachBaseContext(newBase);
        try{
            AMSHookHelper.hookAMN();
            AMSHookHelper.hookInstrumentation();
        }catch (ClassNotFoundException | NoSuchMethodException e){
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.turn_to_other_activity).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, SecondActivity.class);
                startActivity(intent);
            }
        });
    }
}

源码

猜你喜欢

转载自blog.csdn.net/jxq1994/article/details/130765093