Andorid BluetoothSocket的工作原理之六

问题点8:如何理解原生Android BT,在Framework层执行监听动作后但当被连接时二次执行“alloc_rfc_slot”的行为

---在之前的checking flow中我们了解到:

当Framework层执行listenUsingRfcommWithServiceRecord 实现监听动作时,

其在BlueDroid中触发btsock_listen --> btsock_rfc_listen--> alloc_rfc_slot并建立socketpair,

并把“slot->app_fd = fds[1];”返回给Java层用于数据监听;

但在实际中发现,如车机端通过listenUsingRfcommWithServiceRecord 注册SPP 监听后,SPP被连接时的flow是:

-->rfcomm_cback 被触发,Event ID 34: BTA_JV_RFCOMM_SRV_OPEN_EVT

-->API on_srv_rfc_connect,这个API就是当前问题讨论的重点;

on_srv_rfc_connect函数中进行多种处理,且当此函数返回时,其返回虽是“return srv_rs->id;”但其已经在第2步操作中变成了Slot B id;使得bta_jv_port_mgmt_sr_cback中的“p_pcb_new_listen->rfcomm_slot_id”变成了Slot Bid 值;

on_srv_rfc_connect函数内部:

        -->1步:先通过find_rfc_slot_by_id 找到之前的slot (简称为 Slot A);

        -->2步:使用create_srv_accept_rfc_slot 创建新的Slot (简称为 Slot B),此函数我们看到其把Slot A 作为入参传入;在函数内部可以看到Slot A参数赋值给了Slot B,但最难理解的是函数最后:Slot ABid值进行了交换(答案在后面)

Note:交换id,当使用find_rfc_slot_by_id时,原来的Slot A id 会改为返回Slot B;

同样,Slot B的id会返回Slot A;

 

        -->3:通过btsock_thread_add_fd 对Slot A 设置异常标志位,

使得sock_poll_thread中的 poll能检测到socket 关闭时触发的exception;

       -->4步:通过btsock_thread_add_fd 对Slot B 设置读取标志位,使得当Slot B socket有数据写入时,poll 函数能检测到;

        -->5步:使用函数send_app_connect_signal对Slot A的app_fd发出20Byte 数据(表示当前RFCOMM channel 连接上),但这里需留意的是最后一个参数(Slot B 的app_fd)我们对比发现当Socket 作为客户端主动连接时(on_cli_rfc_connect),最后一个参数是-1;

 

延伸问题点:为何要把Slot B app_fd值发送给Socket Server

以上截图可以看到,其使用“cmsghdr”存储Slot B 的app_fd值,连同连接上的20Byte 数据一起,使用API sendmsg 发送给了Slot A 的add_fd;

 在BluetoothSocket.java中,监听20Byte 连接数据的方法是waitSocketSignal

-->waitSocketSignal,中调用readall;

-->readall中可以看到read 方法但这里如之前问题描述过,不能直接理解为原来的InputStream  中的read方法

原因是其已经在“mSocketIS = mSocket.getInputStream();”中被重写,最终执行JNI API

readba_native (位置在android_net_LocalSocketImpl.cpp (frameworks\base\core\jni)) 

JNI层:socket_readba -->socket_read_all-->通过recvmsg 进行message接收;

-->当接收到20Byte数据后,执行“socket_process_cmsg 

通过FrameworkBluetoothSocket.java中的方法acceptSocket,或许我们可以理解

为何在监听连接上后二次执行“alloc_rfc_slot

以下截图,accept 方法内,当通过waitSocketSignal 阻塞获取到20Byte数据表明已经

连接上,此时会看到其继续执行方法acceptSocket,并且返回了一个新的socket 实例;

 

基于此我们可以理解为何二次“alloc_rfc_slot”并且在create_srv_accept_rfc_slot 内交换了

Id值;

原因(推断)Framework中的监听并非是一次监听一次有效,即“监听-->接受-->连接-->/

写-->断开-->重新执行监听API…,而应该是“一次监听,后续不需要再次监听就可以继续等

待被连接(在官方描述中,二次alloc_rfc_slot”用意并非是为

了“一次监听多次使用”,其建议“一次监听一次使用,虽然监听可以被多次使用”,当侦查到被连接后,官方建议关闭侦听Socket)”;所以在执行btsock_rfc_listen触发的第一次

alloc_rfc_slot”只是同于通知连接消息,当被连接上时,会在create_srv_accept_rfc_slot

进行第二次“alloc_rfc_slot”,此时得到Slot B 的app_fd才是当前RFCOMM Linked的操作

fd, 上层Framework在方法acceptSocket返回新的socket 操作实例,用于当前RFCOMM

Linked的读写;原来的Slot A 的app_fd继续同于监听被连接消息;

延伸问题点:为何在原生BT Framework中,在socketpair 返回的fd[1] (app_fd)时,其不直接返回fd 值,而是返回类ParcelFileDescriptor,且上层实际操作时的fd也已经不是fd[1] (app_fd)

---在原生BT的建立监听实现的“bindListen, 其对应执行的是JNI 函数“createSocketChannel

-->JNI 函数createSocketChannel中,在此函数中得到了btsock_listen返回的app_fd,但并不是直接返回fd值给上层,而是通过parcel 形式写入到了ParcelFileDescriptor 类中;

 

但此时并没有直接返回app_fd值,而是使用了智能指针unique_ptr 进行处理;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值