Android10.0 Binder communication theory (X) -AIDL principle analysis -Proxy-Stub design patterns

Summary: This section focuses on communication theory to explain the Android10.0 AIDL

Read this article takes approximately 24 minutes.

Articles starting micro-channel public number: IngresGe

Focus on Android system-level source code analysis, the Android platform design, welcome attention to me, thank you!

[Learn the way the Android] are based on source Android-Q (10.0) were analyzed

[Android learn the way] series:

"Boot articles"

  1. Android System Architecture
  2. Android is how to start
  3. Android 10.0 system starts the init process
  4. Android10.0 system startup process of Zygote
  5. Android 10.0 system startup process of SystemServer
  6. Android 10.0 System Services of ActivityMnagerService
  7. Android10.0 system starts the Launcher (Desktop) to start the process
  8. Android10.0 application process as well as the creation of Zygote fork process
  9. Android 10.0 PackageManagerService (a) works and start the process
  10. Android 10.0 PackageManagerService (ii) allowed to scan
  11. Android 10.0 PackageManagerService (three) scanning APK
  12. Android 10.0 PackageManagerService (four) installation process APK

"Log System chapter"

  1. Android10.0 log analysis system (a) -logd, logcat instruction description, classification and properties
  2. Android10.0 log analysis system (b) -logd, logcat architecture analysis and log system initialization
  3. Android10.0 log analysis system (C) -logd, logcat log write source code analysis
  4. Android10.0 logging system analysis (four) -selinux, kernel log in to achieve in logd

"Binder communication principle" :

  1. Android10.0 Binder communication principle (one) Binder, HwBinder, VndBinder Overview
  2. Android10.0 Binder communication theory (b) -Binder Beginners
  3. Android10.0 Binder communication theory (c) -ServiceManager articles
  4. Android10.0 Binder communication theory (four) -Native-C C ++ case study \
  5. Android10.0 Binder communication theory (five) -Binder Driving
  6. How Android10.0 Binder communication theory (six) -Binder complete data directed against
  7. Android10.0 Binder communication theory (seven) -Framework binder examples
  8. Android10.0 Binder communication theory (eight) -Framework layer analysis
  9. Android10.0 Binder communication theory (IX) -AIDL Binder Example

1 Overview

On the one we wrote a AIDL example, to achieve the communication between the two applications, this section we'll explore together how the next AIDL is in force.

 

2. What is AIDL

AIDL: Android Interface Definition Language, that is, Android Interface Definition Language.

Android can not share memory between processes in the system, therefore, need to provide some mechanism for data communication between different processes. In order to enable other applications can also access services provided by this application, Android system uses a Remote Procedure Call (Remote Procedure Call, RPC) manner. Like many other RPC-based solutions, Android using an interface definition language (Interface Definition Language, IDL) interfaces to public services. We know that four Android application components 3 (Activity, BroadcastReceiver and ContentProvider) can be accessed across processes, another Android Application Component Service can also be. Therefore, such a process can access services across called AIDL (Android Interface Definition Language) services.

 

3. Why AIDL

Each Android application is a separate process with its own virtual machine memory between virtual address, applications can not access more than each other, there is an application isolation, so the two can not apply object-oriented languages ​​like direct call interface. Call between the two processes is called IPC (interprocess communication). Binder at the beginning of the chapter, we learned IPC calls between Android in the process are: pipes, shared memory, message queues, semaphores, socket, binder, in "Binder Beginners" in the performance, security point of view to explain respectively advantages and disadvantages of the various IPC communication, and ultimately we chose Binder.

Well, since we have Binder, why have AIDL it?

In front of us "Framrwork binder example," we know, to client \ server through the binder, we write a complete service creation and client acquisition process, on a AIDL example, after we finished AIDL compiled, the resulting file is found IMyService.java and we write in the Framework of similar, AIDL simplifies the code logic Binder, the interaction of the Service with the logic generated by the compiler tools.

 

4.AIDL communication flow

Client-side and Server-side using the same AIDL, even the name of the package needs to be consistent.

Server-side inherited from the Service, overloading a onBind (), return to the service entity Stub (), Stub provides a method asInterface (Binder), if it is in the same process so asInterface () will return the Stub object itself, otherwise Stub.Proxy object.

Code:

IMyService.Stub mStub = new IMyService.Stub(){...};
@Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG,"onBind");
        return mStub;//通过ServiceConnection在activity中拿到MyService
}

