Proxy-Service für Kfz-Displays

Mit diesem einfachen Framework-Dienst können Anbieterprozesse SurfaceFlinger/EGL in HAL-Implementierungen verwenden, ohne libgui zu verknüpfen. AOSP stellt die Standardimplementierung dieses Dienstes bereit, die voll funktionsfähig ist. Allerdings muss der Anbieter 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);
}

Um diesen Dienst zu nutzen:

  1. Holen Sie sich IAutomotiveDisplayProxyService .
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. Rufen Sie aktive Anzeigeinformationen vom Dienst ab, um die Auflösung zu bestimmen.
    // 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. Rufen Sie einen Hardware IGraphicBufferProducer (oder HIDL GraphicBufferProducer (HGBP)) von IAutomotiveDisplayProxyService ab:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. Rufen Sie einen SurfaceHolder aus einem abgerufenen HGBP ab, indem Sie die API libbufferqueueconverter verwenden:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. Konvertieren Sie einen SurfaceHolder in ein natives Fenster, indem Sie die API libbufferqueueconverter :
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
    
    verwenden
  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 den Bildschirm vom aktuellen Besitzer:
    mAutomotiveDisplayProxyService->showWindow();
    

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

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

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

Unterstützung für mehrere Displays

Gerätenummer anzeigen und Anzeigeinformationen abrufen

Wie die Kamerageräteaufzählung bietet das EVS-Framework eine Methode zum Aufzählen der verfügbaren Anzeigen. Der statische Anzeigebezeichner kodiert einen typlangen Bezeichner, die Anzeigeanschlussinformationen 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, und IEvsEnumerator::getDisplayIdList() gibt eine Liste der Display-Ports zurück, mit denen erkannte Displays verbunden sind. Die erste ID in der Liste ist immer die der primären Anzeige.

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 Ziel-Display-Port-Nummer 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 jeweils nur ein einziges Display verwendet werden, was bedeutet, dass der aktuelle EVS-Client sein Display verliert, wenn ein anderer EVS-Client das Öffnen des Displays anfordert, auch wenn diese nicht identisch sind.