Android模拟器将OpenGL数据传输到宿主机的过程

今天花了很长时间,终于搞懂了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_recvguest_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_recvguest_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类实现了IOStreamread方法,定义在$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;
}

至此,整个数据传输的过程就结束了。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容