• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "av_shared_memory_ext.h"
17 #include <unistd.h>
18 #include "ashmem.h"
19 #include "av_shared_allocator.h"
20 #include "avbuffer_utils.h"
21 #include "buffer/avallocator.h"
22 #include "common/log.h"
23 #include "common/status.h"
24 #include "message_parcel.h"
25 #include "scope_guard.h"
26 
27 #ifdef MEDIA_OHOS
28 #include "sys/mman.h"
29 #endif
30 
31 namespace OHOS {
32 namespace Media {
CreateSharedAllocator(MemoryFlag memFlag)33 std::shared_ptr<AVAllocator> AVAllocatorFactory::CreateSharedAllocator(MemoryFlag memFlag)
34 {
35     auto allocator = std::shared_ptr<AVSharedAllocator>(new AVSharedAllocator());
36     FALSE_RETURN_V_MSG_E(allocator != nullptr, nullptr, "Create AVSharedAllocator failed, no memory");
37     allocator->memFlag_ = memFlag;
38     return allocator;
39 }
40 
AVSharedAllocator()41 AVSharedAllocator::AVSharedAllocator(){};
42 
Alloc(int32_t capacity)43 void *AVSharedAllocator::Alloc(int32_t capacity)
44 {
45     int32_t fd = AshmemCreate(0, static_cast<size_t>(capacity)); // release by close(fd)
46     FALSE_RETURN_V_MSG_E(fd > 0, nullptr, "fd is invalid, fd:%{public}d", fd);
47 
48     return reinterpret_cast<void *>(fd);
49 }
50 
Free(void * ptr)51 bool AVSharedAllocator::Free(void *ptr)
52 {
53     int32_t fd = reinterpret_cast<intptr_t>(ptr);
54     if (fd > 0) {
55         (void)::close(fd);
56         return true;
57     }
58     return false;
59 }
60 
GetMemoryType()61 MemoryType AVSharedAllocator::GetMemoryType()
62 {
63     return MemoryType::SHARED_MEMORY;
64 }
65 
GetMemFlag()66 MemoryFlag AVSharedAllocator::GetMemFlag()
67 {
68     return memFlag_;
69 }
70 
AVSharedMemoryExt()71 AVSharedMemoryExt::AVSharedMemoryExt() : fd_(-1), isFirstFlag_(true), memFlag_(MemoryFlag::MEMORY_READ_ONLY) {}
72 
~AVSharedMemoryExt()73 AVSharedMemoryExt::~AVSharedMemoryExt()
74 {
75     UnMapMemoryAddr();
76     if (allocator_ == nullptr) {
77         if (fd_ > 0) {
78             (void)::close(fd_);
79             fd_ = -1;
80         }
81         return;
82     }
83     bool ret = allocator_->Free(reinterpret_cast<void *>(fd_));
84     FALSE_RETURN_MSG(ret, "Free memory failed, instance: 0x%{public}06" PRIXPTR, FAKE_POINTER(this));
85 }
86 
Init()87 Status AVSharedMemoryExt::Init()
88 {
89     memFlag_ = std::static_pointer_cast<AVSharedAllocator>(allocator_)->GetMemFlag();
90 
91     int32_t allocSize = align_ ? (capacity_ + align_ - 1) : capacity_;
92     fd_ = reinterpret_cast<intptr_t>(allocator_->Alloc(allocSize));
93     FALSE_RETURN_V_MSG_E(fd_ > 0, Status::ERROR_NO_MEMORY, "Alloc AVSharedMemoryExt failed");
94 
95     uintptr_t addrBase = reinterpret_cast<uintptr_t>(base_);
96     offset_ = static_cast<size_t>(AlignUp(addrBase, static_cast<uintptr_t>(offset_)) - addrBase);
97 
98     return Status::OK;
99 }
100 
Init(MessageParcel & parcel)101 Status AVSharedMemoryExt::Init(MessageParcel &parcel)
102 {
103 #ifdef MEDIA_OHOS
104     int32_t fd = parcel.ReadFileDescriptor();
105     FALSE_RETURN_V_MSG_E(fd > 0, Status::ERROR_INVALID_DATA, "File descriptor is invalid");
106     fd_ = dup(fd);
107 
108     memFlag_ = static_cast<MemoryFlag>(parcel.ReadUint32());
109     (void)::close(fd);
110     return Status::OK;
111 #else
112     return Status::OK;
113 #endif
114 }
115 
WriteToMessageParcel(MessageParcel & parcel)116 bool AVSharedMemoryExt::WriteToMessageParcel(MessageParcel &parcel)
117 {
118 #ifdef MEDIA_OHOS
119     MessageParcel bufferParcel;
120     bool ret = bufferParcel.WriteFileDescriptor(fd_) && bufferParcel.WriteUint32(static_cast<uint32_t>(memFlag_));
121     if (ret) {
122         parcel.Append(bufferParcel);
123     }
124     return ret;
125 #else
126     return false;
127 #endif
128 }
129 
ReadFromMessageParcel(MessageParcel & parcel)130 bool AVSharedMemoryExt::ReadFromMessageParcel(MessageParcel &parcel)
131 {
132 #ifdef MEDIA_OHOS
133     int32_t fd = parcel.ReadFileDescriptor();
134     (void)parcel.ReadUint32();
135     if (fd > 0) {
136         (void)::close(fd);
137     }
138 #endif
139     return true;
140 }
141 
GetAddr()142 uint8_t *AVSharedMemoryExt::GetAddr()
143 {
144     if (isFirstFlag_) {
145         Status ret = MapMemoryAddr();
146         FALSE_RETURN_V_MSG_E(ret == Status::OK, nullptr, "MapMemory failed");
147         isFirstFlag_ = false;
148     }
149     return base_;
150 }
151 
GetMemoryType()152 MemoryType AVSharedMemoryExt::GetMemoryType()
153 {
154     return MemoryType::SHARED_MEMORY;
155 }
156 
GetMemoryFlag()157 MemoryFlag AVSharedMemoryExt::GetMemoryFlag()
158 {
159     return memFlag_;
160 }
161 
GetFileDescriptor()162 int32_t AVSharedMemoryExt::GetFileDescriptor()
163 {
164     return fd_;
165 }
166 
UnMapMemoryAddr()167 void AVSharedMemoryExt::UnMapMemoryAddr() noexcept
168 {
169 #ifdef MEDIA_OHOS
170     if (base_ != nullptr) {
171         (void)::munmap(base_, static_cast<size_t>(capacity_));
172         base_ = nullptr;
173         size_ = 0;
174     }
175 #endif
176 }
177 
MapMemoryAddr()178 Status AVSharedMemoryExt::MapMemoryAddr()
179 {
180 #ifdef MEDIA_OHOS
181     ON_SCOPE_EXIT(0)
182     {
183         MEDIA_LOG_E("create avsharedmemory failed. "
184                     "uid:" PUBLIC_LOG_U64 ", size:%{public}d, flags:0x%{public}x, fd:%{public}d",
185                     uid_, capacity_, memFlag_, fd_);
186         UnMapMemoryAddr();
187         return Status::ERROR_NO_MEMORY;
188     };
189     FALSE_RETURN_V_MSG_E(capacity_ > 0, Status::ERROR_INVALID_DATA, "size is invalid, size:%{public}d", capacity_);
190     unsigned int prot = PROT_READ | PROT_WRITE;
191     if (memFlag_ == MemoryFlag::MEMORY_READ_ONLY) {
192         prot &= ~PROT_WRITE;
193     } else if (memFlag_ == MemoryFlag::MEMORY_WRITE_ONLY) {
194         prot &= ~PROT_READ;
195     }
196     int result = AshmemSetProt(fd_, static_cast<int>(prot));
197     FALSE_RETURN_V_MSG_E(result >= 0, Status::ERROR_INVALID_OPERATION, "AshmemSetProt failed, result:%{public}d",
198                          result);
199 
200     void *addr = ::mmap(nullptr, static_cast<size_t>(capacity_), static_cast<int>(prot), MAP_SHARED, fd_, 0);
201     FALSE_RETURN_V_MSG_E(addr != MAP_FAILED, Status::ERROR_INVALID_OPERATION, "mmap failed, please check params");
202 
203     base_ = static_cast<uint8_t *>(addr);
204     CANCEL_SCOPE_EXIT_GUARD(0);
205 #endif
206     return Status::OK;
207 }
208 } // namespace Media
209 } // namespace OHOS
210