blob: 2a607308d1e8fb3d1d9ebce609531d1b355ee9bf [file] [log] [blame]
/*
* 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 <aidl/android/hardware/graphics/allocator/AllocationError.h>
#include <aidl/android/hardware/graphics/allocator/AllocationResult.h>
#include <aidl/android/hardware/graphics/common/BufferUsage.h>
#include <aidlcommonsupport/NativeHandle.h>
#include <android/binder_enums.h>
#include <android/binder_manager.h>
#include <cutils/android_filesystem_config.h>
#include <cutils/multiuser.h>
#include <gralloctypes/Gralloc4.h>
#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 aidl::android::hardware::graphics::allocator::AllocationError;
using aidl::android::hardware::graphics::allocator::AllocationResult;
using aidl::android::hardware::graphics::common::ExtendableType;
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
using aidl::android::hardware::graphics::common::StandardMetadataType;
using android::hardware::hidl_vec;
using android::hardware::graphics::allocator::V4_0::IAllocator;
using android::hardware::graphics::common::V1_2::BufferUsage;
using android::hardware::graphics::common::V1_2::PixelFormat;
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 AidlIAllocator = ::aidl::android::hardware::graphics::allocator::IAllocator;
using AidlBufferUsage = ::aidl::android::hardware::graphics::common::BufferUsage;
using AidlDataspace = ::aidl::android::hardware::graphics::common::Dataspace;
using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle;
using BufferDump = android::hardware::graphics::mapper::V4_0::IMapper::BufferDump;
using MetadataDump = android::hardware::graphics::mapper::V4_0::IMapper::MetadataDump;
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
using MetadataTypeDescription =
android::hardware::graphics::mapper::V4_0::IMapper::MetadataTypeDescription;
namespace android {
namespace {
static constexpr Error kTransactionError = Error::NO_RESOURCES;
static const auto kAidlAllocatorServiceName = AidlIAllocator::descriptor + std::string("/default");
// TODO(b/72323293, b/72703005): Remove these invalid bits from callers
static constexpr uint64_t kRemovedUsageBits = static_cast<uint64_t>((1 << 10) | (1 << 13));
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 | kRemovedUsageBits;
}
uint64_t getValidUsageBits41() {
static const uint64_t validUsageBits = []() -> uint64_t {
uint64_t bits = 0;
for (const auto bit : ndk::enum_range<AidlBufferUsage>{}) {
bits |= static_cast<int64_t>(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;
}
// See if gralloc "4.1" is available.
static bool hasIAllocatorAidl() {
// Avoid re-querying repeatedly for this information;
static bool sHasIAllocatorAidl = []() -> bool {
if (__builtin_available(android 31, *)) {
return AServiceManager_isDeclared(kAidlAllocatorServiceName.c_str());
}
return false;
}();
return sHasIAllocatorAidl;
}
// Determines whether the passed info is compatible with the mapper.
static status_t validateBufferDescriptorInfo(IMapper::BufferDescriptorInfo* descriptorInfo) {
uint64_t validUsageBits = getValidUsageBits();
if (hasIAllocatorAidl()) {
validUsageBits |= getValidUsageBits41();
}
if (descriptorInfo->usage & ~validUsageBits) {
ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
descriptorInfo->usage & ~validUsageBits);
return BAD_VALUE;
}
// Combinations that are only allowed with gralloc 4.1.
// Previous grallocs must be protected from this.
if (!hasIAllocatorAidl() &&
descriptorInfo->format != hardware::graphics::common::V1_2::PixelFormat::BLOB &&
descriptorInfo->usage & BufferUsage::GPU_DATA_BUFFER) {
ALOGE("non-BLOB pixel format with GPU_DATA_BUFFER usage is not supported prior to gralloc 4.1");
return BAD_VALUE;
}
return NO_ERROR;
}
static inline status_t sBufferDescriptorInfo(std::string name, uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount,
uint64_t usage,
IMapper::BufferDescriptorInfo* outDescriptorInfo) {
outDescriptorInfo->name = name;
outDescriptorInfo->width = width;
outDescriptorInfo->height = height;
outDescriptorInfo->layerCount = layerCount;
outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
outDescriptorInfo->usage = usage;
outDescriptorInfo->reservedSize = 0;
return validateBufferDescriptorInfo(outDescriptorInfo);
}
} // 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::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 native_handle_t* 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, PixelFormat format,
uint32_t layerCount, uint64_t usage,
uint32_t stride) const {
IMapper::BufferDescriptorInfo descriptorInfo;
if (auto error = sBufferDescriptorInfo("validateBufferSize", width, height, format, layerCount,
usage, &descriptorInfo) != OK) {
return error;
}
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 {
if (outBytesPerPixel) *outBytesPerPixel = -1;
if (outBytesPerStride) *outBytesPerStride = -1;
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) {
error = tmpError;
if (error != Error::NONE) {
return;
}
*outData = tmpData;
});
// 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* outYcbcr) const {
if (!outYcbcr) {
return BAD_VALUE;
}
std::vector<ui::PlaneLayout> planeLayouts;
status_t error = getPlaneLayouts(bufferHandle, &planeLayouts);
if (error != NO_ERROR) {
return error;
}
void* data = nullptr;
error = lock(bufferHandle, usage, bounds, acquireFence, &data, nullptr, nullptr);
if (error != NO_ERROR) {
return error;
}
android_ycbcr ycbcr;
ycbcr.y = nullptr;
ycbcr.cb = nullptr;
ycbcr.cr = nullptr;
ycbcr.ystride = 0;
ycbcr.cstride = 0;
ycbcr.chroma_step = 0;
for (const auto& planeLayout : planeLayouts) {
for (const auto& planeLayoutComponent : planeLayout.components) {
if (!gralloc4::isStandardPlaneLayoutComponentType(planeLayoutComponent.type)) {
continue;
}
uint8_t* tmpData = static_cast<uint8_t*>(data) + planeLayout.offsetInBytes;
// Note that `offsetInBits` may not be a multiple of 8 for packed formats (e.g. P010)
// but we still want to point to the start of the first byte.
tmpData += (planeLayoutComponent.offsetInBits / 8);
uint64_t sampleIncrementInBytes;
auto type = static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value);
switch (type) {
case PlaneLayoutComponentType::Y:
if ((ycbcr.y != nullptr) || (planeLayout.sampleIncrementInBits % 8 != 0)) {
unlock(bufferHandle);
return BAD_VALUE;
}
ycbcr.y = tmpData;
ycbcr.ystride = planeLayout.strideInBytes;
break;
case PlaneLayoutComponentType::CB:
case PlaneLayoutComponentType::CR:
if (planeLayout.sampleIncrementInBits % 8 != 0) {
unlock(bufferHandle);
return BAD_VALUE;
}
sampleIncrementInBytes = planeLayout.sampleIncrementInBits / 8;
if ((sampleIncrementInBytes != 1) && (sampleIncrementInBytes != 2) &&
(sampleIncrementInBytes != 4)) {
unlock(bufferHandle);
return BAD_VALUE;
}
if (ycbcr.cstride == 0 && ycbcr.chroma_step == 0) {
ycbcr.cstride = planeLayout.strideInBytes;
ycbcr.chroma_step = sampleIncrementInBytes;
} else {
if ((static_cast<int64_t>(ycbcr.cstride) != planeLayout.strideInBytes) ||
(ycbcr.chroma_step != sampleIncrementInBytes)) {
unlock(bufferHandle);
return BAD_VALUE;
}
}
if (type == PlaneLayoutComponentType::CB) {
if (ycbcr.cb != nullptr) {
unlock(bufferHandle);
return BAD_VALUE;
}
ycbcr.cb = tmpData;
} else {
if (ycbcr.cr != nullptr) {
unlock(bufferHandle);
return BAD_VALUE;
}
ycbcr.cr = tmpData;
}
break;
default:
break;
};
}
}
*outYcbcr = ycbcr;
return static_cast<status_t>(Error::NONE);
}
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 {
ALOGW("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, PixelFormat format,
uint32_t layerCount, uint64_t usage,
bool* outSupported) const {
IMapper::BufferDescriptorInfo descriptorInfo;
if (sBufferDescriptorInfo("isSupported", width, height, format, layerCount, usage,
&descriptorInfo) != OK) {
// Usage isn't known to the HAL or otherwise failed validation.
*outSupported = false;
return OK;
}
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);
}
template <class T>
status_t Gralloc4Mapper::get(buffer_handle_t bufferHandle, const MetadataType& metadataType,
DecodeFunction<T> decodeFunction, T* outMetadata) const {
if (!outMetadata) {
return BAD_VALUE;
}
hidl_vec<uint8_t> vec;
Error error;
auto ret = mMapper->get(const_cast<native_handle_t*>(bufferHandle), metadataType,
[&](const auto& tmpError, const hidl_vec<uint8_t>& tmpVec) {
error = tmpError;
vec = tmpVec;
});
if (!ret.isOk()) {
error = kTransactionError;
}
if (error != Error::NONE) {
ALOGE("get(%s, %" PRIu64 ", ...) failed with %d", metadataType.name.c_str(),
metadataType.value, error);
return static_cast<status_t>(error);
}
return decodeFunction(vec, outMetadata);
}
template <class T>
status_t Gralloc4Mapper::set(buffer_handle_t bufferHandle, const MetadataType& metadataType,
const T& metadata, EncodeFunction<T> encodeFunction) const {
hidl_vec<uint8_t> encodedMetadata;
if (const status_t status = encodeFunction(metadata, &encodedMetadata); status != OK) {
ALOGE("Encoding metadata(%s) failed with %d", metadataType.name.c_str(), status);
return status;
}
hidl_vec<uint8_t> vec;
auto ret =
mMapper->set(const_cast<native_handle_t*>(bufferHandle), metadataType, encodedMetadata);
const Error error = ret.withDefault(kTransactionError);
switch (error) {
case Error::BAD_DESCRIPTOR:
case Error::BAD_BUFFER:
case Error::BAD_VALUE:
case Error::NO_RESOURCES:
ALOGE("set(%s, %" PRIu64 ", ...) failed with %d", metadataType.name.c_str(),
metadataType.value, error);
break;
// It is not an error to attempt to set metadata that a particular gralloc implementation
// happens to not support.
case Error::UNSUPPORTED:
case Error::NONE:
break;
}
return static_cast<status_t>(error);
}
status_t Gralloc4Mapper::getBufferId(buffer_handle_t bufferHandle, uint64_t* outBufferId) const {
return get(bufferHandle, gralloc4::MetadataType_BufferId, gralloc4::decodeBufferId,
outBufferId);
}
status_t Gralloc4Mapper::getName(buffer_handle_t bufferHandle, std::string* outName) const {
return get(bufferHandle, gralloc4::MetadataType_Name, gralloc4::decodeName, outName);
}
status_t Gralloc4Mapper::getWidth(buffer_handle_t bufferHandle, uint64_t* outWidth) const {
return get(bufferHandle, gralloc4::MetadataType_Width, gralloc4::decodeWidth, outWidth);
}
status_t Gralloc4Mapper::getHeight(buffer_handle_t bufferHandle, uint64_t* outHeight) const {
return get(bufferHandle, gralloc4::MetadataType_Height, gralloc4::decodeHeight, outHeight);
}
status_t Gralloc4Mapper::getLayerCount(buffer_handle_t bufferHandle,
uint64_t* outLayerCount) const {
return get(bufferHandle, gralloc4::MetadataType_LayerCount, gralloc4::decodeLayerCount,
outLayerCount);
}
status_t Gralloc4Mapper::getPixelFormatRequested(buffer_handle_t bufferHandle,
ui::PixelFormat* outPixelFormatRequested) const {
return get(bufferHandle, gralloc4::MetadataType_PixelFormatRequested,
gralloc4::decodePixelFormatRequested, outPixelFormatRequested);
}
status_t Gralloc4Mapper::getPixelFormatFourCC(buffer_handle_t bufferHandle,
uint32_t* outPixelFormatFourCC) const {
return get(bufferHandle, gralloc4::MetadataType_PixelFormatFourCC,
gralloc4::decodePixelFormatFourCC, outPixelFormatFourCC);
}
status_t Gralloc4Mapper::getPixelFormatModifier(buffer_handle_t bufferHandle,
uint64_t* outPixelFormatModifier) const {
return get(bufferHandle, gralloc4::MetadataType_PixelFormatModifier,
gralloc4::decodePixelFormatModifier, outPixelFormatModifier);
}
status_t Gralloc4Mapper::getUsage(buffer_handle_t bufferHandle, uint64_t* outUsage) const {
return get(bufferHandle, gralloc4::MetadataType_Usage, gralloc4::decodeUsage, outUsage);
}
status_t Gralloc4Mapper::getAllocationSize(buffer_handle_t bufferHandle,
uint64_t* outAllocationSize) const {
return get(bufferHandle, gralloc4::MetadataType_AllocationSize, gralloc4::decodeAllocationSize,
outAllocationSize);
}
status_t Gralloc4Mapper::getProtectedContent(buffer_handle_t bufferHandle,
uint64_t* outProtectedContent) const {
return get(bufferHandle, gralloc4::MetadataType_ProtectedContent,
gralloc4::decodeProtectedContent, outProtectedContent);
}
status_t Gralloc4Mapper::getCompression(buffer_handle_t bufferHandle,
ExtendableType* outCompression) const {
return get(bufferHandle, gralloc4::MetadataType_Compression, gralloc4::decodeCompression,
outCompression);
}
status_t Gralloc4Mapper::getCompression(buffer_handle_t bufferHandle,
ui::Compression* outCompression) const {
if (!outCompression) {
return BAD_VALUE;
}
ExtendableType compression;
status_t error = getCompression(bufferHandle, &compression);
if (error) {
return error;
}
if (!gralloc4::isStandardCompression(compression)) {
return BAD_TYPE;
}
*outCompression = gralloc4::getStandardCompressionValue(compression);
return NO_ERROR;
}
status_t Gralloc4Mapper::getInterlaced(buffer_handle_t bufferHandle,
ExtendableType* outInterlaced) const {
return get(bufferHandle, gralloc4::MetadataType_Interlaced, gralloc4::decodeInterlaced,
outInterlaced);
}
status_t Gralloc4Mapper::getInterlaced(buffer_handle_t bufferHandle,
ui::Interlaced* outInterlaced) const {
if (!outInterlaced) {
return BAD_VALUE;
}
ExtendableType interlaced;
status_t error = getInterlaced(bufferHandle, &interlaced);
if (error) {
return error;
}
if (!gralloc4::isStandardInterlaced(interlaced)) {
return BAD_TYPE;
}
*outInterlaced = gralloc4::getStandardInterlacedValue(interlaced);
return NO_ERROR;
}
status_t Gralloc4Mapper::getChromaSiting(buffer_handle_t bufferHandle,
ExtendableType* outChromaSiting) const {
return get(bufferHandle, gralloc4::MetadataType_ChromaSiting, gralloc4::decodeChromaSiting,
outChromaSiting);
}
status_t Gralloc4Mapper::getChromaSiting(buffer_handle_t bufferHandle,
ui::ChromaSiting* outChromaSiting) const {
if (!outChromaSiting) {
return BAD_VALUE;
}
ExtendableType chromaSiting;
status_t error = getChromaSiting(bufferHandle, &chromaSiting);
if (error) {
return error;
}
if (!gralloc4::isStandardChromaSiting(chromaSiting)) {
return BAD_TYPE;
}
*outChromaSiting = gralloc4::getStandardChromaSitingValue(chromaSiting);
return NO_ERROR;
}
status_t Gralloc4Mapper::getPlaneLayouts(buffer_handle_t bufferHandle,
std::vector<ui::PlaneLayout>* outPlaneLayouts) const {
return get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, gralloc4::decodePlaneLayouts,
outPlaneLayouts);
}
status_t Gralloc4Mapper::getDataspace(buffer_handle_t bufferHandle,
ui::Dataspace* outDataspace) const {
if (!outDataspace) {
return BAD_VALUE;
}
AidlDataspace dataspace;
status_t error = get(bufferHandle, gralloc4::MetadataType_Dataspace, gralloc4::decodeDataspace,
&dataspace);
if (error) {
return error;
}
// Gralloc4 uses stable AIDL dataspace but the rest of the system still uses HIDL dataspace
*outDataspace = static_cast<ui::Dataspace>(dataspace);
return NO_ERROR;
}
status_t Gralloc4Mapper::setDataspace(buffer_handle_t bufferHandle, ui::Dataspace dataspace) const {
return set(bufferHandle, gralloc4::MetadataType_Dataspace,
static_cast<aidl::android::hardware::graphics::common::Dataspace>(dataspace),
gralloc4::encodeDataspace);
}
status_t Gralloc4Mapper::getBlendMode(buffer_handle_t bufferHandle,
ui::BlendMode* outBlendMode) const {
return get(bufferHandle, gralloc4::MetadataType_BlendMode, gralloc4::decodeBlendMode,
outBlendMode);
}
status_t Gralloc4Mapper::getSmpte2086(buffer_handle_t bufferHandle,
std::optional<ui::Smpte2086>* outSmpte2086) const {
return get(bufferHandle, gralloc4::MetadataType_Smpte2086, gralloc4::decodeSmpte2086,
outSmpte2086);
}
status_t Gralloc4Mapper::setSmpte2086(buffer_handle_t bufferHandle,
std::optional<ui::Smpte2086> smpte2086) const {
return set(bufferHandle, gralloc4::MetadataType_Smpte2086, smpte2086,
gralloc4::encodeSmpte2086);
}
status_t Gralloc4Mapper::getCta861_3(buffer_handle_t bufferHandle,
std::optional<ui::Cta861_3>* outCta861_3) const {
return get(bufferHandle, gralloc4::MetadataType_Cta861_3, gralloc4::decodeCta861_3,
outCta861_3);
}
status_t Gralloc4Mapper::setCta861_3(buffer_handle_t bufferHandle,
std::optional<ui::Cta861_3> cta861_3) const {
return set(bufferHandle, gralloc4::MetadataType_Cta861_3, cta861_3, gralloc4::encodeCta861_3);
}
status_t Gralloc4Mapper::getSmpte2094_40(
buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_40) const {
return get(bufferHandle, gralloc4::MetadataType_Smpte2094_40, gralloc4::decodeSmpte2094_40,
outSmpte2094_40);
}
status_t Gralloc4Mapper::setSmpte2094_40(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>> smpte2094_40) const {
return set(bufferHandle, gralloc4::MetadataType_Smpte2094_40, smpte2094_40,
gralloc4::encodeSmpte2094_40);
}
status_t Gralloc4Mapper::getSmpte2094_10(
buffer_handle_t bufferHandle, std::optional<std::vector<uint8_t>>* outSmpte2094_10) const {
return get(bufferHandle, gralloc4::MetadataType_Smpte2094_10, gralloc4::decodeSmpte2094_10,
outSmpte2094_10);
}
status_t Gralloc4Mapper::setSmpte2094_10(buffer_handle_t bufferHandle,
std::optional<std::vector<uint8_t>> smpte2094_10) const {
return set(bufferHandle, gralloc4::MetadataType_Smpte2094_10, smpte2094_10,
gralloc4::encodeSmpte2094_10);
}
std::vector<MetadataTypeDescription> Gralloc4Mapper::listSupportedMetadataTypes() const {
hidl_vec<MetadataTypeDescription> descriptions;
Error error;
auto ret = mMapper->listSupportedMetadataTypes(
[&](const auto& tmpError, const auto& tmpDescriptions) {
error = tmpError;
descriptions = tmpDescriptions;
});
if (!ret.isOk()) {
error = kTransactionError;
}
if (error != Error::NONE) {
ALOGE("listSupportedMetadataType() failed with %d", error);
return {};
}
return static_cast<std::vector<MetadataTypeDescription>>(descriptions);
}
template <class T>
status_t Gralloc4Mapper::metadataDumpHelper(const BufferDump& bufferDump,
StandardMetadataType metadataType,
DecodeFunction<T> decodeFunction, T* outT) const {
const auto& metadataDump = bufferDump.metadataDump;
auto itr =
std::find_if(metadataDump.begin(), metadataDump.end(),
[&](const MetadataDump& tmpMetadataDump) {
if (!gralloc4::isStandardMetadataType(tmpMetadataDump.metadataType)) {
return false;
}
return metadataType ==
gralloc4::getStandardMetadataTypeValue(
tmpMetadataDump.metadataType);
});
if (itr == metadataDump.end()) {
return BAD_VALUE;
}
return decodeFunction(itr->metadata, outT);
}
status_t Gralloc4Mapper::bufferDumpHelper(const BufferDump& bufferDump, std::ostringstream* outDump,
uint64_t* outAllocationSize, bool less) const {
uint64_t bufferId;
std::string name;
uint64_t width;
uint64_t height;
uint64_t layerCount;
ui::PixelFormat pixelFormatRequested;
uint32_t pixelFormatFourCC;
uint64_t pixelFormatModifier;
uint64_t usage;
AidlDataspace dataspace;
uint64_t allocationSize;
uint64_t protectedContent;
ExtendableType compression;
ExtendableType interlaced;
ExtendableType chromaSiting;
std::vector<ui::PlaneLayout> planeLayouts;
status_t error = metadataDumpHelper(bufferDump, StandardMetadataType::BUFFER_ID,
gralloc4::decodeBufferId, &bufferId);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::NAME, gralloc4::decodeName, &name);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::WIDTH, gralloc4::decodeWidth,
&width);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::HEIGHT, gralloc4::decodeHeight,
&height);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::LAYER_COUNT,
gralloc4::decodeLayerCount, &layerCount);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::PIXEL_FORMAT_REQUESTED,
gralloc4::decodePixelFormatRequested, &pixelFormatRequested);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::PIXEL_FORMAT_FOURCC,
gralloc4::decodePixelFormatFourCC, &pixelFormatFourCC);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::PIXEL_FORMAT_MODIFIER,
gralloc4::decodePixelFormatModifier, &pixelFormatModifier);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::USAGE, gralloc4::decodeUsage,
&usage);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::DATASPACE,
gralloc4::decodeDataspace, &dataspace);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::ALLOCATION_SIZE,
gralloc4::decodeAllocationSize, &allocationSize);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::PROTECTED_CONTENT,
gralloc4::decodeProtectedContent, &protectedContent);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::COMPRESSION,
gralloc4::decodeCompression, &compression);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::INTERLACED,
gralloc4::decodeInterlaced, &interlaced);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::CHROMA_SITING,
gralloc4::decodeChromaSiting, &chromaSiting);
if (error != NO_ERROR) {
return error;
}
error = metadataDumpHelper(bufferDump, StandardMetadataType::PLANE_LAYOUTS,
gralloc4::decodePlaneLayouts, &planeLayouts);
if (error != NO_ERROR) {
return error;
}
if (outAllocationSize) {
*outAllocationSize = allocationSize;
}
double allocationSizeKiB = static_cast<double>(allocationSize) / 1024;
*outDump << "+ name:" << name << ", id:" << bufferId << ", size:" << std::fixed
<< allocationSizeKiB << "KiB, w/h:" << width << "x" << height << ", usage: 0x"
<< std::hex << usage << std::dec
<< ", req fmt:" << static_cast<int32_t>(pixelFormatRequested)
<< ", fourcc/mod:" << pixelFormatFourCC << "/" << pixelFormatModifier
<< ", dataspace: 0x" << std::hex << static_cast<uint32_t>(dataspace) << std::dec
<< ", compressed: ";
if (less) {
bool isCompressed = !gralloc4::isStandardCompression(compression) ||
(gralloc4::getStandardCompressionValue(compression) != ui::Compression::NONE);
*outDump << std::boolalpha << isCompressed << "\n";
} else {
*outDump << gralloc4::getCompressionName(compression) << "\n";
}
bool firstPlane = true;
for (const auto& planeLayout : planeLayouts) {
if (firstPlane) {
firstPlane = false;
*outDump << "\tplanes: ";
} else {
*outDump << "\t ";
}
for (size_t i = 0; i < planeLayout.components.size(); i++) {
const auto& planeLayoutComponent = planeLayout.components[i];
*outDump << gralloc4::getPlaneLayoutComponentTypeName(planeLayoutComponent.type);
if (i < planeLayout.components.size() - 1) {
*outDump << "/";
} else {
*outDump << ":\t";
}
}
*outDump << " w/h:" << planeLayout.widthInSamples << "x" << planeLayout.heightInSamples
<< ", stride:" << planeLayout.strideInBytes
<< " bytes, size:" << planeLayout.totalSizeInBytes;
if (!less) {
*outDump << ", inc:" << planeLayout.sampleIncrementInBits
<< " bits, subsampling w/h:" << planeLayout.horizontalSubsampling << "x"
<< planeLayout.verticalSubsampling;
}
*outDump << "\n";
}
if (!less) {
*outDump << "\tlayer cnt: " << layerCount << ", protected content: " << protectedContent
<< ", interlaced: " << gralloc4::getInterlacedName(interlaced)
<< ", chroma siting:" << gralloc4::getChromaSitingName(chromaSiting) << "\n";
}
return NO_ERROR;
}
std::string Gralloc4Mapper::dumpBuffer(buffer_handle_t bufferHandle, bool less) const {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
BufferDump bufferDump;
Error error;
auto ret = mMapper->dumpBuffer(buffer, [&](const auto& tmpError, const auto& tmpBufferDump) {
error = tmpError;
bufferDump = tmpBufferDump;
});
if (!ret.isOk()) {
error = kTransactionError;
}
if (error != Error::NONE) {
ALOGE("dumpBuffer() failed with %d", error);
return "";
}
std::ostringstream stream;
stream.precision(2);
status_t err = bufferDumpHelper(bufferDump, &stream, nullptr, less);
if (err != NO_ERROR) {
ALOGE("bufferDumpHelper() failed with %d", err);
return "";
}
return stream.str();
}
std::string Gralloc4Mapper::dumpBuffers(bool less) const {
hidl_vec<BufferDump> bufferDumps;
Error error;
auto ret = mMapper->dumpBuffers([&](const auto& tmpError, const auto& tmpBufferDump) {
error = tmpError;
bufferDumps = tmpBufferDump;
});
if (!ret.isOk()) {
error = kTransactionError;
}
if (error != Error::NONE) {
ALOGE("dumpBuffer() failed with %d", error);
return "";
}
uint64_t totalAllocationSize = 0;
std::ostringstream stream;
stream.precision(2);
stream << "Imported gralloc buffers:\n";
for (const auto& bufferDump : bufferDumps) {
uint64_t allocationSize = 0;
status_t err = bufferDumpHelper(bufferDump, &stream, &allocationSize, less);
if (err != NO_ERROR) {
ALOGE("bufferDumpHelper() failed with %d", err);
return "";
}
totalAllocationSize += allocationSize;
}
double totalAllocationSizeKiB = static_cast<double>(totalAllocationSize) / 1024;
stream << "Total imported by gralloc: " << totalAllocationSizeKiB << "KiB\n";
return stream.str();
}
Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) {
mAllocator = IAllocator::getService();
if (__builtin_available(android 31, *)) {
if (hasIAllocatorAidl()) {
// TODO(b/269517338): Perform the isolated checking for this in service manager instead.
uid_t aid = multiuser_get_app_id(getuid());
if (aid >= AID_ISOLATED_START && aid <= AID_ISOLATED_END) {
mAidlAllocator = AidlIAllocator::fromBinder(ndk::SpAIBinder(
AServiceManager_getService(kAidlAllocatorServiceName.c_str())));
} else {
mAidlAllocator = AidlIAllocator::fromBinder(ndk::SpAIBinder(
AServiceManager_waitForService(kAidlAllocatorServiceName.c_str())));
}
ALOGE_IF(!mAidlAllocator, "AIDL IAllocator declared but failed to get service");
}
}
if (mAllocator == nullptr && mAidlAllocator == nullptr) {
ALOGW("allocator 4.x is not supported");
return;
}
}
bool Gralloc4Allocator::isLoaded() const {
return mAllocator != nullptr || mAidlAllocator != nullptr;
}
std::string Gralloc4Allocator::dumpDebugInfo(bool less) const {
return mMapper.dumpBuffers(less);
}
status_t Gralloc4Allocator::allocate(std::string requestorName, uint32_t width, uint32_t height,
android::PixelFormat format, uint32_t layerCount,
uint64_t usage, uint32_t* outStride,
buffer_handle_t* outBufferHandles, bool importBuffers) const {
IMapper::BufferDescriptorInfo descriptorInfo;
if (auto error = sBufferDescriptorInfo(requestorName, width, height, format, layerCount, usage,
&descriptorInfo) != OK) {
return error;
}
BufferDescriptor descriptor;
status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
static_cast<void*>(&descriptor));
if (error != NO_ERROR) {
return error;
}
constexpr auto bufferCount = 1;
if (mAidlAllocator) {
AllocationResult result;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
auto status = mAidlAllocator->allocate(descriptor, bufferCount, &result);
#pragma clang diagnostic pop // deprecation
if (!status.isOk()) {
error = status.getExceptionCode();
if (error == EX_SERVICE_SPECIFIC) {
error = status.getServiceSpecificError();
}
if (error == OK) {
error = UNKNOWN_ERROR;
}
} else {
if (importBuffers) {
for (uint32_t i = 0; i < bufferCount; i++) {
auto handle = makeFromAidl(result.buffers[i]);
error = mMapper.importBuffer(handle, &outBufferHandles[i]);
native_handle_delete(handle);
if (error != NO_ERROR) {
for (uint32_t j = 0; j < i; j++) {
mMapper.freeBuffer(outBufferHandles[j]);
outBufferHandles[j] = nullptr;
}
break;
}
}
} else {
for (uint32_t i = 0; i < bufferCount; i++) {
outBufferHandles[i] = dupFromAidl(result.buffers[i]);
if (!outBufferHandles[i]) {
for (uint32_t j = 0; j < i; j++) {
auto buffer = const_cast<native_handle_t*>(outBufferHandles[j]);
native_handle_close(buffer);
native_handle_delete(buffer);
outBufferHandles[j] = nullptr;
}
}
}
}
}
*outStride = result.stride;
// Release all the resources held by AllocationResult (specifically any remaining FDs)
result = {};
// make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
hardware::IPCThreadState::self()->flushCommands();
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;
}
if (importBuffers) {
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;
}
}
} else {
for (uint32_t i = 0; i < bufferCount; i++) {
outBufferHandles[i] = native_handle_clone(
tmpBuffers[i].getNativeHandle());
if (!outBufferHandles[i]) {
for (uint32_t j = 0; j < i; j++) {
auto buffer = const_cast<native_handle_t*>(
outBufferHandles[j]);
native_handle_close(buffer);
native_handle_delete(buffer);
outBufferHandles[j] = nullptr;
}
}
}
}
*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