天天看点

android emulator虚拟设备分析第三篇之pipe上的qemud service一、概述二、guest os中使用qemud service的方法三、注册新的qemud service

本篇和第二篇是强相关的,需要结合第二篇一起看。

os中的qemud进行相关的,已废弃。

启动emulator时,有一个参数-prop <key>=<value>,用于向guest os中添加属性。

qemud_channel_send和qemud_channel_recv是qemu-pipe和qemud所通用的,直接对fd进行读写,先读写4个字节,为size,然后读取具体的内容。

所有的qemud service都使用pipe:qemud这个pipe service,是它的子服务。如何去实现这种子服务呢?

emulator里面有两中结构体QemudService, QemudClient分别表示子服务,以及子服务的client。

QemudPipe和之前说的pipe类似,每次打开/dev/qemu_pipe时,kernel和emulator中都会产生一个pipe,对应一个CHANNEL,在guest os第一次通过/dev/qemu_pipe发送数据时,会创建一个QemudPipe,也就是peer,作为pipe:qemud funcs中的opaque。

pipeConnector_sendBuffers函数代码片段:

代码为external/qemu/android/emulation/android_qemud.cpp,我在android源码中没有找到,在另一个模拟器的repo中找到了。注意代码中夹杂着一些guest os中qemud相关的东西,关键词serial,不需要看。

初始化代码如下,_qemudPipe_funcs就是第二篇中所说的svc->funcs,从第二次通信开始,qemu_pipe都使用这些funcs去读写。

_qemudPipe_init是建立连接后,初始化QemudPipe的代码。

QemudMultiplexer中只有两个链表有用。

先根据service name查找子服务QemudService,然后调用子服务的qemud_service_connect_client去创建QemudClient,然后去创建QemudPipe

_qemudPipe_sendBuffers是guest通过/dev/qemu_pipe写数据时,将被调用的函数,也就是QemudClient接收到数据的函数,注意不要把send/recv的概念搞错了。

代码就是把guest发送的buffers拼起来,然后调用QemudClient的接收函数qemud_client_recv去处理。

_qemudPipe_recvBuffers是guest想从/dev/qemu_pipe读取数据时被调用的。

QemudClient写数据时是写到自己的ProtocolSelector.Pipe.messages中的,在这个函数中把QemudClient中的ProtocolSelector.Pipe.messages倒腾到buffers中。

_qemudPipe_poll,PIPE_POLL_OUT总是有效,PIPE_POLL_IN需要看QemudClient的ProtocolSelector.Pipe.messages中是否有数据

_qemudPipe_wakeOn,发现ProtocolSelector.Pipe.messages中有数据时,会调用android_pipe_wake,把pipe添加到dev->signaled链表中。

代码是external/qemu/android/boot-properties.c,也是在模拟器repo中的

boot_property_init_service去注册一个QemudService,主要函数就一个boot_property_service_connect,用于创建新的QemudClient

boot_property_service_connect创建新的QemudClient,channel一般都是-1,表示是pipe方式,而不是serial方式(使用guest qemud进程)

qemud_client_new会绑定QemudClient的读写函数,读函数boot_property_client_recv(也就是qemud_client_recv)是在_qemudPipe_sendBuffers中调用的

循环执行qemud_client_send将数据(-prop指定的属性值的列表)写到QemudClient的ProtocolSelector.Pipe.messages中,当_qemudPipe_recvBuffers函数执行时,从QemudClient的ProtocolSelector.Pipe.messages中倒腾数据返回给guest

boot-properties服务的入口函数是boot_property_parse_option,emulator在解析-prop参数时,会调用这个函数。

获得name和value后,调用boot_property_add2(name, namelen, value, valuelen)去添加属性到属性列表(_boot_properties)中

boot_property_add2会检查服务是否已初始化,如果没有,将调用boot_property_init_service。如果属性名和值没有非法字符,将申请新的属性:prop = boot_property_alloc(name, namelen, value, valuelen)并添加到属性列表中

boot_property_init_service先检查是否已初始化,如果没有,将进行初始化

QemudService*  serv = qemud_service_register( SERVICE_NAME,

                                                       1, NULL,

                                                       boot_property_service_connect,

                                                       boot_property_save,

                                                       boot_property_load);

第二个参数是max_clients,最大客户数量

第三个参数是serv_opaque,将传递给注册的serv_connect函数的第一个参数

第四个参数是注册的serv_connect函数

第五、第六是保存和恢复属性链表的函数

继续阅读