• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, [&param] { 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, [&param] { 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, [&param] { 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, [&param] { 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