1 /*
2 * Copyright (C) 2021-2022 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 <limits>
18 #include <unistd.h>
19 #include "ipc_debug.h"
20 #include "log_tags.h"
21 #include "securec.h"
22 #include "napi_rpc_error.h"
23
24 namespace OHOS {
25 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_ID_IPC, "napi_ashmem" };
26
27 static constexpr int MMAP_PROT_MAX = NAPIAshmem::PROT_EXEC | NAPIAshmem::PROT_READ | NAPIAshmem::PROT_WRITE;
28 constexpr size_t BYTE_SIZE_32 = 4;
29
30 NapiError NAPIAshmem::napiErr;
31
NAPIAshmem(sptr<Ashmem> & ashmem)32 NAPIAshmem::NAPIAshmem(sptr<Ashmem> &ashmem) : ashmem_(ashmem)
33 {
34 if (ashmem == nullptr) {
35 ZLOGE(LOG_LABEL, "%s: ashmem is null", __func__);
36 }
37 }
38
CloseAshmem(napi_env env,napi_callback_info info)39 napi_value NAPIAshmem::CloseAshmem(napi_env env, napi_callback_info info)
40 {
41 napi_value thisVar = nullptr;
42 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
43 NAPIAshmem *napiAshmem = nullptr;
44 napi_unwrap(env, thisVar, (void **)&napiAshmem);
45 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
46 napiAshmem->GetAshmem()->CloseAshmem();
47 napi_value result = nullptr;
48 napi_get_undefined(env, &result);
49 return result;
50 }
51
CreateAshmem(napi_env env,napi_callback_info info)52 napi_value NAPIAshmem::CreateAshmem(napi_env env, napi_callback_info info)
53 {
54 napi_value thisVar = nullptr;
55 size_t argc = 2;
56 napi_value argv[2] = { 0 };
57 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
58 NAPI_ASSERT(env, argc == 2, "requires 2 parameter");
59 napi_valuetype valueType = napi_null;
60 napi_typeof(env, argv[0], &valueType);
61 if (valueType != napi_string) {
62 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
63 return nullptr;
64 }
65 size_t bufferSize = 0;
66 napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
67 if (bufferSize == 0) {
68 ZLOGE(LOG_LABEL, "invalid ashmem name");
69 return nullptr;
70 }
71 napi_typeof(env, argv[1], &valueType);
72 if (valueType != napi_number) {
73 ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
74 return nullptr;
75 }
76 int32_t ashmemSize = 0;
77 napi_get_value_int32(env, argv[1], &ashmemSize);
78 if (ashmemSize <= 0) {
79 ZLOGE(LOG_LABEL, "invalid ashmem size");
80 return nullptr;
81 }
82 napi_value global = nullptr;
83 napi_status status = napi_get_global(env, &global);
84 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
85 napi_value constructor = nullptr;
86 status = napi_get_named_property(env, global, "AshmemConstructor_", &constructor);
87 NAPI_ASSERT(env, status == napi_ok, "get Ashmem constructor failed");
88 napi_value jsAshmem;
89 status = napi_new_instance(env, constructor, 2, argv, &jsAshmem);
90 NAPI_ASSERT(env, status == napi_ok, "failed to construct js Ashmem");
91 return jsAshmem;
92 }
93
CreateAshmemFromExisting(napi_env env,napi_callback_info info)94 napi_value NAPIAshmem::CreateAshmemFromExisting(napi_env env, napi_callback_info info)
95 {
96 size_t argc = 1;
97 napi_value argv[1] = {nullptr};
98 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
99 NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
100 napi_value global = nullptr;
101 napi_status status = napi_get_global(env, &global);
102 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
103 napi_value constructor = nullptr;
104 status = napi_get_named_property(env, global, "AshmemConstructor_", &constructor);
105 NAPI_ASSERT(env, status == napi_ok, "get Ashmem constructor failed");
106 bool isAshmem = false;
107 napi_instanceof(env, argv[0], constructor, &isAshmem);
108 NAPI_ASSERT(env, isAshmem == true, "parameter is not instanceof Ashmem");
109 NAPIAshmem *napiAshmem = nullptr;
110 napi_unwrap(env, argv[0], (void **)&napiAshmem);
111 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
112 int32_t fd = napiAshmem->GetAshmem()->GetAshmemFd();
113 uint32_t size = (uint32_t)(napiAshmem->GetAshmem()->GetAshmemSize());
114 NAPI_ASSERT(env, (fd > 0) && (size > 0), "fd <= 0 or size <= 0");
115 sptr<Ashmem> newAshmem(new Ashmem(dup(fd), size));
116 NAPI_ASSERT(env, newAshmem != nullptr, "napiAshmem is null");
117 napi_value jsAshmem = nullptr;
118 status = napi_new_instance(env, constructor, 0, nullptr, &jsAshmem);
119 NAPI_ASSERT(env, status == napi_ok, "failed to construct js Ashmem");
120 NAPIAshmem *newNapiAshmem = nullptr;
121 napi_unwrap(env, jsAshmem, (void **)&newNapiAshmem);
122 NAPI_ASSERT(env, newNapiAshmem != nullptr, "newNapiAshmem is null");
123 newNapiAshmem->SetAshmem(newAshmem);
124 return jsAshmem;
125 }
126
Create(napi_env env,napi_callback_info info)127 napi_value NAPIAshmem::Create(napi_env env, napi_callback_info info)
128 {
129 napi_value thisVar = nullptr;
130 size_t argc = 2;
131 size_t argcExistingAshmem = 1;
132 size_t argcAshmem = 2;
133 napi_value argv[2] = { 0 };
134 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
135 if (!(argc == argcExistingAshmem || argc == argcAshmem)) {
136 ZLOGE(LOG_LABEL, "requires 1 or 2 parameter");
137 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
138 }
139
140 if (argc == argcExistingAshmem) {
141 return GetAshmemFromExisting(env, info);
142 }
143
144 napi_valuetype valueType = napi_null;
145 napi_typeof(env, argv[0], &valueType);
146 if (valueType != napi_string) {
147 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
148 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
149 }
150 size_t bufferSize = 0;
151 napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
152 if (bufferSize == 0) {
153 ZLOGE(LOG_LABEL, "invalid ashmem name");
154 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
155 }
156
157 napi_typeof(env, argv[1], &valueType);
158 if (valueType != napi_number) {
159 ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
160 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
161 }
162
163 int32_t ashmemSize = 0;
164 napi_get_value_int32(env, argv[1], &ashmemSize);
165 if (ashmemSize <= 0) {
166 ZLOGE(LOG_LABEL, "invalid ashmem size");
167 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
168 }
169
170 return GetAshmemConstructor(env, argv);
171 }
172
GetAshmemConstructor(napi_env env,napi_value * argv)173 napi_value NAPIAshmem::GetAshmemConstructor(napi_env env, napi_value* argv)
174 {
175 napi_value global = nullptr;
176 napi_status status = napi_get_global(env, &global);
177 if (status != napi_ok) {
178 ZLOGE(LOG_LABEL, "get napi global failed");
179 return nullptr;
180 }
181 napi_value constructor = nullptr;
182 status = napi_get_named_property(env, global, "AshmemConstructor_", &constructor);
183 if (status != napi_ok) {
184 ZLOGE(LOG_LABEL, "get Ashmem constructor failed");
185 return nullptr;
186 }
187 napi_value jsAshmem;
188 status = napi_new_instance(env, constructor, 2, argv, &jsAshmem);
189 if (status != napi_ok) {
190 ZLOGE(LOG_LABEL, "failed to construct js Ashmem");
191 return nullptr;
192 }
193 return jsAshmem;
194 }
195
GetAshmemFromExisting(napi_env env,napi_callback_info info)196 napi_value NAPIAshmem::GetAshmemFromExisting(napi_env env, napi_callback_info info)
197 {
198 size_t argc = 1;
199 napi_value argv[1] = {nullptr};
200 napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
201 napi_value global = nullptr;
202 napi_status status = napi_get_global(env, &global);
203 if (status != napi_ok) {
204 ZLOGE(LOG_LABEL, "get napi global failed");
205 return nullptr;
206 }
207 napi_value constructor = nullptr;
208 status = napi_get_named_property(env, global, "AshmemConstructor_", &constructor);
209 if (status != napi_ok) {
210 ZLOGE(LOG_LABEL, "get Ashmem constructor failed");
211 return nullptr;
212 }
213 bool isAshmem = false;
214 napi_instanceof(env, argv[0], constructor, &isAshmem);
215 if (isAshmem == false) {
216 ZLOGE(LOG_LABEL, "parameter is not instanceof Ashmem");
217 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
218 }
219 NAPIAshmem *napiAshmem = nullptr;
220 napi_unwrap(env, argv[0], (void **)&napiAshmem);
221 if (napiAshmem == nullptr) {
222 ZLOGE(LOG_LABEL, "napiAshmem is null");
223 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
224 }
225 int32_t fd = napiAshmem->GetAshmem()->GetAshmemFd();
226 uint32_t size = (uint32_t)(napiAshmem->GetAshmem()->GetAshmemSize());
227 if (!((fd > 0) && (size > 0))) {
228 ZLOGE(LOG_LABEL, "fd <= 0 or size <= 0");
229 return nullptr;
230 }
231
232 return getNewAshmemConstructor(env, constructor, fd, size);
233 }
234
getNewAshmemConstructor(napi_env env,napi_value & constructor,int32_t fd,uint32_t size)235 napi_value NAPIAshmem::getNewAshmemConstructor(napi_env env, napi_value& constructor, int32_t fd, uint32_t size)
236 {
237 sptr<Ashmem> newAshmem(new Ashmem(dup(fd), size));
238 if (newAshmem == nullptr) {
239 ZLOGE(LOG_LABEL, "newAshmem is null");
240 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
241 }
242
243 napi_value jsAshmem = nullptr;
244 napi_status status = napi_new_instance(env, constructor, 0, nullptr, &jsAshmem);
245 if (status != napi_ok) {
246 ZLOGE(LOG_LABEL, "failed to construct js Ashmem");
247 return nullptr;
248 }
249 NAPIAshmem *newNapiAshmem = nullptr;
250 napi_unwrap(env, jsAshmem, (void **)&newNapiAshmem);
251 if (newNapiAshmem == nullptr) {
252 ZLOGE(LOG_LABEL, "newNapiAshmem is null");
253 return nullptr;
254 }
255 newNapiAshmem->SetAshmem(newAshmem);
256 return jsAshmem;
257 }
258
GetAshmemSize(napi_env env,napi_callback_info info)259 napi_value NAPIAshmem::GetAshmemSize(napi_env env, napi_callback_info info)
260 {
261 napi_value thisVar = nullptr;
262 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
263 NAPIAshmem *napiAshmem = nullptr;
264 napi_unwrap(env, thisVar, (void **)&napiAshmem);
265 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
266 uint32_t ashmemSize = (uint32_t)(napiAshmem->GetAshmem()->GetAshmemSize());
267 napi_value napiValue;
268 napi_create_uint32(env, ashmemSize, &napiValue);
269 return napiValue;
270 }
271
MapAshmem(napi_env env,napi_callback_info info)272 napi_value NAPIAshmem::MapAshmem(napi_env env, napi_callback_info info)
273 {
274 napi_value thisVar = nullptr;
275 size_t argc = 1;
276 napi_value argv[1] = {0};
277 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
278 NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
279 napi_valuetype valueType = napi_null;
280 napi_typeof(env, argv[0], &valueType);
281 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
282 uint32_t mapType = 0;
283 napi_get_value_uint32(env, argv[0], &mapType);
284 NAPI_ASSERT(env, mapType <= MMAP_PROT_MAX, "napiAshmem mapType error");
285 NAPIAshmem *napiAshmem = nullptr;
286 napi_unwrap(env, thisVar, (void **)&napiAshmem);
287 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
288 bool result = napiAshmem->GetAshmem()->MapAshmem(mapType);
289 napi_value napiValue = nullptr;
290 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
291 return napiValue;
292 }
293
MapTypedAshmem(napi_env env,napi_callback_info info)294 napi_value NAPIAshmem::MapTypedAshmem(napi_env env, napi_callback_info info)
295 {
296 napi_value thisVar = nullptr;
297 size_t argc = 1;
298 napi_value argv[1] = {0};
299 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
300 if (argc != 1) {
301 ZLOGE(LOG_LABEL, "requires 1 parameter");
302 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
303 }
304 napi_valuetype valueType = napi_null;
305 napi_typeof(env, argv[0], &valueType);
306 if (valueType != napi_number) {
307 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
308 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
309 }
310 uint32_t mapType = 0;
311 napi_get_value_uint32(env, argv[0], &mapType);
312 if (mapType > MMAP_PROT_MAX) {
313 ZLOGE(LOG_LABEL, "napiAshmem mapType error");
314 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
315 }
316 NAPIAshmem *napiAshmem = nullptr;
317 napi_unwrap(env, thisVar, (void **)&napiAshmem);
318 if (napiAshmem == nullptr) {
319 ZLOGE(LOG_LABEL, "napiAshmem is null");
320 return napiErr.ThrowError(env, OHOS::errorDesc::OS_MMAP_ERROR);
321 }
322 napiAshmem->GetAshmem()->MapAshmem(mapType);
323 napi_value result = nullptr;
324 napi_get_undefined(env, &result);
325 return result;
326 }
327
MapReadAndWriteAshmem(napi_env env,napi_callback_info info)328 napi_value NAPIAshmem::MapReadAndWriteAshmem(napi_env env, napi_callback_info info)
329 {
330 napi_value thisVar = nullptr;
331 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
332 NAPIAshmem *napiAshmem = nullptr;
333 napi_unwrap(env, thisVar, (void **)&napiAshmem);
334 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
335 bool result = napiAshmem->GetAshmem()->MapReadAndWriteAshmem();
336 napi_value napiValue = nullptr;
337 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
338 return napiValue;
339 }
340
MapReadWriteAshmem(napi_env env,napi_callback_info info)341 napi_value NAPIAshmem::MapReadWriteAshmem(napi_env env, napi_callback_info info)
342 {
343 napi_value thisVar = nullptr;
344 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
345 NAPIAshmem *napiAshmem = nullptr;
346 napi_unwrap(env, thisVar, (void **)&napiAshmem);
347 if (napiAshmem == nullptr) {
348 ZLOGE(LOG_LABEL, "napiAshmem is null");
349 return napiErr.ThrowError(env, OHOS::errorDesc::OS_MMAP_ERROR);
350 }
351 napiAshmem->GetAshmem()->MapReadAndWriteAshmem();
352 napi_value result = nullptr;
353 napi_get_undefined(env, &result);
354 return result;
355 }
356
MapReadOnlyAshmem(napi_env env,napi_callback_info info)357 napi_value NAPIAshmem::MapReadOnlyAshmem(napi_env env, napi_callback_info info)
358 {
359 napi_value thisVar = nullptr;
360 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
361 NAPIAshmem *napiAshmem = nullptr;
362 napi_unwrap(env, thisVar, (void **)&napiAshmem);
363 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
364 bool result = napiAshmem->GetAshmem()->MapReadOnlyAshmem();
365 napi_value napiValue = nullptr;
366 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
367 return napiValue;
368 }
369
MapReadonlyAshmem(napi_env env,napi_callback_info info)370 napi_value NAPIAshmem::MapReadonlyAshmem(napi_env env, napi_callback_info info)
371 {
372 napi_value thisVar = nullptr;
373 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
374 NAPIAshmem *napiAshmem = nullptr;
375 napi_unwrap(env, thisVar, (void **)&napiAshmem);
376 if (napiAshmem == nullptr) {
377 ZLOGE(LOG_LABEL, "napiAshmem is null");
378 return napiErr.ThrowError(env, OHOS::errorDesc::OS_MMAP_ERROR);
379 }
380 napiAshmem->GetAshmem()->MapReadOnlyAshmem();
381 napi_value result = nullptr;
382 napi_get_undefined(env, &result);
383 return result;
384 }
385
ReadFromAshmem(napi_env env,napi_callback_info info)386 napi_value NAPIAshmem::ReadFromAshmem(napi_env env, napi_callback_info info)
387 {
388 napi_value thisVar = nullptr;
389 size_t argc = 2;
390 napi_value argv[2] = {0};
391 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
392 NAPI_ASSERT(env, argc == 2, "requires 2 parameter");
393 napi_valuetype valueType = napi_null;
394 napi_typeof(env, argv[0], &valueType);
395 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
396 napi_typeof(env, argv[1], &valueType);
397 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
398 int64_t size = 0;
399 napi_get_value_int64(env, argv[0], &size);
400 int64_t offset = 0;
401 napi_get_value_int64(env, argv[1], &offset);
402 NAPIAshmem *napiAshmem = nullptr;
403 napi_unwrap(env, thisVar, (void **)&napiAshmem);
404 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
405
406 uint32_t ashmemSize = (uint32_t)napiAshmem->GetAshmem()->GetAshmemSize();
407 if (size < 0 || size > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
408 offset < 0 || offset > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
409 (size * BYTE_SIZE_32 + offset * BYTE_SIZE_32) > ashmemSize) {
410 ZLOGE(LOG_LABEL, "invalid parameter, size = %{public}jd, offset = %{public}jd", size, offset);
411 return nullptr;
412 }
413 size *= BYTE_SIZE_32;
414 offset *= BYTE_SIZE_32;
415 const void *result = napiAshmem->GetAshmem()->ReadFromAshmem(size, offset);
416 if (result == nullptr) {
417 ZLOGE(LOG_LABEL, "ashmem->ReadFromAshmem returns null");
418 return nullptr;
419 }
420 // c++ byte[] to js []
421 napi_value arrayBuffer = nullptr;
422 void *arrayBufferPtr = nullptr;
423 napi_create_arraybuffer(env, size, &arrayBufferPtr, &arrayBuffer);
424 napi_value typedarray = nullptr;
425 napi_create_typedarray(env, napi_int32_array, size / BYTE_SIZE_32, arrayBuffer, 0, &typedarray);
426 bool isTypedArray = false;
427 napi_is_typedarray(env, typedarray, &isTypedArray);
428 NAPI_ASSERT(env, isTypedArray == true, "create TypedArray failed");
429 if (size == 0) {
430 return typedarray;
431 }
432 errno_t status = memcpy_s(arrayBufferPtr, size, result, size);
433 NAPI_ASSERT(env, status == EOK, "memcpy_s is failed");
434 return typedarray;
435 }
436
ReadAshmem(napi_env env,napi_callback_info info)437 napi_value NAPIAshmem::ReadAshmem(napi_env env, napi_callback_info info)
438 {
439 napi_value thisVar = nullptr;
440 size_t argc = 2;
441 size_t argNum = 2;
442 napi_value argv[2] = {0};
443 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
444 if (argc != argNum) {
445 ZLOGE(LOG_LABEL, "requires 2 parameter");
446 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
447 }
448 napi_valuetype valueType = napi_null;
449 napi_typeof(env, argv[0], &valueType);
450 if (valueType != napi_number) {
451 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
452 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
453 }
454 napi_typeof(env, argv[1], &valueType);
455 if (valueType != napi_number) {
456 ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
457 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
458 }
459 int64_t size = 0;
460 napi_get_value_int64(env, argv[0], &size);
461 int64_t offset = 0;
462 napi_get_value_int64(env, argv[1], &offset);
463 NAPIAshmem *napiAshmem = nullptr;
464 napi_unwrap(env, thisVar, (void **)&napiAshmem);
465 if (napiAshmem == nullptr) {
466 ZLOGE(LOG_LABEL, "napiAshmem is null");
467 return napiErr.ThrowError(env, OHOS::errorDesc::READ_FROM_ASHMEM_ERROR);
468 }
469 uint32_t ashmemSize = (uint32_t)napiAshmem->GetAshmem()->GetAshmemSize();
470 if (size < 0 || size > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
471 offset < 0 || offset > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
472 (size * BYTE_SIZE_32 + offset * BYTE_SIZE_32) > ashmemSize) {
473 ZLOGE(LOG_LABEL, "invalid parameter, size = %{public}jd, offset = %{public}jd", size, offset);
474 return nullptr;
475 }
476 size *= BYTE_SIZE_32;
477 offset *= BYTE_SIZE_32;
478 const void *result = napiAshmem->GetAshmem()->ReadFromAshmem(size, offset);
479 if (result == nullptr) {
480 ZLOGE(LOG_LABEL, "ashmem->ReadFromAshmem returns null");
481 return nullptr;
482 }
483 // c++ byte[] to js []
484 return TransferByteToJsData(env, size, result);
485 }
486
TransferByteToJsData(napi_env env,uint32_t size,const void * result)487 napi_value NAPIAshmem::TransferByteToJsData(napi_env env, uint32_t size, const void *result)
488 {
489 napi_value arrayBuffer = nullptr;
490 void *arrayBufferPtr = nullptr;
491 napi_create_arraybuffer(env, size, &arrayBufferPtr, &arrayBuffer);
492 napi_value typedarray = nullptr;
493 napi_create_typedarray(env, napi_int32_array, size / BYTE_SIZE_32, arrayBuffer, 0, &typedarray);
494 bool isTypedArray = false;
495 napi_is_typedarray(env, typedarray, &isTypedArray);
496 NAPI_ASSERT(env, isTypedArray == true, "create TypedArray failed");
497 if (isTypedArray == false) {
498 ZLOGE(LOG_LABEL, "napiAshmem is null");
499 return napiErr.ThrowError(env, OHOS::errorDesc::READ_FROM_ASHMEM_ERROR);
500 }
501 if (size == 0) {
502 return typedarray;
503 }
504 errno_t status = memcpy_s(arrayBufferPtr, size, result, size);
505 if (status != EOK) {
506 ZLOGE(LOG_LABEL, "memcpy_s is failed");
507 return napiErr.ThrowError(env, OHOS::errorDesc::READ_FROM_ASHMEM_ERROR);
508 }
509 return typedarray;
510 }
511
SetProtection(napi_env env,napi_callback_info info)512 napi_value NAPIAshmem::SetProtection(napi_env env, napi_callback_info info)
513 {
514 napi_value thisVar = nullptr;
515 size_t argc = 1;
516 napi_value argv[1] = { 0 };
517 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
518 NAPI_ASSERT(env, argc == 1, "requires 1 parameter");
519 napi_valuetype valueType = napi_null;
520 napi_typeof(env, argv[0], &valueType);
521 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 1");
522 uint32_t protectionType = 0;
523 napi_get_value_uint32(env, argv[0], &protectionType);
524 NAPIAshmem *napiAshmem = nullptr;
525 napi_unwrap(env, thisVar, (void **)&napiAshmem);
526 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
527 bool result = napiAshmem->GetAshmem()->SetProtection(protectionType);
528 napi_value napiValue = nullptr;
529 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
530 return napiValue;
531 }
532
SetProtectionType(napi_env env,napi_callback_info info)533 napi_value NAPIAshmem::SetProtectionType(napi_env env, napi_callback_info info)
534 {
535 napi_value thisVar = nullptr;
536 size_t argc = 1;
537 size_t argNum = 1;
538 napi_value argv[1] = { 0 };
539 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
540 if (argc != argNum) {
541 ZLOGE(LOG_LABEL, "requires 1 parameter");
542 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
543 }
544 napi_valuetype valueType = napi_null;
545 napi_typeof(env, argv[0], &valueType);
546 if (valueType != napi_number) {
547 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
548 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
549 }
550 uint32_t protectionType = 0;
551 napi_get_value_uint32(env, argv[0], &protectionType);
552 NAPIAshmem *napiAshmem = nullptr;
553 napi_unwrap(env, thisVar, (void **)&napiAshmem);
554 if (napiAshmem == nullptr) {
555 ZLOGE(LOG_LABEL, "napiAshmem is null");
556 return napiErr.ThrowError(env, OHOS::errorDesc::OS_IOCTL_ERROR);
557 }
558 napiAshmem->GetAshmem()->SetProtection(protectionType);
559 napi_value result = nullptr;
560 napi_get_undefined(env, &result);
561 return result;
562 }
563
UnmapAshmem(napi_env env,napi_callback_info info)564 napi_value NAPIAshmem::UnmapAshmem(napi_env env, napi_callback_info info)
565 {
566 napi_value thisVar = nullptr;
567 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
568 NAPIAshmem *napiAshmem = nullptr;
569 napi_unwrap(env, thisVar, (void **)&napiAshmem);
570 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
571 napiAshmem->GetAshmem()->UnmapAshmem();
572 napi_value result = nullptr;
573 napi_get_undefined(env, &result);
574 return result;
575 }
576
WriteToAshmem(napi_env env,napi_callback_info info)577 napi_value NAPIAshmem::WriteToAshmem(napi_env env, napi_callback_info info)
578 {
579 size_t argc = 3;
580 napi_value argv[3] = {0};
581 napi_value thisVar = nullptr;
582 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
583 NAPI_ASSERT(env, argc == 3, "requires 3 parameter");
584 bool isArray = false;
585 napi_is_array(env, argv[0], &isArray);
586 NAPI_ASSERT(env, isArray == true, "type mismatch for parameter 1");
587 napi_valuetype valueType = napi_null;
588 napi_typeof(env, argv[1], &valueType);
589 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
590 napi_typeof(env, argv[2], &valueType);
591 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 3");
592
593 std::vector<int32_t> array;
594 uint32_t arrayLength = 0;
595 napi_get_array_length(env, argv[0], &arrayLength);
596
597 for (size_t i = 0; i < arrayLength; i++) {
598 bool hasElement = false;
599 napi_has_element(env, argv[0], i, &hasElement);
600 NAPI_ASSERT(env, hasElement == true, "parameter check error");
601
602 napi_value element = nullptr;
603 napi_get_element(env, argv[0], i, &element);
604
605 int32_t value = 0;
606 napi_get_value_int32(env, element, &value);
607 array.push_back(value);
608 }
609
610 int64_t size = 0;
611 napi_get_value_int64(env, argv[1], &size);
612 int64_t offset = 0;
613 napi_get_value_int64(env, argv[2], &offset);
614 NAPIAshmem *napiAshmem = nullptr;
615 napi_unwrap(env, thisVar, (void **)&napiAshmem);
616 NAPI_ASSERT(env, napiAshmem != nullptr, "napiAshmem is null");
617
618 // need check size offset and capacity
619 napi_value napiValue = nullptr;
620 bool result = true;
621 uint32_t ashmemSize = (uint32_t)napiAshmem->GetAshmem()->GetAshmemSize();
622 if (size < 0 || size > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
623 offset < 0 || offset > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
624 (size * BYTE_SIZE_32 + offset * BYTE_SIZE_32) > ashmemSize) {
625 ZLOGE(LOG_LABEL, "invalid parameter, size = %{public}jd, offset = %{public}jd", size, offset);
626 result = false;
627 } else {
628 result = napiAshmem->GetAshmem()->WriteToAshmem(array.data(), size * BYTE_SIZE_32, offset * BYTE_SIZE_32);
629 }
630 NAPI_CALL(env, napi_get_boolean(env, result, &napiValue));
631 return napiValue;
632 }
633
WriteAshmem(napi_env env,napi_callback_info info)634 napi_value NAPIAshmem::WriteAshmem(napi_env env, napi_callback_info info)
635 {
636 size_t argc = 3;
637 napi_value argv[3] = {0};
638 napi_value thisVar = nullptr;
639 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
640 napi_value checkArgsResult = CheckWriteAshmemParams(env, argc, argv);
641 if (checkArgsResult != nullptr) {
642 return checkArgsResult;
643 }
644
645 std::vector<int32_t> array;
646 uint32_t arrayLength = 0;
647 napi_get_array_length(env, argv[0], &arrayLength);
648
649 for (size_t i = 0; i < arrayLength; i++) {
650 bool hasElement = false;
651 napi_has_element(env, argv[0], i, &hasElement);
652 if (hasElement == false) {
653 ZLOGE(LOG_LABEL, "parameter check error");
654 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
655 }
656
657 napi_value element = nullptr;
658 napi_get_element(env, argv[0], i, &element);
659
660 int32_t value = 0;
661 napi_get_value_int32(env, element, &value);
662 array.push_back(value);
663 }
664
665 int64_t size = 0;
666 napi_get_value_int64(env, argv[1], &size);
667 int64_t offset = 0;
668 napi_get_value_int64(env, argv[2], &offset);
669 NAPIAshmem *napiAshmem = nullptr;
670 napi_unwrap(env, thisVar, (void **)&napiAshmem);
671 if (napiAshmem == nullptr) {
672 ZLOGE(LOG_LABEL, "napiAshmem is null");
673 return napiErr.ThrowError(env, OHOS::errorDesc::WRITE_TO_ASHMEM_ERROR);
674 }
675
676 // need check size offset and capacity
677 uint32_t ashmemSize = (uint32_t)napiAshmem->GetAshmem()->GetAshmemSize();
678 if (size < 0 || size > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
679 offset < 0 || offset > (int64_t)(std::numeric_limits<int32_t>::max() / BYTE_SIZE_32) ||
680 (size * BYTE_SIZE_32 + offset * BYTE_SIZE_32) > ashmemSize) {
681 ZLOGE(LOG_LABEL, "invalid parameter, size = %{public}jd, offset = %{public}jd", size, offset);
682 return napiErr.ThrowError(env, OHOS::errorDesc::WRITE_TO_ASHMEM_ERROR);
683 }
684 napiAshmem->GetAshmem()->WriteToAshmem(array.data(), size * BYTE_SIZE_32, offset * BYTE_SIZE_32);
685 napi_value result = nullptr;
686 napi_get_undefined(env, &result);
687 return result;
688 }
689
CheckWriteAshmemParams(napi_env env,size_t argc,napi_value * argv)690 napi_value NAPIAshmem::CheckWriteAshmemParams(napi_env env, size_t argc, napi_value* argv)
691 {
692 size_t argNum = 3;
693 if (argc != argNum) {
694 ZLOGE(LOG_LABEL, "requires 3 parameter");
695 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
696 }
697 bool isArray = false;
698 napi_is_array(env, argv[0], &isArray);
699 if (isArray == false) {
700 ZLOGE(LOG_LABEL, "type mismatch for parameter 1");
701 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
702 }
703 napi_valuetype valueType = napi_null;
704 napi_typeof(env, argv[1], &valueType);
705 if (valueType != napi_number) {
706 ZLOGE(LOG_LABEL, "type mismatch for parameter 2");
707 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
708 }
709 napi_typeof(env, argv[2], &valueType);
710 if (valueType != napi_number) {
711 ZLOGE(LOG_LABEL, "type mismatch for parameter 4");
712 return napiErr.ThrowError(env, OHOS::errorDesc::CHECK_PARAM_ERROR);
713 }
714 return nullptr;
715 }
716
AshmemExport(napi_env env,napi_value exports)717 napi_value NAPIAshmem::AshmemExport(napi_env env, napi_value exports)
718 {
719 const std::string className = "Ashmem";
720 napi_value exec = nullptr;
721 napi_create_int32(env, NAPIAshmem::PROT_EXEC, &exec);
722 napi_value none = nullptr;
723 napi_create_int32(env, NAPIAshmem::PROT_NONE, &none);
724 napi_value read = nullptr;
725 napi_create_int32(env, NAPIAshmem::PROT_READ, &read);
726 napi_value write = nullptr;
727 napi_create_int32(env, NAPIAshmem::PROT_WRITE, &write);
728 napi_property_descriptor properties[] = {
729 DECLARE_NAPI_STATIC_FUNCTION("createAshmem", NAPIAshmem::CreateAshmem),
730 DECLARE_NAPI_STATIC_FUNCTION("create", NAPIAshmem::Create),
731 DECLARE_NAPI_STATIC_FUNCTION("createAshmemFromExisting", NAPIAshmem::CreateAshmemFromExisting),
732 DECLARE_NAPI_FUNCTION("closeAshmem", NAPIAshmem::CloseAshmem),
733 DECLARE_NAPI_FUNCTION("getAshmemSize", NAPIAshmem::GetAshmemSize),
734 DECLARE_NAPI_FUNCTION("mapAshmem", NAPIAshmem::MapAshmem),
735 DECLARE_NAPI_FUNCTION("mapTypedAshmem", NAPIAshmem::MapTypedAshmem),
736 DECLARE_NAPI_FUNCTION("mapReadAndWriteAshmem", NAPIAshmem::MapReadAndWriteAshmem),
737 DECLARE_NAPI_FUNCTION("mapReadWriteAshmem", NAPIAshmem::MapReadWriteAshmem),
738 DECLARE_NAPI_FUNCTION("mapReadOnlyAshmem", NAPIAshmem::MapReadOnlyAshmem),
739 DECLARE_NAPI_FUNCTION("mapReadonlyAshmem", NAPIAshmem::MapReadonlyAshmem),
740 DECLARE_NAPI_FUNCTION("readFromAshmem", NAPIAshmem::ReadFromAshmem),
741 DECLARE_NAPI_FUNCTION("readAshmem", NAPIAshmem::ReadAshmem),
742 DECLARE_NAPI_FUNCTION("setProtection", NAPIAshmem::SetProtection),
743 DECLARE_NAPI_FUNCTION("setProtectionType", NAPIAshmem::SetProtectionType),
744 DECLARE_NAPI_FUNCTION("unmapAshmem", NAPIAshmem::UnmapAshmem),
745 DECLARE_NAPI_FUNCTION("writeToAshmem", NAPIAshmem::WriteToAshmem),
746 DECLARE_NAPI_FUNCTION("writeAshmem", NAPIAshmem::WriteAshmem),
747 DECLARE_NAPI_STATIC_PROPERTY("PROT_EXEC", exec),
748 DECLARE_NAPI_STATIC_PROPERTY("PROT_NONE", none),
749 DECLARE_NAPI_STATIC_PROPERTY("PROT_READ", read),
750 DECLARE_NAPI_STATIC_PROPERTY("PROT_WRITE", write),
751 };
752 napi_value constructor = nullptr;
753 napi_define_class(env, className.c_str(), className.length(), Ashmem_JS_Constructor, nullptr,
754 sizeof(properties) / sizeof(properties[0]), properties, &constructor);
755 NAPI_ASSERT(env, constructor != nullptr, "define js class Ashmem failed");
756 napi_status status = napi_set_named_property(env, exports, "Ashmem", constructor);
757 NAPI_ASSERT(env, status == napi_ok, "set property Ashmem failed");
758 napi_value global = nullptr;
759 status = napi_get_global(env, &global);
760 NAPI_ASSERT(env, status == napi_ok, "get napi global failed");
761 status = napi_set_named_property(env, global, "AshmemConstructor_", constructor);
762 NAPI_ASSERT(env, status == napi_ok, "set Ashmem constructor failed");
763 return exports;
764 }
765
Ashmem_JS_Constructor(napi_env env,napi_callback_info info)766 napi_value NAPIAshmem::Ashmem_JS_Constructor(napi_env env, napi_callback_info info)
767 {
768 napi_value thisVar = nullptr;
769 size_t argc = 2;
770 napi_value argv[2] = { 0 };
771 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
772 NAPIAshmem *napiAshmem = nullptr;
773 if (argc == 0) {
774 napiAshmem = new NAPIAshmem();
775 } else {
776 NAPI_ASSERT(env, argc == 2, "requires 2 parameter");
777 napi_valuetype valueType = napi_null;
778 napi_typeof(env, argv[0], &valueType);
779 NAPI_ASSERT(env, valueType == napi_string, "type mismatch for parameter 1");
780 napi_typeof(env, argv[1], &valueType);
781 NAPI_ASSERT(env, valueType == napi_number, "type mismatch for parameter 2");
782 size_t bufferSize = 0;
783 size_t maxLen = 40960;
784 napi_get_value_string_utf8(env, argv[0], nullptr, 0, &bufferSize);
785 NAPI_ASSERT(env, bufferSize < maxLen, "string length too large");
786 char stringValue[bufferSize + 1];
787 size_t jsStringLength = 0;
788 napi_get_value_string_utf8(env, argv[0], stringValue, bufferSize + 1, &jsStringLength);
789 NAPI_ASSERT(env, jsStringLength == bufferSize, "string length wrong");
790 std::string ashmemName = stringValue;
791 uint32_t ashmemSize = 0;
792 napi_get_value_uint32(env, argv[1], &ashmemSize);
793 // new napi Ashmem
794 sptr<Ashmem> nativeAshmem = Ashmem::CreateAshmem(ashmemName.c_str(), ashmemSize);
795 NAPI_ASSERT(env, nativeAshmem != nullptr, "invalid parameters");
796 napiAshmem = new NAPIAshmem(nativeAshmem);
797 }
798 // connect native object to js thisVar
799 napi_status status = napi_wrap(
800 env, thisVar, napiAshmem,
801 [](napi_env env, void *data, void *hint) {
802 ZLOGI(LOG_LABEL, "Ashmem destructed by js callback");
803 delete (reinterpret_cast<NAPIAshmem *>(data));
804 },
805 nullptr, nullptr);
806 NAPI_ASSERT(env, status == napi_ok, "wrap js Ashmem and native holder failed");
807 return thisVar;
808 }
809 } // namespace OHOS
810