package com.lody.virtual.client.hook.base; import android.content.Context; import android.os.Build; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.interfaces.Injectable; import java.lang.reflect.Constructor; /** * @author Lody * * This class is responsible with: * - Instantiating a {@link HookDelegate.HookHandler} on {@link #getHookDelegate()} ()} * - Install a bunch of {@link Hook}s, either with a @{@link Patch} annotation or manually * calling {@link #addHook(Hook)} from {@link #onBindHooks()} * - Install the hooked object on the Runtime via {@link #inject()} * * All {@link PatchDelegate}s (plus a couple of other @{@link Injectable}s are installed by * {@link com.lody.virtual.client.core.PatchManager} * * @see Patch */ public abstract class PatchDelegate<T extends HookDelegate> implements Injectable { protected T hookDelegate; public PatchDelegate(T hookDelegate) { this.hookDelegate = hookDelegate; onBindHooks(); afterHookApply(hookDelegate); } protected void onBindHooks() { if (hookDelegate == null) { return; } Class<? extends PatchDelegate> clazz = getClass(); Patch patch = clazz.getAnnotation(Patch.class); int version = Build.VERSION.SDK_INT; if (patch != null) { Class<?>[] hookTypes = patch.value(); for (Class<?> hookType : hookTypes) { ApiLimit apiLimit = hookType.getAnnotation(ApiLimit.class); boolean needToAddHook = true; if (apiLimit != null) { int apiStart = apiLimit.start(); int apiEnd = apiLimit.end(); boolean highThanStart = apiStart == -1 || version > apiStart; boolean lowThanEnd = apiEnd == -1 || version < apiEnd; if (!highThanStart || !lowThanEnd) { needToAddHook = false; } } if (needToAddHook) { addHook(hookType); } } } } private void addHook(Class<?> hookType) { try { Constructor<?> constructor = hookType.getDeclaredConstructors()[0]; if (!constructor.isAccessible()) { constructor.setAccessible(true); } Hook hook; if (constructor.getParameterTypes().length == 0) { hook = (Hook) constructor.newInstance(); } else { hook = (Hook) constructor.newInstance(this); } hookDelegate.addHook(hook); } catch (Throwable e) { throw new RuntimeException("Unable to instance Hook : " + hookType + " : " + e.getMessage()); } } public Hook addHook(Hook hook) { return hookDelegate.addHook(hook); } protected void afterHookApply(T delegate) { } @Override public abstract void inject() throws Throwable; public Context getContext() { return VirtualCore.get().getContext(); } public T getHookDelegate() { return hookDelegate; } }