1 /*
2 * Copyright (c) 2021-2022 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_service_extension.h"
17
18 #include "ability_info.h"
19 #include "bytrace.h"
20 #include "hilog_wrapper.h"
21 #include "js_extension_context.h"
22 #include "js_runtime.h"
23 #include "js_runtime_utils.h"
24 #include "js_service_extension_context.h"
25 #include "napi/native_api.h"
26 #include "napi/native_node_api.h"
27 #include "napi_common_configuration.h"
28 #include "napi_common_want.h"
29 #include "napi_remote_object.h"
30
31 namespace OHOS {
32 namespace AbilityRuntime {
33 namespace {
34 constexpr size_t ARGC_ONE = 1;
35 constexpr size_t ARGC_TWO = 2;
36 }
37
38 using namespace OHOS::AppExecFwk;
Create(const std::unique_ptr<Runtime> & runtime)39 JsServiceExtension* JsServiceExtension::Create(const std::unique_ptr<Runtime>& runtime)
40 {
41 return new JsServiceExtension(static_cast<JsRuntime&>(*runtime));
42 }
43
JsServiceExtension(JsRuntime & jsRuntime)44 JsServiceExtension::JsServiceExtension(JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
45 JsServiceExtension::~JsServiceExtension() = default;
46
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)47 void JsServiceExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
48 const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
49 const sptr<IRemoteObject> &token)
50 {
51 ServiceExtension::Init(record, application, handler, token);
52 std::string srcPath = "";
53 GetSrcPath(srcPath);
54 if (srcPath.empty()) {
55 HILOG_ERROR("Failed to get srcPath");
56 return;
57 }
58
59 std::string moduleName(Extension::abilityInfo_->moduleName);
60 moduleName.append("::").append(abilityInfo_->name);
61 HILOG_INFO("JsServiceExtension::Init module:%{public}s,srcPath:%{public}s.", moduleName.c_str(), srcPath.c_str());
62 HandleScope handleScope(jsRuntime_);
63 auto& engine = jsRuntime_.GetNativeEngine();
64
65 jsObj_ = jsRuntime_.LoadModule(moduleName, srcPath);
66 if (jsObj_ == nullptr) {
67 HILOG_ERROR("Failed to get jsObj_");
68 return;
69 }
70 HILOG_INFO("JsServiceExtension::Init ConvertNativeValueTo.");
71 NativeObject* obj = ConvertNativeValueTo<NativeObject>(jsObj_->Get());
72 if (obj == nullptr) {
73 HILOG_ERROR("Failed to get JsServiceExtension object");
74 return;
75 }
76
77 auto context = GetContext();
78 if (context == nullptr) {
79 HILOG_ERROR("Failed to get context");
80 return;
81 }
82 HILOG_INFO("JsServiceExtension::Init CreateJsServiceExtensionContext.");
83 NativeValue* contextObj = CreateJsServiceExtensionContext(engine, context);
84 shellContextRef_ = jsRuntime_.LoadSystemModule("application.ServiceExtensionContext", &contextObj, ARGC_ONE);
85 contextObj = shellContextRef_->Get();
86 HILOG_INFO("JsServiceExtension::Init Bind.");
87 context->Bind(jsRuntime_, shellContextRef_.get());
88 HILOG_INFO("JsServiceExtension::SetProperty.");
89 obj->SetProperty("context", contextObj);
90
91 auto nativeObj = ConvertNativeValueTo<NativeObject>(contextObj);
92 if (nativeObj == nullptr) {
93 HILOG_ERROR("Failed to get service extension native object");
94 return;
95 }
96
97 HILOG_INFO("Set service extension context pointer: %{public}p", context.get());
98
99 nativeObj->SetNativePointer(new std::weak_ptr<AbilityRuntime::Context>(context),
100 [](NativeEngine*, void* data, void*) {
101 HILOG_INFO("Finalizer for weak_ptr service extension context is called");
102 delete static_cast<std::weak_ptr<AbilityRuntime::Context>*>(data);
103 }, nullptr);
104
105 HILOG_INFO("JsServiceExtension::Init end.");
106 }
107
OnStart(const AAFwk::Want & want)108 void JsServiceExtension::OnStart(const AAFwk::Want &want)
109 {
110 Extension::OnStart(want);
111 HILOG_INFO("JsServiceExtension OnStart begin..");
112 HandleScope handleScope(jsRuntime_);
113 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
114 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
115 NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
116 NativeValue* argv[] = {nativeWant};
117 CallObjectMethod("onCreate", argv, ARGC_ONE);
118 HILOG_INFO("%{public}s end.", __func__);
119 }
120
OnStop()121 void JsServiceExtension::OnStop()
122 {
123 ServiceExtension::OnStop();
124 HILOG_INFO("JsServiceExtension OnStop begin.");
125 CallObjectMethod("onDestroy");
126 bool ret = ConnectionManager::GetInstance().DisconnectCaller(GetContext()->GetToken());
127 if (ret) {
128 ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid());
129 HILOG_INFO("The service extension connection is not disconnected.");
130 }
131 HILOG_INFO("%{public}s end.", __func__);
132 }
133
OnConnect(const AAFwk::Want & want)134 sptr<IRemoteObject> JsServiceExtension::OnConnect(const AAFwk::Want &want)
135 {
136 BYTRACE_NAME(BYTRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
137 Extension::OnConnect(want);
138 HILOG_INFO("%{public}s begin.", __func__);
139 HandleScope handleScope(jsRuntime_);
140 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
141 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
142 NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
143 NativeValue* argv[] = {nativeWant};
144 if (!jsObj_) {
145 HILOG_WARN("Not found ServiceExtension.js");
146 return nullptr;
147 }
148
149 NativeValue* value = jsObj_->Get();
150 NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
151 if (obj == nullptr) {
152 HILOG_ERROR("Failed to get ServiceExtension object");
153 return nullptr;
154 }
155
156 NativeValue* method = obj->GetProperty("onConnect");
157 if (method == nullptr) {
158 HILOG_ERROR("Failed to get onConnect from ServiceExtension object");
159 return nullptr;
160 }
161 HILOG_INFO("JsServiceExtension::CallFunction onConnect, success");
162 NativeValue* remoteNative = nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
163 if (remoteNative == nullptr) {
164 HILOG_ERROR("remoteNative nullptr.");
165 }
166 auto remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(
167 reinterpret_cast<napi_env>(nativeEngine), reinterpret_cast<napi_value>(remoteNative));
168 if (remoteObj == nullptr) {
169 HILOG_ERROR("remoteObj nullptr.");
170 }
171 return remoteObj;
172 }
173
OnDisconnect(const AAFwk::Want & want)174 void JsServiceExtension::OnDisconnect(const AAFwk::Want &want)
175 {
176 BYTRACE_NAME(BYTRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
177 Extension::OnDisconnect(want);
178 HILOG_INFO("%{public}s begin.", __func__);
179 HandleScope handleScope(jsRuntime_);
180 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
181 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
182 NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
183 NativeValue* argv[] = {nativeWant};
184 if (!jsObj_) {
185 HILOG_WARN("Not found ServiceExtension.js");
186 return;
187 }
188
189 NativeValue* value = jsObj_->Get();
190 NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
191 if (obj == nullptr) {
192 HILOG_ERROR("Failed to get ServiceExtension object");
193 return;
194 }
195
196 NativeValue* method = obj->GetProperty("onDisconnect");
197 if (method == nullptr) {
198 HILOG_ERROR("Failed to get onDisconnect from ServiceExtension object");
199 return;
200 }
201 nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
202 HILOG_INFO("%{public}s end.", __func__);
203 }
204
OnCommand(const AAFwk::Want & want,bool restart,int startId)205 void JsServiceExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId)
206 {
207 Extension::OnCommand(want, restart, startId);
208 HILOG_INFO("%{public}s begin restart=%{public}s,startId=%{public}d.",
209 __func__,
210 restart ? "true" : "false",
211 startId);
212 // wrap want
213 HandleScope handleScope(jsRuntime_);
214 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
215 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
216 NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
217 // wrap startId
218 napi_value napiStartId = nullptr;
219 napi_create_int32(reinterpret_cast<napi_env>(nativeEngine), startId, &napiStartId);
220 NativeValue* nativeStartId = reinterpret_cast<NativeValue*>(napiStartId);
221 NativeValue* argv[] = {nativeWant, nativeStartId};
222 CallObjectMethod("onRequest", argv, ARGC_TWO);
223 HILOG_INFO("%{public}s end.", __func__);
224 }
225
CallObjectMethod(const char * name,NativeValue * const * argv,size_t argc)226 NativeValue* JsServiceExtension::CallObjectMethod(const char* name, NativeValue* const* argv, size_t argc)
227 {
228 HILOG_INFO("JsServiceExtension::CallObjectMethod(%{public}s), begin", name);
229
230 if (!jsObj_) {
231 HILOG_WARN("Not found ServiceExtension.js");
232 return nullptr;
233 }
234
235 HandleScope handleScope(jsRuntime_);
236 auto& nativeEngine = jsRuntime_.GetNativeEngine();
237
238 NativeValue* value = jsObj_->Get();
239 NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
240 if (obj == nullptr) {
241 HILOG_ERROR("Failed to get ServiceExtension object");
242 return nullptr;
243 }
244
245 NativeValue* method = obj->GetProperty(name);
246 if (method == nullptr || method->TypeOf() != NATIVE_FUNCTION) {
247 HILOG_ERROR("Failed to get '%{public}s' from ServiceExtension object", name);
248 return nullptr;
249 }
250 HILOG_INFO("JsServiceExtension::CallFunction(%{public}s), success", name);
251 return nativeEngine.CallFunction(value, method, argv, argc);
252 }
253
GetSrcPath(std::string & srcPath)254 void JsServiceExtension::GetSrcPath(std::string &srcPath)
255 {
256 if (!Extension::abilityInfo_->isModuleJson) {
257 /* temporary compatibility api8 + config.json */
258 srcPath.append(Extension::abilityInfo_->package);
259 srcPath.append("/assets/js/");
260 if (!Extension::abilityInfo_->srcPath.empty()) {
261 srcPath.append(Extension::abilityInfo_->srcPath);
262 }
263 srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
264 return;
265 }
266
267 if (!Extension::abilityInfo_->srcEntrance.empty()) {
268 srcPath.append(Extension::abilityInfo_->moduleName + "/");
269 srcPath.append(Extension::abilityInfo_->srcEntrance);
270 srcPath.erase(srcPath.rfind('.'));
271 srcPath.append(".abc");
272 }
273 }
274
OnConfigurationUpdated(const AppExecFwk::Configuration & configuration)275 void JsServiceExtension::OnConfigurationUpdated(const AppExecFwk::Configuration& configuration)
276 {
277 Extension::OnConfigurationUpdated(configuration);
278 HILOG_INFO("%{public}s called.", __func__);
279
280 HandleScope handleScope(jsRuntime_);
281 auto& nativeEngine = jsRuntime_.GetNativeEngine();
282
283 // Notify extension context
284 auto fullConfig = GetContext()->GetConfiguration();
285 if (!fullConfig) {
286 HILOG_ERROR("configuration is nullptr.");
287 return;
288 }
289 JsExtensionContext::ConfigurationUpdated(&nativeEngine, shellContextRef_, fullConfig);
290
291 napi_value napiConfiguration = OHOS::AppExecFwk::WrapConfiguration(
292 reinterpret_cast<napi_env>(&nativeEngine), *fullConfig);
293 NativeValue* jsConfiguration = reinterpret_cast<NativeValue*>(napiConfiguration);
294 CallObjectMethod("onConfigurationUpdated", &jsConfiguration, 1);
295 }
296 }
297 }
298