שירות פרוקסי לתצוגה לרכב

שירות המסגרת הפשוט הזה מאפשר לתהליכי ספק להשתמש ב- SurfaceFlinger/EGL ביישומי HAL, מבלי לקשר את 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);
}

כדי להשתמש בשירות זה:

  1. קבל את IAutomotiveDisplayProxyService .
    android::sp<IAutomotiveDisplayProxyService> windowProxyService =
        IAutomotiveDisplayProxyService::getService("default");
    if (windowProxyService == nullptr) {
        LOG(ERROR) << "Cannot use AutomotiveDisplayProxyService. Exiting.";
        return 1;
    }
    
  2. אחזר מידע תצוגה פעיל מהשירות כדי לקבוע את הרזולוציה.
    // 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. אחזר IGraphicBufferProducer חומרה (או, HIDL GraphicBufferProducer (HGBP) מ- IAutomotiveDisplayProxyService :
    mGfxBufferProducer = pWindowProxy->getIGraphicBufferProducer(displayId);
    if (mGfxBufferProducer == nullptr) {
        LOG(ERROR) << "Failed to get IGraphicBufferProducer from "
                   << "IAutomotiveDisplayProxyService.";
        return false;
    }
    
  4. קבל SurfaceHolder מ-HGBP שאוחזר, על ידי שימוש בממיר ה-API libbufferqueueconverter :
    mSurfaceHolder = getSurfaceFromHGBP(mGfxBufferProducer);
    if (mSurfaceHolder == nullptr) {
        LOG(ERROR) << "Failed to get a Surface from HGBP.";
        return false;
    }
    
  5. המר SurfaceHolder לחלון מקורי על ידי שימוש בממיר ה-API libbufferqueueconverter :
    mWindow = getNativeWindow(mSurfaceHolder.get());
    if (mWindow == nullptr) {
        LOG(ERROR) << "Failed to get a native window from Surface.";
        return false;
    }
    
  6. צור משטח חלון EGL עם חלון מקורי ולאחר מכן עבד:
    // 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. התקשר ל- IAutomotiveDisplayProxyService::showWindow() כדי להציג את התצוגה המעובדת על המסך. לשירות זה יש את העדיפות הגבוהה ביותר, ולכן, תמיד לוקח את השליטה על המסך מהבעלים הנוכחי:
    mAutomotiveDisplayProxyService->showWindow();
    

ראה service.cpp ו- GlWrapper.cpp ב- $ANDROID_BUILD_TOP/packages/services/Car/evs/sampleDriver/ לפרטי הטמעה נוספים.

יישום 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, ו- IEvsEnumerator::getDisplayIdList() מחזירה רשימה של יציאות תצוגה שזוהו שתצוגות מחוברות אליהן. המזהה הראשון ברשימה הוא תמיד של התצוגה הראשית.

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 אחר מבקש לפתוח את התצוגה, גם כשהם אינם זהים.