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