Servicio de proxy de la pantalla de Automotive

Este sencillo servicio de framework permite que los proveedores usan SurfaceFlinger/EGL en implementaciones de HAL, sin vinculación libgui. AOSP proporciona la implementación predeterminada de este servicio, que es y cómo funcionan. Sin embargo, el proveedor también debe implementar APIs para proporcionar 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 usar este servicio, haz lo siguiente:

  1. Obtén IAutomotiveDisplayProxyService.
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. Recupera una información de pantalla activa del servicio para determinar la resolució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. Recuperar un objeto 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. Obtén un SurfaceHolder de un HGBP recuperado mediante la API libbufferqueueconverter
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. Convierte un objeto SurfaceHolder en una ventana nativa con el elemento 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 de ventana EGL con una ventana nativa y, luego, renderiza:
    // 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. Llamar a IAutomotiveDisplayProxyService::showWindow() a mostrar la vista renderizada en la pantalla. Este servicio tiene la prioridad más alta y, Por lo tanto, siempre toma el control de la pantalla desde el propietario actual:
    mAutomotiveDisplayProxyService->showWindow();
    

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

Una implementación de la HAL de EVS 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 pantallas múltiples

Cómo mostrar la enumeración de dispositivos y recuperar información en pantalla

Al igual que la enumeración de dispositivos de cámara, el framework EVS proporciona un método para enumerar las pantallas disponibles. El identificador de pantalla estática codifica un identificador de tipo largo, la pantalla información del puerto en el byte inferior y Extended Display IDentification Data en los bits superiores. IAutomotiveDisplayProxyService::getDisplayIdList() muestra una lista. de los IDs de pantalla de las pantallas físicas locales, que están disponibles para el servicio de EVS, y IEvsEnumerator::getDisplayIdList() muestra una lista de imágenes puertos detectados a los que están conectadas las pantallas. El primer ID de la lista siempre es 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 el dispositivo de visualización de destino

La app de EVS llama a IEvsEnumerator::openDisplay_1_1() con una pantalla de destino número de puerto:

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

Nota: Solo puedes usar una pantalla a la vez, lo que significa que el cliente EVS actual pierde la pantalla cuando otro cliente EVS solicitudes para abrir la pantalla, incluso cuando no son lo mismo.