1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "media/ShmemCompat.h"
17
18 #include "binder/MemoryBase.h"
19 #include "binder/MemoryHeapBase.h"
20 #include "media/ShmemUtil.h"
21
22 namespace android {
23 namespace media {
24
convertSharedFileRegionToIMemory(const SharedFileRegion & shmem,sp<IMemory> * result)25 bool convertSharedFileRegionToIMemory(const SharedFileRegion& shmem,
26 sp<IMemory>* result) {
27 assert(result != nullptr);
28
29 if (!validateSharedFileRegion(shmem)) {
30 return false;
31 }
32
33 // Heap offset and size must be page aligned.
34 const size_t pageSize = getpagesize();
35 const size_t pageMask = ~(pageSize - 1);
36
37 // OK if this wraps.
38 const uint64_t endOffset = static_cast<uint64_t>(shmem.offset) +
39 static_cast<uint64_t>(shmem.size);
40
41 // Round down to page boundary.
42 const uint64_t heapStartOffset = shmem.offset & pageMask;
43 // Round up to page boundary.
44 const uint64_t heapEndOffset = (endOffset + pageSize - 1) & pageMask;
45 const uint64_t heapSize = heapEndOffset - heapStartOffset;
46
47 if (heapStartOffset > std::numeric_limits<size_t>::max() ||
48 heapSize > std::numeric_limits<size_t>::max()) {
49 return false;
50 }
51
52 uint32_t flags = !shmem.writeable ? IMemoryHeap::READ_ONLY : 0;
53
54 const sp<MemoryHeapBase> heap =
55 new MemoryHeapBase(shmem.fd.get(), heapSize, flags, heapStartOffset);
56 *result = sp<MemoryBase>::make(heap,
57 shmem.offset - heapStartOffset,
58 shmem.size);
59 return true;
60 }
61
convertIMemoryToSharedFileRegion(const sp<IMemory> & mem,SharedFileRegion * result)62 bool convertIMemoryToSharedFileRegion(const sp<IMemory>& mem,
63 SharedFileRegion* result) {
64 assert(mem != nullptr);
65 assert(result != nullptr);
66
67 *result = SharedFileRegion();
68
69 ssize_t offset;
70 size_t size;
71
72 sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
73 if (size > 0) {
74 if (heap == nullptr) {
75 return false;
76 }
77 // Make sure the offset and size do not overflow from int64 boundaries.
78 if (size > std::numeric_limits<int64_t>::max() ||
79 offset > std::numeric_limits<int64_t>::max() ||
80 heap->getOffset() > std::numeric_limits<int64_t>::max() ||
81 static_cast<uint64_t>(heap->getOffset()) +
82 static_cast<uint64_t>(offset)
83 > std::numeric_limits<int64_t>::max()) {
84 return false;
85 }
86
87 const int fd = fcntl(heap->getHeapID(), F_DUPFD_CLOEXEC, 0);
88 if (fd < 0) {
89 return false;
90 }
91 result->fd.reset(base::unique_fd(fd));
92 result->size = size;
93 result->offset = heap->getOffset() + offset;
94 result->writeable = (heap->getFlags() & IMemoryHeap::READ_ONLY) == 0;
95 }
96 return true;
97 }
98
convertNullableSharedFileRegionToIMemory(const std::optional<SharedFileRegion> & shmem,sp<IMemory> * result)99 bool convertNullableSharedFileRegionToIMemory(const std::optional<SharedFileRegion>& shmem,
100 sp<IMemory>* result) {
101 assert(result != nullptr);
102
103 if (!shmem.has_value()) {
104 result->clear();
105 return true;
106 }
107
108 return convertSharedFileRegionToIMemory(shmem.value(), result);
109 }
110
convertNullableIMemoryToSharedFileRegion(const sp<IMemory> & mem,std::optional<SharedFileRegion> * result)111 bool convertNullableIMemoryToSharedFileRegion(const sp<IMemory>& mem,
112 std::optional<SharedFileRegion>* result) {
113 assert(result != nullptr);
114
115 if (mem == nullptr) {
116 result->reset();
117 return true;
118 }
119
120 result->emplace();
121 return convertIMemoryToSharedFileRegion(mem, &result->value());
122 }
123
124 } // namespace media
125 } // namespace android
126