خدمة الخادم الوكيل لشاشة Automotive

تسمح خدمة إطار العمل البسيطة هذه لعمليات المورّد باستخدام SurfaceFlinger/EGL في عمليات تنفيذ HAL، بدون ربط libgui. يقدّم AOSP التنفيذ التلقائي لهذه الخدمة، وهو متاح بالكامل. ومع ذلك، على المورّد أيضًا تنفيذ واجهات برمجة التطبيقات لتقديم هذه الخدمة على منصته.

package android.frameworks.automotive.display@1.0;

import android.hardware.graphics.bufferqueue@2.0::IGraphicBufferProducer;

interface IAutomotiveDisplayProxyService {
    /**
     * Gets an IGraphicBufferProducer instance from the service.
     *
     * @param  id   Target's stable display identifier
     *
     * @return igbp Returns an IGraphicBufferProducer object, that can be
     *              converted to an ANativeWindow object.
     */
    getIGraphicBufferProducer(uint64_t id) generates (IGraphicBufferProducer igbp);

    /**
     * Sets the ANativeWindow, which is associated with the
     * IGraphicBufferProducer, to be visible and to take over the display.
     *
     * @param  id      Target display ID
     *
     * @return success Returns true on success.
     */
    showWindow(uint64_t id) generates (bool success);

    /**
     * Sets the ANativeWindow, which is associated with the
     * IGraphicBufferProducer, to be invisible and to release the control
     * over display.
     *
     * @param  id      Target display ID
     *
     * @return success Returns true on success.
     */
    hideWindow(uint64_t id) generates (bool success);

    /**
     * Returns the stable identifiers of all available displays.
     *
     * @return ids A list of stable display identifiers.
     */
    getDisplayIdList() generates (vec<uint64_t> ids);

    /**
     * Returns the descriptor of the target display.
     *
     * @param  id    Stable ID of a target display.
     * @return cfg   DisplayConfig of the active display.
     * @return state Current state of the active display.
     */
    getDisplayInfo(uint64_t id) generates (HwDisplayConfig cfg, HwDisplayState state);
}

لاستخدام هذه الخدمة، يُرجى اتّباع الخطوات التالية:

  1. الحصول على IAutomotiveDisplayProxyService
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
  2. استرداد معلومات شاشة نشطة من الخدمة لتحديد درجة الدقة
    // We use the first display in the list as the primary.
    pWindowProxy->getDisplayInfo(displayId, [this](auto dpyConfig, auto dpyState) {
        DisplayConfig *pConfig = (DisplayConfig*)dpyConfig.data();
        mWidth = pConfig->resolution.getWidth();
        mHeight = pConfig->resolution.getHeight();
    
        ui::DisplayState* pState = (ui::DisplayState*)dpyState.data();
        if (pState->orientation != ui::ROTATION_0 &&
            pState->orientation != ui::ROTATION_180) {
            // rotate
            std::swap(mWidth, mHeight);
        }
    
        LOG(DEBUG) << "Display resolution is " << mWidth << " x " << mHeight;
    });
  3. استرداد جهاز IGraphicBufferProducer (أو HIDL GraphicBufferProducer (HGBP) من IAutomotiveDisplayProxyService:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
  4. الحصول على SurfaceHolder من إعلان معروض على شبكة البحث المجانية الذي تم استرداده، باستخدام واجهة برمجة التطبيقات libbufferqueueconverter:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
  5. حوِّل SurfaceHolder إلى نافذة أصلية باستخدام libbufferqueueconverter: واجهة برمجة التطبيقات
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
  6. أنشئ سطح نافذة EGL باستخدام نافذة أصلية، ثم أعِد التقديم:
    // Set up our OpenGL ES context associated with the default display
    mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (mDisplay == EGL_NO_DISPLAY) {
        LOG(ERROR) << "Failed to get egl display";
        return false;
    }
    ...
    
    // Create the EGL render target surface
    mSurface = eglCreateWindowSurface(mDisplay, egl_config, mWindow, nullptr);
    if (mSurface == EGL_NO_SURFACE) {
        LOG(ERROR) << "eglCreateWindowSurface failed.";
        return false;
    }
    ...
  7. اتصل بالرقم IAutomotiveDisplayProxyService::showWindow() لعرض المنظر المعروض على الشاشة. تحظى هذه الخدمة بأعلى أولوية، وبالتالي، تتمكّن دائمًا من التحكّم في الشاشة من المالك الحالي:
    mAutomotiveDisplayProxyService->showWindow();

اطّلِع على service.cpp وGlWrapper.cpp في $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ للحصول على مزيد من تفاصيل التنفيذ.

يتطلب تنفيذ EVS HAL المكتبات الإضافية المعروضة بخط سمين أدناه.

cc_binary {
    name: "android.hardware.automotive.evs@1.1-sample",

    vendor: true,

    srcs: [
        ...
    ],

    shared_libs: [
        ...
        "libbufferqueueconverter",
        "android.hidl.token@1.0-utils",
        "android.frameworks.automotive.display@1.0",
        "android.hardware.graphics.bufferqueue@1.0",
        "android.hardware.graphics.bufferqueue@2.0",
    ],

التوافق مع الشاشات المتعددة

إحصاء أجهزة العرض واسترداد معلومات العرض

مثل عملية سرد أجهزة الكاميرا، يقدّم إطار عمل EVS طريقة ل سرد الشاشات المتاحة. يُشفِّر معرّف الشاشة الثابت معرّفًا بطول نوع، ومعلومات بوابة الشاشة في البايت السفلي وExtended Display IDentification Data في الوحدات البتية العليا. يعرض IAutomotiveDisplayProxyService::getDisplayIdList() قائمة بأرقام تعريف الشاشات المحلية الفعلية، والتي تتوفّر لخدمة EVS، ويعرض IEvsEnumerator::getDisplayIdList() قائمة بمنفذ العرض المتصل بالشاشات التي تم رصدها. يكون المعرّف الأول في القائمة دائمًا هو الشاشة الأساسية.

interface IEvsEnumerator extends @1.0::IEvsEnumerator {
    ...
    /**
     * Returns a list of all EVS displays available to the system
     *
     * @return displayIds Identifiers of available displays.
     */
    getDisplayIdList() generates (vec<uint8_t> displayIds);
};

فتح جهاز العرض المستهدَف

يُطلِق تطبيق EVS دالة IEvsEnumerator::openDisplay_1_1() مع رقم منفذ شاشة مستهدَف:

android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId);
if (pDisplay.get() == nullptr) {
    LOG(ERROR) << "EVS Display unavailable. Exiting.";
    return 1;
}

ملاحظة: يمكن استخدام شاشة عرض واحدة فقط في المرة الواحدة، ما يعني أنّ برنامج EVS الحالي يفقد شاشة العرض عندما يطلب برنامج EVS آخر فتح الشاشة، حتى لو لم يكنا البرنامجَين نفسهما.