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_context.h"
17
18 #include <chrono>
19 #include <cstdint>
20 #include "ability_manager_client.h"
21 #include "ability_runtime/js_caller_complex.h"
22 #include "hilog_wrapper.h"
23 #include "js_extension_context.h"
24 #include "js_error_utils.h"
25 #include "js_data_struct_converter.h"
26 #include "runtime.h"
27 #include "js_runtime.h"
28 #include "js_runtime_utils.h"
29 #include "napi/native_api.h"
30 #include "napi_common_ability.h"
31 #include "napi_common_want.h"
32 #include "napi_common_util.h"
33 #include "napi_remote_object.h"
34 #include "napi_common_start_options.h"
35 #include "start_options.h"
36 #include "hitrace_meter.h"
37 #include "netmgr_ext_log_wrapper.h"
38 #include "ability_business_error/ability_business_error.h"
39
40 using namespace OHOS::AbilityRuntime;
41 namespace OHOS {
42 namespace NetManagerStandard {
43 namespace {
44 constexpr int32_t INDEX_ZERO = 0;
45 constexpr size_t ARGC_ONE = 1;
46
47 class StartAbilityByCallParameters {
48 public:
49 int err = 0;
50 sptr<IRemoteObject> remoteCallee = nullptr;
51 std::shared_ptr<CallerCallBack> callerCallBack = nullptr;
52 std::mutex mutexlock;
53 std::condition_variable condition;
54 };
55
56 static std::map<ConnectionKey, sptr<JSVpnExtensionContext>, key_compare> g_connects;
57
58 class JsVpnExtensionContext final {
59 public:
JsVpnExtensionContext(const std::shared_ptr<VpnExtensionContext> & context)60 explicit JsVpnExtensionContext(const std::shared_ptr<VpnExtensionContext>& context) : context_(context) {}
61 ~JsVpnExtensionContext() = default;
62
Finalizer(napi_env env,void * data,void * hint)63 static void Finalizer(napi_env env, void* data, void* hint)
64 {
65 NETMGR_EXT_LOG_D("JsAbilityContext::Finalizer is called");
66 std::unique_ptr<JsVpnExtensionContext>(static_cast<JsVpnExtensionContext*>(data));
67 }
68
StartVpnExtensionAbility(napi_env env,napi_callback_info info)69 static napi_value StartVpnExtensionAbility(napi_env env, napi_callback_info info)
70 {
71 GET_NAPI_INFO_AND_CALL(env, info, JsVpnExtensionContext, OnStartExtensionAbility);
72 }
73
StopVpnExtensionAbility(napi_env env,napi_callback_info info)74 static napi_value StopVpnExtensionAbility(napi_env env, napi_callback_info info)
75 {
76 GET_NAPI_INFO_AND_CALL(env, info, JsVpnExtensionContext, OnStopExtensionAbility);
77 }
78
79 private:
80 std::weak_ptr<VpnExtensionContext> context_;
81 sptr<JsFreeInstallObserver> freeInstallObserver_ = nullptr;
ClearFailedCallConnection(const std::weak_ptr<VpnExtensionContext> & vpnContext,const std::shared_ptr<CallerCallBack> & callback)82 static void ClearFailedCallConnection(
83 const std::weak_ptr<VpnExtensionContext>& vpnContext, const std::shared_ptr<CallerCallBack> &callback)
84 {
85 NETMGR_EXT_LOG_D("clear failed call of startup is called.");
86 auto context = vpnContext.lock();
87 if (context == nullptr || callback == nullptr) {
88 NETMGR_EXT_LOG_E("clear failed call of startup input param is nullptr.");
89 return;
90 }
91
92 context->ClearFailedCallConnection(callback);
93 }
94
OnStartExtensionAbility(napi_env env,NapiCallbackInfo & info)95 napi_value OnStartExtensionAbility(napi_env env, NapiCallbackInfo& info)
96 {
97 NETMGR_EXT_LOG_I("StartExtensionAbility");
98 if (info.argc < ARGC_ONE) {
99 NETMGR_EXT_LOG_E("Start extension failed, not enough params.");
100 ThrowTooFewParametersError(env);
101 return CreateJsUndefined(env);
102 }
103 AAFwk::Want want;
104 if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
105 ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
106 return CreateJsUndefined(env);
107 }
108
109 NapiAsyncTask::CompleteCallback complete =
110 [weak = context_, want](napi_env env, NapiAsyncTask& task, int32_t status) {
111 auto context = weak.lock();
112 if (!context) {
113 HILOG_WARN("context is released");
114 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
115 return;
116 }
117 auto innerErrorCode = context->StartVpnExtensionAbility(want);
118 if (innerErrorCode == 0) {
119 task.Resolve(env, CreateJsUndefined(env));
120 } else {
121 task.Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode));
122 }
123 };
124
125 napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
126 napi_value result = nullptr;
127 NapiAsyncTask::ScheduleHighQos("JSVpnExtensionContext::OnStartExtensionAbility",
128 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
129 return result;
130 }
131
OnStopExtensionAbility(napi_env env,NapiCallbackInfo & info)132 napi_value OnStopExtensionAbility(napi_env env, NapiCallbackInfo& info)
133 {
134 NETMGR_EXT_LOG_I("StopExtensionAbility");
135 if (info.argc < ARGC_ONE) {
136 NETMGR_EXT_LOG_E("Start extension failed, not enough params.");
137 ThrowTooFewParametersError(env);
138 return CreateJsUndefined(env);
139 }
140 AAFwk::Want want;
141 if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
142 ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
143 return CreateJsUndefined(env);
144 }
145
146 NapiAsyncTask::CompleteCallback complete =
147 [weak = context_, want](napi_env env, NapiAsyncTask& task, int32_t status) {
148 auto context = weak.lock();
149 if (!context) {
150 HILOG_WARN("context is released");
151 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
152 return;
153 }
154 auto innerErrorCode = context->StopVpnExtensionAbility(want);
155 if (innerErrorCode == 0) {
156 task.Resolve(env, CreateJsUndefined(env));
157 } else {
158 task.Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode));
159 }
160 };
161
162 napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
163 napi_value result = nullptr;
164 NapiAsyncTask::Schedule("JSVpnExtensionContext::OnStopExtensionAbility",
165 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
166 return result;
167 }
168 };
169 } // namespace
170
CreateJsVpnExtensionContext(napi_env env,std::shared_ptr<VpnExtensionContext> context)171 napi_value CreateJsVpnExtensionContext(napi_env env, std::shared_ptr<VpnExtensionContext> context)
172 {
173 NETMGR_EXT_LOG_D("CreateJsVpnExtensionContext");
174 std::shared_ptr<OHOS::AppExecFwk::AbilityInfo> abilityInfo = nullptr;
175 if (context) {
176 abilityInfo = context->GetAbilityInfo();
177 }
178 napi_value object = CreateJsExtensionContext(env, context, abilityInfo);
179
180 std::unique_ptr<JsVpnExtensionContext> jsContext = std::make_unique<JsVpnExtensionContext>(context);
181 napi_wrap(env, object, jsContext.release(), JsVpnExtensionContext::Finalizer, nullptr, nullptr);
182
183 const char *moduleName = "JsVpnExtensionContext";
184 BindNativeFunction(env, object, "startVpnExtensionAbility", moduleName,
185 JsVpnExtensionContext::StartVpnExtensionAbility);
186 BindNativeFunction(env, object, "stopVpnExtensionAbility", moduleName,
187 JsVpnExtensionContext::StopVpnExtensionAbility);
188 return object;
189 }
190
JSVpnExtensionContext(napi_env env)191 JSVpnExtensionContext::JSVpnExtensionContext(napi_env env) : env_(env) {}
192
~JSVpnExtensionContext()193 JSVpnExtensionContext::~JSVpnExtensionContext()
194 {
195 if (jsConnectionObject_ == nullptr) {
196 return;
197 }
198
199 uv_loop_t *loop = nullptr;
200 napi_get_uv_event_loop(env_, &loop);
201 if (loop == nullptr) {
202 return;
203 }
204
205 uv_work_t *work = new (std::nothrow) uv_work_t;
206 if (work == nullptr) {
207 return;
208 }
209 work->data = reinterpret_cast<void *>(jsConnectionObject_.release());
210 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
211 [](uv_work_t *work, int status) {
212 if (work == nullptr) {
213 return;
214 }
215 if (work->data == nullptr) {
216 delete work;
217 work = nullptr;
218 return;
219 }
220 delete reinterpret_cast<NativeReference *>(work->data);
221 work->data = nullptr;
222 delete work;
223 work = nullptr;
224 });
225 if (ret != 0) {
226 delete reinterpret_cast<NativeReference *>(work->data);
227 work->data = nullptr;
228 delete work;
229 work = nullptr;
230 }
231 }
232 } // namespace NetManagerStandard
233 } // namespace OHOS
234