跳到主要内容 设计模式:代理模式详解与实战应用 | 极客日志
Java java 算法
设计模式:代理模式详解与实战应用 代理模式是常用的结构型设计模式,分为静态代理和动态代理。静态代理在编译期生成代理类,动态代理在运行期通过反射生成。阐述了代理模式的基本概念与 UML 结构,通过代购案例演示了静态代理的接口委托实现。结合 Android 线程池管理项目,展示了静态代理在实际业务中的应用。进一步介绍了 JDK 动态代理机制,并通过 Hook ClipboardService 的案例,详细说明了如何利用动态代理拦截系统服务调用,实现功能增强与修改。
魔尊 发布于 2025/2/7 更新于 2026/4/21 0 浏览代理模式
代理模式可以分为两种,一种是静态代理,一种是动态代理。两种代理从虚拟机加载类的角度来讲,本质上都是一样的,都是在原有类的行为基础上,加入一些多出的行为,甚至完全替换原有的行为。在我们平时写代码的过程中,代理模式可以说是随处可见。
基本概念
代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,所访问的真实对象与代理对象需要实现相同的接口。
UML 图
Subject :抽象主题类,声明真实主题与代理的共同接口方法。
RealSubject :真实主题类,定义了代理所表示的真实对象,客户端通过代理类间接的调用真实主题类的方法。
Proxy :代理类,持有对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行。
Client :客户端类。
静态代理
静态代理一般具有如下特点:
代理类一般要持有一个被代理的对象的引用。
对于我们不关心的方法,全部委托给被代理。
自己处理我们关心的方法。
静态代理简单示例
我们都知道网上代购的例子,假设小明想要购买外星人电脑,他委托在美国的好朋友帮他购买。
抽象主题类(Subject)
抽象主题类具有真实主题类和代理的共同接口方法,在这里共同的方法就是购买:
public interface IShop {
void buy () ;
}
真实主题类(RealSubject)
例子中就是小明,他需要实现 IShop 接口提供的 buy() 方法:
public class XiaoMing implements IShop {
@Override
public void buy () {
System.out.println("小明进行购买" );
}
}
代理类(Proxy)
小明的朋友,也就是代理类同样也要实现 IShop 接口,并且要持有被代理者,在 buy() 方法中调用了被代理者的 buy() 方法:
public class ProxyBuyer implements IShop {
private IShop mShop;
{
mShop = shop;
}
{
mShop.buy();
}
}
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
public
ProxyBuyer
(IShop shop)
@Override
public
void
buy
()
客户端类(Client) public class Client {
public static void main (String[] args) {
IShop xiaoMing = new XiaoMing ();
IShop proxyBuyer = new ProxyBuyer (xiaoMing);
proxyBuyer.buy();
}
}
代码很简单,就是代理类包含了真实主题类(被代理者),最终调用的都是真实主题类(被代理者)实现的方法。上面的例子中,代理类的购买方法调用了真实主题类的购买方法,完成了'代购'的过程。这就是代理模式最简单的用法,归结为一句话:代理类和被代理类实现相同的接口,代理类持有被代理类的引用,代理方法执行时,同步调用被代理类的相同方法。
静态代理在项目中的应用 理解了最简单的静态代理的使用方法后,介绍一下在我写项目过程中,应用到静态代理的一个例子。线程在安卓开发中几乎随处可见,线程的管理显得格外重要,所以在项目中我创建一个 ThreadPoolManager 来管理线程池。
public class ThreadPoolManager {
private static HashMap<String, ThreadPoolManager> sThreadPoolManagerhHashMap = new HashMap <String, ThreadPoolManager>();
private final static int DEFAULT_COREPOOL_SIZE = 4 ;
private final static int DEFAULT_MAXIMUMPOOL_SIZE = 4 ;
private final static long DEFAULT_KEEPALIVE_TIME = 0 ;
private final static TimeUnit DEFAULT_TIMEUNIT = TimeUnit.SECONDS;
private static ScheduledExecutorService sScheduledExecutorService = null ;
private static ScheduledRunnable sScheduledRunnable = null ;
private ThreadPoolExecutor mWorkThreadPool = null ;
private Queue<Runnable> mWaitTasksQueue = null ;
private RejectedExecutionHandler mRejectedExecutionHandler = null ;
private Object mLock = new Object ();
private String mName;
private ThreadPoolManager () {
this (DEFAULT_COREPOOL_SIZE, DEFAULT_MAXIMUMPOOL_SIZE, DEFAULT_KEEPALIVE_TIME,
DEFAULT_TIMEUNIT, false , null );
}
private ThreadPoolManager (int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, boolean isPriority, final ITaskExecuteListener listener) {
mWaitTasksQueue = new ConcurrentLinkedQueue <Runnable>();
if (sScheduledRunnable == null ) {
sScheduledRunnable = new ScheduledRunnable ();
sScheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
sScheduledExecutorService.scheduleAtFixedRate(sScheduledRunnable, 0 , 1500 ,
TimeUnit.MILLISECONDS);
}
initRejectedExecutionHandler();
BlockingQueue<Runnable> queue = isPriority
? new PriorityBlockingQueue <Runnable>(16 )
: new LinkedBlockingQueue <Runnable>(16 );
if (listener == null ) {
mWorkThreadPool = new ThreadPoolExecutor (corePoolSize, maximumPoolSize, keepAliveTime,
unit, queue, mRejectedExecutionHandler);
} else {
mWorkThreadPool = new ThreadPoolExecutor (corePoolSize, maximumPoolSize, keepAliveTime,
unit, queue, mRejectedExecutionHandler) {
@Override
protected void beforeExecute (Thread t, Runnable r) {
listener.beforeExecute(t, r);
}
@Override
protected void afterExecute (Runnable r, Throwable t) {
listener.afterExecute(r, t);
}
};
}
}
public static ThreadPoolManager getInstance (String threadPoolManagerName) {
ThreadPoolManager threadPoolManager = null ;
if (threadPoolManagerName != null && !"" .equals(threadPoolManagerName.trim())) {
synchronized (sThreadPoolManagerhHashMap) {
threadPoolManager = sThreadPoolManagerhHashMap.get(threadPoolManagerName);
if (null == threadPoolManager) {
threadPoolManager = new ThreadPoolManager ();
threadPoolManager.mName = threadPoolManagerName;
sThreadPoolManagerhHashMap.put(threadPoolManagerName, threadPoolManager);
}
}
}
return threadPoolManager;
}
public static ThreadPoolManager buildInstance (String threadPoolManagerName,
int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
boolean isPriority, ITaskExecuteListener listener) {
if (threadPoolManagerName == null || "" .equals(threadPoolManagerName.trim())
|| corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize
|| keepAliveTime < 0 ) {
return null ;
} else {
ThreadPoolManager threadPoolManager = new ThreadPoolManager (corePoolSize,
maximumPoolSize, keepAliveTime, unit, isPriority, listener);
threadPoolManager.mName = threadPoolManagerName;
synchronized (sThreadPoolManagerhHashMap) {
sThreadPoolManagerhHashMap.put(threadPoolManagerName, threadPoolManager);
}
return threadPoolManager;
}
}
private static class ScheduledRunnable implements Runnable {
@Override
public void run () {
synchronized (sThreadPoolManagerhHashMap) {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
Collection<ThreadPoolManager> values = sThreadPoolManagerhHashMap.values();
for (ThreadPoolManager manager : values) {
manager.executeWaitTask();
}
}
}
}
private void executeWaitTask () {
synchronized (mLock) {
if (hasMoreWaitTask()) {
Runnable runnable = mWaitTasksQueue.poll();
if (runnable != null ) {
execute(runnable);
}
}
}
}
private void initRejectedExecutionHandler () {
mRejectedExecutionHandler = new RejectedExecutionHandler () {
@Override
public void rejectedExecution (Runnable r, ThreadPoolExecutor executor) {
synchronized (mLock) {
mWaitTasksQueue.offer(r);
}
}
};
}
public boolean hasMoreWaitTask () {
boolean result = false ;
if (!mWaitTasksQueue.isEmpty()) {
result = true ;
}
return result;
}
public void execute (Runnable task) {
if (task != null ) {
mWorkThreadPool.execute(task);
}
}
public void cancel (Runnable task) {
if (task != null ) {
synchronized (mLock) {
if (mWaitTasksQueue.contains(task)) {
mWaitTasksQueue.remove(task);
}
}
mWorkThreadPool.remove(task);
}
}
public void removeAllTask () {
try {
if (!mWorkThreadPool.isShutdown()) {
BlockingQueue<Runnable> tasks = mWorkThreadPool.getQueue();
for (Runnable task : tasks) {
mWorkThreadPool.remove(task);
}
}
} catch (Throwable e) {
Log.e("ThreadPoolManager" , "removeAllTask " + e.getMessage());
}
}
public boolean isShutdown () {
return mWorkThreadPool.isShutdown();
}
private void cleanUp () {
if (!mWorkThreadPool.isShutdown()) {
try {
mWorkThreadPool.shutdownNow();
} catch (Exception e) {
}
}
mRejectedExecutionHandler = null ;
synchronized (mLock) {
mWaitTasksQueue.clear();
}
}
public static void destroyAll () {
synchronized (sThreadPoolManagerhHashMap) {
Set<String> keySet = sThreadPoolManagerhHashMap.keySet();
if (keySet != null && keySet.size() > 0 ) {
ThreadPoolManager threadPoolManager = null ;
for (String key : keySet) {
threadPoolManager = sThreadPoolManagerhHashMap.get(key);
if (threadPoolManager != null ) {
threadPoolManager.cleanUp();
}
}
}
sThreadPoolManagerhHashMap.clear();
}
if (sScheduledExecutorService != null ) {
if (!sScheduledExecutorService.isShutdown()) {
try {
sScheduledExecutorService.shutdownNow();
} catch (Exception e) {
}
}
sScheduledExecutorService = null ;
}
if (sScheduledRunnable != null ) {
sScheduledRunnable = null ;
}
}
public static void destroy (String threadPoolManagerName) {
synchronized (sThreadPoolManagerhHashMap) {
ThreadPoolManager threadPoolManager = sThreadPoolManagerhHashMap
.get(threadPoolManagerName);
if (threadPoolManager != null ) {
threadPoolManager.cleanUp();
}
}
}
public static interface ITaskExecuteListener {
public void beforeExecute (Thread thread, Runnable task) ;
public void afterExecute (Runnable task, Throwable throwable) ;
}
}
ThreadPoolManager 主要有以下逻辑:
ScheduledRunnable 对象负责调度 sThreadPoolManagerhHashMap 中的 ThreadPoolManager 执行任务。
sThreadPoolManagerhHashMap 是一个 HashMap,以 ThreadPoolManager 的名字为 key,ThreadPoolManager 为值对 ThreadPoolManager 进行管理,保证同名的 ThreadPoolManager 只有一个。
mWorkThreadPool 是线程池 ThreadPoolExecutor,每一个 ThreadPoolManager 维护着一个 ThreadPoolExecutor,ThreadPoolManager 执行 Runnable 时,都调用 ThreadPoolExecutor 执行 Runnable,同时提供 Runnable 执行时的监听。
接下来是创建抽象的线程管理类,以静态代理的方式来代理 ThreadPoolManager:
public abstract class AbstractThreadExecutor {
protected ThreadPoolManager mManager;
private byte [] mLock = new byte [0 ];
protected abstract ThreadPoolManager initThreadPoolManager () ;
protected ThreadPoolManager.ITaskExecuteListener getTaskExecuteListener () {
return new ThreadPoolManager .ITaskExecuteListener() {
@Override
public void beforeExecute (Thread thread, Runnable task) {
}
@Override
public void afterExecute (Runnable task, Throwable throwable) {
}
};
}
public void execute (Runnable task) {
if (mManager == null ) {
synchronized (mLock) {
if (mManager == null ) {
mManager = initThreadPoolManager();
}
}
}
mManager.execute(task);
}
public void cancel (final Runnable task) {
if (mManager != null ) {
mManager.cancel(task);
}
}
public void destroy () {
if (mManager != null ) {
ThreadPoolManager.destroy(mManager.getManagerName());
mManager = null ;
}
}
}
可以看出静态代理的逻辑,AbstractThreadExecutor 中执行,取消 Runnable 的方法通过 ThreadPoolManager 来完成,而 ThreadPoolManager 的初始化交给子类去实现,保证拓展性。
AbstractThreadExecutor 的实现 ThreadExecutorProxy:
public class ThreadExecutorProxy {
private final static String POOL_NAME = "thread_pool" ;
private final static int DEFAULT_CORE_POOL_SIZE = 1 ;
private final static int DEFAULT_MAX_POOL_SIZE = 6 ;
private final static int KEEP_ALIVE_TIME = 60 ;
private final static String ASYNC_THREAD_NAME = "single-async-thread" ;
private static ThreadExecutor sExecutor;
private static boolean sIsInit;
private static int sCorePoolSize = DEFAULT_CORE_POOL_SIZE;
private static HandlerThread sSingleAsyncThread;
private static Handler sSingleAsyncHandler;
private static Handler sMainHandler;
private static MessageQueue sMsgQueue;
public static void init () {
if (sIsInit) {
return ;
}
sCorePoolSize = CpuManager.getCpuCoreNums() - 1 ;
if (sCorePoolSize < DEFAULT_CORE_POOL_SIZE) {
sCorePoolSize = DEFAULT_CORE_POOL_SIZE;
}
if (sCorePoolSize > DEFAULT_MAX_POOL_SIZE) {
sCorePoolSize = DEFAULT_MAX_POOL_SIZE;
}
sExecutor = new ThreadExecutor ();
sSingleAsyncThread = new HandlerThread (ASYNC_THREAD_NAME);
sSingleAsyncThread.start();
sSingleAsyncHandler = new Handler (sSingleAsyncThread.getLooper());
sMainHandler = new Handler (Looper.getMainLooper());
sMsgQueue = Looper.myQueue();
sIsInit = true ;
}
public static void execute (Runnable task) {
sExecutor.execute(task);
}
public static void cancel (final Runnable task) {
sExecutor.cancel(task);
sSingleAsyncHandler.removeCallbacks(task);
sMainHandler.removeCallbacks(task);
}
public static void destroy () {
sExecutor.destroy();
sSingleAsyncHandler.removeCallbacksAndMessages(null );
sMainHandler.removeCallbacksAndMessages(null );
}
public static void runOnAsyncThread (Runnable r) {
sSingleAsyncHandler.post(r);
}
public static void runOnAsyncThread (Runnable r, long delay) {
sSingleAsyncHandler.postDelayed(r, delay);
}
public static void runOnMainThread (Runnable r) {
sMainHandler.post(r);
}
public static void runOnMainThread (Runnable r, long delay) {
sMainHandler.postDelayed(r, delay);
}
public static void runOnIdleTime (final Runnable r) {
IdleHandler handler = new IdleHandler () {
@Override
public boolean queueIdle () {
r.run();
return false ;
}
};
sMsgQueue.addIdleHandler(handler);
}
private static class ThreadExecutor extends AbstractThreadExecutor {
private ThreadExecutor () {
}
@Override
protected ThreadPoolManager initThreadPoolManager () {
ThreadPoolManager manager = ThreadPoolManager.buildInstance(POOL_NAME, sCorePoolSize,
DEFAULT_MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, false ,
getTaskExecuteListener());
return manager;
}
}
}
可以看到通过 ThreadExecutorProxy 可以任意的在子线程和主线程中进行切换来执行 Runnable,而线程池的管理,线程的执行都封装在 ThreadPoolManager 中,而调用者根本不需要关心。
动态代理 静态代理是死的,不会在运行时动态创建,相当于在编译期,就给被代理的对象生成了一个不可动态改变的代理类。
静态代理中,被代理的对象很固定,我们只需要去代理一个类或者若干固定的类,数量不是太多的时候,可以使用,而且其实效果比动态代理更好,因为动态代理就是在运行期间动态生成代理类,所以需要消耗的时间会更久一点。
下面介绍下动态代理,动态代理是 JDK 自带的功能,它需要你去实现一个 InvocationHandler 接口,并且调用 Proxy 的静态方法去产生代理类,还是以前面代购的例子。
public class DynamicProxy implements InvocationHandler {
private final Object mTarget;
public DynamicProxy (Object target) {
mTarget = target;
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(mTarget, args);
}
}
public class Client {
public static void main (String[] args) {
IShop xiaoMing = new XiaoMing ();
DynamicProxy dynamicProxy = new DynamicProxy (xiaoMing);
ClassLoader classLoader = xiaoMing.getClass().getClassLoader();
IShop proxyBuyer = (IShop) Proxy.newProxyInstance(classLoader, new Class []{IShop.class}, dynamicProxy);
proxyBuyer.buy();
}
}
动态代理在项目中的应用 动态代理在项目中的使用,那就是在插件化中通过代理的方式来进行 hook,这里我就介绍一下如何通过动态代理去 hook service。首先看一下 ServiceManager 的 getService(String name) 方法
public final class ServiceManager {
private static final String TAG = "ServiceManager" ;
private static IServiceManager sServiceManager;
private static HashMap<String, IBinder> sCache = new HashMap <String, IBinder>();
private static IServiceManager getIServiceManager () {
if (sServiceManager != null ) {
return sServiceManager;
}
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
public static IBinder getService (String name) {
try {
IBinder service = sCache.get(name);
if (service != null ) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService" , e);
}
return null ;
}
public static void addService (String name, IBinder service) {
...
}
....
}
getService 内部首先会去 sCache 这个 map 中根据 Service 的名字获取这个 Service 的 IBinder 对象,如果获取到为空,则会通过 ServiceManagerNative 通过跨进程通信获取这个 Service 的 IBinder 对象,这里我们以 sCache 这个 map 为切入点,反射该对象,对其进行修改,由于系统的 android.os.ServiceManager 类是 @hide 的,所以只能使用反射,所以这里我们需要自己写一个 ServiceManagerProxy 类,然后其 getService 方法是通过反射调用系统 ServiceManager 的 getService 方法
public class ServiceManagerProxy {
private static Method sGetServiceMethod;
private static Map<String, IBinder> sCacheService;
private static Class sServiceManagerClass;
static {
try {
sServiceManagerClass = Class.forName("android.os.ServiceManagerProxy" );
} catch (Exception e) {
e.printStackTrace();
}
}
public static IBinder getService (String serviceName) {
if (sServiceManagerClass == null ) {
return null ;
}
if (sGetServiceMethod == null ) {
try {
sGetServiceMethod = sServiceManagerClass.getDeclaredMethod("getService" , String.class);
sGetServiceMethod.setAccessible(true );
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
if (sGetServiceMethod != null ) {
try {
return (IBinder) sGetServiceMethod.invoke(null , serviceName);
} catch (Exception e) {
e.printStackTrace();
}
}
return null ;
}
public static void setService (String serviceName, IBinder service) {
if (sServiceManagerClass == null ) {
return ;
}
if (sCacheService == null ) {
try {
Field sCache = sServiceManagerClass.getDeclaredField("sCache" );
sCache.setAccessible(true );
sCacheService = (Map<String, IBinder>) sCache.get(null );
} catch (Exception e) {
e.printStackTrace();
}
}
sCacheService.remove(serviceName);
sCacheService.put(serviceName, service);
}
}
而 ServiceManagerProxy 的 setService 方法则是通过反射获取 ServiceManager 中的 sCache,移除系统 Service,然后将我们自己改造过的 Service put 进去,这样就能实现当调用 ServiceManager 的 getService(String name) 方法的时候,返回的是我们改造过的 Service 而不是系统原本的 Service。
接下来以 hook ClipboardService 为例
public class ClipboardHook {
private static final String TAG = ClipboardHook.class.getSimpleName();
public static void hookService (Context context) {
IBinder clipboardService = ServiceManagerProxy.getService(Context.CLIPBOARD_SERVICE);
String IClipboard = "android.content.IClipboard" ;
if (clipboardService != null ) {
IBinder hookClipboardService =
(IBinder) Proxy.newProxyInstance(IBinder.class.getClassLoader(),
new Class []{IBinder.class},
new ServiceHook (clipboardService, IClipboard, true , new ClipboardHookHandler ()));
ServiceManagerProxy.setService(Context.CLIPBOARD_SERVICE, hookClipboardService);
} else {
Log.e(TAG, "ClipboardService hook failed!" );
}
}
public static class ClipboardHookHandler implements InvocationHandler {
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
int argsLength = args.length;
if ("setPrimaryClip" .equals(methodName)) {
if (argsLength >= 2 && args[0 ] instanceof ClipData) {
ClipData data = (ClipData) args[0 ];
String text = data.getItemAt(0 ).getText().toString();
text += "haha" ;
args[0 ] = ClipData.newPlainText(data.getDescription().getLabel(), text);
}
}
return method.invoke(proxy, args);
}
}
}
通过我们之前创建的 ServiceManagerProxy,反射获取 clipboard 的 IBinder
创建一个 ClipboardHookHandler 实现 InvocationHandler,并在其 invoke 方法中,修改'setPrimaryClip'方法的逻辑
将 clipboard 的 IBinder 和 ClipboardHookHandler 传入 ServiceHook 中,并利用其创建一个动态代理,然后调用 ServiceManagerProxy 的 setService 方法替换掉真正 ServiceManager 中的 clipboard
经过以上的几步后,当客户端调用 ClipboardService 的方法的时候,就会调用到 ServiceHook 中的 invoke 方法,所以接下来就是 ServiceHook 中的逻辑
public class ServiceHook implements InvocationHandler {
private static final String TAG = "yyy" ;
private IBinder mBase;
private Class<?> mStub;
private Class<?> mInterface;
private InvocationHandler mInvocationHandler;
public ServiceHook (IBinder base, String iInterfaceName,boolean isStub, InvocationHandler invocationHandler) {
mBase = base;
mInvocationHandler = invocationHandler;
try {
mInterface = Class.forName(iInterfaceName);
mStub = Class.forName(String.format("%s%s" , iInterfaceName, isStub ? "$Stub" : "" ));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
if ("queryLocalInterface" .equals(method.getName())) {
return Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class []{mInterface},
new HookServiceHandler (mBase, mStub, mInvocationHandler));
}
return method.invoke(mBase, args);
}
private static class HookServiceHandler implements InvocationHandler {
private Object mBase;
private InvocationHandler mInvocationHandler;
public HookServiceHandler (IBinder base, Class<?> stubClass,
InvocationHandler invocationHandler) {
mInvocationHandler = invocationHandler;
try {
Method asInterface = stubClass.getDeclaredMethod("asInterface" , IBinder.class);
this .mBase = asInterface.invoke(null , base);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
if (mInvocationHandler != null ) {
return mInvocationHandler.invoke(mBase, method, args);
}
return method.invoke(mBase, args);
}
}
}
可以看到,ServiceHook 的 invoke 函数中,只有当函数为 queryLocalInterface 方法的时候返回一个 HookServiceHandler 的对象,其他的情况直接调用 method.invoke 系统的 ClipboardService 功能,只处理 queryLocalInterface 方法的原因是,asInterface 方法最终会调用到 queryLocalInterface 方法,queryLocalInterface 方法最后的返回结果会作为 asInterface 的结果而返回给 Service 的调用方,所以 queryLocalInterface 方法的最后返回的对象是会被外部直接调用的,所以第一次调用到 queryLocalInterface 函数之后,后续的所有调用都到了 HookHandler 对象中,动态生成的对象中只需要有 IBinder 的 queryLocalInterface 方法即可,而不需要 IClipboard 接口的其他方法;所以 queryLocalInterface 方法会返回通过 HookServiceHandler 生成的代理类,接下来就是 HookServiceHandler 的逻辑了。
在 HookServiceHandler 的构造函数中,反射调用 IClipboard$Stub 的 asInterface 的方法,通过反射 asInterface 方法然后将 IClipboard 的 IBinder 对象变成 IInterface 对象,这是因为通过 ServiceManager.getService 方法获取的 IBinder 对象不能直接调用,必须要通过 asInterface 方法转成对应的 IInterface 对象才可以使用,所以 HookServiceHandler 中的 mBase 对象其实是一个 IInterface 对象。
接下来就是 HookServiceHandler 的 invoke 方法会调用前面 ClipboardHookHandler 的 invoke 方法,从而对 IClipboard 的 setPrimaryClip 达到了 hook 的作用,可以看到 hook 的过程中完美使用了动态代理。