• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "vibrator_napi_utils.h"
17 
18 #include <string>
19 #include "hilog/log.h"
20 #include "securec.h"
21 
22 #include "miscdevice_log.h"
23 #include "vibrator_napi_error.h"
24 
25 #undef LOG_TAG
26 #define LOG_TAG "VibratorNapiUtils"
27 
28 namespace OHOS {
29 namespace Sensors {
30 namespace {
31 constexpr int32_t RESULT_LENGTH = 2;
32 }  // namespace
~AsyncCallbackInfo()33 AsyncCallbackInfo::~AsyncCallbackInfo()
34 {
35     CALL_LOG_ENTER;
36     if (asyncWork != nullptr) {
37         MISC_HILOGD("Delete work");
38         napi_delete_async_work(env, asyncWork);
39     }
40     for (int32_t i = 0; i < CALLBACK_NUM; ++i) {
41         if (callback[i] != nullptr) {
42             MISC_HILOGD("Delete reference, i:%{public}d", i);
43             napi_delete_reference(env, callback[i]);
44         }
45     }
46 }
47 
IsMatchType(const napi_env & env,const napi_value & value,const napi_valuetype & type)48 bool IsMatchType(const napi_env &env, const napi_value &value, const napi_valuetype &type)
49 {
50     napi_valuetype paramType = napi_undefined;
51     napi_status ret = napi_typeof(env, value, &paramType);
52     if ((ret != napi_ok) || (paramType != type)) {
53         MISC_HILOGE("Type mismatch");
54         return false;
55     }
56     return true;
57 }
58 
GetNapiInt32(const napi_env & env,const int32_t value,napi_value & result)59 bool GetNapiInt32(const napi_env &env, const int32_t value, napi_value &result)
60 {
61     CALL_LOG_ENTER;
62     napi_status ret = napi_create_int32(env, value, &result);
63     if (ret != napi_ok) {
64         MISC_HILOGE("GetNapiInt32 failed");
65         return false;
66     }
67     return true;
68 }
69 
GetInt32Value(const napi_env & env,const napi_value & value,int32_t & result)70 bool GetInt32Value(const napi_env &env, const napi_value &value, int32_t &result)
71 {
72     CALL_LOG_ENTER;
73     napi_valuetype valuetype = napi_undefined;
74     CHKCF(napi_typeof(env, value, &valuetype) == napi_ok, "napi_typeof failed");
75     CHKCF((valuetype == napi_number), "Wrong argument type. Number expected");
76     CHKCF(napi_get_value_int32(env, value, &result) == napi_ok, "napi_get_value_int32 failed");
77     return true;
78 }
79 
GetInt64Value(const napi_env & env,const napi_value & value,int64_t & result)80 bool GetInt64Value(const napi_env &env, const napi_value &value, int64_t &result)
81 {
82     CALL_LOG_ENTER;
83     napi_valuetype valuetype = napi_undefined;
84     CHKCF(napi_typeof(env, value, &valuetype) == napi_ok, "napi_typeof failed");
85     CHKCF((valuetype == napi_number), "Wrong argument type. Number expected");
86     CHKCF(napi_get_value_int64(env, value, &result) == napi_ok, "napi_get_value_int64 failed");
87     return true;
88 }
89 
GetBoolValue(const napi_env & env,const napi_value & value,bool & result)90 bool GetBoolValue(const napi_env &env, const napi_value &value, bool &result)
91 {
92     CALL_LOG_ENTER;
93     napi_valuetype valuetype = napi_undefined;
94     CHKCF(napi_typeof(env, value, &valuetype) == napi_ok, "napi_typeof failed");
95     CHKCF((valuetype == napi_boolean), "Wrong argument type. bool expected");
96     CHKCF(napi_get_value_bool(env, value, &result) == napi_ok, "napi_get_value_bool failed");
97     return true;
98 }
99 
GetStringValue(const napi_env & env,const napi_value & value,string & result)100 bool GetStringValue(const napi_env &env, const napi_value &value, string &result)
101 {
102     CALL_LOG_ENTER;
103     napi_valuetype valuetype = napi_undefined;
104     napi_status ret = napi_typeof(env, value, &valuetype);
105     if (ret != napi_ok) {
106         MISC_HILOGE("napi_typeof failed");
107         return false;
108     }
109     CHKCF((valuetype == napi_string), "Wrong argument type. String or function expected");
110     size_t bufLength = 0;
111     ret = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength);
112     if (ret != napi_ok) {
113         MISC_HILOGE("napi_get_value_string_utf8 failed");
114         return false;
115     }
116     bufLength = bufLength > STRING_LENGTH_MAX ? STRING_LENGTH_MAX : bufLength;
117     char str[STRING_LENGTH_MAX] = {0};
118     size_t strLen = 0;
119     ret = napi_get_value_string_utf8(env, value, str, bufLength + 1, &strLen);
120     if (ret != napi_ok) {
121         MISC_HILOGE("napi_get_value_string_utf8 failed");
122         return false;
123     }
124     result = str;
125     return true;
126 }
127 
GetPropertyItem(const napi_env & env,const napi_value & value,const std::string & type,napi_value & item)128 bool GetPropertyItem(const napi_env &env, const napi_value &value, const std::string &type, napi_value &item)
129 {
130     bool exist = false;
131     napi_status status = napi_has_named_property(env, value, type.c_str(), &exist);
132     if ((status != napi_ok) || (!exist)) {
133         MISC_HILOGE("Can not find %{public}s property", type.c_str());
134         return false;
135     }
136     CHKCF((napi_get_named_property(env, value, type.c_str(), &item) == napi_ok), "napi get property fail");
137     return true;
138 }
139 
GetPropertyString(const napi_env & env,const napi_value & value,const std::string & type,std::string & result)140 bool GetPropertyString(const napi_env &env, const napi_value &value, const std::string &type, std::string &result)
141 {
142     bool exist = false;
143     napi_status status = napi_has_named_property(env, value, type.c_str(), &exist);
144     if ((status != napi_ok) || (!exist)) {
145         MISC_HILOGE("Can not find %{public}s property", type.c_str());
146         return false;
147     }
148 
149     napi_value item = nullptr;
150     CHKCF((napi_get_named_property(env, value, type.c_str(), &item) == napi_ok), "napi get property fail");
151     if (!GetStringValue(env, item, result)) {
152         return false;
153     }
154     return true;
155 }
156 
GetPropertyInt32(const napi_env & env,const napi_value & value,const std::string & type,int32_t & result)157 bool GetPropertyInt32(const napi_env &env, const napi_value &value, const std::string &type, int32_t &result)
158 {
159     napi_value item = nullptr;
160     bool exist = false;
161     napi_status status = napi_has_named_property(env, value, type.c_str(), &exist);
162     if (status != napi_ok || !exist) {
163         MISC_HILOGD("Can not find %{public}s property", type.c_str());
164         return false;
165     }
166     CHKCF((napi_get_named_property(env, value, type.c_str(), &item) == napi_ok), "napi get property fail");
167     if (!GetInt32Value(env, item, result)) {
168         MISC_HILOGE("Get int value fail");
169         return false;
170     }
171     return true;
172 }
173 
GetPropertyInt64(const napi_env & env,const napi_value & value,const std::string & type,int64_t & result)174 bool GetPropertyInt64(const napi_env &env, const napi_value &value, const std::string &type, int64_t &result)
175 {
176     napi_value item = nullptr;
177     bool exist = false;
178     napi_status status = napi_has_named_property(env, value, type.c_str(), &exist);
179     if (status != napi_ok || !exist) {
180         MISC_HILOGE("Can not find %{public}s property", type.c_str());
181         return false;
182     }
183     CHKCF((napi_get_named_property(env, value, type.c_str(), &item) == napi_ok), "napi get property fail");
184     if (!GetInt64Value(env, item, result)) {
185         MISC_HILOGE("Get int value fail");
186         return false;
187     }
188     return true;
189 }
190 
GetPropertyBool(const napi_env & env,const napi_value & value,const std::string & type,bool & result)191 bool GetPropertyBool(const napi_env &env, const napi_value &value, const std::string &type, bool &result)
192 {
193     bool exist = false;
194     napi_status status = napi_has_named_property(env, value, type.c_str(), &exist);
195     if ((status != napi_ok) || (!exist)) {
196         MISC_HILOGD("Can not find %{public}s property", type.c_str());
197         return false;
198     }
199     napi_value item = nullptr;
200     CHKCF((napi_get_named_property(env, value, type.c_str(), &item) == napi_ok), "napi get property fail");
201     if (!GetBoolValue(env, item, result)) {
202         MISC_HILOGE("Get bool value fail");
203         return false;
204     }
205     return true;
206 }
207 
208 std::map<int32_t, ConstructResultFunc> g_convertFuncList = {
209     {COMMON_CALLBACK, ConstructCommonResult},
210     {IS_SUPPORT_EFFECT_CALLBACK, ConstructIsSupportEffectResult},
211 };
212 
ConvertErrorToResult(const napi_env & env,sptr<AsyncCallbackInfo> asyncCallbackInfo,napi_value & result)213 bool ConvertErrorToResult(const napi_env &env, sptr<AsyncCallbackInfo> asyncCallbackInfo, napi_value &result)
214 {
215     CHKPF(asyncCallbackInfo);
216     int32_t code = asyncCallbackInfo->error.code;
217     auto msg = GetNapiError(code);
218     if (!msg) {
219         MISC_HILOGE("ErrCode:%{public}d is invalid", code);
220         return false;
221     }
222     result = CreateBusinessError(env, code, msg.value());
223     return (result != nullptr);
224 }
225 
ConstructCommonResult(const napi_env & env,sptr<AsyncCallbackInfo> asyncCallbackInfo,napi_value result[],int32_t length)226 bool ConstructCommonResult(const napi_env &env, sptr<AsyncCallbackInfo> asyncCallbackInfo, napi_value result[],
227     int32_t length)
228 {
229     CHKPF(asyncCallbackInfo);
230     CHKCF(length == RESULT_LENGTH, "Array length is different");
231     if (asyncCallbackInfo->error.code != SUCCESS) {
232         CHKCF(ConvertErrorToResult(env, asyncCallbackInfo, result[0]), "Create napi err fail in async work");
233         CHKCF((napi_get_undefined(env, &result[1]) == napi_ok), "napi_get_undefined fail");
234     } else {
235         CHKCF((napi_get_undefined(env, &result[0]) == napi_ok), "napi_get_undefined fail");
236         CHKCF((napi_get_undefined(env, &result[1]) == napi_ok), "napi_get_undefined fail");
237     }
238     return true;
239 }
240 
ConstructIsSupportEffectResult(const napi_env & env,sptr<AsyncCallbackInfo> asyncCallbackInfo,napi_value result[],int32_t length)241 bool ConstructIsSupportEffectResult(const napi_env &env, sptr<AsyncCallbackInfo> asyncCallbackInfo,
242     napi_value result[], int32_t length)
243 {
244     CHKPF(asyncCallbackInfo);
245     CHKCF(length == RESULT_LENGTH, "Array length is different");
246     if (asyncCallbackInfo->error.code != SUCCESS) {
247         CHKCF(ConvertErrorToResult(env, asyncCallbackInfo, result[0]), "Create napi err fail in async work");
248         CHKCF((napi_get_undefined(env, &result[1]) == napi_ok), "napi_get_undefined fail");
249     } else {
250         CHKCF((napi_get_undefined(env, &result[0]) == napi_ok), "napi_get_undefined fail");
251         CHKCF((napi_get_boolean(env, asyncCallbackInfo->isSupportEffect, &result[1]) == napi_ok),
252             "napi_get_boolean fail");
253     }
254     return true;
255 }
256 
EmitSystemCallback(const napi_env & env,sptr<AsyncCallbackInfo> asyncCallbackInfo)257 void EmitSystemCallback(const napi_env &env, sptr<AsyncCallbackInfo> asyncCallbackInfo)
258 {
259     CHKPV(asyncCallbackInfo);
260     if (asyncCallbackInfo->error.code == SUCCESS) {
261         CHKPV(asyncCallbackInfo->callback[0]);
262         napi_value callback = nullptr;
263         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback));
264         napi_value result = nullptr;
265         NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &result));
266         napi_value callResult = nullptr;
267         NAPI_CALL_RETURN_VOID(env, napi_call_function(env, nullptr, callback, 1, &result, &callResult));
268         return;
269     }
270     CHKPV(asyncCallbackInfo->callback[1]);
271     napi_value callback = nullptr;
272     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->callback[1], &callback));
273     napi_value result[2] = {0};
274     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, asyncCallbackInfo->error.message.data(),
275         NAPI_AUTO_LENGTH, &result[0]));
276     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, asyncCallbackInfo->error.code, &result[1]));
277     napi_value callResult = nullptr;
278     NAPI_CALL_RETURN_VOID(env, napi_call_function(env, nullptr, callback, 1, result, &callResult));
279 }
280 
EmitAsyncCallbackWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)281 void EmitAsyncCallbackWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)
282 {
283     CALL_LOG_ENTER;
284     CHKPV(asyncCallbackInfo);
285     CHKPV(asyncCallbackInfo->env);
286     napi_env env = asyncCallbackInfo->env;
287     napi_value resourceName = nullptr;
288     napi_status ret = napi_create_string_latin1(env, "AsyncCallback", NAPI_AUTO_LENGTH, &resourceName);
289     CHKCV((ret == napi_ok), "napi_create_string_latin1 fail");
290     asyncCallbackInfo->IncStrongRef(nullptr);
291     napi_status status = napi_create_async_work(
292         env, nullptr, resourceName, [](napi_env env, void *data) {},
293         [](napi_env env, napi_status status, void *data) {
294             CALL_LOG_ENTER;
295             sptr<AsyncCallbackInfo> asyncCallbackInfo(static_cast<AsyncCallbackInfo *>(data));
296             /**
297              * After the asynchronous task is created, the asyncCallbackInfo reference count is reduced
298              * to 0 destruction, so you need to add 1 to the asyncCallbackInfo reference count when the
299              * asynchronous task is created, and subtract 1 from the reference count after the naked
300              * pointer is converted to a pointer when the asynchronous task is executed, the reference
301              * count of the smart pointer is guaranteed to be 1.
302              */
303             asyncCallbackInfo->DecStrongRef(nullptr);
304             if (asyncCallbackInfo->callbackType == SYSTEM_VIBRATE_CALLBACK) {
305                 EmitSystemCallback(env, asyncCallbackInfo);
306                 return;
307             }
308             CHKPV(asyncCallbackInfo->callback[0]);
309             napi_value callback = nullptr;
310             napi_status ret = napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback);
311             CHKCV((ret == napi_ok), "napi_get_reference_value fail");
312             napi_value result[RESULT_LENGTH] = { 0 };
313             CHKCV((g_convertFuncList.find(asyncCallbackInfo->callbackType) != g_convertFuncList.end()),
314                 "Callback type invalid in async work");
315             bool state = g_convertFuncList[asyncCallbackInfo->callbackType](env, asyncCallbackInfo, result,
316                 sizeof(result) / sizeof(napi_value));
317             CHKCV(state, "Create napi data fail in async work");
318             napi_value callResult = nullptr;
319             CHKCV((napi_call_function(env, nullptr, callback, 2, result, &callResult) == napi_ok),
320                 "napi_call_function fail");
321         },
322         asyncCallbackInfo.GetRefPtr(), &asyncCallbackInfo->asyncWork);
323     if (status != napi_ok
324         || napi_queue_async_work_with_qos(
325             asyncCallbackInfo->env, asyncCallbackInfo->asyncWork, napi_qos_default) != napi_ok) {
326         MISC_HILOGE("Create async work fail");
327         asyncCallbackInfo->DecStrongRef(nullptr);
328     }
329 }
330 
EmitPromiseWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)331 void EmitPromiseWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)
332 {
333     CALL_LOG_ENTER;
334     CHKPV(asyncCallbackInfo);
335     CHKPV(asyncCallbackInfo->env);
336     napi_value resourceName = nullptr;
337     napi_env env = asyncCallbackInfo->env;
338     napi_status ret = napi_create_string_latin1(env, "Promise", NAPI_AUTO_LENGTH, &resourceName);
339     CHKCV((ret == napi_ok), "napi_create_string_latin1 fail");
340     // Make the reference count of asyncCallbackInfo add 1, and the function exits the non-destructor
341     asyncCallbackInfo->IncStrongRef(nullptr);
342     napi_status status = napi_create_async_work(
343         env, nullptr, resourceName, [](napi_env env, void *data) {},
344         [](napi_env env, napi_status status, void *data) {
345             CALL_LOG_ENTER;
346             sptr<AsyncCallbackInfo> asyncCallbackInfo(static_cast<AsyncCallbackInfo *>(data));
347             /**
348              * After the asynchronous task is created, the asyncCallbackInfo reference count is reduced
349              * to 0 destruction, so you need to add 1 to the asyncCallbackInfo reference count when the
350              * asynchronous task is created, and subtract 1 from the reference count after the naked
351              * pointer is converted to a pointer when the asynchronous task is executed, the reference
352              * count of the smart pointer is guaranteed to be 1.
353              */
354             asyncCallbackInfo->DecStrongRef(nullptr);
355             CHKPV(asyncCallbackInfo->deferred);
356             if (asyncCallbackInfo->callbackType == SYSTEM_VIBRATE_CALLBACK) {
357                 EmitSystemCallback(env, asyncCallbackInfo);
358                 return;
359             }
360             napi_value result[RESULT_LENGTH] = { 0 };
361             CHKCV((g_convertFuncList.find(asyncCallbackInfo->callbackType) != g_convertFuncList.end()),
362                 "Callback type invalid in promise");
363             bool ret = g_convertFuncList[asyncCallbackInfo->callbackType](env, asyncCallbackInfo, result,
364                 sizeof(result) / sizeof(napi_value));
365             CHKCV(ret, "Callback type invalid in promise");
366             if (asyncCallbackInfo->error.code != SUCCESS) {
367                 CHKCV((napi_reject_deferred(env, asyncCallbackInfo->deferred, result[0]) == napi_ok),
368                     "napi_reject_deferred fail");
369             } else {
370                 CHKCV((napi_resolve_deferred(env, asyncCallbackInfo->deferred, result[1]) == napi_ok),
371                     "napi_resolve_deferred fail");
372             }
373         }, asyncCallbackInfo.GetRefPtr(), &asyncCallbackInfo->asyncWork);
374     if (status != napi_ok
375         || napi_queue_async_work_with_qos(
376             asyncCallbackInfo->env, asyncCallbackInfo->asyncWork, napi_qos_default) != napi_ok) {
377         MISC_HILOGE("Create async work fail");
378         asyncCallbackInfo->DecStrongRef(nullptr);
379     }
380 }
381 } // namespace Sensors
382 } // namespace OHOS
383