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
26using namespace OHOS::ExternalDeviceManager;
27namespace {
28static std::unordered_map<int32_t, OHOS::sptr<OHOS::Ashmem>> g_shareMemoryMap;
29std::mutex g_mutex;
30}
31
32DDK_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
68static 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
88DDK_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
113DDK_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
127DDK_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