Questo semplice servizio di framework consente al fornitore di elaborazione utilizzano SurfaceFlinger/EGL nelle implementazioni HAL, senza libgui. AOSP fornisce l'implementazione predefinita di questo servizio, che funzionale. Tuttavia, per fornire questo servizio il fornitore deve anche implementare le API 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:
- Richiedi
IAutomotiveDisplayProxyService
.android::sp<IAutomotiveDisplayProxyService> windowProxyService = IAutomotiveDisplayProxyService::getService("default"); if (windowProxyService == nullptr) { LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting."; return 1; }
- Recupera 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; });
- Recupera un
IGraphicBufferProducer
hardware (oppure HIDL GraphicBufferProducer (HGBP) diIAutomotiveDisplayProxyService
:mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId); if (mGfxBufferProducer == nullptr) { LOG(ERROR) << "Failed to get IGraphicBufferProducer from " << "IAutomotiveDisplayProxyService."; return false; }
- Ricevi un
SurfaceHolder
da un HGBP recuperato utilizzando l'APIlibbufferqueueconverter
:mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer); if (mSurfaceHolder == nullptr) { LOG(ERROR) << "Failed to get a Surface from HGBP."; return false; }
- Converti un
SurfaceHolder
in una finestra nativa utilizzando il metodo APIlibbufferqueueconverter
:mWindow = getNativeWindow(mSurfaceHolder.get()); if (mWindow == nullptr) { LOG(ERROR) << "Failed to get a native window from Surface."; return false; }
- Crea la superficie di una finestra EGL con una finestra nativa ed 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; } ...
- Chiama
IAutomotiveDisplayProxyService::showWindow()
per mostrare la visualizzazione sottoposta a rendering sullo schermo. Questo servizio ha la priorità massima e pertanto assume sempre il controllo dello schermo grazie all'attuale proprietario:mAutomotiveDisplayProxyService->showWindow();
Vedi service.cpp
e GlWrapper.cpp
a $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/
per
ulteriori dettagli sull'implementazione.
Un'implementazione HAL di EVS richiede le librerie aggiuntive visualizzate in grassetto sotto.
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 di più display
Visualizzare l'enumerazione del dispositivo e recuperare le informazioni di visualizzazione
Come per l'enumerazione dei dispositivi della fotocamera, il framework EVS fornisce un metodo per
enumera i display disponibili. Lo
identificativo di visualizzazione statico codifica un identificatore di tipo lungo, l'identificatore display
le informazioni di porta nel byte più basso e Extended Display IDentification
Data
nei bit più alti.
IAutomotiveDisplayProxyService::getDisplayIdList()
restituisce un elenco
di ID display dei display fisici locali, disponibili per il servizio EVS,
e IEvsEnumerator::getDisplayIdList()
restituisce un elenco di
le porte a cui sono collegati i display rilevati. Il primo ID dell'elenco è sempre di
sul 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 display di destinazione
L'app EVS chiama IEvsEnumerator::openDisplay_1_1() con un display di destinazione numero porta:
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 l'attuale cliente EVS perde la sua visualizzazione quando un altro cliente EVS richiede di aprire il display, anche se non sono uguali.