自 2025 年 3 月 27 日起,我们建议您使用 android-latest-release
而非 aosp-main
构建 AOSP 并为其做出贡献。如需了解详情,请参阅 AOSP 的变更。
车载显示屏代理服务
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
这一简单的框架服务支持供应商进程在 HAL 实现中使用 SurfaceFlinger/EGL,而无需链接 libgui。AOSP 提供此服务的默认实现,功能完善。但是,供应商还必须实现 API,以便在其平台上提供此服务。
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);
}
如需使用此服务,请按以下步骤操作:
- 获取
IAutomotiveDisplayProxyService
。
android::sp<IAutomotiveDisplayProxyService> windowProxyService =
IAutomotiveDisplayProxyService::getService("default");
if (windowProxyService == nullptr) {
LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
return 1;
}
- 从服务中检索活跃显示屏的信息,以确定分辨率。
// 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;
});
- 从
IAutomotiveDisplayProxyService
检索硬件 IGraphicBufferProducer
(或 HIDL GraphicBufferProducer [HGBP]):mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
if (mGfxBufferProducer == nullptr) {
LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
<< "IAutomotiveDisplayProxyService.";
return false;
}
- 使用 API
libbufferqueueconverter
从检索到的 HGBP 获取 SurfaceHolder
:mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
if (mSurfaceHolder == nullptr) {
LOG(ERROR) << "Failed to get a Surface from HGBP.";
return false;
}
- 使用 API
libbufferqueueconverter
将 SurfaceHolder
转换为原生窗口:mWindow = getNativeWindow(mSurfaceHolder.get());
if (mWindow == nullptr) {
LOG(ERROR) << "Failed to get a native window from Surface.";
return false;
}
- 使用原生窗口创建一个 EGL 窗口 Surface,然后进行渲染:
// 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;
}
...
- 调用
IAutomotiveDisplayProxyService::showWindow()
以在屏幕上显示所渲染的视图。此服务具有最高的优先级,因此,始终由当前所有者控制屏幕:
mAutomotiveDisplayProxyService->showWindow();
如需了解更多实现详情,请参阅 $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/
中的 service.cpp
和 GlWrapper.cpp
。
EVS HAL 实现需要下面以粗体显示的附加库。
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",
],
多显示屏支持
与相机设备枚举一样,EVS 框架提供了一种枚举可用显示屏的方法。静态显示屏标识符编码长型标识符,其中低位字节为屏幕端口信息,高位为 Extended Display IDentification
Data
。IAutomotiveDisplayProxyService::getDisplayIdList()
返回可用于 EVS 服务的实体本地显示屏的显示屏 ID 列表,IEvsEnumerator::getDisplayIdList()
则返回与检测到的显示屏连接的显示屏端口列表。列表中的第一个 ID 始终为主显示屏。
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);
};
打开目标显示设备
EVS 应用使用目标显示屏端口号调用 IEvsEnumerator::openDisplay_1_1():
android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId);
if (pDisplay.get() == nullptr) {
LOG(ERROR) << "EVS Display unavailable. Exiting.";
return 1;
}
注意:一次只能使用一个显示屏,也就是说,当另一个 EVS 客户端请求打开显示屏时,当前的 EVS 客户端将停止显示,即使它们并不是同一个显示屏也会如此。
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-08-08。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-08-08。"],[],[],null,["# Automotive display proxy service\n\nThis simple framework service lets vendor\nprocesses use SurfaceFlinger/EGL in HAL implementations, without linking\nlibgui. AOSP provides the default implementation of this service, which is fully\nfunctional. However, the vendor must also implement APIs to provide this service\non their platform. \n\n```python\npackage android.frameworks.automotive.display@1.0;\n\nimport android.hardware.graphics.bufferqueue@2.0::IGraphicBufferProducer;\n\ninterface IAutomotiveDisplayProxyService {\n /**\n * Gets an IGraphicBufferProducer instance from the service.\n *\n * @param id Target's stable display identifier\n *\n * @return igbp Returns an IGraphicBufferProducer object, that can be\n * converted to an ANativeWindow object.\n */\n getIGraphicBufferProducer(uint64_t id) generates (IGraphicBufferProducer igbp);\n\n /**\n * Sets the ANativeWindow, which is associated with the\n * IGraphicBufferProducer, to be visible and to take over the display.\n *\n * @param id Target display ID\n *\n * @return success Returns true on success.\n */\n showWindow(uint64_t id) generates (bool success);\n\n /**\n * Sets the ANativeWindow, which is associated with the\n * IGraphicBufferProducer, to be invisible and to release the control\n * over display.\n *\n * @param id Target display ID\n *\n * @return success Returns true on success.\n */\n hideWindow(uint64_t id) generates (bool success);\n\n /**\n * Returns the stable identifiers of all available displays.\n *\n * @return ids A list of stable display identifiers.\n */\n getDisplayIdList() generates (vec\u003cuint64_t\u003e ids);\n\n /**\n * Returns the descriptor of the target display.\n *\n * @param id Stable ID of a target display.\n * @return cfg DisplayConfig of the active display.\n * @return state Current state of the active display.\n */\n getDisplayInfo(uint64_t id) generates (HwDisplayConfig cfg, HwDisplayState state);\n}\n```\n\nTo use this service:\n\n1. Get `IAutomotiveDisplayProxyService`. \n\n ```css+lasso\n android::sp\u003cIAutomotiveDisplayProxyService\u003e windowProxyService =\n IAutomotiveDisplayProxyService::getService(\"default\");\n if (windowProxyService == nullptr) {\n LOG(ERROR) \u003c\u003c \"Cannot use AutomotiveDisplayProxyService. Exiting.\";\n return 1;\n }\n ```\n2. Retrieve an active display information from the service to determine the resolution. \n\n ```transact-sql\n // We use the first display in the list as the primary.\n pWindowProxy-\u003egetDisplayInfo(displayId, [this](auto dpyConfig, auto dpyState) {\n DisplayConfig *pConfig = (DisplayConfig*)dpyConfig.data();\n mWidth = pConfig-\u003eresolution.getWidth();\n mHeight = pConfig-\u003eresolution.getHeight();\n\n ui::DisplayState* pState = (ui::DisplayState*)dpyState.data();\n if (pState-\u003eorientation != ui::ROTATION_0 &&\n pState-\u003eorientation != ui::ROTATION_180) {\n // rotate\n std::swap(mWidth, mHeight);\n }\n\n LOG(DEBUG) \u003c\u003c \"Display resolution is \" \u003c\u003c mWidth \u003c\u003c \" x \" \u003c\u003c mHeight;\n });\n ```\n3. Retrieve a hardware `IGraphicBufferProducer` (or, HIDL GraphicBufferProducer (HGBP) from `IAutomotiveDisplayProxyService`: \n\n ```text\n mGfxBufferProducer = pWindowProxy-\u003egetIGraphicBufferProducer(displayId);\n if (mGfxBufferProducer == nullptr) {\n LOG(ERROR) \u003c\u003c \"Failed to get IGraphicBufferProducer from \"\n \u003c\u003c \"IAutomotiveDisplayProxyService.\";\n return false;\n }\n ```\n4. Get a `SurfaceHolder` from a retrieved HGBP, by using the API `libbufferqueueconverter`: \n\n ```text\n mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);\n if (mSurfaceHolder == nullptr) {\n LOG(ERROR) \u003c\u003c \"Failed to get a Surface from HGBP.\";\n return false;\n }\n ```\n5. Convert a `SurfaceHolder` into a native window by using the API `libbufferqueueconverter`: \n\n ```text\n mWindow = getNativeWindow(mSurfaceHolder.get());\n if (mWindow == nullptr) {\n LOG(ERROR) \u003c\u003c \"Failed to get a native window from Surface.\";\n return false;\n }\n ```\n6. Create an EGL window surface with a native window and then render: \n\n ```scilab\n // Set up our OpenGL ES context associated with the default display\n mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);\n if (mDisplay == EGL_NO_DISPLAY) {\n LOG(ERROR) \u003c\u003c \"Failed to get egl display\";\n return false;\n }\n ...\n\n // Create the EGL render target surface\n mSurface = eglCreateWindowSurface(mDisplay, egl_config, mWindow, nullptr);\n if (mSurface == EGL_NO_SURFACE) {\n LOG(ERROR) \u003c\u003c \"eglCreateWindowSurface failed.\";\n return false;\n }\n ...\n ```\n7. Call `IAutomotiveDisplayProxyService::showWindow()` to display the rendered view on the screen. This service has the highest priority and, therefore, always takes control of the screen from the current owner: \n\n ```text\n mAutomotiveDisplayProxyService-\u003eshowWindow();\n ```\n\nSee `service.cpp` and `GlWrapper.cpp`\nin `$ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/` for\nmore implementation details.\n\nAn EVS HAL implementation requires the additional libraries displayed in\n**bold** below. \n\n```objective-c\ncc_binary {\n name: \"android.hardware.automotive.evs@1.1-sample\",\n\n vendor: true,\n\n srcs: [\n ...\n ],\n\n shared_libs: [\n ...\n \"libbufferqueueconverter\",\n \"android.hidl.token@1.0-utils\",\n \"android.frameworks.automotive.display@1.0\",\n \"android.hardware.graphics.bufferqueue@1.0\",\n \"android.hardware.graphics.bufferqueue@2.0\",\n ],\n```\n\nMulti-display support\n---------------------\n\n### Display device enumeration and retrieve display information\n\nLike the camera device enumeration, the EVS framework provides a method to\nenumerate the available displays. The [static display identifier](/devices/tech/display/multi_display/displays#static) encodes a type-long identifier, the display\nport information in the lower byte and `Extended Display IDentification\nData` in upper bits.\n`IAutomotiveDisplayProxyService::getDisplayIdList()` returns a list\nof display IDs of physical local displays, which are available to EVS service,\nand `IEvsEnumerator::getDisplayIdList()` returns a list of display\nports detected displays are connected to. The first ID in the list is always of\nthe primary display. \n\n```objective-c\ninterface IEvsEnumerator extends @1.0::IEvsEnumerator {\n ...\n /**\n * Returns a list of all EVS displays available to the system\n *\n * @return displayIds Identifiers of available displays.\n */\n getDisplayIdList() generates (vec\u003cuint8_t\u003e displayIds);\n};\n```\n\n### Open target display device\n\nEVS app calls IEvsEnumerator::openDisplay_1_1() with a target display\nport number: \n\n```css+lasso\nandroid::sp\u003cIEvsDisplay\u003e pDisplay = pEvs-\u003eopenDisplay_1_1(displayId);\nif (pDisplay.get() == nullptr) {\n LOG(ERROR) \u003c\u003c \"EVS Display unavailable. Exiting.\";\n return 1;\n}\n```\n\n**Note:** Only a single display can be in use at one time,\nwhich means the current EVS client loses its display when another EVS client\nrequests to open the display, even when they are not the same."]]