当前位置:网站首页>Cross process communication Aidl

Cross process communication Aidl

2022-07-05 09:47:00 Black Mountain demon 2018

AIDL What is it? , What is the role

The project involves two applications, that is, data communication between two processes , and Android Memory addresses between processes in are independent , One process cannot access the memory address of another process . Here is a brief introduction to the concept of process , A process is an entity of a program or application , Each process has its own independent memory address space . Official documents say , To communicate , The process needs to decompose its objects into primitives that can be understood by the operating system , And group them into objects that you can manipulate . Writing the code to perform the grouping operation is cumbersome , therefore Android Will use AIDL To complete cross process communication .

Android The cross process in is actually IPC(Inter-Process Communication) signal communication , and AIDL It is IPC The mechanism of communication .
AIDL The full name is Android Interface Definition Language, It means Android interface definition , Realize cross process communication by defining relevant interfaces .


AIDL Use

1.AIDl Supported data types
AIDL Use a simple syntax , Allows you to use one or more methods ( Acceptable parameters and return values ) To declare acceptance mouth . Parameters and return values can be of any type , Even AIDL Other interfaces generated .
You must use Java Programming language construction .aidl file . Every .aidl Each document must define a single interface , And you only need the interface declaration and method signature .
By default ,AIDL The following data types are supported :
Java All primitive types in programming languages ( Such as int、long、char、boolean etc. java Basic data type )
1.String
2.CharSequence
3.List
List All elements in the must be data types supported in the above list , Or what you declared by AIDL Other interfaces generated or Parcelable type . You can choose to List Used as a “ Generic ” class ( for example ,List). Although the generated method is intended to use List Interface , But the specific class actually received by the other party is always ArrayList.
4. Map
Map All elements in the must be data types supported in the above list , Or what you declared by AIDL Other interfaces generated or Parcelable type . Generics are not supported Map( Such as Map<String,Integer> Formal Map). Although the generated method is intended to use Map Interface , But the specific class actually received by the other party is always HashMap.
5. other AIDL Generated interfaces
6. Realization Parcelable Class data type

2. To write AIDL Related codes
Write server code
Create entity class Person class , Realization Parcelable Interface , Entity classes for cross process communication .

public class People implements Parcelable {
    
            private String id;
            private String name;

   @Override
   public void writeToParcel(Parcel dest, int flags) {
    
            dest.writeString(id);
            dest.writeString(name);
    }

    @Override
    public int describeContents() {
    
           return 0;
    }

    public static final Creator<People> CREATOR = new Creator<People>() {
    
        @Override
        public People createFromParcel(Parcel in) {
    
             People people =  new People();
             people.setId(in.readString());
             people.setName(in.readString());
             return people;
        }

        @Override
        public People[] newArray(int size) {
    
             return new People[size];
        }
    };

    public String getId() {
    
         return id;
    }

    public void setId(String id) {
    
         this.id = id;
    }

    public String getName() {
    
         return name;
    }

    public void setName(String name) {
    
         this.name = name;
    }
}

establish .aldl file , Here are two files , One is the entity class People The file of , One is the interface file

// People.aidl
package com.uniubi.aidlapplication;

parcelable People;
  // People.aidl
package com.uniubi.aidlapplication;
import com.uniubi.aidlapplication.People;

interface IRemoteService {
    
   void basicTypes(int a, long b, in People person, in String d);
}

Remember to import People class , otherwise .aidl The file will not be found .

Implementation interface

Click on android studio Of make project
Will be in build/generated//Users/chenxuming/generated/aidl_source_output_dir/debug/compileDebugAidl/out/ Generate under directory IRemoteService.java file .
 Insert picture description here
Remember to be present moudle Of gradle The document specifies .aidl File path , Otherwise, the compiler will not find People This class ,
I suffered a big loss here .

sourceSets {
    
       main {
    
           manifest.srcFile 'src/main/AndroidManifest.xml'
           java.srcDirs = ['src/main/java', 'src/main/aidl']
           resources.srcDirs = ['src/main/java', 'src/main/aidl']
           aidl.srcDirs = ['src/main/aidl']
           res.srcDirs = ['src/main/res']
           assets.srcDirs = ['src/main/assets']
       }
   }

View the generated java file , You can see the interface IRemoteService Class inheritance android.os.IInterface Interface , It contains an inheritance Binder Of Sub Subclass , And this Sub Subclass implementation IRemoteService Interface , Later, we will talk about the generated IRemoteService Class specific source code .

establish Service, And create binder object , adopt onBind Method returns this binder object , So far, the server code has been written .

public class RemoteService extends Service {
    

  private static final String TAG = "RemoteService";
  private IRemoteService.Stub binder = new IRemoteService.Stub() {
    

       @Override
       public void basicTypes(int a, long b, People person, String d) throws RemoteException {
    
           Log.i(TAG, "basicTypes" + person.getName());
       }
   };

   @Override
   public IBinder onBind(Intent intent) {
    
       return binder;
   }
}

Expose the interface to the client
1. Will server end src/main The whole below aidl Copy the files in the directory to the same location of the client , Under the client project, don't forget the current module Under the gradle To configure sourceSets, Can let .aidl File found People class , then make project.
2. Binding remote services , Here, you must bind the remote service ,“com.uniubi.aidlapplication.RemoteService” It is a remote service actiob name, Bind implicitly .

 Intent intent1 = new Intent();
 intent1.setComponent(new ComponentName("com.uniubi.aidlapplication", "com.uniubi.aidlapplication.RemoteService"));
 bindService(intent1, serviceConnection, BIND_AUTO_CREATE);
