/* * Copyright (C) 2020 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 "media/ShmemCompat.h" #include "binder/MemoryBase.h" #include "binder/MemoryHeapBase.h" #include "media/ShmemUtil.h" namespace android { namespace media { bool convertSharedFileRegionToIMemory(const SharedFileRegion& shmem, sp* result) { assert(result != nullptr); if (!validateSharedFileRegion(shmem)) { return false; } // Heap offset and size must be page aligned. const size_t pageSize = getpagesize(); const size_t pageMask = ~(pageSize - 1); // OK if this wraps. const uint64_t endOffset = static_cast(shmem.offset) + static_cast(shmem.size); // Round down to page boundary. const uint64_t heapStartOffset = shmem.offset & pageMask; // Round up to page boundary. const uint64_t heapEndOffset = (endOffset + pageSize - 1) & pageMask; const uint64_t heapSize = heapEndOffset - heapStartOffset; if (heapStartOffset > std::numeric_limits::max() || heapSize > std::numeric_limits::max()) { return false; } uint32_t flags = !shmem.writeable ? IMemoryHeap::READ_ONLY : 0; const sp heap = new MemoryHeapBase(shmem.fd.get(), heapSize, flags, heapStartOffset); *result = sp::make(heap, shmem.offset - heapStartOffset, shmem.size); return true; } bool convertIMemoryToSharedFileRegion(const sp& mem, SharedFileRegion* result) { assert(mem != nullptr); assert(result != nullptr); *result = SharedFileRegion(); ssize_t offset; size_t size; sp heap = mem->getMemory(&offset, &size); if (size > 0) { if (heap == nullptr) { return false; } // Make sure the offset and size do not overflow from int64 boundaries. if (size > std::numeric_limits::max() || offset > std::numeric_limits::max() || heap->getOffset() > std::numeric_limits::max() || static_cast(heap->getOffset()) + static_cast(offset) > std::numeric_limits::max()) { return false; } const int fd = fcntl(heap->getHeapID(), F_DUPFD_CLOEXEC, 0); if (fd < 0) { return false; } result->fd.reset(base::unique_fd(fd)); result->size = size; result->offset = heap->getOffset() + offset; result->writeable = (heap->getFlags() & IMemoryHeap::READ_ONLY) == 0; } return true; } bool convertNullableSharedFileRegionToIMemory(const std::optional& shmem, sp* result) { assert(result != nullptr); if (!shmem.has_value()) { result->clear(); return true; } return convertSharedFileRegionToIMemory(shmem.value(), result); } bool convertNullableIMemoryToSharedFileRegion(const sp& mem, std::optional* result) { assert(result != nullptr); if (mem == nullptr) { result->reset(); return true; } result->emplace(); return convertIMemoryToSharedFileRegion(mem, &result->value()); } } // namespace media } // namespace android