美文网首页android技术
binder机制 源码解读

binder机制 源码解读

作者: remax1 | 来源:发表于2020-06-02 15:42 被阅读0次

前言

进程是操作系统分配资源的最小单位,进程的主要结构是PCB(Progress Control Block),其中就包括进程名,物理地址等。各个进程互不影响,因为有进程隔离技术。正是因为进程隔离技术,所以不同进程的资源并不共享,当A进程想去操作B进程的方法时,就需要通过进程间通信技术,也就是IPC技术来完成调用。

图片.png
图片来源出自:https://zhuanlan.zhihu.com/p/35519585

Binder与传统IPC对比

共享内存:无需拷贝,但是需要借助到Memory Map来完成用户空间 和内核空间的映射,这就涉及到同步的问题且不安全。

Socket:需拷贝两次,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,传入效率低,开销大且不安全

Binder:只需拷贝一次,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,借助Memory Map完成接收方和内核空间的映射,而且Binder机制需要为每个APP分配UID,在通信时需要鉴别身份。

图片.png
图片来源出自:https://zhuanlan.zhihu.com/p/35519585

流程分析

在这借助Aidl来分析整个流程。

private void bindService() {
        Intent intent = new Intent();
        //开启服务端,也就是另一个进程的服务
        intent.setComponent(new ComponentName("com.lxxl.binder_service", "com.lxxl.binder_service.AidlService"));
        bindService(intent, connection, Context.BIND_AUTO_CREATE);
    }

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: success");
            iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: success");
            iMyAidlInterface = null;
        }
    };

熟悉Aidl的知道,这个ServiceConnection 就是在启动服务需要传递的参数。重点是asInterface这个方法做了啥

 public static com.lxxl.binder_service.IMyAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.lxxl.binder_service.IMyAidlInterface))) {
        return ((com.lxxl.binder_service.IMyAidlInterface)iin);
      }
      //返回了一个Proxy对象
      return new com.lxxl.binder_service.IMyAidlInterface.Stub.Proxy(obj);
    }

首先,给我们返回了一个Proxy对象,这个对象用来干啥的??我们接着往下看这个Proxy类。

 private static class Proxy implements com.lxxl.binder_service.IMyAidlInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
``````省略

//这个方法就是在声明Aidl时自定义的方法。
@Override 
public void addPerson(com.lxxl.binder_service.Person person) throws android.os.RemoteException
      {
      //这就是要需要通过binder传递的数据
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((person!=null)) {
            _data.writeInt(1);
            person.writeToParcel(_data, 0);
          }
          else {
            _data.writeInt(0);
          }
          //注释①
          boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addPerson(person);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }

注释①:在调用一个方法时,要知道方法名和形参列表,形参列表通过_data来传递,方法名则需要传递String,不过由于服务端和客户端的AIDL文件一致,我只需要传递一个整形值,就知道是第几个方法了,效率更高。

在调用完注释①后,会调用Binder的onTransact()方法来完成数据的发送。

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
     case TRANSACTION_addPerson://整型值,代表第几个方法。
        {
          data.enforceInterface(descriptor);
          com.lxxl.binder_service.Person _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.lxxl.binder_service.Person.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addPerson(_arg0);
          reply.writeNoException();
          return true;
        }
}

至此,数据已经到用户空间到内核空间了,服务端怎么接收数据呢?

public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        Log.e("AidlService", "success onBind");
        return iBinder;
    }

    private IBinder iBinder = new IMyAidlInterface.Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
          //来自客户端的数据
            persons.add(person);
        }

        @Override
        public List<Person> getPersonList() throws RemoteException {
            return persons;
        }
    };

通过Stub.onTransact()来完成。

总结

建议还是不借助Aidl的情况下手写一遍加强对binder机制的理解。

相关文章

网友评论

    本文标题:binder机制 源码解读

    本文链接:https://www.haomeiwen.com/subject/eviyzhtx.html