Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 249e1f25 authored by Jayant Chowdhary's avatar Jayant Chowdhary
Browse files

Add an llndk api to get a native handle corresponding to ANativeWindow in AImageReader.



Since vendor modules sometimes might need to transfer ANativeWindow(specific to
AImageReader) over hidl to system processes, here, we introduce an llndk
function to convert the ANativeWindow owned by AImageReader into a
native_handle_t which may be transported over hwbinder.

We also introduce a platform only api to retrieve an HIDL
IGraphicBufferProducer from the handle received.

Bug: 110364143

Test: mm -j64
Test: AImageReaderWindowHandleTest

Change-Id: I5f2aec41d9c67c619413c02e48cd97933e3b2986
Signed-off-by: default avatarJayant Chowdhary <jchowdhary@google.com>
parent 1e91e0ea
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@ cc_library_shared {
    vndk: {
        enabled: true,
    },

    double_loadable: true,
    srcs: [
        "Conversion.cpp",
        "FrameDropper.cpp",
+29 −2
Original line number Diff line number Diff line
@@ -57,7 +57,6 @@ cc_library_shared {
    cflags: [
        "-fvisibility=hidden",
        "-DEXPORT=__attribute__((visibility(\"default\")))",

        "-Werror",
        "-Wall",
    ],
@@ -67,6 +66,8 @@ cc_library_shared {
    ],

    shared_libs: [
        "android.hardware.graphics.bufferqueue@1.0",
        "android.hidl.token@1.0-utils",
        "libbinder",
        "libmedia",
        "libmedia_omx",
@@ -75,12 +76,15 @@ cc_library_shared {
        "libmediaextractor",
        "libstagefright",
        "libstagefright_foundation",
        "libstagefright_bufferqueue_helper",
        "liblog",
        "libutils",
        "libcutils",
        "libandroid",
        "libandroid_runtime",
        "libbinder",
        "libhwbinder",
        "libhidlbase",
        "libgui",
        "libui",
        "libmedia2_jni_core",
@@ -99,7 +103,9 @@ cc_library_shared {
llndk_library {
    name: "libmediandk",
    symbol_file: "libmediandk.map.txt",
    export_include_dirs: ["include"],
    export_include_dirs: [
        "include",
    ],
}

cc_library {
@@ -143,3 +149,24 @@ cc_library {
        },
    },
}

cc_test {
    name: "AImageReaderWindowHandleTest",
    srcs: ["tests/AImageReaderWindowHandleTest.cpp"],
    shared_libs: [
        "libbinder",
        "libmediandk",
        "libnativewindow",
        "libgui",
        "libutils",
        "libui",
        "libcutils",
        "android.hardware.graphics.bufferqueue@1.0",
    ],
    cflags: [
        "-D__ANDROID_VNDK__",
    ],
    include_dirs: [
        "frameworks/av/media/ndk/",
    ],
}
+98 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <android_runtime/android_view_Surface.h>
#include <android_runtime/android_hardware_HardwareBuffer.h>
#include <grallocusage/GrallocUsageConversion.h>
#include <media/stagefright/bqhelper/WGraphicBufferProducer.h>

using namespace android;

@@ -43,6 +44,10 @@ const char* AImageReader::kCallbackFpKey = "Callback";
const char* AImageReader::kContextKey    = "Context";
const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";

static constexpr int kWindowHalTokenSizeMax = 256;

static native_handle_t *convertHalTokenToNativeHandle(const HalToken &halToken);

bool
AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
    // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
@@ -363,6 +368,15 @@ AImageReader::~AImageReader() {
        mBufferItemConsumer->abandon();
        mBufferItemConsumer->setFrameAvailableListener(nullptr);
    }

    if (mWindowHandle != nullptr) {
        int size = mWindowHandle->data[0];
        hidl_vec<uint8_t> halToken;
        halToken.setToExternal(
            reinterpret_cast<uint8_t *>(&mWindowHandle->data[1]), size);
        deleteHalToken(halToken);
        native_handle_delete(mWindowHandle);
    }
}

media_status_t
@@ -522,6 +536,25 @@ AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
    }
}

media_status_t AImageReader::getWindowNativeHandle(native_handle **handle) {
    if (mWindowHandle != nullptr) {
        *handle = mWindowHandle;
        return AMEDIA_OK;
    }
    sp<HGraphicBufferProducer> hgbp =
        new TWGraphicBufferProducer<HGraphicBufferProducer>(mProducer);
    HalToken halToken;
    if (!createHalToken(hgbp, &halToken)) {
        return AMEDIA_ERROR_UNKNOWN;
    }
    mWindowHandle = convertHalTokenToNativeHandle(halToken);
    if (!mWindowHandle) {
        return AMEDIA_ERROR_UNKNOWN;
    }
    *handle = mWindowHandle;
    return AMEDIA_OK;
}

int
AImageReader::getBufferWidth(BufferItem* buffer) {
    if (buffer == NULL) return -1;
@@ -585,6 +618,58 @@ AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFence
    }
}

static native_handle_t *convertHalTokenToNativeHandle(
        const HalToken &halToken) {
    // We attempt to store halToken in the ints of the native_handle_t after its
    // size. The first int stores the size of the token. We store this in an int
    // to avoid alignment issues where size_t and int do not have the same
    // alignment.
    size_t nhDataByteSize = halToken.size();
    if (nhDataByteSize > kWindowHalTokenSizeMax) {
        // The size of the token isn't reasonable..
        return nullptr;
    }
    size_t numInts = ceil(nhDataByteSize / sizeof(int)) + 1;

    // We don't check for overflow, whether numInts can fit in an int, since we
    // expect kWindowHalTokenSizeMax to be a reasonable limit.
    // create a native_handle_t with 0 numFds and numInts number of ints.
    native_handle_t *nh =
        native_handle_create(0, numInts);
    if (!nh) {
        return nullptr;
    }
    // Store the size of the token in the first int.
    nh->data[0] = nhDataByteSize;
    memcpy(&(nh->data[1]), halToken.data(), nhDataByteSize);
    return nh;
}

static sp<HGraphicBufferProducer> convertNativeHandleToHGBP (
        const native_handle_t *handle) {
    // Read the size of the halToken vec<uint8_t>
    hidl_vec<uint8_t> halToken;
    halToken.setToExternal(
        reinterpret_cast<uint8_t *>(const_cast<int *>(&(handle->data[1]))),
        handle->data[0]);
    sp<HGraphicBufferProducer> hgbp =
        HGraphicBufferProducer::castFrom(retrieveHalInterface(halToken));
    return hgbp;
}

EXPORT
sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(
    const native_handle_t *handle) {
    if (handle == nullptr) {
        return nullptr;
    }
    if (handle->numFds != 0  ||
        handle->numInts < ceil(sizeof(size_t) / sizeof(int))) {
        return nullptr;
    }
    return convertNativeHandleToHGBP(handle);
}

EXPORT
media_status_t AImageReader_new(
        int32_t width, int32_t height, int32_t format, int32_t maxImages,
@@ -594,6 +679,19 @@ media_status_t AImageReader_new(
            width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
}

extern "C" {

EXPORT
media_status_t AImageReader_getWindowNativeHandle(
        AImageReader *reader, /*out*/native_handle_t **handle) {
    if (reader == nullptr || handle == nullptr) {
        return AMEDIA_ERROR_INVALID_PARAMETER;
    }
    return reader->getWindowNativeHandle(handle);
}

} //extern "C"

EXPORT
media_status_t AImageReader_newWithUsage(
        int32_t width, int32_t height, int32_t format, uint64_t usage,
+9 −0
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ struct AImageReader : public RefBase {
    media_status_t acquireNextImage(/*out*/AImage** image, /*out*/int* fenceFd);
    media_status_t acquireLatestImage(/*out*/AImage** image, /*out*/int* fenceFd);

    media_status_t getWindowNativeHandle(/*out*/native_handle_t **handle);

    ANativeWindow* getWindow()    const { return mWindow.get(); };
    int32_t        getWidth()     const { return mWidth; };
    int32_t        getHeight()    const { return mHeight; };
@@ -160,10 +162,17 @@ struct AImageReader : public RefBase {
    sp<Surface>                mSurface;
    sp<BufferItemConsumer>     mBufferItemConsumer;
    sp<ANativeWindow>          mWindow;
    native_handle_t*           mWindowHandle = nullptr;

    List<AImage*>              mAcquiredImages;

    Mutex                      mLock;
};

// Retrieves HGraphicBufferProducer corresponding to the native_handle_t
// provided. This method also deletes the HalToken corresponding to the
// native_handle_t. Thus, if it is used twice in succession, the second call
// returns nullptr;
sp<HGraphicBufferProducer> AImageReader_getHGBPFromHandle(const native_handle_t *handle);

#endif // _NDK_IMAGE_READER_PRIV_H
+20 −0
Original line number Diff line number Diff line
@@ -37,6 +37,9 @@
#define _NDK_IMAGE_READER_H

#include <sys/cdefs.h>
#ifdef __ANDROID_VNDK__
#include <cutils/native_handle.h>
#endif

#include <android/native_window.h>
#include "NdkMediaError.h"
@@ -461,6 +464,23 @@ typedef struct AImageReader_BufferRemovedListener {
media_status_t AImageReader_setBufferRemovedListener(
        AImageReader* reader, AImageReader_BufferRemovedListener* listener) __INTRODUCED_IN(26);

#ifdef __ANDROID_VNDK__
/*
 * Get the native_handle_t corresponding to the ANativeWindow owned by the
 * AImageReader provided.
 *
 * @param reader The image reader of interest.
 * @param handle The output native_handle_t. This native handle is owned by
 *               this image reader.
 *
 * @return AMEDIA_OK if the method call succeeds.
 *         AMEDIA_ERROR_INVALID_PARAMETER if reader or handle are NULL.
 *         AMEDIA_ERROR_UNKNOWN if some other error is encountered.
 */
media_status_t AImageReader_getWindowNativeHandle(
    AImageReader *reader, /* out */native_handle_t **handle);
#endif

#endif /* __ANDROID_API__ >= 26 */

__END_DECLS
Loading