0%

第4章:代理模式

概述

插件化用到代理模式,所以要掌握代理模式。随着泛型引进,代理模式分为动态代理和静态代理,在插件化中分别表现为对 Instrumentation 和 对 AMN 进行Hook。

代理模式的UML图如下:

代理模式类图

其中RealSubject 和 Proxy 都是Subject 的子类,在Proxy内部有一个RealSubject类型的成员变量,Proxy 的Reqeust 方法会调用 RealSubject 的Request方法,代码如下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
abstract public class Subject {
abstract public void Request();
}

public class RealSubject : Subject {
public override void Request(){
//完成一些任务
}
}

public class Proxy : Subject {
private RealSubject realSubject;

public override void Request() {
//关键是这句话
realSubject.Request();
}
}

简单的UML图和这短短的代码,就是代理的精髓,在介绍代理模式的使用场景时,就知道它的威力了。

远程代理(AIDL)

在Android系统中,远程代理的设计实现就是AIDL。以之前的例子来说,add 方法把a和b两个整数写入data中,通过mRemote的transact方法,把data和reply发送到AIDL的另一端,replay是回调函数,会把计算结果传递回来,UML图如下所示:

AIDL的UML图

给生活加点料(记日记)

Class1有个doSomething方法,我们想在这个方法之前记录一行日志,一般的做法是,直接在在doSomething 方法的最前端写一行代码用于记录日志,在学习了代理模式后,我们可以设计一个Class1Proxy,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Class1Proxy implements Class1Interface {

Class 1 clazz = new Class1();

@Override
public void doSomething() {
println("begin log");
clazz.doSomething();
println("End log");
}
}

//接下来使用ClassProxy 而不是使用 Class1:

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

静态代理和动态代理

前面讲的是“静态代理”,但是其实这样是有问题的,每个类都要有个对应的Proxy类,Proxy类的数量会很多,但其实它们的逻辑大同小异。接下来介绍“动态代理”,基于 Proxy 类的 newProxyInstance 方法,它的声明如下:

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

其中,interfaces 设置为目标对象Class1 所实现的接口类型,对应上面的例子是 Class1Interface,我们通过h对象,可以实现把目标对象 class1 注入,我们看下在实际应用中自己实现的这个h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class InvocationHandlerTest implements InvocationHandler {
private Object target;

public InvocationHandlerTest(Object target) {
this.target = target;
}

@Overrid
public Object invoke(Object o, Method method,Object[] objects) throws Throwable {
println("start log");
Object obj = method.invoke(target,objects);
println("end log");
retun obj;
}
}

注意 method.invoke(target,objects),其中target 就是 class1 对象,接下来调用就是如下方式:

1
2
Class1Interface proxy = new Class1();
Class1Interface class1Proxy = (Class1Interface)Proxy.newProxyInstance(class1.getclass.getClassLoder(),class1.getclass.getInterfaces(),new InvocationHandlerTest(class1));

所以,invoke方法实际上就是在执行 class1 的doSomething 方法。

对AMN的Hook

后续有时间补上

对PMS的Hook

PMS 是系统服务,是没办法Hook的,这个标题只是为了容易理解。我们只能修改它在Android App 进程中的代理对象,它是PackageManager 类型的在很多类中都有这个代理的对象,比如,在ActivityThread 中,有一个字段 sPackageManager ,以及 ApplicationPackageManager 的 mPM字段,我们可以尝试Hook这些字段。

代码:略,后续补上。

谢谢你的鼓励