Servizio proxy display automobilistico

Questo semplice servizio framework consente ai processi del fornitore di utilizzare SurfaceFlinger/EGL nelle implementazioni HAL, senza collegare libgui. AOSP fornisce l'implementazione predefinita di questo servizio, che è completamente funzionante. Tuttavia, il fornitore deve anche implementare le API per fornire questo servizio sulla propria piattaforma.

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

Per utilizzare questo servizio:

  1. Ottieni IAutomotiveDisplayProxyService .
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. Recuperare le informazioni sul display attivo dal servizio per determinare la risoluzione.
    // 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. Recupera un IGraphicBufferProducer hardware (o HIDL GraphicBufferProducer (HGBP) da IAutomotiveDisplayProxyService :
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. Ottieni un SurfaceHolder da un HGBP recuperato, utilizzando l'API libbufferqueueconverter :
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. Converti un SurfaceHolder in una finestra nativa utilizzando l'API libbufferqueueconverter :
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
    
  6. Crea una superficie della finestra EGL con una finestra nativa e quindi esegui il rendering:
    // 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. Chiama IAutomotiveDisplayProxyService::showWindow() per visualizzare la vista renderizzata sullo schermo. Questo servizio ha la massima priorità e, pertanto, prende sempre il controllo dello schermo dall'attuale proprietario:
    mAutomotiveDisplayProxyService->showWindow();
    

Vedi service.cpp e GlWrapper.cpp in $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ per ulteriori dettagli sull'implementazione.

Un'implementazione dell'HAL EVS richiede le librerie aggiuntive visualizzate in grassetto di seguito.

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

Supporto multi-display

Visualizza l'enumerazione dei dispositivi e recupera le informazioni sul display

Come l'enumerazione dei dispositivi della fotocamera, il framework EVS fornisce un metodo per enumerare i display disponibili. L' identificatore di visualizzazione statico codifica un identificatore lungo il tipo, le informazioni sulla porta di visualizzazione nel byte inferiore e Extended Display IDentification Data nei bit superiori. IAutomotiveDisplayProxyService::getDisplayIdList() restituisce un elenco di ID di visualizzazione di display locali fisici, che sono disponibili per il servizio EVS, e IEvsEnumerator::getDisplayIdList() restituisce un elenco di porte di visualizzazione a cui sono connessi i display rilevati. Il primo ID nell'elenco è sempre quello del display principale.

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

Apri il dispositivo di visualizzazione di destinazione

L'app EVS chiama IEvsEnumerator::openDisplay_1_1() con un numero di porta display di destinazione:

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

Nota: è possibile utilizzare un solo display alla volta, il che significa che il client EVS corrente perde il display quando un altro client EVS richiede di aprire il display, anche quando non sono gli stessi.