content: package com.lody.virtual.client.hook.secondary;
  
  import android.os.IBinder;
  import android.os.IInterface;
  import android.os.Parcel;
  import android.os.RemoteException;
  
  import java.io.FileDescriptor;
  import java.lang.reflect.InvocationHandler;
  import java.lang.reflect.Method;
  import java.lang.reflect.Modifier;
  import java.lang.reflect.Proxy;
  
  /**
   * @author Lody
   */
  
  abstract class StubBinder implements IBinder {
  	private ClassLoader mClassLoader;
  	private IBinder mBase;
  	private IInterface mInterface;
  
  	StubBinder(ClassLoader classLoader, IBinder base) {
  		this.mClassLoader = classLoader;
  		this.mBase = base;
  	}
  
  	@Override
  	public String getInterfaceDescriptor() throws RemoteException {
  		return mBase.getInterfaceDescriptor();
  	}
  
  	@Override
  	public boolean pingBinder() {
  		return mBase.pingBinder();
  	}
  
  	@Override
  	public boolean isBinderAlive() {
  		return mBase.isBinderAlive();
  	}
  
  
  	/**
  	 * Anti the Proguard.
  	 *
  	 * Search the AidlClass.Stub.asInterface(IBinder) method by the StackTrace.
  	 *
  	 */
  	@Override
  	public IInterface queryLocalInterface(String descriptor) {
  		if (mInterface == null) {
  			StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
  			if (stackTrace == null || stackTrace.length <= 1) {
  				return null;
  			}
  			Class<?> aidlType = null;
  			IInterface targetInterface = null;
  
  			for (StackTraceElement element : stackTrace) {
  				if (element.isNativeMethod()) {
  					continue;
  				}
  				try {
                      Method method = mClassLoader.loadClass(element.getClassName())
                              .getDeclaredMethod(element.getMethodName(), IBinder.class);
                      if ((method.getModifiers() & Modifier.STATIC) != 0) {
                          method.setAccessible(true);
                          Class<?> returnType = method.getReturnType();
                          if (returnType.isInterface() && IInterface.class.isAssignableFrom(returnType)) {
                              aidlType = returnType;
                              targetInterface = (IInterface) method.invoke(null, mBase);
                          }
                      }
                  } catch (Exception e) {
                      // go to the next cycle
                  }
  			}
  			if (aidlType == null || targetInterface == null) {
                  return null;
              }
  			InvocationHandler handler = createHandler(aidlType, targetInterface);
  			mInterface = (IInterface) Proxy.newProxyInstance(mClassLoader, new Class[]{aidlType}, handler);
  		}
  		return mInterface;
  
  	}
  
  	public abstract InvocationHandler createHandler(Class<?> interfaceClass, IInterface iInterface);
  
  
  	@Override
  	public void dump(FileDescriptor fd, String[] args) throws RemoteException {
  		mBase.dump(fd, args);
  	}
  
  	@Override
  	public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
  		mBase.dumpAsync(fd, args);
  	}
  
  	@Override
  	public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
  		return mBase.transact(code, data, reply, flags);
  	}
  
  	@Override
  	public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException {
  		mBase.linkToDeath(recipient, flags);
  	}
  
  	@Override
  	public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
  		return mBase.unlinkToDeath(recipient, flags);
  	}
  }
  