1 /*
2  * Copyright (c) 2024 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 <cerrno>
17 #include <ashmem.h>
18 #include <unordered_map>
19 #include <mutex>
20 #include "ddk_api.h"
21 #include "ddk_types.h"
22 #include "hilog_wrapper.h"
23 
24 #define PORT_MAX 7
25 
26 using namespace OHOS::ExternalDeviceManager;
27 namespace {
28 static std::unordered_map<int32_t, OHOS::sptr<OHOS::Ashmem>> g_shareMemoryMap;
29 std::mutex g_mutex;
30 }
31 
OH_DDK_CreateAshmem(const uint8_t * name,uint32_t size,DDK_Ashmem ** ashmem)32 DDK_RetCode OH_DDK_CreateAshmem(const uint8_t *name, uint32_t size, DDK_Ashmem **ashmem)
33 {
34     if (name == nullptr) {
35         EDM_LOGE(MODULE_BASE_DDK, "invalid buffer name!");
36         return DDK_INVALID_PARAMETER;
37     }
38 
39     if (size == 0) {
40         EDM_LOGE(MODULE_BASE_DDK, "invalid buffer size!, size = %{public}d", size);
41         return DDK_INVALID_PARAMETER;
42     }
43 
44     if (ashmem == nullptr) {
45         EDM_LOGE(MODULE_BASE_DDK, "invalid pointer of ashmem!");
46         return DDK_INVALID_PARAMETER;
47     }
48 
49     OHOS::sptr<OHOS::Ashmem> shareMemory = OHOS::Ashmem::CreateAshmem(reinterpret_cast<const char*>(name), size);
50     if (shareMemory == nullptr) {
51         EDM_LOGE(MODULE_BASE_DDK, "create ashmem failed! errno = %{public}d", errno);
52         return DDK_FAILURE;
53     }
54 
55     int32_t fd = shareMemory->GetAshmemFd();
56     DDK_Ashmem *ddkAshmem = new DDK_Ashmem({fd, nullptr, size, 0, size, 0});
57     if (ddkAshmem == nullptr) {
58         EDM_LOGE(MODULE_BASE_DDK, "alloc ddk ashmem failed! errno = %{public}d", errno);
59         return DDK_FAILURE;
60     }
61     *ashmem = ddkAshmem;
62 
63     std::lock_guard<std::mutex> lock(g_mutex);
64     g_shareMemoryMap[ddkAshmem->ashmemFd] = shareMemory;
65     return DDK_SUCCESS;
66 }
67 
AshmemValidityCheck(DDK_Ashmem * ashmem)68 static DDK_RetCode AshmemValidityCheck(DDK_Ashmem *ashmem)
69 {
70     if (ashmem == nullptr) {
71         EDM_LOGE(MODULE_BASE_DDK, "ashmem is nullptr!");
72         return DDK_NULL_PTR;
73     }
74 
75     if (g_shareMemoryMap.find(ashmem->ashmemFd) == g_shareMemoryMap.end()) {
76         EDM_LOGE(MODULE_BASE_DDK, "ashmemFd dose not exist! error fd = %{public}d", ashmem->ashmemFd);
77         return DDK_FAILURE;
78     }
79 
80     if (g_shareMemoryMap[ashmem->ashmemFd] == nullptr) {
81         EDM_LOGE(MODULE_BASE_DDK, "share memory dose not create!");
82         return DDK_FAILURE;
83     }
84 
85     return DDK_SUCCESS;
86 }
87 
OH_DDK_MapAshmem(DDK_Ashmem * ashmem,const uint8_t ashmemMapType)88 DDK_RetCode OH_DDK_MapAshmem(DDK_Ashmem *ashmem, const uint8_t ashmemMapType)
89 {
90     std::lock_guard<std::mutex> lock(g_mutex);
91     DDK_RetCode ret = AshmemValidityCheck(ashmem);
92     if (ret != DDK_SUCCESS) {
93         EDM_LOGE(MODULE_BASE_DDK, "%{public}s: check the validity of ashmem fail!", __func__);
94         return ret;
95     }
96 
97     if (ashmemMapType > PORT_MAX) {
98         EDM_LOGE(MODULE_BASE_DDK, "%{public}s: the ashmemMapType is illegal ,ashmemMapType = %{public}u",
99             __func__, ashmemMapType);
100         return DDK_INVALID_OPERATION;
101     }
102 
103     if (!g_shareMemoryMap[ashmem->ashmemFd]->MapAshmem(ashmemMapType)) {
104         EDM_LOGE(MODULE_BASE_DDK, "MapAshmem fail! errno = %{public}d", errno);
105         return DDK_INVALID_OPERATION;
106     }
107 
108     ashmem->address =
109         reinterpret_cast<const uint8_t *>(g_shareMemoryMap[ashmem->ashmemFd]->ReadFromAshmem(ashmem->size, 0));
110     return DDK_SUCCESS;
111 }
112 
OH_DDK_UnmapAshmem(DDK_Ashmem * ashmem)113 DDK_RetCode OH_DDK_UnmapAshmem(DDK_Ashmem *ashmem)
114 {
115     std::lock_guard<std::mutex> lock(g_mutex);
116     DDK_RetCode ret = AshmemValidityCheck(ashmem);
117     if (ret != DDK_SUCCESS) {
118         EDM_LOGE(MODULE_BASE_DDK, "%{public}s: check the validity of ashmem fail!", __func__);
119         return ret;
120     }
121 
122     g_shareMemoryMap[ashmem->ashmemFd]->UnmapAshmem();
123     ashmem->address = nullptr;
124     return DDK_SUCCESS;
125 }
126 
OH_DDK_DestroyAshmem(DDK_Ashmem * ashmem)127 DDK_RetCode OH_DDK_DestroyAshmem(DDK_Ashmem *ashmem)
128 {
129     std::lock_guard<std::mutex> lock(g_mutex);
130     DDK_RetCode ret = AshmemValidityCheck(ashmem);
131     if (ret != DDK_SUCCESS) {
132         EDM_LOGE(MODULE_BASE_DDK, "%{public}s: check the validity of ashmem fail!", __func__);
133         return ret;
134     }
135 
136     g_shareMemoryMap.erase(ashmem->ashmemFd);
137     ashmem->address = nullptr;
138     delete ashmem;
139     ashmem = nullptr;
140     return DDK_SUCCESS;
141 }
142