package cm.android.hook;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
/**
* <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
*/
public abstract class MethodInvocationProxy<T extends MethodInvocationStub> implements IInjector {
protected T mInvocationStub;
public MethodInvocationProxy(T invocationStub) {
this.mInvocationStub = invocationStub;
onBindMethods();
afterHookApply(invocationStub);
}
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 T getInvocationStub() {
return mInvocationStub;
}
}