Dịch vụ proxy hiển thị ô tô

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 triển khai HAL mà không cần liên kết libgui. AOSP cung cấp cách triển khai mặc định của dịch vụ này với đầy đủ chức năng. Tuy nhiên, nhà cung cấp cũng phải triển khai 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);
}

Để sử dụng dịch vụ này:

  1. Nhận IAutomotiveDisplayProxyService .
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. 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;
    });
    
  3. Truy xuất phần cứng IGraphicBufferProducer (hoặc HIDL GraphicBufferProducer (HGBP) từ IAutomotiveDisplayProxyService :
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. Nhận SurfaceHolder từ HGBP được 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;
    }
    
  5. 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;
    }
    
  6. Tạo bề mặt cửa sổ EGL bằng cửa sổ gốc rồi hiển thị:
    // 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. Gọi IAutomotiveDisplayProxyService::showWindow() để hiển thị chế độ xem được hiển thị trên màn hình. Dịch vụ này có mức độ ưu tiên cao nhất và do đó luôn chiếm quyền kiểm soát màn hình từ chủ sở hữu hiện tại:
    mAutomotiveDisplayProxyService->showWindow();
    

Xem service.cppGlWrapper.cpp trong $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ để biết thêm chi tiết triển khai.

Việc triển khai EVS HAL yêu cầu các thư viện bổ sung được 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ợ đa màn hình

Hiển thị liệt kê thiết bị và truy xuất thông tin hiển thị

Giống như việc liệt kê thiết bị máy ảnh, khung EVS cung cấp một phương pháp để liệt kê các màn hình có sẵn. Mã định danh hiển thị tĩnh mã hóa mã định danh có độ dài loại, thông tin cổng hiển thị ở byte dưới và Extended Display IDentification Data ở bit trên. IAutomotiveDisplayProxyService::getDisplayIdList() trả về danh sách ID hiển thị của màn hình vật lý cục bộ, có sẵn cho dịch vụ EVS và IEvsEnumerator::getDisplayIdList() trả về danh sách các cổng hiển thị được phát hiện mà màn hình được kết nối. ID đầu tiên trong danh sách luôn hiển thị 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 hiển thị 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 ý: Chỉ có thể sử dụng một màn hình tại một thời điểm, điều đó có nghĩa là máy khách EVS hiện tại sẽ mất màn hình khi máy khách EVS khác yêu cầu mở màn hình, ngay cả khi chúng không giống nhau.