Client Services Stub.asInterface return to get through the proxy Stub.Proxy () when binding service

Code:

myService = IMyService.Stub.asInterface(service);

Client and Server interaction of simple schematic process:

From the view of the above example, the local service to get the service entity generated AIDL Stub (), Client binding service, get a service proxy Stub.proxy (). This we explain in the previous Framewok layer of relatively similar, Client get BinderProxy objects, Server Binder to get entity objects.

AIDL here uses a Proxy-Stub (proxy - stub) design pattern, here we have this design model to expand explain.

Binder communication data flow is shown below:

5.proxy-stub design patterns

Proxy Interface converted into particularity universal interfaces, universal interface to the Stub converted into particularity interface between the two data conversion performed by Parcel (packing), Proxy agents often transmitted as the data, the data package sent by Parcel , received data often as the Stub pile, unpacked and analytical Parcel data package.

Examples appreciated Proxy-Stub:

If we watch TV now, I am a customer Client, remote control proxy Proxy, television is an entity (the playback screen display function), pass the TV remote control Bluetooth, infrared parameters Parcel data.

I pressed a few buttons on the remote control - before lifting the volume with the TV remote control to do the binding, you can get the TV object - an entity Stub, the assembly operation into a key Parcel data, sent TV -Server, TV -Server get the request, perform the appropriate treatment - to enhance the volume and return the results to the remote control, our operation is completed (in fact, this step is not, we just look at hypothetical). This completes the Proxy-Stub data exchange processes.

 

Proxy and Stub description:

  1. Proxy Stub is with a pair commonly known as "proxy - stub" is generally used in Remote Method Invocation
  2. Proxy interface for client programs to call, and then it will good information inside the package, delivered to Stub in some way, and the latter to the server system, thus completing the "Remote Call" through the interface corresponding action
  3. In AIDL, the Stub service entity; Stub.Proxy () of the proxy service, the Stub.asInterface (IBinder) is acquired by, it can be seen by AIDL generated java files.
public static com.android.myservice.IMyService asInterface(android.os.IBinder obj)
{
    if ((obj==null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin!=null)&&(iin instanceof com.android.myservice.IMyService))) {
        return ((com.android.myservice.IMyService)iin); //如果是同一进程,返回的是服务Stub本身
    }
    return new com.android.myservice.IMyService.Stub.Proxy(obj); //如果是不同进程,则返回Stub.Proxy()代理
}

6.AIDL Principle Analysis

After the last one, IMyService.aidl compiler, Android Studio automatically generates the IMyService.java file, we look at the contents of this file:

Code:IMyService.java


/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.android.myservice;
// Declare any non-default types here with import statements

public interface IMyService extends android.os.IInterface
{
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.android.myservice.IMyService
{
    private static final java.lang.String DESCRIPTOR = "com.android.myservice.IMyService";
    /** Construct the stub at attach it to the interface. */
    public Stub()
{
      this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * Cast an IBinder object into an com.android.myservice.IMyService interface,
     * generating a proxy if needed.
     */
    public static com.android.myservice.IMyService asInterface(android.os.IBinder obj)
{
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.android.myservice.IMyService))) {
        return ((com.android.myservice.IMyService)iin);
      }
      return new com.android.myservice.IMyService.Stub.Proxy(obj);
    }

    @Override public android.os.IBinder asBinder()
{
      return this;
    }

    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_basicTypes:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          long _arg1;
          _arg1 = data.readLong();
          boolean _arg2;
          _arg2 = (0!=data.readInt());
          float _arg3;
          _arg3 = data.readFloat();
          double _arg4;
          _arg4 = data.readDouble();
          java.lang.String _arg5;
          _arg5 = data.readString();
          this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_add:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          int _arg1;
          _arg1 = data.readInt();
          int _result = this.add(_arg0, _arg1);
          reply.writeNoException();
          reply.writeInt(_result);
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }

    private static class Proxy implements com.android.myservice.IMyService
{
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }

      @Override public android.os.IBinder asBinder()
{
        return mRemote;
      }

      public java.lang.String getInterfaceDescriptor()
{
        return DESCRIPTOR;
      }

      /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
      @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(anInt);
          _data.writeLong(aLong);
          _data.writeInt(((aBoolean)?(1):(0)));
          _data.writeFloat(aFloat);
          _data.writeDouble(aDouble);
          _data.writeString(aString);
          mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public int add(int num1, int num2) throws android.os.RemoteException
{
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(num1);
          _data.writeInt(num2);
          mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
          _reply.readException();
          _result = _reply.readInt();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
    }
    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
  }
  /**
   * Demonstrates some basic types that you can use as parameters
   * and return values in AIDL.
   */
  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
  public int add(int num1, int num2) throws android.os.RemoteException;
}

