1 /*
2 * Copyright (c) 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 "webview_javascript_result_callback.h"
17
18 #include <sys/mman.h>
19 #include <unistd.h>
20
21 #include "core/common/container_scope.h"
22 #include "napi_parse_utils.h"
23 #include "nweb_napi_scope.h"
24 #include "native_engine/native_engine.h"
25 #include "nweb_helper.h"
26 #include "nweb_log.h"
27 #include "ohos_adapter_helper.h"
28 #include "webview_value.h"
29 #include "../../../../ohos_interface/ohos_glue/base/include/ark_web_errno.h"
30
31 namespace OHOS::NWeb {
32 namespace {
33 #define JS_BRIDGE_BINARY_ARGS_COUNT 2
34
35 const int MAX_FLOWBUF_DATA_SIZE = 52428800; /* 50MB*/
36 const int MAX_ENTRIES = 10;
37 const int HEADER_SIZE = (MAX_ENTRIES * 8); /* 10 * (int position + int length) */
38 const int INDEX_SIZE = 2;
39
40 // For the sake of the storage API, make this quite large.
41 const uint32_t MAX_RECURSION_DEPTH = 11;
42 const uint32_t MAX_DATA_LENGTH = 10000;
43
44 std::unordered_map<int32_t, WebviewJavaScriptResultCallBack*> g_webviewJsResultCallbackMap;
45 std::mutex g_objectMtx;
46
47 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value& value,
48 std::shared_ptr<NWebValue> nwebValue, bool* isObject);
49 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value* value,
50 std::shared_ptr<NWebValue> nwebValue, bool* isObject);
51
52 template<typename T>
53 napi_value ParseNwebValue2NapiValueV2(napi_env env, std::shared_ptr<T> value,
54 WebviewJavaScriptResultCallBack::ObjectMap objectsMap, int32_t nwebId, int32_t frameId);
55
56 template<typename T>
57 std::vector<std::string> ParseNapiValue2NwebValueV2(
58 napi_env env, napi_value* value, std::shared_ptr<T> nwebValue, bool* isObject);
59
60 class ValueConvertState {
61 public:
62 // Level scope which updates the current depth of some ValueConvertState.
63 class Level {
64 public:
Level(ValueConvertState * state)65 explicit Level(ValueConvertState* state) : state_(state)
66 {
67 if (state_) {
68 state_->maxRecursionDepth_--;
69 }
70 }
~Level()71 ~Level()
72 {
73 if (state_) {
74 state_->maxRecursionDepth_++;
75 }
76 }
77
78 private:
79 ValueConvertState* state_;
80 };
81
ValueConvertState()82 explicit ValueConvertState() : maxRecursionDepth_(MAX_RECURSION_DEPTH)
83 {
84 }
85
86 ValueConvertState(const ValueConvertState&) = delete;
87 ValueConvertState& operator=(const ValueConvertState&) = delete;
88
HasReachedMaxRecursionDepth()89 bool HasReachedMaxRecursionDepth()
90 {
91 return maxRecursionDepth_ == 0;
92 }
93
94 private:
95 uint32_t maxRecursionDepth_;
96 };
97
FromNwebID(int32_t nwebId)98 WebviewJavaScriptResultCallBack* FromNwebID(int32_t nwebId)
99 {
100 std::unique_lock<std::mutex> lk(g_objectMtx);
101 if (auto it = g_webviewJsResultCallbackMap.find(nwebId); it != g_webviewJsResultCallbackMap.end()) {
102 auto js_result_callback = it->second;
103 return js_result_callback;
104 }
105 return nullptr;
106 }
107
StringSplit(std::string str,const char split,std::vector<std::string> & result)108 void StringSplit(std::string str, const char split, std::vector<std::string>& result)
109 {
110 std::istringstream iss(str);
111 std::string token;
112 while (getline(iss, token, split)) {
113 result.push_back(token);
114 }
115 }
116
CallH5Function(napi_env env,napi_value * napiArg,std::shared_ptr<NWebValue> nwebValue,WebviewJavaScriptResultCallBack::H5Bundle bundle)117 void CallH5Function(napi_env env, napi_value* napiArg, std::shared_ptr<NWebValue> nwebValue,
118 WebviewJavaScriptResultCallBack::H5Bundle bundle)
119 {
120 WVLOG_D("CallH5Function called");
121 bool isObject = false;
122 std::vector<std::string> methodNameList;
123 methodNameList = ParseNapiValue2NwebValue(env, napiArg, nwebValue, &isObject);
124 if (isObject && FromNwebID(bundle.nwebId)) {
125 JavaScriptOb::ObjectID returnedObjectId;
126 if (FromNwebID(bundle.nwebId)->FindObjectIdInJsTd(env, *napiArg, &returnedObjectId)
127 && FromNwebID(bundle.nwebId)->FindObject(returnedObjectId)) {
128 FromNwebID(bundle.nwebId)->FindObject(returnedObjectId)->AddHolder(bundle.frameRoutingId);
129 } else {
130 returnedObjectId = FromNwebID(bundle.nwebId)->AddObject(env, *napiArg, false, bundle.frameRoutingId);
131 }
132
133 FromNwebID(bundle.nwebId)->SetUpAnnotateMethods(returnedObjectId, methodNameList);
134
135 napi_valuetype valueType = napi_undefined;
136 napi_typeof(env, *napiArg, &valueType);
137 if (valueType == napi_function) {
138 WVLOG_D("CallH5Function function");
139 nwebValue = std::make_shared<NWebValue>();
140 } else {
141 WVLOG_D("CallH5Function object");
142 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
143 nwebValue = std::make_shared<NWebValue>(bin.c_str(), bin.size());
144 }
145 }
146 }
147
CallH5FunctionV2(napi_env env,napi_value * napiArg,std::shared_ptr<NWebRomValue> nwebValue,WebviewJavaScriptResultCallBack::H5Bundle bundle)148 void CallH5FunctionV2(napi_env env, napi_value* napiArg, std::shared_ptr<NWebRomValue> nwebValue,
149 WebviewJavaScriptResultCallBack::H5Bundle bundle)
150 {
151 WVLOG_D("CallH5Function called");
152 bool isObject = false;
153 std::vector<std::string> methodNameList;
154 methodNameList = ParseNapiValue2NwebValueV2(env, napiArg, nwebValue, &isObject);
155 if (isObject && FromNwebID(bundle.nwebId)) {
156 JavaScriptOb::ObjectID returnedObjectId;
157 if (FromNwebID(bundle.nwebId)->FindObjectIdInJsTd(env, *napiArg, &returnedObjectId)
158 && FromNwebID(bundle.nwebId)->FindObject(returnedObjectId)) {
159 FromNwebID(bundle.nwebId)->FindObject(returnedObjectId)->AddHolder(bundle.frameRoutingId);
160 } else {
161 returnedObjectId = FromNwebID(bundle.nwebId)->AddObject(env, *napiArg, false, bundle.frameRoutingId);
162 }
163
164 FromNwebID(bundle.nwebId)->SetUpAnnotateMethods(returnedObjectId, methodNameList);
165
166 napi_valuetype valueType = napi_undefined;
167 napi_typeof(env, *napiArg, &valueType);
168 if (valueType == napi_function) {
169 WVLOG_D("CallH5Function function");
170 } else {
171 WVLOG_D("CallH5Function object");
172 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
173 nwebValue->SetType(NWebRomValue::Type::BINARY);
174 nwebValue->SetBinary(bin.size(), bin.c_str());
175 }
176 }
177 }
178
CallbackFunctionForH5(napi_env env,napi_callback_info info)179 napi_value CallbackFunctionForH5(napi_env env, napi_callback_info info)
180 {
181 WVLOG_D("CallbackFunctionForH5 called");
182 napi_escapable_handle_scope scope = nullptr;
183 napi_open_escapable_handle_scope(env, &scope);
184 napi_value h5CallBackResult = nullptr;
185 napi_value thisVar = nullptr;
186 size_t argc = 0;
187 void* data = nullptr;
188 napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);
189 napi_value* napiArgs = nullptr;
190 if (argc > 0) {
191 WVLOG_D("CallbackFunctionForH5 argc not zero");
192 napiArgs = new napi_value[argc];
193 if (!napiArgs) {
194 WVLOG_D("CallbackFunctionForH5 argc malloc fail");
195 napi_get_undefined(env, &h5CallBackResult);
196 napi_close_escapable_handle_scope(env, scope);
197 return h5CallBackResult;
198 }
199 }
200
201 napi_get_cb_info(env, info, &argc, napiArgs, &thisVar, &data);
202 WebviewJavaScriptResultCallBack::H5Bundle bundle =
203 *reinterpret_cast<WebviewJavaScriptResultCallBack::H5Bundle*>(data);
204
205 std::vector<std::shared_ptr<NWebValue>> nwebArgs;
206 for (size_t i = 0; i < argc; i++) {
207 std::shared_ptr<NWebValue> nwebArg = std::make_shared<NWebValue>(NWebValue::Type::NONE);
208 napi_value napiArg = napiArgs[i];
209 napi_escape_handle(env, scope, napiArg, &napiArg);
210 CallH5Function(env, &napiArg, nwebArg, bundle);
211 nwebArgs.push_back(nwebArg);
212 }
213
214 std::vector<std::shared_ptr<NWebRomValue>> romArgs;
215 for (size_t i = 0; i < argc; i++) {
216 std::shared_ptr<NWebRomValue> romArg = std::make_shared<WebViewValue>(NWebRomValue::Type::NONE);
217 napi_value napiArg = napiArgs[i];
218 napi_escape_handle(env, scope, napiArg, &napiArg);
219 CallH5FunctionV2(env, &napiArg, romArg, bundle);
220 romArgs.push_back(romArg);
221 }
222
223 if (FromNwebID(bundle.nwebId)) {
224 FromNwebID(bundle.nwebId)->CallH5FunctionInternal(env, bundle, romArgs, nwebArgs);
225 }
226
227 if (napiArgs) {
228 delete[] napiArgs;
229 }
230
231 napi_get_undefined(env, &h5CallBackResult);
232 napi_close_escapable_handle_scope(env, scope);
233 return h5CallBackResult;
234 }
235
CreateFunctionForH5(napi_env env,int32_t nwebId,int32_t frameRoutingId,int32_t h5ObjectId,std::string funcName)236 napi_value CreateFunctionForH5(
237 napi_env env, int32_t nwebId, int32_t frameRoutingId, int32_t h5ObjectId, std::string funcName)
238 {
239 // Create a bundle.
240 auto bundle = std::make_unique<OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle>();
241 bundle->nwebId = nwebId;
242 bundle->frameRoutingId = frameRoutingId;
243 bundle->h5Id = h5ObjectId;
244 bundle->funcName = funcName;
245
246 napi_value func = nullptr;
247 napi_status s = napi_ok;
248 s = napi_create_function(env, funcName.c_str(), funcName.size(), CallbackFunctionForH5, bundle.release(), &func);
249 if (s != napi_ok) {
250 WVLOG_E("CreateFunctionForH5 napi api call fail");
251 return nullptr;
252 }
253 return func;
254 }
255
AddFunctionToObjectForH5(napi_env env,OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle & bundle,napi_value obj)256 void AddFunctionToObjectForH5(
257 napi_env env, OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle& bundle, napi_value obj)
258 {
259 if (!obj || bundle.frameRoutingId < 0) {
260 WVLOG_D("AddFunctionToObjectForH5 obj or frame id error");
261 return;
262 }
263 napi_value func = CreateFunctionForH5(env, bundle.nwebId, bundle.frameRoutingId, bundle.h5Id, bundle.funcName);
264 if (!func) {
265 WVLOG_D("AddFunctionToObjectForH5 create func fail");
266 return;
267 }
268 napi_status s = napi_ok;
269 s = napi_set_named_property(env, obj, bundle.funcName.c_str(), func);
270 if (s != napi_ok) {
271 WVLOG_E("AddFunctionToObjectForH5 napi api call fail");
272 }
273 }
274
CreateProxyForH5Object(napi_env env,napi_value * result)275 void CreateProxyForH5Object(napi_env env, napi_value* result)
276 {
277 napi_status s = napi_ok;
278 s = napi_create_object(env, result);
279 if (s != napi_ok) {
280 WVLOG_E("CreateProxyFOrH5Object napi api call fail");
281 }
282 }
283
OpenScope(napi_env env)284 napi_handle_scope OpenScope(napi_env env)
285 {
286 napi_handle_scope scope = nullptr;
287 NAPI_CALL(env, napi_open_handle_scope(env, &scope));
288 return scope;
289 }
290
CloseScope(napi_env env,napi_handle_scope scope)291 void CloseScope(napi_env env, napi_handle_scope scope)
292 {
293 (void)napi_close_handle_scope(env, scope);
294 }
295
CreateUvQueueWorkEnhanced(napi_env env,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * data,void (* handler)(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * data))296 void CreateUvQueueWorkEnhanced(napi_env env, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data,
297 void (*handler)(napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data))
298 {
299 uv_loop_s* loop = nullptr;
300 NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
301 class WorkData {
302 public:
303 WorkData() = delete;
304
305 WorkData(napi_env env, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data,
306 void (*handler)(
307 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data))
308 : env_(env), data_(data), handler_(handler)
309 {}
310
311 napi_env env_;
312 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data_;
313 void (*handler_)(napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data);
314 };
315
316 auto workData = new WorkData(env, data, handler);
317 auto work = new uv_work_t;
318 work->data = reinterpret_cast<void*>(workData);
319
320 auto callback = [](uv_work_t* work, int status) {
321 auto workData = static_cast<WorkData*>(work->data);
322 if (!workData) {
323 delete work;
324 return;
325 }
326
327 if (!workData->env_ || !workData->data_ || !workData->handler_) {
328 delete workData;
329 delete work;
330 return;
331 }
332
333 napi_env env = workData->env_;
334 auto closeScope = [env](napi_handle_scope scope) { CloseScope(env, scope); };
335 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(OpenScope(env), closeScope);
336
337 workData->handler_(workData->env_, static_cast<napi_status>(status), workData->data_);
338
339 delete workData;
340 delete work;
341 };
342 int ret = uv_queue_work_with_qos(
343 loop, work, [](uv_work_t* work) {}, callback, uv_qos_user_initiated);
344 if (ret != 0) {
345 if (workData) {
346 delete workData;
347 workData = nullptr;
348 }
349 if (work) {
350 delete work;
351 work = nullptr;
352 }
353 return;
354 }
355 }
356
CreateNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm * & inParam,WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm * & outParam,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * & param)357 bool CreateNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*& inParam,
358 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*& outParam,
359 WebviewJavaScriptResultCallBack::NapiJsCallBackParm*& param)
360 {
361 inParam = new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackInParm();
362 if (inParam == nullptr) {
363 WVLOG_D("CreateNapiJsCallBackParm argc malloc fail");
364 return false;
365 }
366 outParam = new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm();
367 if (outParam == nullptr) {
368 WVLOG_D("CreateNapiJsCallBackParm argc malloc fail");
369 delete inParam;
370 return false;
371 }
372 param = new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackParm();
373 if (param == nullptr) {
374 WVLOG_D("CreateNapiJsCallBackParm argc malloc fail");
375 delete inParam;
376 delete outParam;
377 return false;
378 }
379 return true;
380 }
381
DeleteNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm * inParam,WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm * outParam,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)382 void DeleteNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam,
383 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam,
384 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
385 {
386 if (inParam != nullptr) {
387 delete inParam;
388 inParam = nullptr;
389 }
390
391 if (outParam != nullptr) {
392 delete outParam;
393 outParam = nullptr;
394 }
395
396 if (param != nullptr) {
397 delete param;
398 param = nullptr;
399 }
400 }
401
402 napi_value ParseArrayNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
403 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId);
404 napi_value ParseDictionaryNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
405 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId);
406 napi_value ParseBinNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
407 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId);
408
409 void ParseDictionaryNapiValue2NwebValue(
410 napi_env env, ValueConvertState* state, napi_value& value, std::shared_ptr<NWebValue>& nwebValue, bool* isOject);
411
ParseBasicTypeNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,napi_value & napiValue)412 bool ParseBasicTypeNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value, napi_value& napiValue)
413 {
414 napi_status s = napi_ok;
415 switch (value->GetType()) {
416 case NWebValue::Type::INTEGER:
417 WVLOG_D("ParseBasicTypeNwebValue2NapiValue INTEGER type");
418 s = napi_create_int32(env, value->GetInt(), &napiValue);
419 if (s != napi_ok) {
420 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
421 }
422 break;
423 case NWebValue::Type::DOUBLE:
424 WVLOG_D("ParseBasicTypeNwebValue2NapiValue DOUBLE type");
425 s = napi_create_double(env, value->GetDouble(), &napiValue);
426 if (s != napi_ok) {
427 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
428 }
429 break;
430 case NWebValue::Type::BOOLEAN:
431 WVLOG_D("ParseBasicTypeNwebValue2NapiValue BOOLEAN type");
432 s = napi_get_boolean(env, value->GetBoolean(), &napiValue);
433 if (s != napi_ok) {
434 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
435 }
436 break;
437 case NWebValue::Type::STRING:
438 WVLOG_D("ParseBasicTypeNwebValue2NapiValue STRING type");
439 s = napi_create_string_utf8(env, value->GetString().c_str(), NAPI_AUTO_LENGTH, &napiValue);
440 if (s != napi_ok) {
441 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
442 }
443 break;
444 default:
445 return false;
446 }
447 return true;
448 }
449
ParseNwebValue2NapiValueHelper(napi_env env,std::shared_ptr<NWebValue> value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)450 napi_value ParseNwebValue2NapiValueHelper(napi_env env, std::shared_ptr<NWebValue> value,
451 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
452 {
453 napi_value napiValue = nullptr;
454 if (!value) {
455 napi_get_undefined(env, &napiValue);
456 return napiValue;
457 }
458 if (ParseBasicTypeNwebValue2NapiValue(env, value, napiValue)) {
459 return napiValue;
460 }
461 switch (value->GetType()) {
462 case NWebValue::Type::LIST: {
463 WVLOG_D("ParseBasicTypeNwebValue2NapiValue LIST type");
464 napiValue = ParseArrayNwebValue2NapiValue(env, value, objectsMap, nwebId, frameId);
465 return napiValue;
466 }
467 case NWebValue::Type::DICTIONARY: {
468 WVLOG_D("ParseBasicTypeNwebValue2NapiValue DICTIONARY type");
469 napiValue = ParseDictionaryNwebValue2NapiValue(env, value, objectsMap, nwebId, frameId);
470 return napiValue;
471 }
472 case NWebValue::Type::BINARY: {
473 WVLOG_D("ParseBasicTypeNwebValue2NapiValue BINARY type");
474 napiValue = ParseBinNwebValue2NapiValue(env, value, objectsMap, nwebId, frameId);
475 return napiValue;
476 }
477 case NWebValue::Type::NONE: {
478 WVLOG_D("ParseBasicTypeNwebValue2NapiValue NONE type");
479 break;
480 }
481 default:
482 WVLOG_E("ParseNwebValue2NapiValueHelper invalid type");
483 break;
484 }
485 napi_get_undefined(env, &napiValue);
486 return napiValue;
487 }
488
ParseArrayNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)489 napi_value ParseArrayNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
490 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
491 {
492 napi_value napiValue = nullptr;
493 napi_status s = napi_ok;
494 size_t length = value->GetListValueSize();
495 s = napi_create_array_with_length(env, length, &napiValue);
496 if (s != napi_ok) {
497 WVLOG_E("ParseArrayNwebValue2NapiValue napi api call fail");
498 return napiValue;
499 }
500 for (size_t i = 0; i < length; ++i) {
501 auto nPtr = std::make_shared<NWebValue>(value->GetListValue(i));
502 s = napi_set_element(env, napiValue, i, ParseNwebValue2NapiValueHelper(env, nPtr, objectsMap, nwebId, frameId));
503 if (s != napi_ok) {
504 WVLOG_E("ParseArrayNwebValue2NapiValue napi api call fail");
505 }
506 }
507 return napiValue;
508 }
509
ParseDictionaryNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)510 napi_value ParseDictionaryNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
511 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
512 {
513 napi_value napiValue = nullptr;
514 napi_status s = napi_ok;
515 s = napi_create_object(env, &napiValue);
516 auto dict = value->GetDictionaryValue();
517 for (auto& item : dict) {
518 auto nValuePtr = std::make_shared<NWebValue>(item.second);
519 auto nKeyPtr = std::make_shared<NWebValue>(item.first);
520 s = napi_set_property(env, napiValue, ParseNwebValue2NapiValueHelper(env, nKeyPtr, objectsMap, nwebId, frameId),
521 ParseNwebValue2NapiValueHelper(env, nValuePtr, objectsMap, nwebId, frameId));
522 if (s != napi_ok) {
523 WVLOG_E("ParseDictionaryNwebValue2NapiValue napi api call fail");
524 }
525 }
526 return napiValue;
527 }
528
ParseBinNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)529 napi_value ParseBinNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
530 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
531 {
532 napi_value napiValue = nullptr;
533 napi_get_undefined(env, &napiValue);
534 auto buff = value->GetBinaryValue();
535 JavaScriptOb::ObjectID objId;
536 std::string str(buff);
537 std::vector<std::string> strList;
538 StringSplit(str, ';', strList);
539 if (strList.size() < JS_BRIDGE_BINARY_ARGS_COUNT) {
540 napi_get_undefined(env, &napiValue);
541 return napiValue;
542 }
543 std::istringstream ss(strList[1]);
544 ss >> objId;
545 if (strList[0] == "TYPE_OBJECT_ID") {
546 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_OBJECT_ID");
547 auto iter = objectsMap.find(objId);
548 if (iter != objectsMap.end() && iter->second) {
549 WVLOG_I("ParseNwebValue2NapiValueHelper: type is "
550 "binary, object is found and object_id == %{public}d",
551 objId);
552 napiValue = iter->second->GetValue();
553 }
554 return napiValue;
555 } else if (strList[0] == "TYPE_H5_OBJECT_ID") {
556 CreateProxyForH5Object(env, &napiValue);
557 std::vector<std::string> methodNames;
558 methodNames.assign(strList.begin() + JS_BRIDGE_BINARY_ARGS_COUNT, strList.end()); // skip id and type
559 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_H5_OBJECT_ID");
560 for (auto name : methodNames) {
561 OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle bundle;
562 bundle.nwebId = nwebId;
563 bundle.frameRoutingId = frameId;
564 bundle.h5Id = objId;
565 bundle.funcName = name;
566 AddFunctionToObjectForH5(env, bundle, napiValue);
567 }
568 return napiValue;
569 } else if (strList[0] == "TYPE_H5_FUNCTION_ID") {
570 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_H5_FUNCTION_ID");
571 napiValue = CreateFunctionForH5(env, nwebId, frameId, objId, "");
572 return napiValue;
573 }
574 return napiValue;
575 }
576
ParseNwebValue2NapiValue(napi_env env,std::shared_ptr<NWebValue> value,WebviewJavaScriptResultCallBack::ObjectMap objectsMap,int32_t nwebId,int32_t frameId)577 napi_value ParseNwebValue2NapiValue(napi_env env, std::shared_ptr<NWebValue> value,
578 WebviewJavaScriptResultCallBack::ObjectMap objectsMap, int32_t nwebId, int32_t frameId)
579 {
580 return ParseNwebValue2NapiValueHelper(env, value, objectsMap, nwebId, frameId);
581 }
582
ParseBasicTypeNapiValue2NwebValue(napi_env env,napi_value & value,std::shared_ptr<NWebValue> & nwebValue,bool * isObject)583 bool ParseBasicTypeNapiValue2NwebValue(napi_env env, napi_value& value,
584 std::shared_ptr<NWebValue>& nwebValue, bool* isObject)
585 {
586 napi_valuetype valueType = napi_undefined;
587 napi_typeof(env, value, &valueType);
588 napi_status s = napi_ok;
589 switch (valueType) {
590 case napi_undefined: // fallthrough
591 case napi_null:
592 WVLOG_D("ParseBasicTypeNapiValue2NwebValue null or undefined type");
593 nwebValue->SetType(NWebValue::Type::NONE);
594 break;
595 case napi_number: {
596 WVLOG_D("ParseBasicTypeNapiValue2NwebValue number type");
597 double douVal = 0.0;
598 s = napi_get_value_double(env, value, &douVal);
599 nwebValue->SetType(NWebValue::Type::DOUBLE);
600 nwebValue->SetDouble(douVal);
601 break;
602 }
603 case napi_boolean: {
604 WVLOG_D("ParseBasicTypeNapiValue2NwebValue boolean type");
605 bool boolVal;
606 s = napi_get_value_bool(env, value, &boolVal);
607 nwebValue->SetType(NWebValue::Type::BOOLEAN);
608 nwebValue->SetBoolean(boolVal);
609 break;
610 }
611 case napi_symbol: // fallthrough
612 case napi_string: {
613 WVLOG_D("ParseBasicTypeNapiValue2NwebValue string type");
614 std::string strVal;
615 if (!NapiParseUtils::ParseString(env, value, strVal)) {
616 WVLOG_E("ParseBasicTypeNapiValue2NwebValue NapiParseUtils::ParseString "
617 "failed");
618 }
619 if (strVal == "methodNameListForJsProxy") {
620 *isObject = true;
621 }
622 nwebValue->SetType(NWebValue::Type::STRING);
623 nwebValue->SetString(strVal);
624 break;
625 }
626 default: {
627 WVLOG_D("ParseBasicTypeNapiValue2NwebValue invalid type");
628 return false;
629 }
630 }
631 return true;
632 }
633
ParseNapiValue2NwebValueHelper(napi_env env,ValueConvertState * state,napi_value & value,std::shared_ptr<NWebValue> nwebValue,bool * isOject)634 void ParseNapiValue2NwebValueHelper(
635 napi_env env, ValueConvertState* state, napi_value& value,
636 std::shared_ptr<NWebValue> nwebValue, bool* isOject)
637 {
638 ValueConvertState::Level stateLevel(state);
639 if (state->HasReachedMaxRecursionDepth()) {
640 return;
641 }
642 if (!nwebValue || ParseBasicTypeNapiValue2NwebValue(env, value, nwebValue, isOject)) {
643 return;
644 }
645 napi_valuetype valueType = napi_undefined;
646 napi_typeof(env, value, &valueType);
647 napi_status s = napi_ok;
648 switch (valueType) {
649 case napi_object: {
650 bool isArray;
651 s = napi_is_array(env, value, &isArray);
652 if (s != napi_ok) {
653 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
654 }
655 if (!isArray) {
656 WVLOG_D("ParseNapiValue2NwebValueHelper napi isArray");
657 ParseDictionaryNapiValue2NwebValue(env, state, value, nwebValue, isOject);
658 break;
659 }
660 nwebValue->SetType(NWebValue::Type::LIST);
661 uint32_t size;
662 s = napi_get_array_length(env, value, &size);
663 size = std::min(size, MAX_DATA_LENGTH);
664 if (s != napi_ok) {
665 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
666 }
667 for (uint32_t i = 0; i < size; i++) {
668 napi_value napiTmp;
669 s = napi_get_element(env, value, i, &napiTmp);
670 if (s != napi_ok) {
671 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
672 }
673 auto nwebTmp = std::make_shared<NWebValue>();
674 ParseNapiValue2NwebValueHelper(env, state, napiTmp, nwebTmp, isOject);
675 nwebValue->AddListValue(*nwebTmp);
676 }
677 break;
678 }
679 default: {
680 WVLOG_E("ParseNapiValue2NwebValueHelper invalid type");
681 }
682 }
683 }
684
ParseDictionaryNapiValue2NwebValue(napi_env env,ValueConvertState * state,napi_value & value,std::shared_ptr<NWebValue> & nwebValue,bool * isOject)685 void ParseDictionaryNapiValue2NwebValue(
686 napi_env env, ValueConvertState* state, napi_value& value, std::shared_ptr<NWebValue>& nwebValue, bool* isOject)
687 {
688 napi_status s = napi_ok;
689 nwebValue->SetType(NWebValue::Type::DICTIONARY);
690 napi_value propertyNames;
691 s = napi_get_property_names(env, value, &propertyNames);
692 if (s != napi_ok) {
693 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
694 }
695 uint32_t size;
696 s = napi_get_array_length(env, propertyNames, &size);
697 size = std::min(size, MAX_DATA_LENGTH);
698 if (s != napi_ok) {
699 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
700 }
701
702 for (uint32_t i = 0; i < size; i++) {
703 napi_value napiKeyTmp;
704 s = napi_get_element(env, propertyNames, i, &napiKeyTmp);
705 if (s != napi_ok) {
706 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
707 }
708 bool hasOwnProperty = false;
709 s = napi_has_own_property(env, value, napiKeyTmp, &hasOwnProperty);
710 if (s != napi_ok) {
711 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
712 }
713 if (!hasOwnProperty) {
714 continue;
715 }
716 napi_value napiValueTmp;
717 s = napi_get_property(env, value, napiKeyTmp, &napiValueTmp);
718 if (s != napi_ok) {
719 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
720 }
721 auto nwebValueTmp = std::make_shared<NWebValue>();
722 auto nwebKeyTmp = std::make_shared<NWebValue>();
723 ParseNapiValue2NwebValueHelper(env, state, napiKeyTmp, nwebKeyTmp, isOject);
724 ParseNapiValue2NwebValueHelper(env, state, napiValueTmp, nwebValueTmp, isOject);
725 nwebValue->AddDictionaryValue(nwebKeyTmp->GetString(), *nwebValueTmp);
726 }
727 }
728
HasAnnotationProperty(napi_env env,napi_value & value)729 bool HasAnnotationProperty(napi_env env, napi_value& value)
730 {
731 std::string annotation = "methodNameListForJsProxy";
732 napi_status s = napi_ok;
733 bool hasProperty = false;
734 napi_value napi_str;
735 s = napi_create_string_utf8(env, annotation.c_str(), NAPI_AUTO_LENGTH,
736 &napi_str);
737 if (s != napi_ok) {
738 WVLOG_E("HasAnnotationProperty napi api call fail");
739 }
740 s = napi_has_own_property(env, value, napi_str, &hasProperty);
741 if (s != napi_ok) {
742 WVLOG_D("HasAnnotationProperty napi api call fail");
743 }
744 WVLOG_D(
745 "HasAnnotationProperty hasProperty = "
746 "%{public}d",
747 hasProperty);
748 return hasProperty;
749 }
750
IsCallableObject(napi_env env,napi_value & value,std::vector<std::string> * methodNameList)751 bool IsCallableObject(napi_env env,
752 napi_value& value,
753 std::vector<std::string>* methodNameList)
754 {
755 std::string annotation = "methodNameListForJsProxy";
756 napi_status s = napi_ok;
757 napi_value napi_str;
758 s = napi_create_string_utf8(env, annotation.c_str(), NAPI_AUTO_LENGTH,
759 &napi_str);
760 if (s != napi_ok) {
761 WVLOG_E("IsCallableObject napi api call fail");
762 }
763 if (!HasAnnotationProperty(env, value)) {
764 return false;
765 }
766 napi_value result;
767 s = napi_get_property(env, value, napi_str, &result);
768 if (s != napi_ok) {
769 WVLOG_E("IsCallableObject napi api call fail");
770 }
771 bool isArray = false;
772 s = napi_is_array(env, result, &isArray);
773 if (s != napi_ok) {
774 WVLOG_E("IsCallableObject napi api call fail");
775 }
776 if (!isArray) {
777 return false;
778 }
779 uint32_t size;
780 s = napi_get_array_length(env, result, &size);
781 if (s != napi_ok) {
782 WVLOG_E("IsCallableObject napi api call fail");
783 }
784 for (uint32_t i = 0; i < size; i++) {
785 napi_value napiTmp;
786 s = napi_get_element(env, result, i, &napiTmp);
787 if (s != napi_ok) {
788 WVLOG_E("IsCallableObject napi api call fail");
789 }
790 napi_valuetype valueType = napi_undefined;
791 napi_typeof(env, napiTmp, &valueType);
792 if (valueType != napi_string) {
793 continue;
794 }
795 std::string strVal;
796 if (!NapiParseUtils::ParseString(env, napiTmp, strVal)) {
797 WVLOG_E("IsCallableObject NapiParseUtils::ParseString failed");
798 }
799 methodNameList->push_back(strVal);
800 }
801 return true;
802 }
803
ParseNapiValue2NwebValue(napi_env env,napi_value & value,std::shared_ptr<NWebValue> nwebValue,bool * isObject)804 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value& value,
805 std::shared_ptr<NWebValue> nwebValue, bool* isObject)
806 {
807 napi_status s = napi_ok;
808 std::vector<std::string> methodNameList;
809
810 s = napi_is_promise(env, value, isObject);
811 if (s != napi_ok) {
812 WVLOG_E("ParseNapiValue2NwebValue napi api call fail");
813 }
814
815 if (*isObject) {
816 return std::vector<std::string>{"then", "catch", "finally"};
817 }
818
819 if (IsCallableObject(env, value, &methodNameList)) {
820 *isObject = true;
821 return methodNameList;
822 }
823
824 ValueConvertState state;
825 bool isObjectForRecursion = false; // FixMe: for Recursion case, now not use
826 ParseNapiValue2NwebValueHelper(env, &state, value, nwebValue, &isObjectForRecursion);
827 return methodNameList;
828 }
829
ParseNapiValue2NwebValue(napi_env env,napi_value * value,std::shared_ptr<NWebValue> nwebValue,bool * isObject)830 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value* value,
831 std::shared_ptr<NWebValue> nwebValue, bool* isObject)
832 {
833 napi_status s = napi_ok;
834 std::vector<std::string> methodNameList;
835
836 s = napi_is_promise(env, *value, isObject);
837 if (s != napi_ok) {
838 WVLOG_E("ParseNapiValue2NwebValue napi api call fail");
839 }
840
841 if (*isObject) {
842 return std::vector<std::string>{"then", "catch", "finally"};
843 }
844
845 if (IsCallableObject(env, *value, &methodNameList)) {
846 *isObject = true;
847 return methodNameList;
848 }
849
850 ValueConvertState state;
851 bool isObjectForRecursion = false; // FixMe: for Recursion case, now not use
852 ParseNapiValue2NwebValueHelper(env, &state, *value, nwebValue, &isObjectForRecursion);
853 return methodNameList;
854 }
855
856 template<typename T>
ParseBasicTypeNwebValue2NapiValueV2(napi_env env,const std::shared_ptr<T> & value,napi_value & napiValue)857 bool ParseBasicTypeNwebValue2NapiValueV2(napi_env env, const std::shared_ptr<T>& value, napi_value& napiValue)
858 {
859 auto type = value->GetType();
860 WVLOG_D("ParseBasicTypeNwebValue2NapiValue type is %{public}hhu", type);
861
862 napi_status s = napi_ok;
863 switch (type) {
864 case T::Type::INTEGER:
865 s = napi_create_int32(env, value->GetInt(), &napiValue);
866 break;
867 case T::Type::DOUBLE:
868 s = napi_create_double(env, value->GetDouble(), &napiValue);
869 break;
870 case T::Type::BOOLEAN:
871 s = napi_get_boolean(env, value->GetBool(), &napiValue);
872 break;
873 case T::Type::STRING:
874 s = napi_create_string_utf8(env, value->GetString().c_str(), NAPI_AUTO_LENGTH, &napiValue);
875 break;
876 default:
877 return false;
878 }
879
880 if (s != napi_ok) {
881 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail,type is %{public}hhu", type);
882 }
883 return true;
884 }
885
886 template<typename T>
ParseBinNwebValue2NapiValueV2(napi_env env,const std::shared_ptr<T> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)887 napi_value ParseBinNwebValue2NapiValueV2(napi_env env, const std::shared_ptr<T>& value,
888 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
889 {
890 napi_value napiValue = nullptr;
891 napi_get_undefined(env, &napiValue);
892 int length = 0;
893 auto buff = value->GetBinary(length);
894 JavaScriptOb::ObjectID objId;
895 std::string str(buff);
896 std::vector<std::string> strList;
897 StringSplit(str, ';', strList);
898 if (strList.size() < JS_BRIDGE_BINARY_ARGS_COUNT) {
899 napi_get_undefined(env, &napiValue);
900 return napiValue;
901 }
902
903 std::istringstream ss(strList[1]);
904 ss >> objId;
905 if (strList[0] == "TYPE_OBJECT_ID") {
906 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_OBJECT_ID");
907 auto iter = objectsMap.find(objId);
908 if (iter != objectsMap.end() && iter->second) {
909 WVLOG_I("ParseNwebValue2NapiValueHelper: type is "
910 "binary, object is found and object_id == %{public}d",
911 objId);
912 napiValue = iter->second->GetValue();
913 }
914 return napiValue;
915 } else if (strList[0] == "TYPE_H5_OBJECT_ID") {
916 CreateProxyForH5Object(env, &napiValue);
917 std::vector<std::string> methodNames;
918 methodNames.assign(strList.begin() + JS_BRIDGE_BINARY_ARGS_COUNT, strList.end()); // skip id and type
919 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_H5_OBJECT_ID");
920 for (auto name : methodNames) {
921 OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle bundle;
922 bundle.nwebId = nwebId;
923 bundle.frameRoutingId = frameId;
924 bundle.h5Id = objId;
925 bundle.funcName = name;
926 AddFunctionToObjectForH5(env, bundle, napiValue);
927 }
928 return napiValue;
929 } else if (strList[0] == "TYPE_H5_FUNCTION_ID") {
930 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_H5_FUNCTION_ID");
931 napiValue = CreateFunctionForH5(env, nwebId, frameId, objId, "");
932 return napiValue;
933 }
934 return napiValue;
935 }
936
937 template<typename T>
ParseArrayNwebValue2NapiValueV2(napi_env env,const std::shared_ptr<T> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)938 napi_value ParseArrayNwebValue2NapiValueV2(napi_env env, const std::shared_ptr<T>& value,
939 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
940 {
941 napi_value napiValue = nullptr;
942 auto list = value->GetListValue();
943 napi_status s = napi_create_array_with_length(env, list.size(), &napiValue);
944 if (s != napi_ok) {
945 WVLOG_E("ParseArrayNwebValue2NapiValue napi api call fail");
946 return napiValue;
947 }
948
949 int i = 0;
950 for (auto& item : list) {
951 s = napi_set_element(env, napiValue, i++, ParseNwebValue2NapiValueV2(env, item, objectsMap, nwebId, frameId));
952 if (s != napi_ok) {
953 WVLOG_E("ParseArrayNwebValue2NapiValue napi api call fail");
954 }
955 }
956 return napiValue;
957 }
958
959 template<typename T>
ParseDictionaryNwebValue2NapiValueV2(napi_env env,const std::shared_ptr<T> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)960 napi_value ParseDictionaryNwebValue2NapiValueV2(napi_env env, const std::shared_ptr<T>& value,
961 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
962 {
963 napi_value napiValue = nullptr;
964 napi_status s = napi_create_object(env, &napiValue);
965
966 auto dict = value->GetDictValue();
967 for (auto& item : dict) {
968 napi_value napiKey = nullptr;
969 s = napi_create_string_utf8(env, item.first.c_str(), NAPI_AUTO_LENGTH, &napiKey);
970 if (s != napi_ok) {
971 WVLOG_E("GetJavaScriptResultFlowbuf napi api call fail");
972 }
973
974 s = napi_set_property(
975 env, napiValue, napiKey, ParseNwebValue2NapiValueV2(env, item.second, objectsMap, nwebId, frameId));
976 if (s != napi_ok) {
977 WVLOG_E("ParseDictionaryNwebValue2NapiValueV2 napi api call fail");
978 }
979 }
980 return napiValue;
981 }
982
983 template<typename T>
ParseNwebValue2NapiValueV2(napi_env env,std::shared_ptr<T> value,WebviewJavaScriptResultCallBack::ObjectMap objectsMap,int32_t nwebId,int32_t frameId)984 napi_value ParseNwebValue2NapiValueV2(napi_env env, std::shared_ptr<T> value,
985 WebviewJavaScriptResultCallBack::ObjectMap objectsMap, int32_t nwebId, int32_t frameId)
986 {
987 napi_value napiValue = nullptr;
988 if (!value) {
989 napi_get_undefined(env, &napiValue);
990 return napiValue;
991 }
992 if (ParseBasicTypeNwebValue2NapiValueV2(env, value, napiValue)) {
993 return napiValue;
994 }
995 switch (value->GetType()) {
996 case T::Type::LIST: {
997 WVLOG_D("ParseBasicTypeNwebValue2NapiValue LIST type");
998 napiValue = ParseArrayNwebValue2NapiValueV2(env, value, objectsMap, nwebId, frameId);
999 return napiValue;
1000 }
1001 case T::Type::DICTIONARY: {
1002 WVLOG_D("ParseBasicTypeNwebValue2NapiValue DICTIONARY type");
1003 napiValue = ParseDictionaryNwebValue2NapiValueV2(env, value, objectsMap, nwebId, frameId);
1004 return napiValue;
1005 }
1006 case T::Type::BINARY: {
1007 WVLOG_D("ParseBasicTypeNwebValue2NapiValue BINARY type");
1008 napiValue = ParseBinNwebValue2NapiValueV2(env, value, objectsMap, nwebId, frameId);
1009 return napiValue;
1010 }
1011 case T::Type::NONE: {
1012 WVLOG_D("ParseBasicTypeNwebValue2NapiValue NONE type");
1013 break;
1014 }
1015 default:
1016 WVLOG_E("ParseNwebValue2NapiValueHelper invalid type");
1017 break;
1018 }
1019 napi_get_undefined(env, &napiValue);
1020 return napiValue;
1021 }
1022
1023 template<typename T>
ParseBasicTypeNapiValue2NwebValueV2(napi_env env,napi_value & value,std::shared_ptr<T> & nwebValue,bool * isObject)1024 bool ParseBasicTypeNapiValue2NwebValueV2(napi_env env, napi_value& value, std::shared_ptr<T>& nwebValue, bool* isObject)
1025 {
1026 napi_valuetype valueType = napi_undefined;
1027 napi_typeof(env, value, &valueType);
1028
1029 napi_status s = napi_ok;
1030 switch (valueType) {
1031 case napi_undefined: // fallthrough
1032 case napi_null:
1033 WVLOG_D("ParseBasicTypeNapiValue2NwebValue null or undefined type");
1034 nwebValue->SetType(T::Type::NONE);
1035 break;
1036 case napi_number: {
1037 WVLOG_D("ParseBasicTypeNapiValue2NwebValue number type");
1038 double douVal = 0.0;
1039 s = napi_get_value_double(env, value, &douVal);
1040 nwebValue->SetType(T::Type::DOUBLE);
1041 nwebValue->SetDouble(douVal);
1042 break;
1043 }
1044 case napi_boolean: {
1045 WVLOG_D("ParseBasicTypeNapiValue2NwebValue boolean type");
1046 bool boolVal;
1047 s = napi_get_value_bool(env, value, &boolVal);
1048 nwebValue->SetType(T::Type::BOOLEAN);
1049 nwebValue->SetBool(boolVal);
1050 break;
1051 }
1052 case napi_symbol: // fallthrough
1053 case napi_string: {
1054 WVLOG_D("ParseBasicTypeNapiValue2NwebValue string type");
1055 std::string strVal;
1056 if (!NapiParseUtils::ParseString(env, value, strVal)) {
1057 WVLOG_E("ParseBasicTypeNapiValue2NwebValue NapiParseUtils::ParseString "
1058 "failed");
1059 }
1060 if (strVal == "methodNameListForJsProxy") {
1061 *isObject = true;
1062 }
1063 nwebValue->SetType(T::Type::STRING);
1064 nwebValue->SetString(strVal);
1065 break;
1066 }
1067 default: {
1068 WVLOG_D("ParseBasicTypeNapiValue2NwebValue invalid type");
1069 return false;
1070 }
1071 }
1072 return true;
1073 }
1074
1075 template<typename T>
ParseNapiValue2NwebValueHelperV2(napi_env env,ValueConvertState * state,napi_value & value,std::shared_ptr<T> nwebValue,bool * isOject)1076 void ParseNapiValue2NwebValueHelperV2(
1077 napi_env env, ValueConvertState* state, napi_value& value, std::shared_ptr<T> nwebValue, bool* isOject)
1078 {
1079 ValueConvertState::Level stateLevel(state);
1080 if (state->HasReachedMaxRecursionDepth()) {
1081 return;
1082 }
1083 if (!nwebValue || ParseBasicTypeNapiValue2NwebValueV2(env, value, nwebValue, isOject)) {
1084 return;
1085 }
1086 napi_valuetype valueType = napi_undefined;
1087 napi_typeof(env, value, &valueType);
1088 napi_status s = napi_ok;
1089 switch (valueType) {
1090 case napi_object: {
1091 bool isArray;
1092 s = napi_is_array(env, value, &isArray);
1093 if (s != napi_ok) {
1094 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
1095 }
1096 if (!isArray) {
1097 WVLOG_D("ParseNapiValue2NwebValueHelper napi isArray");
1098 ParseDictionaryNapiValue2NwebValueV2(env, state, value, nwebValue, isOject);
1099 break;
1100 }
1101 nwebValue->SetType(T::Type::LIST);
1102 uint32_t size;
1103 s = napi_get_array_length(env, value, &size);
1104 size = std::min(size, MAX_DATA_LENGTH);
1105 if (s != napi_ok) {
1106 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
1107 }
1108 for (uint32_t i = 0; i < size; i++) {
1109 napi_value napiTmp;
1110 s = napi_get_element(env, value, i, &napiTmp);
1111 if (s != napi_ok) {
1112 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
1113 }
1114
1115 auto child = nwebValue->NewChildValue();
1116 ParseNapiValue2NwebValueHelperV2(env, state, napiTmp, child, isOject);
1117 nwebValue->SaveListChildValue();
1118 }
1119 break;
1120 }
1121 default: {
1122 WVLOG_E("ParseNapiValue2NwebValueHelper invalid type");
1123 }
1124 }
1125 }
1126
1127 template<typename T>
ParseDictionaryNapiValue2NwebValueV2(napi_env env,ValueConvertState * state,napi_value & value,std::shared_ptr<T> & nwebValue,bool * isOject)1128 void ParseDictionaryNapiValue2NwebValueV2(
1129 napi_env env, ValueConvertState* state, napi_value& value, std::shared_ptr<T>& nwebValue, bool* isOject)
1130 {
1131 nwebValue->SetType(T::Type::DICTIONARY);
1132
1133 napi_value propertyNames;
1134 napi_status s = napi_get_property_names(env, value, &propertyNames);
1135 if (s != napi_ok) {
1136 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
1137 }
1138
1139 uint32_t size;
1140 s = napi_get_array_length(env, propertyNames, &size);
1141 size = std::min(size, MAX_DATA_LENGTH);
1142 if (s != napi_ok) {
1143 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
1144 }
1145
1146 for (uint32_t i = 0; i < size; i++) {
1147 napi_value napiKeyTmp;
1148 s = napi_get_element(env, propertyNames, i, &napiKeyTmp);
1149 if (s != napi_ok) {
1150 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
1151 }
1152
1153 bool hasOwnProperty = false;
1154 s = napi_has_own_property(env, value, napiKeyTmp, &hasOwnProperty);
1155 if (s != napi_ok) {
1156 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
1157 }
1158
1159 if (!hasOwnProperty) {
1160 continue;
1161 }
1162
1163 napi_value napiValueTmp;
1164 s = napi_get_property(env, value, napiKeyTmp, &napiValueTmp);
1165 if (s != napi_ok) {
1166 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
1167 }
1168
1169 auto nwebKeyTmp = std::make_shared<NWebValue>();
1170 ParseNapiValue2NwebValueHelper(env, state, napiKeyTmp, nwebKeyTmp, isOject);
1171 auto nwebValueTmp = nwebValue->NewChildValue();
1172 ParseNapiValue2NwebValueHelperV2(env, state, napiValueTmp, nwebValueTmp, isOject);
1173 nwebValue->SaveDictChildValue(nwebKeyTmp->GetString());
1174 }
1175 }
1176
1177 template<typename T>
ParseNapiValue2NwebValueV2(napi_env env,napi_value * value,std::shared_ptr<T> nwebValue,bool * isObject)1178 std::vector<std::string> ParseNapiValue2NwebValueV2(
1179 napi_env env, napi_value* value, std::shared_ptr<T> nwebValue, bool* isObject)
1180 {
1181 std::vector<std::string> methodNameList;
1182 napi_status s = napi_is_promise(env, *value, isObject);
1183 if (s != napi_ok) {
1184 WVLOG_E("ParseNapiValue2NwebValue napi api call fail");
1185 }
1186
1187 if (*isObject) {
1188 return std::vector<std::string> { "then", "catch", "finally" };
1189 }
1190
1191 if (IsCallableObject(env, *value, &methodNameList)) {
1192 *isObject = true;
1193 return methodNameList;
1194 }
1195
1196 ValueConvertState state;
1197 bool isObjectForRecursion = false; // FixMe: for Recursion case, now not use
1198 ParseNapiValue2NwebValueHelperV2(env, &state, *value, nwebValue, &isObjectForRecursion);
1199 return methodNameList;
1200 }
1201 } // namespace
1202
CreateNamed(napi_env env,int32_t containerScopeId,napi_value value,size_t refCount)1203 std::shared_ptr<JavaScriptOb> JavaScriptOb::CreateNamed(
1204 napi_env env, int32_t containerScopeId, napi_value value, size_t refCount)
1205 {
1206 return std::make_shared<JavaScriptOb>(env, containerScopeId, value, refCount);
1207 }
CreateTransient(napi_env env,int32_t containerScopeId,napi_value value,int32_t holder,size_t refCount)1208 std::shared_ptr<JavaScriptOb> JavaScriptOb::CreateTransient(
1209 napi_env env, int32_t containerScopeId, napi_value value, int32_t holder, size_t refCount)
1210 {
1211 std::set<int32_t> holders;
1212 holders.insert(holder);
1213 return std::make_shared<JavaScriptOb>(env, containerScopeId, value, holders, refCount);
1214 }
1215
JavaScriptOb(napi_env env,int32_t containerScopeId,napi_value value,size_t refCount)1216 JavaScriptOb::JavaScriptOb(napi_env env, int32_t containerScopeId, napi_value value, size_t refCount)
1217 : env_(env), containerScopeId_(containerScopeId), isStrongRef_(refCount != 0), namesCount_(1)
1218 {
1219 napi_status s = napi_create_reference(env, value, refCount, &objRef_);
1220 if (s != napi_ok) {
1221 WVLOG_E("create javascript obj fail");
1222 }
1223 }
1224
JavaScriptOb(napi_env env,int32_t containerScopeId,napi_value value,std::set<int32_t> holders,size_t refCount)1225 JavaScriptOb::JavaScriptOb(
1226 napi_env env, int32_t containerScopeId, napi_value value, std::set<int32_t> holders, size_t refCount)
1227 : env_(env), containerScopeId_(containerScopeId), isStrongRef_(refCount != 0), namesCount_(0), holders_(holders)
1228 {
1229 std::unique_lock<std::mutex> lock(mutex_);
1230 napi_status s = napi_create_reference(env, value, refCount, &objRef_);
1231 if (s != napi_ok) {
1232 WVLOG_E("create javascript obj fail");
1233 }
1234 }
1235
WebviewJavaScriptResultCallBack(int32_t nwebId)1236 WebviewJavaScriptResultCallBack::WebviewJavaScriptResultCallBack(int32_t nwebId)
1237 : nwebId_(nwebId)
1238 {
1239 std::unique_lock<std::mutex> lk(g_objectMtx);
1240 g_webviewJsResultCallbackMap.emplace(nwebId, this);
1241 }
1242
~WebviewJavaScriptResultCallBack()1243 WebviewJavaScriptResultCallBack::~WebviewJavaScriptResultCallBack()
1244 {
1245 std::unique_lock<std::mutex> lk(g_objectMtx);
1246 g_webviewJsResultCallbackMap.erase(nwebId_);
1247 }
1248
FindObject(JavaScriptOb::ObjectID objectId)1249 std::shared_ptr<JavaScriptOb> WebviewJavaScriptResultCallBack::FindObject(JavaScriptOb::ObjectID objectId)
1250 {
1251 auto iter = objects_.find(objectId);
1252 if (iter != objects_.end()) {
1253 return iter->second;
1254 }
1255 WVLOG_E("WebviewJavaScriptResultCallBack::FindObject Unknown object: objectId = "
1256 "%{public}d",
1257 objectId);
1258 return nullptr;
1259 }
1260
ProcessObjectCaseInJsTd(napi_env env,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param,napi_value callResult,std::vector<std::string> & methodNameList)1261 void ProcessObjectCaseInJsTd(
1262 napi_env env, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param,
1263 napi_value callResult, std::vector<std::string>& methodNameList)
1264 {
1265 if (!param) {
1266 WVLOG_E("WebviewJavaScriptResultCallBack::ProcessObjectCaseInJsTd param null");
1267 return;
1268 }
1269
1270 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1271 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
1272 JavaScriptOb::ObjectID returnedObjectId;
1273
1274 if (inParam->webJsResCb->FindObjectIdInJsTd(env, callResult, &returnedObjectId)
1275 && inParam->webJsResCb->FindObject(returnedObjectId)) {
1276 inParam->webJsResCb->FindObject(returnedObjectId)->AddHolder(inParam->frameRoutingId);
1277 } else {
1278 returnedObjectId = inParam->webJsResCb->AddObject(env, callResult, false, inParam->frameRoutingId);
1279 }
1280
1281 inParam->webJsResCb->SetUpAnnotateMethods(returnedObjectId, methodNameList);
1282
1283 napi_valuetype valueType = napi_undefined;
1284 napi_typeof(env, callResult, &valueType);
1285 if (valueType == napi_function) {
1286 WVLOG_D("WebviewJavaScriptResultCallBack::ProcessObjectCaseInJsTd type is function");
1287 *(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)) = std::make_shared<NWebValue>();
1288 } else {
1289 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
1290 *(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)) =
1291 std::make_shared<NWebValue>(bin.c_str(), bin.size());
1292 }
1293 }
1294
ExecuteGetJavaScriptResult(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)1295 void ExecuteGetJavaScriptResult(
1296 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
1297 {
1298 WVLOG_D("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult called");
1299 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1300 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
1301 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
1302 if (!jsObj) {
1303 std::unique_lock<std::mutex> lock(param->mutex);
1304 param->ready = true;
1305 param->condition.notify_all();
1306 return;
1307 }
1308 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1309 NApiScope scope(env);
1310 if (!scope.IsVaild()) {
1311 std::unique_lock<std::mutex> lock(param->mutex);
1312 param->ready = true;
1313 param->condition.notify_all();
1314 return;
1315 }
1316 if (jsObj && (jsObj->HasMethod(inParam->methodName))) {
1317 std::vector<napi_value> argv = {};
1318 auto nwebArgs = *(static_cast<std::vector<std::shared_ptr<NWebValue>>*>(inParam->data));
1319 for (std::shared_ptr<NWebValue> input : nwebArgs) {
1320 argv.push_back(ParseNwebValue2NapiValue(
1321 env, input, inParam->webJsResCb->GetObjectMap(), inParam->nwebId, inParam->frameRoutingId));
1322 }
1323 napi_value callback = jsObj->FindMethod(inParam->methodName);
1324 if (!callback) {
1325 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
1326 }
1327 napi_value callResult = nullptr;
1328 napi_call_function(env, jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
1329 bool isObject = false;
1330 std::vector<std::string> methodNameList;
1331 methodNameList = ParseNapiValue2NwebValue(
1332 env, callResult, *(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)), &isObject);
1333 if (isObject) {
1334 ProcessObjectCaseInJsTd(env, param, callResult, methodNameList);
1335 }
1336 }
1337
1338 std::unique_lock<std::mutex> lock(param->mutex);
1339 param->ready = true;
1340 param->condition.notify_all();
1341 }
1342
GetJavaScriptResultSelf(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int32_t routingId,int32_t objectId)1343 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf(
1344 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName,
1345 int32_t routingId, int32_t objectId)
1346 {
1347 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1348 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1349 if (!jsObj) {
1350 return ret;
1351 }
1352 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1353 NApiScope scope(jsObj->GetEnv());
1354 if (!scope.IsVaild()) {
1355 return ret;
1356 }
1357
1358 WVLOG_D("get javaScript result already in js thread");
1359 std::vector<napi_value> argv = {};
1360 for (std::shared_ptr<NWebValue> input : args) {
1361 argv.push_back(ParseNwebValue2NapiValue(jsObj->GetEnv(), input, GetObjectMap(), GetNWebId(), routingId));
1362 }
1363 napi_value callback = jsObj->FindMethod(method);
1364 if (!callback) {
1365 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
1366 }
1367 napi_value callResult = nullptr;
1368 napi_call_function(jsObj->GetEnv(), jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
1369 bool isObject = false;
1370 std::vector<std::string> methodNameList;
1371 methodNameList = ParseNapiValue2NwebValue(jsObj->GetEnv(), &callResult, ret, &isObject);
1372 napi_valuetype valueType = napi_undefined;
1373 napi_typeof(jsObj->GetEnv(), callResult, &valueType);
1374 WVLOG_D("get javaScript result already in js thread end");
1375 if (isObject) {
1376 JavaScriptOb::ObjectID returnedObjectId;
1377 if (FindObjectIdInJsTd(jsObj->GetEnv(), callResult, &returnedObjectId)) {
1378 std::shared_ptr<JavaScriptOb> obj = FindObject(returnedObjectId);
1379 if (obj) {
1380 obj->AddHolder(routingId);
1381 }
1382 } else {
1383 returnedObjectId = AddObject(jsObj->GetEnv(), callResult, false, routingId);
1384 }
1385 SetUpAnnotateMethods(returnedObjectId, methodNameList);
1386 if (valueType == napi_function) {
1387 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is function");
1388 ret = std::make_shared<NWebValue>();
1389 } else {
1390 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is object");
1391 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
1392 ret = std::make_shared<NWebValue>(bin.c_str(), bin.size());
1393 }
1394 }
1395 return ret;
1396 }
1397
GetJavaScriptResult(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int32_t routingId,int32_t objectId)1398 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResult(
1399 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName,
1400 int32_t routingId, int32_t objectId)
1401 {
1402 (void)objName; // to be compatible with older webcotroller, classname may be empty
1403 WVLOG_D(
1404 "GetJavaScriptResult objName = %{public}s, method = %{public}s, "
1405 "routingId = %{public}d, objectId = %{public}d",
1406 objName.c_str(), method.c_str(), routingId, objectId);
1407 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1408 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1409 if (!jsObj || !jsObj->HasMethod(method)) {
1410 return ret;
1411 }
1412
1413 auto engine = reinterpret_cast<NativeEngine*>(jsObj->GetEnv());
1414 if (engine == nullptr) {
1415 return ret;
1416 }
1417
1418 if (pthread_self() == engine->GetTid()) {
1419 return GetJavaScriptResultSelf(args, method, objName, routingId, objectId);
1420 } else {
1421 WVLOG_D("get javaScript result, not in js thread, post task to js thread");
1422 return PostGetJavaScriptResultToJsThread(args, method, objName, routingId, objectId);
1423 }
1424 }
1425
FlowbufStrAtIndex(void * mem,int flowbufIndex,int * argIndex,int * strLen)1426 char* WebviewJavaScriptResultCallBack::FlowbufStrAtIndex(void* mem, int flowbufIndex, int* argIndex, int* strLen)
1427 {
1428 int* header = static_cast<int*>(mem); // Cast the memory block to int* for easier access
1429 int offset = 0;
1430
1431 if (flowbufIndex >= MAX_ENTRIES) {
1432 *argIndex = -1;
1433 return nullptr;
1434 }
1435
1436 int* entry = header + (flowbufIndex * INDEX_SIZE);
1437 if (*(entry + 1) == 0) { // Check if length is 0, indicating unused entry
1438 *argIndex = -1;
1439 return nullptr;
1440 }
1441
1442 int i = 0;
1443 for (i = 0; i < flowbufIndex; i++) {
1444 offset += *(header + (i * INDEX_SIZE) + 1);
1445 }
1446
1447 *strLen = *(header + (i * INDEX_SIZE) + 1) - 1;
1448
1449 *argIndex = *entry;
1450
1451 char* dataSegment = static_cast<char*>(mem) + HEADER_SIZE;
1452 char* currentString = dataSegment + offset;
1453 return currentString;
1454 }
1455
ConstructArgv(void * ashmem,std::vector<std::shared_ptr<NWebValue>> args,std::vector<napi_value> & argv,std::shared_ptr<JavaScriptOb> jsObj,int32_t routingId)1456 bool WebviewJavaScriptResultCallBack::ConstructArgv(void* ashmem,
1457 std::vector<std::shared_ptr<NWebValue>> args,
1458 std::vector<napi_value>& argv,
1459 std::shared_ptr<JavaScriptOb> jsObj,
1460 int32_t routingId)
1461 {
1462 int argIndex = -1;
1463 int currIndex = 0;
1464 int flowbufIndex = 0;
1465 int strLen = 0;
1466 char* flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1467 flowbufIndex++;
1468 while (argIndex == currIndex) {
1469 napi_value napiValue = nullptr;
1470 napi_status s = napi_ok;
1471 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
1472 if (s != napi_ok) {
1473 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
1474 return false;
1475 }
1476 argv.push_back(napiValue);
1477 currIndex++;
1478 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1479 flowbufIndex++;
1480 }
1481
1482 for (std::shared_ptr<NWebValue> input : args) {
1483 while (argIndex == currIndex) {
1484 napi_value napiValue = nullptr;
1485 napi_status s = napi_ok;
1486 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
1487 if (s != napi_ok) {
1488 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
1489 }
1490 argv.push_back(napiValue);
1491 currIndex ++;
1492 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1493 flowbufIndex++;
1494 }
1495
1496 argv.push_back(ParseNwebValue2NapiValue(jsObj->GetEnv(), input, GetObjectMap(), GetNWebId(), routingId));
1497 currIndex++;
1498 }
1499
1500 while (argIndex == currIndex) {
1501 napi_value napiValue = nullptr;
1502 napi_status s = napi_ok;
1503 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
1504 if (s != napi_ok) {
1505 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
1506 }
1507 argv.push_back(napiValue);
1508 currIndex++;
1509 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1510 flowbufIndex++;
1511 }
1512 return true;
1513 }
1514
GetJavaScriptResultSelfHelper(std::shared_ptr<JavaScriptOb> jsObj,const std::string & method,int32_t routingId,std::vector<napi_value> argv)1515 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultSelfHelper(
1516 std::shared_ptr<JavaScriptOb> jsObj,
1517 const std::string& method,
1518 int32_t routingId,
1519 std::vector<napi_value> argv)
1520 {
1521 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1522 if (!jsObj) {
1523 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult jsObj null");
1524 return ret;
1525 }
1526 napi_value callback = jsObj->FindMethod(method);
1527 if (!callback) {
1528 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
1529 }
1530 napi_value callResult = nullptr;
1531 napi_call_function(jsObj->GetEnv(), jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
1532 bool isObject = false;
1533 std::vector<std::string> methodNameList;
1534 methodNameList = ParseNapiValue2NwebValue(jsObj->GetEnv(), &callResult, ret, &isObject);
1535 napi_valuetype valueType = napi_undefined;
1536 napi_typeof(jsObj->GetEnv(), callResult, &valueType);
1537 WVLOG_D("get javaScript result already in js thread end");
1538 if (!isObject) {
1539 return ret;
1540 }
1541 JavaScriptOb::ObjectID returnedObjectId;
1542 if (FindObjectIdInJsTd(jsObj->GetEnv(), callResult, &returnedObjectId) && FindObject(returnedObjectId)) {
1543 FindObject(returnedObjectId)->AddHolder(routingId);
1544 } else {
1545 returnedObjectId = AddObject(jsObj->GetEnv(), callResult, false, routingId);
1546 }
1547 SetUpAnnotateMethods(returnedObjectId, methodNameList);
1548 if (valueType == napi_function) {
1549 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is function");
1550 ret = std::make_shared<NWebValue>();
1551 } else {
1552 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is object");
1553 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
1554 ret = std::make_shared<NWebValue>(bin.c_str(), bin.size());
1555 }
1556 return ret;
1557 }
1558
GetJavaScriptResultSelfFlowbuf(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int fd,int32_t routingId,int32_t objectId)1559 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultSelfFlowbuf(
1560 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName, int fd,
1561 int32_t routingId, int32_t objectId)
1562 {
1563 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1564 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1565 if (!jsObj) {
1566 return ret;
1567 }
1568 NApiScope scope(jsObj->GetEnv());
1569 if (!scope.IsVaild()) {
1570 return ret;
1571 }
1572 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
1573 if (!flowbufferAdapter) {
1574 return ret;
1575 }
1576 auto ashmem = flowbufferAdapter->CreateAshmemWithFd(fd, MAX_FLOWBUF_DATA_SIZE + HEADER_SIZE, PROT_READ);
1577 if (!ashmem) {
1578 return ret;
1579 }
1580
1581 std::vector<napi_value> argv = {};
1582 if (!ConstructArgv(ashmem, args, argv, jsObj, routingId)) {
1583 return ret;
1584 }
1585 close(fd);
1586
1587 ret = GetJavaScriptResultSelfHelper(jsObj, method, routingId, argv);
1588 return ret;
1589 }
1590
GetJavaScriptResultFlowbuf(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int fd,int32_t routingId,int32_t objectId)1591 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultFlowbuf(
1592 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName, int fd,
1593 int32_t routingId, int32_t objectId)
1594 {
1595 (void)objName; // to be compatible with older webcotroller, classname may be empty
1596 WVLOG_D("GetJavaScriptResult method = %{public}s", method.c_str());
1597 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1598 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1599 if (!jsObj || !jsObj->HasMethod(method)) {
1600 return ret;
1601 }
1602
1603 auto engine = reinterpret_cast<NativeEngine*>(jsObj->GetEnv());
1604 if (engine == nullptr) {
1605 return ret;
1606 }
1607
1608 if (pthread_self() == engine->GetTid()) {
1609 return GetJavaScriptResultSelfFlowbuf(args, method, objName, fd, routingId, objectId);
1610 } else {
1611 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
1612 if (!flowbufferAdapter) {
1613 return ret;
1614 }
1615
1616 auto ashmem = flowbufferAdapter->CreateAshmemWithFd(fd, MAX_FLOWBUF_DATA_SIZE + HEADER_SIZE, PROT_READ);
1617 if (!ashmem) {
1618 return ret;
1619 }
1620
1621 int argIndex = -1;
1622 int flowbufIndex = 0;
1623 int strLen = 0;
1624 do {
1625 char* flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1626 if (argIndex == -1) {
1627 break;
1628 }
1629 flowbufIndex++;
1630 std::string str(flowbufStr);
1631 std::shared_ptr<NWebValue> insertArg = std::make_shared<NWebValue>(str);
1632 args.insert(args.begin() + argIndex, insertArg);
1633 } while (argIndex <= MAX_ENTRIES);
1634
1635 close(fd);
1636 WVLOG_D("get javaScript result, not in js thread, post task to js thread");
1637 return PostGetJavaScriptResultToJsThread(args, method, objName, routingId, objectId);
1638 }
1639 }
1640
PostGetJavaScriptResultToJsThread(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int32_t routingId,int32_t objectId)1641 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThread(
1642 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName,
1643 int32_t routingId, int32_t objectId)
1644 {
1645 // to be compatible with older webcotroller, classname may be empty
1646 (void)objName;
1647 WVLOG_D("WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThread method = "
1648 "%{public}s",
1649 method.c_str());
1650 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1651 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1652 if (!jsObj) {
1653 return ret;
1654 }
1655 napi_env env = jsObj->GetEnv();
1656 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1657 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1658 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1659 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1660 WVLOG_E("WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThread malloc fail");
1661 return ret;
1662 }
1663
1664 inParam->webJsResCb = this;
1665 inParam->nwebId = GetNWebId();
1666 inParam->frameRoutingId = routingId;
1667 inParam->objId = objectId;
1668 inParam->methodName = method;
1669 inParam->data = reinterpret_cast<void*>(&args);
1670 outParam->ret = reinterpret_cast<void*>(&ret);
1671 param->input = reinterpret_cast<void*>(inParam);
1672 param->out = reinterpret_cast<void*>(outParam);
1673 param->env = env;
1674
1675 CreateUvQueueWorkEnhanced(env, param, ExecuteGetJavaScriptResult);
1676 {
1677 std::unique_lock<std::mutex> lock(param->mutex);
1678 param->condition.wait(lock, [¶m] { return param->ready; });
1679 }
1680 DeleteNapiJsCallBackParm(inParam, outParam, param);
1681 return ret;
1682 }
1683
FindObjectIdInJsTd(napi_env env,napi_value object,JavaScriptOb::ObjectID * objectId)1684 bool WebviewJavaScriptResultCallBack::FindObjectIdInJsTd(
1685 napi_env env, napi_value object, JavaScriptOb::ObjectID* objectId)
1686 {
1687 *objectId = static_cast<JavaScriptOb::ObjectID>(JavaScriptOb::JavaScriptObjIdErrorCode::WEBVIEWCONTROLLERERROR);
1688 for (const auto& pair : objects_) {
1689 bool result = false;
1690 napi_status s = napi_strict_equals(env, object, pair.second->GetValue(), &result);
1691 if (s != napi_ok) {
1692 WVLOG_E("WebviewJavaScriptResultCallBack::FindObjectIdInJsTd fail");
1693 }
1694 if (result) {
1695 *objectId = pair.first;
1696 return true;
1697 }
1698 }
1699 return false;
1700 }
1701
ExecuteHasJavaScriptObjectMethods(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)1702 void ExecuteHasJavaScriptObjectMethods(
1703 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
1704 {
1705 if (!param) {
1706 return;
1707 }
1708
1709 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1710 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
1711 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
1712 if (!jsObj) {
1713 std::unique_lock<std::mutex> lock(param->mutex);
1714 param->ready = true;
1715 param->condition.notify_all();
1716 return;
1717 }
1718 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1719
1720 NApiScope scope(env);
1721 if (scope.IsVaild()) {
1722 if (jsObj && jsObj->HasMethod(inParam->methodName)) {
1723 *(static_cast<bool*>(outParam->ret)) = true;
1724 } else {
1725 WVLOG_D("WebviewJavaScriptResultCallBack::HasJavaScriptObjectMethods cannot find "
1726 "object");
1727 }
1728 }
1729
1730 std::unique_lock<std::mutex> lock(param->mutex);
1731 param->ready = true;
1732 param->condition.notify_all();
1733 }
1734
PostHasJavaScriptObjectMethodsToJsThread(int32_t objectId,const std::string & methodName)1735 bool WebviewJavaScriptResultCallBack::PostHasJavaScriptObjectMethodsToJsThread(
1736 int32_t objectId, const std::string& methodName)
1737 {
1738 bool ret = false;
1739 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1740 if (!jsObj) {
1741 return false;
1742 }
1743 napi_env env = jsObj->GetEnv();
1744 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1745 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1746 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1747 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1748 return false;
1749 }
1750
1751 inParam->webJsResCb = this;
1752 inParam->objId = objectId;
1753 inParam->methodName = methodName;
1754 outParam->ret = reinterpret_cast<void*>(&ret);
1755 param->input = reinterpret_cast<void*>(inParam);
1756 param->out = reinterpret_cast<void*>(outParam);
1757 param->env = env;
1758
1759 CreateUvQueueWorkEnhanced(env, param, ExecuteHasJavaScriptObjectMethods);
1760
1761 {
1762 std::unique_lock<std::mutex> lock(param->mutex);
1763 param->condition.wait(lock, [¶m] { return param->ready; });
1764 }
1765 DeleteNapiJsCallBackParm(inParam, outParam, param);
1766 return ret;
1767 }
1768
HasJavaScriptObjectMethods(int32_t objectId,const std::string & methodName)1769 bool WebviewJavaScriptResultCallBack::HasJavaScriptObjectMethods(int32_t objectId, const std::string& methodName)
1770 {
1771 bool ret = false;
1772 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1773 if (!jsObj) {
1774 return false;
1775 }
1776 napi_env env = jsObj->GetEnv();
1777 auto engine = reinterpret_cast<NativeEngine*>(env);
1778 if (engine == nullptr) {
1779 return ret;
1780 }
1781 if (pthread_self() == engine->GetTid()) {
1782 WVLOG_D(
1783 "has javaScript object methods already in js thread, objectId = "
1784 "%{public}d, methodName = %{public}s",
1785 objectId, methodName.c_str());
1786 NApiScope scope(env);
1787 if (!scope.IsVaild()) {
1788 return ret;
1789 }
1790
1791 if (jsObj && jsObj->HasMethod(methodName)) {
1792 ret = true;
1793 } else {
1794 WVLOG_D("WebviewJavaScriptResultCallBack::HasJavaScriptObjectMethods cannot find "
1795 "object");
1796 }
1797
1798 return ret;
1799 } else {
1800 WVLOG_D(
1801 "has javaScript object methods, not in js thread, post task to js "
1802 "thread, objectId = "
1803 "%{public}d, methodName = %{public}s",
1804 objectId, methodName.c_str());
1805 return PostHasJavaScriptObjectMethodsToJsThread(objectId, methodName);
1806 }
1807 }
1808
ExecuteGetJavaScriptObjectMethods(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)1809 void ExecuteGetJavaScriptObjectMethods(
1810 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
1811 {
1812 if (!param) {
1813 return;
1814 }
1815
1816 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1817 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
1818
1819 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
1820 if (!jsObj) {
1821 std::unique_lock<std::mutex> lock(param->mutex);
1822 param->ready = true;
1823 param->condition.notify_all();
1824 return;
1825 }
1826 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1827
1828 NApiScope scope(env);
1829
1830 if (scope.IsVaild()) {
1831 if (jsObj) {
1832 auto methods = jsObj->GetMethodNames();
1833 for (auto& method : methods) {
1834 (*(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)))->AddListValue(NWebValue(method));
1835 }
1836 }
1837 }
1838
1839 std::unique_lock<std::mutex> lock(param->mutex);
1840 param->ready = true;
1841 param->condition.notify_all();
1842 }
1843
PostGetJavaScriptObjectMethodsToJsThread(int32_t objectId)1844 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::PostGetJavaScriptObjectMethodsToJsThread(int32_t objectId)
1845 {
1846 auto ret = std::make_shared<NWebValue>(NWebValue::Type::LIST);
1847 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1848 if (!jsObj) {
1849 return ret;
1850 }
1851 napi_env env = jsObj->GetEnv();
1852 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1853 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1854 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1855 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1856 return ret;
1857 }
1858
1859 inParam->webJsResCb = this;
1860 inParam->objId = objectId;
1861 outParam->ret = reinterpret_cast<void*>(&ret);
1862 param->input = reinterpret_cast<void*>(inParam);
1863 param->out = reinterpret_cast<void*>(outParam);
1864 param->env = env;
1865
1866 CreateUvQueueWorkEnhanced(env, param, ExecuteGetJavaScriptObjectMethods);
1867
1868 {
1869 std::unique_lock<std::mutex> lock(param->mutex);
1870 param->condition.wait(lock, [¶m] { return param->ready; });
1871 }
1872 DeleteNapiJsCallBackParm(inParam, outParam, param);
1873 return ret;
1874 }
1875
GetJavaScriptObjectMethods(int32_t objectId)1876 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptObjectMethods(int32_t objectId)
1877 {
1878 auto ret = std::make_shared<NWebValue>(NWebValue::Type::LIST);
1879 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1880 if (!jsObj) {
1881 return ret;
1882 }
1883 napi_env env = jsObj->GetEnv();
1884 auto engine = reinterpret_cast<NativeEngine*>(env);
1885 if (engine == nullptr) {
1886 return ret;
1887 }
1888
1889 if (pthread_self() == engine->GetTid()) {
1890 WVLOG_D(
1891 "get javaScript object methods already in js thread, objectId = "
1892 "%{public}d",
1893 objectId);
1894 NApiScope scope(env);
1895 if (!scope.IsVaild()) {
1896 return ret;
1897 }
1898
1899 if (jsObj) {
1900 auto methods = jsObj->GetMethodNames();
1901 for (auto& method : methods) {
1902 ret->AddListValue(NWebValue(method));
1903 }
1904 }
1905
1906 return ret;
1907 } else {
1908 WVLOG_D(
1909 "get javaScript object methods, not in js thread, post task to js "
1910 "thread, objectId = %{public}d",
1911 objectId);
1912 return PostGetJavaScriptObjectMethodsToJsThread(objectId);
1913 }
1914 }
1915
RemoveJavaScriptObjectHolderInJsTd(int32_t holder,JavaScriptOb::ObjectID objectId)1916 void WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolderInJsTd(
1917 int32_t holder, JavaScriptOb::ObjectID objectId)
1918 {
1919 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1920 if (jsObj && !(jsObj->IsNamed())) {
1921 jsObj->RemoveHolder(holder);
1922 if (!(jsObj->HasHolders())) {
1923 // reminder me: object->ToWeakRef(), object is erased so the destructor
1924 // called
1925 retainedObjectSet_.erase(jsObj);
1926 objects_.erase(objects_.find(objectId));
1927 }
1928 }
1929 }
1930
ExecuteRemoveJavaScriptObjectHolder(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)1931 void ExecuteRemoveJavaScriptObjectHolder(
1932 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
1933 {
1934 if (!param) {
1935 return;
1936 }
1937
1938 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1939
1940 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
1941 if (!jsObj) {
1942 std::unique_lock<std::mutex> lock(param->mutex);
1943 param->ready = true;
1944 param->condition.notify_all();
1945 return;
1946 }
1947 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1948
1949 NApiScope scope(env);
1950
1951 if (scope.IsVaild()) {
1952 inParam->webJsResCb->RemoveJavaScriptObjectHolderInJsTd(inParam->frameRoutingId, inParam->objId);
1953 }
1954
1955 std::unique_lock<std::mutex> lock(param->mutex);
1956 param->ready = true;
1957 param->condition.notify_all();
1958 }
1959
PostRemoveJavaScriptObjectHolderToJsThread(int32_t holder,JavaScriptOb::ObjectID objectId)1960 void WebviewJavaScriptResultCallBack::PostRemoveJavaScriptObjectHolderToJsThread(
1961 int32_t holder, JavaScriptOb::ObjectID objectId)
1962 {
1963 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolder called, "
1964 "objectId = %{public}d",
1965 objectId);
1966 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1967 if (!jsObj) {
1968 return;
1969 }
1970 napi_env env = jsObj->GetEnv();
1971 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1972 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1973 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1974 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1975 return;
1976 }
1977
1978 inParam->webJsResCb = this;
1979 inParam->objId = objectId;
1980 inParam->frameRoutingId = holder;
1981 param->input = reinterpret_cast<void*>(inParam);
1982 param->out = reinterpret_cast<void*>(outParam);
1983 param->env = env;
1984
1985 CreateUvQueueWorkEnhanced(env, param, ExecuteRemoveJavaScriptObjectHolder);
1986
1987 {
1988 std::unique_lock<std::mutex> lock(param->mutex);
1989 param->condition.wait(lock, [¶m] { return param->ready; });
1990 }
1991 DeleteNapiJsCallBackParm(inParam, outParam, param);
1992 }
1993
RemoveJavaScriptObjectHolder(int32_t holder,JavaScriptOb::ObjectID objectId)1994 void WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolder(int32_t holder, JavaScriptOb::ObjectID objectId)
1995 {
1996 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolder called, "
1997 "objectId = %{public}d",
1998 objectId);
1999 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2000 if (!jsObj) {
2001 return;
2002 }
2003 napi_env env = jsObj->GetEnv();
2004 auto engine = reinterpret_cast<NativeEngine*>(env);
2005 if (engine == nullptr) {
2006 return;
2007 }
2008 if (pthread_self() == engine->GetTid()) {
2009 WVLOG_D("remove javaScript object holder already in js thread");
2010 NApiScope scope(env);
2011 if (!scope.IsVaild()) {
2012 return;
2013 }
2014
2015 RemoveJavaScriptObjectHolderInJsTd(holder, objectId);
2016
2017 return;
2018 } else {
2019 WVLOG_D("remove javaScript object holder, not in js thread, post task to js thread");
2020 PostRemoveJavaScriptObjectHolderToJsThread(holder, objectId);
2021 }
2022 }
2023
RemoveTransientJavaScriptObjectInJsTd()2024 void WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObjectInJsTd()
2025 {
2026 // remove retainedObjectSet_ and objects_ CreateTransient object
2027 auto iter = objects_.begin();
2028 while (iter != objects_.end()) {
2029 if (!(iter->second->IsNamed())) {
2030 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject "
2031 "objectId = %{public}d is removed",
2032 (int32_t)iter->first);
2033 // reminder me: object->ToWeakRef(), object is erased so the destructor called
2034 retainedObjectSet_.erase(iter->second);
2035 objects_.erase(iter++);
2036 } else {
2037 ++iter;
2038 }
2039 }
2040
2041 // remove retainedObjectSet_ named object but not in objects_
2042 auto iter1 = retainedObjectSet_.begin();
2043 while (iter1 != retainedObjectSet_.end()) {
2044 auto iter2 = objects_.begin();
2045 bool isHasObj = false;
2046 while (iter2 != objects_.end()) {
2047 if (*iter1 == iter2->second) {
2048 isHasObj = true;
2049 break;
2050 }
2051 ++iter2;
2052 }
2053 if (!isHasObj) {
2054 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject "
2055 "isHasObj == false");
2056 retainedObjectSet_.erase(*iter1);
2057 }
2058 ++iter1;
2059 }
2060 }
2061
ExecuteRemoveTransientJavaScriptObject(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)2062 void ExecuteRemoveTransientJavaScriptObject(
2063 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
2064 {
2065 if (!param) {
2066 return;
2067 }
2068
2069 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
2070
2071 Ace::ContainerScope containerScope(inParam->containerScopeId);
2072
2073 NApiScope scope(env);
2074
2075 if (scope.IsVaild()) {
2076 inParam->webJsResCb->RemoveTransientJavaScriptObjectInJsTd();
2077 }
2078
2079 std::unique_lock<std::mutex> lock(param->mutex);
2080 param->ready = true;
2081 param->condition.notify_all();
2082 }
2083
PostRemoveTransientJavaScriptObjectToJsThread(std::shared_ptr<JavaScriptOb> jsObj)2084 void WebviewJavaScriptResultCallBack::PostRemoveTransientJavaScriptObjectToJsThread(
2085 std::shared_ptr<JavaScriptOb> jsObj)
2086 {
2087 WVLOG_D("WebviewJavaScriptResultCallBack::PostRemoveTransientJavaScriptObjectToJsThread called");
2088 if (!jsObj) {
2089 return;
2090 }
2091 napi_env env = jsObj->GetEnv();
2092 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
2093 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
2094 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
2095 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
2096 return;
2097 }
2098
2099 inParam->webJsResCb = this;
2100 inParam->containerScopeId = jsObj->GetContainerScopeId();
2101 param->input = reinterpret_cast<void*>(inParam);
2102 param->out = reinterpret_cast<void*>(outParam);
2103 param->env = env;
2104
2105 CreateUvQueueWorkEnhanced(env, param, ExecuteRemoveTransientJavaScriptObject);
2106
2107 {
2108 std::unique_lock<std::mutex> lock(param->mutex);
2109 param->condition.wait(lock, [¶m] { return param->ready; });
2110 }
2111 DeleteNapiJsCallBackParm(inParam, outParam, param);
2112 }
2113
RemoveTransientJavaScriptObject()2114 void WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject()
2115 {
2116 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject called");
2117 std::shared_ptr<JavaScriptOb> jsObj = nullptr;
2118 if (!objects_.empty()) {
2119 jsObj = objects_.begin()->second;
2120 } else if (!retainedObjectSet_.empty()) {
2121 jsObj = *(retainedObjectSet_.begin());
2122 } else {
2123 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject "
2124 "objects_ & retainedObjectSet_ is empty.");
2125 return;
2126 }
2127
2128 if (!jsObj) {
2129 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject "
2130 "jsObj is nullptr.");
2131 return;
2132 }
2133
2134 napi_env env = jsObj->GetEnv();
2135 auto engine = reinterpret_cast<NativeEngine*>(env);
2136 if (engine == nullptr) {
2137 return;
2138 }
2139 if (pthread_self() == engine->GetTid()) {
2140 WVLOG_D("remove transient javaScript object already in js thread");
2141 NApiScope scope(env);
2142 if (!scope.IsVaild()) {
2143 return;
2144 }
2145
2146 RemoveTransientJavaScriptObjectInJsTd();
2147 } else {
2148 WVLOG_D("remove transient javaScript object, not in js thread, post task to js thread");
2149 PostRemoveTransientJavaScriptObjectToJsThread(jsObj);
2150 }
2151 }
2152
SetUpAnnotateMethods(JavaScriptOb::ObjectID objId,std::vector<std::string> & methodNameList)2153 void WebviewJavaScriptResultCallBack::SetUpAnnotateMethods(
2154 JavaScriptOb::ObjectID objId, std::vector<std::string>& methodNameList)
2155 {
2156 // set up annotate(methodNameListForJsProxy) object method
2157 if (objects_[objId]) {
2158 objects_[objId]->SetMethods(methodNameList);
2159 }
2160 }
2161
AddObject(napi_env env,const napi_value & object,bool methodName,int32_t holder)2162 JavaScriptOb::ObjectID WebviewJavaScriptResultCallBack::AddObject(
2163 napi_env env, const napi_value& object, bool methodName, int32_t holder)
2164 {
2165 JavaScriptOb::ObjectID objectId;
2166 {
2167 int32_t containerScopeId = Ace::ContainerScope::CurrentId();
2168 auto new_object = methodName ? JavaScriptOb::CreateNamed(env, containerScopeId, object)
2169 : JavaScriptOb::CreateTransient(env, containerScopeId, object, holder);
2170 objectId = nextObjectId_++;
2171 WVLOG_D(
2172 "WebviewJavaScriptResultCallBack::AddObject objectId = "
2173 "%{public}d",
2174 static_cast<int32_t>(objectId));
2175 objects_[objectId] = new_object;
2176 retainedObjectSet_.insert(new_object);
2177 }
2178 return objectId;
2179 }
2180
AddNamedObject(napi_env env,napi_value & obj,const std::string & objName)2181 JavaScriptOb::ObjectID WebviewJavaScriptResultCallBack::AddNamedObject(
2182 napi_env env, napi_value& obj, const std::string& objName)
2183 {
2184 JavaScriptOb::ObjectID objectId;
2185 NamedObjectMap::iterator iter = namedObjects_.find(objName);
2186 bool methodName = FindObjectIdInJsTd(env, obj, &objectId);
2187 if (methodName && iter != namedObjects_.end() && iter->second == objectId) {
2188 // Nothing to do.
2189 WVLOG_D(
2190 "WebviewJavaScriptResultCallBack::AddNamedObject obj and "
2191 "objName(%{public}s) "
2192 "already exist",
2193 objName.c_str());
2194 return objectId;
2195 }
2196 if (iter != namedObjects_.end()) {
2197 RemoveNamedObject(iter->first);
2198 }
2199 if (methodName) {
2200 objects_[objectId]->AddName();
2201 } else {
2202 objectId = AddObject(env, obj, true, 0);
2203 }
2204 namedObjects_[objName] = objectId;
2205 return objectId;
2206 }
2207
GetNamedObjects()2208 std::unordered_map<std::string, std::shared_ptr<JavaScriptOb>> WebviewJavaScriptResultCallBack::GetNamedObjects()
2209 {
2210 // Get named objects
2211 std::unordered_map<std::string, std::shared_ptr<JavaScriptOb>> ret;
2212 for (auto iter = namedObjects_.begin(); iter != namedObjects_.end(); iter++) {
2213 if (objects_.find(iter->second) != objects_.end()) {
2214 ret.emplace(iter->first, objects_[iter->second]);
2215 }
2216 }
2217 return ret;
2218 }
2219
GetObjectMap()2220 WebviewJavaScriptResultCallBack::ObjectMap WebviewJavaScriptResultCallBack::GetObjectMap()
2221 {
2222 return objects_;
2223 }
2224
RegisterJavaScriptProxy(RegisterJavaScriptProxyParam & param)2225 JavaScriptOb::ObjectID WebviewJavaScriptResultCallBack::RegisterJavaScriptProxy(
2226 RegisterJavaScriptProxyParam& param)
2227 {
2228 JavaScriptOb::ObjectID objId = AddNamedObject(param.env, param.obj, param.objName);
2229 // set up named object method
2230 if (namedObjects_.find(param.objName) != namedObjects_.end() && objects_[namedObjects_[param.objName]]) {
2231 std::shared_ptr<OHOS::NWeb::JavaScriptOb> jsObj = objects_[namedObjects_[param.objName]];
2232 jsObj->SetMethods(param.syncMethodList);
2233 jsObj->SetAsyncMethods(param.asyncMethodList);
2234 jsObj->SetPermission(param.permission);
2235 }
2236 for (auto& item : param.syncMethodList) {
2237 WVLOG_D(
2238 "WebviewJavaScriptResultCallBack::RegisterJavaScriptProxy called, "
2239 "objectId = %{public}d, objName = %{public}s, method = %{public}s",
2240 static_cast<int32_t>(objId), param.objName.c_str(), item.c_str());
2241 }
2242 return objId;
2243 }
2244
RemoveNamedObject(const std::string & name)2245 bool WebviewJavaScriptResultCallBack::RemoveNamedObject(const std::string& name)
2246 {
2247 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveNamedObject called, "
2248 "name = %{public}s",
2249 name.c_str());
2250 NamedObjectMap::iterator iter = namedObjects_.find(name);
2251 if (iter == namedObjects_.end()) {
2252 return false;
2253 }
2254 if (objects_[iter->second]) {
2255 objects_[iter->second]->RemoveName();
2256 }
2257 namedObjects_.erase(iter);
2258 return true;
2259 }
2260
DeleteJavaScriptRegister(const std::string & objName)2261 bool WebviewJavaScriptResultCallBack::DeleteJavaScriptRegister(const std::string& objName)
2262 {
2263 return RemoveNamedObject(objName);
2264 }
2265
CallH5FunctionInternal(napi_env env,H5Bundle & bundle,const std::vector<std::shared_ptr<NWebRomValue>> & romArgs,const std::vector<std::shared_ptr<NWebValue>> & nwebArgs)2266 void WebviewJavaScriptResultCallBack::CallH5FunctionInternal(
2267 napi_env env, H5Bundle& bundle, const std::vector<std::shared_ptr<NWebRomValue>>& romArgs,
2268 const std::vector<std::shared_ptr<NWebValue>>& nwebArgs)
2269 {
2270 if (bundle.nwebId != GetNWebId()) {
2271 WVLOG_E("WebviewJavaScriptResultCallBack::CallH5FunctionInternal nweb id not equal");
2272 return;
2273 }
2274 auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId_);
2275 if (!nweb_ptr) {
2276 WVLOG_E("WebviewJavaScriptResultCallBack::CallH5FunctionInternal nweb_ptr null");
2277 return;
2278 }
2279
2280 nweb_ptr->CallH5FunctionV2(bundle.frameRoutingId, bundle.h5Id, bundle.funcName, romArgs);
2281 if (ArkWebGetErrno() != RESULT_OK) {
2282 nweb_ptr->CallH5Function(bundle.frameRoutingId, bundle.h5Id, bundle.funcName, nwebArgs);
2283 }
2284 WVLOG_D("WebviewJavaScriptResultCallBack::CallH5FunctionInternal end");
2285 }
2286
UpdateInstanceId(int32_t newId)2287 void WebviewJavaScriptResultCallBack::UpdateInstanceId(int32_t newId)
2288 {
2289 for (const auto& [nwebId, obj] : objects_) {
2290 obj->SetContainerScopeId(newId);
2291 }
2292 }
2293
ProcessObjectCaseInJsTdV2(napi_env env,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param,napi_value callResult,std::vector<std::string> & methodNameList,std::shared_ptr<NWebHapValue> result)2294 void ProcessObjectCaseInJsTdV2(napi_env env, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param,
2295 napi_value callResult, std::vector<std::string>& methodNameList, std::shared_ptr<NWebHapValue> result)
2296 {
2297 if (!param) {
2298 WVLOG_E("WebviewJavaScriptResultCallBack::ProcessObjectCaseInJsTd param null");
2299 return;
2300 }
2301
2302 JavaScriptOb::ObjectID returnedObjectId;
2303 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
2304 if (inParam->webJsResCb->FindObjectIdInJsTd(env, callResult, &returnedObjectId)
2305 && inParam->webJsResCb->FindObject(returnedObjectId)) {
2306 inParam->webJsResCb->FindObject(returnedObjectId)->AddHolder(inParam->frameRoutingId);
2307 } else {
2308 returnedObjectId = inParam->webJsResCb->AddObject(env, callResult, false, inParam->frameRoutingId);
2309 }
2310
2311 inParam->webJsResCb->SetUpAnnotateMethods(returnedObjectId, methodNameList);
2312
2313 napi_valuetype valueType = napi_undefined;
2314 napi_typeof(env, callResult, &valueType);
2315 if (valueType == napi_function) {
2316 WVLOG_D("WebviewJavaScriptResultCallBack::ProcessObjectCaseInJsTd type is function");
2317 } else {
2318 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
2319 result->SetType(NWebHapValue::Type::BINARY);
2320 result->SetBinary(bin.size(), bin.c_str());
2321 }
2322 }
2323
ExecuteGetJavaScriptResultV2(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)2324 void ExecuteGetJavaScriptResultV2(
2325 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
2326 {
2327 WVLOG_D("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult called");
2328 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
2329 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
2330 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
2331 if (!jsObj) {
2332 std::unique_lock<std::mutex> lock(param->mutex);
2333 param->ready = true;
2334 param->condition.notify_all();
2335 return;
2336 }
2337
2338 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
2339 NApiScope scope(env);
2340 if (!scope.IsVaild()) {
2341 std::unique_lock<std::mutex> lock(param->mutex);
2342 param->ready = true;
2343 param->condition.notify_all();
2344 return;
2345 }
2346
2347 if (jsObj && (jsObj->HasMethod(inParam->methodName))) {
2348 napi_value callback = jsObj->FindMethod(inParam->methodName);
2349 if (!callback) {
2350 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
2351 }
2352
2353 napi_value callResult = nullptr;
2354 auto argv = *(static_cast<std::vector<napi_value>*>(inParam->data));
2355 napi_call_function(env, jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
2356
2357 bool isObject = false;
2358 std::vector<std::string> methodNameList;
2359 auto result = *(static_cast<std::shared_ptr<NWebHapValue>*>(outParam->ret));
2360 methodNameList = ParseNapiValue2NwebValueV2(env, &callResult, result, &isObject);
2361 if (isObject) {
2362 ProcessObjectCaseInJsTdV2(env, param, callResult, methodNameList, result);
2363 }
2364 }
2365
2366 std::unique_lock<std::mutex> lock(param->mutex);
2367 param->ready = true;
2368 param->condition.notify_all();
2369 }
2370
ExecuteGetJavaScriptObjectMethodsV2(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)2371 void ExecuteGetJavaScriptObjectMethodsV2(
2372 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
2373 {
2374 if (!param) {
2375 return;
2376 }
2377
2378 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
2379 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
2380
2381 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
2382 if (!jsObj) {
2383 std::unique_lock<std::mutex> lock(param->mutex);
2384 param->ready = true;
2385 param->condition.notify_all();
2386 return;
2387 }
2388 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
2389
2390 NApiScope scope(env);
2391 if (scope.IsVaild()) {
2392 auto methods = jsObj->GetMethodNames();
2393 NWebHapValue* result = static_cast<NWebHapValue*>(outParam->ret);
2394 for (auto& method : methods) {
2395 std::shared_ptr<NWebHapValue> child = result->NewChildValue();
2396 if (child) {
2397 child->SetString(method);
2398 result->SaveListChildValue();
2399 }
2400 }
2401 }
2402
2403 std::unique_lock<std::mutex> lock(param->mutex);
2404 param->ready = true;
2405 param->condition.notify_all();
2406 }
2407
ConstructArgvV2(void * ashmem,const std::vector<std::shared_ptr<NWebHapValue>> & args,std::vector<napi_value> & argv,std::shared_ptr<JavaScriptOb> jsObj,int32_t routingId)2408 bool WebviewJavaScriptResultCallBack::ConstructArgvV2(void* ashmem,
2409 const std::vector<std::shared_ptr<NWebHapValue>>& args, std::vector<napi_value>& argv,
2410 std::shared_ptr<JavaScriptOb> jsObj, int32_t routingId)
2411 {
2412 int argIndex = -1;
2413 int currIndex = 0;
2414 int flowbufIndex = 0;
2415 int strLen = 0;
2416 char* flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
2417 flowbufIndex++;
2418 while (argIndex == currIndex) {
2419 napi_value napiValue = nullptr;
2420 napi_status s = napi_ok;
2421 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
2422 if (s != napi_ok) {
2423 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
2424 return false;
2425 }
2426
2427 argv.push_back(napiValue);
2428 currIndex++;
2429 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
2430 flowbufIndex++;
2431 }
2432
2433 for (auto& input : args) {
2434 while (argIndex == currIndex) {
2435 napi_value napiValue = nullptr;
2436 napi_status s = napi_ok;
2437 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
2438 if (s != napi_ok) {
2439 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
2440 }
2441
2442 argv.push_back(napiValue);
2443 currIndex++;
2444 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
2445 flowbufIndex++;
2446 }
2447
2448 argv.push_back(ParseNwebValue2NapiValueV2(jsObj->GetEnv(), input, GetObjectMap(), GetNWebId(), routingId));
2449 currIndex++;
2450 }
2451
2452 while (argIndex == currIndex) {
2453 napi_value napiValue = nullptr;
2454 napi_status s = napi_ok;
2455 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
2456 if (s != napi_ok) {
2457 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
2458 }
2459
2460 argv.push_back(napiValue);
2461 currIndex++;
2462 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
2463 flowbufIndex++;
2464 }
2465
2466 return true;
2467 }
2468
GetJavaScriptResultSelfV2(const std::vector<std::shared_ptr<NWebHapValue>> & args,const std::string & method,int32_t routingId,int32_t objectId,std::shared_ptr<NWebHapValue> result)2469 void WebviewJavaScriptResultCallBack::GetJavaScriptResultSelfV2(const std::vector<std::shared_ptr<NWebHapValue>>& args,
2470 const std::string& method, int32_t routingId, int32_t objectId, std::shared_ptr<NWebHapValue> result)
2471 {
2472 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2473 if (!jsObj) {
2474 return;
2475 }
2476
2477 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
2478 NApiScope scope(jsObj->GetEnv());
2479 if (!scope.IsVaild()) {
2480 return;
2481 }
2482
2483 WVLOG_D("get javaScript result already in js thread");
2484 std::vector<napi_value> argv = {};
2485 for (auto& input : args) {
2486 argv.push_back(ParseNwebValue2NapiValueV2(jsObj->GetEnv(), input, GetObjectMap(), GetNWebId(), routingId));
2487 }
2488
2489 napi_value callback = jsObj->FindMethod(method);
2490 if (!callback) {
2491 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
2492 }
2493
2494 napi_value callResult = nullptr;
2495 napi_call_function(jsObj->GetEnv(), jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
2496 bool isObject = false;
2497 std::vector<std::string> methodNameList =
2498 ParseNapiValue2NwebValueV2(jsObj->GetEnv(), &callResult, result, &isObject);
2499
2500 napi_valuetype valueType = napi_undefined;
2501 napi_typeof(jsObj->GetEnv(), callResult, &valueType);
2502
2503 WVLOG_D("get javaScript result already in js thread end");
2504 if (isObject) {
2505 JavaScriptOb::ObjectID returnedObjectId;
2506 if (FindObjectIdInJsTd(jsObj->GetEnv(), callResult, &returnedObjectId)) {
2507 std::shared_ptr<JavaScriptOb> obj = FindObject(returnedObjectId);
2508 if (obj) {
2509 obj->AddHolder(routingId);
2510 }
2511 } else {
2512 returnedObjectId = AddObject(jsObj->GetEnv(), callResult, false, routingId);
2513 }
2514
2515 SetUpAnnotateMethods(returnedObjectId, methodNameList);
2516 if (valueType == napi_function) {
2517 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is function");
2518 } else {
2519 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is object");
2520 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
2521 result->SetType(NWebHapValue::Type::BINARY);
2522 result->SetBinary(bin.size(), bin.c_str());
2523 }
2524 }
2525 }
2526
GetJavaScriptResultSelfHelperV2(std::shared_ptr<JavaScriptOb> jsObj,const std::string & method,int32_t routingId,const std::vector<napi_value> & argv,std::shared_ptr<NWebHapValue> result)2527 void WebviewJavaScriptResultCallBack::GetJavaScriptResultSelfHelperV2(std::shared_ptr<JavaScriptOb> jsObj,
2528 const std::string& method, int32_t routingId, const std::vector<napi_value>& argv,
2529 std::shared_ptr<NWebHapValue> result)
2530 {
2531 napi_value callback = jsObj->FindMethod(method);
2532 if (!callback) {
2533 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
2534 }
2535
2536 napi_value callResult = nullptr;
2537 napi_call_function(jsObj->GetEnv(), jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
2538
2539 bool isObject = false;
2540 std::vector<std::string> methodNameList;
2541 methodNameList = ParseNapiValue2NwebValueV2(jsObj->GetEnv(), &callResult, result, &isObject);
2542
2543 napi_valuetype valueType = napi_undefined;
2544 napi_typeof(jsObj->GetEnv(), callResult, &valueType);
2545 WVLOG_D("get javaScript result already in js thread end");
2546 if (!isObject) {
2547 return;
2548 }
2549
2550 JavaScriptOb::ObjectID returnedObjectId;
2551 if (FindObjectIdInJsTd(jsObj->GetEnv(), callResult, &returnedObjectId) && FindObject(returnedObjectId)) {
2552 FindObject(returnedObjectId)->AddHolder(routingId);
2553 } else {
2554 returnedObjectId = AddObject(jsObj->GetEnv(), callResult, false, routingId);
2555 }
2556
2557 SetUpAnnotateMethods(returnedObjectId, methodNameList);
2558 if (valueType == napi_function) {
2559 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is function");
2560 } else {
2561 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is object");
2562 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
2563 result->SetType(NWebHapValue::Type::BINARY);
2564 result->SetBinary(bin.size(), bin.c_str());
2565 }
2566 }
2567
GetJavaScriptResultSelfFlowbufV2(const std::vector<std::shared_ptr<NWebHapValue>> & args,const std::string & method,int fd,int32_t routingId,int32_t objectId,std::shared_ptr<NWebHapValue> result)2568 void WebviewJavaScriptResultCallBack::GetJavaScriptResultSelfFlowbufV2(
2569 const std::vector<std::shared_ptr<NWebHapValue>>& args, const std::string& method, int fd, int32_t routingId,
2570 int32_t objectId, std::shared_ptr<NWebHapValue> result)
2571 {
2572 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2573 if (!jsObj) {
2574 return;
2575 }
2576
2577 NApiScope scope(jsObj->GetEnv());
2578 if (!scope.IsVaild()) {
2579 return;
2580 }
2581
2582 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
2583 if (!flowbufferAdapter) {
2584 return;
2585 }
2586
2587 auto ashmem = flowbufferAdapter->CreateAshmemWithFd(fd, MAX_FLOWBUF_DATA_SIZE + HEADER_SIZE, PROT_READ);
2588 if (!ashmem) {
2589 return;
2590 }
2591
2592 std::vector<napi_value> argv = {};
2593 if (!ConstructArgvV2(ashmem, args, argv, jsObj, routingId)) {
2594 return;
2595 }
2596 close(fd);
2597
2598 GetJavaScriptResultSelfHelperV2(jsObj, method, routingId, argv, result);
2599 }
2600
PostGetJavaScriptResultToJsThreadV2(std::vector<napi_value> & argv,const std::string & method,int32_t routingId,int32_t objectId,std::shared_ptr<NWebHapValue> result)2601 void WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThreadV2(std::vector<napi_value>& argv,
2602 const std::string& method, int32_t routingId, int32_t objectId, std::shared_ptr<NWebHapValue> result)
2603 {
2604 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2605 if (!jsObj) {
2606 return;
2607 }
2608
2609 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
2610 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
2611 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
2612 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
2613 WVLOG_E("WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThread malloc fail");
2614 return;
2615 }
2616
2617 inParam->webJsResCb = this;
2618 inParam->objId = objectId;
2619 inParam->nwebId = GetNWebId();
2620 inParam->methodName = method;
2621 inParam->frameRoutingId = routingId;
2622 inParam->data = reinterpret_cast<void*>(&argv);
2623 outParam->ret = reinterpret_cast<void*>(&result);
2624
2625 param->env = jsObj->GetEnv();
2626 param->out = reinterpret_cast<void*>(outParam);
2627 param->input = reinterpret_cast<void*>(inParam);
2628
2629 CreateUvQueueWorkEnhanced(param->env, param, ExecuteGetJavaScriptResultV2);
2630 {
2631 std::unique_lock<std::mutex> lock(param->mutex);
2632 param->condition.wait(lock, [¶m] { return param->ready; });
2633 }
2634 DeleteNapiJsCallBackParm(inParam, outParam, param);
2635 }
2636
PostGetJavaScriptObjectMethodsToJsThreadV2(int32_t objectId,std::shared_ptr<NWebHapValue> result)2637 void WebviewJavaScriptResultCallBack::PostGetJavaScriptObjectMethodsToJsThreadV2(
2638 int32_t objectId, std::shared_ptr<NWebHapValue> result)
2639 {
2640 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2641 if (!jsObj) {
2642 return;
2643 }
2644
2645 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
2646 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
2647 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
2648 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
2649 return;
2650 }
2651
2652 inParam->objId = objectId;
2653 inParam->webJsResCb = this;
2654 outParam->ret = reinterpret_cast<void*>(result.get());
2655 param->env = jsObj->GetEnv();
2656 param->out = reinterpret_cast<void*>(outParam);
2657 param->input = reinterpret_cast<void*>(inParam);
2658
2659 CreateUvQueueWorkEnhanced(param->env, param, ExecuteGetJavaScriptObjectMethodsV2);
2660 {
2661 std::unique_lock<std::mutex> lock(param->mutex);
2662 param->condition.wait(lock, [¶m] { return param->ready; });
2663 }
2664 DeleteNapiJsCallBackParm(inParam, outParam, param);
2665 }
2666
GetJavaScriptResultV2(const std::vector<std::shared_ptr<NWebHapValue>> & args,const std::string & method,const std::string & objectName,int32_t routingId,int32_t objectId,std::shared_ptr<NWebHapValue> result)2667 void WebviewJavaScriptResultCallBack::GetJavaScriptResultV2(const std::vector<std::shared_ptr<NWebHapValue>>& args,
2668 const std::string& method, const std::string& objectName, int32_t routingId, int32_t objectId,
2669 std::shared_ptr<NWebHapValue> result)
2670 {
2671 (void)objectName; // to be compatible with older webcotroller, classname may be empty
2672 WVLOG_D("GetJavaScriptResult method = %{public}s,routingId = %{public}d, objectId = %{public}d", method.c_str(),
2673 routingId, objectId);
2674
2675 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2676 if (!jsObj || !jsObj->HasMethod(method)) {
2677 return;
2678 }
2679
2680 auto engine = reinterpret_cast<NativeEngine*>(jsObj->GetEnv());
2681 if (engine == nullptr) {
2682 return;
2683 }
2684
2685 if (pthread_self() == engine->GetTid()) {
2686 GetJavaScriptResultSelfV2(args, method, routingId, objectId, result);
2687 } else {
2688 WVLOG_D("get javaScript result, not in js thread, post task to js thread");
2689
2690 auto nwebId = GetNWebId();
2691 napi_env env = jsObj->GetEnv();
2692 std::vector<napi_value> argv = {};
2693 for (auto& input : args) {
2694 argv.push_back(ParseNwebValue2NapiValueV2(env, input, GetObjectMap(), nwebId, routingId));
2695 }
2696
2697 PostGetJavaScriptResultToJsThreadV2(argv, method, routingId, objectId, result);
2698 }
2699 }
2700
GetJavaScriptResultFlowbufV2(const std::vector<std::shared_ptr<NWebHapValue>> & args,const std::string & method,const std::string & objectName,int fd,int32_t routingId,int32_t objectId,std::shared_ptr<NWebHapValue> result)2701 void WebviewJavaScriptResultCallBack::GetJavaScriptResultFlowbufV2(
2702 const std::vector<std::shared_ptr<NWebHapValue>>& args, const std::string& method, const std::string& objectName,
2703 int fd, int32_t routingId, int32_t objectId, std::shared_ptr<NWebHapValue> result)
2704 {
2705 (void)objectName; // to be compatible with older webcotroller, classname may be empty
2706 WVLOG_D("GetJavaScriptResult method = %{public}s", method.c_str());
2707
2708 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2709 if (!jsObj || !jsObj->HasMethod(method)) {
2710 return;
2711 }
2712
2713 auto engine = reinterpret_cast<NativeEngine*>(jsObj->GetEnv());
2714 if (engine == nullptr) {
2715 return;
2716 }
2717
2718 if (pthread_self() == engine->GetTid()) {
2719 GetJavaScriptResultSelfFlowbufV2(args, method, fd, routingId, objectId, result);
2720 } else {
2721 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
2722 if (!flowbufferAdapter) {
2723 return;
2724 }
2725
2726 auto ashmem = flowbufferAdapter->CreateAshmemWithFd(fd, MAX_FLOWBUF_DATA_SIZE + HEADER_SIZE, PROT_READ);
2727 if (!ashmem) {
2728 return;
2729 }
2730
2731 int strLen = 0;
2732 int argIndex = -1;
2733 int flowbufIndex = 0;
2734 napi_env env = jsObj->GetEnv();
2735 std::vector<napi_value> argv = {};
2736 do {
2737 char* flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
2738 if (argIndex == -1) {
2739 break;
2740 }
2741 flowbufIndex++;
2742 std::string str(flowbufStr);
2743
2744 napi_value napiValue = nullptr;
2745 napi_status s = napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &napiValue);
2746 if (s != napi_ok) {
2747 WVLOG_E("GetJavaScriptResultFlowbuf napi api call fail");
2748 } else {
2749 argv.push_back(napiValue);
2750 }
2751 } while (argIndex <= MAX_ENTRIES);
2752
2753 auto nwebId = GetNWebId();
2754 for (auto& input : args) {
2755 argv.push_back(ParseNwebValue2NapiValueV2(env, input, GetObjectMap(), nwebId, routingId));
2756 }
2757
2758 close(fd);
2759 WVLOG_D("get javaScript result, not in js thread, post task to js thread");
2760 PostGetJavaScriptResultToJsThreadV2(argv, method, routingId, objectId, result);
2761 }
2762 }
2763
GetJavaScriptObjectMethodsV2(int32_t objectId,std::shared_ptr<NWebHapValue> result)2764 void WebviewJavaScriptResultCallBack::GetJavaScriptObjectMethodsV2(
2765 int32_t objectId, std::shared_ptr<NWebHapValue> result)
2766 {
2767 if (!result) {
2768 return;
2769 }
2770
2771 result->SetType(NWebHapValue::Type::LIST);
2772 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
2773 if (!jsObj) {
2774 return;
2775 }
2776
2777 napi_env env = jsObj->GetEnv();
2778 auto engine = reinterpret_cast<NativeEngine*>(env);
2779 if (engine == nullptr) {
2780 return;
2781 }
2782
2783 if (pthread_self() == engine->GetTid()) {
2784 WVLOG_D("get javascript object methods already in js thread, objectId = %{public}d", objectId);
2785 NApiScope scope(env);
2786 if (!scope.IsVaild()) {
2787 return;
2788 }
2789
2790 auto methods = jsObj->GetMethodNames();
2791 for (auto& method : methods) {
2792 auto child = result->NewChildValue();
2793 child->SetString(method);
2794 result->SaveListChildValue();
2795 }
2796 } else {
2797 WVLOG_D("post task to js thread for get get javascript object methods, objectId = %{public}d", objectId);
2798 PostGetJavaScriptObjectMethodsToJsThreadV2(objectId, result);
2799 }
2800 }
2801
2802 } // namespace OHOS::NWeb
2803