binder 双向通信时客户端没有joinThreadPool也能接收到服务端的请求

服务端之所以能够接收到客户端的请求,并能正确调用服务端进程中对应服务的onTransact方法,是因为服务端会通过joinThreadPool或者startThreadPool,在里面循环的等待客户端的请求并在接收到请求之后做对应的处理。
但是今天我在用C++写binder双向通信的代码时,发现,我客户端并没有调用joinThreadPool或者startThreadPool,也能接收到服务端的请求,而且能正确的调用对应的方法,这是为什么呢?理论上我客户端都没有在循环的等待服务端的数据并做处理,那这个是怎么调用到的呢?
我的代码实现是这样写的:
客户端:

service->registerCallBack(new BnCallBack());//1,先向服务端注册一个callback,即通过writeStrongBinder写入一个BBbinder对象	
service->say_hello();//2,远程调用服务端的方法

//3,如果接收到回调消息,则进行处理
status_t BnCallBack::onTransact(
    	uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
		{
		int ret;
		int32_t strict_policy = data.readInt32();
    	switch (code) {

        	case SUCESS_CMD: {
				int32_t code = data.readInt32();
            	onSucess(code);
            	return NO_ERROR;

服务端:

void BnHelloService::say_hello(void){
	int cnt = callback->onError();//回调客户端
	ALOGD("call say_hello : %d\n",cnt);
}

为了搞清楚客户端是如何调用到对应的方法,打印了一下调用栈

 onSucess:: #00 pc 00003635  /system/bin/test_client
04-26 10:18:46.968 10131 10131 D onSucess:: #01 pc 000035d1  /system/bin/test_client
04-26 10:18:46.968 10131 10131 D onSucess:: #02 pc 000359df  /system/lib/libbinder.so (_ZN7android7BBinder8transactEjRKNS_6ParcelEPS1_j+70)
04-26 10:18:46.968 10131 10131 D onSucess:: #03 pc 0003d16d  /system/lib/libbinder.so (_ZN7android14IPCThreadState14executeCommandEi+684)
04-26 10:18:46.968 10131 10131 D onSucess:: #04 pc 0003d635  /system/lib/libbinder.so (_ZN7android14IPCThreadState15waitForResponseEPNS_6ParcelEPi+224)
04-26 10:18:46.968 10131 10131 D onSucess:: #05 pc 00036589  /system/lib/libbinder.so (_ZN7android8BpBinder8transactEjRKNS_6ParcelEPS1_j+36)
04-26 10:18:46.968 10131 10131 D onSucess:: #06 pc 0000331f  /system/bin/test_client
04-26 10:18:46.968 10131 10131 D onSucess:: #07 pc 00002ded  /system/bin/test_client
04-26 10:18:46.968 10131 10131 D onSucess:: #08 pc 00016c61  /system/lib/libc.so (__libc_init+48)

可以看出是在BpBinder的transact方法中开始调用的,在transact方法中又调用waitForResponse方法。
原来在客户端远程调用say_hello方法后,就会通过waitForResponse等待服务端返回数据,而刚好,我回调的方法又是写在say_hello方法中,这就导致服务端在该方法内发出BC_TRANSACTION,那在客户端就会收到BR_TRANSACTION,进而正确的调用到对应的方法。

总结
如果服务端是在客户端的远程调用方法内又回调给客户端,这时候还是由客户端主动发起请求,是不需要添加循环等待服务端的数据的。如果是在其它的地方,服务端需要主动的发送消息给客户端,这时候,客户端依旧需要通过joinThreadPool或者startThreadPool来处理服务端的请求。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Binder 中,服务端可以通过 IBinder 类中的 transact() 方法向客户端发送消息。下面是一个简单的示例代码,演示了如何在服务端中向客户端发送消息: 1.服务端代码 ```java public class MyService extends Service { private MyBinder mBinder = new MyBinder(); public class MyBinder extends Binder { public void sendMessage(String message) { Parcel data = Parcel.obtain(); data.writeString(message); // 获取客户端的 IBinder IBinder clientBinder = getApplicationContext() .getServiceManager() .getService("com.example.client"); try { clientBinder.transact(0, data, null, IBinder.FLAG_ONEWAY); } catch (RemoteException e) { e.printStackTrace(); } finally { data.recycle(); } } } @Override public IBinder onBind(Intent intent) { return mBinder; } } ``` 在服务端代码中,我们定义了一个 MyBinder 对象,并实现了 sendMessage() 方法。在 sendMessage() 方法中,我们创建了一个 Parcel 对象,将消息写入 Parcel 中,然后获取客户端的 IBinder 对象,并通过 transact() 方法向客户端发送消息。 2.客户端代码 ```java public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String message = intent.getStringExtra("message"); Toast.makeText(context, message, Toast.LENGTH_SHORT).show(); } } ``` 在客户端代码中,我们定义了一个 BroadcastReceiver 对象,用于接收服务端发送的消息。在 onReceive() 方法中,我们获取到消息,并使用 Toast 将其显示出来。 需要注意的是,服务端在通过 transact() 方法向客户端发送消息,需要获取客户端的 IBinder 对象。在上面的示例代码中,我们使用了 getApplicationContext().getServiceManager().getService("com.example.client") 来获取客户端的 IBinder 对象,其中 "com.example.client" 是客户端的包名。如果客户端没有在系统服务中注册,服务端将无法获取客户端的 IBinder 对象,从而无法向客户端发送消息。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值