/* * Copyright 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "GrallocMapperPassthrough" #include "GrallocMapper.h" #include "Gralloc0Mapper.h" #include "Gralloc1Mapper.h" #include "GrallocBufferDescriptor.h" #include #include #include namespace android { namespace hardware { namespace graphics { namespace mapper { namespace V2_0 { namespace implementation { using android::hardware::graphics::common::V1_0::BufferUsage; using android::hardware::graphics::common::V1_0::PixelFormat; namespace { class RegisteredHandlePool { public: bool add(buffer_handle_t bufferHandle) { std::lock_guard lock(mMutex); return mHandles.insert(bufferHandle).second; } native_handle_t* pop(void* buffer) { auto bufferHandle = static_cast(buffer); std::lock_guard lock(mMutex); return mHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr; } buffer_handle_t get(const void* buffer) { auto bufferHandle = static_cast(buffer); std::lock_guard lock(mMutex); return mHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr; } private: std::mutex mMutex; std::unordered_set mHandles; }; // GraphicBufferMapper is expected to be valid (and leaked) during process // termination. We need to make sure IMapper, and in turn, gRegisteredHandles // are 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 bool GrallocMapper::validateDescriptorInfo( const BufferDescriptorInfo& descriptorInfo) const { const uint64_t validUsageBits = BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK | BufferUsage::GPU_TEXTURE | BufferUsage::GPU_RENDER_TARGET | BufferUsage::COMPOSER_OVERLAY | BufferUsage::COMPOSER_CLIENT_TARGET | BufferUsage::PROTECTED | BufferUsage::COMPOSER_CURSOR | BufferUsage::VIDEO_ENCODER | BufferUsage::CAMERA_OUTPUT | BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT | BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK | (mCapabilities.highUsageBits ? BufferUsage::VENDOR_MASK_HI : static_cast(0)); if (!descriptorInfo.width || !descriptorInfo.height || !descriptorInfo.layerCount) { return false; } if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount > 1) { return false; } if (descriptorInfo.format == static_cast(0)) { return false; } if (descriptorInfo.usage & ~validUsageBits) { // could not fail as gralloc may use the reserved bits... ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64, descriptorInfo.usage & ~validUsageBits); } return true; } Return GrallocMapper::createDescriptor( const BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) { if (validateDescriptorInfo(descriptorInfo)) { hidl_cb(Error::NONE, grallocEncodeBufferDescriptor(descriptorInfo)); } else { hidl_cb(Error::BAD_VALUE, BufferDescriptor()); } return Void(); } Return GrallocMapper::importBuffer(const hidl_handle& rawHandle, importBuffer_cb hidl_cb) { // because of passthrough HALs, we must not generate an error when // rawHandle has been imported if (!rawHandle.getNativeHandle()) { hidl_cb(Error::BAD_BUFFER, nullptr); return Void(); } native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle()); if (!bufferHandle) { hidl_cb(Error::NO_RESOURCES, nullptr); return Void(); } Error error = registerBuffer(bufferHandle); if (error != Error::NONE) { native_handle_close(bufferHandle); native_handle_delete(bufferHandle); hidl_cb(error, nullptr); return Void(); } // The newly cloned handle is already registered? This can only happen // when a handle previously registered was native_handle_delete'd instead // of freeBuffer'd. if (!gRegisteredHandles->add(bufferHandle)) { ALOGE("handle %p has already been imported; potential fd leaking", bufferHandle); unregisterBuffer(bufferHandle); if (!mCapabilities.unregisterImplyDelete) { native_handle_close(bufferHandle); native_handle_delete(bufferHandle); } hidl_cb(Error::NO_RESOURCES, nullptr); return Void(); } hidl_cb(Error::NONE, bufferHandle); return Void(); } Return GrallocMapper::freeBuffer(void* buffer) { native_handle_t* bufferHandle = gRegisteredHandles->pop(buffer); if (!bufferHandle) { return Error::BAD_BUFFER; } unregisterBuffer(bufferHandle); if (!mCapabilities.unregisterImplyDelete) { native_handle_close(bufferHandle); native_handle_delete(bufferHandle); } return Error::NONE; } void GrallocMapper::waitFenceFd(int fenceFd, const char* logname) { if (fenceFd < 0) { return; } const int warningTimeout = 3500; const int error = sync_wait(fenceFd, warningTimeout); if (error < 0 && errno == ETIME) { ALOGE("%s: fence %d didn't signal in %u ms", logname, fenceFd, warningTimeout); sync_wait(fenceFd, -1); } } bool GrallocMapper::getFenceFd(const hidl_handle& fenceHandle, int* outFenceFd) { auto handle = fenceHandle.getNativeHandle(); if (handle && handle->numFds > 1) { ALOGE("invalid fence handle with %d fds", handle->numFds); return false; } *outFenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1; return true; } hidl_handle GrallocMapper::getFenceHandle(int fenceFd, char* handleStorage) { native_handle_t* handle = nullptr; if (fenceFd >= 0) { handle = native_handle_init(handleStorage, 1, 0); handle->data[0] = fenceFd; } return hidl_handle(handle); } Return 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) { 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; Error error = lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &data); hidl_cb(error, data); 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) { hidl_cb(Error::BAD_BUFFER, layout); return Void(); } int fenceFd; if (!getFenceFd(acquireFence, &fenceFd)) { hidl_cb(Error::BAD_VALUE, layout); return Void(); } Error error = lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &layout); hidl_cb(error, layout); return Void(); } Return GrallocMapper::unlock(void* buffer, unlock_cb hidl_cb) { buffer_handle_t bufferHandle = gRegisteredHandles->get(buffer); if (!bufferHandle) { hidl_cb(Error::BAD_BUFFER, nullptr); return Void(); } int fenceFd; Error error = unlockBuffer(bufferHandle, &fenceFd); if (error == Error::NONE) { NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0); hidl_cb(error, getFenceHandle(fenceFd, fenceStorage)); if (fenceFd >= 0) { close(fenceFd); } } else { hidl_cb(error, nullptr); } return Void(); } IMapper* HIDL_FETCH_IMapper(const char* /* name */) { const hw_module_t* module = nullptr; int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module); if (err) { ALOGE("failed to get gralloc module"); return nullptr; } uint8_t major = (module->module_api_version >> 8) & 0xff; switch (major) { case 1: return new Gralloc1Mapper(module); case 0: return new Gralloc0Mapper(module); default: ALOGE("unknown gralloc module major version %d", major); return nullptr; } } } // namespace implementation } // namespace V2_0 } // namespace mapper } // namespace graphics } // namespace hardware } // namespace android