• 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 namespace OHOS {
26 namespace Sensors {
27 namespace {
28 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, MISC_LOG_DOMAIN, "VibratorNapiUtils"};
29 }  // namespace
~AsyncCallbackInfo()30 AsyncCallbackInfo::~AsyncCallbackInfo()
31 {
32     CALL_LOG_ENTER;
33     if (asyncWork != nullptr) {
34         MISC_HILOGD("delete work");
35         napi_delete_async_work(env, asyncWork);
36     }
37     for (int32_t i = 0; i < CALLBACK_NUM; ++i) {
38         if (callback[i] != nullptr) {
39             MISC_HILOGD("delete reference, i: %{public}d", i);
40             napi_delete_reference(env, callback[i]);
41         }
42     }
43 }
44 
IsMatchType(const napi_env & env,const napi_value & value,const napi_valuetype & type)45 bool IsMatchType(const napi_env &env, const napi_value &value, const napi_valuetype &type)
46 {
47     napi_valuetype paramType = napi_undefined;
48     napi_status ret = napi_typeof(env, value, &paramType);
49     if ((ret != napi_ok) || (paramType != type)) {
50         MISC_HILOGE("Type mismatch");
51         return false;
52     }
53     return true;
54 }
55 
GetNapiInt32(const napi_env & env,const int32_t value,napi_value & result)56 bool GetNapiInt32(const napi_env &env, const int32_t value, napi_value &result)
57 {
58     CALL_LOG_ENTER;
59     napi_status ret = napi_create_int32(env, value, &result);
60     if (ret != napi_ok) {
61         MISC_HILOGE("GetNapiInt32 failed");
62         return false;
63     }
64     return true;
65 }
66 
GetInt32Value(const napi_env & env,const napi_value & value,int32_t & result)67 bool GetInt32Value(const napi_env &env, const napi_value &value, int32_t &result)
68 {
69     CALL_LOG_ENTER;
70     napi_valuetype valuetype = napi_undefined;
71     NAPI_CALL_BASE(env, napi_typeof(env, value, &valuetype), false);
72     NAPI_ASSERT_BASE(env, valuetype == napi_number,
73         "Wrong argument type. Number or function expected", false);
74     NAPI_CALL_BASE(env, napi_get_value_int32(env, value, &result), false);
75     return true;
76 }
77 
GetStringValue(const napi_env & env,const napi_value & value,string & result)78 bool GetStringValue(const napi_env &env, const napi_value &value, string &result)
79 {
80     CALL_LOG_ENTER;
81     napi_valuetype valuetype = napi_undefined;
82     napi_status ret = napi_typeof(env, value, &valuetype);
83     if (ret != napi_ok) {
84         MISC_HILOGE("napi_typeof failed");
85         return false;
86     }
87     CHKCF((valuetype == napi_string), "Wrong argument type. String or function expected");
88     size_t bufLength = 0;
89     ret = napi_get_value_string_utf8(env, value, nullptr, 0, &bufLength);
90     if (ret != napi_ok) {
91         MISC_HILOGE("napi_get_value_string_utf8 failed");
92         return false;
93     }
94     bufLength = bufLength > STRING_LENGTH_MAX ? STRING_LENGTH_MAX : bufLength;
95     char str[STRING_LENGTH_MAX] = {0};
96     size_t strLen = 0;
97     ret = napi_get_value_string_utf8(env, value, str, bufLength + 1, &strLen);
98     if (ret != napi_ok) {
99         MISC_HILOGE("napi_get_value_string_utf8 failed");
100         return false;
101     }
102     result = str;
103     return true;
104 }
105 
GetPropertyString(const napi_env & env,const napi_value & value,const std::string & type,std::string & result)106 bool GetPropertyString(const napi_env &env, const napi_value &value, const std::string &type, std::string &result)
107 {
108     bool exist = false;
109     napi_status status = napi_has_named_property(env, value, type.c_str(), &exist);
110     if ((status != napi_ok) || (!exist)) {
111         MISC_HILOGE("can not find %{public}s property", type.c_str());
112         return false;
113     }
114 
115     napi_value item = nullptr;
116     CHKCF((napi_get_named_property(env, value, type.c_str(), &item) == napi_ok), "napi get property fail");
117     if (!GetStringValue(env, item, result)) {
118         return false;
119     }
120     return true;
121 }
122 
GetPropertyInt32(const napi_env & env,const napi_value & value,const std::string & type,int32_t & result)123 bool GetPropertyInt32(const napi_env &env, const napi_value &value, const std::string &type, int32_t &result)
124 {
125     napi_value item = nullptr;
126     bool exist = false;
127     napi_status status = napi_has_named_property(env, value, type.c_str(), &exist);
128     if (status != napi_ok || !exist) {
129         MISC_HILOGE("can not find %{public}s property", type.c_str());
130         return false;
131     }
132     CHKCF((napi_get_named_property(env, value, type.c_str(), &item) == napi_ok), "napi get property fail");
133     if (!GetInt32Value(env, item, result)) {
134         MISC_HILOGE("Get int value fail");
135         return false;
136     }
137     return true;
138 }
139 
EmitSystemCallback(const napi_env & env,sptr<AsyncCallbackInfo> asyncCallbackInfo)140 void EmitSystemCallback(const napi_env &env, sptr<AsyncCallbackInfo> asyncCallbackInfo)
141 {
142     CHKPV(asyncCallbackInfo);
143     if (asyncCallbackInfo->error.code == SUCCESS) {
144         CHKPV(asyncCallbackInfo->callback[0]);
145         napi_value callback = nullptr;
146         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback));
147         napi_value result = nullptr;
148         NAPI_CALL_RETURN_VOID(env, napi_get_undefined(env, &result));
149         napi_value callResult = nullptr;
150         NAPI_CALL_RETURN_VOID(env, napi_call_function(env, nullptr, callback, 1, &result, &callResult));
151         return;
152     }
153     CHKPV(asyncCallbackInfo->callback[1]);
154     napi_value callback = nullptr;
155     NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, asyncCallbackInfo->callback[1], &callback));
156     napi_value result[2] = {0};
157     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, asyncCallbackInfo->error.message.data(),
158         NAPI_AUTO_LENGTH, &result[0]));
159     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, asyncCallbackInfo->error.code, &result[1]));
160     napi_value callResult = nullptr;
161     NAPI_CALL_RETURN_VOID(env, napi_call_function(env, nullptr, callback, 1, result, &callResult));
162 }
163 
EmitAsyncCallbackWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)164 void EmitAsyncCallbackWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)
165 {
166     CALL_LOG_ENTER;
167     CHKPV(asyncCallbackInfo);
168     CHKPV(asyncCallbackInfo->env);
169     napi_env env = asyncCallbackInfo->env;
170     napi_value resourceName = nullptr;
171     napi_status ret = napi_create_string_latin1(env, "AsyncCallback", NAPI_AUTO_LENGTH, &resourceName);
172     CHKCV((ret == napi_ok), "napi_create_string_latin1 fail");
173     asyncCallbackInfo->IncStrongRef(nullptr);
174     napi_status status = napi_create_async_work(
175         env, nullptr, resourceName, [](napi_env env, void* data) {},
176         [](napi_env env, napi_status status, void* data) {
177             CALL_LOG_ENTER;
178             sptr<AsyncCallbackInfo> asyncCallbackInfo(static_cast<AsyncCallbackInfo *>(data));
179             /**
180              * After the asynchronous task is created, the asyncCallbackInfo reference count is reduced
181              * to 0 destructions, so you need to add 1 to the asyncCallbackInfo reference count when the
182              * asynchronous task is created, and subtract 1 from the reference count after the naked
183              * pointer is converted to a pointer when the asynchronous task is executed, the reference
184              * count of the smart pointer is guaranteed to be 1.
185              */
186             asyncCallbackInfo->DecStrongRef(nullptr);
187             if (asyncCallbackInfo->callbackType == TYPE_SYSTEM_VIBRATE) {
188                 EmitSystemCallback(env, asyncCallbackInfo);
189                 return;
190             }
191             CHKPV(asyncCallbackInfo->callback[0]);
192             napi_value callback = nullptr;
193             napi_status ret = napi_get_reference_value(env, asyncCallbackInfo->callback[0], &callback);
194             CHKCV((ret == napi_ok), "napi_get_reference_value fail");
195             napi_value result = nullptr;
196             if (asyncCallbackInfo->error.code != SUCCESS) {
197                 auto msg = GetNapiError(asyncCallbackInfo->error.code);
198                 if (!msg) {
199                     MISC_HILOGE("errCode: %{public}d is invalid", asyncCallbackInfo->error.code);
200                     return;
201                 }
202                 result = CreateBusinessError(env, asyncCallbackInfo->error.code, msg.value());
203                 CHKPV(result);
204             } else {
205                 CHKCV((napi_get_undefined(env, &result) == napi_ok), "napi_get_undefined fail");
206             }
207             napi_value callResult = nullptr;
208             CHKCV((napi_call_function(env, nullptr, callback, 1, &result, &callResult) == napi_ok),
209                 "napi_call_function fail");
210         },
211         asyncCallbackInfo.GetRefPtr(), &asyncCallbackInfo->asyncWork);
212     if (status != napi_ok
213         || napi_queue_async_work(asyncCallbackInfo->env, asyncCallbackInfo->asyncWork) != napi_ok) {
214         MISC_HILOGE("Create async work fail");
215         asyncCallbackInfo->DecStrongRef(nullptr);
216     }
217 }
218 
EmitPromiseWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)219 void EmitPromiseWork(sptr<AsyncCallbackInfo> asyncCallbackInfo)
220 {
221     CALL_LOG_ENTER;
222     CHKPV(asyncCallbackInfo);
223     CHKPV(asyncCallbackInfo->env);
224     napi_value resourceName = nullptr;
225     napi_env env = asyncCallbackInfo->env;
226     napi_status ret = napi_create_string_latin1(env, "Promise", NAPI_AUTO_LENGTH, &resourceName);
227     CHKCV((ret == napi_ok), "napi_create_string_latin1 fail");
228     // Make the reference count of asyncCallbackInfo add 1, and the function exits the non-destructor
229     asyncCallbackInfo->IncStrongRef(nullptr);
230     napi_status status = napi_create_async_work(
231         env, nullptr, resourceName, [](napi_env env, void* data) {},
232         [](napi_env env, napi_status status, void* data) {
233             CALL_LOG_ENTER;
234             sptr<AsyncCallbackInfo> asyncCallbackInfo(static_cast<AsyncCallbackInfo *>(data));
235             /**
236              * After the asynchronous task is created, the asyncCallbackInfo reference count is reduced
237              * to 0 destructions, so you need to add 1 to the asyncCallbackInfo reference count when the
238              * asynchronous task is created, and subtract 1 from the reference count after the naked
239              * pointer is converted to a pointer when the asynchronous task is executed, the reference
240              * count of the smart pointer is guaranteed to be 1.
241              */
242             asyncCallbackInfo->DecStrongRef(nullptr);
243             CHKPV(asyncCallbackInfo->deferred);
244             if (asyncCallbackInfo->callbackType == TYPE_SYSTEM_VIBRATE) {
245                 EmitSystemCallback(env, asyncCallbackInfo);
246                 return;
247             }
248             napi_value result = nullptr;
249             if (asyncCallbackInfo->error.code == 0) {
250                 CHKCV((napi_get_undefined(env, &result) == napi_ok), "napi_get_undefined fail");
251                 CHKCV((napi_resolve_deferred(env, asyncCallbackInfo->deferred, result) == napi_ok),
252                     "napi_resolve_deferred fail");
253             } else {
254                 auto msg = GetNapiError(asyncCallbackInfo->error.code);
255                 if (!msg) {
256                     MISC_HILOGE("errCode: %{public}d is invalid", asyncCallbackInfo->error.code);
257                     return;
258                 }
259                 result = CreateBusinessError(env, asyncCallbackInfo->error.code, msg.value());
260                 CHKPV(result);
261                 CHKCV((napi_reject_deferred(env, asyncCallbackInfo->deferred, result) == napi_ok),
262                     "napi_reject_deferred fail");
263             }
264         }, asyncCallbackInfo.GetRefPtr(), &asyncCallbackInfo->asyncWork);
265     if (status != napi_ok
266         || napi_queue_async_work(asyncCallbackInfo->env, asyncCallbackInfo->asyncWork) != napi_ok) {
267         MISC_HILOGE("Create async work fail");
268         asyncCallbackInfo->DecStrongRef(nullptr);
269     }
270 }
271 }  // namespace Sensors
272 }  // namespace OHOS
273