שירות proxy למסך של כלי רכב

שירות framework פשוט זה מאפשר לספק בתהליכי שימוש ב-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 לחלון מקורי באמצעות libbufferqueueconverter ב-API:
    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, נדרשות ספריות נוספות שמוצגות bold למטה.

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

תמיכה בתצוגה מרובת מסכים

הצגה של מספר המכשירים ואחזור של פרטי התצוגה

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