Android Binder 简单理解

来源:互联网 发布:libcurl windows 编辑:程序博客网 时间:2024/05/03 22:05

近期想找个实习,在看各个公司的面试题,看到一道题目是要说说binder的通信机制和底层实现,平时对binder的了解仅限于ALDL调用时使用过,其他地方并没有使用过,看过Android内核剖析,对它只有初步的了解,为了防止以后忘记,先将 初步的了解记录下来,等待以后扩展。。

关于Binder  它是用来实现Android系统的进程间通信的,Android是基于Linux系统的,而linux系统已经提供了消息队列,共享内存和信号量以及socket(这个还不太了解)这几种IPC方式,但是这几种方式都不太适用于资源有限的android系统,在传输性能方面,socket主要用于跨网络的进程间通信和主机上的进程间通信,传输效率低,并且开销大,消息队列和信号量采用存储转发的方式,也就是需要从发送者那拷贝一份到内存,然后从内存拷贝一份到接受者一方,需要进行2次拷贝,对于共享内存,虽然不需要拷贝 但是处理起来比较复杂,而且还有处于安全考虑,因此Android系统开发者就自己定义了一套Ipc机制,也就是Binder 机制 。

下面我就先来简单写下我自己理解的Binder机制  

Binder架构包括服务端(server),binder驱动,客户端(client) ,server和client处于android的用户层,而binder驱动处于内核层,

服务端binder就是一个binder对象,每创建一个binder服务端都会开启一个线程,这个线程会不断接收来自binder驱动发送来的消息,收到消息后会执行相关的服务端代码(比如要求播放音乐,就会调用内核中播放音乐的系统代码)。

Binder驱动,在一个binder服务端被创建之后,驱动Binder就会相应的在其中创建一个mRemote对象,这个对象也是binder对象,然后客户端就可以借助这个mRemote来访问服务端相关服务了。。。

客户端Binder也是一个binder对象 客户端想要访问一个服务端的服务,就必须获取服务端放在binder驱动中的mRemote引用,因为客户端和服务端无法直接通信,只能通过binder驱动来相互访问。只要获取到了mRemote引用,客户端就可以访问服务端的服务了。

接下来还存在一个问题,怎样获取binder驱动中 mRemote中的引用呢?书上说Service类 启动成功时会远程调用ActivityThread类中的ApplicationThread对象,调用的参数中会有binder对象  然后回调  接口 即可实现客户端获取mRemote对象。。 但是个人还是不很理解,因为远程调用ActivityThread不还是binder机制里的东西吗  这个又是怎么获取的?   很不理解  希望有大神指点一二。。


public ComponentName startService(Intent intent); 
该函数用于启动intent指定的服务,而启动后,客户端暂时还没有服务端的Binder引用,因此,暂时还不能调用任何服务功能。

    @Override    public boolean bindService(Intent service, ServiceConnection conn, int flags) {        IServiceConnection sd;        if (mPackageInfo != null) {            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),                    mMainThread.getHandler(), flags);        }         // ......int res = ActivityManagerNative.getDefault().bindService(                mMainThread.getApplicationThread(), getActivityToken(),                service, service.resolveTypeIfNeeded(getContentResolver()),                sd, flags);    }

该函数用于绑定一个服务,这就是第一个重要问题的关键所在。其中第二个参数是一个interface类,该interface的定义如以下代码所示:

public interface ServiceConnection {  public void onServiceConnected(ComponentName name, IBinder service);  public void onServiceDisconnected(ComponentName name);}

此interface中的onServiceConnected()方法的第二个变量Service。当客户端请求AmS启动某个Service后, 该Service如果正常启动,那么AmS就会远程调用ActivityThread类中的ApplicationThread对象,调用的参数中会包含Service的Binder引用,然后在ApplicationThread中会回调bindService中的conn接口。因此,在客户端中,可以在onServiceConnected()方法中将其参数Service保存为一个全局变量,从而在客户端的任何地方都可以随时调用该远程服务。这就解决了第一个重要问题,即客户端如何获取远程服务的Binder引用。



下面查看源码 

public final void scheduleBindService(IBinder token, Intent intent, boolean rebind) {            BindServiceData s = new BindServiceData();            s.token = token;            s.intent = intent;            s.rebind = rebind;            queueOrSendMessage(H.BIND_SERVICE, s);        }    // if the thread hasn't started yet, we don't have the handler, so just    // save the messages until we're ready.    private final void queueOrSendMessage(int what, Object obj) {        queueOrSendMessage(what, obj, 0, 0);    }    private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {        synchronized (this) {            // ...            Message msg = Message.obtain();            msg.what = what;            msg.obj = obj;            msg.arg1 = arg1;            msg.arg2 = arg2;            mH.sendMessage(msg);         }    }
上面是网上找的别人写的  希望以后可以理解  先放着   http://www.tuicool.com/articles/FRNFFj

上面问题暂且放下  接着说!!

客户端调用服务端功能的个人理解流程:

首先客户端会获取到mRemote对象的引用(假设以Service为例) 通过bindService 实现接口回调接口 获得mRemote的引用  然后可以调用mRemote的transact方法  这个方法有四个参数  transact(int code,parcle data, parcle reply,int flags);   第一个参数是与服务端规定好的一组标识,标识着该调用服务端的哪部分代码,第二个参数是要发送给服务端的数据信息,第三个参数是服务端返回的数据信息,第四个参数是模式,0表示双向。 这样就会发送给服务端要调用的代码并且获得回复。调用该方法后,客户端线程进入Binder驱动,Binder驱动就会挂起当前线程,并向远程服务发送一个消息,消息中包含了客户端传进来的包裹。服务端拿到包裹后,会对包裹进行拆解,然后执行指定的服务函数,执行完毕后,再把执行结果放入客户端提供的reply包裹中。然后服务端向Binder驱动发送一个notify的消息,从而使得客户端线程从Binder驱动代码区返回到客户端代码区。

其中transact方法有这几个过程:

  • 以线程间消息通信的模式,向服务端发送客户端传递过来的参数。
  •  挂起当前线程,当前线程正是客户端线程,并等待服务端线程执行完指定服务函数后通知(notify)。
  •  接收到服务端线程的通知,然后继续执行客户端线程,并返回到客户端代码区。






0 0
原创粉丝点击