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 "native_engine/native_engine.h"
24 #include "nweb_helper.h"
25 #include "nweb_log.h"
26 #include "ohos_adapter_helper.h"
27
28 namespace OHOS::NWeb {
29 namespace {
30 #define JS_BRIDGE_BINARY_ARGS_COUNT 2
31
32 const int MAX_FLOWBUF_DATA_SIZE = 52428800; /* 50MB*/
33 const int MAX_ENTRIES = 10;
34 const int HEADER_SIZE = (MAX_ENTRIES * 8); /* 10 * (int position + int length) */
35 const int INDEX_SIZE = 2;
36
37 // For the sake of the storage API, make this quite large.
38 const uint32_t MAX_RECURSION_DEPTH = 11;
39 const uint32_t MAX_DATA_LENGTH = 10000;
40
41 std::unordered_map<int32_t, WebviewJavaScriptResultCallBack*> g_webviewJsResultCallbackMap;
42 std::mutex g_objectMtx;
43
44 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value& value,
45 std::shared_ptr<NWebValue> nwebValue, bool* isObject);
46 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value* value,
47 std::shared_ptr<NWebValue> nwebValue, bool* isObject);
48
49 class ValueConvertState {
50 public:
51 // Level scope which updates the current depth of some ValueConvertState.
52 class Level {
53 public:
Level(ValueConvertState * state)54 explicit Level(ValueConvertState* state) : state_(state)
55 {
56 if (state_) {
57 state_->maxRecursionDepth_--;
58 }
59 }
~Level()60 ~Level()
61 {
62 if (state_) {
63 state_->maxRecursionDepth_++;
64 }
65 }
66
67 private:
68 ValueConvertState* state_;
69 };
70
ValueConvertState()71 explicit ValueConvertState() : maxRecursionDepth_(MAX_RECURSION_DEPTH)
72 {
73 }
74
75 ValueConvertState(const ValueConvertState&) = delete;
76 ValueConvertState& operator=(const ValueConvertState&) = delete;
77
HasReachedMaxRecursionDepth()78 bool HasReachedMaxRecursionDepth()
79 {
80 return maxRecursionDepth_ == 0;
81 }
82
83 private:
84 uint32_t maxRecursionDepth_;
85 };
86
FromNwebID(int32_t nwebId)87 WebviewJavaScriptResultCallBack* FromNwebID(int32_t nwebId)
88 {
89 std::unique_lock<std::mutex> lk(g_objectMtx);
90 if (auto it = g_webviewJsResultCallbackMap.find(nwebId); it != g_webviewJsResultCallbackMap.end()) {
91 auto js_result_callback = it->second;
92 return js_result_callback;
93 }
94 return nullptr;
95 }
96
StringSplit(std::string str,const char split,std::vector<std::string> & result)97 void StringSplit(std::string str, const char split, std::vector<std::string>& result)
98 {
99 std::istringstream iss(str);
100 std::string token;
101 while (getline(iss, token, split)) {
102 result.push_back(token);
103 }
104 }
105
CallH5Function(napi_env env,napi_value * napiArg,std::shared_ptr<NWebValue> nwebValue,WebviewJavaScriptResultCallBack::H5Bundle bundle)106 void CallH5Function(napi_env env, napi_value* napiArg, std::shared_ptr<NWebValue> nwebValue,
107 WebviewJavaScriptResultCallBack::H5Bundle bundle)
108 {
109 WVLOG_D("CallH5Function called");
110 bool isObject = false;
111 std::vector<std::string> methodNameList;
112 methodNameList = ParseNapiValue2NwebValue(env, napiArg, nwebValue, &isObject);
113 if (isObject && FromNwebID(bundle.nwebId)) {
114 JavaScriptOb::ObjectID returnedObjectId;
115 if (FromNwebID(bundle.nwebId)->FindObjectIdInJsTd(env, *napiArg, &returnedObjectId)) {
116 FromNwebID(bundle.nwebId)->FindObject(returnedObjectId)->AddHolder(bundle.frameRoutingId);
117 } else {
118 returnedObjectId = FromNwebID(bundle.nwebId)->AddObject(env, *napiArg, false, bundle.frameRoutingId);
119 }
120
121 FromNwebID(bundle.nwebId)->SetUpAnnotateMethods(returnedObjectId, methodNameList);
122
123 napi_valuetype valueType = napi_undefined;
124 napi_typeof(env, *napiArg, &valueType);
125 if (valueType == napi_function) {
126 WVLOG_D("CallH5Function function");
127 nwebValue = std::make_shared<NWebValue>();
128 } else {
129 WVLOG_D("CallH5Function object");
130 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
131 nwebValue = std::make_shared<NWebValue>(bin.c_str(), bin.size());
132 }
133 }
134 }
135
CallbackFunctionForH5(napi_env env,napi_callback_info info)136 napi_value CallbackFunctionForH5(napi_env env, napi_callback_info info)
137 {
138 WVLOG_D("CallbackFunctionForH5 called");
139 napi_escapable_handle_scope scope = nullptr;
140 napi_open_escapable_handle_scope(env, &scope);
141 napi_value h5CallBackResult = nullptr;
142 napi_value thisVar = nullptr;
143 size_t argc = 0;
144 void* data = nullptr;
145 napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);
146 napi_value* napiArgs = nullptr;
147 if (argc > 0) {
148 WVLOG_D("CallbackFunctionForH5 argc not zero");
149 napiArgs = new napi_value[argc];
150 if (!napiArgs) {
151 WVLOG_D("CallbackFunctionForH5 argc malloc fail");
152 napi_get_undefined(env, &h5CallBackResult);
153 napi_close_escapable_handle_scope(env, scope);
154 return h5CallBackResult;
155 }
156 }
157
158 napi_get_cb_info(env, info, &argc, napiArgs, &thisVar, &data);
159 WebviewJavaScriptResultCallBack::H5Bundle bundle =
160 *reinterpret_cast<WebviewJavaScriptResultCallBack::H5Bundle*>(data);
161
162 std::vector<std::shared_ptr<NWebValue>> nwebArgs;
163 for (size_t i = 0; i < argc; i++) {
164 std::shared_ptr<NWebValue> nwebArg = std::make_shared<NWebValue>(NWebValue::Type::NONE);
165 napi_value napiArg = napiArgs[i];
166 napi_escape_handle(env, scope, napiArg, &napiArg);
167 CallH5Function(env, &napiArg, nwebArg, bundle);
168 nwebArgs.push_back(nwebArg);
169 }
170
171 if (FromNwebID(bundle.nwebId)) {
172 FromNwebID(bundle.nwebId)->CallH5FunctionInternal(env, bundle, nwebArgs);
173 }
174
175 if (napiArgs) {
176 delete[] napiArgs;
177 }
178
179 napi_get_undefined(env, &h5CallBackResult);
180 napi_close_escapable_handle_scope(env, scope);
181 return h5CallBackResult;
182 }
183
CreateFunctionForH5(napi_env env,int32_t nwebId,int32_t frameRoutingId,int32_t h5ObjectId,std::string funcName)184 napi_value CreateFunctionForH5(
185 napi_env env, int32_t nwebId, int32_t frameRoutingId, int32_t h5ObjectId, std::string funcName)
186 {
187 // Create a bundle.
188 auto bundle = std::make_unique<OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle>();
189 bundle->nwebId = nwebId;
190 bundle->frameRoutingId = frameRoutingId;
191 bundle->h5Id = h5ObjectId;
192 bundle->funcName = funcName;
193
194 napi_value func = nullptr;
195 napi_status s = napi_ok;
196 s = napi_create_function(env, funcName.c_str(), funcName.size(), CallbackFunctionForH5, bundle.release(), &func);
197 if (s != napi_ok) {
198 WVLOG_E("CreateFunctionForH5 napi api call fail");
199 return nullptr;
200 }
201 return func;
202 }
203
AddFunctionToObjectForH5(napi_env env,OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle & bundle,napi_value obj)204 void AddFunctionToObjectForH5(
205 napi_env env, OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle& bundle, napi_value obj)
206 {
207 if (!obj || bundle.frameRoutingId < 0) {
208 WVLOG_D("AddFunctionToObjectForH5 obj or frame id error");
209 return;
210 }
211 napi_value func = CreateFunctionForH5(env, bundle.nwebId, bundle.frameRoutingId, bundle.h5Id, bundle.funcName);
212 if (!func) {
213 WVLOG_D("AddFunctionToObjectForH5 create func fail");
214 return;
215 }
216 napi_status s = napi_ok;
217 s = napi_set_named_property(env, obj, bundle.funcName.c_str(), func);
218 if (s != napi_ok) {
219 WVLOG_E("AddFunctionToObjectForH5 napi api call fail");
220 }
221 }
222
CreateProxyForH5Object(napi_env env,napi_value * result)223 void CreateProxyForH5Object(napi_env env, napi_value* result)
224 {
225 napi_status s = napi_ok;
226 s = napi_create_object(env, result);
227 if (s != napi_ok) {
228 WVLOG_E("CreateProxyFOrH5Object napi api call fail");
229 }
230 }
231
OpenScope(napi_env env)232 napi_handle_scope OpenScope(napi_env env)
233 {
234 napi_handle_scope scope = nullptr;
235 NAPI_CALL(env, napi_open_handle_scope(env, &scope));
236 return scope;
237 }
238
CloseScope(napi_env env,napi_handle_scope scope)239 void CloseScope(napi_env env, napi_handle_scope scope)
240 {
241 (void)napi_close_handle_scope(env, scope);
242 }
243
CreateUvQueueWorkEnhanced(napi_env env,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * data,void (* handler)(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * data))244 void CreateUvQueueWorkEnhanced(napi_env env, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data,
245 void (*handler)(napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data))
246 {
247 uv_loop_s* loop = nullptr;
248 NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
249 class WorkData {
250 public:
251 WorkData() = delete;
252
253 WorkData(napi_env env, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data,
254 void (*handler)(
255 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data))
256 : env_(env), data_(data), handler_(handler)
257 {}
258
259 napi_env env_;
260 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data_;
261 void (*handler_)(napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* data);
262 };
263
264 auto workData = new WorkData(env, data, handler);
265 auto work = new uv_work_t;
266 work->data = reinterpret_cast<void*>(workData);
267
268 auto callback = [](uv_work_t* work, int status) {
269 auto workData = static_cast<WorkData*>(work->data);
270 if (!workData) {
271 delete work;
272 return;
273 }
274
275 if (!workData->env_ || !workData->data_ || !workData->handler_) {
276 delete workData;
277 delete work;
278 return;
279 }
280
281 napi_env env = workData->env_;
282 auto closeScope = [env](napi_handle_scope scope) { CloseScope(env, scope); };
283 std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(OpenScope(env), closeScope);
284
285 workData->handler_(workData->env_, static_cast<napi_status>(status), workData->data_);
286
287 delete workData;
288 delete work;
289 };
290 int ret = uv_queue_work_with_qos(
291 loop, work, [](uv_work_t* work) {}, callback, uv_qos_user_initiated);
292 if (ret != 0) {
293 if (workData) {
294 delete workData;
295 workData = nullptr;
296 }
297 if (work) {
298 delete work;
299 work = nullptr;
300 }
301 return;
302 }
303 }
304
CreateNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm * & inParam,WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm * & outParam,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * & param)305 bool CreateNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*& inParam,
306 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*& outParam,
307 WebviewJavaScriptResultCallBack::NapiJsCallBackParm*& param)
308 {
309 inParam = new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackInParm();
310 if (inParam == nullptr) {
311 WVLOG_D("CreateNapiJsCallBackParm argc malloc fail");
312 return false;
313 }
314 outParam = new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm();
315 if (outParam == nullptr) {
316 WVLOG_D("CreateNapiJsCallBackParm argc malloc fail");
317 delete inParam;
318 return false;
319 }
320 param = new (std::nothrow) WebviewJavaScriptResultCallBack::NapiJsCallBackParm();
321 if (param == nullptr) {
322 WVLOG_D("CreateNapiJsCallBackParm argc malloc fail");
323 delete inParam;
324 delete outParam;
325 return false;
326 }
327 return true;
328 }
329
DeleteNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm * inParam,WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm * outParam,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)330 void DeleteNapiJsCallBackParm(WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam,
331 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam,
332 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
333 {
334 if (inParam != nullptr) {
335 delete inParam;
336 inParam = nullptr;
337 }
338
339 if (outParam != nullptr) {
340 delete outParam;
341 outParam = nullptr;
342 }
343
344 if (param != nullptr) {
345 delete param;
346 param = nullptr;
347 }
348 }
349
350 napi_value ParseArrayNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
351 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId);
352 napi_value ParseDictionaryNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
353 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId);
354 napi_value ParseBinNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
355 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId);
356
357 void ParseDictionaryNapiValue2NwebValue(
358 napi_env env, ValueConvertState* state, napi_value& value, std::shared_ptr<NWebValue>& nwebValue, bool* isOject);
359
ParseBasicTypeNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,napi_value & napiValue)360 bool ParseBasicTypeNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value, napi_value& napiValue)
361 {
362 napi_status s = napi_ok;
363 switch (value->GetType()) {
364 case NWebValue::Type::INTEGER:
365 WVLOG_D("ParseBasicTypeNwebValue2NapiValue INTEGER type");
366 s = napi_create_int32(env, value->GetInt(), &napiValue);
367 if (s != napi_ok) {
368 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
369 }
370 break;
371 case NWebValue::Type::DOUBLE:
372 WVLOG_D("ParseBasicTypeNwebValue2NapiValue DOUBLE type");
373 s = napi_create_double(env, value->GetDouble(), &napiValue);
374 if (s != napi_ok) {
375 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
376 }
377 break;
378 case NWebValue::Type::BOOLEAN:
379 WVLOG_D("ParseBasicTypeNwebValue2NapiValue BOOLEAN type");
380 s = napi_get_boolean(env, value->GetBoolean(), &napiValue);
381 if (s != napi_ok) {
382 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
383 }
384 break;
385 case NWebValue::Type::STRING:
386 WVLOG_D("ParseBasicTypeNwebValue2NapiValue STRING type");
387 s = napi_create_string_utf8(env, value->GetString().c_str(), NAPI_AUTO_LENGTH, &napiValue);
388 if (s != napi_ok) {
389 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
390 }
391 break;
392 default:
393 return false;
394 }
395 return true;
396 }
397
ParseNwebValue2NapiValueHelper(napi_env env,std::shared_ptr<NWebValue> value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)398 napi_value ParseNwebValue2NapiValueHelper(napi_env env, std::shared_ptr<NWebValue> value,
399 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
400 {
401 napi_value napiValue = nullptr;
402 if (!value) {
403 napi_get_undefined(env, &napiValue);
404 return napiValue;
405 }
406 if (ParseBasicTypeNwebValue2NapiValue(env, value, napiValue)) {
407 return napiValue;
408 }
409 switch (value->GetType()) {
410 case NWebValue::Type::LIST: {
411 WVLOG_D("ParseBasicTypeNwebValue2NapiValue LIST type");
412 napiValue = ParseArrayNwebValue2NapiValue(env, value, objectsMap, nwebId, frameId);
413 return napiValue;
414 }
415 case NWebValue::Type::DICTIONARY: {
416 WVLOG_D("ParseBasicTypeNwebValue2NapiValue DICTIONARY type");
417 napiValue = ParseDictionaryNwebValue2NapiValue(env, value, objectsMap, nwebId, frameId);
418 return napiValue;
419 }
420 case NWebValue::Type::BINARY: {
421 WVLOG_D("ParseBasicTypeNwebValue2NapiValue BINARY type");
422 napiValue = ParseBinNwebValue2NapiValue(env, value, objectsMap, nwebId, frameId);
423 return napiValue;
424 }
425 case NWebValue::Type::NONE: {
426 WVLOG_D("ParseBasicTypeNwebValue2NapiValue NONE type");
427 break;
428 }
429 default:
430 WVLOG_E("ParseNwebValue2NapiValueHelper invalid type");
431 break;
432 }
433 napi_get_undefined(env, &napiValue);
434 return napiValue;
435 }
436
ParseArrayNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)437 napi_value ParseArrayNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
438 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
439 {
440 napi_value napiValue = nullptr;
441 napi_status s = napi_ok;
442 size_t length = value->GetListValueSize();
443 s = napi_create_array_with_length(env, length, &napiValue);
444 if (s != napi_ok) {
445 WVLOG_E("ParseArrayNwebValue2NapiValue napi api call fail");
446 return napiValue;
447 }
448 for (size_t i = 0; i < length; ++i) {
449 auto nPtr = std::make_shared<NWebValue>(value->GetListValue(i));
450 s = napi_set_element(env, napiValue, i, ParseNwebValue2NapiValueHelper(env, nPtr, objectsMap, nwebId, frameId));
451 if (s != napi_ok) {
452 WVLOG_E("ParseArrayNwebValue2NapiValue napi api call fail");
453 }
454 }
455 return napiValue;
456 }
457
ParseDictionaryNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)458 napi_value ParseDictionaryNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
459 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
460 {
461 napi_value napiValue = nullptr;
462 napi_status s = napi_ok;
463 s = napi_create_object(env, &napiValue);
464 auto dict = value->GetDictionaryValue();
465 for (auto& item : dict) {
466 auto nValuePtr = std::make_shared<NWebValue>(item.second);
467 auto nKeyPtr = std::make_shared<NWebValue>(item.first);
468 s = napi_set_property(env, napiValue, ParseNwebValue2NapiValueHelper(env, nKeyPtr, objectsMap, nwebId, frameId),
469 ParseNwebValue2NapiValueHelper(env, nValuePtr, objectsMap, nwebId, frameId));
470 if (s != napi_ok) {
471 WVLOG_E("ParseDictionaryNwebValue2NapiValue napi api call fail");
472 }
473 }
474 return napiValue;
475 }
476
ParseBinNwebValue2NapiValue(napi_env env,const std::shared_ptr<NWebValue> & value,WebviewJavaScriptResultCallBack::ObjectMap & objectsMap,int32_t nwebId,int32_t frameId)477 napi_value ParseBinNwebValue2NapiValue(napi_env env, const std::shared_ptr<NWebValue>& value,
478 WebviewJavaScriptResultCallBack::ObjectMap& objectsMap, int32_t nwebId, int32_t frameId)
479 {
480 napi_value napiValue = nullptr;
481 napi_get_undefined(env, &napiValue);
482 auto buff = value->GetBinaryValue();
483 JavaScriptOb::ObjectID objId;
484 std::string str(buff);
485 std::vector<std::string> strList;
486 StringSplit(str, ';', strList);
487 if (strList.size() < JS_BRIDGE_BINARY_ARGS_COUNT) {
488 napi_get_undefined(env, &napiValue);
489 return napiValue;
490 }
491 std::istringstream ss(strList[1]);
492 ss >> objId;
493 if (strList[0] == "TYPE_OBJECT_ID") {
494 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_OBJECT_ID");
495 auto iter = objectsMap.find(objId);
496 if (iter != objectsMap.end() && iter->second) {
497 WVLOG_I("ParseNwebValue2NapiValueHelper: type is "
498 "binary, object is found and object_id == %{public}d",
499 objId);
500 napiValue = iter->second->GetValue();
501 }
502 return napiValue;
503 } else if (strList[0] == "TYPE_H5_OBJECT_ID") {
504 CreateProxyForH5Object(env, &napiValue);
505 std::vector<std::string> methodNames;
506 methodNames.assign(strList.begin() + JS_BRIDGE_BINARY_ARGS_COUNT, strList.end()); // skip id and type
507 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_H5_OBJECT_ID");
508 for (auto name : methodNames) {
509 OHOS::NWeb::WebviewJavaScriptResultCallBack::H5Bundle bundle;
510 bundle.nwebId = nwebId;
511 bundle.frameRoutingId = frameId;
512 bundle.h5Id = objId;
513 bundle.funcName = name;
514 AddFunctionToObjectForH5(env, bundle, napiValue);
515 }
516 return napiValue;
517 } else if (strList[0] == "TYPE_H5_FUNCTION_ID") {
518 WVLOG_D("ParseNwebValue2NapiValueHelper: TYPE_H5_FUNCTION_ID");
519 napiValue = CreateFunctionForH5(env, nwebId, frameId, objId, "");
520 return napiValue;
521 }
522 return napiValue;
523 }
524
ParseNwebValue2NapiValue(napi_env env,std::shared_ptr<NWebValue> value,WebviewJavaScriptResultCallBack::ObjectMap objectsMap,int32_t nwebId,int32_t frameId)525 napi_value ParseNwebValue2NapiValue(napi_env env, std::shared_ptr<NWebValue> value,
526 WebviewJavaScriptResultCallBack::ObjectMap objectsMap, int32_t nwebId, int32_t frameId)
527 {
528 return ParseNwebValue2NapiValueHelper(env, value, objectsMap, nwebId, frameId);
529 }
530
ParseBasicTypeNapiValue2NwebValue(napi_env env,napi_value & value,std::shared_ptr<NWebValue> & nwebValue,bool * isObject)531 bool ParseBasicTypeNapiValue2NwebValue(napi_env env, napi_value& value,
532 std::shared_ptr<NWebValue>& nwebValue, bool* isObject)
533 {
534 napi_valuetype valueType = napi_undefined;
535 napi_typeof(env, value, &valueType);
536 napi_status s = napi_ok;
537 switch (valueType) {
538 case napi_undefined: // fallthrough
539 case napi_null:
540 WVLOG_D("ParseBasicTypeNapiValue2NwebValue null or undefined type");
541 nwebValue->SetType(NWebValue::Type::NONE);
542 break;
543 case napi_number: {
544 WVLOG_D("ParseBasicTypeNapiValue2NwebValue number type");
545 double douVal = 0.0;
546 s = napi_get_value_double(env, value, &douVal);
547 nwebValue->SetType(NWebValue::Type::DOUBLE);
548 nwebValue->SetDouble(douVal);
549 break;
550 }
551 case napi_boolean: {
552 WVLOG_D("ParseBasicTypeNapiValue2NwebValue boolean type");
553 bool boolVal;
554 s = napi_get_value_bool(env, value, &boolVal);
555 nwebValue->SetType(NWebValue::Type::BOOLEAN);
556 nwebValue->SetBoolean(boolVal);
557 break;
558 }
559 case napi_symbol: // fallthrough
560 case napi_string: {
561 WVLOG_D("ParseBasicTypeNapiValue2NwebValue string type");
562 std::string strVal;
563 if (!NapiParseUtils::ParseString(env, value, strVal)) {
564 WVLOG_E("ParseBasicTypeNapiValue2NwebValue NapiParseUtils::ParseString "
565 "failed");
566 }
567 if (strVal == "methodNameListForJsProxy") {
568 *isObject = true;
569 }
570 nwebValue->SetType(NWebValue::Type::STRING);
571 nwebValue->SetString(strVal);
572 break;
573 }
574 default: {
575 WVLOG_D("ParseBasicTypeNapiValue2NwebValue invalid type");
576 return false;
577 }
578 }
579 return true;
580 }
581
ParseNapiValue2NwebValueHelper(napi_env env,ValueConvertState * state,napi_value & value,std::shared_ptr<NWebValue> nwebValue,bool * isOject)582 void ParseNapiValue2NwebValueHelper(
583 napi_env env, ValueConvertState* state, napi_value& value,
584 std::shared_ptr<NWebValue> nwebValue, bool* isOject)
585 {
586 ValueConvertState::Level stateLevel(state);
587 if (state->HasReachedMaxRecursionDepth()) {
588 return;
589 }
590 if (!nwebValue || ParseBasicTypeNapiValue2NwebValue(env, value, nwebValue, isOject)) {
591 return;
592 }
593 napi_valuetype valueType = napi_undefined;
594 napi_typeof(env, value, &valueType);
595 napi_status s = napi_ok;
596 switch (valueType) {
597 case napi_object: {
598 bool isArray;
599 s = napi_is_array(env, value, &isArray);
600 if (s != napi_ok) {
601 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
602 }
603 if (!isArray) {
604 WVLOG_D("ParseNapiValue2NwebValueHelper napi isArray");
605 ParseDictionaryNapiValue2NwebValue(env, state, value, nwebValue, isOject);
606 break;
607 }
608 nwebValue->SetType(NWebValue::Type::LIST);
609 uint32_t size;
610 s = napi_get_array_length(env, value, &size);
611 size = std::min(size, MAX_DATA_LENGTH);
612 if (s != napi_ok) {
613 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
614 }
615 for (uint32_t i = 0; i < size; i++) {
616 napi_value napiTmp;
617 s = napi_get_element(env, value, i, &napiTmp);
618 if (s != napi_ok) {
619 WVLOG_E("ParseNapiValue2NwebValueHelper napi api call fail");
620 }
621 auto nwebTmp = std::make_shared<NWebValue>();
622 ParseNapiValue2NwebValueHelper(env, state, napiTmp, nwebTmp, isOject);
623 nwebValue->AddListValue(*nwebTmp);
624 }
625 break;
626 }
627 default: {
628 WVLOG_E("ParseNapiValue2NwebValueHelper invalid type");
629 }
630 }
631 }
632
ParseDictionaryNapiValue2NwebValue(napi_env env,ValueConvertState * state,napi_value & value,std::shared_ptr<NWebValue> & nwebValue,bool * isOject)633 void ParseDictionaryNapiValue2NwebValue(
634 napi_env env, ValueConvertState* state, napi_value& value, std::shared_ptr<NWebValue>& nwebValue, bool* isOject)
635 {
636 napi_status s = napi_ok;
637 nwebValue->SetType(NWebValue::Type::DICTIONARY);
638 napi_value propertyNames;
639 s = napi_get_property_names(env, value, &propertyNames);
640 if (s != napi_ok) {
641 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
642 }
643 uint32_t size;
644 s = napi_get_array_length(env, propertyNames, &size);
645 size = std::min(size, MAX_DATA_LENGTH);
646 if (s != napi_ok) {
647 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
648 }
649
650 for (uint32_t i = 0; i < size; i++) {
651 napi_value napiKeyTmp;
652 s = napi_get_element(env, propertyNames, i, &napiKeyTmp);
653 if (s != napi_ok) {
654 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
655 }
656 bool hasOwnProperty = false;
657 s = napi_has_own_property(env, value, napiKeyTmp, &hasOwnProperty);
658 if (s != napi_ok) {
659 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
660 }
661 if (!hasOwnProperty) {
662 continue;
663 }
664 napi_value napiValueTmp;
665 s = napi_get_property(env, value, napiKeyTmp, &napiValueTmp);
666 if (s != napi_ok) {
667 WVLOG_E("ParseDictionaryNapiValue2NwebValue napi api call fail");
668 }
669 auto nwebValueTmp = std::make_shared<NWebValue>();
670 auto nwebKeyTmp = std::make_shared<NWebValue>();
671 ParseNapiValue2NwebValueHelper(env, state, napiKeyTmp, nwebKeyTmp, isOject);
672 ParseNapiValue2NwebValueHelper(env, state, napiValueTmp, nwebValueTmp, isOject);
673 nwebValue->AddDictionaryValue(nwebKeyTmp->GetString(), *nwebValueTmp);
674 }
675 }
676
HasAnnotationProperty(napi_env env,napi_value & value)677 bool HasAnnotationProperty(napi_env env, napi_value& value)
678 {
679 std::string annotation = "methodNameListForJsProxy";
680 napi_status s = napi_ok;
681 bool hasProperty = false;
682 napi_value napi_str;
683 s = napi_create_string_utf8(env, annotation.c_str(), NAPI_AUTO_LENGTH,
684 &napi_str);
685 if (s != napi_ok) {
686 WVLOG_E("HasAnnotationProperty napi api call fail");
687 }
688 s = napi_has_own_property(env, value, napi_str, &hasProperty);
689 if (s != napi_ok) {
690 WVLOG_D("HasAnnotationProperty napi api call fail");
691 }
692 WVLOG_D(
693 "HasAnnotationProperty hasProperty = "
694 "%{public}d",
695 hasProperty);
696 return hasProperty;
697 }
698
IsCallableObject(napi_env env,napi_value & value,std::vector<std::string> * methodNameList)699 bool IsCallableObject(napi_env env,
700 napi_value& value,
701 std::vector<std::string>* methodNameList)
702 {
703 std::string annotation = "methodNameListForJsProxy";
704 napi_status s = napi_ok;
705 napi_value napi_str;
706 s = napi_create_string_utf8(env, annotation.c_str(), NAPI_AUTO_LENGTH,
707 &napi_str);
708 if (s != napi_ok) {
709 WVLOG_E("IsCallableObject napi api call fail");
710 }
711 if (!HasAnnotationProperty(env, value)) {
712 return false;
713 }
714 napi_value result;
715 s = napi_get_property(env, value, napi_str, &result);
716 if (s != napi_ok) {
717 WVLOG_E("IsCallableObject napi api call fail");
718 }
719 bool isArray = false;
720 s = napi_is_array(env, result, &isArray);
721 if (s != napi_ok) {
722 WVLOG_E("IsCallableObject napi api call fail");
723 }
724 if (!isArray) {
725 return false;
726 }
727 uint32_t size;
728 s = napi_get_array_length(env, result, &size);
729 if (s != napi_ok) {
730 WVLOG_E("IsCallableObject napi api call fail");
731 }
732 for (uint32_t i = 0; i < size; i++) {
733 napi_value napiTmp;
734 s = napi_get_element(env, result, i, &napiTmp);
735 if (s != napi_ok) {
736 WVLOG_E("IsCallableObject napi api call fail");
737 }
738 napi_valuetype valueType = napi_undefined;
739 napi_typeof(env, napiTmp, &valueType);
740 if (valueType != napi_string) {
741 continue;
742 }
743 std::string strVal;
744 if (!NapiParseUtils::ParseString(env, napiTmp, strVal)) {
745 WVLOG_E("IsCallableObject NapiParseUtils::ParseString failed");
746 }
747 methodNameList->push_back(strVal);
748 }
749 return true;
750 }
751
ParseNapiValue2NwebValue(napi_env env,napi_value & value,std::shared_ptr<NWebValue> nwebValue,bool * isObject)752 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value& value,
753 std::shared_ptr<NWebValue> nwebValue, bool* isObject)
754 {
755 napi_status s = napi_ok;
756 std::vector<std::string> methodNameList;
757
758 s = napi_is_promise(env, value, isObject);
759 if (s != napi_ok) {
760 WVLOG_E("ParseNapiValue2NwebValue napi api call fail");
761 }
762
763 if (*isObject) {
764 return std::vector<std::string>{"then", "catch", "finally"};
765 }
766
767 if (IsCallableObject(env, value, &methodNameList)) {
768 *isObject = true;
769 return methodNameList;
770 }
771
772 ValueConvertState state;
773 bool isObjectForRecursion = false; // FixMe: for Recursion case, now not use
774 ParseNapiValue2NwebValueHelper(env, &state, value, nwebValue, &isObjectForRecursion);
775 return methodNameList;
776 }
777
ParseNapiValue2NwebValue(napi_env env,napi_value * value,std::shared_ptr<NWebValue> nwebValue,bool * isObject)778 std::vector<std::string> ParseNapiValue2NwebValue(napi_env env, napi_value* value,
779 std::shared_ptr<NWebValue> nwebValue, bool* isObject)
780 {
781 napi_status s = napi_ok;
782 std::vector<std::string> methodNameList;
783
784 s = napi_is_promise(env, *value, isObject);
785 if (s != napi_ok) {
786 WVLOG_E("ParseNapiValue2NwebValue napi api call fail");
787 }
788
789 if (*isObject) {
790 return std::vector<std::string>{"then", "catch", "finally"};
791 }
792
793 if (IsCallableObject(env, *value, &methodNameList)) {
794 *isObject = true;
795 return methodNameList;
796 }
797
798 ValueConvertState state;
799 bool isObjectForRecursion = false; // FixMe: for Recursion case, now not use
800 ParseNapiValue2NwebValueHelper(env, &state, *value, nwebValue, &isObjectForRecursion);
801 return methodNameList;
802 }
803 } // namespace
804
CreateNamed(napi_env env,int32_t containerScopeId,napi_value value,size_t refCount)805 std::shared_ptr<JavaScriptOb> JavaScriptOb::CreateNamed(
806 napi_env env, int32_t containerScopeId, napi_value value, size_t refCount)
807 {
808 return std::make_shared<JavaScriptOb>(env, containerScopeId, value, refCount);
809 }
CreateTransient(napi_env env,int32_t containerScopeId,napi_value value,int32_t holder,size_t refCount)810 std::shared_ptr<JavaScriptOb> JavaScriptOb::CreateTransient(
811 napi_env env, int32_t containerScopeId, napi_value value, int32_t holder, size_t refCount)
812 {
813 std::set<int32_t> holders;
814 holders.insert(holder);
815 return std::make_shared<JavaScriptOb>(env, containerScopeId, value, holders, refCount);
816 }
817
JavaScriptOb(napi_env env,int32_t containerScopeId,napi_value value,size_t refCount)818 JavaScriptOb::JavaScriptOb(napi_env env, int32_t containerScopeId, napi_value value, size_t refCount)
819 : env_(env), containerScopeId_(containerScopeId), isStrongRef_(refCount != 0), namesCount_(1)
820 {
821 napi_status s = napi_create_reference(env, value, refCount, &objRef_);
822 if (s != napi_ok) {
823 WVLOG_E("create javascript obj fail");
824 }
825 }
826
JavaScriptOb(napi_env env,int32_t containerScopeId,napi_value value,std::set<int32_t> holders,size_t refCount)827 JavaScriptOb::JavaScriptOb(
828 napi_env env, int32_t containerScopeId, napi_value value, std::set<int32_t> holders, size_t refCount)
829 : env_(env), containerScopeId_(containerScopeId), isStrongRef_(refCount != 0), namesCount_(0), holders_(holders)
830 {
831 std::unique_lock<std::mutex> lock(mutex_);
832 napi_status s = napi_create_reference(env, value, refCount, &objRef_);
833 if (s != napi_ok) {
834 WVLOG_E("create javascript obj fail");
835 }
836 }
837
WebviewJavaScriptResultCallBack(int32_t nwebId)838 WebviewJavaScriptResultCallBack::WebviewJavaScriptResultCallBack(int32_t nwebId)
839 : nwebId_(nwebId)
840 {
841 std::unique_lock<std::mutex> lk(g_objectMtx);
842 g_webviewJsResultCallbackMap.emplace(nwebId, this);
843 }
844
~WebviewJavaScriptResultCallBack()845 WebviewJavaScriptResultCallBack::~WebviewJavaScriptResultCallBack()
846 {
847 std::unique_lock<std::mutex> lk(g_objectMtx);
848 g_webviewJsResultCallbackMap.erase(nwebId_);
849 }
850
FindObject(JavaScriptOb::ObjectID objectId)851 std::shared_ptr<JavaScriptOb> WebviewJavaScriptResultCallBack::FindObject(JavaScriptOb::ObjectID objectId)
852 {
853 auto iter = objects_.find(objectId);
854 if (iter != objects_.end()) {
855 return iter->second;
856 }
857 WVLOG_E("WebviewJavaScriptResultCallBack::FindObject Unknown object: objectId = "
858 "%{public}d",
859 objectId);
860 return nullptr;
861 }
862
ProcessObjectCaseInJsTd(napi_env env,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param,napi_value callResult,std::vector<std::string> & methodNameList)863 void ProcessObjectCaseInJsTd(
864 napi_env env, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param,
865 napi_value callResult, std::vector<std::string>& methodNameList)
866 {
867 if (!param) {
868 WVLOG_E("WebviewJavaScriptResultCallBack::ProcessObjectCaseInJsTd param null");
869 return;
870 }
871
872 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
873 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
874 JavaScriptOb::ObjectID returnedObjectId;
875
876 if (inParam->webJsResCb->FindObjectIdInJsTd(env, callResult, &returnedObjectId)) {
877 inParam->webJsResCb->FindObject(returnedObjectId)->AddHolder(inParam->frameRoutingId);
878 } else {
879 returnedObjectId = inParam->webJsResCb->AddObject(env, callResult, false, inParam->frameRoutingId);
880 }
881
882 inParam->webJsResCb->SetUpAnnotateMethods(returnedObjectId, methodNameList);
883
884 napi_valuetype valueType = napi_undefined;
885 napi_typeof(env, callResult, &valueType);
886 if (valueType == napi_function) {
887 WVLOG_D("WebviewJavaScriptResultCallBack::ProcessObjectCaseInJsTd type is function");
888 *(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)) = std::make_shared<NWebValue>();
889 } else {
890 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
891 *(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)) =
892 std::make_shared<NWebValue>(bin.c_str(), bin.size());
893 }
894 }
895
ExecuteGetJavaScriptResult(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)896 void ExecuteGetJavaScriptResult(
897 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
898 {
899 WVLOG_D("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult called");
900 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
901 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
902 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
903 if (!jsObj) {
904 std::unique_lock<std::mutex> lock(param->mutex);
905 param->ready = true;
906 param->condition.notify_all();
907 return;
908 }
909 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
910 napi_handle_scope scope = nullptr;
911 napi_open_handle_scope(env, &scope);
912 if (scope == nullptr) {
913 std::unique_lock<std::mutex> lock(param->mutex);
914 param->ready = true;
915 param->condition.notify_all();
916 return;
917 }
918 if (jsObj && (jsObj->HasMethod(inParam->methodName))) {
919 std::vector<napi_value> argv = {};
920 auto nwebArgs = *(static_cast<std::vector<std::shared_ptr<NWebValue>>*>(inParam->data));
921 for (std::shared_ptr<NWebValue> input : nwebArgs) {
922 argv.push_back(ParseNwebValue2NapiValue(
923 env, input, inParam->webJsResCb->GetObjectMap(), inParam->nwebId, inParam->frameRoutingId));
924 }
925 napi_value callback = jsObj->FindMethod(inParam->methodName);
926 if (!callback) {
927 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
928 }
929 napi_value callResult = nullptr;
930 napi_call_function(env, jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
931 bool isObject = false;
932 std::vector<std::string> methodNameList;
933 methodNameList = ParseNapiValue2NwebValue(
934 env, callResult, *(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)), &isObject);
935 if (isObject) {
936 ProcessObjectCaseInJsTd(env, param, callResult, methodNameList);
937 }
938 }
939
940 napi_close_handle_scope(env, scope);
941 std::unique_lock<std::mutex> lock(param->mutex);
942 param->ready = true;
943 param->condition.notify_all();
944 }
945
GetJavaScriptResultSelf(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int32_t routingId,int32_t objectId)946 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf(
947 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName,
948 int32_t routingId, int32_t objectId)
949 {
950 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
951 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
952 if (!jsObj) {
953 return ret;
954 }
955 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
956 napi_handle_scope scope = nullptr;
957 napi_open_handle_scope(jsObj->GetEnv(), &scope);
958 if (scope == nullptr) {
959 return ret;
960 }
961
962 WVLOG_D("get javaScript result already in js thread");
963 std::vector<napi_value> argv = {};
964 for (std::shared_ptr<NWebValue> input : args) {
965 argv.push_back(ParseNwebValue2NapiValue(jsObj->GetEnv(), input, GetObjectMap(), GetNWebId(), routingId));
966 }
967 napi_value callback = jsObj->FindMethod(method);
968 if (!callback) {
969 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
970 }
971 napi_value callResult = nullptr;
972 napi_call_function(jsObj->GetEnv(), jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
973 bool isObject = false;
974 std::vector<std::string> methodNameList;
975 methodNameList = ParseNapiValue2NwebValue(jsObj->GetEnv(), &callResult, ret, &isObject);
976 napi_valuetype valueType = napi_undefined;
977 napi_typeof(jsObj->GetEnv(), callResult, &valueType);
978 WVLOG_D("get javaScript result already in js thread end");
979 if (isObject) {
980 JavaScriptOb::ObjectID returnedObjectId;
981 if (FindObjectIdInJsTd(jsObj->GetEnv(), callResult, &returnedObjectId)) {
982 FindObject(returnedObjectId)->AddHolder(routingId);
983 } else {
984 returnedObjectId = AddObject(jsObj->GetEnv(), callResult, false, routingId);
985 }
986 SetUpAnnotateMethods(returnedObjectId, methodNameList);
987 if (valueType == napi_function) {
988 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is function");
989 ret = std::make_shared<NWebValue>();
990 } else {
991 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is object");
992 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
993 ret = std::make_shared<NWebValue>(bin.c_str(), bin.size());
994 }
995 }
996 napi_close_handle_scope(jsObj->GetEnv(), scope);
997 return ret;
998 }
999
GetJavaScriptResult(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int32_t routingId,int32_t objectId)1000 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResult(
1001 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName,
1002 int32_t routingId, int32_t objectId)
1003 {
1004 (void)objName; // to be compatible with older webcotroller, classname may be empty
1005 WVLOG_D(
1006 "GetJavaScriptResult objName = %{public}s, method = %{public}s, "
1007 "routingId = %{public}d, objectId = %{public}d",
1008 objName.c_str(), method.c_str(), routingId, objectId);
1009 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1010 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1011 if (!jsObj || !jsObj->HasMethod(method)) {
1012 return ret;
1013 }
1014
1015 auto engine = reinterpret_cast<NativeEngine*>(jsObj->GetEnv());
1016 if (engine == nullptr) {
1017 return ret;
1018 }
1019
1020 if (pthread_self() == engine->GetTid()) {
1021 return GetJavaScriptResultSelf(args, method, objName, routingId, objectId);
1022 } else {
1023 WVLOG_D("get javaScript result, not in js thread, post task to js thread");
1024 return PostGetJavaScriptResultToJsThread(args, method, objName, routingId, objectId);
1025 }
1026 }
1027
FlowbufStrAtIndex(void * mem,int flowbufIndex,int * argIndex,int * strLen)1028 char* WebviewJavaScriptResultCallBack::FlowbufStrAtIndex(void* mem, int flowbufIndex, int* argIndex, int* strLen)
1029 {
1030 int* header = static_cast<int*>(mem); // Cast the memory block to int* for easier access
1031 int offset = 0;
1032
1033 if (flowbufIndex >= MAX_ENTRIES) {
1034 *argIndex = -1;
1035 return nullptr;
1036 }
1037
1038 int* entry = header + (flowbufIndex * INDEX_SIZE);
1039 if (*(entry + 1) == 0) { // Check if length is 0, indicating unused entry
1040 *argIndex = -1;
1041 return nullptr;
1042 }
1043
1044 int i = 0;
1045 for (i = 0; i < flowbufIndex; i++) {
1046 offset += *(header + (i * INDEX_SIZE) + 1);
1047 }
1048
1049 *strLen = *(header + (i * INDEX_SIZE) + 1) - 1;
1050
1051 *argIndex = *entry;
1052
1053 char* dataSegment = static_cast<char*>(mem) + HEADER_SIZE;
1054 char* currentString = dataSegment + offset;
1055 return currentString;
1056 }
1057
ConstructArgv(void * ashmem,std::vector<std::shared_ptr<NWebValue>> args,std::vector<napi_value> & argv,std::shared_ptr<JavaScriptOb> jsObj,int32_t routingId)1058 bool WebviewJavaScriptResultCallBack::ConstructArgv(void* ashmem,
1059 std::vector<std::shared_ptr<NWebValue>> args,
1060 std::vector<napi_value>& argv,
1061 std::shared_ptr<JavaScriptOb> jsObj,
1062 int32_t routingId)
1063 {
1064 int argIndex = -1;
1065 int currIndex = 0;
1066 int flowbufIndex = 0;
1067 int strLen = 0;
1068 char* flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1069 flowbufIndex++;
1070 while (argIndex == currIndex) {
1071 napi_value napiValue = nullptr;
1072 napi_status s = napi_ok;
1073 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
1074 if (s != napi_ok) {
1075 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
1076 return false;
1077 }
1078 argv.push_back(napiValue);
1079 currIndex++;
1080 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1081 flowbufIndex++;
1082 }
1083
1084 for (std::shared_ptr<NWebValue> input : args) {
1085 while (argIndex == currIndex) {
1086 napi_value napiValue = nullptr;
1087 napi_status s = napi_ok;
1088 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
1089 if (s != napi_ok) {
1090 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
1091 }
1092 argv.push_back(napiValue);
1093 currIndex ++;
1094 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1095 flowbufIndex++;
1096 }
1097
1098 argv.push_back(ParseNwebValue2NapiValue(jsObj->GetEnv(), input, GetObjectMap(), GetNWebId(), routingId));
1099 currIndex++;
1100 }
1101
1102 while (argIndex == currIndex) {
1103 napi_value napiValue = nullptr;
1104 napi_status s = napi_ok;
1105 s = napi_create_string_utf8(jsObj->GetEnv(), flowbufStr, strLen, &napiValue);
1106 if (s != napi_ok) {
1107 WVLOG_E("ParseBasicTypeNwebValue2NapiValue napi api call fail");
1108 }
1109 argv.push_back(napiValue);
1110 currIndex++;
1111 flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1112 flowbufIndex++;
1113 }
1114 return true;
1115 }
1116
GetJavaScriptResultSelfHelper(std::shared_ptr<JavaScriptOb> jsObj,const std::string & method,int32_t routingId,napi_handle_scope scope,std::vector<napi_value> argv)1117 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultSelfHelper(
1118 std::shared_ptr<JavaScriptOb> jsObj,
1119 const std::string& method,
1120 int32_t routingId,
1121 napi_handle_scope scope,
1122 std::vector<napi_value> argv)
1123 {
1124 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1125 napi_value callback = jsObj->FindMethod(method);
1126 if (!callback) {
1127 WVLOG_E("WebviewJavaScriptResultCallBack::ExecuteGetJavaScriptResult callback null");
1128 }
1129 napi_value callResult = nullptr;
1130 napi_call_function(jsObj->GetEnv(), jsObj->GetValue(), callback, argv.size(), &argv[0], &callResult);
1131 bool isObject = false;
1132 std::vector<std::string> methodNameList;
1133 methodNameList = ParseNapiValue2NwebValue(jsObj->GetEnv(), &callResult, ret, &isObject);
1134 napi_valuetype valueType = napi_undefined;
1135 napi_typeof(jsObj->GetEnv(), callResult, &valueType);
1136 WVLOG_D("get javaScript result already in js thread end");
1137 if (!isObject) {
1138 napi_close_handle_scope(jsObj->GetEnv(), scope);
1139 return ret;
1140 }
1141 JavaScriptOb::ObjectID returnedObjectId;
1142 if (FindObjectIdInJsTd(jsObj->GetEnv(), callResult, &returnedObjectId) && FindObject(returnedObjectId)) {
1143 FindObject(returnedObjectId)->AddHolder(routingId);
1144 } else {
1145 returnedObjectId = AddObject(jsObj->GetEnv(), callResult, false, routingId);
1146 }
1147 SetUpAnnotateMethods(returnedObjectId, methodNameList);
1148 if (valueType == napi_function) {
1149 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is function");
1150 ret = std::make_shared<NWebValue>();
1151 } else {
1152 WVLOG_D("WebviewJavaScriptResultCallBack::GetJavaScriptResultSelf type is object");
1153 std::string bin = std::string("TYPE_OBJECT_ID") + std::string(";") + std::to_string(returnedObjectId);
1154 ret = std::make_shared<NWebValue>(bin.c_str(), bin.size());
1155 }
1156 napi_close_handle_scope(jsObj->GetEnv(), scope);
1157 return ret;
1158 }
1159
GetJavaScriptResultSelfFlowbuf(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int fd,int32_t routingId,int32_t objectId)1160 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultSelfFlowbuf(
1161 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName, int fd,
1162 int32_t routingId, int32_t objectId)
1163 {
1164 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1165 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1166 if (!jsObj) {
1167 return ret;
1168 }
1169 napi_handle_scope scope = nullptr;
1170 napi_open_handle_scope(jsObj->GetEnv(), &scope);
1171 if (scope == nullptr) {
1172 return ret;
1173 }
1174 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
1175 if (!flowbufferAdapter) {
1176 napi_close_handle_scope(jsObj->GetEnv(), scope);
1177 return ret;
1178 }
1179 auto ashmem = flowbufferAdapter->CreateAshmemWithFd(fd, MAX_FLOWBUF_DATA_SIZE + HEADER_SIZE, PROT_READ);
1180 if (!ashmem) {
1181 napi_close_handle_scope(jsObj->GetEnv(), scope);
1182 return ret;
1183 }
1184
1185 std::vector<napi_value> argv = {};
1186 if (!ConstructArgv(ashmem, args, argv, jsObj, routingId)) {
1187 napi_close_handle_scope(jsObj->GetEnv(), scope);
1188 return ret;
1189 }
1190 close(fd);
1191
1192 ret = GetJavaScriptResultSelfHelper(jsObj, method, routingId, scope, argv);
1193 return ret;
1194 }
1195
GetJavaScriptResultFlowbuf(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int fd,int32_t routingId,int32_t objectId)1196 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptResultFlowbuf(
1197 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName, int fd,
1198 int32_t routingId, int32_t objectId)
1199 {
1200 (void)objName; // to be compatible with older webcotroller, classname may be empty
1201 WVLOG_D("GetJavaScriptResult method = %{public}s", method.c_str());
1202 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1203 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1204 if (!jsObj || !jsObj->HasMethod(method)) {
1205 return ret;
1206 }
1207
1208 auto engine = reinterpret_cast<NativeEngine*>(jsObj->GetEnv());
1209 if (engine == nullptr) {
1210 return ret;
1211 }
1212
1213 if (pthread_self() == engine->GetTid()) {
1214 return GetJavaScriptResultSelfFlowbuf(args, method, objName, fd, routingId, objectId);
1215 } else {
1216 auto flowbufferAdapter = OhosAdapterHelper::GetInstance().CreateFlowbufferAdapter();
1217 if (!flowbufferAdapter) {
1218 return ret;
1219 }
1220
1221 auto ashmem = flowbufferAdapter->CreateAshmemWithFd(fd, MAX_FLOWBUF_DATA_SIZE + HEADER_SIZE, PROT_READ);
1222 if (!ashmem) {
1223 return ret;
1224 }
1225
1226 int argIndex = -1;
1227 int flowbufIndex = 0;
1228 int strLen = 0;
1229 do {
1230 char* flowbufStr = FlowbufStrAtIndex(ashmem, flowbufIndex, &argIndex, &strLen);
1231 if (argIndex == -1) {
1232 break;
1233 }
1234 flowbufIndex++;
1235 std::string str(flowbufStr);
1236 std::shared_ptr<NWebValue> insertArg = std::make_shared<NWebValue>(str);
1237 args.insert(args.begin() + argIndex, insertArg);
1238 } while (argIndex <= MAX_ENTRIES);
1239
1240 close(fd);
1241 WVLOG_D("get javaScript result, not in js thread, post task to js thread");
1242 return PostGetJavaScriptResultToJsThread(args, method, objName, routingId, objectId);
1243 }
1244 }
1245
PostGetJavaScriptResultToJsThread(std::vector<std::shared_ptr<NWebValue>> args,const std::string & method,const std::string & objName,int32_t routingId,int32_t objectId)1246 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThread(
1247 std::vector<std::shared_ptr<NWebValue>> args, const std::string& method, const std::string& objName,
1248 int32_t routingId, int32_t objectId)
1249 {
1250 // to be compatible with older webcotroller, classname may be empty
1251 (void)objName;
1252 WVLOG_D("WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThread method = "
1253 "%{public}s",
1254 method.c_str());
1255 std::shared_ptr<NWebValue> ret = std::make_shared<NWebValue>(NWebValue::Type::NONE);
1256 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1257 if (!jsObj) {
1258 return ret;
1259 }
1260 napi_env env = jsObj->GetEnv();
1261 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1262 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1263 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1264 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1265 WVLOG_E("WebviewJavaScriptResultCallBack::PostGetJavaScriptResultToJsThread malloc fail");
1266 return ret;
1267 }
1268
1269 inParam->webJsResCb = this;
1270 inParam->nwebId = GetNWebId();
1271 inParam->frameRoutingId = routingId;
1272 inParam->objId = objectId;
1273 inParam->methodName = method;
1274 inParam->data = reinterpret_cast<void*>(&args);
1275 outParam->ret = reinterpret_cast<void*>(&ret);
1276 param->input = reinterpret_cast<void*>(inParam);
1277 param->out = reinterpret_cast<void*>(outParam);
1278 param->env = env;
1279
1280 CreateUvQueueWorkEnhanced(env, param, ExecuteGetJavaScriptResult);
1281 {
1282 std::unique_lock<std::mutex> lock(param->mutex);
1283 param->condition.wait(lock, [¶m] { return param->ready; });
1284 }
1285 DeleteNapiJsCallBackParm(inParam, outParam, param);
1286 return ret;
1287 }
1288
FindObjectIdInJsTd(napi_env env,napi_value object,JavaScriptOb::ObjectID * objectId)1289 bool WebviewJavaScriptResultCallBack::FindObjectIdInJsTd(
1290 napi_env env, napi_value object, JavaScriptOb::ObjectID* objectId)
1291 {
1292 *objectId = static_cast<JavaScriptOb::ObjectID>(JavaScriptOb::JavaScriptObjIdErrorCode::WEBVIEWCONTROLLERERROR);
1293 for (const auto& pair : objects_) {
1294 bool result = false;
1295 napi_status s = napi_strict_equals(env, object, pair.second->GetValue(), &result);
1296 if (s != napi_ok) {
1297 WVLOG_E("WebviewJavaScriptResultCallBack::FindObjectIdInJsTd fail");
1298 }
1299 if (result) {
1300 *objectId = pair.first;
1301 return true;
1302 }
1303 }
1304 return false;
1305 }
1306
ExecuteHasJavaScriptObjectMethods(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)1307 void ExecuteHasJavaScriptObjectMethods(
1308 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
1309 {
1310 if (!param) {
1311 return;
1312 }
1313
1314 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1315 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
1316 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
1317 if (!jsObj) {
1318 std::unique_lock<std::mutex> lock(param->mutex);
1319 param->ready = true;
1320 param->condition.notify_all();
1321 return;
1322 }
1323 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1324
1325 napi_handle_scope scope = nullptr;
1326 napi_open_handle_scope(env, &scope);
1327 if (scope) {
1328 if (jsObj && jsObj->HasMethod(inParam->methodName)) {
1329 *(static_cast<bool*>(outParam->ret)) = true;
1330 } else {
1331 WVLOG_D("WebviewJavaScriptResultCallBack::HasJavaScriptObjectMethods cannot find "
1332 "object");
1333 }
1334 napi_close_handle_scope(env, scope);
1335 }
1336
1337 std::unique_lock<std::mutex> lock(param->mutex);
1338 param->ready = true;
1339 param->condition.notify_all();
1340 }
1341
PostHasJavaScriptObjectMethodsToJsThread(int32_t objectId,const std::string & methodName)1342 bool WebviewJavaScriptResultCallBack::PostHasJavaScriptObjectMethodsToJsThread(
1343 int32_t objectId, const std::string& methodName)
1344 {
1345 bool ret = false;
1346 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1347 if (!jsObj) {
1348 return false;
1349 }
1350 napi_env env = jsObj->GetEnv();
1351 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1352 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1353 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1354 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1355 return false;
1356 }
1357
1358 inParam->webJsResCb = this;
1359 inParam->objId = objectId;
1360 inParam->methodName = methodName;
1361 outParam->ret = reinterpret_cast<void*>(&ret);
1362 param->input = reinterpret_cast<void*>(inParam);
1363 param->out = reinterpret_cast<void*>(outParam);
1364 param->env = env;
1365
1366 CreateUvQueueWorkEnhanced(env, param, ExecuteHasJavaScriptObjectMethods);
1367
1368 {
1369 std::unique_lock<std::mutex> lock(param->mutex);
1370 param->condition.wait(lock, [¶m] { return param->ready; });
1371 }
1372 DeleteNapiJsCallBackParm(inParam, outParam, param);
1373 return ret;
1374 }
1375
HasJavaScriptObjectMethods(int32_t objectId,const std::string & methodName)1376 bool WebviewJavaScriptResultCallBack::HasJavaScriptObjectMethods(int32_t objectId, const std::string& methodName)
1377 {
1378 bool ret = false;
1379 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1380 if (!jsObj) {
1381 return false;
1382 }
1383 napi_env env = jsObj->GetEnv();
1384 auto engine = reinterpret_cast<NativeEngine*>(env);
1385 if (engine == nullptr) {
1386 return ret;
1387 }
1388 if (pthread_self() == engine->GetTid()) {
1389 WVLOG_D(
1390 "has javaScript object methods already in js thread, objectId = "
1391 "%{public}d, methodName = %{public}s",
1392 objectId, methodName.c_str());
1393 napi_handle_scope scope = nullptr;
1394 napi_open_handle_scope(env, &scope);
1395 if (scope == nullptr) {
1396 return ret;
1397 }
1398
1399 if (jsObj && jsObj->HasMethod(methodName)) {
1400 ret = true;
1401 } else {
1402 WVLOG_D("WebviewJavaScriptResultCallBack::HasJavaScriptObjectMethods cannot find "
1403 "object");
1404 }
1405
1406 napi_close_handle_scope(env, scope);
1407 return ret;
1408 } else {
1409 WVLOG_D(
1410 "has javaScript object methods, not in js thread, post task to js "
1411 "thread, objectId = "
1412 "%{public}d, methodName = %{public}s",
1413 objectId, methodName.c_str());
1414 return PostHasJavaScriptObjectMethodsToJsThread(objectId, methodName);
1415 }
1416 }
1417
ExecuteGetJavaScriptObjectMethods(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)1418 void ExecuteGetJavaScriptObjectMethods(
1419 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
1420 {
1421 if (!param) {
1422 return;
1423 }
1424
1425 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1426 auto* outParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm*>(param->out);
1427
1428 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
1429 if (!jsObj) {
1430 std::unique_lock<std::mutex> lock(param->mutex);
1431 param->ready = true;
1432 param->condition.notify_all();
1433 return;
1434 }
1435 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1436
1437 napi_handle_scope scope = nullptr;
1438 napi_open_handle_scope(env, &scope);
1439
1440 if (scope) {
1441 if (jsObj) {
1442 auto methods = jsObj->GetMethodNames();
1443 for (auto& method : methods) {
1444 (*(static_cast<std::shared_ptr<NWebValue>*>(outParam->ret)))->AddListValue(NWebValue(method));
1445 }
1446 }
1447 napi_close_handle_scope(env, scope);
1448 }
1449
1450 std::unique_lock<std::mutex> lock(param->mutex);
1451 param->ready = true;
1452 param->condition.notify_all();
1453 }
1454
PostGetJavaScriptObjectMethodsToJsThread(int32_t objectId)1455 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::PostGetJavaScriptObjectMethodsToJsThread(int32_t objectId)
1456 {
1457 auto ret = std::make_shared<NWebValue>(NWebValue::Type::LIST);
1458 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1459 if (!jsObj) {
1460 return ret;
1461 }
1462 napi_env env = jsObj->GetEnv();
1463 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1464 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1465 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1466 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1467 return ret;
1468 }
1469
1470 inParam->webJsResCb = this;
1471 inParam->objId = objectId;
1472 outParam->ret = reinterpret_cast<void*>(&ret);
1473 param->input = reinterpret_cast<void*>(inParam);
1474 param->out = reinterpret_cast<void*>(outParam);
1475 param->env = env;
1476
1477 CreateUvQueueWorkEnhanced(env, param, ExecuteGetJavaScriptObjectMethods);
1478
1479 {
1480 std::unique_lock<std::mutex> lock(param->mutex);
1481 param->condition.wait(lock, [¶m] { return param->ready; });
1482 }
1483 DeleteNapiJsCallBackParm(inParam, outParam, param);
1484 return ret;
1485 }
1486
GetJavaScriptObjectMethods(int32_t objectId)1487 std::shared_ptr<NWebValue> WebviewJavaScriptResultCallBack::GetJavaScriptObjectMethods(int32_t objectId)
1488 {
1489 auto ret = std::make_shared<NWebValue>(NWebValue::Type::LIST);
1490 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1491 if (!jsObj) {
1492 return ret;
1493 }
1494 napi_env env = jsObj->GetEnv();
1495 auto engine = reinterpret_cast<NativeEngine*>(env);
1496 if (engine == nullptr) {
1497 return ret;
1498 }
1499
1500 if (pthread_self() == engine->GetTid()) {
1501 WVLOG_D(
1502 "get javaScript object methods already in js thread, objectId = "
1503 "%{public}d",
1504 objectId);
1505 napi_handle_scope scope = nullptr;
1506 napi_open_handle_scope(env, &scope);
1507 if (scope == nullptr) {
1508 return ret;
1509 }
1510
1511 if (jsObj) {
1512 auto methods = jsObj->GetMethodNames();
1513 for (auto& method : methods) {
1514 ret->AddListValue(NWebValue(method));
1515 }
1516 }
1517
1518 napi_close_handle_scope(env, scope);
1519 return ret;
1520 } else {
1521 WVLOG_D(
1522 "get javaScript object methods, not in js thread, post task to js "
1523 "thread, objectId = %{public}d",
1524 objectId);
1525 return PostGetJavaScriptObjectMethodsToJsThread(objectId);
1526 }
1527 }
1528
RemoveJavaScriptObjectHolderInJsTd(int32_t holder,JavaScriptOb::ObjectID objectId)1529 void WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolderInJsTd(
1530 int32_t holder, JavaScriptOb::ObjectID objectId)
1531 {
1532 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1533 if (jsObj && !(jsObj->IsNamed())) {
1534 jsObj->RemoveHolder(holder);
1535 if (!(jsObj->HasHolders())) {
1536 // reminder me: object->ToWeakRef(), object is erased so the destructor
1537 // called
1538 retainedObjectSet_.erase(jsObj);
1539 objects_.erase(objects_.find(objectId));
1540 }
1541 }
1542 }
1543
ExecuteRemoveJavaScriptObjectHolder(napi_env env,napi_status status,WebviewJavaScriptResultCallBack::NapiJsCallBackParm * param)1544 void ExecuteRemoveJavaScriptObjectHolder(
1545 napi_env env, napi_status status, WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param)
1546 {
1547 if (!param) {
1548 return;
1549 }
1550
1551 auto* inParam = static_cast<WebviewJavaScriptResultCallBack::NapiJsCallBackInParm*>(param->input);
1552
1553 std::shared_ptr<JavaScriptOb> jsObj = inParam->webJsResCb->FindObject(inParam->objId);
1554 if (!jsObj) {
1555 std::unique_lock<std::mutex> lock(param->mutex);
1556 param->ready = true;
1557 param->condition.notify_all();
1558 return;
1559 }
1560 Ace::ContainerScope containerScope(jsObj->GetContainerScopeId());
1561
1562 napi_handle_scope scope = nullptr;
1563 napi_open_handle_scope(env, &scope);
1564
1565 if (scope) {
1566 inParam->webJsResCb->RemoveJavaScriptObjectHolderInJsTd(inParam->frameRoutingId, inParam->objId);
1567 napi_close_handle_scope(env, scope);
1568 }
1569
1570 std::unique_lock<std::mutex> lock(param->mutex);
1571 param->ready = true;
1572 param->condition.notify_all();
1573 }
1574
PostRemoveJavaScriptObjectHolderToJsThread(int32_t holder,JavaScriptOb::ObjectID objectId)1575 void WebviewJavaScriptResultCallBack::PostRemoveJavaScriptObjectHolderToJsThread(
1576 int32_t holder, JavaScriptOb::ObjectID objectId)
1577 {
1578 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolder called, "
1579 "objectId = %{public}d",
1580 objectId);
1581 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1582 if (!jsObj) {
1583 return;
1584 }
1585 napi_env env = jsObj->GetEnv();
1586 WebviewJavaScriptResultCallBack::NapiJsCallBackInParm* inParam = nullptr;
1587 WebviewJavaScriptResultCallBack::NapiJsCallBackOutParm* outParam = nullptr;
1588 WebviewJavaScriptResultCallBack::NapiJsCallBackParm* param = nullptr;
1589 if (!CreateNapiJsCallBackParm(inParam, outParam, param)) {
1590 return;
1591 }
1592
1593 inParam->webJsResCb = this;
1594 inParam->objId = objectId;
1595 inParam->frameRoutingId = holder;
1596 param->input = reinterpret_cast<void*>(inParam);
1597 param->out = reinterpret_cast<void*>(outParam);
1598 param->env = env;
1599
1600 CreateUvQueueWorkEnhanced(env, param, ExecuteRemoveJavaScriptObjectHolder);
1601
1602 {
1603 std::unique_lock<std::mutex> lock(param->mutex);
1604 param->condition.wait(lock, [¶m] { return param->ready; });
1605 }
1606 DeleteNapiJsCallBackParm(inParam, outParam, param);
1607 }
1608
RemoveJavaScriptObjectHolder(int32_t holder,JavaScriptOb::ObjectID objectId)1609 void WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolder(int32_t holder, JavaScriptOb::ObjectID objectId)
1610 {
1611 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveJavaScriptObjectHolder called, "
1612 "objectId = %{public}d",
1613 objectId);
1614 std::shared_ptr<JavaScriptOb> jsObj = FindObject(objectId);
1615 if (!jsObj) {
1616 return;
1617 }
1618 napi_env env = jsObj->GetEnv();
1619 auto engine = reinterpret_cast<NativeEngine*>(env);
1620 if (engine == nullptr) {
1621 return;
1622 }
1623 if (pthread_self() == engine->GetTid()) {
1624 WVLOG_D("remove javaScript object holder already in js thread");
1625 napi_handle_scope scope = nullptr;
1626 napi_open_handle_scope(env, &scope);
1627 if (scope == nullptr) {
1628 return;
1629 }
1630
1631 RemoveJavaScriptObjectHolderInJsTd(holder, objectId);
1632
1633 napi_close_handle_scope(env, scope);
1634 return;
1635 } else {
1636 WVLOG_D("remove javaScript object holder, not in js thread, post task to js thread");
1637 PostRemoveJavaScriptObjectHolderToJsThread(holder, objectId);
1638 }
1639 }
1640
RemoveTransientJavaScriptObject()1641 void WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject()
1642 {
1643 // remove retainedObjectSet_ and objects_ CreateTransient object
1644 auto iter = objects_.begin();
1645 while (iter != objects_.end()) {
1646 if (!(iter->second->IsNamed())) {
1647 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject "
1648 "objectId = %{public}d is removed",
1649 (int32_t)iter->first);
1650 // reminder me: object->ToWeakRef(), object is erased so the destructor called
1651 retainedObjectSet_.erase(iter->second);
1652 objects_.erase(iter++);
1653 } else {
1654 ++iter;
1655 }
1656 }
1657
1658 // remove retainedObjectSet_ named object but not in objects_
1659 auto iter1 = retainedObjectSet_.begin();
1660 while (iter1 != retainedObjectSet_.end()) {
1661 auto iter2 = objects_.begin();
1662 bool isHasObj = false;
1663 while (iter2 != objects_.end()) {
1664 if (*iter1 == iter2->second) {
1665 isHasObj = true;
1666 break;
1667 }
1668 ++iter2;
1669 }
1670 if (!isHasObj) {
1671 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveTransientJavaScriptObject "
1672 "isHasObj == false");
1673 retainedObjectSet_.erase(*iter1);
1674 }
1675 ++iter1;
1676 }
1677 }
1678
SetUpAnnotateMethods(JavaScriptOb::ObjectID objId,std::vector<std::string> & methodNameList)1679 void WebviewJavaScriptResultCallBack::SetUpAnnotateMethods(
1680 JavaScriptOb::ObjectID objId, std::vector<std::string>& methodNameList)
1681 {
1682 // set up annotate(methodNameListForJsProxy) object method
1683 if (objects_[objId]) {
1684 objects_[objId]->SetMethods(methodNameList);
1685 }
1686 }
1687
AddObject(napi_env env,const napi_value & object,bool methodName,int32_t holder)1688 JavaScriptOb::ObjectID WebviewJavaScriptResultCallBack::AddObject(
1689 napi_env env, const napi_value& object, bool methodName, int32_t holder)
1690 {
1691 JavaScriptOb::ObjectID objectId;
1692 {
1693 int32_t containerScopeId = Ace::ContainerScope::CurrentId();
1694 auto new_object = methodName ? JavaScriptOb::CreateNamed(env, containerScopeId, object)
1695 : JavaScriptOb::CreateTransient(env, containerScopeId, object, holder);
1696 objectId = nextObjectId_++;
1697 WVLOG_D(
1698 "WebviewJavaScriptResultCallBack::AddObject objectId = "
1699 "%{public}d",
1700 static_cast<int32_t>(objectId));
1701 objects_[objectId] = new_object;
1702 retainedObjectSet_.insert(new_object);
1703 }
1704 return objectId;
1705 }
1706
AddNamedObject(napi_env env,napi_value & obj,const std::string & objName)1707 JavaScriptOb::ObjectID WebviewJavaScriptResultCallBack::AddNamedObject(
1708 napi_env env, napi_value& obj, const std::string& objName)
1709 {
1710 JavaScriptOb::ObjectID objectId;
1711 NamedObjectMap::iterator iter = namedObjects_.find(objName);
1712 bool methodName = FindObjectIdInJsTd(env, obj, &objectId);
1713 if (methodName && iter != namedObjects_.end() && iter->second == objectId) {
1714 // Nothing to do.
1715 WVLOG_D(
1716 "WebviewJavaScriptResultCallBack::AddNamedObject obj and "
1717 "objName(%{public}s) "
1718 "already exist",
1719 objName.c_str());
1720 return objectId;
1721 }
1722 if (iter != namedObjects_.end()) {
1723 RemoveNamedObject(iter->first);
1724 }
1725 if (methodName) {
1726 objects_[objectId]->AddName();
1727 } else {
1728 objectId = AddObject(env, obj, true, 0);
1729 }
1730 namedObjects_[objName] = objectId;
1731 return objectId;
1732 }
1733
GetNamedObjects()1734 std::unordered_map<std::string, std::shared_ptr<JavaScriptOb>> WebviewJavaScriptResultCallBack::GetNamedObjects()
1735 {
1736 // Get named objects
1737 std::unordered_map<std::string, std::shared_ptr<JavaScriptOb>> ret;
1738 for (auto iter = namedObjects_.begin(); iter != namedObjects_.end(); iter++) {
1739 if (objects_.find(iter->second) != objects_.end()) {
1740 ret.emplace(iter->first, objects_[iter->second]);
1741 }
1742 }
1743 return ret;
1744 }
1745
GetObjectMap()1746 WebviewJavaScriptResultCallBack::ObjectMap WebviewJavaScriptResultCallBack::GetObjectMap()
1747 {
1748 return objects_;
1749 }
1750
RegisterJavaScriptProxy(RegisterJavaScriptProxyParam & param)1751 JavaScriptOb::ObjectID WebviewJavaScriptResultCallBack::RegisterJavaScriptProxy(
1752 RegisterJavaScriptProxyParam& param)
1753 {
1754 JavaScriptOb::ObjectID objId = AddNamedObject(param.env, param.obj, param.objName);
1755 // set up named object method
1756 if (namedObjects_.find(param.objName) != namedObjects_.end() && objects_[namedObjects_[param.objName]]) {
1757 std::shared_ptr<OHOS::NWeb::JavaScriptOb> jsObj = objects_[namedObjects_[param.objName]];
1758 jsObj->SetMethods(param.syncMethodList);
1759 jsObj->SetAsyncMethods(param.asyncMethodList);
1760 jsObj->SetPermission(param.permission);
1761 }
1762 for (auto& item : param.syncMethodList) {
1763 WVLOG_D(
1764 "WebviewJavaScriptResultCallBack::RegisterJavaScriptProxy called, "
1765 "objectId = %{public}d, objName = %{public}s, method = %{public}s",
1766 static_cast<int32_t>(objId), param.objName.c_str(), item.c_str());
1767 }
1768 return objId;
1769 }
1770
RemoveNamedObject(const std::string & name)1771 bool WebviewJavaScriptResultCallBack::RemoveNamedObject(const std::string& name)
1772 {
1773 WVLOG_D("WebviewJavaScriptResultCallBack::RemoveNamedObject called, "
1774 "name = %{public}s",
1775 name.c_str());
1776 NamedObjectMap::iterator iter = namedObjects_.find(name);
1777 if (iter == namedObjects_.end()) {
1778 return false;
1779 }
1780 if (objects_[iter->second]) {
1781 objects_[iter->second]->RemoveName();
1782 }
1783 namedObjects_.erase(iter);
1784 return true;
1785 }
1786
DeleteJavaScriptRegister(const std::string & objName)1787 bool WebviewJavaScriptResultCallBack::DeleteJavaScriptRegister(const std::string& objName)
1788 {
1789 return RemoveNamedObject(objName);
1790 }
1791
CallH5FunctionInternal(napi_env env,H5Bundle & bundle,std::vector<std::shared_ptr<NWebValue>> nwebArgs)1792 void WebviewJavaScriptResultCallBack::CallH5FunctionInternal(
1793 napi_env env, H5Bundle& bundle, std::vector<std::shared_ptr<NWebValue>> nwebArgs)
1794 {
1795 if (bundle.nwebId != GetNWebId()) {
1796 WVLOG_E("WebviewJavaScriptResultCallBack::CallH5FunctionInternal nweb id not equal");
1797 return;
1798 }
1799 auto nweb_ptr = NWebHelper::Instance().GetNWeb(nwebId_);
1800 if (!nweb_ptr) {
1801 WVLOG_E("WebviewJavaScriptResultCallBack::CallH5FunctionInternal nweb_ptr null");
1802 return;
1803 }
1804
1805 nweb_ptr->CallH5Function(bundle.frameRoutingId, bundle.h5Id, bundle.funcName, nwebArgs);
1806 WVLOG_D("WebviewJavaScriptResultCallBack::CallH5FunctionInternal end");
1807 }
1808
UpdateInstanceId(int32_t newId)1809 void WebviewJavaScriptResultCallBack::UpdateInstanceId(int32_t newId)
1810 {
1811 for (const auto& [nwebId, obj] : objects_) {
1812 obj->SetContainerScopeId(newId);
1813 }
1814 }
1815
1816 } // namespace OHOS::NWeb
1817