I. Related concepts

1, define,

Provide a proxy for other objects to control access to that object

2. Application scenarios

Main functions: Controls object access

  • Extend the function of the target object: for example, the actor (target object), has the function of acting, find a broker (agent), will provide an additional charge function, is actually the agent function, not the actor function.
  • Limit the function of the target object: for example, the agent is not satisfied with the fee and only allows the actor to perform one scene, which partially limits the function of the actor.

3, the class diagram

  • Subject: Abstracts the Subject role, essentially declaring the interface methods common to the proxied and proxied classes
  • RealSubject: Specific subject roles (brokered roles) that perform specific business logic
  • Proxy: A Proxy class that holds a reference to a prosted-object and is responsible for doing extra operations before and after a prosted-object method is called

4, strengths,

  • Responsibilities are clear, the proxyed role implements only the actual business logic, and the proxy object implements additional processing logic
  • It has high scalability and can replace different proxy classes to achieve different proxy logic

Two, static proxy:

It exists at compile time, and typically the interface needs to be defined first, and the proxied object and the proxied object implement the same interface together.

1. Interface Definition:

Public interface Play {// sing void sing(int count); // perform void show(); }Copy the code

2. Actor (agent) :

public class Actor implements Play {
  @Override
  public void sing(int count) {
    System.out.print("Sing" + count + "Song");
  }

  @Override
  public void show() {
    System.out.print("Put on a show"); }}Copy the code

The proxied object provides several concrete method implementations

3. Broker (Agent object) :

Public class Agent implements Play {// Private Play player; private long money; public voidsetMoney(long money){ this.money = money; } /** * @param player * @param money */ public Agent(Play player, long money) {this.player = player; this.money = money; } @Override public void sing(int count) { player.sing(count); } // Override public void Overrideshow() {
    if (money > 100) {
      player.show();
    } else {
      System.out.println("baibai..."); }}}Copy the code

4, the use of

public class PlayTest { public static void main(String[] args){ Actor actor = new Actor(); Agent agent = new Agent(actor, 50); agent.sing(2); agent.show(); agent.setMoney(200); agent.show(); }}Copy the code

The proxy object controls the function of the target object through its own logical processing.

Dynamic proxy:

Dynamic generally refers to the state at run time, as opposed to static at compile time, which is to generate a proxy object at run time to do some logic for us. The main use of reflection techniques is to get the loader of the class and create the instance. Dynamic proxy can dynamically create a class at run time, implement one or more interfaces, and dynamically add methods and modify behavior for objects obtained through this class without modifying the original class.

1. Generate dynamic proxy class:

InvocationHandler is the dynamic proxy interface that the dynamic proxy class needs to implement and process the proxy class’s methods in the Invoke method

public interface InvocationHandler {
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable;
}
Copy the code

Parameter Description:

  • Object proxy: the Object to be proxied
  • Object[] args: method to call
  • Object[] args: parameters required for method calls

Create a dynamic proxy class

The Proxy class can create a Proxy object with newProxyInstance

#Proxypublic static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h) throws IllegalArgumentException {if(h == null) { throw new NullPointerException(); } Class<? > cl = getProxyClass0(loader, interfaces); Final Constructor<? > cons = cl.getConstructor(constructorParams);returnnewInstance(cons, h); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); }}Copy the code

Parameter Description:

  • ClassLoader: indicates the ClassLoader
  • Class
    [] interfaces: all interfaces
  • InvocationHandler h: Subclasses that implement the InvocationHandler interface

3, dynamic proxy demo:

(1) Define the dynamic proxy class

public class ActorProxy implements InvocationHandler { private Play player; public ActorProxy(Play player){ this.player = player; } @override public Object invoke(Object proxy, Method Method, Object[] args) throws Throwable {// Process the Method implementation of the proxy Objectif ("show".equals(method.getName())){
      System.out.println("Proxy processing show....");
      return method.invoke(player, null);
    }else if ("sing".equals(method.getName())){
      System.out.println("Agent handling sing....");
      return method.invoke(player, 2);
    }
    returnnull; }}Copy the code

The proxy class implements the InvocationHandler interface and performs the corresponding logical processing on the Player (proxyed object) in the Invoke method.

(2) Use

