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 "napi_ashmem.h"
17 #include <unistd.h>
18 #include "ipc_debug.h"
19 #include "log_tags.h"
20 #include "securec.h"
21
22 namespace OHOS {
23 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "napi_ashmem" };
24 #ifndef TITLE
25 #define TITLE __PRETTY_FUNCTION__
26 #endif
27 #define DBINDER_LOGE(fmt, args...) \
28 (void)OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args)
29 #define DBINDER_LOGI(fmt, args...) \
30 (void)OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "%{public}s %{public}d: " fmt, TITLE, __LINE__, ##args)
31 static constexpr int MMAP_PROT_MAX = NAPIAshmem::PROT_EXEC | NAPIAshmem::PROT_READ | NAPIAshmem::PROT_WRITE;
32
NAPIAshmem(sptr<Ashmem> & ashmem)33 NAPIAshmem::NAPIAshmem(sptr<Ashmem> &ashmem) : ashmem_(ashmem)
34 {
35 if (ashmem == nullptr) {
36 ZLOGE(LOG_LABEL, "%s: ashmem is null", __func__);
37 }
38 }
39
CloseAshmem(napi_env env,napi_callback_info info)40 napi_value NAPIAshmem::CloseAshmem(napi_env env, napi_callback_info info)
41 {
42 napi_value thisVar = nullptr;
43 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
44 NAPIAshmem *napiAshmem = nullptr;
45 napi_unwrap(env, thisVar, (void **)&napiAshmem);
46 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
47 napiAshmem->GetAshmem()->CloseAshmem();
48 napi_value result = nullptr;
49 napi_get_undefined(env, &result);
50 return result;
51 }
52
CreateAshmem(napi_env env,napi_callback_info info)53 napi_value NAPIAshmem::CreateAshmem(napi_env env, napi_callback_info info)
54 {
55 napi_value thisVar = nullptr;
56 size_t argc = 2;
57 napi_value argv[2] = { 0 };
58 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
59 NAPI_ASSERT(env, argc == 2, "requires 2 parameter");
60 napi_valuetype valueType = napi_null;
61 napi_typeof(env, argv[0], &valueType);
62 if (valueType != napi_string) {
63 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
64 return nullptr;
65 }
66 size_t bufferSize = 0;
67 napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
68 if (bufferSize <= 0) {
69 ZLOGE(LOG_LABEL, "invalid ashmem name");
70 return nullptr;
71 }
72 napi_typeof(env, argv[1], &valueType);
73 if (valueType != napi_number) {
74 ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
75 return nullptr;
76 }
77 int32_t ashmemSize = 0;
78 napi_get_value_int32(env, argv[1], &ashmemSize);
79 if (ashmemSize <= 0) {
80 ZLOGE(LOG_LABEL, "invalid ashmem size");
81 return nullptr;
82 }
83 napi_value global = nullptr;
84 napi_status status = napi_get_global(env, &global);
85 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
86 napi_value constructor = nullptr;
87 status = napi_get_named_property(env, global, "AshmemConstructor_", &constructor);
88 NAPI_ASSERT(env, status == napi_ok, "get Ashmem constructor failed");
89 napi_value jsAshmem;
90 status = napi_new_instance(env, constructor, 2, argv, &jsAshmem);
91 NAPI_ASSERT(env, status == napi_ok, "failed to construct js Ashmem");
92 return jsAshmem;
93 }
94
CreateAshmemFromExisting(napi_env env,napi_callback_info info)95 napi_value NAPIAshmem::CreateAshmemFromExisting(napi_env env, napi_callback_info info)
96 {
97 size_t argc = 1;
98 napi_value argv[1] = {nullptr};
99 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
100 NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
101 napi_value global = nullptr;
102 napi_status status = napi_get_global(env, &global);
103 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
104 napi_value constructor = nullptr;
105 status = napi_get_named_property(env, global, "AshmemConstructor_", &constructor);
106 NAPI_ASSERT(env, status == napi_ok, "get Ashmem constructor failed");
107 bool isAshmem = false;
108 napi_instanceof(env, argv[0], constructor, &isAshmem);
109 NAPI_ASSERT(env, isAshmem == true, "parameter is not instanceof Ashmem");
110 NAPIAshmem *napiAshmem = nullptr;
111 napi_unwrap(env, argv[0], (void **)&napiAshmem);
112 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
113 int32_t fd = napiAshmem->GetAshmem()->GetAshmemFd();
114 uint32_t size = (uint32_t)(napiAshmem->GetAshmem()->GetAshmemSize());
115 NAPI_ASSERT(env, (fd > 0) && (size > 0), "fd <= 0 or size <= 0");
116 sptr<Ashmem> newAshmem(new Ashmem(dup(fd), size));
117 NAPI_ASSERT(env, newAshmem != nullptr, "napiAshmem is null");
118 napi_value jsAshmem = nullptr;
119 status = napi_new_instance(env, constructor, 0, nullptr, &jsAshmem);
120 NAPI_ASSERT(env, status == napi_ok, "failed to construct js Ashmem");
121 NAPIAshmem *newNapiAshmem = nullptr;
122 napi_unwrap(env, jsAshmem, (void **)&newNapiAshmem);
123 NAPI_ASSERT(env, newNapiAshmem != nullptr, "newNapiAshmem is null");
124 newNapiAshmem->SetAshmem(newAshmem);
125 return jsAshmem;
126 }
127
GetAshmemSize(napi_env env,napi_callback_info info)128 napi_value NAPIAshmem::GetAshmemSize(napi_env env, napi_callback_info info)
129 {
130 napi_value thisVar = nullptr;
131 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
132 NAPIAshmem *napiAshmem = nullptr;
133 napi_unwrap(env, thisVar, (void **)&napiAshmem);
134 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
135 uint32_t ashmemSize = (uint32_t)(napiAshmem->GetAshmem()->GetAshmemSize());
136 napi_value napiValue;
137 napi_create_uint32(env, ashmemSize, &napiValue);
138 return napiValue;
139 }
140
MapAshmem(napi_env env,napi_callback_info info)141 napi_value NAPIAshmem::MapAshmem(napi_env env, napi_callback_info info)
142 {
143 napi_value thisVar = nullptr;
144 size_t argc = 1;
145 napi_value argv[1] = {0};
146 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
147 NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
148 napi_valuetype valueType = napi_null;
149 napi_typeof(env, argv[0], &valueType);
150 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
151 uint32_t mapType = 0;
152 napi_get_value_uint32(env, argv[0], &mapType);
153 NAPI_ASSERT(env, mapType <= MMAP_PROT_MAX, "napiAshmem mapType error");
154 NAPIAshmem *napiAshmem = nullptr;
155 napi_unwrap(env, thisVar, (void **)&napiAshmem);
156 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
157 bool result = napiAshmem->GetAshmem()->MapAshmem(mapType);
158 napi_value napiValue = nullptr;
159 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
160 return napiValue;
161 }
162
MapReadAndWriteAshmem(napi_env env,napi_callback_info info)163 napi_value NAPIAshmem::MapReadAndWriteAshmem(napi_env env, napi_callback_info info)
164 {
165 napi_value thisVar = nullptr;
166 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
167 NAPIAshmem *napiAshmem = nullptr;
168 napi_unwrap(env, thisVar, (void **)&napiAshmem);
169 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
170 bool result = napiAshmem->GetAshmem()->MapReadAndWriteAshmem();
171 napi_value napiValue = nullptr;
172 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
173 return napiValue;
174 }
175
MapReadOnlyAshmem(napi_env env,napi_callback_info info)176 napi_value NAPIAshmem::MapReadOnlyAshmem(napi_env env, napi_callback_info info)
177 {
178 napi_value thisVar = nullptr;
179 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
180 NAPIAshmem *napiAshmem = nullptr;
181 napi_unwrap(env, thisVar, (void **)&napiAshmem);
182 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
183 bool result = napiAshmem->GetAshmem()->MapReadOnlyAshmem();
184 napi_value napiValue = nullptr;
185 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
186 return napiValue;
187 }
188
ReadFromAshmem(napi_env env,napi_callback_info info)189 napi_value NAPIAshmem::ReadFromAshmem(napi_env env, napi_callback_info info)
190 {
191 napi_value thisVar = nullptr;
192 size_t argc = 2;
193 napi_value argv[2] = {0};
194 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
195 NAPI_ASSERT(env, argc == 2, "requires 2 parameter");
196 napi_valuetype valueType = napi_null;
197 napi_typeof(env, argv[0], &valueType);
198 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
199 napi_typeof(env, argv[1], &valueType);
200 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
201 uint32_t size = 0;
202 uint32_t offset = 0;
203 napi_get_value_uint32(env, argv[0], &size);
204 napi_get_value_uint32(env, argv[1], &offset);
205 NAPIAshmem *napiAshmem = nullptr;
206 napi_unwrap(env, thisVar, (void **)&napiAshmem);
207 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
208 const void *result = napiAshmem->GetAshmem()->ReadFromAshmem(size, offset);
209 if (result == nullptr) {
210 DBINDER_LOGE("ashmem->ReadFromAshmem returns null");
211 return nullptr;
212 }
213 // c++ byte[] to js []
214 napi_value arrayBuffer = nullptr;
215 void *arrayBufferPtr = nullptr;
216 napi_create_arraybuffer(env, size, &arrayBufferPtr, &arrayBuffer);
217 napi_value typedarray = nullptr;
218 napi_create_typedarray(env, napi_int8_array, size, arrayBuffer, 0, &typedarray);
219 bool isTypedArray = false;
220 napi_is_typedarray(env, typedarray, &isTypedArray);
221 NAPI_ASSERT(env, isTypedArray == true, "create TypedArray failed");
222 if (size == 0) {
223 return typedarray;
224 }
225 errno_t status = memcpy_s(arrayBufferPtr, size, result, size);
226 NAPI_ASSERT(env, status == EOK, "memcpy_s is failed");
227 return typedarray;
228 }
229
SetProtection(napi_env env,napi_callback_info info)230 napi_value NAPIAshmem::SetProtection(napi_env env, napi_callback_info info)
231 {
232 napi_value thisVar = nullptr;
233 size_t argc = 1;
234 napi_value argv[1] = { 0 };
235 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
236 NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
237 napi_valuetype valueType = napi_null;
238 napi_typeof(env, argv[0], &valueType);
239 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
240 uint32_t protectionType = 0;
241 napi_get_value_uint32(env, argv[0], &protectionType);
242 NAPIAshmem *napiAshmem = nullptr;
243 napi_unwrap(env, thisVar, (void **)&napiAshmem);
244 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
245 bool result = napiAshmem->GetAshmem()->SetProtection(protectionType);
246 napi_value napiValue = nullptr;
247 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
248 return napiValue;
249 }
250
UnmapAshmem(napi_env env,napi_callback_info info)251 napi_value NAPIAshmem::UnmapAshmem(napi_env env, napi_callback_info info)
252 {
253 napi_value thisVar = nullptr;
254 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
255 NAPIAshmem *napiAshmem = nullptr;
256 napi_unwrap(env, thisVar, (void **)&napiAshmem);
257 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
258 napiAshmem->GetAshmem()->UnmapAshmem();
259 napi_value result = nullptr;
260 napi_get_undefined(env, &result);
261 return result;
262 }
263
WriteToAshmem(napi_env env,napi_callback_info info)264 napi_value NAPIAshmem::WriteToAshmem(napi_env env, napi_callback_info info)
265 {
266 size_t argc = 3;
267 napi_value argv[3] = {0};
268 napi_value thisVar = nullptr;
269 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
270 NAPI_ASSERT(env, argc == 3, "requires 1 parameter");
271 bool isTypedArray = false;
272 napi_is_typedarray(env, argv[0], &isTypedArray);
273 NAPI_ASSERT(env, isTypedArray == true, "type mismatch for parameter 1");
274 napi_valuetype valueType = napi_null;
275 napi_typeof(env, argv[1], &valueType);
276 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
277 napi_typeof(env, argv[2], &valueType);
278 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 3");
279 napi_typedarray_type typedarrayType = napi_uint8_array;
280 size_t typedarrayLength = 0;
281 void *typedarrayBufferPtr = nullptr;
282 napi_value tmpArrayBuffer = nullptr;
283 size_t byteOffset = 0;
284 napi_get_typedarray_info(env, argv[0], &typedarrayType, &typedarrayLength, &typedarrayBufferPtr,
285 &tmpArrayBuffer, &byteOffset);
286 NAPI_ASSERT(env, typedarrayType == napi_int8_array, "array type mismatch for parameter 1");
287 DBINDER_LOGI("ashmem WriteBuffer typedarrayLength = %{public}d", (int)(typedarrayLength));
288 uint32_t size = 0;
289 napi_get_value_uint32(env, argv[1], &size);
290 uint32_t offset = 0;
291 napi_get_value_uint32(env, argv[2], &offset);
292 NAPIAshmem *napiAshmem = nullptr;
293 napi_unwrap(env, thisVar, (void **)&napiAshmem);
294 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
295 // need check size offset and capacity
296 bool result = napiAshmem->GetAshmem()->WriteToAshmem(typedarrayBufferPtr, size, offset);
297 napi_value napiValue = nullptr;
298 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
299 return napiValue;
300 }
301
AshmemExport(napi_env env,napi_value exports)302 napi_value NAPIAshmem::AshmemExport(napi_env env, napi_value exports)
303 {
304 const std::string className = "Ashmem";
305 napi_value exec = nullptr;
306 napi_create_int32(env, NAPIAshmem::PROT_EXEC, &exec);
307 napi_value none = nullptr;
308 napi_create_int32(env, NAPIAshmem::PROT_NONE, &none);
309 napi_value read = nullptr;
310 napi_create_int32(env, NAPIAshmem::PROT_READ, &read);
311 napi_value write = nullptr;
312 napi_create_int32(env, NAPIAshmem::PROT_WRITE, &write);
313 napi_property_descriptor properties[] = {
314 DECLARE_NAPI_STATIC_FUNCTION("createAshmem", NAPIAshmem::CreateAshmem),
315 DECLARE_NAPI_STATIC_FUNCTION("createAshmemFromExisting", NAPIAshmem::CreateAshmemFromExisting),
316 DECLARE_NAPI_FUNCTION("closeAshmem", NAPIAshmem::CloseAshmem),
317 DECLARE_NAPI_FUNCTION("getAshmemSize", NAPIAshmem::GetAshmemSize),
318 DECLARE_NAPI_FUNCTION("mapAshmem", NAPIAshmem::MapAshmem),
319 DECLARE_NAPI_FUNCTION("mapReadAndWriteAshmem", NAPIAshmem::MapReadAndWriteAshmem),
320 DECLARE_NAPI_FUNCTION("mapReadOnlyAshmem", NAPIAshmem::MapReadOnlyAshmem),
321 DECLARE_NAPI_FUNCTION("readFromAshmem", NAPIAshmem::ReadFromAshmem),
322 DECLARE_NAPI_FUNCTION("setProtection", NAPIAshmem::SetProtection),
323 DECLARE_NAPI_FUNCTION("unmapAshmem", NAPIAshmem::UnmapAshmem),
324 DECLARE_NAPI_FUNCTION("writeToAshmem", NAPIAshmem::WriteToAshmem),
325 DECLARE_NAPI_STATIC_PROPERTY("PROT_EXEC", exec),
326 DECLARE_NAPI_STATIC_PROPERTY("PROT_NONE", none),
327 DECLARE_NAPI_STATIC_PROPERTY("PROT_READ", read),
328 DECLARE_NAPI_STATIC_PROPERTY("PROT_WRITE", write),
329 };
330 napi_value constructor = nullptr;
331 napi_define_class(env, className.c_str(), className.length(), Ashmem_JS_Constructor, nullptr,
332 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
333 NAPI_ASSERT(env, constructor != nullptr, "define js class Ashmem failed");
334 napi_status status = napi_set_named_property(env, exports, "Ashmem", constructor);
335 NAPI_ASSERT(env, status == napi_ok, "set property Ashmem failed");
336 napi_value global = nullptr;
337 status = napi_get_global(env, &global);
338 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
339 status = napi_set_named_property(env, global, "AshmemConstructor_", constructor);
340 NAPI_ASSERT(env, status == napi_ok, "set Ashmem constructor failed");
341 return exports;
342 }
343
Ashmem_JS_Constructor(napi_env env,napi_callback_info info)344 napi_value NAPIAshmem::Ashmem_JS_Constructor(napi_env env, napi_callback_info info)
345 {
346 napi_value thisVar = nullptr;
347 size_t argc = 2;
348 napi_value argv[2] = { 0 };
349 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
350 NAPIAshmem *napiAshmem = nullptr;
351 if (argc == 0) {
352 napiAshmem = new NAPIAshmem();
353 } else {
354 NAPI_ASSERT(env, argc == 2, "requires 2 parameter");
355 napi_valuetype valueType = napi_null;
356 napi_typeof(env, argv[0], &valueType);
357 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
358 napi_typeof(env, argv[1], &valueType);
359 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
360 size_t bufferSize = 0;
361 size_t maxLen = 40960;
362 napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
363 NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
364 char stringValue[bufferSize + 1];
365 size_t jsStringLength = 0;
366 napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength);
367 NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
368 std::string ashmemName = stringValue;
369 uint32_t ashmemSize = 0;
370 napi_get_value_uint32(env, argv[1], &ashmemSize);
371 // new napi Ashmem
372 sptr<Ashmem> nativeAshmem = Ashmem::CreateAshmem(ashmemName.c_str(), ashmemSize);
373 NAPI_ASSERT(env, nativeAshmem != nullptr, "invalid parameters");
374 napiAshmem = new NAPIAshmem(nativeAshmem);
375 }
376 // connect native object to js thisVar
377 napi_status status = napi_wrap(
378 env, thisVar, napiAshmem,
379 [](napi_env env, void *data, void *hint) {
380 DBINDER_LOGI("Ashmem destructed by js callback");
381 delete (reinterpret_cast<NAPIAshmem *>(data));
382 },
383 nullptr, nullptr);
384 NAPI_ASSERT(env, status == napi_ok, "wrap js Ashmem and native holder failed");
385 return thisVar;
386 }
387 }
388