Layanan Proksi Tampilan Otomotif

Layanan kerangka kerja baru yang sederhana ini disediakan untuk memungkinkan proses vendor menggunakan SurfaceFlinger/EGL dalam implementasi HAL, tanpa menautkan libgui. AOSP menyediakan implementasi default dari layanan ini, yang berfungsi penuh. Namun, vendor juga harus mengimplementasikan API untuk menyediakan layanan ini di platform mereka.

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

Untuk menggunakan layanan ini:

  1. Dapatkan IAutomotiveDisplayProxyService .
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. Ambil informasi tampilan aktif dari layanan untuk menentukan resolusi.
    // We will 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. Ambil perangkat keras IGraphicBufferProducer (atau, HIDL GraphicBufferProducer (HGBP) dari IAutomotiveDisplayProxyService : l10n
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. Dapatkan SurfaceHolder dari HGBP yang diambil, dengan menggunakan API libbufferqueueconverter : l10n
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. Ubah SurfaceHolder menjadi jendela asli dengan menggunakan API libbufferqueueconverter : l10n
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
    
  6. Buat permukaan jendela EGL dengan jendela asli dan kemudian render:
    // 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. Panggil IAutomotiveDisplayProxyService::showWindow() untuk menampilkan tampilan yang dirender di layar. Layanan ini memiliki prioritas tertinggi dan, oleh karena itu, selalu mengendalikan layar dari pemilik saat ini:
    mAutomotiveDisplayProxyService->showWindow();
    

Lihat service.cpp dan GlWrapper.cpp di $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ untuk detail implementasi lebih lanjut.

Implementasi EVS HAL memerlukan pustaka tambahan yang ditampilkan dalam huruf tebal di bawah ini.

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

Dukungan Multi-Tampilan

Tampilkan Enumerasi Perangkat dan Ambil Informasi Tampilan

Seperti enumerasi perangkat kamera, kerangka EVS menyediakan metode untuk menghitung tampilan yang tersedia. Pengidentifikasi tampilan statis mengkodekan pengidentifikasi tipe-panjang, informasi port tampilan dalam byte yang lebih rendah dan Extended Display IDentification Data dalam bit atas. IAutomotiveDisplayProxyService::getDisplayIdList() mengembalikan daftar ID tampilan dari tampilan lokal fisik, yang tersedia untuk layanan EVS, dan IEvsEnumerator::getDisplayIdList() mengembalikan daftar port tampilan yang terhubung dengan tampilan yang terdeteksi. ID pertama dalam daftar selalu merupakan tampilan utama.

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

Buka Perangkat Tampilan Target

Aplikasi EVS memanggil IevsEnumerator::openDisplay_1_1() dengan nomor port tampilan target:

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

Catatan: Hanya satu tampilan yang dapat digunakan pada satu waktu, yang berarti klien EVS saat ini kehilangan tampilannya saat klien EVS lain meminta untuk membuka tampilan, meskipun tampilannya tidak sama.