خدمة وكيل عرض السيارات

تتيح خدمة إطار العمل البسيطة هذه لعمليات البائعين استخدام 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 من HGBP المسترد، باستخدام libbufferqueueconverter API:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. تحويل SurfaceHolder إلى نافذة أصلية باستخدام API 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 آخر فتح الشاشة، حتى عندما لا تكون هي نفسها.