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