05.Binder系统:第8课第4节_Binder系统_分层

该小节我们开始讲解Binder在Java中的实现机制,我们先来回顾一下binder系统的运行过程。

bingder系统回顾

在binder的应用程序中,他会涉及3个应用程序,如下图所示:
在这里插入图片描述
如上所示,这三个程序分别为server,service_manager,client。一般流程如下:

server:
	1.通过addservice(“heelo”,xxx),添加服务。
	2.驱动生成一个对应的binder_node节点,binder_node中存在两个成员,分别为ptr,cokie,对于每个服务,该值的设定都不一样,后续根据这两个值区分服务
	12.接收到client数据之后,读取,解析,处理,然后分局收到的ptr,cokie调用对应函数。
	
service_manager:
	3.驱动收到到添加服务之后会创建一个binder_ref,其中存在node与desc两个成员。node指向binder_node,desc=1表示这是第一个服务。
	4.应用程序会创建一个surinfo链表,其中每个节点存在成员name与handlr,如图这里为name=“hello”,handlr为驱动中的desc
	7.接收到client发送的hello,在surinfo链表中查找,可以获得对应的handle值。
	8.驱动根据handlr值,找到对应的binder_ref,创建一个client的binder_ref,回复给给client
	
client:
	5.通过getservice(“hello")获得服务。
	6.在驱动层hello会被发送给service_manager,
	9.驱动程序接收到service_manager回复的binder_ref,其中的binder_ref.node指向server中的服务,把binder_ref.desc返回给用户空间。
	10.应用程序获得desc,即一个handle。
	11.使用服务:首先构造数据,然后向handlr=1发送数据,驱动程序根据handlr=1找到binder_ref,根据binder_ref.proc找到server,然后发送数据给对应的server。
	

从上面可以看出,binder系统是非常的复杂的,所以会分成好几个层次,比如写应用程序的人,其只要写出应用程序就可以了,对于进程之间的通信,由binder驱动的系统工程师编写,现在我们讲解bander系统的分成。

Binder系统分层

其可以分为3个层次如下图:
在这里插入图片描述
binder系统可以分为服务层,RPC(远程调用),IPC(进程通信)3个层次。

第一层为服务层

我们打开之前边写的C++程序,test_client.cpp。可以看到:

int main(int argc, char **argv)
	sm->getService(String16("goodbye"));
	service->saygoodbye();

其并不关心内部是如何实现的,负责调用即可。函数的实现是在BnHelloService.cpp中。那么client怎么调用server中对应的函数呢?是通过第二层的RPC。

第二层为RPC(远程调用)

实现RPC的文件为BpGoodbyeService.cpp,其中实现了sayhello与sayhello_to两个函数。其主要是构造数据发送数据,打开BpGoodbyeService.cpp:

	void saygoodbye(void)
	{
		/* 构造/发送数据 */

        Parcel data, reply;
        data.writeInt32(0);

        remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE, data, &reply);
	}
	
	int saygoodbye_to(const char *name)
	{
		/* 构造/发送数据 */
        Parcel data, reply;

        data.writeInt32(0);
        data.writeString16(String16(name));

        remote()->transact(GOODBYE_SVR_CMD_SAYGOODBYE_TO, data, &reply);

		return reply.readInt32();
	}

其工作很简单,就是构造数据之后,通过remote()->transact函数发送数据。最终导致BnHelloService.cpp中对应的onTransact被调用,然后解析再区分调用的对应的函数。

第三层为IPC(进程通信)

其remote()->transact如何发送数据,BnHelloService如何接受数据,怎么调用到服务的onTransact函数?
我们知道remote()得到一个Bpbinder对象,我们进入Bpbinder.cpp找到transact函数:

status_t BpBinder::transact(
	status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply, flags);

我们在看看test_server.cpp:

int main(void)
	/* 循环体 */
	IPCThreadState::self()->joinThreadPool();

这个循环一直等待接受数据。

使用c++实现一个服务,除了IPC层不需要编写,其他的都需要我们编写。如果我们使用java编写,则只需要实现服务层即可。

java实现

打开我们之前编写的java程序,TestClient.java:

public static void main(String args[])
	IBinder binder = ServiceManager.getService("hello");
	IHelloService svr = IHelloService.Stub.asInterface(binder);
	svr.sayhello();

可以知道TestClient只需要获取服务,然后调用即可。
其具体实现为HelloService.java:

public class HelloService extends IHelloService.Stub {
    public void sayhello() throws android.os.RemoteException {
    public int sayhello_to(java.lang.String name) throws android.os.RemoteException {	

看起来我们似乎直接通过客户端调用服务端的函数。其实他们是用过RPC层实现的,其为IHelloService.java,该为自动生成文件。其中:

public interface IHelloService extends android.os.IInterface
    public static abstract class Stub extends android.os.Binder implements IHelloService
		public Stub()
android.os.RemoteException;
	    public static IHelloService asInterface(android.os.IBinder obj)
	    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
	    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
	    private static class Proxy implements IHelloService
	    	@Override public void sayhello() throws android.os.RemoteException
	    		 mRemote.transact(Stub.TRANSACTION_sayhello, _data, _reply, 0);
	    	@Override public int sayhello_to(java.lang.String name) throws android.os.RemoteException
	    		mRemote.transact(Stub.TRANSACTION_sayhello_to, _data, _reply, 0);
	public void sayhello() throws android.os.RemoteException;
    public int sayhello_to(java.lang.String name) throws 

其上发送数据是类Proxy,接收数据的函数是onTransact。onTransact中会分别去调用的具体函数。

猜你喜欢

转载自blog.csdn.net/weixin_43013761/article/details/89204845