private IRemoteService iRemoteService;

private ServiceConnection serviceConnection = new ServiceConnection() {
    

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
    
            Log.i("MainActivity", "onServiceConnected");
            iRemoteService = IRemoteService.Stub.asInterface(service);

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
    
            Log.i("MainActivity", "onServiceDisconnected");
        }
    };

From the code, we can see that after binding the remote service successfully , Can get it IBinder object , And then through IRemoteService.Stub.asInterface(service) Turn it into what we need iRemoteService object , And then through
iRemoteService object , You can make cross process requests .

 try {
    
       if(iRemoteService != null){
    
          iRemoteService.basicTypes(1, 2, people, " ha-ha ");
       }
 } catch (RemoteException e) {
    
        Log.i("MainActivity", e.getMessage());
         e.printStackTrace();
}

AIDL Source code analysis
The generated code format is messy , It's best to format it first for easy reading .

 /* * This file is auto-generated. DO NOT MODIFY. * Original file: /Users/chenxuming/AndroidStudioProjects/AIDLClient/app/src/main/aidl/com/uniubi/aidlapplication/IRemoteService.aidl */
package com.uniubi.aidlapplication;

public interface IRemoteService extends android.os.IInterface {
    
    /** * Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.uniubi.aidlapplication.IRemoteService {
    
        private static final java.lang.String DESCRIPTOR = "com.uniubi.aidlapplication.IRemoteService";

        /** * Construct the stub at attach it to the interface. */
        public Stub() {
    
            this.attachInterface(this, DESCRIPTOR);
        }

        /** * Cast an IBinder object into an com.uniubi.aidlapplication.IRemoteService interface, * generating a proxy if needed. */
        public static com.uniubi.aidlapplication.IRemoteService asInterface(android.os.IBinder obj) {
    
            if ((obj == null)) {
    
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.uniubi.aidlapplication.IRemoteService))) {
    
                return ((com.uniubi.aidlapplication.IRemoteService) iin);
            }
            return new com.uniubi.aidlapplication.IRemoteService.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();
                    com.uniubi.aidlapplication.People _arg2;
                    if ((0 != data.readInt())) {
    
                        _arg2 = com.uniubi.aidlapplication.People.CREATOR.createFromParcel(data);
                    } else {
    
                        _arg2 = null;
                    }
                    java.lang.String _arg3;
                    _arg3 = data.readString();
                    this.basicTypes(_arg0, _arg1, _arg2, _arg3);
                    reply.writeNoException();
                    return true;
                }
                default: {
    
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.uniubi.aidlapplication.IRemoteService {
    
            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;
            }

            @Override
            public void basicTypes(int a, long b, com.uniubi.aidlapplication.People person, java.lang.String d) 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(a);
                    _data.writeLong(b);
                    if ((person != null)) {
    
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
    
                        _data.writeInt(0);
                    }
                    _data.writeString(d);
                    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                    _reply.readException();
                } finally {
    
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    public void basicTypes(int a, long b, com.uniubi.aidlapplication.People person, java.lang.String d) throws android.os.RemoteException;
}

It's not hard to find out IRemoteService This class consists of two parts , Part is the declared interface , Part is inheritance Binder Class Sub Inner class , This Sub Inner classes have two main methods ,asInterface() and onTransact() Method , There is also an inner class Proxy, At the first glance, you can see that it is the agent mode , I won't elaborate on the proxy mode here .
Step by step , Take a look first iRemoteService = IRemoteService.Stub.asInterface(service) This line of code , Will serve the end of binder Object resolves to client iRemoteService object , This method returns IRemoteService.Stub.Proxy object , in other words iRemoteService Object is IRemoteService.Stub.Proxy, Then look at the call iRemoteService.basicTypes(1, 2, people, “ ha-ha ”) The place of , In fact, what you see is Proxy Object's basicTypes Method , See key code mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0); It's through mRemote Object's transact Methods to communicate ,mRemote The object is the remote server Sub object , Click in to check the source code , Main view onTransact Method , And the above also mentioned Sub Class implements Binder Class onTransact Methodical ( It has been posted , There is no repetition here ).

 public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
    
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);
        if (data != null) {
    
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
    
            reply.setDataPosition(0);
        }
        return r;
    }

Find out onTransact It's through code To specify the specific invocation behavior , Key code this.basicTypes(_arg0, _arg1, _arg2, _arg3); And here it is this It's the remote server Sub object , Specifically basicTypes The implementation of the method has to go to the server , The client cannot see . Here, the whole process of cross process communication between client and server is explained .


summary

1.asInterface(android.os.IBinder obj)
For server Binder Object is converted to what the client needs AIDL Object of interface type , This conversion process is process specific ( If the client and server are in the same process , Then what this method returns is the... Of the server Stub Object itself , Otherwise, the returned is the system encapsulated Stub.proxy object )

2.onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
Clients' cross process requests are mainly through remote services binder Object's onTransact Method to complete .
code : Determine the target method of the client request .
data : If the target method has parameters , From data Get the parameters required by the target method .
reply : When the target method is executed , If the target method has a return value , As to the reply Write the return value in .
flag : 0

3.DESCRIPTOR
Binder Unique identification of , Usually use the current AIDL The interface name indicates .

In short, everything is through binder Object to complete , The remote server holds binder Object entities , Local client Proxy Hold the server binder Object reference , And pass Sub.asInterface() Method into a local interface class object .
 Insert picture description here

原网站

版权声明
本文为[Black Mountain demon 2018]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202140536454135.html