/* * Copyright (C) 2018-2019 ARM Limited. All rights reserved. * * Copyright 2016 The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "GrallocMapper.h" #include "GrallocBufferDescriptor.h" #include "mali_gralloc_bufferallocation.h" #include "mali_gralloc_bufferdescriptor.h" #include "mali_gralloc_bufferaccess.h" #include "mali_gralloc_reference.h" #include "mali_gralloc_ion.h" #include "mali_gralloc_buffer.h" namespace android { namespace hardware { namespace graphics { namespace mapper { namespace HIDL_IMAPPER_NAMESPACE { namespace implementation { /* Default definitions for IMapper 2.x interface */ using V2_0::Error; using V2_0::BufferDescriptor; namespace { /* An unordered set to internally store / retrieve imported buffer handles */ class RegisteredHandlePool { public: /* Stores the buffer handle in the internal list */ bool add(buffer_handle_t bufferHandle) { std::lock_guard lock(mutex); return bufPool.insert(bufferHandle).second; } /* Retrieves and removes the buffer handle from internal list */ native_handle_t* remove(void* buffer) { auto bufferHandle = static_cast(buffer); std::lock_guard lock(mutex); return bufPool.erase(bufferHandle) == 1 ? bufferHandle : nullptr; } /* Retrieves the buffer handle from internal list */ buffer_handle_t get(const void* buffer) { auto bufferHandle = static_cast(buffer); std::lock_guard lock(mutex); return bufPool.count(bufferHandle) == 1 ? bufferHandle : nullptr; } private: std::mutex mutex; std::unordered_set bufPool; }; /* GraphicBufferMapper is expected to be valid (and leaked) during process * termination. IMapper, and in turn, gRegisteredHandles must be valid as * well. Create the registered handle pool on the heap, and let * it leak for simplicity. * * However, there is no way to make sure gralloc0/gralloc1 are valid. Any use * of static/global object in gralloc0/gralloc1 that may have been destructed * is potentially broken. */ RegisteredHandlePool* gRegisteredHandles = new RegisteredHandlePool; } /* anonymous namespace */ /** * IMapper constructor. All the state information required for the Gralloc * private module is populated in its default constructor. Gralloc 2.0 specific * state information can be populated here. * * @return None */ GrallocMapper::GrallocMapper() { } /* * IMapper destructor. All the resources aquired for Gralloc private module * (in the IMapper context) are released * * @return None */ GrallocMapper::~GrallocMapper() { mali_gralloc_ion_close(); } /* * Validates incoming IMapper descriptor attributes * * @param descriptor_attr [in] Specifies the attributes of the descriptor. * * @return false, for invalid buffer attributes * true, otherwise * Note: Latest IMapper version encapsulates all previous versions, hence all * incoming descriptor information is mapped to the latest IMapper for validation */ bool GrallocMapper::validateDescriptorInfo(void *descriptor_attr) const { BufferDescriptorInfo * const descriptorInfo = (BufferDescriptorInfo *)descriptor_attr; using android::hardware::graphics::common::HIDL_COMMON_NAMESPACE::BufferUsage; using android::hardware::graphics::common::HIDL_COMMON_NAMESPACE::PixelFormat; const uint64_t validUsageBits = #if HIDL_MAPPER_VERSION_SCALED >= 210 BufferUsage::GPU_CUBE_MAP | BufferUsage::GPU_MIPMAP_COMPLETE | #endif BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK | BufferUsage::GPU_TEXTURE | BufferUsage::GPU_RENDER_TARGET | BufferUsage::COMPOSER_OVERLAY | BufferUsage::COMPOSER_CLIENT_TARGET | BufferUsage::CAMERA_INPUT | BufferUsage::CAMERA_OUTPUT | BufferUsage::PROTECTED | BufferUsage::COMPOSER_CURSOR | BufferUsage::VIDEO_ENCODER | BufferUsage::RENDERSCRIPT | BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK; if (!descriptorInfo->width || !descriptorInfo->height || !descriptorInfo->layerCount) { AERR("Invalid buffer descriptor (2.x mapper) attributes, width = %d height = %d layerCount = %d ", descriptorInfo->width, descriptorInfo->height, descriptorInfo->layerCount); return false; } if (descriptorInfo->format == static_cast(0)) { return false; } if (descriptorInfo->usage & ~validUsageBits) { /* It is possible that application uses private usage bits. */ ALOGW("Buffer descriptor with invalid usage bits 0x%" PRIx64, descriptorInfo->usage & ~validUsageBits); } return true; } /* * Creates a buffer descriptor from incoming descriptor attributes * * @param descriptorInfo [in] Specifies the (2.0 IMapper) attributes of * the descriptor. * @param hidl_cb [in] HIDL callback function generating - * error: NONE upon success. Otherwise, * BAD_VALUE when any of the specified attributes are invalid * descriptor: Newly created buffer descriptor. * * @return Void */ Return GrallocMapper::createDescriptor( const V2_0::IMapper::BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) { if (validateDescriptorInfo((void *)&descriptorInfo)) { hidl_cb(Error::NONE, grallocEncodeBufferDescriptor(descriptorInfo)); } else { AERR("Invalid attributes to create descriptor for Mapper 2.0"); hidl_cb(Error::BAD_VALUE, BufferDescriptor()); } return Void(); } /* * Imports a raw buffer handle to create an imported buffer handle for use with * the rest of the mapper or with other in-process libraries. * * @param rawHandle [in] Raw buffer handle to import. * @param hidl_cb [in] HIDL Callback function to export output information * @param hidl_cb [in] HIDL callback function generating - * error : NONE upon success. Otherwise, * BAD_BUFFER for an invalid buffer * NO_RESOURCES when the raw handle cannot be imported * BAD_VALUE when any of the specified attributes are invalid * buffer : Imported buffer handle * * @return Void */ Return GrallocMapper::importBuffer(const hidl_handle& rawHandle, importBuffer_cb hidl_cb) { if (!rawHandle.getNativeHandle()) { AERR("Invalid buffer handle to import"); hidl_cb(Error::BAD_BUFFER, nullptr); return Void(); } native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle()); if (!bufferHandle) { AERR("Failed to clone buffer handle"); hidl_cb(Error::NO_RESOURCES, nullptr); return Void(); } const Error error = registerBuffer(bufferHandle); if (error != Error::NONE) { native_handle_close(bufferHandle); native_handle_delete(bufferHandle); hidl_cb(error, nullptr); return Void(); } if (gRegisteredHandles->add(bufferHandle) == false) { /* The newly cloned handle is already registered. This can only happen * when a handle previously registered was native_handle_delete'd instead * of freeBuffer'd. */ AERR("Handle %p has already been imported; potential fd leaking", bufferHandle); unregisterBuffer(bufferHandle); native_handle_close(bufferHandle); native_handle_delete(bufferHandle); hidl_cb(Error::NO_RESOURCES, nullptr); return Void(); } hidl_cb(Error::NONE, bufferHandle); return Void(); } /* * Frees a buffer handle and releases all the resources associated with it * * @param buffer [in] Imported buffer to free * * @return Error::BAD_BUFFER for an invalid buffer / when failed to free the buffer * Error::NONE on successful free */ Return GrallocMapper::freeBuffer(void* buffer) { native_handle_t * const bufferHandle = gRegisteredHandles->remove(buffer); if (!bufferHandle) { AERR("Invalid buffer handle %p to freeBuffer", buffer); return Error::BAD_BUFFER; } const Error status = unregisterBuffer(bufferHandle); if (status != Error::NONE) { return status; } native_handle_close(bufferHandle); native_handle_delete(bufferHandle); return Error::NONE; } /* * Retrieves the file descriptor referring to a sync fence object * * @param fenceHandle [in] HIDL fence handle * @param outFenceFd [out] Fence file descriptor. '-1' indicates no fence * * @return false, for an invalid HIDL fence handle * true, otherwise */ bool GrallocMapper::getFenceFd(const hidl_handle& fenceHandle, int* outFenceFd) const { auto const handle = fenceHandle.getNativeHandle(); if (handle && handle->numFds > 1) { AERR("Invalid fence handle with %d fds", handle->numFds); return false; } *outFenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1; return true; } /* * Populates the HIDL fence handle for the given fence object * * @param fenceFd [in] Fence file descriptor * @param handleStorage [in] HIDL handle storage for fence * * @return HIDL fence handle */ hidl_handle GrallocMapper::getFenceHandle(int fenceFd, char* handleStorage) const { native_handle_t* handle = nullptr; if (fenceFd >= 0) { handle = native_handle_init(handleStorage, 1, 0); handle->data[0] = fenceFd; } return hidl_handle(handle); } /* * Locks the given buffer for the specified CPU usage. * * @param buffer [in] Buffer to lock * @param cpuUsage [in] Specifies one or more CPU usage flags to request * @param accessRegion [in] Portion of the buffer that the client intends to access * @param acquireFence [in] Handle for aquire fence object * @param hidl_cb [in] HIDL callback function generating - * error: NONE upon success. Otherwise, * BAD_BUFFER for an invalid buffer * BAD_VALUE for an invalid input parameters * data: CPU-accessible pointer to the buffer data * * @return Void */ Return GrallocMapper::lock(void* buffer, uint64_t cpuUsage, const IMapper::Rect& accessRegion, const hidl_handle& acquireFence, lock_cb hidl_cb) { buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer); if (!bufferHandle) { AERR("Buffer to lock: %p has not been registered with Gralloc", buffer); hidl_cb(Error::BAD_BUFFER, nullptr); return Void(); } int fenceFd; if (!getFenceFd(acquireFence, &fenceFd)) { hidl_cb(Error::BAD_VALUE, nullptr); return Void(); } void* data = nullptr; const Error error = lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &data); hidl_cb(error, data); return Void(); } /* * Locks the given buffer for the specified CPU usage and exports cpu accessible * data in YCbCr structure. * * @param buffer [in] Buffer to lock. * @param cpuUsage [in] Specifies one or more CPU usage flags to request * @param accessRegion [in] Portion of the buffer that the client intends to access. * @param acquireFence [in] Handle for aquire fence object * @param hidl_cb [in] HIDL callback function generating - * error: NONE upon success. Otherwise, * BAD_BUFFER for an invalid buffer * BAD_VALUE for an invalid input parameters * layout: Data layout of the buffer * * @return Void */ Return GrallocMapper::lockYCbCr(void* buffer, uint64_t cpuUsage, const IMapper::Rect& accessRegion, const hidl_handle& acquireFence, lockYCbCr_cb hidl_cb) { YCbCrLayout layout = {}; buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer); if (!bufferHandle) { AERR("Buffer to lock(YCbCr): %p has not been registered with Gralloc", buffer); hidl_cb(Error::BAD_BUFFER, layout); return Void(); } int fenceFd; if (!getFenceFd(acquireFence, &fenceFd)) { hidl_cb(Error::BAD_VALUE, layout); return Void(); } const Error error = lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &layout); hidl_cb(error, layout); return Void(); } /* * Unlocks a buffer to indicate all CPU accesses to the buffer have completed * * @param buffer [in] Buffer to lock. * @param hidl_cb [in] HIDL callback function generating - * error: NONE upon success. Otherwise, * BAD_BUFFER for an invalid buffer * releaseFence: Referrs to a sync fence object * * @return Void */ Return GrallocMapper::unlock(void* buffer, unlock_cb hidl_cb) { buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer); if (!bufferHandle) { AERR("Buffer to unlock: %p has not been registered with Gralloc", buffer); hidl_cb(Error::BAD_BUFFER, nullptr); return Void(); } int fenceFd; const Error error = unlockBuffer(bufferHandle, &fenceFd); if (error == Error::NONE) { NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0); hidl_cb(error, getFenceHandle(fenceFd, fenceStorage)); if (fenceFd >= 0) { close(fenceFd); } } else { hidl_cb(error, nullptr); } return Void(); } /* * Translates the register buffer API into existing gralloc implementation * * @param bufferHandle [in] Private handle for the buffer to be imported * * @return Error::BAD_BUFFER for an invalid buffer * Error::NO_RESOURCES when unable to import the given buffer * Error::NONE on successful import */ Error GrallocMapper::registerBuffer(buffer_handle_t bufferHandle) const { if (private_handle_t::validate(bufferHandle) < 0) { AERR("Buffer: %p is corrupted", bufferHandle); return Error::BAD_BUFFER; } if (mali_gralloc_reference_retain(&privateModule, bufferHandle) < 0) { return Error::NO_RESOURCES; } return Error::NONE; } /* * Translates the unregister buffer API into existing gralloc implementation * * @param bufferHandle [in] Private handle for the buffer to be released * * @return Error::BAD_BUFFER for an invalid buffer / buffers which can't be released * Error::NONE on successful release of the buffer */ Error GrallocMapper::unregisterBuffer(buffer_handle_t bufferHandle) const { if (private_handle_t::validate(bufferHandle) < 0) { AERR("Buffer: %p is corrupted", bufferHandle); return Error::BAD_BUFFER; } const int status = mali_gralloc_reference_release(&privateModule, bufferHandle, true); if (status != 0) { AERR("Unable to release buffer:%p", bufferHandle); return Error::BAD_BUFFER; } return Error::NONE; } /* * Locks the given buffer for the specified CPU usage. * * @param bufferHandle [in] Buffer to lock. * @param cpuUsage [in] Specifies one or more CPU usage flags to request * @param accessRegion [in] Portion of the buffer that the client intends to access. * @param fenceFd [in] Fence file descriptor * @param outData [out] CPU accessible buffer address * * @return Error::BAD_BUFFER for an invalid buffer * Error::NO_RESOURCES when unable to duplicate fence * Error::BAD_VALUE when locking fails * Error::NONE on successful buffer lock */ Error GrallocMapper::lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage, const IMapper::Rect& accessRegion, int fenceFd, void** outData) const { /* dup fenceFd as it is going to be owned by gralloc. Note that it is * gralloc's responsibility to close it, even on locking errors. */ if (fenceFd >= 0) { fenceFd = dup(fenceFd); if (fenceFd < 0) { AERR("Error encountered while duplicating fence file descriptor"); return Error::NO_RESOURCES; } } if (private_handle_t::validate(bufferHandle) < 0) { AERR("Buffer: %p is corrupted", bufferHandle); return Error::BAD_BUFFER; } void* data = nullptr; if (mali_gralloc_lock_async(&privateModule, bufferHandle, cpuUsage, accessRegion.left, accessRegion.top, accessRegion.width, accessRegion.height, &data, fenceFd) < 0) { return Error::BAD_VALUE; } *outData = data; return Error::NONE; } /* * Locks the given buffer for the specified CPU usage and exports cpu accessible * data in YCbCr structure. * * @param bufferHandle [in] Buffer to lock. * @param cpuUsage [in] Specifies one or more CPU usage flags to request * @param accessRegion [in] Portion of the buffer that the client intends to access. * @param fenceFd [in] Fence file descriptor * @param outLayout [out] Describes CPU accessible information in YCbCr format * * @return Error::BAD_BUFFER for an invalid buffer * Error::NO_RESOURCES when unable to duplicate fence * Error::BAD_VALUE when locking fails * Error::NONE on successful buffer lock */ Error GrallocMapper::lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage, const IMapper::Rect& accessRegion, int fenceFd, YCbCrLayout* outLayout) const { int result; android_ycbcr ycbcr = {}; if (private_handle_t::validate(bufferHandle) < 0) { AERR("Buffer: %p is corrupted", bufferHandle); return Error::BAD_BUFFER; } if (fenceFd >= 0) { fenceFd = dup(fenceFd); if (fenceFd < 0) { AERR("Error encountered while duplicating fence file descriptor"); return Error::NO_RESOURCES; } } result = mali_gralloc_lock_ycbcr_async(&privateModule, bufferHandle, cpuUsage, accessRegion.left, accessRegion.top, accessRegion.width, accessRegion.height, &ycbcr, fenceFd); if (result) { AERR("Locking(YCbCr) failed with error: %d", result); return Error::BAD_VALUE; } outLayout->y = ycbcr.y; outLayout->cb = ycbcr.cb; outLayout->cr = ycbcr.cr; outLayout->yStride = ycbcr.ystride; outLayout->cStride = ycbcr.cstride; outLayout->chromaStep = ycbcr.chroma_step; return Error::NONE; } /* * Unlocks a buffer to indicate all CPU accesses to the buffer have completed * * @param bufferHandle [in] Buffer to lock. * @param outFenceFd [out] Fence file descriptor * * @return Error::BAD_BUFFER for an invalid buffer * Error::BAD_VALUE when unlocking failed * Error::NONE on successful buffer unlock */ Error GrallocMapper::unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) const { if (private_handle_t::validate(bufferHandle) < 0) { AERR("Buffer: %p is corrupted", bufferHandle); return Error::BAD_BUFFER; } int fenceFd = -1; const int result = mali_gralloc_unlock_async(&privateModule, bufferHandle, &fenceFd); if (result) { AERR("Unlocking failed with error: %d", result); return Error::BAD_VALUE; } *outFenceFd = fenceFd; return Error::NONE; } #if HIDL_MAPPER_VERSION_SCALED >= 210 /* * Validates the buffer against specified descriptor attributes * * @param buffer [in] Buffer which needs to be validated. * @param descriptorInfo [in] Required attributes of the buffer * @param in_stride [in] Buffer stride returned by IAllocator::allocate * * @return Error::NONE upon success. Otherwise, * Error::BAD_BUFFER upon bad buffer input * Error::BAD_VALUE when any of the specified attributes are invalid */ Return GrallocMapper::validateBufferSize(void* buffer, const V2_1::IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t in_stride) { /* The buffer must have been allocated by Gralloc */ buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer); if (!bufferHandle) { AERR("Buffer: %p has not been registered with Gralloc", buffer); return Error::BAD_BUFFER; } if (private_handle_t::validate(bufferHandle) < 0) { AERR("Buffer: %p is corrupted", bufferHandle); return Error::BAD_BUFFER; } /* All Gralloc allocated buffers must be conform to local descriptor validation */ if (!validateDescriptorInfo((void *)&descriptorInfo)) { AERR("Invalid descriptor attributes for validating buffer size"); return Error::BAD_VALUE; } buffer_descriptor_t grallocDescriptor; grallocDescriptor.width = descriptorInfo.width; grallocDescriptor.height = descriptorInfo.height; grallocDescriptor.layer_count = descriptorInfo.layerCount; grallocDescriptor.hal_format = static_cast(descriptorInfo.format); grallocDescriptor.producer_usage = static_cast(descriptorInfo.usage); grallocDescriptor.consumer_usage = grallocDescriptor.producer_usage; grallocDescriptor.format_type = MALI_GRALLOC_FORMAT_TYPE_USAGE; /* Derive the buffer size for the given descriptor */ const int result = mali_gralloc_derive_format_and_size(&privateModule, &grallocDescriptor); if (result) { AERR("Unable to derive format and size for the given descriptor information. error: %d", result); return Error::BAD_VALUE; } /* Validate the buffer parameters against descriptor info */ private_handle_t *gralloc_buffer = (private_handle_t *)bufferHandle; /* The buffer size must be greater than (or equal to) what would have been allocated with descriptor */ if ((size_t)gralloc_buffer->size < grallocDescriptor.size) { ALOGW("Buf size mismatch. Buffer size = %u, Descriptor (derived) size = %zu", gralloc_buffer->size, grallocDescriptor.size); return Error::BAD_VALUE; } if ((uint32_t)gralloc_buffer->stride != in_stride) { AERR("Stride mismatch. Expected stride = %d, Buffer stride = %d", in_stride, gralloc_buffer->stride); return Error::BAD_VALUE; } if (gralloc_buffer->internal_format != grallocDescriptor.internal_format) { AERR("Buffer format :0x%" PRIx64" does not match descriptor (derived) format :0x%" PRIx64, gralloc_buffer->internal_format, grallocDescriptor.internal_format); return Error::BAD_VALUE; } if ((uint32_t)gralloc_buffer->width != grallocDescriptor.width) { AERR("Width mismatch. Buffer width = %u, Descriptor width = %u", gralloc_buffer->width, grallocDescriptor.width); return Error::BAD_VALUE; } if ((uint32_t)gralloc_buffer->height != grallocDescriptor.height) { AERR("Height mismatch. Buffer height = %u, Descriptor height = %u", gralloc_buffer->height, grallocDescriptor.height); return Error::BAD_VALUE; } if (gralloc_buffer->layer_count != grallocDescriptor.layer_count) { AERR("Layer Count mismatch. Buffer layer_count = %u, Descriptor layer_count width = %u", gralloc_buffer->layer_count, grallocDescriptor.layer_count); return Error::BAD_VALUE; } return Error::NONE; } /* * Get the transport size of a buffer * * @param buffer [in] Buffer for computing transport size * @param hidl_cb [in] HIDL callback function generating - * error: NONE upon success. Otherwise, * BAD_BUFFER for an invalid buffer * numFds: Number of file descriptors needed for transport * numInts: Number of integers needed for transport * * @return Void */ Return GrallocMapper::getTransportSize(void* buffer, getTransportSize_cb hidl_cb) { /* The buffer must have been allocated by Gralloc */ buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer); if (!bufferHandle) { AERR("Buffer %p is not registered with Gralloc", bufferHandle); hidl_cb(Error::BAD_BUFFER, -1, -1); return Void(); } if (private_handle_t::validate(bufferHandle) < 0) { AERR("Buffer %p is corrupted", buffer); hidl_cb(Error::BAD_BUFFER, -1, -1); return Void(); } hidl_cb(Error::NONE, GRALLOC_ARM_NUM_FDS, NUM_INTS_IN_PRIVATE_HANDLE); return Void(); } /* * Creates a buffer descriptor from incoming descriptor attributes * * @param descriptorInfo [in] Specifies the (2.1 IMapper) attributes of * the descriptor. * @param hidl_cb [in] HIDL callback function generating - * error: NONE upon success. Otherwise, * BAD_VALUE when any of the specified attributes are invalid * descriptor: Newly created buffer descriptor. * * @return Void */ Return GrallocMapper::createDescriptor_2_1(const V2_1::IMapper::BufferDescriptorInfo& descriptorInfo, createDescriptor_2_1_cb hidl_cb) { if (validateDescriptorInfo((void *)&descriptorInfo)) { hidl_cb(Error::NONE, grallocEncodeBufferDescriptor(descriptorInfo)); } else { AERR("Invalid (IMapper 2.1) attributes to create descriptor"); hidl_cb(Error::BAD_VALUE, V2_0::BufferDescriptor()); } return Void(); } #endif /* HIDL_MAPPER_VERSION_SCALED >= 210 */ IMapper* HIDL_FETCH_IMapper(const char* /* name */) { ALOGV("Arm Module IMapper %d.%d , pid = %d ppid = %d ", GRALLOC_VERSION_MAJOR, (HIDL_MAPPER_VERSION_SCALED - (GRALLOC_VERSION_MAJOR * 100)) / 10, getpid(), getppid()); return new GrallocMapper(); } } // namespace implementation } // namespace HIDL_IMAPPER_NAMESPACE } // namespace mapper } // namespace graphics } // namespace hardware } // namespace android