Binder 机制解析

1.Binder 是什么?

Binder 是一个工作在Linux层面的驱动,这一段驱动运行在内核态。Binder也是一种进程间通信机制。

2.为什么要多进程?

  • Android 系统分配给每个进程的资源空间是有限的,当项目需要申请的资源过于庞大时,比如微信,qq,今日头条就需要多进程。
  • 为了解决某些问题,比如WebView使用过程中,会存在内存泄漏,就可以将WebView放在另外一个进程中,就不会影响主进程。

3.进程间通信为什么要用到Binder机制?

由于进程是系统分配资源的基本单位,Android系统将每个进程空间隔离开,进程与进程之间是不能直接交换数据的,但每个进程可以与内核空间直接交互,所以可以借助在内核空间的Binder机制实现进程与进程之间的数据交互。

在这里插入图片描述

  • Binder是将服务端、内核空间通过mmap同时映射到同一个物理空间,客户端只需要一次拷贝,将数据从客户端拷贝到这个物理空间,即可完成数据传输。
  • 共享内存是将客户端,服务端、内核空间通过mmap同时映射到同一个物理空间,就无须拷贝就可实现数据传输。共享内存使用比较复杂,因为物理内存与各端的需要进行同步。
  • Socket需要将客户端数据拷贝到内核空间,再将数据从内核空间拷贝到服务端,所以需要两次拷贝,传输效率比较低。

在这里插入图片描述

4.AIDL源码分析

客户端连接到服务端的服务后,在客户端可以通过BookManager.Stub.asInterface(service)拿到服务端AIDL在客户端的代理Proxy。(通信中的AIDL在服务端是Stub,在客户端是Proxy)

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
         manager = BookManager.Stub.asInterface(service);
         isConnected = true;
         Log.d(TAG,"  onServiceConnected");
}
 public static com.zzq.service.BookManager asInterface(android.os.IBinder obj){
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.zzq.service.BookManager))) {
        return ((com.zzq.service.BookManager)iin);
      }
      return new com.zzq.service.BookManager.Stub.Proxy(obj);//返回服务端AIDL在客户端的代理
    }

当客户端拿到BookManager的代理类调用getbooks()方法时,会调用以下函数

 boolean _status = mRemote.transact(Stub.TRANSACTION_getbooks, _data, _reply, 0);
  • mRemote是Binder
  • Stub.TRANSACTION_getbooks是一个int值,由于客户端和服务端的AIDL完全一样,所以Binder给每个方法都标记了int值,这个值可以告诉服务端服务端想调用哪个方法
  • _data是客户端传入参数数据
  • _reply是服务端返回数据
  • flags取值可以为0和1,0表示数据可以发送到服务端,服务端也可以返回数据,1表示数据可以由客户端发往服务端,但服务端不能返回。

当调用transact方法后,Binder会将数据传入到服务端,服务端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_getbooks:  //注释1  通过code得知客户端想调用这个方法
        {
          data.enforceInterface(descriptor);
          java.util.List<com.zzq.service.Book> _result = this.getbooks();//注释2
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
        case TRANSACTION_addBook:
        {
          data.enforceInterface(descriptor);
          com.zzq.service.Book _arg0;
          if ((0!=data.readInt())) {
            _arg0 = com.zzq.service.Book.CREATOR.createFromParcel(data);
          }
          else {
            _arg0 = null;
          }
          this.addBook(_arg0);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }

注释2出的getbooks()方法直接调用到了服务端实现的BookManager.Stub中的getbooks()方法,进而完成从客户端到服务端的调用流程

private BookManager.Stub stub = new BookManager.Stub() {
        @Override
        public List<Book> getbooks() throws RemoteException {
            return books;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            books.add(book);
        }
    };
客户端绑定服务端Service流程

客户端调用bindService(intent,connection, Context.BIND_AUTO_CREATE)后,会通过AIDL绑定ActivityManagerService。

如果服务端进程已经创建,则直接通过反射创建服务
如果服务端进程没有创建,则会创建进程,再创建服务

绑定服务实在ActivityThread中进行的,服务端每绑定一个服务,如果之前绑定过,就调用onBind,如果之前绑定过,就调用onRebind

private void handleBindService(BindServiceData data) {
        Service s = mServices.get(data.token);
        if (DEBUG_SERVICE)
            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
        if (s != null) {
            try {
                data.intent.setExtrasClassLoader(s.getClassLoader());
                data.intent.prepareToEnterProcess();
                try {
                    if (!data.rebind) {
                        IBinder binder = s.onBind(data.intent);//如果之前没有绑定过,就调用onBind,这里会返回binder ,这个binder是我们在自定义Service的onBind返回的服务端的存根stub。
                        ActivityManager.getService().publishService(
                                data.token, data.intent, binder);//在这里ActivityManagerService会将binder返回给客户端
                    } else {
                        s.onRebind(data.intent);//如果之前绑定过,就调用onRebind
                        ActivityManager.getService().serviceDoneExecuting(
                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                    }
                    ensureJitEnabled();
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            } catch (Exception e) {
                if (!mInstrumentation.onException(s, e)) {
                    throw new RuntimeException(
                            "Unable to bind to service " + s
                            + " with " + data.intent + ": " + e.toString(), e);
                }
            }
        }
    }

ActivityManager.getService().publishService(
data.token, data.intent, binder)最终会调到一下代码

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
        final long origId = Binder.clearCallingIdentity();
        try {
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
                    + " " + intent + ": " + service);
            if (r != null) {
                Intent.FilterComparison filter
                        = new Intent.FilterComparison(intent);
                IntentBindRecord b = r.bindings.get(filter);
                if (b != null && !b.received) {
                    b.binder = service;
                    b.requested = true;
                    b.received = true;
                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
                        for (int i=0; i<clist.size(); i++) {
                            ConnectionRecord c = clist.get(i);
                            if (!filter.equals(c.binding.intent.intent)) {
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Not publishing to: " + c);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
                                if (DEBUG_SERVICE) Slog.v(
                                        TAG_SERVICE, "Published intent: " + intent);
                                continue;
                            }
                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                            try {
                                c.conn.connected(r.name, service, false);//在这里会将服务端的Binder传给客户端的connected方法
                            } catch (Exception e) {
                                Slog.w(TAG, "Failure sending service " + r.name +
                                      " to connection " + c.conn.asBinder() +
                                      " (in " + c.binding.client.processName + ")", e);
                            }
                        }
                    }
                }

                serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

c.conn.connected(r.name, service, false);方法会将服务端的Binder传给客户端的connected方法,进而完成绑定。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值