今天花了很长时间,终于搞懂了Android SDK中的模拟器是如何处理来自Android系统的OpenGL数据流的,特此记录,以防忘记。
本文是基于此时(2018年4月29日)最新的 emu-2.7-release
分支来写作的。
$ANDROID_ROOT = Android 源码存放目录
$QEMU = $ANDROID_ROOT/external/qemu
Guest 端
运行在模拟器内部的Android系统是通过模拟器中名为 /dev/goldfish_pipe
的管道设备(3.10之前的内核中,此设备名为qemu_pipe)向宿主机传递GL数据流的。这部分可以参考 $QEMU/android/android-emugl/DESIGN 文档中所描述的内容。
本文主要分析 Host 端的处理过程。
Host 端
模拟器启动时,调用了$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; // 真正初始化设备的过程
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);
}
// 注册设备
type_init(goldfish_pipe_register);
然后来到同一个文件中的goldfish_pipe_realize
函数:
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; // 注册 Guest 对管道设备的读写操作处理函数
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);
// 注册模拟器保存/加载状态时的处理函数
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 读取该设备时的处理函数
.dev_write = &pipe_dev_write_v2 // Guest 写入该设备时的处理函数
};
此时,管道设备已经被注册到 qemu 中。接下来我们主要关注 Guest 写入该设备时的处理函数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]) {
// 处理来自 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;
}
}
很明显,重点是对 pipeDevice_doCommand_v2
的调用。来看它的源码(也位于 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)));
// 定义数据缓冲区
GoldfishPipeBuffer buffers[
COMMAND_BUFFER_SIZE / (sizeof(*rwPtrs) + sizeof(*rwSizes))];
...... 跳过处理内存边界的代码
pipe->command_buffer->status =
willModifyData
? service_ops->guest_recv(pipe->host_pipe,
buffers, // 数据在这里面
buffers_count) // Guest 接收数据,即 Host 向 Guest 发送数据
: service_ops->guest_send(pipe->host_pipe,
buffers, // 数据在这里面
buffers_count); // Guest 发送数据,即 Host 接收来自 Guest 的数据
......
break;
}
我们遇到了service_ops
这个变量以及guest_recv
、guest_send
两个函数。让我们先来看看它们是怎么来的。
还是回到qemu初始化的时候,这次是 $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;
}
对于 qemu_android_pipe_init
的调用,该函数定义在 $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); // 注册管道设备的各种操作
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, // 数据在这里面
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, // 数据在这里面
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;
}
此时,我们得到了 service_ops
变量。
现在,我们再来关注guest_send
函数:
// 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, // 数据在这里面
int numBuffers) -> int {
return android_pipe_guest_send(
hostPipe,
reinterpret_cast<const AndroidPipeBuffer*>(buffers),
numBuffers);
},
这个函数直接调用了android_pipe_guest_send
函数。此函数位于$QEMU/android/android-emu/android/emulation/AndroidPipe.cpp
中:
int android_pipe_guest_send(void* internalPipe,
const AndroidPipeBuffer* buffers, // 数据在这里面
int numBuffers) {
CHECK_VM_STATE_LOCK();
auto pipe = static_cast<AndroidPipe*>(internalPipe);
// 调用该管道的处理函数
return pipe->onGuestSend(buffers, numBuffers);
}
onGuestSend
也定义在同一文件内:
// 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, // 数据在这里面
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 想要调用的服务的名称,现在开始查找对应的服务类
svc = findServiceByName(pipeName);
if (svc) {
pipeArgs = pipeArgs2;
} else if (pipeArgs2) {
// Restore colon.
*pipeArgs2 = ':';
}
}
if (pipeArgs) {
*pipeArgs++ = '\0';
if (!pipeArgs) {
pipeArgs = NULL;
}
}
if (!svc) {
// 没找到?再来一次
svc = findServiceByName(pipeName);
}
if (!svc) {
// 还是没找到?算了,退出
D("%s: Unknown server with name %s!", __FUNCTION__, pipeName);
return PIPE_ERROR_INVAL;
}
// 从该服务创建新的管道类,该管道类是 AndroidPipe 的子类
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 中关联的 AndroidPipe 类用新创建的子类替换掉
sPipeHwFuncs->resetPipe(mHwPipe, newPipe);
// 自杀
delete this;
return result;
}
到这里好像没有对数据进行任何处理?那让我们来看看findServiceByName
这个函数(定义在同一文件中):
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();
}
又是一个全局变量sGlobals
,它用于维护所有注册了的服务列表。那么服务们又是在哪里注册的呢?我们在同一个文件中找到了add
函数:
// 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
的所有子类,在$QEMU/android/android-emu/android/opengl/OpenglEsPipe.cpp
中,我们发现了EmuglPipe
这个类:
class EmuglPipe : public AndroidPipe {
public:
//////////////////////////////////////////////////////////////////////////
// The pipe service class for this implementation.
class Service : public AndroidPipe::Service {
public:
// 我是叫做 opengles 的服务
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() {
// 注册 opengles 服务
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();
}
于是,我们的目光转向了EmuglPipe
这个类:
virtual int onGuestSend(const AndroidPipeBuffer* buffers, // 数据在这里面
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)); // 记住这个 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;
}
重点看来是mChannel->tryWrite
这个调用。该方法定义于$QEMU/android/android-emugl/host/libs/libOpenglRender/RenderChannelImpl.cpp
:
IoResult RenderChannelImpl::tryWrite(Buffer&& buffer /* 数据在这里面 */) {
D("buffer size=%d", (int)buffer.size());
AutoLock lock(mLock);
// 记住此处,数据被放到了 RenderChannelImpl::mFromGuest 里面
auto result = mFromGuest.tryPushLocked(std::move(buffer));
updateStateLocked();
DD("mFromGuest.tryPushLocked() returned %d, state %d", (int)result,
(int)mState);
return result;
}
mFromGuest
是一个BufferQueue<RenderChannel::Buffer>
类型的成员,用于存放来自于 Guest 的数据。那么,数据被放到这个成员里面之后,就结束了吗?
当然没有。接下来,我们要从另一个方向开始:$QEMU/objs/lib64/lib64OpenglRender.so
。根据$QEMU/android/android-emugl/DESIGN
所述,这是独立的渲染程序,负责接收 qemu 转发的来自 Guest 的GL数据并渲染在屏幕上。
若未发现此文件,请执行
$QEMU/android/configure.sh && make
来编译模拟器。
我们执行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
注意最后一行导出的initLibrary
函数。这也是该共享库的唯一导出函数。
在源码中查找initLibrary
的调用,我们来到了$QEMU/android/android-emu/android/opengles.cpp
中:
int android_initOpenglesEmulation() {
char* error = NULL;
if (sRenderLib != NULL)
return 0;
......
// 已经加载了 lib64OpenglRender.so,调用其初始化函数
sRenderLib = initLibrary();
if (!sRenderLib) {
derror("OpenGLES initialization failed!");
goto BAD_EXIT;
}
跟进initLibrary
,我们来到了$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
中,我们发现了紧接着android_initOpenglesEmulation
函数的android_startOpenglesRenderer
函数:
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); // 这里面的东西似乎并没有被任何地方使用
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); // 这里面的东西似乎并没有被任何地方使用
// 初始化渲染器
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;
}
继续跟进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;
}
继续跟进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;
}
虽然这个地方看起来有个RenderThread
,但此处并不是真正地启动了渲染线程。真正启动渲染的地方,还要回到$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 用于保存/恢复虚拟机状态所用的
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();
}
// 创建 RenderChannelImpl 类。记住这个 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
类以及AndroidPipe::onGuestSend
中的AndroidPipe* newPipe = svc->create(mHwPipe, pipeArgs);
吧?让我们来看看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;
}
// 构造 EmuglPipe 类
auto pipe = new EmuglPipe(hwPipe, service, renderer, loadStream);
if (!pipe->mIsWorking) {
delete pipe;
pipe = nullptr;
}
return pipe;
}
现在,我们终于找到了上面 EmuglPipe::EmuglPipe()
的调用来源。让我们正式进入RendererImpl::createRenderChannel
方法:
RenderChannelPtr RendererImpl::createRenderChannel(
android::base::Stream* loadStream) {
const auto channel = std::make_shared<RenderChannelImpl>(loadStream);
{
......
}
return channel;
}
再进入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 指向的是同一个实例
mRenderThread.reset(new RenderThread(this, loadStream));
mRenderThread->start();
}
这里我们终于真正地启动了渲染线程。
还记得之前EmuglPipe::onGuestSend
方法中的auto result = mChannel->tryWrite(std::move(outBuffer));
吗?此处的mChannel
就是由RendererImpl::createRenderChannel
所返回的RenderChannelImpl
的实例。同时,这个实例也被传入了新创建的RenderThread
中。
最后,让我们进入RenderThread::main
方法,定义在$QEMU/android/android-emugl/host/libs/libOpenglRender/RenderThread.cpp
中:
intptr_t RenderThread::main() {
......
// 这里的 mChannel 就是之前传入的`RenderChannelImpl`的实例,与`EmuglPipe::mChannel`指向同一个实例
ChannelStream stream(mChannel, RenderChannel::Buffer::kSmallSize);
ReadBuffer readBuf(kStreamBufferSize);
......
while (1) {
......
int stat = 0;
if (packetSize > (int)readBuf.validData()) {
// 从 RenderChannelImpl 中读出之前在 `EmuglPipe::onGuestSend` 中写入的数据
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));
......
// 下面是解码来自 Guest 的GL数据的过程
bool progress;
do {
progress = false;
......
return 0;
}
让我们再来看看readBuf.getData
这个方法,定义在$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 中读取数据
const size_t readNow = stream->read(m_readPtr + m_validData,
maxSizeToRead - readTotal);
......
} while (readTotal < minSizeToRead);
return readTotal;
}
ChannelStream
类实现了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);
// 还记得之前写入 RenderChannelImpl::mFromGuest 的数据吗?
auto result = mChannel->readFromGuest(&mReadBuffer, blocking);
D("readFromGuest() returned %d, size %d", (int)result, (int)mReadBuffer.size());
......
return (const unsigned char*)buf;
}
跟进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 中通过 mChannel->tryWrite 写入的数据
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;
}
至此,整个数据传输的过程就结束了。