public class ProxyTest { public static void main(String[] args) { Play actor = new Actor(); Play Proxy = (Play) proxy.newproxyInstance (actor.getClass().getClassLoader(), actor.getClass().getInterfaces(), new ActorProxy(actor)); // call proxy.show(); proxy.sing(3); }}Copy the code

4. Proxy mode in Android

1. Retrofit agent model

(1) Retrofit uses: Define interfaces

public interface MyService {
    @GET("users/{user}/list")
    Call<String> getMyList(@Path("user") String user);
}
Copy the code

Create a New RetroFit object, generate an interface object, and call concrete methods to fulfill the request.

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://xxx.com")
            .build();
MyService myService = retrofit.create(MyService.class);
Call<String> myList = myService.getMyList("my");
Copy the code

The retrofit.create method simply passes in an interface as a dynamic proxy that returns an object

(2) Dynamic proxy analysis:

Public < T > T create (final Class < T > service) {/ / determine whether for interface Utils. ValidateServiceInterface (service);if(validateEagerly) { eagerlyValidateMethods(service); } // Create a dynamic proxy object for the request interfacereturn(T) Proxy.newProxyInstance(service.getClassLoader(), new Class<? >[] { service }, newInvocationHandler() {
        private final Platform platform = Platform.get();
        private final Object[] emptyArgs = new Object[0];

        @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
            throws Throwable {
          // If the method is a method from Object then defer to normal invocation.
          if (method.getDeclaringClass() == Object.class) {
            return method.invoke(this, args);
          }
          if (platform.isDefaultMethod(method)) {
            returnplatform.invokeDefaultMethod(method, service, proxy, args); } // Passing a method in the interface returns ServiceMethodreturn loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
        }
      });
}
Copy the code

With proxy.newProxyInstance, the dynamic Proxy object can get all the annotations on the request interface instance and then make network requests through the Proxy object.

2. Agent mode in Binder

Binder mechanism

Remote proxy: Provides local proxy objects for an object in different memory address Spaces

AMS, ApplicationThread

  • When an Activity starts, the application communicates with ActivityManagerService in the SystemServer process through the IActivityManager local proxy object.
  • When AMS has finished processing permissions, stacks, and other information, it can call the methods of the application process (proxied object) ApplicationThread through the proxy object IApplicationThread.

(2) Binder model

  • Includes Client, Server, ServiceManager, and Binder drivers.
  • Client, Server, Service Manager run in user space, Binder drivers run in kernel space.
  • For clients, a Binder is a reference to a Server’s local object. The reference is actually a proxy object through which the Client accesses the Server’s local object indirectly.
  • For Servers, a Binder is a local object that provides a concrete implementation and needs to be registered with a ServiceManager.
  • Binder drivers are the bridge between Client and Server, responsible for converting proxy objects into local objects and returning Server execution results to Client.
  • The ServiceManager stores mappings between Server Binder character names and Binder references that clients use to find Server Binder references.

3. Proxy mode in plug-in

In plug-ins, such as VirtualApk, the local proxy object for AMS, IActivityManager, acts as a proxy for the IActivityManager, controlling some of the behavior of the IActivityManager

(1) Create dynamic proxy

protected void hookSystemServices() {
  try {
    Singleton<IActivityManager> defaultSingleton;

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      defaultSingleton = Reflector.on(ActivityManager.class).field("IActivityManagerSingleton").get();
    } else {
      defaultSingleton = Reflector.on(ActivityManagerNative.class).field("gDefault").get(); } IActivityManager origin = defaultSingleton.get(); ActivityManagerProxy = (IActivityManager) Proxy.newProxyInstance(mContext.getClassLoader(), new Class[] { IActivityManager.class }, createActivityManagerProxy(origin)); // Hook IActivityManager Reflector. With (defaulleton). Field ()"mInstance").set(activityManagerProxy);

    if (defaultSingleton.get() == activityManagerProxy) {
      this.mActivityManager = activityManagerProxy;
      Log.d(TAG, "hookSystemServices succeed : " + mActivityManager);
    }
  } catch (Exception e) {
    Log.w(TAG, e);
  }
}

protected ActivityManagerProxy createActivityManagerProxy(IActivityManager origin) throws Exception {
  return new ActivityManagerProxy(this, origin);
}

Copy the code

Create the dynamic proxy ActivityManagerProxy and hook the IActivityManager through reflection

(2) Dynamic proxy objects

public class ActivityManagerProxy implements InvocationHandler { ...... Private IActivityManager mActivityManager; public ActivityManagerProxy(PluginManager pluginManager, IActivityManager activityManager) { this.mPluginManager = pluginManager; this.mActivityManager = activityManager; } @override public Object invoke(Object proxy, Method Method, Object[] args) throws Throwable { Perform your own logicif ("startService".equals(method.getName())) {
      try {
        return startService(proxy, method, args);
      } catch (Throwable e) {
        Log.e(TAG, "Start service error", e); }}... }}Copy the code

ActivityManagerProxy implements InvocationHandler and holds the IActivityManager, which controls and executes its own logic when the IActivityManager method executes