| /* | |
| * 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 "Gralloc2" | |
| #include <hidl/ServiceManagement.h> | |
| #include <hwbinder/IPCThreadState.h> | |
| #include <ui/Gralloc2.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 | |
| namespace android { | |
| namespace Gralloc2 { | |
| namespace { | |
| static constexpr Error kTransactionError = Error::NO_RESOURCES; | |
| uint64_t getValid10UsageBits() { | |
| static const uint64_t valid10UsageBits = []() -> uint64_t { | |
| using hardware::graphics::common::V1_0::BufferUsage; | |
| uint64_t bits = 0; | |
| for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) { | |
| bits = bits | bit; | |
| } | |
| // TODO(b/72323293, b/72703005): Remove these additional bits | |
| bits = bits | (1 << 10) | (1 << 13); | |
| return bits; | |
| }(); | |
| return valid10UsageBits; | |
| } | |
| uint64_t getValid11UsageBits() { | |
| static const uint64_t valid11UsageBits = []() -> uint64_t { | |
| using hardware::graphics::common::V1_1::BufferUsage; | |
| uint64_t bits = 0; | |
| for (const auto bit : hardware::hidl_enum_iterator<BufferUsage>()) { | |
| bits = bits | bit; | |
| } | |
| return bits; | |
| }(); | |
| return valid11UsageBits; | |
| } | |
| } // anonymous namespace | |
| void Mapper::preload() { | |
| android::hardware::preloadPassthroughService<hardware::graphics::mapper::V2_0::IMapper>(); | |
| } | |
| Mapper::Mapper() | |
| { | |
| mMapper = hardware::graphics::mapper::V2_0::IMapper::getService(); | |
| if (mMapper == nullptr) { | |
| LOG_ALWAYS_FATAL("gralloc-mapper is missing"); | |
| } | |
| if (mMapper->isRemote()) { | |
| LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode"); | |
| } | |
| // IMapper 2.1 is optional | |
| mMapperV2_1 = IMapper::castFrom(mMapper); | |
| } | |
| Gralloc2::Error Mapper::validateBufferDescriptorInfo( | |
| const IMapper::BufferDescriptorInfo& descriptorInfo) const { | |
| uint64_t validUsageBits = getValid10UsageBits(); | |
| if (mMapperV2_1 != nullptr) { | |
| validUsageBits = validUsageBits | getValid11UsageBits(); | |
| } | |
| if (descriptorInfo.usage & ~validUsageBits) { | |
| ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64, | |
| descriptorInfo.usage & ~validUsageBits); | |
| return Error::BAD_VALUE; | |
| } | |
| return Error::NONE; | |
| } | |
| Error Mapper::createDescriptor( | |
| const IMapper::BufferDescriptorInfo& descriptorInfo, | |
| BufferDescriptor* outDescriptor) const | |
| { | |
| Error error = validateBufferDescriptorInfo(descriptorInfo); | |
| if (error != Error::NONE) { | |
| return error; | |
| } | |
| auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) | |
| { | |
| error = tmpError; | |
| if (error != Error::NONE) { | |
| return; | |
| } | |
| *outDescriptor = tmpDescriptor; | |
| }; | |
| hardware::Return<void> ret; | |
| if (mMapperV2_1 != nullptr) { | |
| ret = mMapperV2_1->createDescriptor_2_1(descriptorInfo, hidl_cb); | |
| } else { | |
| const hardware::graphics::mapper::V2_0::IMapper::BufferDescriptorInfo info = { | |
| descriptorInfo.width, | |
| descriptorInfo.height, | |
| descriptorInfo.layerCount, | |
| static_cast<hardware::graphics::common::V1_0::PixelFormat>(descriptorInfo.format), | |
| descriptorInfo.usage, | |
| }; | |
| ret = mMapper->createDescriptor(info, hidl_cb); | |
| } | |
| return (ret.isOk()) ? error : kTransactionError; | |
| } | |
| Error Mapper::importBuffer(const hardware::hidl_handle& rawHandle, | |
| buffer_handle_t* outBufferHandle) const | |
| { | |
| Error error; | |
| auto ret = mMapper->importBuffer(rawHandle, | |
| [&](const auto& tmpError, const auto& tmpBuffer) | |
| { | |
| error = tmpError; | |
| if (error != Error::NONE) { | |
| return; | |
| } | |
| *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer); | |
| }); | |
| return (ret.isOk()) ? error : kTransactionError; | |
| } | |
| void Mapper::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); | |
| } | |
| Error Mapper::validateBufferSize(buffer_handle_t bufferHandle, | |
| const IMapper::BufferDescriptorInfo& descriptorInfo, | |
| uint32_t stride) const | |
| { | |
| if (mMapperV2_1 == nullptr) { | |
| return Error::NONE; | |
| } | |
| auto buffer = const_cast<native_handle_t*>(bufferHandle); | |
| auto ret = mMapperV2_1->validateBufferSize(buffer, descriptorInfo, stride); | |
| return (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError; | |
| } | |
| void Mapper::getTransportSize(buffer_handle_t bufferHandle, | |
| uint32_t* outNumFds, uint32_t* outNumInts) const | |
| { | |
| *outNumFds = uint32_t(bufferHandle->numFds); | |
| *outNumInts = uint32_t(bufferHandle->numInts); | |
| if (mMapperV2_1 == nullptr) { | |
| return; | |
| } | |
| Error error; | |
| auto buffer = const_cast<native_handle_t*>(bufferHandle); | |
| auto ret = mMapperV2_1->getTransportSize(buffer, | |
| [&](const auto& tmpError, const auto& tmpNumFds, const auto& tmpNumInts) { | |
| error = tmpError; | |
| if (error != Error::NONE) { | |
| return; | |
| } | |
| *outNumFds = tmpNumFds; | |
| *outNumInts = tmpNumInts; | |
| }); | |
| if (!ret.isOk()) { | |
| error = kTransactionError; | |
| } | |
| ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", | |
| buffer, error); | |
| } | |
| Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, | |
| const IMapper::Rect& accessRegion, | |
| int acquireFence, void** outData) const | |
| { | |
| auto buffer = const_cast<native_handle_t*>(bufferHandle); | |
| // 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); | |
| } | |
| return (ret.isOk()) ? error : kTransactionError; | |
| } | |
| Error Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, | |
| const IMapper::Rect& accessRegion, | |
| int acquireFence, YCbCrLayout* outLayout) const | |
| { | |
| auto buffer = const_cast<native_handle_t*>(bufferHandle); | |
| // 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->lockYCbCr(buffer, usage, accessRegion, | |
| acquireFenceHandle, | |
| [&](const auto& tmpError, const auto& tmpLayout) | |
| { | |
| error = tmpError; | |
| if (error != Error::NONE) { | |
| return; | |
| } | |
| *outLayout = tmpLayout; | |
| }); | |
| // we own acquireFence even on errors | |
| if (acquireFence >= 0) { | |
| close(acquireFence); | |
| } | |
| return (ret.isOk()) ? error : kTransactionError; | |
| } | |
| int Mapper::unlock(buffer_handle_t bufferHandle) const | |
| { | |
| auto buffer = const_cast<native_handle_t*>(bufferHandle); | |
| int releaseFence = -1; | |
| Error error; | |
| auto ret = mMapper->unlock(buffer, | |
| [&](const auto& tmpError, const auto& tmpReleaseFence) | |
| { | |
| error = tmpError; | |
| if (error != Error::NONE) { | |
| return; | |
| } | |
| auto fenceHandle = tmpReleaseFence.getNativeHandle(); | |
| if (fenceHandle && fenceHandle->numFds == 1) { | |
| int fd = dup(fenceHandle->data[0]); | |
| if (fd >= 0) { | |
| releaseFence = fd; | |
| } else { | |
| ALOGD("failed to dup unlock release fence"); | |
| sync_wait(fenceHandle->data[0], -1); | |
| } | |
| } | |
| }); | |
| if (!ret.isOk()) { | |
| error = kTransactionError; | |
| } | |
| if (error != Error::NONE) { | |
| ALOGE("unlock(%p) failed with %d", buffer, error); | |
| } | |
| return releaseFence; | |
| } | |
| Allocator::Allocator(const Mapper& mapper) | |
| : mMapper(mapper) | |
| { | |
| mAllocator = IAllocator::getService(); | |
| if (mAllocator == nullptr) { | |
| LOG_ALWAYS_FATAL("gralloc-alloc is missing"); | |
| } | |
| } | |
| std::string Allocator::dumpDebugInfo() const | |
| { | |
| std::string debugInfo; | |
| mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { | |
| debugInfo = tmpDebugInfo.c_str(); | |
| }); | |
| return debugInfo; | |
| } | |
| Error Allocator::allocate(BufferDescriptor descriptor, uint32_t count, | |
| uint32_t* outStride, buffer_handle_t* outBufferHandles) const | |
| { | |
| Error error; | |
| auto ret = mAllocator->allocate(descriptor, count, | |
| [&](const auto& tmpError, const auto& tmpStride, | |
| const auto& tmpBuffers) { | |
| error = tmpError; | |
| if (tmpError != Error::NONE) { | |
| return; | |
| } | |
| // import buffers | |
| for (uint32_t i = 0; i < count; i++) { | |
| error = mMapper.importBuffer(tmpBuffers[i], | |
| &outBufferHandles[i]); | |
| if (error != Error::NONE) { | |
| for (uint32_t j = 0; j < i; j++) { | |
| mMapper.freeBuffer(outBufferHandles[j]); | |
| outBufferHandles[j] = nullptr; | |
| } | |
| return; | |
| } | |
| } | |
| *outStride = tmpStride; | |
| }); | |
| // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now | |
| hardware::IPCThreadState::self()->flushCommands(); | |
| return (ret.isOk()) ? error : kTransactionError; | |
| } | |
| } // namespace Gralloc2 | |
| } // namespace android |