IMyService.java description:

  1. There is a Stub abstract class, Stub and there were a Proxy abstract class
  2. Stub.asInterface (IBinder) is based on the same communication, or a different process communication, return Stub () entity, or Stub.Proxy () proxy object
  3. Stub () of Binder entities have a onTransact () function, in some Binder Native, Framework flow front, we know that the service entrance of final disposal is onTransact (), this will resolve Client came TRANSACTION code, parsing Parcel data, call the corresponding service interface processing
  4. The presence of Proxy () in a asBinder (), the returned object is mRemote, as we understand Framework earlier, the corresponding fact BinderProxy object.
  5. The Proxy () assembled core AIDL Client interface implemented in assembly Parcel data, call BinderProxy () of Transact () TRANSACTION code transmitted

 

 

AIDL specific process is as follows:

  1. Client and Server use the same AIDL file with the same package name, compiled, both sides will generate IMyService.java, including Stub two entities and Proxy agent objects
  2. Server side through AndroidManifest.xml registered Service
  3. Client get proxy service Stub.Proxy () by bindService ()
  4. Client calls AIDL methods add (), in fact, calls are Stub.Proxy.add IMyService.java in (), finally sent to the server through transact BinderProxy.java of ()
  5. Binder driven by the flow proceeds to onTransact service side (), according TRANSACTION code Client transmitted, parses the incoming process corresponding process proceeds add ()
  6. In MyService bound, the entity with IMyService.Stub, eventually enter the MyService.java add () process interface call is completed, the call is completed after Parcel write data, sent to the Client reply by

7.AIDL configuration methods

AIDL using a simple grammar that allows you by one or more methods (may receive parameters and return values) to declare interfaces. Parameters and return value other interfaces may be of any type, even AIDL generated.

You must use the Java programming language to build .aidl file. Each .aidl file must define a single interface, and requires only the interface declaration and the method signatures.

By default, AIDL supports the following data types:

  • All primitive types in the Java programming language (such as int, long, char, boolean, etc.)

  • String

  • CharSequence

  • List

List all of the elements in the list above must be supported data types, or other type of interface or Parcelable AIDL generated by your statement. List as an option to "generic" (e.g., List <String>). Although the generation method is designed to use the List interface, but the other party actually received specific class is always ArrayList.

  • Map

Map of all the elements in the list above must be supported data types, or other type of interface or Parcelable AIDL generated by your statement. It does not support the generic Map (such as Map <String, Integer> form Map). Although the generation method is designed to use the Map interface, but the other party actually received specific class is always HashMap.

 

When you define a service interface, please note:

Method with zero or more arguments, returns or empty value.

All non-primitive parameters are required to indicate the direction of data marks. Such markers may be in, out, or INOUT (see example below).

Primitives The default is in, not other direction.

 

oneway keyword is used to modify the behavior of remote calls. After using this keyword, remote call does not block, but only send transaction data and returns immediately. When the final data is received, the interface will implement it as a routine call (ordinary long-distance calls) from Binder thread pool. If oneway for a local call, there will not be any impact, and the call is still synchronous calls.

 

8. Conclusion

Proxy Client to the Server by the request and eventually into Binder Driver, binder according to different transactions, to a Binder entity, entity processing logic into different depending TRANSACTION code, the processed result obtained, the data is assembled as will Parcel, sent out by the reply, the Client reply data received, the final processing flow.

 

reference:

"Android in AIDL works"

"From the start with an example analysis AIDL principle" 

"Android Binder fully resolve (c) AIDL implement the principle of analysis"

"Android Interface Definition Language (AIDL)"

"Android is used in AIDL explain"

"From IBinder Interface design patterns learning Proxy-Stub"

"Inter-process communication -AIDL Android realization of the principle"

 

My micro-channel public number: IngresGe

Published 26 original articles · won praise 62 · views 50000 +

Guess you like

Origin blog.csdn.net/yiranfeng/article/details/105314318