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