Servicio de proxy de pantalla automotriz

Este nuevo y simple servicio de marco se proporciona para permitir que los procesos de proveedores usen SurfaceFlinger/EGL en implementaciones HAL, sin vincular libgui. AOSP proporciona la implementación predeterminada de este servicio, que es totalmente funcional. Sin embargo, el proveedor también debe implementar API para brindar este servicio en su plataforma.

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

Para utilizar este servicio:

  1. Obtenga IAutomotiveDisplayProxyService .
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. Recupere la información de una pantalla activa del servicio para determinar la resolución.
    // We will 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. Recupere un IGraphicBufferProducer de hardware (o HIDL GraphicBufferProducer (HGBP) de IAutomotiveDisplayProxyService :
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. Obtenga un SurfaceHolder de un HGBP recuperado, utilizando la API libbufferqueueconverter :
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. Convierta un SurfaceHolder en una ventana nativa usando la API libbufferqueueconverter :
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
    
  6. Cree una superficie de ventana EGL con una ventana nativa y luego renderice:
    // 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. Llame IAutomotiveDisplayProxyService::showWindow() para mostrar la vista renderizada en la pantalla. Este servicio tiene la máxima prioridad y, por lo tanto, siempre toma el control de la pantalla del propietario actual:
    mAutomotiveDisplayProxyService->showWindow();
    

Consulte service.cpp y GlWrapper.cpp en $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ para obtener más detalles de implementación.

Una implementación de EVS HAL requiere las bibliotecas adicionales que se muestran en negrita a continuación.

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

Compatibilidad con varias pantallas

Enumeración de dispositivos de visualización y recuperación de información de visualización

Al igual que la enumeración de dispositivos de cámara, el marco EVS proporciona un método para enumerar las pantallas disponibles. El identificador de visualización estático codifica un identificador de tipo largo, la información del puerto de visualización en el byte inferior y Extended Display IDentification Data en los bits superiores. IAutomotiveDisplayProxyService::getDisplayIdList() devuelve una lista de ID de pantalla de pantallas locales físicas, que están disponibles para el servicio EVS, e IEvsEnumerator::getDisplayIdList() devuelve una lista de puertos de pantalla a los que están conectadas las pantallas detectadas. El primer ID de la lista es siempre el de la pantalla principal.

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

Abrir dispositivo de visualización de destino

La aplicación EVS llama a IEvsEnumerator::openDisplay_1_1() con un número de puerto de visualización de destino:

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

Nota: Solo se puede usar una pantalla a la vez, lo que significa que el cliente EVS actual pierde su pantalla cuando otro cliente EVS solicita abrir la pantalla, incluso cuando no son iguales.