gralloc: add IAllocator/IMapper 4.0 to frameworks/native
Add support for gralloc 4.0 to the framework.
Bug: 136016160
Test: Compiles and boots
Change-Id: I26408e984308fa557e102efabb60302907310308
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 2bbb0ee..8462fe7 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -65,6 +65,7 @@
"Gralloc.cpp",
"Gralloc2.cpp",
"Gralloc3.cpp",
+ "Gralloc4.cpp",
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
@@ -89,10 +90,12 @@
"android.frameworks.bufferhub@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"libbase",
"libcutils",
"libhidlbase",
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
new file mode 100644
index 0000000..dc105c0
--- /dev/null
+++ b/libs/ui/Gralloc4.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2019 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 "Gralloc4"
+
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <ui/Gralloc4.h>
+
+#include <inttypes.h>
+#include <log/log.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#include <sync/sync.h>
+#pragma clang diagnostic pop
+
+using android::hardware::graphics::allocator::V4_0::IAllocator;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::IMapper;
+using android::hardware::graphics::mapper::V4_0::YCbCrLayout;
+
+namespace android {
+
+namespace {
+
+static constexpr Error kTransactionError = Error::NO_RESOURCES;
+
+uint64_t getValidUsageBits() {
+ static const uint64_t validUsageBits = []() -> uint64_t {
+ uint64_t bits = 0;
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ return bits;
+ }();
+ return validUsageBits;
+}
+
+static inline IMapper::Rect sGralloc4Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+static inline void sBufferDescriptorInfo(uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount,
+ uint64_t usage,
+ IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+ outDescriptorInfo->width = width;
+ outDescriptorInfo->height = height;
+ outDescriptorInfo->layerCount = layerCount;
+ outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
+ outDescriptorInfo->usage = usage;
+}
+
+} // anonymous namespace
+
+void Gralloc4Mapper::preload() {
+ android::hardware::preloadPassthroughService<IMapper>();
+}
+
+Gralloc4Mapper::Gralloc4Mapper() {
+ mMapper = IMapper::getService();
+ if (mMapper == nullptr) {
+ ALOGI("mapper 4.x is not supported");
+ return;
+ }
+ if (mMapper->isRemote()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
+ }
+}
+
+bool Gralloc4Mapper::isLoaded() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc4Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
+ uint64_t validUsageBits = getValidUsageBits();
+
+ if (descriptorInfo->usage & ~validUsageBits) {
+ ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+status_t Gralloc4Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ Error error;
+ auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outDescriptor = tmpDescriptor;
+ };
+
+ hardware::Return<void> ret = mMapper->createDescriptor(*descriptorInfo, hidl_cb);
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+status_t Gralloc4Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
+ Error error;
+ auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
+ });
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+void Gralloc4Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->freeBuffer(buffer);
+
+ auto error = (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc4Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
+}
+
+void Gralloc4Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
+ *outNumFds = uint32_t(bufferHandle->numFds);
+ *outNumInts = uint32_t(bufferHandle->numInts);
+
+ Error error;
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->getTransportSize(buffer,
+ [&](const auto& tmpError, const auto& tmpNumFds,
+ const auto& tmpNumInts) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc4Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ Error error;
+ auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData,
+ const auto& tmpBytesPerPixel, const auto& tmpBytesPerStride) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outData = tmpData;
+ if (outBytesPerPixel) {
+ *outBytesPerPixel = tmpBytesPerPixel;
+ }
+ if (outBytesPerStride) {
+ *outBytesPerStride = tmpBytesPerStride;
+ }
+ });
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
+}
+
+status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc4Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ YCbCrLayout layout;
+ Error error;
+ auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ layout = tmpLayout;
+ });
+
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+int Gralloc4Mapper::unlock(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ Error error;
+ auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle && fenceHandle->numFds == 1) {
+ int fd = dup(fenceHandle->data[0]);
+ if (fd >= 0) {
+ releaseFence = fd;
+ } else {
+ ALOGD("failed to dup unlock release fence");
+ sync_wait(fenceHandle->data[0], -1);
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("unlock(%p) failed with %d", buffer, error);
+ }
+
+ return releaseFence;
+}
+
+status_t Gralloc4Mapper::isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ bool* outSupported) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ Error error;
+ auto ret = mMapper->isSupported(descriptorInfo,
+ [&](const auto& tmpError, const auto& tmpSupported) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ if (outSupported) {
+ *outSupported = tmpSupported;
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("isSupported(%u, %u, %d, %u, ...) failed with %d", width, height, format, layerCount,
+ error);
+ }
+
+ return static_cast<status_t>(error);
+}
+
+Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) {
+ mAllocator = IAllocator::getService();
+ if (mAllocator == nullptr) {
+ ALOGW("allocator 3.x is not supported");
+ return;
+ }
+}
+
+bool Gralloc4Allocator::isLoaded() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc4Allocator::dumpDebugInfo() const {
+ std::string debugInfo;
+
+ mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+status_t Gralloc4Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+ *outStride = tmpStride;
+ });
+
+ // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
+ hardware::IPCThreadState::self()->flushCommands();
+
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 9c7d1fd..eb787a2 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -33,6 +33,7 @@
#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
#include <ui/Gralloc3.h>
+#include <ui/Gralloc4.h>
#include <ui/GraphicBufferMapper.h>
namespace android {
@@ -47,16 +48,23 @@
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
+ mAllocator = std::make_unique<const Gralloc4Allocator>(
+ reinterpret_cast<const Gralloc4Mapper&>(mMapper.getGrallocMapper()));
+ if (mAllocator->isLoaded()) {
+ return;
+ }
mAllocator = std::make_unique<const Gralloc3Allocator>(
reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
- if (!mAllocator->isLoaded()) {
- mAllocator = std::make_unique<const Gralloc2Allocator>(
- reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+ if (mAllocator->isLoaded()) {
+ return;
+ }
+ mAllocator = std::make_unique<const Gralloc2Allocator>(
+ reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+ if (mAllocator->isLoaded()) {
+ return;
}
- if (!mAllocator->isLoaded()) {
- LOG_ALWAYS_FATAL("gralloc-allocator is missing");
- }
+ LOG_ALWAYS_FATAL("gralloc-allocator is missing");
}
GraphicBufferAllocator::~GraphicBufferAllocator() {}
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 25b7247..4d087d1 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -35,6 +35,7 @@
#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
#include <ui/Gralloc3.h>
+#include <ui/Gralloc4.h>
#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
@@ -47,20 +48,27 @@
void GraphicBufferMapper::preloadHal() {
Gralloc2Mapper::preload();
Gralloc3Mapper::preload();
+ Gralloc4Mapper::preload();
}
GraphicBufferMapper::GraphicBufferMapper() {
+ mMapper = std::make_unique<const Gralloc4Mapper>();
+ if (mMapper->isLoaded()) {
+ mMapperVersion = Version::GRALLOC_4;
+ return;
+ }
mMapper = std::make_unique<const Gralloc3Mapper>();
- if (!mMapper->isLoaded()) {
- mMapper = std::make_unique<const Gralloc2Mapper>();
- mMapperVersion = Version::GRALLOC_2;
- } else {
+ if (mMapper->isLoaded()) {
mMapperVersion = Version::GRALLOC_3;
+ return;
+ }
+ mMapper = std::make_unique<const Gralloc2Mapper>();
+ if (mMapper->isLoaded()) {
+ mMapperVersion = Version::GRALLOC_2;
+ return;
}
- if (!mMapper->isLoaded()) {
- LOG_ALWAYS_FATAL("gralloc-mapper is missing");
- }
+ LOG_ALWAYS_FATAL("gralloc-mapper is missing");
}
status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h
new file mode 100644
index 0000000..14b65bc
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc4.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 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_UI_GRALLOC4_H
+#define ANDROID_UI_GRALLOC4_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Gralloc4Mapper : public GrallocMapper {
+public:
+ static void preload();
+
+ Gralloc4Mapper();
+
+ bool isLoaded() const override;
+
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
+
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
+
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
+
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
+
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
+
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
+
+private:
+ // Determines whether the passed info is compatible with the mapper.
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo* descriptorInfo) const;
+
+ sp<hardware::graphics::mapper::V4_0::IMapper> mMapper;
+};
+
+class Gralloc4Allocator : public GrallocAllocator {
+public:
+ // An allocator relies on a mapper, and that mapper must be alive at all
+ // time.
+ Gralloc4Allocator(const Gralloc4Mapper& mapper);
+
+ bool isLoaded() const override;
+
+ std::string dumpDebugInfo() const override;
+
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
+
+private:
+ const Gralloc4Mapper& mMapper;
+ sp<hardware::graphics::allocator::V4_0::IAllocator> mAllocator;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC4_H
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 2461454..c401a48 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -44,6 +44,7 @@
enum Version {
GRALLOC_2,
GRALLOC_3,
+ GRALLOC_4,
};
static void preloadHal();
static inline GraphicBufferMapper& get() { return getInstance(); }