本篇和第二篇是強相關的,需要結合第二篇一起看。
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函數
第五、第六是儲存和恢複屬性連結清單的函數