package com.lody.virtual.client.hook.base; import android.content.Context; import com.lody.virtual.client.core.InvocationStubManager; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.interfaces.IInjector; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; /** * @author Lody * <p> * This class is responsible with: * - Instantiating a {@link MethodInvocationStub.HookInvocationHandler} on {@link #getInvocationStub()} ()} * - Install a bunch of {@link MethodProxy}s, either with a @{@link Inject} annotation or manually * calling {@link #addMethodProxy(MethodProxy)} from {@link #onBindMethods()} * - Install the hooked object on the Runtime via {@link #inject()} * <p> * All {@link MethodInvocationProxy}s (plus a couple of other @{@link IInjector}s are installed by * {@link InvocationStubManager} * @see Inject */ public abstract class MethodInvocationProxy<T extends MethodInvocationStub> implements IInjector { protected T mInvocationStub; public MethodInvocationProxy(T invocationStub) { this.mInvocationStub = invocationStub; onBindMethods(); afterHookApply(invocationStub); LogInvocation loggingAnnotation = getClass().getAnnotation(LogInvocation.class); if (loggingAnnotation != null) { invocationStub.setInvocationLoggingCondition(loggingAnnotation.value()); } } protected void onBindMethods() { if (mInvocationStub == null) { return; } Class<? extends MethodInvocationProxy> clazz = getClass(); Inject inject = clazz.getAnnotation(Inject.class); if (inject != null) { Class<?> proxiesClass = inject.value(); Class<?>[] innerClasses = proxiesClass.getDeclaredClasses(); for (Class<?> innerClass : innerClasses) { if (!Modifier.isAbstract(innerClass.getModifiers()) && MethodProxy.class.isAssignableFrom(innerClass) && innerClass.getAnnotation(SkipInject.class) == null) { addMethodProxy(innerClass); } } } } private void addMethodProxy(Class<?> hookType) { try { Constructor<?> constructor = hookType.getDeclaredConstructors()[0]; if (!constructor.isAccessible()) { constructor.setAccessible(true); } MethodProxy methodProxy; if (constructor.getParameterTypes().length == 0) { methodProxy = (MethodProxy) constructor.newInstance(); } else { methodProxy = (MethodProxy) constructor.newInstance(this); } mInvocationStub.addMethodProxy(methodProxy); } catch (Throwable e) { throw new RuntimeException("Unable to instance Hook : " + hookType + " : " + e.getMessage()); } } public MethodProxy addMethodProxy(MethodProxy methodProxy) { return mInvocationStub.addMethodProxy(methodProxy); } protected void afterHookApply(T delegate) { } @Override public abstract void inject() throws Throwable; public Context getContext() { return VirtualCore.get().getContext(); } public T getInvocationStub() { return mInvocationStub; } }