Android模擬器將OpenGL數(shù)據(jù)傳輸?shù)剿拗鳈C(jī)的過(guò)程

今天花了很長(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_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;
}

此時(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)了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);
        // 還記得之前寫(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é)束了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容