• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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