خدمات پراکسی نمایش خودرو

این سرویس فریمورک ساده به فرآیندهای فروشنده اجازه می‌دهد از SurfaceFlinger/EGL در پیاده‌سازی HAL، بدون پیوند libgui استفاده کنند. AOSP اجرای پیش فرض این سرویس را ارائه می دهد که کاملاً کاربردی است. با این حال، فروشنده باید API ها را نیز برای ارائه این سرویس بر روی پلت فرم خود پیاده سازی کند.

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. با استفاده از API libbufferqueueconverter یک SurfaceHolder از HGBP بازیابی شده دریافت کنید:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
  5. با استفاده از API libbufferqueueconverter یک SurfaceHolder به یک پنجره بومی تبدیل کنید:
    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 نمایش خود را از دست می‌دهد، حتی زمانی که آنها یکسان نیستند.