今天花了很長(zhǎng)時(shí)間,終于搞懂了Android SDK中的模擬器是如何處理來(lái)自Android系統(tǒng)的OpenGL數(shù)據(jù)流的,特此記錄,以防忘記。
本文是基于此時(shí)(2018年4月29日)最新的 emu-2.7-release 分支來(lái)寫(xiě)作的。
$ANDROID_ROOT = Android 源碼存放目錄
$QEMU = $ANDROID_ROOT/external/qemu
Guest 端
運(yùn)行在模擬器內(nèi)部的Android系統(tǒng)是通過(guò)模擬器中名為 /dev/goldfish_pipe 的管道設(shè)備(3.10之前的內(nèi)核中,此設(shè)備名為qemu_pipe)向宿主機(jī)傳遞GL數(shù)據(jù)流的。這部分可以參考 $QEMU/android/android-emugl/DESIGN 文檔中所描述的內(nèi)容。
本文主要分析 Host 端的處理過(guò)程。
Host 端
模擬器啟動(dòng)時(shí),調(diào)用了$QEMU/hw/misc/goldfish_pipe.c中的type_init:
static void goldfish_pipe_class_init(ObjectClass* klass, void* data) {
DeviceClass* dc = DEVICE_CLASS(klass);
dc->realize = goldfish_pipe_realize; // 真正初始化設(shè)備的過(guò)程
dc->desc = "goldfish pipe";
}
static const TypeInfo goldfish_pipe_info = {
.name = TYPE_GOLDFISH_PIPE, // "goldfish_pipe"
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(GoldfishPipeState),
.class_init = goldfish_pipe_class_init
};
static void goldfish_pipe_register(void) {
type_register_static(&goldfish_pipe_info);
}
// 注冊(cè)設(shè)備
type_init(goldfish_pipe_register);
然后來(lái)到同一個(gè)文件中的goldfish_pipe_realize函數(shù):
static void goldfish_pipe_realize(DeviceState* dev, Error** errp) {
SysBusDevice* sbdev = SYS_BUS_DEVICE(dev);
GoldfishPipeState* s = GOLDFISH_PIPE(dev);
s_goldfish_pipe_state = s;
s->dev = (PipeDevice*)g_malloc0(sizeof(PipeDevice));
s->dev->ps = s; /* HACK: backlink */
s->dev->ops = &pipe_ops_v2; // 注冊(cè) Guest 對(duì)管道設(shè)備的讀寫(xiě)操作處理函數(shù)
s->dev->device_version = PIPE_DEVICE_VERSION;
s->dev->driver_version = PIPE_DRIVER_VERSION_v1;
s->dev->pipes_capacity = 64;
s->dev->pipes = calloc(s->dev->pipes_capacity, sizeof(*s->dev->pipes));
if (!s->dev->pipes) {
APANIC("%s: failed to initialize pipes array\n", __func__);
}
s->dev->pipes_by_channel = g_hash_table_new_full(
hash_channel, hash_channel_equal, hash_channel_destroy, NULL);
if (!s->dev->pipes_by_channel) {
APANIC("%s: failed to initialize pipes hash\n", __func__);
}
memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_pipe_iomem_ops, s,
"goldfish_pipe", 0x2000 /*TODO: ?how big?*/);
sysbus_init_mmio(sbdev, &s->iomem);
sysbus_init_irq(sbdev, &s->irq);
// 注冊(cè)模擬器保存/加載狀態(tài)時(shí)的處理函數(shù)
register_savevm_with_post_load(
dev, "goldfish_pipe", 0, GOLDFISH_PIPE_SAVE_VERSION,
goldfish_pipe_save, goldfish_pipe_load, goldfish_pipe_post_load, s);
}
......
static const PipeOperations pipe_ops_v2 = {
.wanted_list_add = &wanted_pipes_add_v2,
.close_all = &close_all_pipes_v2,
.save = &goldfish_pipe_save_v2,
.dev_read = &pipe_dev_read_v2, // Guest 讀取該設(shè)備時(shí)的處理函數(shù)
.dev_write = &pipe_dev_write_v2 // Guest 寫(xiě)入該設(shè)備時(shí)的處理函數(shù)
};
此時(shí),管道設(shè)備已經(jīng)被注冊(cè)到 qemu 中。接下來(lái)我們主要關(guān)注 Guest 寫(xiě)入該設(shè)備時(shí)的處理函數(shù)pipe_dev_write_v2(也位于 goldfish_pipe.c 中):
static void pipe_dev_write_v2(PipeDevice* dev,
hwaddr offset,
uint64_t value) {
switch (offset) {
......
case PIPE_REG_CMD: {
unsigned id = value;
if (id < dev->pipes_capacity && dev->pipes[id]) {
// 處理來(lái)自 Guest 的命令
pipeDevice_doCommand_v2(dev->pipes[id]);
} else {
pipeDevice_doOpenClose_v2(dev, id);
}
break;
}
default:
qemu_log_mask(LOG_GUEST_ERROR,
"%s: unknown register offset = 0x%" HWADDR_PRIx
" value=%" PRIu64 "/0x%" PRIx64 "\n",
__func__, offset, value, value);
break;
}
}
很明顯,重點(diǎn)是對(duì) pipeDevice_doCommand_v2 的調(diào)用。來(lái)看它的源碼(也位于 goldfish_pipe.c 中):
static void pipeDevice_doCommand_v2(HwPipe* pipe) {
......
switch (command) {
......
case PIPE_CMD_READ:
case PIPE_CMD_WRITE: {
const bool willModifyData = command == PIPE_CMD_READ;
pipe->command_buffer->rw_params.consumed_size = 0;
unsigned buffers_count =
pipe->command_buffer->rw_params.buffers_count;
if (buffers_count > pipe->rw_params_max_count) {
buffers_count = pipe->rw_params_max_count;
}
// This isn't supposed to happen, what's the puprose of calling
// us with no data?
assert(buffers_count);
// We know that the |rw_params| fit into single page as of now, so
// we're free to estimate the maximum size this way.
uint64_t* const rwPtrs = hwpipe_get_command_rw_ptrs(pipe);
uint32_t* const rwSizes = hwpipe_get_command_rw_sizes(pipe);
assert(buffers_count <=
COMMAND_BUFFER_SIZE / (sizeof(*rwPtrs) + sizeof(*rwSizes)));
// 定義數(shù)據(jù)緩沖區(qū)
GoldfishPipeBuffer buffers[
COMMAND_BUFFER_SIZE / (sizeof(*rwPtrs) + sizeof(*rwSizes))];
...... 跳過(guò)處理內(nèi)存邊界的代碼
pipe->command_buffer->status =
willModifyData
? service_ops->guest_recv(pipe->host_pipe,
buffers, // 數(shù)據(jù)在這里面
buffers_count) // Guest 接收數(shù)據(jù),即 Host 向 Guest 發(fā)送數(shù)據(jù)
: service_ops->guest_send(pipe->host_pipe,
buffers, // 數(shù)據(jù)在這里面
buffers_count); // Guest 發(fā)送數(shù)據(jù),即 Host 接收來(lái)自 Guest 的數(shù)據(jù)
......
break;
}
我們遇到了service_ops這個(gè)變量以及guest_recv、guest_send兩個(gè)函數(shù)。讓我們先來(lái)看看它們是怎么來(lái)的。
還是回到qemu初始化的時(shí)候,這次是 $QEMU/android-qemu2-glue/qemu-setup.cpp 中的 qemu_android_emulation_early_setup:
bool qemu_android_emulation_early_setup() {
......
// Initialize host pipe service.
if (!qemu_android_pipe_init(vmLock)) {
return false;
}
對(duì)于 qemu_android_pipe_init 的調(diào)用,該函數(shù)定義在 $QEMU/android-qemu2-glue/emulation/android_pipe_device.cpp中:
bool qemu_android_pipe_init(android::VmLock* vmLock) {
goldfish_pipe_set_service_ops(&goldfish_pipe_service_ops); // 注冊(cè)管道設(shè)備的各種操作
android_pipe_set_hw_funcs(&android_pipe_hw_funcs);
android::AndroidPipe::initThreading(vmLock);
return true;
}
goldfish_pipe_service_ops也定義在同一文件中:
// These callbacks are called from the virtual device into the pipe service.
static const GoldfishPipeServiceOps goldfish_pipe_service_ops = {
......
// guest_recv()
[](GoldfishHostPipe* hostPipe,
GoldfishPipeBuffer* buffers, // 數(shù)據(jù)在這里面
int numBuffers) -> int {
// NOTE: Assumes that AndroidPipeBuffer and GoldfishPipeBuffer
// have exactly the same layout.
static_assert(
sizeof(AndroidPipeBuffer) == sizeof(GoldfishPipeBuffer),
"Invalid PipeBuffer sizes");
static_assert(offsetof(AndroidPipeBuffer, data) ==
offsetof(GoldfishPipeBuffer, data),
"Invalid PipeBuffer::data offsets");
static_assert(offsetof(AndroidPipeBuffer, size) ==
offsetof(GoldfishPipeBuffer, size),
"Invalid PipeBuffer::size offsets");
return android_pipe_guest_recv(
hostPipe, reinterpret_cast<AndroidPipeBuffer*>(buffers),
numBuffers);
},
// guest_send()
[](GoldfishHostPipe* hostPipe,
const GoldfishPipeBuffer* buffers, // 數(shù)據(jù)在這里面
int numBuffers) -> int {
return android_pipe_guest_send(
hostPipe,
reinterpret_cast<const AndroidPipeBuffer*>(buffers),
numBuffers);
},
......
};
我們終于找到了guest_recv和guest_send的定義。
然后我們又回到了 $QEMU/hw/misc/goldfish_pipe.c 中:
static const GoldfishPipeServiceOps* service_ops = &s_null_service_ops;
void goldfish_pipe_set_service_ops(const GoldfishPipeServiceOps* ops) {
service_ops = ops ? ops : &s_null_service_ops;
}
此時(shí),我們得到了 service_ops 變量。
現(xiàn)在,我們?cè)賮?lái)關(guān)注guest_send函數(shù):
// These callbacks are called from the virtual device into the pipe service.
static const GoldfishPipeServiceOps goldfish_pipe_service_ops = {
......
// guest_send()
[](GoldfishHostPipe* hostPipe,
const GoldfishPipeBuffer* buffers, // 數(shù)據(jù)在這里面
int numBuffers) -> int {
return android_pipe_guest_send(
hostPipe,
reinterpret_cast<const AndroidPipeBuffer*>(buffers),
numBuffers);
},
這個(gè)函數(shù)直接調(diào)用了android_pipe_guest_send函數(shù)。此函數(shù)位于$QEMU/android/android-emu/android/emulation/AndroidPipe.cpp中:
int android_pipe_guest_send(void* internalPipe,
const AndroidPipeBuffer* buffers, // 數(shù)據(jù)在這里面
int numBuffers) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<AndroidPipe*>(internalPipe);
// 調(diào)用該管道的處理函數(shù)
return pipe->onGuestSend(buffers, numBuffers);
}
onGuestSend也定義在同一文件內(nèi):
// TECHNICAL NOTE: This function reads data from the guest until it
// finds a zero-terminated C-string. After that it parses it to find
// a registered service corresponding to one of the allowed formats
// (see below). In case of success, this creates a new AndroidPipe
// instance and calls AndroidPipeHwFuncs::resetPipe() to associate it with
// the current hardware-side |mHwPipe|, then *deletes* the current
// instance! In case of error (e.g. invalid service name, or error during
// initialization), PIPE_ERROR_INVAL will be returned, otherwise, the
// number of bytes accepted from the guest is returned.
virtual int onGuestSend(const AndroidPipeBuffer* buffers, // 數(shù)據(jù)在這里面
int numBuffers) override {
......
// Acceptable formats for the connection string are:
//
// pipe:<name>
// pipe:<name>:<arguments>
//
char* pipeName;
char* pipeArgs;
D("%s: connector: '%s'", __FUNCTION__, mBuffer);
if (memcmp(mBuffer, "pipe:", 5) != 0) {
// Nope, we don't handle these for now.
D("%s: Unknown pipe connection: '%s'", __FUNCTION__, mBuffer);
return PIPE_ERROR_INVAL;
}
pipeName = mBuffer + 5;
pipeArgs = strchr(pipeName, ':');
Service* svc = nullptr;
// As a special case, if the service name is as:
// qemud:<name>
// qemud:<name>:args
//
// First look for a registered pipe service named "qemud:<name>"
// and if not found, fallback to "qemud" only.
//
// This is useful to support qemud services that are now served
// by a dedicated (and faster) pipe service, e.g. 'qemud:adb'
// as currently implemented by QEMU2 (and soon by QEMU1).
static const char kQemudPrefix[] = "qemud:";
const size_t kQemudPrefixSize = sizeof(kQemudPrefix) - 1U;
if (!::strncmp(pipeName, kQemudPrefix, kQemudPrefixSize)) {
assert(pipeArgs == pipeName + kQemudPrefixSize - 1);
char* pipeArgs2 = strchr(pipeArgs + 1, ':');
if (pipeArgs2) {
*pipeArgs2 = '\0';
}
// 上面處理完了 Guest 想要調(diào)用的服務(wù)的名稱(chēng),現(xiàn)在開(kāi)始查找對(duì)應(yīng)的服務(wù)類(lèi)
svc = findServiceByName(pipeName);
if (svc) {
pipeArgs = pipeArgs2;
} else if (pipeArgs2) {
// Restore colon.
*pipeArgs2 = ':';
}
}
if (pipeArgs) {
*pipeArgs++ = '\0';
if (!pipeArgs) {
pipeArgs = NULL;
}
}
if (!svc) {
// 沒(méi)找到?再來(lái)一次
svc = findServiceByName(pipeName);
}
if (!svc) {
// 還是沒(méi)找到?算了,退出
D("%s: Unknown server with name %s!", __FUNCTION__, pipeName);
return PIPE_ERROR_INVAL;
}
// 從該服務(wù)創(chuàng)建新的管道類(lèi),該管道類(lèi)是 AndroidPipe 的子類(lèi)
AndroidPipe* newPipe = svc->create(mHwPipe, pipeArgs);
if (!newPipe) {
D("%s: Initialization failed for %s pipe!", __FUNCTION__, pipeName);
return PIPE_ERROR_INVAL;
}
// Swap your host-side pipe instance with this one weird trick!
D("%s: starting new pipe %p (swapping %p) for service %s",
__FUNCTION__,
newPipe,
mHwPipe,
pipeName);
// 把 mHwPipe 中關(guān)聯(lián)的 AndroidPipe 類(lèi)用新創(chuàng)建的子類(lèi)替換掉
sPipeHwFuncs->resetPipe(mHwPipe, newPipe);
// 自殺
delete this;
return result;
}
到這里好像沒(méi)有對(duì)數(shù)據(jù)進(jìn)行任何處理?那讓我們來(lái)看看findServiceByName這個(gè)函數(shù)(定義在同一文件中):
android::base::LazyInstance<Globals> sGlobals = LAZY_INSTANCE_INIT;
Service* findServiceByName(const char* name) {
const int pos = sGlobals->findServicePositionByName(name);
return pos < 0 ? nullptr : sGlobals->services[pos].get();
}
又是一個(gè)全局變量sGlobals,它用于維護(hù)所有注冊(cè)了的服務(wù)列表。那么服務(wù)們又是在哪里注冊(cè)的呢?我們?cè)谕粋€(gè)文件中找到了add函數(shù):
// static
void AndroidPipe::Service::add(Service* service) {
DD("Adding new pipe service '%s' this=%p", service->name().c_str(),
service);
std::unique_ptr<Service> svc(service);
sGlobals->services.push_back(std::move(svc));
}
在源碼中查找AndroidPipe的所有子類(lèi),在$QEMU/android/android-emu/android/opengl/OpenglEsPipe.cpp中,我們發(fā)現(xiàn)了EmuglPipe這個(gè)類(lèi):
class EmuglPipe : public AndroidPipe {
public:
//////////////////////////////////////////////////////////////////////////
// The pipe service class for this implementation.
class Service : public AndroidPipe::Service {
public:
// 我是叫做 opengles 的服務(wù)
Service() : AndroidPipe::Service("opengles") {}
// Create a new EmuglPipe instance.
AndroidPipe* create(void* hwPipe, const char* args) override {
return createPipe(hwPipe, this, args);
}
bool canLoad() const override { return true; }
以及該文件的末尾:
void registerPipeService() {
// 注冊(cè) opengles 服務(wù)
android::AndroidPipe::Service::add(new EmuglPipe::Service());
registerGLProcessPipeService();
}
} // namespace opengl
} // namespace android
// Declared in android/opengles-pipe.h
void android_init_opengles_pipe() {
android::opengl::registerPipeService();
}
于是,我們的目光轉(zhuǎn)向了EmuglPipe這個(gè)類(lèi):
virtual int onGuestSend(const AndroidPipeBuffer* buffers, // 數(shù)據(jù)在這里面
int numBuffers) override {
......
// Copy everything into a single ChannelBuffer.
ChannelBuffer outBuffer;
outBuffer.resize_noinit(count);
auto ptr = outBuffer.data();
for (int n = 0; n < numBuffers; ++n) {
memcpy(ptr, buffers[n].data, buffers[n].size);
ptr += buffers[n].size;
}
D("%s: sending %d bytes to host", __func__, count);
// Send it through the channel.
auto result = mChannel->tryWrite(std::move(outBuffer)); // 記住這個(gè) mChannel
if (result != IoResult::Ok) {
D("%s: tryWrite() failed with %d", __func__, (int)result);
return result == IoResult::Error ? PIPE_ERROR_IO : PIPE_ERROR_AGAIN;
}
return count;
}
重點(diǎn)看來(lái)是mChannel->tryWrite這個(gè)調(diào)用。該方法定義于$QEMU/android/android-emugl/host/libs/libOpenglRender/RenderChannelImpl.cpp:
IoResult RenderChannelImpl::tryWrite(Buffer&& buffer /* 數(shù)據(jù)在這里面 */) {
D("buffer size=%d", (int)buffer.size());
AutoLock lock(mLock);
// 記住此處,數(shù)據(jù)被放到了 RenderChannelImpl::mFromGuest 里面
auto result = mFromGuest.tryPushLocked(std::move(buffer));
updateStateLocked();
DD("mFromGuest.tryPushLocked() returned %d, state %d", (int)result,
(int)mState);
return result;
}
mFromGuest是一個(gè)BufferQueue<RenderChannel::Buffer>類(lèi)型的成員,用于存放來(lái)自于 Guest 的數(shù)據(jù)。那么,數(shù)據(jù)被放到這個(gè)成員里面之后,就結(jié)束了嗎?
當(dāng)然沒(méi)有。接下來(lái),我們要從另一個(gè)方向開(kāi)始:$QEMU/objs/lib64/lib64OpenglRender.so 。根據(jù)$QEMU/android/android-emugl/DESIGN 所述,這是獨(dú)立的渲染程序,負(fù)責(zé)接收 qemu 轉(zhuǎn)發(fā)的來(lái)自 Guest 的GL數(shù)據(jù)并渲染在屏幕上。
若未發(fā)現(xiàn)此文件,請(qǐng)執(zhí)行
$QEMU/android/configure.sh && make來(lái)編譯模擬器。
我們執(zhí)行readelf -Ws lib64OpenglRender.so:
......
201: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __fxstat64@GLIBC_2.2.5 (3)
202: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __lxstat64@GLIBC_2.2.5 (3)
203: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __xstat64@GLIBC_2.2.5 (3)
204: 000000000009b6b8 0 NOTYPE GLOBAL DEFAULT ABS _edata
205: 000000000009e528 0 NOTYPE GLOBAL DEFAULT ABS _end
206: 0000000000000000 0 OBJECT GLOBAL DEFAULT ABS VERSION
207: 000000000009b6b8 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
208: 0000000000026000 156 FUNC GLOBAL DEFAULT 11 initLibrary@@VERSION
注意最后一行導(dǎo)出的initLibrary函數(shù)。這也是該共享庫(kù)的唯一導(dǎo)出函數(shù)。
在源碼中查找initLibrary的調(diào)用,我們來(lái)到了$QEMU/android/android-emu/android/opengles.cpp中:
int android_initOpenglesEmulation() {
char* error = NULL;
if (sRenderLib != NULL)
return 0;
......
// 已經(jīng)加載了 lib64OpenglRender.so,調(diào)用其初始化函數(shù)
sRenderLib = initLibrary();
if (!sRenderLib) {
derror("OpenGLES initialization failed!");
goto BAD_EXIT;
}
跟進(jìn)initLibrary,我們來(lái)到了$QEMU/android/android-emugl/host/libs/libOpenglRender/render_api.cpp中:
RENDER_APICALL emugl::RenderLibPtr RENDER_APIENTRY initLibrary() {
......
return emugl::RenderLibPtr(new emugl::RenderLibImpl());
}
回到$QEMU/android/android-emu/android/opengles.cpp中,我們發(fā)現(xiàn)了緊接著android_initOpenglesEmulation函數(shù)的android_startOpenglesRenderer函數(shù):
int
android_startOpenglesRenderer(int width, int height, bool guestPhoneApi, int guestApiLevel,
int* glesMajorVersion_out,
int* glesMinorVersion_out)
{
if (!sRenderLib) {
D("Can't start OpenGLES renderer without support libraries");
return -1;
}
if (sRenderer) {
return 0;
}
android_init_opengl_logger();
sRenderLib->setRenderer(emuglConfig_get_current_renderer());
sRenderLib->setAvdInfo(guestPhoneApi, guestApiLevel);
sRenderLib->setCrashReporter(&crashhandler_die_format);
sRenderLib->setFeatureController(&android::featurecontrol::isEnabled);
sRenderLib->setSyncDevice(goldfish_sync_create_timeline,
goldfish_sync_create_fence,
goldfish_sync_timeline_inc,
goldfish_sync_destroy_timeline,
goldfish_sync_register_trigger_wait,
goldfish_sync_device_exists); // 這里面的東西似乎并沒(méi)有被任何地方使用
emugl_logger_struct logfuncs;
logfuncs.coarse = android_opengl_logger_write;
logfuncs.fine = android_opengl_cxt_logger_write;
sRenderLib->setLogger(logfuncs);
emugl_dma_ops dma_ops;
dma_ops.add_buffer = android_goldfish_dma_ops.add_buffer;
dma_ops.remove_buffer = android_goldfish_dma_ops.remove_buffer;
dma_ops.get_host_addr = android_goldfish_dma_ops.get_host_addr;
dma_ops.invalidate_host_mappings = android_goldfish_dma_ops.invalidate_host_mappings;
dma_ops.unlock = android_goldfish_dma_ops.unlock;
sRenderLib->setDmaOps(dma_ops); // 這里面的東西似乎并沒(méi)有被任何地方使用
// 初始化渲染器
sRenderer = sRenderLib->initRenderer(width, height, sRendererUsesSubWindow, sEgl2egl);
if (!sRenderer) {
D("Can't start OpenGLES renderer?");
return -1;
}
// after initRenderer is a success, the maximum GLES API is calculated depending
// on feature control and host GPU support. Set the obtained GLES version here.
if (glesMajorVersion_out && glesMinorVersion_out)
sRenderLib->getGlesVersion(glesMajorVersion_out, glesMinorVersion_out);
return 0;
}
繼續(xù)跟進(jìn)initRenderer方法,定義在$QEMU/android/android-emugl/host/libs/libOpenglRender/RenderLibImpl.cpp中:
RendererPtr RenderLibImpl::initRenderer(int width, int height,
bool useSubWindow, bool egl2egl) {
if (!mRenderer.expired()) {
return nullptr;
}
const auto res = std::make_shared<RendererImpl>();
if (!res->initialize(width, height, useSubWindow, egl2egl)) {
return nullptr;
}
mRenderer = res;
return res;
}
繼續(xù)跟進(jìn)RendererImpl::initialize方法,定義在$QEMU/android/android-emugl/host/libs/libOpenglRender/RendererImpl.cpp中:
bool RendererImpl::initialize(int width, int height, bool useSubWindow, bool egl2egl) {
......
// This render thread won't do anything but will only preload resources
// for the real threads to start faster.
mLoaderRenderThread.reset(new RenderThread(nullptr));
mLoaderRenderThread->start();
return true;
}
雖然這個(gè)地方看起來(lái)有個(gè)RenderThread,但此處并不是真正地啟動(dòng)了渲染線(xiàn)程。真正啟動(dòng)渲染的地方,還要回到$QEMU/android/android-emu/android/opengl/OpenglEsPipe.cpp中:
/////////////////////////////////////////////////////////////////////////
// Constructor, check that |mIsWorking| is true after this call to verify
// that everything went well.
EmuglPipe(void* hwPipe,
Service* service,
const emugl::RendererPtr& renderer,
android::base::Stream* loadStream = nullptr)
: AndroidPipe(hwPipe, service) {
bool isWorking = true;
// 此處和后面的 loadStream 都是 qemu 用于保存/恢復(fù)虛擬機(jī)狀態(tài)所用的
if (loadStream) {
DD("%s: loading GLES pipe state for hwpipe=%p", __func__, mHwPipe);
isWorking = (bool)loadStream->getBe32();
android::base::loadBuffer(loadStream, &mDataForReading);
mDataForReadingLeft = loadStream->getBe32();
}
// 創(chuàng)建 RenderChannelImpl 類(lèi)。記住這個(gè) mChannel
mChannel = renderer->createRenderChannel(loadStream);
if (!mChannel) {
D("Failed to create an OpenGLES pipe channel!");
return;
}
mIsWorking = isWorking;
mChannel->setEventCallback([this](RenderChannel::State events) {
onChannelHostEvent(events);
});
}
還記得前面的EmuglPipe::Service類(lèi)以及AndroidPipe::onGuestSend中的AndroidPipe* newPipe = svc->create(mHwPipe, pipeArgs);吧?讓我們來(lái)看看EmuglPipe::Service::create方法,定義在$QEMU/android/android-emu/android/opengl/OpenglEsPipe.cpp中:
// Create a new EmuglPipe instance.
AndroidPipe* create(void* hwPipe, const char* args) override {
return createPipe(hwPipe, this, args);
}
......
static AndroidPipe* createPipe(
void* hwPipe,
Service* service,
const char* args,
android::base::Stream* loadStream = nullptr) {
const auto& renderer = android_getOpenglesRenderer();
if (!renderer) {
// This should never happen, unless there is a bug in the
// emulator's initialization, or the system image, or we're
// loading from an incompatible snapshot.
D("Trying to open the OpenGLES pipe without GPU emulation!");
return nullptr;
}
// 構(gòu)造 EmuglPipe 類(lèi)
auto pipe = new EmuglPipe(hwPipe, service, renderer, loadStream);
if (!pipe->mIsWorking) {
delete pipe;
pipe = nullptr;
}
return pipe;
}
現(xiàn)在,我們終于找到了上面 EmuglPipe::EmuglPipe() 的調(diào)用來(lái)源。讓我們正式進(jìn)入RendererImpl::createRenderChannel方法:
RenderChannelPtr RendererImpl::createRenderChannel(
android::base::Stream* loadStream) {
const auto channel = std::make_shared<RenderChannelImpl>(loadStream);
{
......
}
return channel;
}
再進(jìn)入RenderChannelImpl::RenderChannelImpl(),定義在$QEMU/android/android-emugl/host/libs/libOpenglRender/RenderChannelImpl.cpp中:
RenderChannelImpl::RenderChannelImpl(android::base::Stream* loadStream)
: mFromGuest(kGuestToHostQueueCapacity, mLock),
mToGuest(kHostToGuestQueueCapacity, mLock) {
......
// 這里的 this 與之前的 EmuglPipe::mChannel 指向的是同一個(gè)實(shí)例
mRenderThread.reset(new RenderThread(this, loadStream));
mRenderThread->start();
}
這里我們終于真正地啟動(dòng)了渲染線(xiàn)程。
還記得之前EmuglPipe::onGuestSend方法中的auto result = mChannel->tryWrite(std::move(outBuffer));嗎?此處的mChannel就是由RendererImpl::createRenderChannel所返回的RenderChannelImpl的實(shí)例。同時(shí),這個(gè)實(shí)例也被傳入了新創(chuàng)建的RenderThread中。
最后,讓我們進(jìn)入RenderThread::main方法,定義在$QEMU/android/android-emugl/host/libs/libOpenglRender/RenderThread.cpp中:
intptr_t RenderThread::main() {
......
// 這里的 mChannel 就是之前傳入的`RenderChannelImpl`的實(shí)例,與`EmuglPipe::mChannel`指向同一個(gè)實(shí)例
ChannelStream stream(mChannel, RenderChannel::Buffer::kSmallSize);
ReadBuffer readBuf(kStreamBufferSize);
......
while (1) {
......
int stat = 0;
if (packetSize > (int)readBuf.validData()) {
// 從 RenderChannelImpl 中讀出之前在 `EmuglPipe::onGuestSend` 中寫(xiě)入的數(shù)據(jù)
stat = readBuf.getData(&stream, packetSize);
if (stat <= 0) {
if (doSnapshotOperation(snapshotObjects, SnapshotState::StartSaving)) {
continue;
} else {
D("Warning: render thread could not read data from stream");
break;
}
} else if (needRestoreFromSnapshot) {
......
}
}
DD("render thread read %d bytes, op %d, packet size %d",
(int)readBuf.validData(), *(int32_t*)readBuf.buf(),
*(int32_t*)(readBuf.buf() + 4));
......
// 下面是解碼來(lái)自 Guest 的GL數(shù)據(jù)的過(guò)程
bool progress;
do {
progress = false;
......
return 0;
}
讓我們?cè)賮?lái)看看readBuf.getData這個(gè)方法,定義在$QEMU/android/android-emugl/host/libs/libOpenglRender/ReadBuffer.cpp中:
int ReadBuffer::getData(IOStream* stream, int minSize) {
......
// get fresh data into the buffer;
int readTotal = 0;
do {
// 從 stream,也就是之前的 ChannelStream 中讀取數(shù)據(jù)
const size_t readNow = stream->read(m_readPtr + m_validData,
maxSizeToRead - readTotal);
......
} while (readTotal < minSizeToRead);
return readTotal;
}
ChannelStream類(lèi)實(shí)現(xiàn)了IOStream的read方法,定義在$QEMU/android/android-emugl/host/libs/libOpenglRender/ChannelStream.cpp中:
const unsigned char* ChannelStream::readRaw(void* buf, size_t* inout_len) {
......
bool blocking = (count == 0);
// 還記得之前寫(xiě)入 RenderChannelImpl::mFromGuest 的數(shù)據(jù)嗎?
auto result = mChannel->readFromGuest(&mReadBuffer, blocking);
D("readFromGuest() returned %d, size %d", (int)result, (int)mReadBuffer.size());
......
return (const unsigned char*)buf;
}
跟進(jìn)mChannel->readFromGuest方法,定義在$QEMU/android/android-emugl/host/libs/libOpenglRender/RenderChannelImpl.cpp中:
IoResult RenderChannelImpl::readFromGuest(Buffer* buffer, bool blocking) {
D("enter");
AutoLock lock(mLock);
IoResult result;
if (blocking) {
// 取出之前在 EmuglPipe::onGuestSend 中通過(guò) mChannel->tryWrite 寫(xiě)入的數(shù)據(jù)
result = mFromGuest.popLocked(buffer);
} else {
result = mFromGuest.tryPopLocked(buffer);
}
updateStateLocked();
DD("mFromGuest.%s() return %d, buffer size %d, state %d",
blocking ? "popLocked" : "tryPopLocked", (int)result,
(int)buffer->size(), (int)mState);
notifyStateChangeLocked();
return result;
}
至此,整個(gè)數(shù)據(jù)傳輸?shù)倪^(guò)程就結(jié)束了。