| /* |
| * 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 { |
| std::vector<ui::PlaneLayout> planeLayouts; |
| status_t err = getPlaneLayouts(bufferHandle, &planeLayouts); |
| |
| if (err == NO_ERROR && !planeLayouts.empty()) { |
| if (outBytesPerPixel) { |
| int32_t bitsPerPixel = planeLayouts.front().sampleIncrementInBits; |
| for (const auto& planeLayout : planeLayouts) { |
| if (bitsPerPixel != planeLayout.sampleIncrementInBits) { |
| bitsPerPixel = -1; |
| } |
| } |
| if (bitsPerPixel >= 0 && bitsPerPixel % 8 == 0) { |
| *outBytesPerPixel = bitsPerPixel / 8; |
| } else { |
| *outBytesPerPixel = -1; |
| } |
| } |
| if (outBytesPerStride) { |
| int32_t bytesPerStride = planeLayouts.front().strideInBytes; |
| for (const auto& planeLayout : planeLayouts) { |
| if (bytesPerStride != planeLayout.strideInBytes) { |
| bytesPerStride = -1; |
| } |
| } |
| if (bytesPerStride >= 0) { |
| *outBytesPerStride = bytesPerStride; |
| } else { |
| *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 bufferCount, 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; |
| } |
| |
| 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 |