graphics: revise gralloc interfaces
Revise IAllocator and IMapper to reduce IPC and to support gralloc0
devices.
Specifically, IAllocator is trimmed down to have essentially only
allocate(BufferDescriptor descriptor, uint32_t count)
generates (Error error,
uint32_t stride,
vec<handle> buffers);
The ability to allocate buffers with shared backing store is
removed. ProducerUsage and ConsumerUsage are moved to the
graphics.common package and are merged and renamed to BufferUsage.
BufferUsage's bits follow gralloc0.
IMapper gains
typedef vec<uint32_t> BufferDescriptor;
createDescriptor(BufferDescriptorInfo descriptorInfo)
generates (Error error,
BufferDescriptor descriptor);
where BufferDescriptor is an implementation-defined blob. lockFlex
is replaced by lockYCbCr. All getters are removed.
Reference counting with retain/release is replaced by
importBuffer/freeBuffer.
Most if not all gralloc1 features are not used by the runtime yet.
There is also not too much test written for them. As such, they
tend to behave differently between implementations and cannot be
used reliably.
Bug: 36481301
Test: builds and boots on Pixel
Change-Id: I1d31105120517ea2c128c7a19297acf3bfd312bb
diff --git a/graphics/mapper/2.0/Android.bp b/graphics/mapper/2.0/Android.bp
index 98a509b..cc2bd73 100644
--- a/graphics/mapper/2.0/Android.bp
+++ b/graphics/mapper/2.0/Android.bp
@@ -51,7 +51,6 @@
"liblog",
"libutils",
"libcutils",
- "android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
@@ -60,7 +59,6 @@
"libhidltransport",
"libhwbinder",
"libutils",
- "android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
diff --git a/graphics/mapper/2.0/IMapper.hal b/graphics/mapper/2.0/IMapper.hal
index 573dcd0..246be24 100644
--- a/graphics/mapper/2.0/IMapper.hal
+++ b/graphics/mapper/2.0/IMapper.hal
@@ -16,10 +16,39 @@
package android.hardware.graphics.mapper@2.0;
-import android.hardware.graphics.common@1.0::PixelFormat;
-import android.hardware.graphics.allocator@2.0;
+import android.hardware.graphics.common@1.0;
interface IMapper {
+ struct BufferDescriptorInfo {
+ /**
+ * The width specifies how many columns of pixels must be in the
+ * allocated buffer, but does not necessarily represent the offset in
+ * columns between the same column in adjacent rows. The rows may be
+ * padded.
+ */
+ uint32_t width;
+
+ /**
+ * The height specifies how many rows of pixels must be in the
+ * allocated buffer.
+ */
+ uint32_t height;
+
+ /**
+ * The number of image layers that must be in the allocated buffer.
+ */
+ uint32_t layerCount;
+
+ /** Buffer pixel format. */
+ PixelFormat format;
+
+ /**
+ * Buffer usage mask; valid flags can be found in the definition of
+ * BufferUsage.
+ */
+ bitfield<BufferUsage> usage;
+ };
+
struct Rect {
int32_t left;
int32_t top;
@@ -28,170 +57,76 @@
};
/**
- * Adds a reference to the given buffer handle.
+ * Creates a buffer descriptor. The descriptor can be used with IAllocator
+ * to allocate buffers.
*
- * A buffer handle received from a remote process or exported by
- * IAllocator::exportHandle is unknown to the mapper. There is also no
- * guarantee that the buffer's backing store will stay alive. This
- * function must be called at least once in both cases to intrdouce the
- * buffer handle to the mapper and to secure the backing store. It may
- * also be called more than once to increase the reference count if two
- * components in the same process want to interact with the buffer
- * independently.
+ * Since the buffer descriptor fully describes a buffer, any device
+ * dependent or device independent checks must be performed here whenever
+ * possible. Specifically, when layered buffers are not supported, this
+ * function must return UNSUPPORTED if layerCount is great than 1.
*
- * @param bufferHandle is the buffer to which a reference must be added.
+ * @param descriptorInfo specifies the attributes of the descriptor.
* @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid
- * NO_RESOURCES when it is not possible to add a
- * reference to this buffer at this time
+ * BAD_VALUE when any of the specified attributes is
+ * invalid or conflicting.
+ * NO_RESOURCES when the creation cannot be fullfilled at
+ * this time.
+ * UNSUPPORTED when any of the specified attributes is
+ * not supported.
+ * @return descriptor is the newly created buffer descriptor.
*/
@entry
@callflow(next="*")
- retain(handle bufferHandle) generates (Error error);
+ createDescriptor(BufferDescriptorInfo descriptorInfo)
+ generates (Error error,
+ BufferDescriptor descriptor);
/**
- * Removes a reference from the given buffer buffer.
+ * Imports a raw buffer handle to create an imported buffer handle for use
+ * with the rest of the mapper or with other in-process libraries.
*
- * If no references remain, the buffer handle must be freed with
- * native_handle_close/native_handle_delete by the mapper. When the last
- * buffer handle referring to a particular backing store is freed, that
- * backing store must also be freed.
+ * A buffer handle is considered raw when it is cloned or when it is
+ * received from another HAL or another process. A raw buffer handle must
+ * not be used to access the underlying graphics buffer. It must be
+ * imported to create an imported handle first.
*
- * @param bufferHandle is the buffer from which a reference must be
- * removed.
+ * This function must at least validate the raw handle before creating the
+ * imported handle. It must also support importing the same raw handle
+ * multiple times to create multiple imported handles. The imported handle
+ * must be considered valid everywhere in the process, including in
+ * another instance of the mapper.
+ *
+ * @param rawHandle is the raw buffer handle to import.
* @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
+ * BAD_BUFFER when the raw handle is invalid.
+ * NO_RESOURCES when the raw handle cannot be imported at
+ * this time.
+ * @return buffer is the imported buffer handle and has the type
+ * buffer_handle_t.
+ */
+ @entry
+ @callflow(next="*")
+ importBuffer(handle rawHandle) generates (Error error, pointer buffer);
+
+ /**
+ * Frees a buffer handle. Buffer handles returned by importBuffer must be
+ * freed with this function when no longer needed.
+ *
+ * This function must free up all resources allocated by importBuffer for
+ * the imported handle. For example, if the imported handle was created
+ * with native_handle_create, this function must call native_handle_close
+ * and native_handle_delete.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_BUFFER when the buffer is invalid.
*/
@exit
- release(handle bufferHandle) generates (Error error);
-
- /**
- * Gets the width and height of the buffer in pixels.
- *
- * See IAllocator::BufferDescriptorInfo for more information.
- *
- * @param bufferHandle is the buffer from which to get the dimensions.
- * @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * @return width is the width of the buffer in pixels.
- * @return height is the height of the buffer in pixels.
- */
@callflow(next="*")
- getDimensions(handle bufferHandle)
- generates (Error error,
- uint32_t width,
- uint32_t height);
-
- /**
- * Gets the format of the buffer.
- *
- * See IAllocator::BufferDescriptorInfo for more information.
- *
- * @param bufferHandle is the buffer from which to get format.
- * @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * @return format is the format of the buffer.
- */
- @callflow(next="*")
- getFormat(handle bufferHandle)
- generates (Error error,
- PixelFormat format);
-
- /**
- * Gets the number of layers of the buffer.
- *
- * See IAllocator::BufferDescriptorInfo for more information.
- *
- * @param bufferHandle is the buffer from which to get format.
- * @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * @return layerCount is the number of layers of the buffer.
- */
- @callflow(next="*")
- getLayerCount(handle bufferHandle)
- generates (Error error,
- uint32_t layerCount);
-
- /**
- * Gets the producer usage flags which were used to allocate this buffer.
- *
- * See IAllocator::BufferDescriptorInfo for more information.
- *
- * @param bufferHandle is the buffer from which to get the producer usage
- * flags.
- * @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * @return usageMask contains the producer usage flags of the buffer.
- */
- @callflow(next="*")
- getProducerUsageMask(handle bufferHandle)
- generates (Error error,
- uint64_t usageMask);
-
- /**
- * Gets the consumer usage flags which were used to allocate this buffer.
- *
- * See IAllocator::BufferDescriptorInfo for more information.
- *
- * @param bufferHandle is the buffer from which to get the consumer usage
- * flags.
- * @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * @return usageMask contains the consumer usage flags of the buffer.
- */
- @callflow(next="*")
- getConsumerUsageMask(handle bufferHandle)
- generates (Error error,
- uint64_t usageMask);
-
- /**
- * Gets a value that uniquely identifies the backing store of the given
- * buffer.
- *
- * Buffers which share a backing store should return the same value from
- * this function. If the buffer is present in more than one process, the
- * backing store value for that buffer is not required to be the same in
- * every process.
- *
- * @param device is the mapper device.
- * @param bufferHandle is the buffer from which to get the backing store
- * identifier.
- * @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * @return store is the backing store identifier for this buffer.
- */
- @callflow(next="*")
- getBackingStore(handle bufferHandle)
- generates (Error error,
- BackingStore store);
-
- /**
- * Gets the stride of the buffer in pixels.
- *
- * The stride is the offset in pixel-sized elements between the same
- * column in two adjacent rows of pixels. This may not be equal to the
- * width of the buffer.
- *
- * @param device is the mapper device.
- * @param bufferHandle is the buffer from which to get the stride.
- * @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * UNDEFINED when the notion of a stride is not
- * meaningful for the buffer format.
- * @return store is the stride in pixels.
- */
- @callflow(next="*")
- getStride(handle bufferHandle)
- generates (Error error,
- uint32_t stride);
+ freeBuffer(pointer buffer) generates (Error error);
/**
* Locks the given buffer for the specified CPU usage.
*
- * Exactly one of producerUsageMask and consumerUsageMask must be 0. The
- * usage which is not 0 must be one of the *Usage::CPU* values, as
- * applicable. Locking a buffer for a non-CPU usage is not supported.
- *
* Locking the same buffer simultaneously from multiple threads is
* permitted, but if any of the threads attempt to lock the buffer for
* writing, the behavior is undefined, except that it must not cause
@@ -209,39 +144,27 @@
* address will represent the top-left corner of the entire buffer, even
* if accessRegion does not begin at the top-left corner.
*
- * acquireFence is a file descriptor referring to a acquire sync fence
- * object, which will be signaled when it is safe for the device to access
- * the contents of the buffer (prior to locking). If it is already safe to
- * access the buffer contents, -1 may be passed instead.
- *
- * @param bufferHandle is the buffer to lock.
- * @param producerUsageMask contains the producer usage flags to request;
- * either this or consumerUsagemask must be 0, and the other must
- * be a CPU usage.
- * @param consumerUsageMask contains the consumer usage flags to request;
- * either this or producerUsageMask must be 0, and the other must
- * be a CPU usage.
+ * @param buffer is the buffer to lock.
+ * @param cpuUsage specifies one or more CPU usage flags to request.
* @param accessRegion is the portion of the buffer that the client
* intends to access.
- * @param acquireFence is a sync fence file descriptor as described above.
+ * @param acquireFence, when non-empty, is a handle containing a file
+ * descriptor referring to a sync fence object, which will be
+ * signaled when it is safe for the mapper to lock the buffer. If
+ * it is already safe to lock, acquireFence is empty.
* @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * BAD_VALUE when neither or both of producerUsageMask
- * and consumerUsageMask were 0, or the usage
- * which was not 0 was not a CPU usage.
+ * BAD_BUFFER when the buffer is invalid or is
+ * incompatible with this function.
+ * BAD_VALUE when cpuUsage is 0, contains non-CPU usage
+ * flags, or is incompatible with the buffer.
* NO_RESOURCES when the buffer cannot be locked at this
* time, but locking may succeed at a future
* time.
- * UNSUPPORTED when the buffer cannot be locked with the
- * given usage, and any future attempts at
- * locking will also fail.
- * @return data will be filled with a CPU-accessible pointer to the buffer
- * data.
+ * @return data is a CPU-accessible pointer to the buffer data.
*/
@callflow(next="unlock")
- lock(handle bufferHandle,
- uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
+ lock(pointer buffer,
+ bitfield<BufferUsage> cpuUsage,
Rect accessRegion,
handle acquireFence)
generates (Error error,
@@ -249,7 +172,7 @@
/**
* This is largely the same as lock(), except that instead of returning a
- * pointer directly to the buffer data, it returns an FlexLayout struct
+ * pointer directly to the buffer data, it returns an YCbCrLayout struct
* describing how to access the data planes.
*
* This function must work on buffers with PixelFormat::YCbCr_*_888 if
@@ -257,67 +180,46 @@
* multimedia codecs when they are configured with a
* flexible-YUV-compatible color format.
*
- * This function may also be called on buffers of other formats, including
- * non-YUV formats, but if the buffer format is not compatible with a
- * flexible representation, it may return UNSUPPORTED.
- *
- * @param device is the mapper device.
- * @param bufferHandle is the buffer to lock.
- * @param producerUsageMask contains the producer usage flags to request;
- * either this or consumerUsagemask must be 0, and the other must
- * be a CPU usage.
- * @param consumerUsageMask contains the consumer usage flags to request;
- * either this or producerUsageMask must be 0, and the other must
- * be a CPU usage.
+ * @param buffer is the buffer to lock.
+ * @param cpuUsage specifies one or more CPU usage flags to request.
* @param accessRegion is the portion of the buffer that the client
* intends to access.
- * @param acquireFence is a sync fence file descriptor as described in
- * lock().
+ * @param acquireFence, when non-empty, is a handle containing a file
+ * descriptor referring to a sync fence object, which will be
+ * signaled when it is safe for the mapper to lock the buffer. If
+ * it is already safe to lock, acquireFence is empty.
* @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * BAD_VALUE when neither or both of producerUsageMask
- * and consumerUsageMask were 0, or the usage
- * which was not 0 was not a CPU usage.
+ * BAD_BUFFER when the buffer is invalid or is
+ * incompatible with this function.
+ * BAD_VALUE when cpuUsage is 0, contains non-CPU usage
+ * flags, or is incompatible with the buffer.
* NO_RESOURCES when the buffer cannot be locked at this
* time, but locking may succeed at a future
* time.
- * UNSUPPORTED when the buffer cannot be locked with the
- * given usage, and any future attempts at
- * locking will also fail.
- * @return flexLayout will be filled with the description of the planes in
- * the buffer.
+ * @return layout is the data layout of the buffer.
*/
@callflow(next="unlock")
- lockFlex(handle bufferHandle,
- uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
- Rect accessRegion,
- handle acquireFence)
+ lockYCbCr(pointer buffer,
+ bitfield<BufferUsage> cpuUsage,
+ Rect accessRegion,
+ handle acquireFence)
generates (Error error,
- FlexLayout layout);
+ YCbCrLayout layout);
/**
- * This function indicates to the device that the client will be done with
- * the buffer when releaseFence signals.
+ * Unlocks a buffer to indicate all CPU accesses to the buffer have
+ * completed.
*
- * releaseFence will be filled with a file descriptor referring to a
- * release sync fence object, which will be signaled when it is safe to
- * access the contents of the buffer (after the buffer has been unlocked).
- * If it is already safe to access the buffer contents, then -1 may be
- * returned instead.
- *
- * This function is used to unlock both buffers locked by lock() and those
- * locked by lockFlex().
- *
- * @param device is the mapper device.
- * @param bufferHandle is the buffer to unlock.
+ * @param buffer is the buffer to unlock.
* @return error is NONE upon success. Otherwise,
- * BAD_BUFFER when the buffer handle is invalid.
- * @return releaseFence is a sync fence file descriptor as described
- * above.
+ * BAD_BUFFER when the buffer is invalid or not locked.
+ * @return releaseFence, when non-empty, is a handle containing a file
+ * descriptor referring to a sync fence object. The sync fence
+ * object will be signaled when the mapper has completed any
+ * pending work.
*/
@callflow(next="*")
- unlock(handle bufferHandle)
+ unlock(pointer buffer)
generates (Error error,
handle releaseFence);
};
diff --git a/graphics/mapper/2.0/default/Android.bp b/graphics/mapper/2.0/default/Android.bp
index 1dc5aea..090c61f 100644
--- a/graphics/mapper/2.0/default/Android.bp
+++ b/graphics/mapper/2.0/default/Android.bp
@@ -18,10 +18,9 @@
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
- srcs: ["GrallocMapper.cpp"],
+ srcs: ["GrallocMapper.cpp", "Gralloc0Mapper.cpp", "Gralloc1Mapper.cpp"],
cppflags: ["-Wall", "-Wextra"],
shared_libs: [
- "android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
"libbase",
"libcutils",
@@ -29,6 +28,12 @@
"libhidlbase",
"libhidltransport",
"liblog",
+ "libsync",
"libutils",
],
}
+
+cc_library_static {
+ name: "libgrallocmapperincludes",
+ export_include_dirs: ["."],
+}
diff --git a/graphics/mapper/2.0/default/Gralloc0Mapper.cpp b/graphics/mapper/2.0/default/Gralloc0Mapper.cpp
new file mode 100644
index 0000000..28f5016
--- /dev/null
+++ b/graphics/mapper/2.0/default/Gralloc0Mapper.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Gralloc0Mapper"
+
+#include "Gralloc0Mapper.h"
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace implementation {
+
+Gralloc0Mapper::Gralloc0Mapper(const hw_module_t* module)
+ : mModule(reinterpret_cast<const gralloc_module_t*>(module)),
+ mMinor(module->module_api_version & 0xff) {
+ mCapabilities.highUsageBits = false;
+ mCapabilities.layeredBuffers = false;
+ mCapabilities.unregisterImplyDelete = false;
+}
+
+Error Gralloc0Mapper::registerBuffer(buffer_handle_t bufferHandle) {
+ int result = mModule->registerBuffer(mModule, bufferHandle);
+ return result ? Error::BAD_BUFFER : Error::NONE;
+}
+
+void Gralloc0Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
+ mModule->unregisterBuffer(mModule, bufferHandle);
+}
+
+Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
+ uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ void** outData) {
+ int result;
+ void* data = nullptr;
+ if (mMinor >= 3 && mModule->lockAsync) {
+ // Dup fenceFd as it is going to be owned by gralloc. Note that it is
+ // gralloc's responsibility to close it, even on locking errors.
+ if (fenceFd >= 0) {
+ fenceFd = dup(fenceFd);
+ if (fenceFd < 0) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ result = mModule->lockAsync(mModule, bufferHandle, cpuUsage,
+ accessRegion.left, accessRegion.top,
+ accessRegion.width, accessRegion.height,
+ &data, fenceFd);
+ } else {
+ waitFenceFd(fenceFd, "Gralloc0Mapper::lock");
+
+ result = mModule->lock(mModule, bufferHandle, cpuUsage,
+ accessRegion.left, accessRegion.top,
+ accessRegion.width, accessRegion.height, &data);
+ }
+
+ if (result) {
+ return Error::BAD_VALUE;
+ } else {
+ *outData = data;
+ return Error::NONE;
+ }
+}
+
+Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
+ uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ YCbCrLayout* outLayout) {
+ int result;
+ android_ycbcr ycbcr = {};
+ if (mMinor >= 3 && mModule->lockAsync_ycbcr) {
+ // Dup fenceFd as it is going to be owned by gralloc. Note that it is
+ // gralloc's responsibility to close it, even on locking errors.
+ if (fenceFd >= 0) {
+ fenceFd = dup(fenceFd);
+ if (fenceFd < 0) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ result = mModule->lockAsync_ycbcr(mModule, bufferHandle, cpuUsage,
+ accessRegion.left, accessRegion.top,
+ accessRegion.width,
+ accessRegion.height, &ycbcr, fenceFd);
+ } else {
+ waitFenceFd(fenceFd, "Gralloc0Mapper::lockYCbCr");
+
+ if (mModule->lock_ycbcr) {
+ result = mModule->lock_ycbcr(mModule, bufferHandle, cpuUsage,
+ accessRegion.left, accessRegion.top,
+ accessRegion.width,
+ accessRegion.height, &ycbcr);
+ } else {
+ result = -EINVAL;
+ }
+ }
+
+ if (result) {
+ return Error::BAD_VALUE;
+ } else {
+ outLayout->y = ycbcr.y;
+ outLayout->cb = ycbcr.cb;
+ outLayout->cr = ycbcr.cr;
+ outLayout->yStride = ycbcr.ystride;
+ outLayout->cStride = ycbcr.cstride;
+ outLayout->chromaStep = ycbcr.chroma_step;
+ return Error::NONE;
+ }
+}
+
+Error Gralloc0Mapper::unlockBuffer(buffer_handle_t bufferHandle,
+ int* outFenceFd) {
+ int result;
+ int fenceFd = -1;
+ if (mMinor >= 3 && mModule->unlockAsync) {
+ result = mModule->unlockAsync(mModule, bufferHandle, &fenceFd);
+ } else {
+ result = mModule->unlock(mModule, bufferHandle);
+ }
+
+ if (result) {
+ // we always own the fenceFd even when unlock failed
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+
+ return Error::BAD_VALUE;
+ } else {
+ *outFenceFd = fenceFd;
+ return Error::NONE;
+ }
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/2.0/default/Gralloc0Mapper.h b/graphics/mapper/2.0/default/Gralloc0Mapper.h
new file mode 100644
index 0000000..e792a69
--- /dev/null
+++ b/graphics/mapper/2.0/default/Gralloc0Mapper.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
+#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
+
+#include "GrallocMapper.h"
+
+#include <hardware/gralloc.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace implementation {
+
+class Gralloc0Mapper : public GrallocMapper {
+ public:
+ Gralloc0Mapper(const hw_module_t* module);
+
+ private:
+ Error registerBuffer(buffer_handle_t bufferHandle) override;
+ void unregisterBuffer(buffer_handle_t bufferHandle) override;
+ Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ void** outData) override;
+ Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ YCbCrLayout* outLayout) override;
+ Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
+
+ const gralloc_module_t* mModule;
+ uint8_t mMinor;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
diff --git a/graphics/mapper/2.0/default/Gralloc1Mapper.cpp b/graphics/mapper/2.0/default/Gralloc1Mapper.cpp
new file mode 100644
index 0000000..c1e5adc
--- /dev/null
+++ b/graphics/mapper/2.0/default/Gralloc1Mapper.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Gralloc1Mapper"
+
+#include "Gralloc1Mapper.h"
+
+#include <vector>
+
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace implementation {
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+
+Gralloc1Mapper::Gralloc1Mapper(const hw_module_t* module)
+ : mDevice(nullptr), mDispatch() {
+ int result = gralloc1_open(module, &mDevice);
+ if (result) {
+ LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
+ strerror(-result));
+ }
+
+ initCapabilities();
+ initDispatch();
+}
+
+Gralloc1Mapper::~Gralloc1Mapper() {
+ gralloc1_close(mDevice);
+}
+
+void Gralloc1Mapper::initCapabilities() {
+ mCapabilities.highUsageBits = true;
+ mCapabilities.layeredBuffers = false;
+ mCapabilities.unregisterImplyDelete = false;
+
+ uint32_t count = 0;
+ mDevice->getCapabilities(mDevice, &count, nullptr);
+
+ std::vector<int32_t> capabilities(count);
+ mDevice->getCapabilities(mDevice, &count, capabilities.data());
+ capabilities.resize(count);
+
+ for (auto capability : capabilities) {
+ switch (capability) {
+ case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
+ mCapabilities.layeredBuffers = true;
+ break;
+ case GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE:
+ mCapabilities.unregisterImplyDelete = true;
+ break;
+ }
+ }
+}
+
+template <typename T>
+void Gralloc1Mapper::initDispatch(gralloc1_function_descriptor_t desc,
+ T* outPfn) {
+ auto pfn = mDevice->getFunction(mDevice, desc);
+ if (!pfn) {
+ LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
+ }
+
+ *outPfn = reinterpret_cast<T>(pfn);
+}
+
+void Gralloc1Mapper::initDispatch() {
+ initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain);
+ initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
+ initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES,
+ &mDispatch.getNumFlexPlanes);
+ initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock);
+ initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex);
+ initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock);
+}
+
+Error Gralloc1Mapper::toError(int32_t error) {
+ switch (error) {
+ case GRALLOC1_ERROR_NONE:
+ return Error::NONE;
+ case GRALLOC1_ERROR_BAD_DESCRIPTOR:
+ return Error::BAD_DESCRIPTOR;
+ case GRALLOC1_ERROR_BAD_HANDLE:
+ return Error::BAD_BUFFER;
+ case GRALLOC1_ERROR_BAD_VALUE:
+ return Error::BAD_VALUE;
+ case GRALLOC1_ERROR_NOT_SHARED:
+ return Error::NONE; // this is fine
+ case GRALLOC1_ERROR_NO_RESOURCES:
+ return Error::NO_RESOURCES;
+ case GRALLOC1_ERROR_UNDEFINED:
+ case GRALLOC1_ERROR_UNSUPPORTED:
+ default:
+ return Error::UNSUPPORTED;
+ }
+}
+
+bool Gralloc1Mapper::toYCbCrLayout(const android_flex_layout& flex,
+ YCbCrLayout* outLayout) {
+ // must be YCbCr
+ if (flex.format != FLEX_FORMAT_YCbCr || flex.num_planes < 3) {
+ return false;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ const auto& plane = flex.planes[i];
+ // must have 8-bit depth
+ if (plane.bits_per_component != 8 || plane.bits_used != 8) {
+ return false;
+ }
+
+ if (plane.component == FLEX_COMPONENT_Y) {
+ // Y must not be interleaved
+ if (plane.h_increment != 1) {
+ return false;
+ }
+ } else {
+ // Cb and Cr can be interleaved
+ if (plane.h_increment != 1 && plane.h_increment != 2) {
+ return false;
+ }
+ }
+
+ if (!plane.v_increment) {
+ return false;
+ }
+ }
+
+ if (flex.planes[0].component != FLEX_COMPONENT_Y ||
+ flex.planes[1].component != FLEX_COMPONENT_Cb ||
+ flex.planes[2].component != FLEX_COMPONENT_Cr) {
+ return false;
+ }
+
+ const auto& y = flex.planes[0];
+ const auto& cb = flex.planes[1];
+ const auto& cr = flex.planes[2];
+
+ if (cb.h_increment != cr.h_increment || cb.v_increment != cr.v_increment) {
+ return false;
+ }
+
+ outLayout->y = y.top_left;
+ outLayout->cb = cb.top_left;
+ outLayout->cr = cr.top_left;
+ outLayout->yStride = y.v_increment;
+ outLayout->cStride = cb.v_increment;
+ outLayout->chromaStep = cb.h_increment;
+
+ return true;
+}
+
+gralloc1_rect_t Gralloc1Mapper::asGralloc1Rect(const IMapper::Rect& rect) {
+ return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
+}
+
+Error Gralloc1Mapper::registerBuffer(buffer_handle_t bufferHandle) {
+ return toError(mDispatch.retain(mDevice, bufferHandle));
+}
+
+void Gralloc1Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
+ mDispatch.release(mDevice, bufferHandle);
+}
+
+Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
+ uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ void** outData) {
+ // Dup fenceFd as it is going to be owned by gralloc. Note that it is
+ // gralloc's responsibility to close it, even on locking errors.
+ if (fenceFd >= 0) {
+ fenceFd = dup(fenceFd);
+ if (fenceFd < 0) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ const uint64_t consumerUsage =
+ cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
+ const auto accessRect = asGralloc1Rect(accessRegion);
+ void* data = nullptr;
+ int32_t error = mDispatch.lock(mDevice, bufferHandle, cpuUsage,
+ consumerUsage, &accessRect, &data, fenceFd);
+
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outData = data;
+ }
+
+ return toError(error);
+}
+
+Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
+ uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ YCbCrLayout* outLayout) {
+ // prepare flex layout
+ android_flex_layout flex = {};
+ int32_t error =
+ mDispatch.getNumFlexPlanes(mDevice, bufferHandle, &flex.num_planes);
+ if (error != GRALLOC1_ERROR_NONE) {
+ return toError(error);
+ }
+ std::vector<android_flex_plane_t> flexPlanes(flex.num_planes);
+ flex.planes = flexPlanes.data();
+
+ // Dup fenceFd as it is going to be owned by gralloc. Note that it is
+ // gralloc's responsibility to close it, even on locking errors.
+ if (fenceFd >= 0) {
+ fenceFd = dup(fenceFd);
+ if (fenceFd < 0) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ const uint64_t consumerUsage =
+ cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
+ const auto accessRect = asGralloc1Rect(accessRegion);
+ error = mDispatch.lockFlex(mDevice, bufferHandle, cpuUsage, consumerUsage,
+ &accessRect, &flex, fenceFd);
+ if (error == GRALLOC1_ERROR_NONE && !toYCbCrLayout(flex, outLayout)) {
+ ALOGD("unable to convert android_flex_layout to YCbCrLayout");
+
+ // undo the lock
+ fenceFd = -1;
+ mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
+
+ error = GRALLOC1_ERROR_BAD_HANDLE;
+ }
+
+ return toError(error);
+}
+
+Error Gralloc1Mapper::unlockBuffer(buffer_handle_t bufferHandle,
+ int* outFenceFd) {
+ int fenceFd = -1;
+ int32_t error = mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
+
+ if (error == GRALLOC1_ERROR_NONE) {
+ *outFenceFd = fenceFd;
+ } else if (fenceFd >= 0) {
+ // we always own the fenceFd even when unlock failed
+ close(fenceFd);
+ }
+
+ return toError(error);
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/2.0/default/Gralloc1Mapper.h b/graphics/mapper/2.0/default/Gralloc1Mapper.h
new file mode 100644
index 0000000..452afdf
--- /dev/null
+++ b/graphics/mapper/2.0/default/Gralloc1Mapper.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ * * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
+#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
+
+#include "GrallocMapper.h"
+
+#include <hardware/gralloc1.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace implementation {
+
+class Gralloc1Mapper : public GrallocMapper {
+ public:
+ Gralloc1Mapper(const hw_module_t* module);
+ ~Gralloc1Mapper();
+
+ private:
+ void initCapabilities();
+
+ template <typename T>
+ void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
+ void initDispatch();
+
+ static Error toError(int32_t error);
+ static bool toYCbCrLayout(const android_flex_layout& flex,
+ YCbCrLayout* outLayout);
+ static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect);
+
+ Error registerBuffer(buffer_handle_t bufferHandle) override;
+ void unregisterBuffer(buffer_handle_t bufferHandle) override;
+ Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ void** outData) override;
+ Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ YCbCrLayout* outLayout) override;
+ Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
+
+ gralloc1_device_t* mDevice;
+
+ struct {
+ GRALLOC1_PFN_RETAIN retain;
+ GRALLOC1_PFN_RELEASE release;
+ GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
+ GRALLOC1_PFN_LOCK lock;
+ GRALLOC1_PFN_LOCK_FLEX lockFlex;
+ GRALLOC1_PFN_UNLOCK unlock;
+ } mDispatch;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
diff --git a/graphics/mapper/2.0/default/GrallocBufferDescriptor.h b/graphics/mapper/2.0/default/GrallocBufferDescriptor.h
new file mode 100644
index 0000000..9b5ab04
--- /dev/null
+++ b/graphics/mapper/2.0/default/GrallocBufferDescriptor.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
+#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
+
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V2_0 {
+namespace implementation {
+
+using android::hardware::graphics::common::V1_0::PixelFormat;
+
+/**
+ * BufferDescriptor is created by IMapper and consumed by IAllocator. It is
+ * versioned so that IMapper and IAllocator can be updated independently.
+ */
+constexpr uint32_t grallocBufferDescriptorSize = 7;
+constexpr uint32_t grallocBufferDescriptorMagicVersion = ((0x9487 << 16) | 0);
+
+inline BufferDescriptor grallocEncodeBufferDescriptor(
+ const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ BufferDescriptor descriptor;
+ descriptor.resize(grallocBufferDescriptorSize);
+ descriptor[0] = grallocBufferDescriptorMagicVersion;
+ descriptor[1] = descriptorInfo.width;
+ descriptor[2] = descriptorInfo.height;
+ descriptor[3] = descriptorInfo.layerCount;
+ descriptor[4] = static_cast<uint32_t>(descriptorInfo.format);
+ descriptor[5] = static_cast<uint32_t>(descriptorInfo.usage);
+ descriptor[6] = static_cast<uint32_t>(descriptorInfo.usage >> 32);
+
+ return descriptor;
+}
+
+inline bool grallocDecodeBufferDescriptor(
+ const BufferDescriptor& descriptor,
+ IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+ if (descriptor.size() != grallocBufferDescriptorSize ||
+ descriptor[0] != grallocBufferDescriptorMagicVersion) {
+ return false;
+ }
+
+ *outDescriptorInfo = IMapper::BufferDescriptorInfo{
+ descriptor[1],
+ descriptor[2],
+ descriptor[3],
+ static_cast<PixelFormat>(descriptor[4]),
+ (static_cast<uint64_t>(descriptor[6]) << 32) | descriptor[5],
+ };
+
+ return true;
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
diff --git a/graphics/mapper/2.0/default/GrallocMapper.cpp b/graphics/mapper/2.0/default/GrallocMapper.cpp
index 526aca2..339317a 100644
--- a/graphics/mapper/2.0/default/GrallocMapper.cpp
+++ b/graphics/mapper/2.0/default/GrallocMapper.cpp
@@ -17,14 +17,14 @@
#include "GrallocMapper.h"
-#include <mutex>
-#include <vector>
-#include <unordered_map>
+#include "Gralloc0Mapper.h"
+#include "Gralloc1Mapper.h"
+#include "GrallocBufferDescriptor.h"
-#include <string.h>
+#include <inttypes.h>
-#include <hardware/gralloc1.h>
#include <log/log.h>
+#include <sync/sync.h>
namespace android {
namespace hardware {
@@ -33,374 +33,251 @@
namespace V2_0 {
namespace implementation {
-namespace {
-
-using android::hardware::graphics::allocator::V2_0::Error;
+using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::PixelFormat;
-class GrallocMapperHal : public IMapper {
-public:
- GrallocMapperHal(const hw_module_t* module);
- ~GrallocMapperHal();
+std::mutex GrallocMapper::mMutex;
+std::unordered_set<buffer_handle_t> GrallocMapper::mRegisteredHandles;
- // IMapper interface
- Return<Error> retain(const hidl_handle& bufferHandle) override;
- Return<Error> release(const hidl_handle& bufferHandle) override;
- Return<void> getDimensions(const hidl_handle& bufferHandle,
- getDimensions_cb hidl_cb) override;
- Return<void> getFormat(const hidl_handle& bufferHandle,
- getFormat_cb hidl_cb) override;
- Return<void> getLayerCount(const hidl_handle& bufferHandle,
- getLayerCount_cb hidl_cb) override;
- Return<void> getProducerUsageMask(const hidl_handle& bufferHandle,
- getProducerUsageMask_cb hidl_cb) override;
- Return<void> getConsumerUsageMask(const hidl_handle& bufferHandle,
- getConsumerUsageMask_cb hidl_cb) override;
- Return<void> getBackingStore(const hidl_handle& bufferHandle,
- getBackingStore_cb hidl_cb) override;
- Return<void> getStride(const hidl_handle& bufferHandle,
- getStride_cb hidl_cb) override;
- Return<void> lock(const hidl_handle& bufferHandle,
- uint64_t producerUsageMask, uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
- lock_cb hidl_cb) override;
- Return<void> lockFlex(const hidl_handle& bufferHandle,
- uint64_t producerUsageMask, uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
- lockFlex_cb hidl_cb) override;
- Return<void> unlock(const hidl_handle& bufferHandle,
- unlock_cb hidl_cb) override;
+bool GrallocMapper::validateDescriptorInfo(
+ const BufferDescriptorInfo& descriptorInfo) const {
+ const uint64_t validUsageBits =
+ BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
+ BufferUsage::GPU_TEXTURE | BufferUsage::GPU_RENDER_TARGET |
+ BufferUsage::COMPOSER_OVERLAY | BufferUsage::COMPOSER_CLIENT_TARGET |
+ BufferUsage::PROTECTED | BufferUsage::COMPOSER_CURSOR |
+ BufferUsage::VIDEO_ENCODER | BufferUsage::CAMERA_OUTPUT |
+ BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT |
+ BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA |
+ BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK |
+ (mCapabilities.highUsageBits ? BufferUsage::VENDOR_MASK_HI
+ : static_cast<BufferUsage>(0));
-private:
- void initCapabilities();
-
- template<typename T>
- void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
- void initDispatch();
-
- static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect);
- static bool dupFence(const hidl_handle& fenceHandle, int* outFd);
-
- gralloc1_device_t* mDevice;
-
- struct {
- bool layeredBuffers;
- } mCapabilities;
-
- struct {
- GRALLOC1_PFN_RETAIN retain;
- GRALLOC1_PFN_RELEASE release;
- GRALLOC1_PFN_GET_DIMENSIONS getDimensions;
- GRALLOC1_PFN_GET_FORMAT getFormat;
- GRALLOC1_PFN_GET_LAYER_COUNT getLayerCount;
- GRALLOC1_PFN_GET_PRODUCER_USAGE getProducerUsage;
- GRALLOC1_PFN_GET_CONSUMER_USAGE getConsumerUsage;
- GRALLOC1_PFN_GET_BACKING_STORE getBackingStore;
- GRALLOC1_PFN_GET_STRIDE getStride;
- GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
- GRALLOC1_PFN_LOCK lock;
- GRALLOC1_PFN_LOCK_FLEX lockFlex;
- GRALLOC1_PFN_UNLOCK unlock;
- } mDispatch;
-
- std::mutex mMutex;
- std::unordered_map<buffer_handle_t, size_t> mBufferReferenceCounts;
-};
-
-GrallocMapperHal::GrallocMapperHal(const hw_module_t* module)
- : mDevice(nullptr), mCapabilities(), mDispatch()
-{
- int status = gralloc1_open(module, &mDevice);
- if (status) {
- LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
- strerror(-status));
- }
-
- initCapabilities();
- initDispatch();
-}
-
-GrallocMapperHal::~GrallocMapperHal()
-{
- gralloc1_close(mDevice);
-}
-
-void GrallocMapperHal::initCapabilities()
-{
- uint32_t count = 0;
- mDevice->getCapabilities(mDevice, &count, nullptr);
-
- std::vector<int32_t> caps(count);
- mDevice->getCapabilities(mDevice, &count, caps.data());
- caps.resize(count);
-
- for (auto cap : caps) {
- switch (cap) {
- case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
- mCapabilities.layeredBuffers = true;
- break;
- default:
- break;
- }
- }
-}
-
-template<typename T>
-void GrallocMapperHal::initDispatch(gralloc1_function_descriptor_t desc,
- T* outPfn)
-{
- auto pfn = mDevice->getFunction(mDevice, desc);
- if (!pfn) {
- LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
- }
-
- *outPfn = reinterpret_cast<T>(pfn);
-}
-
-void GrallocMapperHal::initDispatch()
-{
- initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain);
- initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
- initDispatch(GRALLOC1_FUNCTION_GET_DIMENSIONS, &mDispatch.getDimensions);
- initDispatch(GRALLOC1_FUNCTION_GET_FORMAT, &mDispatch.getFormat);
- if (mCapabilities.layeredBuffers) {
- initDispatch(GRALLOC1_FUNCTION_GET_LAYER_COUNT,
- &mDispatch.getLayerCount);
- }
- initDispatch(GRALLOC1_FUNCTION_GET_PRODUCER_USAGE,
- &mDispatch.getProducerUsage);
- initDispatch(GRALLOC1_FUNCTION_GET_CONSUMER_USAGE,
- &mDispatch.getConsumerUsage);
- initDispatch(GRALLOC1_FUNCTION_GET_BACKING_STORE,
- &mDispatch.getBackingStore);
- initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride);
- initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES,
- &mDispatch.getNumFlexPlanes);
- initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock);
- initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex);
- initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock);
-}
-
-gralloc1_rect_t GrallocMapperHal::asGralloc1Rect(const IMapper::Rect& rect)
-{
- return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
-}
-
-bool GrallocMapperHal::dupFence(const hidl_handle& fenceHandle, int* outFd)
-{
- auto handle = fenceHandle.getNativeHandle();
- if (!handle || handle->numFds == 0) {
- *outFd = -1;
- return true;
- }
-
- if (handle->numFds > 1) {
- ALOGE("invalid fence handle with %d fds", handle->numFds);
+ if (!descriptorInfo.width || !descriptorInfo.height ||
+ !descriptorInfo.layerCount) {
return false;
}
- *outFd = dup(handle->data[0]);
- return (*outFd >= 0);
-}
-
-Return<Error> GrallocMapperHal::retain(const hidl_handle& bufferHandle)
-{
- int32_t err = mDispatch.retain(mDevice, bufferHandle);
- if (err == GRALLOC1_ERROR_NONE) {
- auto nativeHandle = bufferHandle.getNativeHandle();
- std::lock_guard<std::mutex> lock(mMutex);
-
- ++mBufferReferenceCounts[nativeHandle];
- }
- return static_cast<Error>(err);
-}
-
-Return<Error> GrallocMapperHal::release(const hidl_handle& bufferHandle)
-{
- int32_t err = mDispatch.release(mDevice, bufferHandle);
- if (err == GRALLOC1_ERROR_NONE) {
- auto nativeHandle = bufferHandle.getNativeHandle();
- std::lock_guard<std::mutex> lock(mMutex);
-
- auto iter = mBufferReferenceCounts.find(bufferHandle);
- if (iter == mBufferReferenceCounts.end()) {
- // this should never happen
- err = GRALLOC1_ERROR_BAD_HANDLE;
- } else if (--iter->second == 0) {
- native_handle_close(nativeHandle);
- native_handle_delete(const_cast<native_handle_t*>(nativeHandle));
-
- mBufferReferenceCounts.erase(iter);
- }
+ if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount > 1) {
+ return false;
}
- return static_cast<Error>(err);
-}
-
-Return<void> GrallocMapperHal::getDimensions(const hidl_handle& bufferHandle,
- getDimensions_cb hidl_cb)
-{
- uint32_t width = 0;
- uint32_t height = 0;
- int32_t err = mDispatch.getDimensions(mDevice, bufferHandle,
- &width, &height);
-
- hidl_cb(static_cast<Error>(err), width, height);
- return Void();
-}
-
-Return<void> GrallocMapperHal::getFormat(const hidl_handle& bufferHandle,
- getFormat_cb hidl_cb)
-{
- int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- int32_t err = mDispatch.getFormat(mDevice, bufferHandle, &format);
-
- hidl_cb(static_cast<Error>(err), static_cast<PixelFormat>(format));
- return Void();
-}
-
-Return<void> GrallocMapperHal::getLayerCount(const hidl_handle& bufferHandle,
- getLayerCount_cb hidl_cb)
-{
- int32_t err = GRALLOC1_ERROR_NONE;
- uint32_t count = 1;
- if (mCapabilities.layeredBuffers) {
- err = mDispatch.getLayerCount(mDevice, bufferHandle, &count);
+ if (descriptorInfo.format == static_cast<PixelFormat>(0)) {
+ return false;
}
- hidl_cb(static_cast<Error>(err), count);
+ if (descriptorInfo.usage & ~validUsageBits) {
+ // could not fail as gralloc may use the reserved bits...
+ ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64,
+ descriptorInfo.usage & ~validUsageBits);
+ }
+
+ return true;
+}
+
+Return<void> GrallocMapper::createDescriptor(
+ const BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) {
+ if (validateDescriptorInfo(descriptorInfo)) {
+ hidl_cb(Error::NONE, grallocEncodeBufferDescriptor(descriptorInfo));
+ } else {
+ hidl_cb(Error::BAD_VALUE, BufferDescriptor());
+ }
+
return Void();
}
-Return<void> GrallocMapperHal::getProducerUsageMask(
- const hidl_handle& bufferHandle, getProducerUsageMask_cb hidl_cb)
-{
- uint64_t mask = 0x0;
- int32_t err = mDispatch.getProducerUsage(mDevice, bufferHandle, &mask);
-
- hidl_cb(static_cast<Error>(err), mask);
- return Void();
+bool GrallocMapper::addRegisteredHandle(buffer_handle_t bufferHandle) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mRegisteredHandles.insert(bufferHandle).second;
}
-Return<void> GrallocMapperHal::getConsumerUsageMask(
- const hidl_handle& bufferHandle, getConsumerUsageMask_cb hidl_cb)
-{
- uint64_t mask = 0x0;
- int32_t err = mDispatch.getConsumerUsage(mDevice, bufferHandle, &mask);
+native_handle_t* GrallocMapper::popRegisteredHandle(void* buffer) {
+ auto bufferHandle = static_cast<native_handle_t*>(buffer);
- hidl_cb(static_cast<Error>(err), mask);
- return Void();
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mRegisteredHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
}
-Return<void> GrallocMapperHal::getBackingStore(
- const hidl_handle& bufferHandle, getBackingStore_cb hidl_cb)
-{
- uint64_t store = 0;
- int32_t err = mDispatch.getBackingStore(mDevice, bufferHandle, &store);
+buffer_handle_t GrallocMapper::getRegisteredHandle(const void* buffer) {
+ auto bufferHandle = static_cast<buffer_handle_t>(buffer);
- hidl_cb(static_cast<Error>(err), store);
- return Void();
+ std::lock_guard<std::mutex> lock(mMutex);
+ return mRegisteredHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr;
}
-Return<void> GrallocMapperHal::getStride(const hidl_handle& bufferHandle,
- getStride_cb hidl_cb)
-{
- uint32_t stride = 0;
- int32_t err = mDispatch.getStride(mDevice, bufferHandle, &stride);
+Return<void> GrallocMapper::importBuffer(const hidl_handle& rawHandle,
+ importBuffer_cb hidl_cb) {
+ // importing an already imported handle rather than a raw handle
+ if (getRegisteredHandle(rawHandle.getNativeHandle())) {
+ hidl_cb(Error::BAD_BUFFER, nullptr);
+ return Void();
+ }
- hidl_cb(static_cast<Error>(err), stride);
- return Void();
-}
+ if (!rawHandle.getNativeHandle()) {
+ hidl_cb(Error::BAD_BUFFER, nullptr);
+ return Void();
+ }
-Return<void> GrallocMapperHal::lock(const hidl_handle& bufferHandle,
- uint64_t producerUsageMask, uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
- lock_cb hidl_cb)
-{
- gralloc1_rect_t rect = asGralloc1Rect(accessRegion);
-
- int fence = -1;
- if (!dupFence(acquireFence, &fence)) {
+ native_handle_t* bufferHandle =
+ native_handle_clone(rawHandle.getNativeHandle());
+ if (!bufferHandle) {
hidl_cb(Error::NO_RESOURCES, nullptr);
return Void();
}
+ Error error = registerBuffer(bufferHandle);
+ if (error != Error::NONE) {
+ native_handle_close(bufferHandle);
+ native_handle_delete(bufferHandle);
+
+ hidl_cb(error, nullptr);
+ return Void();
+ }
+
+ // The newly cloned handle is already registered? This can only happen
+ // when a handle previously registered was native_handle_delete'd instead
+ // of freeBuffer'd.
+ if (!addRegisteredHandle(bufferHandle)) {
+ ALOGE("handle %p has already been imported; potential fd leaking",
+ bufferHandle);
+ unregisterBuffer(bufferHandle);
+ if (!mCapabilities.unregisterImplyDelete) {
+ native_handle_close(bufferHandle);
+ native_handle_delete(bufferHandle);
+ }
+
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ hidl_cb(Error::NONE, bufferHandle);
+ return Void();
+}
+
+Return<Error> GrallocMapper::freeBuffer(void* buffer) {
+ native_handle_t* bufferHandle = popRegisteredHandle(buffer);
+ if (!bufferHandle) {
+ return Error::BAD_BUFFER;
+ }
+
+ unregisterBuffer(bufferHandle);
+ if (!mCapabilities.unregisterImplyDelete) {
+ native_handle_close(bufferHandle);
+ native_handle_delete(bufferHandle);
+ }
+
+ return Error::NONE;
+}
+
+void GrallocMapper::waitFenceFd(int fenceFd, const char* logname) {
+ if (fenceFd < 0) {
+ return;
+ }
+
+ const int warningTimeout = 3500;
+ const int error = sync_wait(fenceFd, warningTimeout);
+ if (error < 0 && errno == ETIME) {
+ ALOGE("%s: fence %d didn't signal in %u ms", logname, fenceFd,
+ warningTimeout);
+ sync_wait(fenceFd, -1);
+ }
+}
+
+bool GrallocMapper::getFenceFd(const hidl_handle& fenceHandle,
+ int* outFenceFd) {
+ auto handle = fenceHandle.getNativeHandle();
+ if (handle && handle->numFds > 1) {
+ ALOGE("invalid fence handle with %d fds", handle->numFds);
+ return false;
+ }
+
+ *outFenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1;
+ return true;
+}
+
+hidl_handle GrallocMapper::getFenceHandle(int fenceFd, char* handleStorage) {
+ native_handle_t* handle = nullptr;
+ if (fenceFd >= 0) {
+ handle = native_handle_init(handleStorage, 1, 0);
+ handle->data[0] = fenceFd;
+ }
+
+ return hidl_handle(handle);
+}
+
+Return<void> GrallocMapper::lock(void* buffer, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion,
+ const hidl_handle& acquireFence,
+ lock_cb hidl_cb) {
+ buffer_handle_t bufferHandle = getRegisteredHandle(buffer);
+ if (!bufferHandle) {
+ hidl_cb(Error::BAD_BUFFER, nullptr);
+ return Void();
+ }
+
+ int fenceFd;
+ if (!getFenceFd(acquireFence, &fenceFd)) {
+ hidl_cb(Error::BAD_VALUE, nullptr);
+ return Void();
+ }
+
void* data = nullptr;
- int32_t err = mDispatch.lock(mDevice, bufferHandle, producerUsageMask,
- consumerUsageMask, &rect, &data, fence);
- if (err != GRALLOC1_ERROR_NONE) {
- close(fence);
- }
+ Error error =
+ lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &data);
- hidl_cb(static_cast<Error>(err), data);
+ hidl_cb(error, data);
return Void();
}
-Return<void> GrallocMapperHal::lockFlex(const hidl_handle& bufferHandle,
- uint64_t producerUsageMask, uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
- lockFlex_cb hidl_cb)
-{
- FlexLayout layout_reply{};
+Return<void> GrallocMapper::lockYCbCr(void* buffer, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion,
+ const hidl_handle& acquireFence,
+ lockYCbCr_cb hidl_cb) {
+ YCbCrLayout layout = {};
- uint32_t planeCount = 0;
- int32_t err = mDispatch.getNumFlexPlanes(mDevice, bufferHandle,
- &planeCount);
- if (err != GRALLOC1_ERROR_NONE) {
- hidl_cb(static_cast<Error>(err), layout_reply);
+ buffer_handle_t bufferHandle = getRegisteredHandle(buffer);
+ if (!bufferHandle) {
+ hidl_cb(Error::BAD_BUFFER, layout);
return Void();
}
- gralloc1_rect_t rect = asGralloc1Rect(accessRegion);
-
- int fence = -1;
- if (!dupFence(acquireFence, &fence)) {
- hidl_cb(Error::NO_RESOURCES, layout_reply);
+ int fenceFd;
+ if (!getFenceFd(acquireFence, &fenceFd)) {
+ hidl_cb(Error::BAD_VALUE, layout);
return Void();
}
- std::vector<android_flex_plane_t> planes(planeCount);
- android_flex_layout_t layout{};
- layout.num_planes = planes.size();
- layout.planes = planes.data();
+ Error error =
+ lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &layout);
- err = mDispatch.lockFlex(mDevice, bufferHandle, producerUsageMask,
- consumerUsageMask, &rect, &layout, fence);
- if (err == GRALLOC1_ERROR_NONE) {
- layout_reply.format = static_cast<FlexFormat>(layout.format);
+ hidl_cb(error, layout);
+ return Void();
+}
- planes.resize(layout.num_planes);
- layout_reply.planes.setToExternal(
- reinterpret_cast<FlexPlane*>(planes.data()), planes.size());
+Return<void> GrallocMapper::unlock(void* buffer, unlock_cb hidl_cb) {
+ buffer_handle_t bufferHandle = getRegisteredHandle(buffer);
+ if (!bufferHandle) {
+ hidl_cb(Error::BAD_BUFFER, nullptr);
+ return Void();
+ }
+
+ int fenceFd;
+ Error error = unlockBuffer(bufferHandle, &fenceFd);
+ if (error == Error::NONE) {
+ NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
+
+ hidl_cb(error, getFenceHandle(fenceFd, fenceStorage));
+
+ if (fenceFd >= 0) {
+ close(fenceFd);
+ }
} else {
- close(fence);
+ hidl_cb(error, nullptr);
}
- hidl_cb(static_cast<Error>(err), layout_reply);
return Void();
}
-Return<void> GrallocMapperHal::unlock(const hidl_handle& bufferHandle,
- unlock_cb hidl_cb)
-{
- int32_t fence = -1;
- int32_t err = mDispatch.unlock(mDevice, bufferHandle, &fence);
-
- NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
- hidl_handle fenceHandle;
- if (err == GRALLOC1_ERROR_NONE && fence >= 0) {
- auto nativeHandle = native_handle_init(fenceStorage, 1, 0);
- nativeHandle->data[0] = fence;
-
- fenceHandle = nativeHandle;
- }
-
- hidl_cb(static_cast<Error>(err), fenceHandle);
- return Void();
-}
-
-} // anonymous namespace
-
IMapper* HIDL_FETCH_IMapper(const char* /* name */) {
const hw_module_t* module = nullptr;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
@@ -410,12 +287,15 @@
}
uint8_t major = (module->module_api_version >> 8) & 0xff;
- if (major != 1) {
- ALOGE("unknown gralloc module major version %d", major);
- return nullptr;
+ switch (major) {
+ case 1:
+ return new Gralloc1Mapper(module);
+ case 0:
+ return new Gralloc0Mapper(module);
+ default:
+ ALOGE("unknown gralloc module major version %d", major);
+ return nullptr;
}
-
- return new GrallocMapperHal(module);
}
} // namespace implementation
diff --git a/graphics/mapper/2.0/default/GrallocMapper.h b/graphics/mapper/2.0/default/GrallocMapper.h
index a2f89d1..c9c6d8a 100644
--- a/graphics/mapper/2.0/default/GrallocMapper.h
+++ b/graphics/mapper/2.0/default/GrallocMapper.h
@@ -18,6 +18,10 @@
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <system/window.h>
+
+#include <mutex>
+#include <unordered_set>
namespace android {
namespace hardware {
@@ -26,6 +30,68 @@
namespace V2_0 {
namespace implementation {
+class GrallocMapper : public IMapper {
+ public:
+ // IMapper interface
+ Return<void> createDescriptor(const BufferDescriptorInfo& descriptorInfo,
+ createDescriptor_cb hidl_cb) override;
+ Return<void> importBuffer(const hidl_handle& rawHandle,
+ importBuffer_cb hidl_cb) override;
+ Return<Error> freeBuffer(void* buffer) override;
+ Return<void> lock(void* buffer, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion,
+ const hidl_handle& acquireFence,
+ lock_cb hidl_cb) override;
+ Return<void> lockYCbCr(void* buffer, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion,
+ const hidl_handle& acquireFence,
+ lockYCbCr_cb hidl_cb) override;
+ Return<void> unlock(void* buffer, unlock_cb hidl_cb) override;
+
+ protected:
+ static void waitFenceFd(int fenceFd, const char* logname);
+
+ struct {
+ bool highUsageBits;
+ bool layeredBuffers;
+ bool unregisterImplyDelete;
+ } mCapabilities = {};
+
+ private:
+ virtual bool validateDescriptorInfo(
+ const BufferDescriptorInfo& descriptorInfo) const;
+
+ // Register a buffer. The handle is already cloned by the caller.
+ virtual Error registerBuffer(buffer_handle_t bufferHandle) = 0;
+
+ // Unregister a buffer. The handle is closed and deleted by the
+ // callee if and only if mCapabilities.unregisterImplyDelete is set.
+ virtual void unregisterBuffer(buffer_handle_t bufferHandle) = 0;
+
+ // Lock a buffer. The fence is owned by the caller.
+ virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ void** outData) = 0;
+ virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int fenceFd,
+ YCbCrLayout* outLayout) = 0;
+
+ // Unlock a buffer. The returned fence is owned by the caller.
+ virtual Error unlockBuffer(buffer_handle_t bufferHandle,
+ int* outFenceFd) = 0;
+
+ static bool addRegisteredHandle(buffer_handle_t bufferHandle);
+ static buffer_handle_t getRegisteredHandle(const void* buffer);
+ static native_handle_t* popRegisteredHandle(void* buffer);
+
+ static bool getFenceFd(const hidl_handle& fenceHandle, int* outFenceFd);
+ static hidl_handle getFenceHandle(int fenceFd, char* handleStorage);
+
+ // these are static and shared by all mappers
+ static std::mutex mMutex;
+ static std::unordered_set<buffer_handle_t> mRegisteredHandles;
+};
+
extern "C" IMapper* HIDL_FETCH_IMapper(const char* name);
} // namespace implementation
diff --git a/graphics/mapper/2.0/types.hal b/graphics/mapper/2.0/types.hal
index 2946e85..e9b2f3a 100644
--- a/graphics/mapper/2.0/types.hal
+++ b/graphics/mapper/2.0/types.hal
@@ -16,101 +16,50 @@
package android.hardware.graphics.mapper@2.0;
+enum Error : int32_t {
+ NONE = 0, /** no error */
+ BAD_DESCRIPTOR = 1, /** invalid BufferDescriptor */
+ BAD_BUFFER = 2, /** invalid buffer handle */
+ BAD_VALUE = 3, /** invalid width, height, etc. */
+ /* 4 is reserved */
+ NO_RESOURCES = 5, /** temporary failure due to resource contention */
+ /* 6 is reserved */
+ UNSUPPORTED = 7, /** permanent failure */
+};
+
/**
- * Structures for describing flexible YUVA/RGBA formats for consumption by
- * applications. Such flexible formats contain a plane for each component (e.g.
- * red, green, blue), where each plane is laid out in a grid-like pattern
- * occupying unique byte addresses and with consistent byte offsets between
- * neighboring pixels.
- *
- * The FlexLayout structure is used with any pixel format that can be
- * represented by it, such as:
- * - PixelFormat::YCBCR_*_888
- * - PixelFormat::FLEX_RGB*_888
- * - PixelFormat::RGB[AX]_888[8],BGRA_8888,RGB_888
- * - PixelFormat::YV12,Y8,Y16,YCBCR_422_SP/I,YCRCB_420_SP
- * - even implementation defined formats that can be represented by
- * the structures
- *
- * Vertical increment (aka. row increment or stride) describes the distance in
- * bytes from the first pixel of one row to the first pixel of the next row
- * (below) for the component plane. This can be negative.
- *
- * Horizontal increment (aka. column or pixel increment) describes the distance
- * in bytes from one pixel to the next pixel (to the right) on the same row for
- * the component plane. This can be negative.
- *
- * Each plane can be subsampled either vertically or horizontally by
- * a power-of-two factor.
- *
- * The bit-depth of each component can be arbitrary, as long as the pixels are
- * laid out on whole bytes, in native byte-order, using the most significant
- * bits of each unit.
+ * A buffer descriptor is an implementation-defined opaque data returned by
+ * createDescriptor. It describes the properties of a buffer and is consumed
+ * by the allocator.
*/
+typedef vec<uint32_t> BufferDescriptor;
-enum FlexComponent : int32_t {
- Y = 1 << 0, /** luma */
- CB = 1 << 1, /** chroma blue */
- CR = 1 << 2, /** chroma red */
-
- R = 1 << 10, /** red */
- G = 1 << 11, /** green */
- B = 1 << 12, /** blue */
-
- A = 1 << 30, /** alpha */
+/**
+ * Structure for describing YCbCr formats for consumption by applications.
+ * This is used with PixelFormat::YCBCR_*_888.
+ *
+ * Buffer chroma subsampling is defined in the format.
+ * e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0.
+ *
+ * Buffers must have a 8 bit depth.
+ *
+ * y, cb, and cr point to the first byte of their respective planes.
+ *
+ * Stride describes the distance in bytes from the first value of one row of
+ * the image to the first value of the next row. It includes the width of the
+ * image plus padding.
+ * yStride is the stride of the luma plane.
+ * cStride is the stride of the chroma planes.
+ *
+ * chromaStep is the distance in bytes from one chroma pixel value to the
+ * next. This is 2 bytes for semiplanar (because chroma values are interleaved
+ * and each chroma value is one byte) and 1 for planar.
+ */
+struct YCbCrLayout {
+ pointer y;
+ pointer cb;
+ pointer cr;
+ uint32_t yStride;
+ uint32_t cStride;
+ uint32_t chromaStep;
};
-
-enum FlexFormat : int32_t {
- /** not a flexible format */
- INVALID = 0x0,
-
- Y = FlexComponent:Y,
- YCBCR = Y | FlexComponent:CB | FlexComponent:CR,
- YCBCRA = YCBCR | FlexComponent:A,
-
- RGB = FlexComponent:R | FlexComponent:G | FlexComponent:B,
- RGBA = RGB | FlexComponent:A,
-};
-
-struct FlexPlane {
- /** Pointer to the first byte of the top-left pixel of the plane. */
- pointer topLeft;
-
- FlexComponent component;
-
- /**
- * Bits allocated for the component in each pixel. Must be a positive
- * multiple of 8.
- */
- int32_t bitsPerComponent;
-
- /**
- * Number of the most significant bits used in the format for this
- * component. Must be between 1 and bitsPerComponent, inclusive.
- */
- int32_t bitsUsed;
-
- /** Horizontal increment. */
- int32_t hIncrement;
- /** Vertical increment. */
- int32_t vIncrement;
- /** Horizontal subsampling. Must be a positive power of 2. */
- int32_t hSubsampling;
- /** Vertical subsampling. Must be a positive power of 2. */
- int32_t vSubsampling;
-};
-
-struct FlexLayout {
- /** The kind of flexible format. */
- FlexFormat format;
-
- /**
- * A plane for each component; ordered in increasing component value
- * order. E.g. FlexFormat::RGBA maps 0 -> R, 1 -> G, etc. Can have size 0
- * for FlexFormat::INVALID.
- */
- vec<FlexPlane> planes;
-};
-
-/** Backing store ID of a buffer. See IMapper::getBackingStore. */
-typedef uint64_t BackingStore;
diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp
index e26f087..1c0e4c5 100644
--- a/graphics/mapper/2.0/vts/functional/Android.bp
+++ b/graphics/mapper/2.0/vts/functional/Android.bp
@@ -24,7 +24,6 @@
],
static_libs: [
"VtsHalHidlTargetTestBase",
- "libVtsHalGraphicsAllocatorTestUtils",
],
cflags: [
"-Wall",
@@ -54,7 +53,6 @@
"android.hardware.graphics.common@1.0",
],
static_libs: [
- "libVtsHalGraphicsAllocatorTestUtils",
"libVtsHalGraphicsMapperTestUtils",
"VtsHalHidlTargetTestBase",
],
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
index f6a26ac..c534889 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp
@@ -25,228 +25,233 @@
namespace V2_0 {
namespace tests {
-using android::hardware::graphics::allocator::V2_0::Buffer;
-using android::hardware::graphics::allocator::V2_0::BufferDescriptor;
-using android::hardware::graphics::allocator::V2_0::Error;
-
-Mapper::Mapper() { init(); }
-
-void Mapper::init() {
- mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>();
- ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
- ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+Gralloc::Gralloc() {
+ init();
}
-Mapper::~Mapper() {
- for (auto it : mHandles) {
- while (it.second) {
- EXPECT_EQ(Error::NONE, mMapper->release(it.first))
- << "failed to release handle " << it.first;
- it.second--;
+void Gralloc::init() {
+ mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>();
+ ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+ mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>();
+ ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
+ ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+}
+
+Gralloc::~Gralloc() {
+ for (auto bufferHandle : mClonedBuffers) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ native_handle_close(buffer);
+ native_handle_delete(buffer);
}
- }
- mHandles.clear();
+ mClonedBuffers.clear();
+
+ for (auto bufferHandle : mImportedBuffers) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer))
+ << "failed to free buffer " << buffer;
+ }
+ mImportedBuffers.clear();
}
-sp<IMapper> Mapper::getRaw() const { return mMapper; }
-
-void Mapper::retain(const native_handle_t* handle) {
- Error error = mMapper->retain(handle);
- ASSERT_EQ(Error::NONE, error) << "failed to retain handle " << handle;
-
- mHandles[handle]++;
+sp<IAllocator> Gralloc::getAllocator() const {
+ return mAllocator;
}
-void Mapper::release(const native_handle_t* handle) {
- Error error = mMapper->release(handle);
- ASSERT_EQ(Error::NONE, error) << "failed to release handle " << handle;
+std::string Gralloc::dumpDebugInfo() {
+ std::string debugInfo;
+ mAllocator->dumpDebugInfo(
+ [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
- if (--mHandles[handle] == 0) {
- mHandles.erase(handle);
- }
+ return debugInfo;
}
-Mapper::Dimensions Mapper::getDimensions(const native_handle_t* handle) {
- Dimensions dimensions = {};
- mMapper->getDimensions(handle, [&](const auto& tmpError, const auto& tmpWidth,
- const auto& tmpHeight) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get dimensions for handle " << handle;
- dimensions.width = tmpWidth;
- dimensions.height = tmpHeight;
- });
+const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
+ const native_handle_t* bufferHandle =
+ native_handle_clone(rawHandle.getNativeHandle());
+ EXPECT_NE(nullptr, bufferHandle);
- return dimensions;
+ if (bufferHandle) {
+ mClonedBuffers.insert(bufferHandle);
+ }
+
+ return bufferHandle;
}
-PixelFormat Mapper::getFormat(const native_handle_t* handle) {
- PixelFormat format = static_cast<PixelFormat>(0);
- mMapper->getFormat(handle, [&](const auto& tmpError, const auto& tmpFormat) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get format for handle " << handle;
- format = tmpFormat;
- });
+std::vector<const native_handle_t*> Gralloc::allocate(
+ const BufferDescriptor& descriptor, uint32_t count, bool import,
+ uint32_t* outStride) {
+ std::vector<const native_handle_t*> bufferHandles;
+ bufferHandles.reserve(count);
+ mAllocator->allocate(
+ descriptor, count, [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+ ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
- return format;
+ for (uint32_t i = 0; i < count; i++) {
+ if (import) {
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandles.push_back(importBuffer(tmpBuffers[i])));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
+ }
+ }
+
+ if (outStride) {
+ *outStride = tmpStride;
+ }
+ });
+
+ if (::testing::Test::HasFatalFailure()) {
+ bufferHandles.clear();
+ }
+
+ return bufferHandles;
}
-uint32_t Mapper::getLayerCount(const native_handle_t* handle) {
- uint32_t count = 0;
- mMapper->getLayerCount(
- handle, [&](const auto& tmpError, const auto& tmpCount) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get layer count for handle " << handle;
- count = tmpCount;
- });
+const native_handle_t* Gralloc::allocate(
+ const IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
+ uint32_t* outStride) {
+ BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
- return count;
+ auto buffers = allocate(descriptor, 1, import, outStride);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+
+ return buffers[0];
}
-uint64_t Mapper::getProducerUsageMask(const native_handle_t* handle) {
- uint64_t usageMask = 0;
- mMapper->getProducerUsageMask(
- handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get producer usage mask for handle " << handle;
- usageMask = tmpUsageMask;
- });
-
- return usageMask;
+sp<IMapper> Gralloc::getMapper() const {
+ return mMapper;
}
-uint64_t Mapper::getConsumerUsageMask(const native_handle_t* handle) {
- uint64_t usageMask = 0;
- mMapper->getConsumerUsageMask(
- handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get consumer usage mask for handle " << handle;
- usageMask = tmpUsageMask;
- });
+BufferDescriptor Gralloc::createDescriptor(
+ const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ BufferDescriptor descriptor;
+ mMapper->createDescriptor(
+ descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+ descriptor = tmpDescriptor;
+ });
- return usageMask;
+ return descriptor;
}
-BackingStore Mapper::getBackingStore(const native_handle_t* handle) {
- BackingStore backingStore = 0;
- mMapper->getBackingStore(
- handle, [&](const auto& tmpError, const auto& tmpBackingStore) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get backing store for handle " << handle;
- backingStore = tmpBackingStore;
- });
+const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) {
+ const native_handle_t* bufferHandle = nullptr;
+ mMapper->importBuffer(
+ rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to import buffer %p"
+ << rawHandle.getNativeHandle();
+ bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
+ });
- return backingStore;
+ if (bufferHandle) {
+ mImportedBuffers.insert(bufferHandle);
+ }
+
+ return bufferHandle;
}
-uint32_t Mapper::getStride(const native_handle_t* handle) {
- uint32_t stride = 0;
- mMapper->getStride(handle, [&](const auto& tmpError, const auto& tmpStride) {
- ASSERT_EQ(Error::NONE, tmpError)
- << "failed to get stride for handle " << handle;
- stride = tmpStride;
- });
+void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
- return stride;
+ if (mImportedBuffers.erase(bufferHandle)) {
+ Error error = mMapper->freeBuffer(buffer);
+ ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer;
+ } else {
+ mClonedBuffers.erase(bufferHandle);
+ native_handle_close(buffer);
+ native_handle_delete(buffer);
+ }
}
-void* Mapper::lock(const native_handle_t* handle, uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion, int acquireFence) {
- NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
- native_handle_t* acquireFenceHandle = nullptr;
- if (acquireFence >= 0) {
- acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
- acquireFenceHandle->data[0] = acquireFence;
- }
+void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
- void* data = nullptr;
- mMapper->lock(
- handle, producerUsageMask, consumerUsageMask, accessRegion,
- acquireFenceHandle, [&](const auto& tmpError, const auto& tmpData) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to lock handle " << handle;
- data = tmpData;
- });
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ hidl_handle acquireFenceHandle;
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
- if (acquireFence >= 0) {
- close(acquireFence);
- }
-
- return data;
-}
-
-FlexLayout Mapper::lockFlex(const native_handle_t* handle,
- uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion,
- int acquireFence) {
- NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
- native_handle_t* acquireFenceHandle = nullptr;
- if (acquireFence >= 0) {
- acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
- acquireFenceHandle->data[0] = acquireFence;
- }
-
- FlexLayout layout = {};
- mMapper->lockFlex(handle, producerUsageMask, consumerUsageMask, accessRegion,
- acquireFenceHandle,
- [&](const auto& tmpError, const auto& tmpLayout) {
+ void* data = nullptr;
+ mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData) {
ASSERT_EQ(Error::NONE, tmpError)
- << "failed to lockFlex handle " << handle;
- layout = tmpLayout;
- });
+ << "failed to lock buffer " << buffer;
+ data = tmpData;
+ });
- if (acquireFence >= 0) {
- close(acquireFence);
- }
-
- return layout;
-}
-
-int Mapper::unlock(const native_handle_t* handle) {
- int releaseFence = -1;
- mMapper->unlock(handle, [&](const auto& tmpError,
- const auto& tmpReleaseFence) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock handle " << handle;
-
- auto handle = tmpReleaseFence.getNativeHandle();
- if (handle) {
- ASSERT_EQ(0, handle->numInts) << "invalid fence handle " << handle;
- if (handle->numFds == 1) {
- releaseFence = dup(handle->data[0]);
- ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
- } else {
- ASSERT_EQ(0, handle->numFds) << " invalid fence handle " << handle;
- }
+ if (acquireFence >= 0) {
+ close(acquireFence);
}
- });
- return releaseFence;
+ return data;
}
-const native_handle_t* Mapper::allocate(
- std::unique_ptr<AllocatorClient>& allocatorClient,
- const IAllocatorClient::BufferDescriptorInfo& info) {
- BufferDescriptor descriptor = allocatorClient->createDescriptor(info);
- if (::testing::Test::HasFatalFailure()) {
- return nullptr;
- }
+YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle,
+ uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion,
+ int acquireFence) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
- Buffer buffer = allocatorClient->allocate(descriptor);
- if (::testing::Test::HasFatalFailure()) {
- allocatorClient->destroyDescriptor(descriptor);
- return nullptr;
- }
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ hidl_handle acquireFenceHandle;
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
- const native_handle_t* handle =
- allocatorClient->exportHandle(descriptor, buffer);
- if (handle) {
- retain(handle);
- }
+ YCbCrLayout layout = {};
+ mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to lockYCbCr buffer " << buffer;
+ layout = tmpLayout;
+ });
- allocatorClient->free(buffer);
- allocatorClient->destroyDescriptor(descriptor);
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
- return handle;
+ return layout;
+}
+
+int Gralloc::unlock(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ mMapper->unlock(
+ buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer "
+ << buffer;
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle) {
+ ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle "
+ << fenceHandle;
+ if (fenceHandle->numFds == 1) {
+ releaseFence = dup(fenceHandle->data[0]);
+ ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+ } else {
+ ASSERT_EQ(0, fenceHandle->numFds)
+ << " invalid fence handle " << fenceHandle;
+ }
+ }
+ });
+
+ return releaseFence;
}
} // namespace tests
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
index c186b00..757f20b 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h
@@ -17,14 +17,12 @@
#ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS
#define VTS_HAL_GRAPHICS_MAPPER_UTILS
-#include <memory>
-#include <unordered_map>
+#include <unordered_set>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <utils/StrongPointer.h>
-#include "VtsHalGraphicsAllocatorTestUtils.h"
-
namespace android {
namespace hardware {
namespace graphics {
@@ -32,59 +30,62 @@
namespace V2_0 {
namespace tests {
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::hardware::graphics::allocator::V2_0::IAllocatorClient;
-using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient;
+using android::hardware::graphics::allocator::V2_0::IAllocator;
-// A wrapper to IMapper.
-class Mapper {
- public:
- Mapper();
- ~Mapper();
+// A wrapper to IAllocator and IMapper.
+class Gralloc {
+ public:
+ Gralloc();
+ ~Gralloc();
- sp<IMapper> getRaw() const;
+ // IAllocator methods
- void retain(const native_handle_t* handle);
- void release(const native_handle_t* handle);
+ sp<IAllocator> getAllocator() const;
- struct Dimensions {
- uint32_t width;
- uint32_t height;
- };
- Dimensions getDimensions(const native_handle_t* handle);
+ std::string dumpDebugInfo();
- PixelFormat getFormat(const native_handle_t* handle);
- uint32_t getLayerCount(const native_handle_t* handle);
- uint64_t getProducerUsageMask(const native_handle_t* handle);
- uint64_t getConsumerUsageMask(const native_handle_t* handle);
- BackingStore getBackingStore(const native_handle_t* handle);
- uint32_t getStride(const native_handle_t* handle);
+ // When import is false, this simply calls IAllocator::allocate. When import
+ // is true, the returned buffers are also imported into the mapper.
+ //
+ // Either case, the returned buffers must be freed with freeBuffer.
+ std::vector<const native_handle_t*> allocate(
+ const BufferDescriptor& descriptor, uint32_t count, bool import = true,
+ uint32_t* outStride = nullptr);
+ const native_handle_t* allocate(
+ const IMapper::BufferDescriptorInfo& descriptorInfo, bool import = true,
+ uint32_t* outStride = nullptr);
- // We use fd instead of hidl_handle in these functions to pass fences
- // in and out of the mapper. The ownership of the fd is always transferred
- // with each of these functions.
- void* lock(const native_handle_t* handle, uint64_t producerUsageMask,
- uint64_t consumerUsageMask, const IMapper::Rect& accessRegion,
- int acquireFence);
- FlexLayout lockFlex(const native_handle_t* handle, uint64_t producerUsageMask,
- uint64_t consumerUsageMask,
- const IMapper::Rect& accessRegion, int acquireFence);
- int unlock(const native_handle_t* handle);
+ // IMapper methods
- // Requests AllocatorClient to allocate a buffer, export the handle, and
- // register the handle with mapper.
- const native_handle_t* allocate(
- std::unique_ptr<AllocatorClient>& allocatorClient,
- const IAllocatorClient::BufferDescriptorInfo& info);
+ sp<IMapper> getMapper() const;
- private:
- void init();
+ BufferDescriptor createDescriptor(
+ const IMapper::BufferDescriptorInfo& descriptorInfo);
- sp<IMapper> mMapper;
+ const native_handle_t* importBuffer(const hidl_handle& rawHandle);
+ void freeBuffer(const native_handle_t* bufferHandle);
- // Keep track of all registered (retained) handles. When a test fails with
- // ASSERT_*, the destructor will release the handles for the test.
- std::unordered_map<const native_handle_t*, uint64_t> mHandles;
+ // We use fd instead of hidl_handle in these functions to pass fences
+ // in and out of the mapper. The ownership of the fd is always transferred
+ // with each of these functions.
+ void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence);
+ YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle,
+ uint64_t cpuUsage, const IMapper::Rect& accessRegion,
+ int acquireFence);
+ int unlock(const native_handle_t* bufferHandle);
+
+ private:
+ void init();
+ const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
+
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+
+ // Keep track of all cloned and imported handles. When a test fails with
+ // ASSERT_*, the destructor will free the handles for the test.
+ std::unordered_set<const native_handle_t*> mClonedBuffers;
+ std::unordered_set<const native_handle_t*> mImportedBuffers;
};
} // namespace tests
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index 92d74d5..f066a1e 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#define LOG_TAG "graphics_mapper_hidl_hal_test"
+#define LOG_TAG "VtsHalGraphicsMapperV2_0TargetTest"
-#include <android-base/logging.h>
#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
#include <sync/sync.h>
#include "VtsHalGraphicsMapperTestUtils.h"
@@ -29,202 +29,384 @@
namespace tests {
namespace {
-using namespace android::hardware::graphics::allocator::V2_0;
-using namespace android::hardware::graphics::allocator::V2_0::tests;
+using android::hardware::graphics::common::V1_0::BufferUsage;
+using android::hardware::graphics::common::V1_0::PixelFormat;
class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
protected:
void SetUp() override {
- ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
- ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient());
- ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>());
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
- mDummyDescriptorInfo.width = 64;
- mDummyDescriptorInfo.height = 64;
- mDummyDescriptorInfo.layerCount = 1;
- mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
- mDummyDescriptorInfo.producerUsageMask =
- static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
- mDummyDescriptorInfo.consumerUsageMask =
- static_cast<uint64_t>(ConsumerUsage::CPU_READ);
+ mDummyDescriptorInfo.width = 64;
+ mDummyDescriptorInfo.height = 64;
+ mDummyDescriptorInfo.layerCount = 1;
+ mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+ mDummyDescriptorInfo.usage = static_cast<uint64_t>(
+ BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
}
void TearDown() override {}
- std::unique_ptr<Allocator> mAllocator;
- std::unique_ptr<AllocatorClient> mAllocatorClient;
- std::unique_ptr<Mapper> mMapper;
- IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
+ std::unique_ptr<Gralloc> mGralloc;
+ IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
};
/**
- * Test IMapper::retain and IMapper::release.
+ * Test IAllocator::dumpDebugInfo by calling it.
*/
-TEST_F(GraphicsMapperHidlTest, RetainRelease) {
- const native_handle_t* buffer;
- ASSERT_NO_FATAL_FAILURE(
- buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
-
- const int maxRefs = 10;
- for (int i = 0; i < maxRefs; i++) {
- ASSERT_NO_FATAL_FAILURE(mMapper->retain(buffer));
- }
- for (int i = 0; i < maxRefs; i++) {
- ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
- }
-
- ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
+TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
+ mGralloc->dumpDebugInfo();
}
/**
- * Test IMapper::get* getters.
+ * Test IAllocator::allocate with valid buffer descriptors.
*/
-TEST_F(GraphicsMapperHidlTest, Getters) {
- const native_handle_t* buffer;
- ASSERT_NO_FATAL_FAILURE(
- buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(
+ descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
- IAllocatorClient::BufferDescriptorInfo info = {};
+ for (uint32_t count = 0; count < 5; count++) {
+ std::vector<const native_handle_t*> bufferHandles;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandles = mGralloc->allocate(
+ descriptor, count, false, &stride));
- Mapper::Dimensions dimensions;
- ASSERT_NO_FATAL_FAILURE(dimensions = mMapper->getDimensions(buffer));
- info.width = dimensions.width;
- info.height = dimensions.height;
+ if (count >= 1) {
+ EXPECT_LE(mDummyDescriptorInfo.width, stride)
+ << "invalid buffer stride";
+ }
- ASSERT_NO_FATAL_FAILURE(info.format = mMapper->getFormat(buffer));
- ASSERT_NO_FATAL_FAILURE(info.producerUsageMask =
- mMapper->getProducerUsageMask(buffer));
- ASSERT_NO_FATAL_FAILURE(info.consumerUsageMask =
- mMapper->getConsumerUsageMask(buffer));
+ for (auto bufferHandle : bufferHandles) {
+ mGralloc->freeBuffer(bufferHandle);
+ }
+ }
+}
- EXPECT_EQ(mDummyDescriptorInfo.width, info.width);
- EXPECT_EQ(mDummyDescriptorInfo.height, info.height);
- EXPECT_EQ(mDummyDescriptorInfo.format, info.format);
- EXPECT_EQ(mDummyDescriptorInfo.producerUsageMask, info.producerUsageMask);
- EXPECT_EQ(mDummyDescriptorInfo.consumerUsageMask, info.consumerUsageMask);
+/**
+ * Test IAllocator::allocate with invalid buffer descriptors.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+ // this assumes any valid descriptor is non-empty
+ BufferDescriptor descriptor;
+ mGralloc->getAllocator()->allocate(
+ descriptor, 1, [&](const auto& tmpError, const auto&, const auto&) {
+ EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+ });
+}
- ASSERT_NO_FATAL_FAILURE(mMapper->getBackingStore(buffer));
+/**
+ * Test IAllocator::allocate does not leak.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 1024;
+ info.height = 1024;
- uint32_t stride;
- ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
- EXPECT_LE(info.width, stride);
+ for (int i = 0; i < 2048; i++) {
+ auto bufferHandle = mGralloc->allocate(info, false);
+ mGralloc->freeBuffer(bufferHandle);
+ }
+}
+
+/**
+ * Test IMapper::createDescriptor with valid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+ ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
+}
+
+/**
+ * Test IMapper::createDescriptor with invalid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 0;
+ mGralloc->getMapper()->createDescriptor(
+ info, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_VALUE, tmpError)
+ << "createDescriptor did not fail with BAD_VALUE";
+ });
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+ const native_handle_t* bufferHandle;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle =
+ mGralloc->allocate(mDummyDescriptorInfo, true));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+ const native_handle_t* clonedBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(
+ clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+ // A cloned handle is a raw handle. Check that we can import it multiple
+ // times.
+ const native_handle_t* importedBufferHandles[2];
+ ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] =
+ mGralloc->importBuffer(clonedBufferHandle));
+ ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] =
+ mGralloc->importBuffer(clonedBufferHandle));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+ const native_handle_t* rawHandle;
+ ASSERT_NO_FATAL_FAILURE(
+ rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+ native_handle_t* importedHandle = nullptr;
+ mGralloc->getMapper()->importBuffer(
+ rawHandle, [&](const auto& tmpError, const auto& buffer) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ importedHandle = static_cast<native_handle_t*>(buffer);
+ });
+
+ // free the imported handle with another mapper
+ std::unique_ptr<Gralloc> anotherGralloc;
+ ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>());
+ Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
+ ASSERT_EQ(Error::NONE, error);
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 1024;
+ info.height = 1024;
+
+ for (int i = 0; i < 2048; i++) {
+ auto bufferHandle = mGralloc->allocate(info, true);
+ mGralloc->freeBuffer(bufferHandle);
+ }
+}
+
+/**
+ * Test IMapper::importBuffer with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ mGralloc->getMapper()->importBuffer(
+ invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "importBuffer with nullptr did not fail with BAD_BUFFER";
+ });
+
+ invalidHandle = native_handle_create(0, 0);
+ mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError,
+ const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "importBuffer with invalid handle did not fail with BAD_BUFFER";
+ });
+ native_handle_delete(invalidHandle);
+
+ const native_handle_t* importedHandle;
+ ASSERT_NO_FATAL_FAILURE(importedHandle =
+ mGralloc->allocate(mDummyDescriptorInfo, true));
+ mGralloc->getMapper()->importBuffer(
+ importedHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "importBuffer with an "
+ "already imported handle did "
+ "not fail with BAD_BUFFER";
+ });
+ mGralloc->freeBuffer(importedHandle);
+}
+
+/**
+ * Test IMapper::freeBuffer with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error)
+ << "freeBuffer with nullptr did not fail with BAD_BUFFER";
+
+ invalidHandle = native_handle_create(0, 0);
+ error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error)
+ << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(invalidHandle);
+
+ const native_handle_t* clonedBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(
+ clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+ error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error)
+ << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
+
+ mGralloc->freeBuffer(clonedBufferHandle);
}
/**
* Test IMapper::lock and IMapper::unlock.
*/
-TEST_F(GraphicsMapperHidlTest, LockBasic) {
- const auto& info = mDummyDescriptorInfo;
+TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+ const auto& info = mDummyDescriptorInfo;
- const native_handle_t* buffer;
- ASSERT_NO_FATAL_FAILURE(
- buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
+ const native_handle_t* bufferHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle =
+ mGralloc->allocate(info, true, &stride));
- uint32_t stride;
- ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ uint8_t* data;
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
+ bufferHandle, info.usage, region, fence)));
- // lock buffer for writing
- const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
- static_cast<int32_t>(info.height)};
- int fence = -1;
- uint32_t* data;
- ASSERT_NO_FATAL_FAILURE(
- data = static_cast<uint32_t*>(
- mMapper->lock(buffer, info.producerUsageMask, 0, region, fence)));
+ // RGBA_8888
+ size_t strideInBytes = stride * 4;
+ size_t writeInBytes = info.width * 4;
- for (uint32_t y = 0; y < info.height; y++) {
- for (uint32_t x = 0; x < info.width; x++) {
- data[stride * y + x] = info.height * y + x;
+ for (uint32_t y = 0; y < info.height; y++) {
+ memset(data, y, writeInBytes);
+ data += strideInBytes;
}
- }
- ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
- // lock buffer for reading
- ASSERT_NO_FATAL_FAILURE(
- data = static_cast<uint32_t*>(
- mMapper->lock(buffer, 0, info.consumerUsageMask, region, fence)));
- for (uint32_t y = 0; y < info.height; y++) {
- for (uint32_t x = 0; x < info.width; x++) {
- EXPECT_EQ(info.height * y + x, data[stride * y + x]);
+ // lock again for reading
+ ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
+ bufferHandle, info.usage, region, fence)));
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (size_t i = 0; i < writeInBytes; i++) {
+ EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
+ }
+ data += strideInBytes;
}
- }
- ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
- if (fence >= 0) {
- close(fence);
- }
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
}
/**
- * Test IMapper::lockFlex. This locks a YV12 buffer, and makes sure we can
+ * Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can
* write to and read from it.
*/
-TEST_F(GraphicsMapperHidlTest, LockFlexBasic) {
- auto info = mDummyDescriptorInfo;
- info.format = PixelFormat::YV12;
+TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::YV12;
- const native_handle_t* buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = mMapper->allocate(mAllocatorClient, info));
+ const native_handle_t* bufferHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle =
+ mGralloc->allocate(info, true, &stride));
- // lock buffer for writing
- const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
- static_cast<int32_t>(info.height)};
- int fence = -1;
- FlexLayout layout;
- ASSERT_NO_FATAL_FAILURE(
- layout =
- mMapper->lockFlex(buffer, info.producerUsageMask, 0, region, fence));
- ASSERT_EQ(FlexFormat::YCBCR, layout.format);
- ASSERT_EQ(3u, layout.planes.size());
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ YCbCrLayout layout;
+ ASSERT_NO_FATAL_FAILURE(
+ layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
- const auto y_stride = layout.planes[0].vIncrement;
- const auto c_stride = layout.planes[1].vIncrement;
- auto y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
- auto cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
- auto cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
+ auto yData = static_cast<uint8_t*>(layout.y);
+ auto cbData = static_cast<uint8_t*>(layout.cb);
+ auto crData = static_cast<uint8_t*>(layout.cr);
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
- for (uint32_t y = 0; y < info.height; y++) {
- for (uint32_t x = 0; x < info.width; x++) {
- auto val = static_cast<uint8_t>(info.height * y + x);
-
- y_data[y_stride * y + x] = val;
- if (y % 2 == 0 && x % 2 == 0) {
- cb_data[c_stride * y / 2 + x / 2] = val;
- cr_data[c_stride * y / 2 + x / 2] = val;
- }
+ yData[layout.yStride * y + x] = val;
+ if (y % 2 == 0 && x % 2 == 0) {
+ cbData[layout.cStride * y / 2 + x / 2] = val;
+ crData[layout.cStride * y / 2 + x / 2] = val;
+ }
+ }
}
- }
- ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
- // lock buffer for reading
- ASSERT_NO_FATAL_FAILURE(
- layout =
- mMapper->lockFlex(buffer, 0, info.consumerUsageMask, region, fence));
+ // lock again for reading
+ ASSERT_NO_FATAL_FAILURE(
+ layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
- y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
- cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
- cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
- for (uint32_t y = 0; y < info.height; y++) {
- for (uint32_t x = 0; x < info.width; x++) {
- auto val = static_cast<uint8_t>(info.height * y + x);
+ yData = static_cast<uint8_t*>(layout.y);
+ cbData = static_cast<uint8_t*>(layout.cb);
+ crData = static_cast<uint8_t*>(layout.cr);
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
- EXPECT_EQ(val, y_data[y_stride * y + x]);
- if (y % 2 == 0 && x % 2 == 0) {
- EXPECT_EQ(val, cb_data[c_stride * y / 2 + x / 2]);
- EXPECT_EQ(val, cr_data[c_stride * y / 2 + x / 2]);
- }
+ EXPECT_EQ(val, yData[layout.yStride * y + x]);
+ if (y % 2 == 0 && x % 2 == 0) {
+ EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]);
+ EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]);
+ }
+ }
}
- }
- ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
- if (fence >= 0) {
- close(fence);
- }
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
}
-} // namespace anonymous
+/**
+ * Test IMapper::unlock with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ mGralloc->getMapper()->unlock(
+ invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with nullptr did not fail with BAD_BUFFER";
+ });
+
+ invalidHandle = native_handle_create(0, 0);
+ mGralloc->getMapper()->unlock(
+ invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with invalid handle did not fail with BAD_BUFFER";
+ });
+ native_handle_delete(invalidHandle);
+
+ ASSERT_NO_FATAL_FAILURE(invalidHandle =
+ const_cast<native_handle_t*>(mGralloc->allocate(
+ mDummyDescriptorInfo, false)));
+ mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError,
+ const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with un-imported handle did not fail with BAD_BUFFER";
+ });
+ mGralloc->freeBuffer(invalidHandle);
+
+// disabled as it fails on many existing drivers
+#if 0
+ ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
+ mGralloc->allocate(mDummyDescriptorInfo, true)));
+ mGralloc->getMapper()->unlock(
+ invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with unlocked handle did not fail with BAD_BUFFER";
+ });
+ mGralloc->freeBuffer(invalidHandle);
+#endif
+}
+
+} // namespace
} // namespace tests
} // namespace V2_0
} // namespace mapper