Service proxy d'affichage automobile

Ce service de framework simple permet au fournisseur utilisent SurfaceFlinger/EGL dans les implémentations HAL, sans associer libgui. AOSP fournit l'implémentation par défaut de ce service, qui est entièrement et fonctionnel. Toutefois, le fournisseur doit également mettre en œuvre des API pour fournir ce service. sur leur plate-forme.

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

Pour utiliser ce service:

  1. Profitez de IAutomotiveDisplayProxyService.
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. Récupérez des informations d'affichage actif à partir du service pour déterminer la résolution.
    // 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. Récupérez un IGraphicBufferProducer matériel (ou HIDL GraphicBufferProducer (HGBP) de IAutomotiveDisplayProxyService:
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. Obtenir une SurfaceHolder à partir d'une HGBP récupérée, à l'aide de l'API libbufferqueueconverter:
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. Convertissez un SurfaceHolder en fenêtre native à l'aide de la méthode API libbufferqueueconverter:
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
    
  6. Créez une surface de fenêtre EGL avec une fenêtre native, puis effectuez le rendu:
    // 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. Appeler IAutomotiveDisplayProxyService::showWindow() au afficher la vue rendue à l'écran. Ce service a la priorité la plus élevée. C'est donc toujours le propriétaire actuel qui contrôle l'écran:
    mAutomotiveDisplayProxyService->showWindow();
    

Voir service.cpp et GlWrapper.cpp dans $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ pour pour en savoir plus sur l'implémentation.

Une implémentation EVS HAL nécessite les bibliothèques supplémentaires affichées dans gras ci-dessous.

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

Compatibilité multi-écran

Afficher l'énumération des appareils et récupérer les informations d'affichage

Tout comme l'énumération des appareils photo, le framework EVS fournit une méthode pour énumérer les écrans disponibles. Le l'identifiant d'affichage statique encode un identifiant de type long, l'identifiant de l'écran les informations de port dans l'octet inférieur et Extended Display IDentification Data dans les bits supérieurs. IAutomotiveDisplayProxyService::getDisplayIdList() renvoie une liste des ID d'affichage des écrans physiques locaux, disponibles pour le service EVS. et IEvsEnumerator::getDisplayIdList() renvoie une liste d'éléments à afficher sur lesquels les écrans détectés sont connectés. Le premier identifiant de la liste est toujours de l'écran 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);
};

Ouvrir l'appareil display cible

L'application EVS appelle IEvsEnumerator::openDisplay_1_1() avec un écran cible. numéro de port:

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

Remarque:Vous ne pouvez utiliser qu'un seul écran à la fois, ce qui signifie que le client EVS actuel perd son écran lorsqu'un autre client EVS les requêtes d'ouverture de l'affichage, même s'ils sont différents.