1 /*
2  * Copyright (c) 2023 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 "js_vpn_extension.h"
17 
18 #include "ability_handler.h"
19 #include "ability_info.h"
20 #include "configuration_utils.h"
21 #include "hitrace_meter.h"
22 #include "hilog_wrapper.h"
23 #include "js_extension_common.h"
24 #include "js_extension_context.h"
25 #include "runtime.h"
26 #include "js_runtime.h"
27 #include "js_runtime_utils.h"
28 #include "display_manager.h"
29 #include "js_vpn_extension_context.h"
30 #include "napi/native_api.h"
31 #include "napi/native_node_api.h"
32 #include "napi_common_configuration.h"
33 #include "napi_common_want.h"
34 #include "napi_remote_object.h"
35 #ifdef SUPPORT_GRAPHICS
36 #include "iservice_registry.h"
37 #include "system_ability_definition.h"
38 #include "window_scene.h"
39 #include "netmgr_ext_log_wrapper.h"
40 #endif
41 
42 using namespace OHOS::AbilityRuntime;
43 namespace OHOS {
44 namespace NetManagerStandard {
45 namespace {
46 constexpr size_t ARGC_ONE = 1;
47 constexpr size_t ARGC_TWO = 2;
48 }
49 
50 namespace {
PromiseCallback(napi_env env,napi_callback_info info)51 napi_value PromiseCallback(napi_env env, napi_callback_info info)
52 {
53     void *data = nullptr;
54     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data), nullptr);
55     auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<> *>(data);
56     callbackInfo->Call();
57     AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo);
58     data = nullptr;
59     return nullptr;
60 }
61 
OnConnectPromiseCallback(napi_env env,napi_callback_info info)62 napi_value OnConnectPromiseCallback(napi_env env, napi_callback_info info)
63 {
64     NETMGR_EXT_LOG_D("enter");
65     void *data = nullptr;
66     size_t argc = ARGC_MAX_COUNT;
67     napi_value argv[ARGC_MAX_COUNT] = {nullptr};
68     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, &argc, argv, nullptr, &data), nullptr);
69     auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *>(data);
70     sptr<IRemoteObject> vpn = nullptr;
71     if (argc > 0) {
72         vpn = NAPI_ohos_rpc_getNativeRemoteObject(env, argv[0]);
73     }
74     callbackInfo->Call(vpn);
75     AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>>::Destroy(callbackInfo);
76     data = nullptr;
77     NETMGR_EXT_LOG_D("end");
78     return nullptr;
79 }
80 }
81 
82 using namespace OHOS::AppExecFwk;
83 
AttachVpnExtensionContext(napi_env env,void * value,void *)84 napi_value AttachVpnExtensionContext(napi_env env, void *value, void *)
85 {
86     NETMGR_EXT_LOG_I("call");
87     if (value == nullptr) {
88         HILOG_WARN("invalid parameter.");
89         return nullptr;
90     }
91     auto ptr = reinterpret_cast<std::weak_ptr<VpnExtensionContext> *>(value)->lock();
92     if (ptr == nullptr) {
93         HILOG_WARN("invalid context.");
94         return nullptr;
95     }
96     napi_value object = CreateJsVpnExtensionContext(env, ptr);
97     auto contextObj = JsRuntime::LoadSystemModuleByEngine(env,
98         "application.VpnExtensionContext", &object, 1)->GetNapiValue();
99     napi_coerce_to_native_binding_object(
100         env, contextObj, DetachCallbackFunc, AttachVpnExtensionContext, value, nullptr);
101     auto workContext = new (std::nothrow) std::weak_ptr<VpnExtensionContext>(ptr);
102     napi_wrap(env, contextObj, workContext,
103         [](napi_env, void *data, void *) {
104             NETMGR_EXT_LOG_I("Finalizer for weak_ptr vpn extension context is called");
105             delete static_cast<std::weak_ptr<VpnExtensionContext> *>(data);
106         },
107         nullptr, nullptr);
108     return contextObj;
109 }
110 
Create(const std::unique_ptr<Runtime> & runtime)111 JsVpnExtension* JsVpnExtension::Create(const std::unique_ptr<Runtime>& runtime)
112 {
113     return new JsVpnExtension(static_cast<JsRuntime&>(*runtime));
114 }
115 
JsVpnExtension(JsRuntime & jsRuntime)116 JsVpnExtension::JsVpnExtension(JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
~JsVpnExtension()117 JsVpnExtension::~JsVpnExtension()
118 {
119     NETMGR_EXT_LOG_D("Js vpn extension destructor.");
120     auto context = GetContext();
121     if (context) {
122         context->Unbind();
123     }
124 
125     jsRuntime_.FreeNativeReference(std::move(jsObj_));
126     jsRuntime_.FreeNativeReference(std::move(shellContextRef_));
127 }
128 
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)129 void JsVpnExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
130     const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
131     const sptr<IRemoteObject> &token)
132 {
133     VpnExtension::Init(record, application, handler, token);
134     std::string srcPath = "";
135     GetSrcPath(srcPath);
136     if (srcPath.empty()) {
137         NETMGR_EXT_LOG_E("Failed to get srcPath");
138         return;
139     }
140 
141     std::string moduleName(Extension::abilityInfo_->moduleName);
142     moduleName.append("::").append(abilityInfo_->name);
143     NETMGR_EXT_LOG_D("JsVpnExtension::Init moduleName:%{public}s,srcPath:%{public}s.",
144         moduleName.c_str(), srcPath.c_str());
145     HandleScope handleScope(jsRuntime_);
146     auto env = jsRuntime_.GetNapiEnv();
147 
148     jsObj_ = jsRuntime_.LoadModule(
149         moduleName, srcPath, abilityInfo_->hapPath, abilityInfo_->compileMode == CompileMode::ES_MODULE);
150     if (jsObj_ == nullptr) {
151         NETMGR_EXT_LOG_E("Failed to get jsObj_");
152         return;
153     }
154 
155     NETMGR_EXT_LOG_I("JsVpnExtension::Init ConvertNativeValueTo.");
156     napi_value obj = jsObj_->GetNapiValue();
157     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
158         NETMGR_EXT_LOG_E("Failed to get JsVpnExtension object");
159         return;
160     }
161 
162     BindContext(env, obj);
163 
164     SetExtensionCommon(JsExtensionCommon::Create(jsRuntime_, static_cast<NativeReference&>(*jsObj_), shellContextRef_));
165 
166     handler_ = handler;
167     auto context = GetContext();
168     auto appContext = Context::GetApplicationContext();
169     if (context != nullptr && appContext != nullptr) {
170         auto appConfig = appContext->GetConfiguration();
171         if (appConfig != nullptr) {
172             NETMGR_EXT_LOG_D("Original config dump: %{public}s", appConfig->GetName().c_str());
173             context->SetConfiguration(std::make_shared<Configuration>(*appConfig));
174         }
175     }
176     ListenWMS();
177 }
178 
ListenWMS()179 void JsVpnExtension::ListenWMS()
180 {
181 #ifdef SUPPORT_GRAPHICS
182     NETMGR_EXT_LOG_I("RegisterDisplayListener");
183     auto abilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
184     if (abilityManager == nullptr) {
185         NETMGR_EXT_LOG_E("Failed to get SaMgr.");
186         return;
187     }
188 
189     auto jsVpnExtension = std::static_pointer_cast<JsVpnExtension>(shared_from_this());
190     displayListener_ = sptr<JsVpnExtensionDisplayListener>::MakeSptr(jsVpnExtension);
191     if (displayListener_ == nullptr) {
192         NETMGR_EXT_LOG_E("Failed to create display listener.");
193         return;
194     }
195 
196     auto listener = sptr<SystemAbilityStatusChangeListener>::MakeSptr(displayListener_);
197     if (listener == nullptr) {
198         NETMGR_EXT_LOG_E("Failed to create status change listener.");
199         return;
200     }
201 
202     auto ret = abilityManager->SubscribeSystemAbility(WINDOW_MANAGER_SERVICE_ID, listener);
203     if (ret != 0) {
204         NETMGR_EXT_LOG_E("subscribe system ability failed, ret = %{public}d.", ret);
205     }
206 #endif
207 }
208 
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)209 void JsVpnExtension::SystemAbilityStatusChangeListener::OnAddSystemAbility(int32_t systemAbilityId,
210     const std::string& deviceId)
211 {
212     NETMGR_EXT_LOG_I("systemAbilityId: %{public}d add", systemAbilityId);
213     if (systemAbilityId == WINDOW_MANAGER_SERVICE_ID) {
214         Rosen::DisplayManager::GetInstance().RegisterDisplayListener(tmpDisplayListener_);
215     }
216 }
217 
BindContext(napi_env env,napi_value obj)218 void JsVpnExtension::BindContext(napi_env env, napi_value obj)
219 {
220     auto context = GetContext();
221     if (context == nullptr) {
222         NETMGR_EXT_LOG_E("Failed to get context");
223         return;
224     }
225     NETMGR_EXT_LOG_I("call");
226     napi_value contextObj = CreateJsVpnExtensionContext(env, context);
227     shellContextRef_ = JsRuntime::LoadSystemModuleByEngine(env, "application.VpnExtensionContext",
228         &contextObj, ARGC_ONE);
229     contextObj = shellContextRef_->GetNapiValue();
230     if (!CheckTypeForNapiValue(env, contextObj, napi_object)) {
231         NETMGR_EXT_LOG_E("Failed to get context native object");
232         return;
233     }
234     auto workContext = new (std::nothrow) std::weak_ptr<VpnExtensionContext>(context);
235     napi_coerce_to_native_binding_object(
236         env, contextObj, DetachCallbackFunc, AttachVpnExtensionContext, workContext, nullptr);
237     NETMGR_EXT_LOG_I("JsVpnExtension::Init Bind.");
238     context->Bind(jsRuntime_, shellContextRef_.get());
239     NETMGR_EXT_LOG_I("JsVpnExtension::SetProperty.");
240     napi_set_named_property(env, obj, "context", contextObj);
241     NETMGR_EXT_LOG_I("Set vpn extension context");
242 
243     napi_wrap(env, contextObj, workContext,
244         [](napi_env, void* data, void*) {
245             NETMGR_EXT_LOG_I("Finalizer for weak_ptr vpn extension context is called");
246             delete static_cast<std::weak_ptr<VpnExtensionContext>*>(data);
247         },
248         nullptr, nullptr);
249 
250     NETMGR_EXT_LOG_I("JsVpnExtension::Init end.");
251 }
252 
OnStart(const AAFwk::Want & want)253 void JsVpnExtension::OnStart(const AAFwk::Want &want)
254 {
255     Extension::OnStart(want);
256     NETMGR_EXT_LOG_I("call");
257 
258     auto context = GetContext();
259     if (context == nullptr) {
260         NETMGR_EXT_LOG_E("context is null");
261         return;
262     }
263 
264     int displayId = want.GetIntParam(Want::PARAM_RESV_DISPLAY_ID, Rosen::WindowScene::DEFAULT_DISPLAY_ID);
265     auto configUtils = std::make_shared<ConfigurationUtils>();
266     configUtils->InitDisplayConfig(displayId, context->GetConfiguration(), context->GetResourceManager());
267 
268     HandleScope handleScope(jsRuntime_);
269     napi_env env = jsRuntime_.GetNapiEnv();
270 
271     // display config has changed, need update context.config
272     JsExtensionContext::ConfigurationUpdated(env, shellContextRef_, context->GetConfiguration());
273 
274     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
275     napi_value argv[] = {napiWant};
276     CallObjectMethod("onCreate", argv, ARGC_ONE);
277     NETMGR_EXT_LOG_I("ok");
278 }
279 
OnStop()280 void JsVpnExtension::OnStop()
281 {
282     VpnExtension::OnStop();
283     NETMGR_EXT_LOG_I("call");
284     CallObjectMethod("onDestroy");
285     bool ret = ConnectionManager::GetInstance().DisconnectCaller(GetContext()->GetToken());
286     if (ret) {
287         ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid());
288         NETMGR_EXT_LOG_I("The vpn extension connection is not disconnected.");
289     }
290     Rosen::DisplayManager::GetInstance().UnregisterDisplayListener(displayListener_);
291     NETMGR_EXT_LOG_I("ok");
292 }
293 
OnConnect(const AAFwk::Want & want)294 sptr<IRemoteObject> JsVpnExtension::OnConnect(const AAFwk::Want &want)
295 {
296     HandleScope handleScope(jsRuntime_);
297     napi_value result = CallOnConnect(want);
298     napi_env env = jsRuntime_.GetNapiEnv();
299     auto remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(env, result);
300     if (remoteObj == nullptr) {
301         NETMGR_EXT_LOG_E("remoteObj null.");
302     }
303     return remoteObj;
304 }
305 
OnConnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> * callbackInfo,bool & isAsyncCallback)306 sptr<IRemoteObject> JsVpnExtension::OnConnect(const AAFwk::Want &want,
307     AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *callbackInfo, bool &isAsyncCallback)
308 {
309     HandleScope handleScope(jsRuntime_);
310     napi_env env = jsRuntime_.GetNapiEnv();
311     napi_value result = CallOnConnect(want);
312     bool isPromise = CheckPromise(result);
313     if (!isPromise) {
314         isAsyncCallback = false;
315         sptr<IRemoteObject> remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(env, result);
316         if (remoteObj == nullptr) {
317             NETMGR_EXT_LOG_E("remoteObj null.");
318         }
319         return remoteObj;
320     }
321 
322     bool callResult = false;
323     do {
324         if (!CheckTypeForNapiValue(env, result, napi_object)) {
325             NETMGR_EXT_LOG_E("CallPromise, error to convert native value to NativeObject.");
326             break;
327         }
328         napi_value then = nullptr;
329         napi_get_named_property(env, result, "then", &then);
330         if (then == nullptr) {
331             NETMGR_EXT_LOG_E("CallPromise, error to get property: then.");
332             break;
333         }
334         bool isCallable = false;
335         napi_is_callable(env, then, &isCallable);
336         if (!isCallable) {
337             NETMGR_EXT_LOG_E("CallPromise, property then is not callable");
338             break;
339         }
340         napi_value promiseCallback = nullptr;
341         napi_create_function(env, "promiseCallback", strlen("promiseCallback"),
342             OnConnectPromiseCallback, callbackInfo, &promiseCallback);
343         napi_value argv[1] = { promiseCallback };
344         napi_call_function(env, result, then, 1, argv, nullptr);
345         callResult = true;
346     } while (false);
347 
348     if (!callResult) {
349         NETMGR_EXT_LOG_E("error to call promise.");
350         isAsyncCallback = false;
351     } else {
352         isAsyncCallback = true;
353     }
354     return nullptr;
355 }
356 
OnDisconnect(const AAFwk::Want & want)357 void JsVpnExtension::OnDisconnect(const AAFwk::Want &want)
358 {
359     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
360     Extension::OnDisconnect(want);
361     NETMGR_EXT_LOG_D("%{public}s begin.", __func__);
362     CallOnDisconnect(want, false);
363     NETMGR_EXT_LOG_D("%{public}s end.", __func__);
364 }
365 
OnDisconnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo,bool & isAsyncCallback)366 void JsVpnExtension::OnDisconnect(const AAFwk::Want &want,
367     AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback)
368 {
369     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
370     Extension::OnDisconnect(want);
371     NETMGR_EXT_LOG_D("%{public}s start.", __func__);
372     napi_value result = CallOnDisconnect(want, true);
373     bool isPromise = CheckPromise(result);
374     if (!isPromise) {
375         isAsyncCallback = false;
376         return;
377     }
378     bool callResult = CallPromise(result, callbackInfo);
379     if (!callResult) {
380         NETMGR_EXT_LOG_E("error to call promise.");
381         isAsyncCallback = false;
382     } else {
383         isAsyncCallback = true;
384     }
385 
386     NETMGR_EXT_LOG_D("%{public}s end.", __func__);
387 }
388 
OnCommand(const AAFwk::Want & want,bool restart,int startId)389 void JsVpnExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId)
390 {
391     Extension::OnCommand(want, restart, startId);
392     NETMGR_EXT_LOG_I("restart=%{public}s,startId=%{public}d.",
393         restart ? "true" : "false",
394         startId);
395     // wrap want
396     HandleScope handleScope(jsRuntime_);
397     napi_env env = jsRuntime_.GetNapiEnv();
398     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
399     // wrap startId
400     napi_value napiStartId = nullptr;
401     napi_create_int32(env, startId, &napiStartId);
402     napi_value argv[] = {napiWant, napiStartId};
403     CallObjectMethod("onRequest", argv, ARGC_TWO);
404     NETMGR_EXT_LOG_I("ok");
405 }
406 
CallObjectMethod(const char * name,napi_value const * argv,size_t argc)407 napi_value JsVpnExtension::CallObjectMethod(const char* name, napi_value const* argv, size_t argc)
408 {
409     NETMGR_EXT_LOG_I("CallObjectMethod(%{public}s)", name);
410 
411     if (!jsObj_) {
412         HILOG_WARN("Not found VpnExtension.js");
413         return nullptr;
414     }
415 
416     HandleScope handleScope(jsRuntime_);
417     napi_env env = jsRuntime_.GetNapiEnv();
418 
419     napi_value obj = jsObj_->GetNapiValue();
420     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
421         NETMGR_EXT_LOG_E("Failed to get VpnExtension object");
422         return nullptr;
423     }
424 
425     napi_value method = nullptr;
426     napi_get_named_property(env, obj, name, &method);
427     if (!CheckTypeForNapiValue(env, method, napi_function)) {
428         NETMGR_EXT_LOG_E("Failed to get '%{public}s' from VpnExtension object", name);
429         return nullptr;
430     }
431     NETMGR_EXT_LOG_I("CallFunction(%{public}s) ok", name);
432     napi_value result = nullptr;
433     napi_call_function(env, obj, method, argc, argv, &result);
434     return result;
435 }
436 
GetSrcPath(std::string & srcPath)437 void JsVpnExtension::GetSrcPath(std::string &srcPath)
438 {
439     NETMGR_EXT_LOG_D("GetSrcPath start.");
440     if (!Extension::abilityInfo_->isModuleJson) {
441         /* temporary compatibility api8 + config.json */
442         srcPath.append(Extension::abilityInfo_->package);
443         srcPath.append("/assets/js/");
444         if (!Extension::abilityInfo_->srcPath.empty()) {
445             srcPath.append(Extension::abilityInfo_->srcPath);
446         }
447         srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
448         return;
449     }
450 
451     if (!Extension::abilityInfo_->srcEntrance.empty()) {
452         srcPath.append(Extension::abilityInfo_->moduleName + "/");
453         srcPath.append(Extension::abilityInfo_->srcEntrance);
454         srcPath.erase(srcPath.rfind('.'));
455         srcPath.append(".abc");
456     }
457 }
458 
CallOnConnect(const AAFwk::Want & want)459 napi_value JsVpnExtension::CallOnConnect(const AAFwk::Want &want)
460 {
461     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
462     Extension::OnConnect(want);
463     NETMGR_EXT_LOG_D("call");
464     napi_env env = jsRuntime_.GetNapiEnv();
465     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
466     napi_value argv[] = {napiWant};
467     if (!jsObj_) {
468         HILOG_WARN("Not found VpnExtension.js");
469         return nullptr;
470     }
471 
472     napi_value obj = jsObj_->GetNapiValue();
473     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
474         NETMGR_EXT_LOG_E("Failed to get VpnExtension object");
475         return nullptr;
476     }
477 
478     napi_value method = nullptr;
479     napi_get_named_property(env, obj, "onConnect", &method);
480     if (method == nullptr) {
481         NETMGR_EXT_LOG_E("Failed to get onConnect from VpnExtension object");
482         return nullptr;
483     }
484     napi_value remoteNative = nullptr;
485     napi_call_function(env, obj, method, ARGC_ONE, argv, &remoteNative);
486     if (remoteNative == nullptr) {
487         NETMGR_EXT_LOG_E("remoteNative nullptr.");
488     }
489     NETMGR_EXT_LOG_I("ok");
490     return remoteNative;
491 }
492 
CallOnDisconnect(const AAFwk::Want & want,bool withResult)493 napi_value JsVpnExtension::CallOnDisconnect(const AAFwk::Want &want, bool withResult)
494 {
495     HandleEscape handleEscape(jsRuntime_);
496     napi_env env = jsRuntime_.GetNapiEnv();
497     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
498     napi_value argv[] = { napiWant };
499     if (!jsObj_) {
500         HILOG_WARN("Not found VpnExtension.js");
501         return nullptr;
502     }
503 
504     napi_value obj = jsObj_->GetNapiValue();
505     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
506         NETMGR_EXT_LOG_E("Failed to get VpnExtension object");
507         return nullptr;
508     }
509 
510     napi_value method = nullptr;
511     napi_get_named_property(env, obj, "onDisconnect", &method);
512     if (method == nullptr) {
513         NETMGR_EXT_LOG_E("Failed to get onDisconnect from VpnExtension object");
514         return nullptr;
515     }
516 
517     if (withResult) {
518         napi_value result = nullptr;
519         napi_call_function(env, obj, method, ARGC_ONE, argv, &result);
520         return handleEscape.Escape(result);
521     } else {
522         napi_call_function(env, obj, method, ARGC_ONE, argv, nullptr);
523         return nullptr;
524     }
525 }
526 
CheckPromise(napi_value result)527 bool JsVpnExtension::CheckPromise(napi_value result)
528 {
529     if (result == nullptr) {
530         NETMGR_EXT_LOG_D("CheckPromise, result is nullptr, no need to call promise.");
531         return false;
532     }
533     napi_env env = jsRuntime_.GetNapiEnv();
534     bool isPromise = false;
535     napi_is_promise(env, result, &isPromise);
536     if (!isPromise) {
537         NETMGR_EXT_LOG_D("CheckPromise, result is not promise, no need to call promise.");
538         return false;
539     }
540     return true;
541 }
542 
CallPromise(napi_value result,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo)543 bool JsVpnExtension::CallPromise(napi_value result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo)
544 {
545     napi_env env = jsRuntime_.GetNapiEnv();
546     if (!CheckTypeForNapiValue(env, result, napi_object)) {
547         NETMGR_EXT_LOG_E("CallPromise, Error to convert native value to NativeObject.");
548         return false;
549     }
550     napi_value then = nullptr;
551     napi_get_named_property(env, result, "then", &then);
552     if (then == nullptr) {
553         NETMGR_EXT_LOG_E("CallPromise, Error to get property: then.");
554         return false;
555     }
556     bool isCallable = false;
557     napi_is_callable(env, then, &isCallable);
558     if (!isCallable) {
559         NETMGR_EXT_LOG_E("CallPromise, Property then is not callable.");
560         return false;
561     }
562     HandleScope handleScope(jsRuntime_);
563     napi_value promiseCallback = nullptr;
564     napi_create_function(env, "promiseCallback", strlen("promiseCallback"), PromiseCallback,
565         callbackInfo, &promiseCallback);
566     napi_value argv[1] = { promiseCallback };
567     napi_call_function(env, result, then, 1, argv, nullptr);
568     NETMGR_EXT_LOG_D("end");
569     return true;
570 }
571 
OnConfigurationUpdated(const AppExecFwk::Configuration & configuration)572 void JsVpnExtension::OnConfigurationUpdated(const AppExecFwk::Configuration& configuration)
573 {
574     VpnExtension::OnConfigurationUpdated(configuration);
575     NETMGR_EXT_LOG_I("call");
576     auto context = GetContext();
577     if (context == nullptr) {
578         NETMGR_EXT_LOG_E("Context is invalid.");
579         return;
580     }
581 
582     auto contextConfig = context->GetConfiguration();
583     if (contextConfig != nullptr) {
584         NETMGR_EXT_LOG_D("Config dump: %{public}s", contextConfig->GetName().c_str());
585         std::vector<std::string> changeKeyV;
586         contextConfig->CompareDifferent(changeKeyV, configuration);
587         if (!changeKeyV.empty()) {
588             contextConfig->Merge(changeKeyV, configuration);
589         }
590         NETMGR_EXT_LOG_D("Config dump after merge: %{public}s", contextConfig->GetName().c_str());
591     }
592     ConfigurationUpdated();
593 }
594 
ConfigurationUpdated()595 void JsVpnExtension::ConfigurationUpdated()
596 {
597     NETMGR_EXT_LOG_D("called.");
598     HandleScope handleScope(jsRuntime_);
599     napi_env env = jsRuntime_.GetNapiEnv();
600 
601     // Notify extension context
602     auto fullConfig = GetContext()->GetConfiguration();
603     if (!fullConfig) {
604         NETMGR_EXT_LOG_E("configuration is nullptr.");
605         return;
606     }
607 
608     napi_value napiConfiguration = OHOS::AppExecFwk::WrapConfiguration(env, *fullConfig);
609     CallObjectMethod("onConfigurationUpdated", &napiConfiguration, ARGC_ONE);
610     CallObjectMethod("onConfigurationUpdate", &napiConfiguration, ARGC_ONE);
611     JsExtensionContext::ConfigurationUpdated(env, shellContextRef_, fullConfig);
612 }
613 
Dump(const std::vector<std::string> & params,std::vector<std::string> & info)614 void JsVpnExtension::Dump(const std::vector<std::string> &params, std::vector<std::string> &info)
615 {
616     Extension::Dump(params, info);
617     NETMGR_EXT_LOG_I("call");
618     HandleScope handleScope(jsRuntime_);
619     napi_env env = jsRuntime_.GetNapiEnv();
620     // create js array object of params
621     napi_value argv[] = { CreateNativeArray(env, params) };
622 
623     if (!jsObj_) {
624         HILOG_WARN("Not found VpnExtension.js");
625         return;
626     }
627 
628     napi_value obj = jsObj_->GetNapiValue();
629     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
630         NETMGR_EXT_LOG_E("Failed to get VpnExtension object");
631         return;
632     }
633 
634     napi_value method = nullptr;
635     napi_get_named_property(env, obj, "onDump", &method);
636     if (!CheckTypeForNapiValue(env, method, napi_function)) {
637         method = nullptr;
638         napi_get_named_property(env, obj, "dump", &method);
639         if (!CheckTypeForNapiValue(env, method, napi_function)) {
640             NETMGR_EXT_LOG_E("Failed to get onConnect from VpnExtension object");
641             return;
642         }
643     }
644     NETMGR_EXT_LOG_I("JsVpnExtension::CallFunction onConnect, success");
645     napi_value dumpInfo = nullptr;
646     napi_call_function(env, obj, method, ARGC_ONE, argv, &dumpInfo);
647     if (dumpInfo == nullptr) {
648         NETMGR_EXT_LOG_E("dumpInfo nullptr.");
649         return;
650     }
651     uint32_t len = 0;
652     napi_get_array_length(env, dumpInfo, &len);
653     for (uint32_t i = 0; i < len; i++) {
654         std::string dumpInfoStr;
655         napi_value element = nullptr;
656         napi_get_element(env, dumpInfo, i, &element);
657         if (!ConvertFromJsValue(env, element, dumpInfoStr)) {
658             NETMGR_EXT_LOG_E("Parse dumpInfoStr failed.");
659             return;
660         }
661         info.push_back(dumpInfoStr);
662     }
663     NETMGR_EXT_LOG_D("Dump info size: %{public}zu", info.size());
664 }
665 
666 #ifdef SUPPORT_GRAPHICS
OnCreate(Rosen::DisplayId displayId)667 void JsVpnExtension::OnCreate(Rosen::DisplayId displayId)
668 {
669     NETMGR_EXT_LOG_D("enter.");
670 }
671 
OnDestroy(Rosen::DisplayId displayId)672 void JsVpnExtension::OnDestroy(Rosen::DisplayId displayId)
673 {
674     NETMGR_EXT_LOG_D("exit.");
675 }
676 
OnChange(Rosen::DisplayId displayId)677 void JsVpnExtension::OnChange(Rosen::DisplayId displayId)
678 {
679     NETMGR_EXT_LOG_D("displayId: %{public}" PRIu64"", displayId);
680     auto context = GetContext();
681     if (context == nullptr) {
682         NETMGR_EXT_LOG_E("Context is invalid.");
683         return;
684     }
685 
686     auto contextConfig = context->GetConfiguration();
687     if (contextConfig == nullptr) {
688         NETMGR_EXT_LOG_E("Configuration is invalid.");
689         return;
690     }
691 
692     NETMGR_EXT_LOG_D("Config dump: %{public}s", contextConfig->GetName().c_str());
693     bool configChanged = false;
694     auto configUtils = std::make_shared<ConfigurationUtils>();
695     configUtils->UpdateDisplayConfig(displayId, contextConfig, context->GetResourceManager(), configChanged);
696     NETMGR_EXT_LOG_D("Config dump after update: %{public}s", contextConfig->GetName().c_str());
697 
698     if (configChanged) {
699         auto jsVpnExtension = std::static_pointer_cast<JsVpnExtension>(shared_from_this());
700         auto task = [jsVpnExtension]() {
701             if (jsVpnExtension) {
702                 jsVpnExtension->ConfigurationUpdated();
703             }
704         };
705         if (handler_ != nullptr) {
706             handler_->PostTask(task, "JsVpnExtension:OnChange");
707         }
708     }
709 
710     NETMGR_EXT_LOG_D("finished.");
711 }
712 #endif
713 } // NetManagerStandard
714 } // OHOS
715