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