Kể từ ngày 27 tháng 3 năm 2025, bạn nên sử dụng android-latest-release
thay vì aosp-main
để xây dựng và đóng góp cho AOSP. Để biết thêm thông tin, hãy xem phần Thay đổi đối với AOSP.
Dịch vụ proxy hiển thị ô tô
Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang
Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Dịch vụ khung đơn giản này cho phép các quy trình của nhà cung cấp sử dụng SurfaceFlinger/EGL trong quá trình triển khai HAL mà không cần liên kết libgui. AOSP cung cấp phương thức triển khai mặc định của dịch vụ này, có đầy đủ chức năng. Tuy nhiên, nhà cung cấp cũng phải triển khai các API để cung cấp dịch vụ này trên nền tảng của họ.
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);
}
Cách sử dụng dịch vụ này:
- Lấy
IAutomotiveDisplayProxyService
.
android::sp<IAutomotiveDisplayProxyService> windowProxyService =
IAutomotiveDisplayProxyService::getService("default");
if (windowProxyService == nullptr) {
LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
return 1;
}
- Truy xuất thông tin hiển thị đang hoạt động từ dịch vụ để xác định độ phân giải.
// 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;
});
- Truy xuất
IGraphicBufferProducer
phần cứng (hoặc HIDL GraphicBufferProducer (HGBP) từ IAutomotiveDisplayProxyService
:
mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
if (mGfxBufferProducer == nullptr) {
LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
<< "IAutomotiveDisplayProxyService.";
return false;
}
- Lấy
SurfaceHolder
từ HGBP đã truy xuất bằng cách sử dụng API libbufferqueueconverter
:
mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
if (mSurfaceHolder == nullptr) {
LOG(ERROR) << "Failed to get a Surface from HGBP.";
return false;
}
- Chuyển đổi
SurfaceHolder
thành cửa sổ gốc bằng cách sử dụng API libbufferqueueconverter
:
mWindow = getNativeWindow(mSurfaceHolder.get());
if (mWindow == nullptr) {
LOG(ERROR) << "Failed to get a native window from Surface.";
return false;
}
- Tạo một bề mặt cửa sổ EGL bằng một cửa sổ gốc, sau đó kết xuất:
// 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;
}
...
- Gọi
IAutomotiveDisplayProxyService::showWindow()
để hiển thị thành phần hiển thị đã kết xuất trên màn hình. Dịch vụ này có mức độ ưu tiên cao nhất và do đó, luôn kiểm soát màn hình từ chủ sở hữu hiện tại:
mAutomotiveDisplayProxyService->showWindow();
Hãy xem service.cpp
và GlWrapper.cpp
trong $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/
để biết thêm thông tin chi tiết về cách triển khai.
Việc triển khai EVS HAL yêu cầu các thư viện bổ sung hiển thị ở dạng in đậm bên dưới.
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",
],
Hỗ trợ nhiều màn hình
Giống như việc liệt kê thiết bị máy ảnh, khung EVS cung cấp một phương thức để liệt kê các màn hình có sẵn.
Mã nhận dạng màn hình tĩnh mã hoá một mã nhận dạng loại dài, thông tin cổng màn hình ở byte thấp hơn và Extended Display IDentification
Data
ở các bit trên.
IAutomotiveDisplayProxyService::getDisplayIdList()
trả về danh sách mã màn hình của màn hình cục bộ thực tế, có sẵn cho dịch vụ EVS, và IEvsEnumerator::getDisplayIdList()
trả về danh sách cổng màn hình mà màn hình được phát hiện được kết nối. Mã nhận dạng đầu tiên trong danh sách luôn là màn hình chính.
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);
};
Mở thiết bị hiển thị mục tiêu
Ứng dụng EVS gọi IEvsEnumerator::openDisplay_1_1() với số cổng màn hình mục tiêu:
android::sp<IEvsDisplay> pDisplay = pEvs->openDisplay_1_1(displayId);
if (pDisplay.get() == nullptr) {
LOG(ERROR) << "EVS Display unavailable. Exiting.";
return 1;
}
Lưu ý: Bạn chỉ có thể sử dụng một màn hình tại một thời điểm, nghĩa là ứng dụng EVS hiện tại sẽ mất màn hình khi một ứng dụng EVS khác yêu cầu mở màn hình, ngay cả khi chúng không giống nhau.
Nội dung và mã mẫu trên trang này phải tuân thủ các giấy phép như mô tả trong phần Giấy phép nội dung. Java và OpenJDK là nhãn hiệu hoặc nhãn hiệu đã đăng ký của Oracle và/hoặc đơn vị liên kết của Oracle.
Cập nhật lần gần đây nhất: 2025-08-08 UTC.
[[["Dễ hiểu","easyToUnderstand","thumb-up"],["Giúp tôi giải quyết được vấn đề","solvedMyProblem","thumb-up"],["Khác","otherUp","thumb-up"]],[["Thiếu thông tin tôi cần","missingTheInformationINeed","thumb-down"],["Quá phức tạp/quá nhiều bước","tooComplicatedTooManySteps","thumb-down"],["Đã lỗi thời","outOfDate","thumb-down"],["Vấn đề về bản dịch","translationIssue","thumb-down"],["Vấn đề về mẫu/mã","samplesCodeIssue","thumb-down"],["Khác","otherDown","thumb-down"]],["Cập nhật lần gần đây nhất: 2025-08-08 UTC."],[],[],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."]]