All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.com.alibaba.jvm.sandbox.spy.Spy Maven / Gradle / Ivy

There is a newer version: 1.4.0
Show newest version
package java.com.alibaba.jvm.sandbox.spy;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 间谍类,藏匿在各个ClassLoader中
 * 

* 从{@code 0.0.0.v}版本之后,因为要考虑能在alipay的CloudEngine环境中使用,这个环境只能向上查找java.开头的包路径. * 所以这里只好把Spy的包路径前缀中增加了java.开头 *

*

*

* 从{@code 1.1.0}版本之后,修复了命名空间在Spy中不支持的问题 *

* * @author [email protected] */ public class Spy { /** * 控制Spy是否在发生异常时主动对外抛出 * T:主动对外抛出,会中断方法 * F:不对外抛出,只将异常信息打印出来 */ public static volatile boolean isSpyThrowException = false; private static final Class SPY_RET_CLASS = Spy.Ret.class; private static final Map namespaceMethodHookMap = new ConcurrentHashMap(); /** * 判断间谍类是否已经完成初始化 * * @param namespace 命名空间 * @return TRUE:已完成初始化;FALSE:未完成初始化; */ public static boolean isInit(final String namespace) { return namespaceMethodHookMap.containsKey(namespace); } /** * 初始化间谍 * * @param namespace 命名空间 * @param ON_BEFORE_METHOD ON_BEFORE 回调 * @param ON_RETURN_METHOD ON_RETURN 回调 * @param ON_THROWS_METHOD ON_THROWS 回调 * @param ON_LINE_METHOD ON_LINE 回调 * @param ON_CALL_BEFORE_METHOD ON_CALL_BEFORE 回调 * @param ON_CALL_RETURN_METHOD ON_CALL_RETURN 回调 * @param ON_CALL_THROWS_METHOD ON_CALL_THROWS 回调 */ public static void init(final String namespace, final Method ON_BEFORE_METHOD, final Method ON_RETURN_METHOD, final Method ON_THROWS_METHOD, final Method ON_LINE_METHOD, final Method ON_CALL_BEFORE_METHOD, final Method ON_CALL_RETURN_METHOD, final Method ON_CALL_THROWS_METHOD) { namespaceMethodHookMap.put( namespace, new MethodHook( ON_BEFORE_METHOD, ON_RETURN_METHOD, ON_THROWS_METHOD, ON_LINE_METHOD, ON_CALL_BEFORE_METHOD, ON_CALL_RETURN_METHOD, ON_CALL_THROWS_METHOD ) ); } /** * 清理间谍钩子方法 * * @param namespace 命名空间 */ public static void clean(final String namespace) { namespaceMethodHookMap.remove(namespace); // 如果是最后的一个命名空间,则需要重新清理Node中所持有的Thread if (namespaceMethodHookMap.isEmpty()) { for (int index = 0; index < selfCallBarrier.nodeArray.length; index++) { selfCallBarrier.nodeArray[index] = new SelfCallBarrier.Node(); } } } // 全局序列 private static volatile int sequence = 1000; /** * 生成全局唯一序列, * 在JVM-SANDBOX中允许多个命名空间的存在,不同的命名空间下listenerId/objectId将会被植入到同一份字节码中, * 此时需要用全局的ID生成策略规避不同的命名空间 * * @return 全局自增序列 */ public static synchronized int nextSequence() { return sequence++; } private static void handleException(Throwable cause) throws Throwable { if (isSpyThrowException) { throw cause; } else { cause.printStackTrace(); } } private static final SelfCallBarrier selfCallBarrier = new SelfCallBarrier(); public static void spyMethodOnCallBefore(final int lineNumber, final String owner, final String name, final String desc, final String namespace, final int listenerId) throws Throwable { try { final MethodHook hook = namespaceMethodHookMap.get(namespace); if (null != hook) { hook.ON_CALL_BEFORE_METHOD.invoke(null, listenerId, lineNumber, owner, name, desc); } } catch (Throwable cause) { handleException(cause); } } public static void spyMethodOnCallReturn(final String namespace, final int listenerId) throws Throwable { try { final MethodHook hook = namespaceMethodHookMap.get(namespace); if (null != hook) { hook.ON_CALL_RETURN_METHOD.invoke(null, listenerId); } } catch (Throwable cause) { handleException(cause); } } public static void spyMethodOnCallThrows(final String throwException, final String namespace, final int listenerId) throws Throwable { try { final MethodHook hook = namespaceMethodHookMap.get(namespace); if (null != hook) { hook.ON_CALL_THROWS_METHOD.invoke(null, listenerId, throwException); } } catch (Throwable cause) { handleException(cause); } } public static void spyMethodOnLine(final int lineNumber, final String namespace, final int listenerId) throws Throwable { try { final MethodHook hook = namespaceMethodHookMap.get(namespace); if (null != hook) { hook.ON_LINE_METHOD.invoke(null, listenerId, lineNumber); } } catch (Throwable cause) { handleException(cause); } } public static Ret spyMethodOnBefore(final Object[] argumentArray, final String namespace, final int listenerId, final int targetClassLoaderObjectID, final String javaClassName, final String javaMethodName, final String javaMethodDesc, final Object target) throws Throwable { final Thread thread = Thread.currentThread(); if (selfCallBarrier.isEnter(thread)) { return Ret.RET_NONE; } final SelfCallBarrier.Node node = selfCallBarrier.enter(thread); try { final MethodHook hook = namespaceMethodHookMap.get(namespace); if (null == hook) { return Ret.RET_NONE; } return (Ret) hook.ON_BEFORE_METHOD.invoke(null, listenerId, targetClassLoaderObjectID, SPY_RET_CLASS, javaClassName, javaMethodName, javaMethodDesc, target, argumentArray); } catch (Throwable cause) { handleException(cause); return Ret.RET_NONE; } finally { selfCallBarrier.exit(thread, node); } } public static Ret spyMethodOnReturn(final Object object, final String namespace, final int listenerId) throws Throwable { final Thread thread = Thread.currentThread(); if (selfCallBarrier.isEnter(thread)) { return Ret.RET_NONE; } final SelfCallBarrier.Node node = selfCallBarrier.enter(thread); try { final MethodHook hook = namespaceMethodHookMap.get(namespace); if (null == hook) { return Ret.RET_NONE; } return (Ret) hook.ON_RETURN_METHOD.invoke(null, listenerId, SPY_RET_CLASS, object); } catch (Throwable cause) { handleException(cause); return Ret.RET_NONE; } finally { selfCallBarrier.exit(thread, node); } } public static Ret spyMethodOnThrows(final Throwable throwable, final String namespace, final int listenerId) throws Throwable { final Thread thread = Thread.currentThread(); if (selfCallBarrier.isEnter(thread)) { return Ret.RET_NONE; } final SelfCallBarrier.Node node = selfCallBarrier.enter(thread); try { final MethodHook hook = namespaceMethodHookMap.get(namespace); if (null == hook) { return Ret.RET_NONE; } return (Ret) hook.ON_THROWS_METHOD.invoke(null, listenerId, SPY_RET_CLASS, throwable); } catch (Throwable cause) { handleException(cause); return Ret.RET_NONE; } finally { selfCallBarrier.exit(thread, node); } } /** * 返回结果 */ public static class Ret { public static final int RET_STATE_NONE = 0; public static final int RET_STATE_RETURN = 1; public static final int RET_STATE_THROWS = 2; private static final Ret RET_NONE = new Ret(RET_STATE_NONE, null); /** * 返回状态(0:NONE;1:RETURN;2:THROWS) */ public final int state; /** * 应答对象 */ public final Object respond; /** * 构造返回结果 * * @param state 返回状态 * @param respond 应答对象 */ private Ret(int state, Object respond) { this.state = state; this.respond = respond; } public static Ret newInstanceForNone() { return RET_NONE; } public static Ret newInstanceForReturn(Object object) { return new Ret(RET_STATE_RETURN, object); } public static Ret newInstanceForThrows(Throwable throwable) { return new Ret(RET_STATE_THROWS, throwable); } } /** * 本地线程 */ public static class SelfCallBarrier { public static class Node { private final Thread thread; private Node pre; private Node next; Node() { this(null); } Node(final Thread thread) { this.thread = thread; } } // 删除节点 void delete(final Node node) { node.pre.next = node.next; if (null != node.next) { node.next.pre = node.pre; } // help gc node.pre = (node.next = null); } // 插入节点 void insert(final Node top, final Node node) { if (null != top.next) { top.next.pre = node; } node.next = top.next; node.pre = top; top.next = node; } static final int THREAD_LOCAL_ARRAY_LENGTH = 1024; final Node[] nodeArray = new Node[THREAD_LOCAL_ARRAY_LENGTH]; SelfCallBarrier() { // init root node for (int i = 0; i < THREAD_LOCAL_ARRAY_LENGTH; i++) { nodeArray[i] = new Node(); } } int abs(int val) { return val < 0 ? val * -1 : val; } boolean isEnter(Thread thread) { final Node top = nodeArray[abs(thread.hashCode()) % THREAD_LOCAL_ARRAY_LENGTH]; Node node = top; synchronized (top) { while (null != node.next) { node = node.next; if (thread == node.thread) { return true; } } return false; }//sync } Node enter(Thread thread) { final Node top = nodeArray[abs(thread.hashCode()) % THREAD_LOCAL_ARRAY_LENGTH]; final Node node = new Node(thread); synchronized (top) { insert(top, node); } return node; } void exit(Thread thread, Node node) { final Node top = nodeArray[abs(thread.hashCode()) % THREAD_LOCAL_ARRAY_LENGTH]; synchronized (top) { delete(node); } } } /** * 回调方法钩子 */ public static class MethodHook { private final Method ON_BEFORE_METHOD; private final Method ON_RETURN_METHOD; private final Method ON_THROWS_METHOD; private final Method ON_LINE_METHOD; private final Method ON_CALL_BEFORE_METHOD; private final Method ON_CALL_RETURN_METHOD; private final Method ON_CALL_THROWS_METHOD; public MethodHook(final Method on_before_method, final Method on_return_method, final Method on_throws_method, final Method on_line_method, final Method on_call_before_method, final Method on_call_return_method, final Method on_call_throws_method) { assert null != on_before_method; assert null != on_return_method; assert null != on_throws_method; assert null != on_line_method; assert null != on_call_before_method; assert null != on_call_return_method; assert null != on_call_throws_method; this.ON_BEFORE_METHOD = on_before_method; this.ON_RETURN_METHOD = on_return_method; this.ON_THROWS_METHOD = on_throws_method; this.ON_LINE_METHOD = on_line_method; this.ON_CALL_BEFORE_METHOD = on_call_before_method; this.ON_CALL_RETURN_METHOD = on_call_return_method; this.ON_CALL_THROWS_METHOD = on_call_throws_method; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy