Otomotiv görüntüleme proxy hizmeti

Bu basit çerçeve hizmeti, tedarikçi firma işlemlerinin libgui'yi bağlamadan HAL uygulamalarında SurfaceFlinger/EGL kullanmasına olanak tanır. AOSP, bu hizmetin varsayılan uygulamasını sağlar ve bu uygulama tamamen işlevseldir. Ancak tedarikçi firmanın, bu hizmeti platformunda sunmak için API'leri de uygulaması gerekir.

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);
}

Bu hizmeti kullanmak için:

  1. IAutomotiveDisplayProxyService'i edinin.
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
  2. Çözünürlüğü belirlemek için hizmetten etkin görüntüleme bilgilerini alın.
    // 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 donanımını (veya IAutomotiveDisplayProxyService'dan HIDL GraphicBufferProducer (HGBP)) alın:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
  4. API'yi kullanarak alınan bir HGBP'den SurfaceHolder alınlibbufferqueueconverter:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
  5. libbufferqueueconverter API'sini kullanarak SurfaceHolder öğesini doğal bir pencereye dönüştürün:
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
  6. Yerel bir pencereyle EGL pencere yüzeyi oluşturun ve ardından oluşturma işlemini gerçekleştirin:
    // 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. Oluşturulan görünümü ekranda görüntülemek için IAutomotiveDisplayProxyService::showWindow() işlevini çağırın. Bu hizmet en yüksek önceliğe sahiptir ve bu nedenle ekranın kontrolünü her zaman mevcut sahipten alır:
    mAutomotiveDisplayProxyService->showWindow();

Daha fazla uygulama ayrıntısı için $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ bölümündeki service.cpp ve GlWrapper.cpp bölümlerine bakın.

EVS HAL uygulaması, aşağıda kalın olarak gösterilen ek kitaplıkları gerektirir.

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",
    ],

Çoklu ekran desteği

Görüntüleme cihazını numaralandırma ve görüntüleme bilgilerini alma

Kamera cihazı numaralandırması gibi EVS çerçevesi de mevcut ekranları numaralandırmak için bir yöntem sağlar. Static Display Identifier (Statik Görüntü Tanımlayıcı), tür uzunlukta bir tanımlayıcı, alt bayttaki görüntü bağlantı noktası bilgilerini ve üst bitlerdeki Extended Display IDentification Data değerini kodlar. IAutomotiveDisplayProxyService::getDisplayIdList(), EVS hizmetinin kullanabileceği fiziksel yerel ekranların ekran kimliklerinin bir listesini döndürür ve IEvsEnumerator::getDisplayIdList(), algılanan ekranların bağlı olduğu ekran bağlantı noktalarının bir listesini döndürür. Listedeki ilk kimlik her zaman birincil ekrana aittir.

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);
};

Hedef görüntüleme cihazını açma

EVS uygulaması, hedef ekran bağlantı noktası numarasıyla IEvsEnumerator::openDisplay_1_1() çağrısı yapar:

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

Not: Aynı anda yalnızca tek bir ekran kullanılabilir. Yani aynı olmasa bile başka bir EVS istemcisi ekranı açmayı istediğinde mevcut EVS istemcisi ekranını kaybeder.