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