1 /*
2  * Copyright (C) 2021 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 "memory_manager.h"
17 
18 #include <cerrno>
19 #include <unistd.h>
20 #include "image_log.h"
21 #include "image_utils.h"
22 #include "media_errors.h"
23 #include "securec.h"
24 
25 #if !defined(_WIN32) && !defined(_APPLE) &&!defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
26 #include <sys/mman.h>
27 #include "ashmem.h"
28 #include "surface_buffer.h"
29 #define SUPPORT_SHARED_MEMORY
30 #endif
31 
32 #undef LOG_DOMAIN
33 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_IMAGE
34 
35 #undef LOG_TAG
36 #define LOG_TAG "MemoryManager"
37 
38 namespace OHOS {
39 namespace Media {
40 static const size_t SIZE_ZERO = 0;
41 static const int LINUX_SUCCESS = 0;
42 // Define pixel map malloc max size 600MB
43 constexpr int32_t PIXEL_MAP_MAX_RAM_SIZE = 600 * 1024 * 1024;
44 
Create()45 uint32_t HeapMemory::Create()
46 {
47     IMAGE_LOGD("HeapMemory::Create IN");
48     if (data.data != nullptr) {
49         IMAGE_LOGD("HeapMemory::Create has created");
50         return SUCCESS;
51     }
52     if (data.size == 0 || data.size > PIXEL_MAP_MAX_RAM_SIZE) {
53         IMAGE_LOGE("HeapMemory::Create Invalid value of bufferSize");
54         return ERR_IMAGE_DATA_ABNORMAL;
55     }
56     data.data = static_cast<uint8_t *>(malloc(data.size));
57     if (data.data == nullptr) {
58         IMAGE_LOGE("HeapMemory::Create malloc buffer failed");
59         return ERR_IMAGE_MALLOC_ABNORMAL;
60     }
61 #if defined(IOS_PLATFORM) || defined(ANDROID_PLATFORM)
62     memset_s(data.data, data.size, 0, data.size);
63 #endif
64     return SUCCESS;
65 }
66 
Release()67 uint32_t HeapMemory::Release()
68 {
69 #if !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
70     IMAGE_LOGD("HeapMemory::Release IN");
71     if (data.data == nullptr) {
72         IMAGE_LOGI("HeapMemory::Release nullptr data");
73         return ERR_IMAGE_DATA_ABNORMAL;
74     }
75     free(data.data);
76     data.data = nullptr;
77 #endif
78     return SUCCESS;
79 }
80 
ReleaseSharedMemory(int * fdPtr,uint8_t * ptr=nullptr,size_t size=SIZE_ZERO)81 static inline void ReleaseSharedMemory(int* fdPtr, uint8_t* ptr = nullptr, size_t size = SIZE_ZERO)
82 {
83 #if !defined(IOS_PLATFORM) &&!defined(ANDROID_PLATFORM)
84     if (ptr != nullptr && ptr != MAP_FAILED) {
85         ::munmap(ptr, size);
86     }
87     if (fdPtr != nullptr) {
88         ::close(*fdPtr);
89     }
90 #endif
91 }
92 
Create()93 uint32_t SharedMemory::Create()
94 {
95 #ifdef SUPPORT_SHARED_MEMORY
96     IMAGE_LOGD("SharedMemory::Create IN tag %{public}s, data size %{public}zu",
97         data.tag == nullptr ? "nullptr" : data.tag, data.size);
98 
99     if (data.tag == nullptr || data.size == SIZE_ZERO) {
100         IMAGE_LOGE("SharedMemory::Create tag is nullptr or data size %{public}zu", data.size);
101         return ERR_IMAGE_DATA_ABNORMAL;
102     }
103     auto fdPtr = std::make_unique<int>();
104     *fdPtr = AshmemCreate(data.tag, data.size);
105     if (*fdPtr < 0) {
106         IMAGE_LOGE("SharedMemory::Create AshmemCreate fd:[%{public}d].", *fdPtr);
107         return ERR_IMAGE_DATA_ABNORMAL;
108     }
109     if (AshmemSetProt(*fdPtr, PROT_READ | PROT_WRITE) < LINUX_SUCCESS) {
110         IMAGE_LOGE("SharedMemory::Create AshmemSetProt errno %{public}d.", errno);
111         ReleaseSharedMemory(fdPtr.get());
112         return ERR_IMAGE_DATA_ABNORMAL;
113     }
114     data.data = ::mmap(nullptr, data.size, PROT_READ | PROT_WRITE, MAP_SHARED, *fdPtr, 0);
115     if (data.data == MAP_FAILED) {
116         IMAGE_LOGE("SharedMemory::Create mmap failed, errno:%{public}d", errno);
117         ReleaseSharedMemory(fdPtr.get(), static_cast<uint8_t*>(data.data), data.size);
118         return ERR_IMAGE_DATA_ABNORMAL;
119     }
120     extend.size = sizeof(int);
121     extend.data = fdPtr.release();
122     return SUCCESS;
123 #else
124     IMAGE_LOGE("SharedMemory::Create unsupported");
125     return ERR_IMAGE_DATA_UNSUPPORT;
126 #endif
127 }
128 
Release()129 uint32_t SharedMemory::Release()
130 {
131 #ifdef SUPPORT_SHARED_MEMORY
132     IMAGE_LOGD("SharedMemory::Release IN");
133     ReleaseSharedMemory(static_cast<int*>(extend.data), static_cast<uint8_t*>(data.data), data.size);
134     data.data = nullptr;
135     data.size = SIZE_ZERO;
136     if (extend.data != nullptr) {
137         free(extend.data);
138         extend.data = nullptr;
139         extend.size = SIZE_ZERO;
140     }
141     return SUCCESS;
142 #else
143     IMAGE_LOGE("SharedMemory::Release unsupported");
144     return ERR_IMAGE_DATA_UNSUPPORT;
145 #endif
146 }
147 
148 #if !defined(_WIN32) && !defined(_APPLE) && !defined(IOS_PLATFORM) && !defined(ANDROID_PLATFORM)
GetRequestBufferFormatWithPixelFormat(const PixelFormat format)149 GraphicPixelFormat GetRequestBufferFormatWithPixelFormat(const PixelFormat format)
150 {
151     switch (format) {
152         case PixelFormat::RGBA_1010102:
153             return GRAPHIC_PIXEL_FMT_RGBA_1010102;
154         case PixelFormat::ASTC_4x4:
155         case PixelFormat::ASTC_6x6:
156         case PixelFormat::ASTC_8x8:
157             return GRAPHIC_PIXEL_FMT_BLOB;
158         case PixelFormat::NV12:
159             return GRAPHIC_PIXEL_FMT_YCBCR_420_SP;
160         case PixelFormat::NV21:
161             return GRAPHIC_PIXEL_FMT_YCRCB_420_SP;
162         case PixelFormat::BGRA_8888:
163             return GRAPHIC_PIXEL_FMT_BGRA_8888;
164         case PixelFormat::YCRCB_P010:
165             return GRAPHIC_PIXEL_FMT_YCRCB_P010;
166         case PixelFormat::YCBCR_P010:
167             return GRAPHIC_PIXEL_FMT_YCBCR_P010;
168         case PixelFormat::RGBA_F16:
169             return GRAPHIC_PIXEL_FMT_RGBA16_FLOAT;
170         default:
171             return GRAPHIC_PIXEL_FMT_RGBA_8888;
172     }
173 }
174 #endif
175 
Create()176 uint32_t DmaMemory::Create()
177 {
178 #if defined(_WIN32) || defined(_APPLE) || defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
179     IMAGE_LOGE("Unsupport dma mem alloc");
180     return ERR_IMAGE_DATA_UNSUPPORT;
181 #else
182     sptr<SurfaceBuffer> sb = SurfaceBuffer::Create();
183     GraphicPixelFormat format = GetRequestBufferFormatWithPixelFormat(data.format);
184     BufferRequestConfig requestConfig = {
185         .width = data.desiredSize.width,
186         .height = data.desiredSize.height,
187         .strideAlignment = 0x8, // set 0x8 as default value to alloc SurfaceBufferImpl
188         .format = format, // PixelFormat
189         .usage = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_CPU_WRITE | BUFFER_USAGE_MEM_DMA | BUFFER_USAGE_MEM_MMZ_CACHE,
190         .timeout = 0,
191     };
192     GSError ret = sb->Alloc(requestConfig);
193     if (ret != GSERROR_OK) {
194         IMAGE_LOGE("SurfaceBuffer Alloc failed, %{public}s", GSErrorStr(ret).c_str());
195         return ERR_DMA_NOT_EXIST;
196     }
197     void* nativeBuffer = sb.GetRefPtr();
198     int32_t err = ImageUtils::SurfaceBuffer_Reference(nativeBuffer);
199     if (err != OHOS::GSERROR_OK) {
200         IMAGE_LOGE("NativeBufferReference failed");
201         return ERR_DMA_DATA_ABNORMAL;
202     }
203     data.data = static_cast<uint8_t*>(sb->GetVirAddr());
204     extend.size = data.size;
205     extend.data = nativeBuffer;
206     return SUCCESS;
207 #endif
208 }
209 
Release()210 uint32_t DmaMemory::Release()
211 {
212 #if defined(_WIN32) || defined(_APPLE) || defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
213     IMAGE_LOGE("Unsupport dma mem release");
214     return ERR_IMAGE_DATA_UNSUPPORT;
215 #else
216     data.data = nullptr;
217     data.size = SIZE_ZERO;
218     if (extend.data != nullptr) {
219         int32_t err = ImageUtils::SurfaceBuffer_Unreference(static_cast<SurfaceBuffer*>(extend.data));
220         if (err != OHOS::GSERROR_OK) {
221             IMAGE_LOGE("NativeBufferReference failed");
222             return ERR_DMA_DATA_ABNORMAL;
223         }
224         extend.data = nullptr;
225         extend.size = SIZE_ZERO;
226     }
227     return SUCCESS;
228 #endif
229 }
230 
CreateMemory(AllocatorType type,MemoryData & data)231 std::unique_ptr<AbsMemory> MemoryManager::CreateMemory(AllocatorType type, MemoryData &data)
232 {
233     MemoryData extend{};
234     return CreateMemory(type, data, extend);
235 }
236 
CreateMemory(AllocatorType type,MemoryData & data,MemoryData & extend)237 std::unique_ptr<AbsMemory> MemoryManager::CreateMemory(AllocatorType type, MemoryData &data, MemoryData &extend)
238 {
239     std::unique_ptr<AbsMemory> res = nullptr;
240     switch (type) {
241         case AllocatorType::SHARE_MEM_ALLOC:
242             res = std::make_unique<SharedMemory>();
243             break;
244         case AllocatorType::DMA_ALLOC:
245             res = std::make_unique<DmaMemory>();
246             break;
247         case AllocatorType::CUSTOM_ALLOC:
248             IMAGE_LOGE("MemoryManager::CreateMemory unsupported CUSTOM_ALLOC now");
249             return nullptr;
250         case AllocatorType::DEFAULT:
251         case AllocatorType::HEAP_ALLOC:
252         default:
253             res = std::make_unique<HeapMemory>();
254             break;
255     }
256     if (res == nullptr) {
257         IMAGE_LOGE("MemoryManager::CreateMemory unsupported %{public}d", type);
258         return nullptr;
259     }
260     res->data.data = data.data;
261     res->data.size = data.size;
262     res->data.tag = data.tag;
263     res->data.desiredSize = data.desiredSize;
264     res->data.format = data.format;
265     res->extend.data = extend.data;
266     res->extend.size = extend.size;
267     res->extend.tag = extend.tag;
268     res->extend.desiredSize = extend.desiredSize;
269     res->extend.format = data.format;
270     if (res->data.data == nullptr) {
271         if (res->Create() != SUCCESS) {
272             return nullptr;
273         }
274     }
275     return res;
276 }
277 
TransMemoryType(const AbsMemory & source,AllocatorType target,std::string tag)278 std::unique_ptr<AbsMemory> MemoryManager::TransMemoryType(const AbsMemory &source, AllocatorType target,
279     std::string tag)
280 {
281     MemoryData data = { nullptr, source.data.size, tag.c_str()};
282     data.format = source.data.format;
283     auto res = CreateMemory(target, data);
284     if (res == nullptr) {
285         return res;
286     }
287     memcpy_s(res->data.data, res->data.size, source.data.data, source.data.size);
288     return res;
289 }
290 } // namespace Media
291 } // namespace OHOS