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_static_subscriber_extension.h"
17 #include <memory>
18
19 #include "ability_info.h"
20 #include "ability_handler.h"
21 #include "event_log_wrapper.h"
22 #include "js_runtime.h"
23 #include "js_runtime_utils.h"
24 #include "js_static_subscriber_extension_context.h"
25 #include "napi_common_want.h"
26 #include "napi/native_api.h"
27 #include "napi/native_node_api.h"
28 #include "napi_remote_object.h"
29 #include "static_subscriber_stub_impl.h"
30
31 namespace OHOS {
32 namespace EventFwk {
33 namespace {
34 constexpr size_t ARGC_ONE = 1;
35 }
36
37 using namespace OHOS::AppExecFwk;
38
AttachStaticSubscriberExtensionContext(napi_env env,void * value,void *)39 napi_value AttachStaticSubscriberExtensionContext(napi_env env, void* value, void*)
40 {
41 EVENT_LOGD("AttachStaticSubscriberExtensionContext");
42 if (value == nullptr) {
43 EVENT_LOGE("invalid parameter.");
44 return nullptr;
45 }
46
47 auto ptr = reinterpret_cast<std::weak_ptr<StaticSubscriberExtensionContext>*>(value)->lock();
48 if (ptr == nullptr) {
49 EVENT_LOGE("invalid context.");
50 return nullptr;
51 }
52
53 napi_value object = CreateJsStaticSubscriberExtensionContext(env, ptr);
54 auto napiContextObj = AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(env,
55 "application.StaticSubscriberExtensionContext", &object, 1)->GetNapiValue();
56 if (napiContextObj == nullptr) {
57 EVENT_LOGE("load context failed.");
58 return nullptr;
59 }
60 napi_coerce_to_native_binding_object(env, napiContextObj, AbilityRuntime::DetachCallbackFunc,
61 AttachStaticSubscriberExtensionContext, value, nullptr);
62 auto workContext = new (std::nothrow) std::weak_ptr<StaticSubscriberExtensionContext>(ptr);
63 if (workContext == nullptr) {
64 EVENT_LOGE("invalid StaticSubscriberExtensionContext.");
65 return nullptr;
66 }
67 napi_wrap(env, napiContextObj, workContext,
68 [](napi_env, void* data, void*) {
69 EVENT_LOGI("Finalizer for weak_ptr static subscriber extension context is called");
70 delete static_cast<std::weak_ptr<StaticSubscriberExtensionContext>*>(data);
71 }, nullptr, nullptr);
72 return napiContextObj;
73 }
74
Create(const std::unique_ptr<AbilityRuntime::Runtime> & runtime)75 JsStaticSubscriberExtension* JsStaticSubscriberExtension::Create(
76 const std::unique_ptr<AbilityRuntime::Runtime>& runtime)
77 {
78 return new (std::nothrow) JsStaticSubscriberExtension(static_cast<AbilityRuntime::JsRuntime&>(*runtime));
79 }
80
JsStaticSubscriberExtension(AbilityRuntime::JsRuntime & jsRuntime)81 JsStaticSubscriberExtension::JsStaticSubscriberExtension(AbilityRuntime::JsRuntime& jsRuntime)
82 : jsRuntime_(jsRuntime) {}
~JsStaticSubscriberExtension()83 JsStaticSubscriberExtension::~JsStaticSubscriberExtension()
84 {
85 EVENT_LOGD("Js static subscriber extension destructor.");
86 auto context = GetContext();
87 if (context) {
88 context->Unbind();
89 }
90
91 jsRuntime_.FreeNativeReference(std::move(jsObj_));
92 }
93
Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord> & record,const std::shared_ptr<AppExecFwk::OHOSApplication> & application,std::shared_ptr<AppExecFwk::AbilityHandler> & handler,const sptr<IRemoteObject> & token)94 void JsStaticSubscriberExtension::Init(const std::shared_ptr<AppExecFwk::AbilityLocalRecord>& record,
95 const std::shared_ptr<AppExecFwk::OHOSApplication>& application,
96 std::shared_ptr<AppExecFwk::AbilityHandler>& handler,
97 const sptr<IRemoteObject>& token)
98 {
99 StaticSubscriberExtension::Init(record, application, handler, token);
100 if (Extension::abilityInfo_->srcEntrance.empty()) {
101 EVENT_LOGE("srcEntrance of abilityInfo is empty");
102 return;
103 }
104
105 std::string srcPath(Extension::abilityInfo_->moduleName + "/");
106 srcPath.append(Extension::abilityInfo_->srcEntrance);
107 srcPath.erase(srcPath.rfind('.'));
108 srcPath.append(".abc");
109
110 std::string moduleName(Extension::abilityInfo_->moduleName);
111 moduleName.append("::").append(abilityInfo_->name);
112 EVENT_LOGD("moduleName: %{public}s, srcPath: %{public}s.", moduleName.c_str(), srcPath.c_str());
113 AbilityRuntime::HandleScope handleScope(jsRuntime_);
114 napi_env env = jsRuntime_.GetNapiEnv();
115
116 jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath, abilityInfo_->hapPath,
117 abilityInfo_->compileMode == CompileMode::ES_MODULE);
118 if (jsObj_ == nullptr) {
119 EVENT_LOGE("Failed to load module");
120 return;
121 }
122 napi_value obj = jsObj_->GetNapiValue();
123 if (obj == nullptr) {
124 EVENT_LOGE("Failed to get static subscriber extension object");
125 return;
126 }
127 ExecNapiWrap(env, obj);
128 }
129
ExecNapiWrap(napi_env env,napi_value obj)130 void JsStaticSubscriberExtension::ExecNapiWrap(napi_env env, napi_value obj)
131 {
132 auto context = GetContext();
133 if (context == nullptr) {
134 EVENT_LOGE("Failed to get context");
135 return;
136 }
137
138 napi_value contextObj = CreateJsStaticSubscriberExtensionContext(env, context);
139 auto shellContextRef = AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(
140 env, "application.StaticSubscriberExtensionContext", &contextObj, ARGC_ONE);
141 if (shellContextRef == nullptr) {
142 EVENT_LOGE("Failed to get shell context reference");
143 return;
144 }
145 napi_value nativeObj = shellContextRef->GetNapiValue();
146 if (nativeObj == nullptr) {
147 EVENT_LOGE("Failed to get context native object");
148 return;
149 }
150
151 auto workContext = new (std::nothrow) std::weak_ptr<StaticSubscriberExtensionContext>(context);
152 if (workContext == nullptr) {
153 EVENT_LOGE("invalid StaticSubscriberExtensionContext.");
154 return;
155 }
156 napi_coerce_to_native_binding_object(env, nativeObj, AbilityRuntime::DetachCallbackFunc,
157 AttachStaticSubscriberExtensionContext, workContext, nullptr);
158 context->Bind(jsRuntime_, shellContextRef.release());
159 napi_set_named_property(env, obj, "context", nativeObj);
160
161 EVENT_LOGD("Set static subscriber extension context");
162 napi_wrap(env, nativeObj, workContext,
163 [](napi_env, void* data, void*) {
164 EVENT_LOGI("Finalizer for weak_ptr static subscriber extension context is called");
165 delete static_cast<std::weak_ptr<StaticSubscriberExtensionContext>*>(data);
166 }, nullptr, nullptr);
167
168 EVENT_LOGI("Init end.");
169 }
170
OnStart(const AAFwk::Want & want)171 void JsStaticSubscriberExtension::OnStart(const AAFwk::Want& want)
172 {
173 EVENT_LOGD("%{public}s called.", __func__);
174 Extension::OnStart(want);
175 }
176
OnStop()177 void JsStaticSubscriberExtension::OnStop()
178 {
179 EVENT_LOGD("%{public}s called.", __func__);
180 Extension::OnStop();
181 }
182
OnConnect(const AAFwk::Want & want)183 sptr<IRemoteObject> JsStaticSubscriberExtension::OnConnect(const AAFwk::Want& want)
184 {
185 EVENT_LOGD("%{public}s called.", __func__);
186 Extension::OnConnect(want);
187 sptr<StaticSubscriberStubImpl> remoteObject = new (std::nothrow) StaticSubscriberStubImpl(
188 std::static_pointer_cast<JsStaticSubscriberExtension>(shared_from_this()));
189 if (remoteObject == nullptr) {
190 EVENT_LOGE("failed to create StaticSubscriberStubImpl!");
191 return nullptr;
192 }
193 return remoteObject->AsObject();
194 }
195
OnDisconnect(const AAFwk::Want & want)196 void JsStaticSubscriberExtension::OnDisconnect(const AAFwk::Want& want)
197 {
198 EVENT_LOGD("%{public}s called.", __func__);
199 Extension::OnDisconnect(want);
200 }
201
GetWeakPtr()202 std::weak_ptr<JsStaticSubscriberExtension> JsStaticSubscriberExtension::GetWeakPtr()
203 {
204 return std::static_pointer_cast<JsStaticSubscriberExtension>(shared_from_this());
205 }
206
OnReceiveEvent(std::shared_ptr<CommonEventData> data)207 void JsStaticSubscriberExtension::OnReceiveEvent(std::shared_ptr<CommonEventData> data)
208 {
209 EVENT_LOGD("%{public}s called.", __func__);
210 if (handler_ == nullptr) {
211 EVENT_LOGE("handler is invalid");
212 return;
213 }
214 std::weak_ptr<JsStaticSubscriberExtension> wThis = GetWeakPtr();
215
216 auto task = [wThis, data]() {
217 std::shared_ptr<JsStaticSubscriberExtension> sThis = wThis.lock();
218 if (sThis == nullptr) {
219 return;
220 }
221 if (data == nullptr) {
222 EVENT_LOGE("OnReceiveEvent common event data is invalid");
223 return;
224 }
225 if (!sThis->jsObj_) {
226 EVENT_LOGE("Not found StaticSubscriberExtension.js");
227 return;
228 }
229
230 AbilityRuntime::HandleScope handleScope(sThis->jsRuntime_);
231 napi_env env = sThis->jsRuntime_.GetNapiEnv();
232 napi_value commonEventData = nullptr;
233 napi_create_object(env, &commonEventData);
234 Want want = data->GetWant();
235
236 napi_value wantAction = nullptr;
237 napi_create_string_utf8(env, want.GetAction().c_str(), want.GetAction().size(), &wantAction);
238 napi_set_named_property(env, commonEventData, "event", wantAction);
239 napi_value wantBundle = nullptr;
240 napi_create_string_utf8(env, want.GetBundle().c_str(), want.GetBundle().size(), &wantBundle);
241 napi_set_named_property(env, commonEventData, "bundleName", wantBundle);
242 napi_value dataCode = nullptr;
243 napi_create_int32(env, data->GetCode(), &dataCode);
244 napi_set_named_property(env, commonEventData, "code", dataCode);
245 napi_value dataNapi = nullptr;
246 napi_create_string_utf8(env, data->GetData().c_str(), data->GetData().size(), &dataNapi);
247 napi_set_named_property(env, commonEventData, "data", dataNapi);
248 napi_value napiParams = AppExecFwk::WrapWantParams(
249 env, want.GetParams());
250 napi_set_named_property(env, commonEventData, "parameters", napiParams);
251
252 napi_value argv[] = {commonEventData};
253 napi_value obj = sThis->jsObj_->GetNapiValue();
254 if (obj == nullptr) {
255 EVENT_LOGE("Failed to get StaticSubscriberExtension object");
256 return;
257 }
258
259 napi_value method = nullptr;
260 napi_get_named_property(env, obj, "onReceiveEvent", &method);
261 if (method == nullptr) {
262 EVENT_LOGE("Failed to get onReceiveEvent from StaticSubscriberExtension object");
263 return;
264 }
265 napi_call_function(env, obj, method, ARGC_ONE, argv, nullptr);
266 EVENT_LOGD("JsStaticSubscriberExtension js receive event called.");
267 };
268 handler_->PostTask(task, "CommonEvent" + data->GetWant().GetAction());
269 }
270 } // namespace EventFwk
271 } // namespace OHOS
272