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, ¶mType);
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