Proxy-Dienst für Autodisplays

Mit diesem einfachen Framework-Dienst können Anbieterprozesse SurfaceFlinger/EGL in HAL-Implementierungen verwenden, ohne libgui zu verknüpfen. AOSP bietet die Standardimplementierung dieses Dienstes, die vollständig funktionsfähig ist. Der Anbieter muss jedoch auch APIs implementieren, um diesen Dienst auf seiner Plattform bereitzustellen.

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

So nutzen Sie diesen Dienst:

  1. IAutomotiveDisplayProxyService erhalten
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
  2. Rufen Sie Informationen zum aktiven Display vom Dienst ab, um die Auflösung zu ermitteln.
    // 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. Hardware-IGraphicBufferProducer (oder HIDL GraphicBufferProducer (HGBP) aus IAutomotiveDisplayProxyService abrufen:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
  4. So rufen Sie mithilfe der API SurfaceHolder aus einer abgerufenen HGBP ab: libbufferqueueconverter
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
  5. Mit der API libbufferqueueconverter ein SurfaceHolder in ein natives Fenster konvertieren:
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
  6. Erstellen Sie eine EGL-Fensteroberfläche mit einem nativen Fenster und rendern Sie dann:
    // 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. Rufen Sie IAutomotiveDisplayProxyService::showWindow() auf, um die gerenderte Ansicht auf dem Bildschirm anzuzeigen. Dieser Dienst hat die höchste Priorität und übernimmt daher immer die Kontrolle über das Display vom aktuellen Inhaber:
    mAutomotiveDisplayProxyService->showWindow();

Weitere Implementierungsdetails finden Sie unter service.cpp und GlWrapper.cpp in $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/.

Für eine EVS HAL-Implementierung sind die zusätzlichen Bibliotheken erforderlich, die unten fett dargestellt sind.

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

Multi-Display-Unterstützung

Anzeigegerät aufzählen und Anzeigeinformationen abrufen

Ähnlich wie bei der Aufzählung von Kamerageräten bietet das EVS-Framework eine Methode zum Aufzählen der verfügbaren Displays. Die Static Display Identifier codiert eine typenlange Kennung, die Displayport-Informationen im unteren Byte und Extended Display IDentification Data in den oberen Bits. IAutomotiveDisplayProxyService::getDisplayIdList() gibt eine Liste der Display-IDs physischer lokaler Displays zurück, die für den EVS-Dienst verfügbar sind. IEvsEnumerator::getDisplayIdList() gibt eine Liste der Displayports zurück, mit denen erkannte Displays verbunden sind. Die erste ID in der Liste ist immer die des primären Displays.

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

Zielanzeigegerät öffnen

Die EVS-App ruft IEvsEnumerator::openDisplay_1_1() mit einer Portnummer des Zieldisplays auf:

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

Hinweis:Es kann immer nur ein Display verwendet werden. Das bedeutet, dass der aktuelle EVS-Client sein Display verliert, wenn ein anderer EVS-Client das Öffnen des Displays anfordert, auch wenn es sich nicht um denselben handelt.