• binder通信实现


    kotlin实现参考链接

    原理说明参考链接

    本文为Java实现,基本流程与参考链接一致,代码和可运行的APK文件在github文件夹

    service端

    目录结构

    service端实际架构如下(与android studio中的目录显示不太一样)

    aidl是Android 接口定义语言,定义数据接口

    在这里插入图片描述

    通过android studio的build功能,可以自动生成IMyAidlInterface.aidl的java接口实现,位置在:

    在这里插入图片描述

    service端需要实现aidl中定义的RequestData类和ResponseData类,以及MyService类调用IMyAidlInterface.Stub对象的asBinder方法

    在这里插入图片描述

    aidl文件

    RequestData.aidl

    parcelable定义了binder在用户空间使用的数据模型

    package com.example.appbinder;
    
    parcelable RequestData;
    
    • 1
    • 2
    • 3

    ResponseData.aidl

    package com.example.appbinder;
    
    parcelable ResponseData;
    
    • 1
    • 2
    • 3

    IMyAidlInterface.aidl

    interface定义了一个binder service,在编译中aidl会自动生成两类binder对象:

    • Stub类继承了Binder,应该在服务端实现
    • Proxy类应该在客户端实现

    interface中函数的参数

    • 可以是原始类型、parcelable、Binder对象
    • 可以通过in、out、inout来修饰
      • in表示参数中的数据只从客户端移动到服务端,服务端只接收其中的数据不做更改
      • out则是相反的情况,在客户端给服务端发消息时,该参数只是一个占位符,不会被序列化;在服务端返回消息时,该占位符才会被初始化
      • inout是两者的结合
    package com.example.appbinder;
    import com.example.appbinder.RequestData;
    import com.example.appbinder.ResponseData;
    
    interface IMyAidlInterface {
        ResponseData send(in RequestData  request);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    aidl文件编译

    配置app的build.gradle

    在这里插入图片描述

    直接编译,在刚才的位置可以找到生成的IMyAidlInterface.java文件

    java文件

    RequestData.java

    实现Parcelable接口,有一个字符串作为私有变量,一个toString函数来打印RequestData类数据

    package com.example.appbinder;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    import static android.os.UserHandle.readFromParcel;
    
    public class RequestData implements Parcelable {
    
        private String s;
    
        protected RequestData(Parcel in) {
            readFromParcel(in);
        }
    
        public RequestData(String s) {
            this.s = s;
        }
    
        /** 将数据写入到Parcel **/
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(s);
        }
    
        /** 从Parcel中读取数据 **/
        public void readFromParcel(Parcel in){
            s = in.readString();
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        public static final Creator<RequestData> CREATOR = new Creator<RequestData>() {
            @Override
            public RequestData createFromParcel(Parcel in) {
                return new RequestData(in);
            }
    
            @Override
            public RequestData[] newArray(int size) {
                return new RequestData[size];
            }
        };
    
        @Override
        public String toString() {
            return s;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    ResponseData.java

    package com.example.appbinder;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    public class ResponseData implements Parcelable {
    
        private String s;
    
        protected ResponseData(Parcel in) {
            readFromParcel(in);
        }
    
        public ResponseData(String s) {
           this.s = s;
        }
    
        /** 将数据写入到Parcel **/
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(s);
        }
    
        /** 从Parcel中读取数据 **/
        public void readFromParcel(Parcel in){
            s = in.readString();
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        public static final Parcelable.Creator<ResponseData> CREATOR = new Parcelable.Creator<ResponseData>() {
            @Override
            public ResponseData createFromParcel(Parcel in) {
                return new ResponseData(in);
            }
    
            @Override
            public ResponseData[] newArray(int size) {
                return new ResponseData[size];
            }
        };
    
        @Override
        public String toString() {
            return s;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    MyService.java

    Service在onBind方法返回Binder实体,最后会注册到ServiceManager的映射表,供客户端调用;binder实体在IMyAidlInterface中已经被定义,只需要实现自定义的send方法

    package com.example.appbinder;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.util.Log;
    
    public class MyService extends Service {
    
        private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
            @Override
            public ResponseData send(RequestData data) throws RemoteException {
                Log.i("service","[RemoteService] receive  "+ data.toString());
                return new ResponseData("i'm service message");
            }
        };
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    MainActivity.java

    启动service

    package com.example.appbinder;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.ComponentName;
    import android.content.Intent;
    import android.os.Bundle;
    
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Intent in = new Intent();
            in.setComponent(new ComponentName("com.example.appbinder", "com.example.appbinder.MyService"));
            //启动service
            startService(in);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    清单文件

    注册service

    <service
        android:name=".MyService"
        android:exported="true">
        <intent-filter>
            <action android:name="com.example.appbinder.service" />
            <category android:name="android.intent.category.DEFAULT" />
        intent-filter>
    service>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    client端

    目录结构

    aidl文件夹与server端一致,里面包含RequestData.aidl、ResponseData.aidl、IMyAidlInterface.aidl三个文件

    java文件夹下com.example.appbinder文件夹中,包含RequestData.java、ResponseData.java两个文件

    注意上面的文件与server端的完全相同,且包名也一致

    在这里插入图片描述

    aidl文件编译

    同样需要配置app的build.gradle

    同样对IMyAidlInterface.aidl进行编译得到IMyAidlInterface.java文件

    MainActivity中bindservice

    实现bindservice,同时定义一个按钮,实现send发送消息和回显消息

    package com.example.appbinderclient;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.widget.TextView;
    
    import com.example.appbinder.IMyAidlInterface;
    import com.example.appbinder.RequestData;
    import com.example.appbinder.ResponseData;
    
    public class MainActivity extends AppCompatActivity {
    
        private IMyAidlInterface mAidlInterface;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    		
            // bind上服务端的service
            Intent in = new Intent();
            in.setComponent(new ComponentName("com.example.appbinder", "com.example.appbinder.MyService"));
            bindService(in, connD, Context.BIND_AUTO_CREATE);
        }
    
        private ServiceConnection connD = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                mAidlInterface = null;
            }
        };
    
        // 发送消息和回显消息
        public void send(android.view.View v) {
            try {
                ResponseData data = mAidlInterface.send(new RequestData("hello i'm client"));
                TextView textView = findViewById(R.id.textview);
                textView.setText(data.toString());
            } catch (Exception e) {
    
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    实现效果

    先打开server端:

    在这里插入图片描述

    然后打开客户端:

    在这里插入图片描述

    点击客户端的send按钮,客户端收到信息:

    在这里插入图片描述

    同时server端后台日志也说明收到了client端信息:

    在这里插入图片描述

    AIDL源码分析

    查看生成的IMyAidlInterface.java文件

    在这里插入图片描述

    IMyAidlInterface实现了android的IInterface接口:

    • Stub类继承了Binder类,为服务端

      • 构造器Stub(),创建stub并附加到接口上

      • asInterface(Ibinder obj),提供给客户端调用

        输入obj可以是Binder也可以是BinderProxy,客户端可以通过调用bindService bind to RemoteService,服务端自己也可以bind to RemoteService,两种情况下都会在onServiceConnected得到一个IBinder,但是如果是客户端IBinder类型为BinderProxy,如果是服务端类型为Binder。

        public static com.example.appbinder.IMyAidlInterface asInterface(android.os.IBinder obj)
        {
          if ((obj==null)) {
            return null;
          }
          // DESCRIPTOR就是com.example.appbinder.IMyAidlInterface
          android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
          if (((iin!=null)&&(iin instanceof com.example.appbinder.IMyAidlInterface))) {
            return ((com.example.appbinder.IMyAidlInterface)iin);
          }
          return new com.example.appbinder.IMyAidlInterface.Stub.Proxy(obj);
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
      • onTransact是核心,Client调用aidl接口后,最终onTransact会接收到消息,并调用我们自己定义的方法

        @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_send:
            {
              data.enforceInterface(descriptor);
              com.example.appbinder.RequestData _arg0;
              if ((0!=data.readInt())) {
                _arg0 = com.example.appbinder.RequestData.CREATOR.createFromParcel(data);
              }
              else {
                _arg0 = null;
              }
              // 调用我们定义的方法
              com.example.appbinder.ResponseData _result = this.send(_arg0);
              reply.writeNoException();
              if ((_result!=null)) {
                reply.writeInt(1);
                _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
              }
              else {
                reply.writeInt(0);
              }
              return true;
            }
            default:
            {
              return super.onTransact(code, data, reply, flags);
            }
          }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
      • Proxy类为客户端

        private static class Proxy implements com.example.appbinder.IMyAidlInterface
        {
          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 com.example.appbinder.ResponseData send(com.example.appbinder.RequestData request) throws android.os.RemoteException
          {
            // 序列化参数
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            com.example.appbinder.ResponseData _result;
            try {
              _data.writeInterfaceToken(DESCRIPTOR);
              if ((request!=null)) {
                _data.writeInt(1);
                request.writeToParcel(_data, 0);
              }
              else {
                _data.writeInt(0);
              }
              // 发送消息,调用Binder的onTransact方法
              boolean _status = mRemote.transact(Stub.TRANSACTION_send, _data, _reply, 0);
              if (!_status && getDefaultImpl() != null) {
                return getDefaultImpl().send(request);
              }
              _reply.readException();
              if ((0!=_reply.readInt())) {
                //读取返回结果
                _result = com.example.appbinder.ResponseData.CREATOR.createFromParcel(_reply);
              }
              else {
                _result = null;
              }
            }
            finally {
              _reply.recycle();
              _data.recycle();
            }
            return _result;
          }
          public static com.example.appbinder.IMyAidlInterface sDefaultImpl;
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23
        • 24
        • 25
        • 26
        • 27
        • 28
        • 29
        • 30
        • 31
        • 32
        • 33
        • 34
        • 35
        • 36
        • 37
        • 38
        • 39
        • 40
        • 41
        • 42
        • 43
        • 44
        • 45
        • 46
        • 47
        • 48
        • 49
        • 50
        • 51
        • 52
        • 53
        • 54
        • 55
        • 56
    • send方法是IMyAidlInterface中自己定义的函数

      public com.example.appbinder.ResponseData send(com.example.appbinder.RequestData request) throws android.os.RemoteException;
      
      • 1
  • 相关阅读:
    IMX6ULL学习笔记(9)——通过SD卡启动Linux内核
    手动实现第一个Servlet程序
    PAT 1014 福尔摩斯的约会
    【算法题】合法分组的最少组数
    机器学习:基于梯度下降算法的逻辑回归实现和原理解析
    【多线程】优雅使用线程池结合CompletableFuture实现异步编排
    C++设计模式之模板方法模式
    责任链模式
    多进程与多线程 - 概述
    数组——螺旋矩阵II
  • 原文地址:https://blog.csdn.net/LJFYYJ/article/details/126139804