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

تتيح خدمة إطار العمل البسيط هذه للبائع 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 GraphicBufferAgentr (HGBP) من IAutomotiveDisplayProxyService:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. الحصول على SurfaceHolder من ملف HGBP تم استرداده باستخدام واجهة برمجة التطبيقات 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 آخر يطلب فتح الشاشة، حتى إذا لم يكونا متماثلين.