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_handler.h"
19 #include "ability_info.h"
20 #include "configuration_utils.h"
21 #include "hitrace_meter.h"
22 #include "hilog_wrapper.h"
23 #include "js_extension_common.h"
24 #include "js_extension_context.h"
25 #include "js_runtime.h"
26 #include "js_runtime_utils.h"
27 #include "js_service_extension_context.h"
28 #include "napi/native_api.h"
29 #include "napi/native_node_api.h"
30 #include "napi_common_configuration.h"
31 #include "napi_common_want.h"
32 #include "napi_remote_object.h"
33 #ifdef SUPPORT_GRAPHICS
34 #include "iservice_registry.h"
35 #include "system_ability_definition.h"
36 #include "window_scene.h"
37 #endif
38
39 namespace OHOS {
40 namespace AbilityRuntime {
41 namespace {
42 constexpr size_t ARGC_ONE = 1;
43 constexpr size_t ARGC_TWO = 2;
44 }
45
46 namespace {
PromiseCallback(NativeEngine * engine,NativeCallbackInfo * info)47 NativeValue *PromiseCallback(NativeEngine *engine, NativeCallbackInfo *info)
48 {
49 if (info == nullptr || info->functionInfo == nullptr || info->functionInfo->data == nullptr) {
50 HILOG_ERROR("PromiseCallback, Invalid input info.");
51 return nullptr;
52 }
53 void *data = info->functionInfo->data;
54 auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<> *>(data);
55 callbackInfo->Call();
56 AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo);
57 info->functionInfo->data = nullptr;
58 return nullptr;
59 }
60
OnConnectPromiseCallback(NativeEngine * engine,NativeCallbackInfo * info)61 NativeValue *OnConnectPromiseCallback(NativeEngine *engine, NativeCallbackInfo *info)
62 {
63 if (info == nullptr || info->functionInfo == nullptr || info->functionInfo->data == nullptr) {
64 HILOG_ERROR("PromiseCallback, Invalid input info.");
65 return nullptr;
66 }
67 void *data = info->functionInfo->data;
68 auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *>(data);
69 sptr<IRemoteObject> service = nullptr;
70 if (info->argc > 0) {
71 service = NAPI_ohos_rpc_getNativeRemoteObject(reinterpret_cast<napi_env>(engine),
72 reinterpret_cast<napi_value>(info->argv[0]));
73 }
74 callbackInfo->Call(service);
75 AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>>::Destroy(callbackInfo);
76 info->functionInfo->data = nullptr;
77 return nullptr;
78 }
79 }
80
81 using namespace OHOS::AppExecFwk;
82
AttachServiceExtensionContext(NativeEngine * engine,void * value,void *)83 NativeValue *AttachServiceExtensionContext(NativeEngine *engine, void *value, void *)
84 {
85 HILOG_INFO("call");
86 if (value == nullptr) {
87 HILOG_WARN("invalid parameter.");
88 return nullptr;
89 }
90 auto ptr = reinterpret_cast<std::weak_ptr<ServiceExtensionContext> *>(value)->lock();
91 if (ptr == nullptr) {
92 HILOG_WARN("invalid context.");
93 return nullptr;
94 }
95 NativeValue *object = CreateJsServiceExtensionContext(*engine, ptr);
96 auto contextObj = JsRuntime::LoadSystemModuleByEngine(engine,
97 "application.ServiceExtensionContext", &object, 1)->Get();
98 NativeObject *nObject = ConvertNativeValueTo<NativeObject>(contextObj);
99 nObject->ConvertToNativeBindingObject(engine, DetachCallbackFunc, AttachServiceExtensionContext,
100 value, nullptr);
101 auto workContext = new (std::nothrow) std::weak_ptr<ServiceExtensionContext>(ptr);
102 nObject->SetNativePointer(workContext,
103 [](NativeEngine *, void *data, void *) {
104 HILOG_INFO("Finalizer for weak_ptr service extension context is called");
105 delete static_cast<std::weak_ptr<ServiceExtensionContext> *>(data);
106 }, nullptr);
107 return contextObj;
108 }
109
Create(const std::unique_ptr<Runtime> & runtime)110 JsServiceExtension* JsServiceExtension::Create(const std::unique_ptr<Runtime>& runtime)
111 {
112 return new JsServiceExtension(static_cast<JsRuntime&>(*runtime));
113 }
114
JsServiceExtension(JsRuntime & jsRuntime)115 JsServiceExtension::JsServiceExtension(JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
~JsServiceExtension()116 JsServiceExtension::~JsServiceExtension()
117 {
118 HILOG_DEBUG("Js service extension destructor.");
119 auto context = GetContext();
120 if (context) {
121 context->Unbind();
122 }
123
124 jsRuntime_.FreeNativeReference(std::move(jsObj_));
125 jsRuntime_.FreeNativeReference(std::move(shellContextRef_));
126 }
127
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)128 void JsServiceExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
129 const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
130 const sptr<IRemoteObject> &token)
131 {
132 ServiceExtension::Init(record, application, handler, token);
133 std::string srcPath = "";
134 GetSrcPath(srcPath);
135 if (srcPath.empty()) {
136 HILOG_ERROR("Failed to get srcPath");
137 return;
138 }
139
140 std::string moduleName(Extension::abilityInfo_->moduleName);
141 moduleName.append("::").append(abilityInfo_->name);
142 HILOG_DEBUG("JsServiceExtension::Init moduleName:%{public}s,srcPath:%{public}s.",
143 moduleName.c_str(), srcPath.c_str());
144 HandleScope handleScope(jsRuntime_);
145 auto& engine = jsRuntime_.GetNativeEngine();
146
147 jsObj_ = jsRuntime_.LoadModule(
148 moduleName, srcPath, abilityInfo_->hapPath, abilityInfo_->compileMode == CompileMode::ES_MODULE);
149 if (jsObj_ == nullptr) {
150 HILOG_ERROR("Failed to get jsObj_");
151 return;
152 }
153
154 HILOG_INFO("JsServiceExtension::Init ConvertNativeValueTo.");
155 NativeObject* obj = ConvertNativeValueTo<NativeObject>(jsObj_->Get());
156 if (obj == nullptr) {
157 HILOG_ERROR("Failed to get JsServiceExtension object");
158 return;
159 }
160
161 BindContext(engine, obj);
162
163 SetExtensionCommon(JsExtensionCommon::Create(jsRuntime_, static_cast<NativeReference&>(*jsObj_), shellContextRef_));
164
165 handler_ = handler;
166 auto context = GetContext();
167 auto appContext = Context::GetApplicationContext();
168 if (context != nullptr && appContext != nullptr) {
169 auto appConfig = appContext->GetConfiguration();
170 if (appConfig != nullptr) {
171 HILOG_DEBUG("Original config dump: %{public}s", appConfig->GetName().c_str());
172 context->SetConfiguration(std::make_shared<Configuration>(*appConfig));
173 }
174 }
175 ListenWMS();
176 }
177
ListenWMS()178 void JsServiceExtension::ListenWMS()
179 {
180 #ifdef SUPPORT_GRAPHICS
181 HILOG_INFO("RegisterDisplayListener");
182 auto abilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
183 if (abilityManager == nullptr) {
184 HILOG_ERROR("Failed to get SaMgr.");
185 return;
186 }
187 auto jsServiceExtension = std::static_pointer_cast<JsServiceExtension>(shared_from_this());
188 displayListener_ = new JsServiceExtensionDisplayListener(jsServiceExtension);
189 sptr<ISystemAbilityStatusChange> listener = new SystemAbilityStatusChangeListener(displayListener_);
190 auto ret = abilityManager->SubscribeSystemAbility(WINDOW_MANAGER_SERVICE_ID, listener);
191 if (ret != 0) {
192 HILOG_ERROR("subscribe system ability failed, ret = %{public}d.", ret);
193 }
194 #endif
195 }
196
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)197 void JsServiceExtension::SystemAbilityStatusChangeListener::OnAddSystemAbility(int32_t systemAbilityId,
198 const std::string& deviceId)
199 {
200 HILOG_INFO("systemAbilityId: %{public}d add", systemAbilityId);
201 if (systemAbilityId == WINDOW_MANAGER_SERVICE_ID) {
202 Rosen::DisplayManager::GetInstance().RegisterDisplayListener(tmpDisplayListener_);
203 }
204 }
205
BindContext(NativeEngine & engine,NativeObject * obj)206 void JsServiceExtension::BindContext(NativeEngine& engine, NativeObject* obj)
207 {
208 auto context = GetContext();
209 if (context == nullptr) {
210 HILOG_ERROR("Failed to get context");
211 return;
212 }
213 HILOG_INFO("call");
214 NativeValue* contextObj = CreateJsServiceExtensionContext(engine, context);
215 shellContextRef_ = JsRuntime::LoadSystemModuleByEngine(&engine, "application.ServiceExtensionContext",
216 &contextObj, ARGC_ONE);
217 contextObj = shellContextRef_->Get();
218 NativeObject *nativeObj = ConvertNativeValueTo<NativeObject>(contextObj);
219 if (nativeObj == nullptr) {
220 HILOG_ERROR("Failed to get context native object");
221 return;
222 }
223 auto workContext = new (std::nothrow) std::weak_ptr<ServiceExtensionContext>(context);
224 nativeObj->ConvertToNativeBindingObject(&engine, DetachCallbackFunc, AttachServiceExtensionContext,
225 workContext, nullptr);
226 HILOG_INFO("JsServiceExtension::Init Bind.");
227 context->Bind(jsRuntime_, shellContextRef_.get());
228 HILOG_INFO("JsServiceExtension::SetProperty.");
229 obj->SetProperty("context", contextObj);
230 HILOG_INFO("Set service extension context");
231
232 nativeObj->SetNativePointer(workContext,
233 [](NativeEngine*, void* data, void*) {
234 HILOG_INFO("Finalizer for weak_ptr service extension context is called");
235 delete static_cast<std::weak_ptr<ServiceExtensionContext>*>(data);
236 }, nullptr);
237
238 HILOG_INFO("JsServiceExtension::Init end.");
239 }
240
OnStart(const AAFwk::Want & want)241 void JsServiceExtension::OnStart(const AAFwk::Want &want)
242 {
243 Extension::OnStart(want);
244 HILOG_INFO("call");
245
246 auto context = GetContext();
247 if (context != nullptr) {
248 int displayId = want.GetIntParam(Want::PARAM_RESV_DISPLAY_ID, Rosen::WindowScene::DEFAULT_DISPLAY_ID);
249 auto configUtils = std::make_shared<ConfigurationUtils>();
250 configUtils->InitDisplayConfig(displayId, context->GetConfiguration(), context->GetResourceManager());
251 }
252
253 HandleScope handleScope(jsRuntime_);
254 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
255
256 // display config has changed, need update context.config
257 JsExtensionContext::ConfigurationUpdated(nativeEngine, shellContextRef_, context->GetConfiguration());
258
259 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
260 NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
261 NativeValue* argv[] = {nativeWant};
262 CallObjectMethod("onCreate", argv, ARGC_ONE);
263 HILOG_INFO("ok");
264 }
265
OnStop()266 void JsServiceExtension::OnStop()
267 {
268 ServiceExtension::OnStop();
269 HILOG_INFO("call");
270 CallObjectMethod("onDestroy");
271 bool ret = ConnectionManager::GetInstance().DisconnectCaller(GetContext()->GetToken());
272 if (ret) {
273 ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid());
274 HILOG_INFO("The service extension connection is not disconnected.");
275 }
276 Rosen::DisplayManager::GetInstance().UnregisterDisplayListener(displayListener_);
277 HILOG_INFO("ok");
278 }
279
OnConnect(const AAFwk::Want & want)280 sptr<IRemoteObject> JsServiceExtension::OnConnect(const AAFwk::Want &want)
281 {
282 HandleScope handleScope(jsRuntime_);
283 NativeValue *result = CallOnConnect(want);
284 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
285 auto remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(
286 reinterpret_cast<napi_env>(nativeEngine), reinterpret_cast<napi_value>(result));
287 if (remoteObj == nullptr) {
288 HILOG_ERROR("remoteObj nullptr.");
289 }
290 return remoteObj;
291 }
292
OnConnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> * callbackInfo,bool & isAsyncCallback)293 sptr<IRemoteObject> JsServiceExtension::OnConnect(const AAFwk::Want &want,
294 AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *callbackInfo, bool &isAsyncCallback)
295 {
296 HandleScope handleScope(jsRuntime_);
297 NativeEngine *nativeEngine = &jsRuntime_.GetNativeEngine();
298 NativeValue *result = CallOnConnect(want);
299 bool isPromise = CheckPromise(result);
300 if (!isPromise) {
301 isAsyncCallback = false;
302 sptr<IRemoteObject> remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(reinterpret_cast<napi_env>(nativeEngine),
303 reinterpret_cast<napi_value>(result));
304 if (remoteObj == nullptr) {
305 HILOG_ERROR("remoteObj nullptr.");
306 }
307 return remoteObj;
308 }
309
310 bool callResult = false;
311 do {
312 auto *retObj = ConvertNativeValueTo<NativeObject>(result);
313 if (retObj == nullptr) {
314 HILOG_ERROR("CallPromise, Failed to convert native value to NativeObject.");
315 break;
316 }
317 NativeValue *then = retObj->GetProperty("then");
318 if (then == nullptr) {
319 HILOG_ERROR("CallPromise, Failed to get property: then.");
320 break;
321 }
322 if (!then->IsCallable()) {
323 HILOG_ERROR("CallPromise, property then is not callable.");
324 break;
325 }
326 auto promiseCallback = nativeEngine->CreateFunction("promiseCallback", strlen("promiseCallback"),
327 OnConnectPromiseCallback, callbackInfo);
328 NativeValue *argv[1] = { promiseCallback };
329 nativeEngine->CallFunction(result, then, argv, 1);
330 callResult = true;
331 } while (false);
332
333 if (!callResult) {
334 HILOG_ERROR("Failed to call promise.");
335 isAsyncCallback = false;
336 } else {
337 isAsyncCallback = true;
338 }
339 return nullptr;
340 }
341
OnDisconnect(const AAFwk::Want & want)342 void JsServiceExtension::OnDisconnect(const AAFwk::Want &want)
343 {
344 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
345 Extension::OnDisconnect(want);
346 HILOG_DEBUG("%{public}s begin.", __func__);
347 CallOnDisconnect(want, false);
348 HILOG_DEBUG("%{public}s end.", __func__);
349 }
350
OnDisconnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo,bool & isAsyncCallback)351 void JsServiceExtension::OnDisconnect(const AAFwk::Want &want,
352 AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback)
353 {
354 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
355 Extension::OnDisconnect(want);
356 HILOG_DEBUG("%{public}s begin.", __func__);
357 NativeValue *result = CallOnDisconnect(want, true);
358 bool isPromise = CheckPromise(result);
359 if (!isPromise) {
360 isAsyncCallback = false;
361 return;
362 }
363 bool callResult = CallPromise(result, callbackInfo);
364 if (!callResult) {
365 HILOG_ERROR("Failed to call promise.");
366 isAsyncCallback = false;
367 } else {
368 isAsyncCallback = true;
369 }
370
371 HILOG_DEBUG("%{public}s end.", __func__);
372 }
373
OnCommand(const AAFwk::Want & want,bool restart,int startId)374 void JsServiceExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId)
375 {
376 Extension::OnCommand(want, restart, startId);
377 HILOG_INFO("restart=%{public}s,startId=%{public}d.",
378 restart ? "true" : "false",
379 startId);
380 // wrap want
381 HandleScope handleScope(jsRuntime_);
382 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
383 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
384 NativeValue* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
385 // wrap startId
386 napi_value napiStartId = nullptr;
387 napi_create_int32(reinterpret_cast<napi_env>(nativeEngine), startId, &napiStartId);
388 NativeValue* nativeStartId = reinterpret_cast<NativeValue*>(napiStartId);
389 NativeValue* argv[] = {nativeWant, nativeStartId};
390 CallObjectMethod("onRequest", argv, ARGC_TWO);
391 HILOG_INFO("ok");
392 }
393
CallObjectMethod(const char * name,NativeValue * const * argv,size_t argc)394 NativeValue* JsServiceExtension::CallObjectMethod(const char* name, NativeValue* const* argv, size_t argc)
395 {
396 HILOG_INFO("CallObjectMethod(%{public}s)", name);
397
398 if (!jsObj_) {
399 HILOG_WARN("Not found ServiceExtension.js");
400 return nullptr;
401 }
402
403 HandleScope handleScope(jsRuntime_);
404 auto& nativeEngine = jsRuntime_.GetNativeEngine();
405
406 NativeValue* value = jsObj_->Get();
407 NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
408 if (obj == nullptr) {
409 HILOG_ERROR("Failed to get ServiceExtension object");
410 return nullptr;
411 }
412
413 NativeValue* method = obj->GetProperty(name);
414 if (method == nullptr || method->TypeOf() != NATIVE_FUNCTION) {
415 HILOG_ERROR("Failed to get '%{public}s' from ServiceExtension object", name);
416 return nullptr;
417 }
418 HILOG_INFO("CallFunction(%{public}s) ok", name);
419 return nativeEngine.CallFunction(value, method, argv, argc);
420 }
421
GetSrcPath(std::string & srcPath)422 void JsServiceExtension::GetSrcPath(std::string &srcPath)
423 {
424 if (!Extension::abilityInfo_->isModuleJson) {
425 /* temporary compatibility api8 + config.json */
426 srcPath.append(Extension::abilityInfo_->package);
427 srcPath.append("/assets/js/");
428 if (!Extension::abilityInfo_->srcPath.empty()) {
429 srcPath.append(Extension::abilityInfo_->srcPath);
430 }
431 srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
432 return;
433 }
434
435 if (!Extension::abilityInfo_->srcEntrance.empty()) {
436 srcPath.append(Extension::abilityInfo_->moduleName + "/");
437 srcPath.append(Extension::abilityInfo_->srcEntrance);
438 srcPath.erase(srcPath.rfind('.'));
439 srcPath.append(".abc");
440 }
441 }
442
CallOnConnect(const AAFwk::Want & want)443 NativeValue *JsServiceExtension::CallOnConnect(const AAFwk::Want &want)
444 {
445 HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
446 Extension::OnConnect(want);
447 HILOG_DEBUG("call");
448 NativeEngine* nativeEngine = &jsRuntime_.GetNativeEngine();
449 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
450 auto* nativeWant = reinterpret_cast<NativeValue*>(napiWant);
451 NativeValue* argv[] = {nativeWant};
452 if (!jsObj_) {
453 HILOG_WARN("Not found ServiceExtension.js");
454 return nullptr;
455 }
456
457 NativeValue* value = jsObj_->Get();
458 auto* obj = ConvertNativeValueTo<NativeObject>(value);
459 if (obj == nullptr) {
460 HILOG_ERROR("Failed to get ServiceExtension object");
461 return nullptr;
462 }
463
464 NativeValue* method = obj->GetProperty("onConnect");
465 if (method == nullptr) {
466 HILOG_ERROR("Failed to get onConnect from ServiceExtension object");
467 return nullptr;
468 }
469 NativeValue* remoteNative = nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
470 if (remoteNative == nullptr) {
471 HILOG_ERROR("remoteNative nullptr.");
472 }
473 HILOG_INFO("ok");
474 return remoteNative;
475 }
476
CallOnDisconnect(const AAFwk::Want & want,bool withResult)477 NativeValue *JsServiceExtension::CallOnDisconnect(const AAFwk::Want &want, bool withResult)
478 {
479 HandleEscape handleEscape(jsRuntime_);
480 NativeEngine *nativeEngine = &jsRuntime_.GetNativeEngine();
481 napi_value napiWant = OHOS::AppExecFwk::WrapWant(reinterpret_cast<napi_env>(nativeEngine), want);
482 NativeValue *nativeWant = reinterpret_cast<NativeValue *>(napiWant);
483 NativeValue *argv[] = { nativeWant };
484 if (!jsObj_) {
485 HILOG_WARN("Not found ServiceExtension.js");
486 return nullptr;
487 }
488
489 NativeValue *value = jsObj_->Get();
490 NativeObject *obj = ConvertNativeValueTo<NativeObject>(value);
491 if (obj == nullptr) {
492 HILOG_ERROR("Failed to get ServiceExtension object");
493 return nullptr;
494 }
495
496 NativeValue *method = obj->GetProperty("onDisconnect");
497 if (method == nullptr) {
498 HILOG_ERROR("Failed to get onDisconnect from ServiceExtension object");
499 return nullptr;
500 }
501
502 if (withResult) {
503 return handleEscape.Escape(nativeEngine->CallFunction(value, method, argv, ARGC_ONE));
504 } else {
505 nativeEngine->CallFunction(value, method, argv, ARGC_ONE);
506 return nullptr;
507 }
508 }
509
CheckPromise(NativeValue * result)510 bool JsServiceExtension::CheckPromise(NativeValue *result)
511 {
512 if (result == nullptr) {
513 HILOG_DEBUG("CheckPromise, result is null, no need to call promise.");
514 return false;
515 }
516 if (!result->IsPromise()) {
517 HILOG_DEBUG("CheckPromise, result is not promise, no need to call promise.");
518 return false;
519 }
520 return true;
521 }
522
CallPromise(NativeValue * result,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo)523 bool JsServiceExtension::CallPromise(NativeValue *result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo)
524 {
525 auto *retObj = ConvertNativeValueTo<NativeObject>(result);
526 if (retObj == nullptr) {
527 HILOG_ERROR("CallPromise, Failed to convert native value to NativeObject.");
528 return false;
529 }
530 NativeValue *then = retObj->GetProperty("then");
531 if (then == nullptr) {
532 HILOG_ERROR("CallPromise, Failed to get property: then.");
533 return false;
534 }
535 if (!then->IsCallable()) {
536 HILOG_ERROR("CallPromise, property then is not callable.");
537 return false;
538 }
539 HandleScope handleScope(jsRuntime_);
540 auto &nativeEngine = jsRuntime_.GetNativeEngine();
541 auto promiseCallback = nativeEngine.CreateFunction("promiseCallback", strlen("promiseCallback"), PromiseCallback,
542 callbackInfo);
543 NativeValue *argv[1] = { promiseCallback };
544 nativeEngine.CallFunction(result, then, argv, 1);
545 return true;
546 }
547
OnConfigurationUpdated(const AppExecFwk::Configuration & configuration)548 void JsServiceExtension::OnConfigurationUpdated(const AppExecFwk::Configuration& configuration)
549 {
550 ServiceExtension::OnConfigurationUpdated(configuration);
551 HILOG_INFO("call");
552 auto context = GetContext();
553 if (context == nullptr) {
554 HILOG_ERROR("Context is invalid.");
555 return;
556 }
557
558 auto contextConfig = context->GetConfiguration();
559 if (contextConfig != nullptr) {
560 HILOG_DEBUG("Config dump: %{public}s", contextConfig->GetName().c_str());
561 std::vector<std::string> changeKeyV;
562 contextConfig->CompareDifferent(changeKeyV, configuration);
563 if (!changeKeyV.empty()) {
564 contextConfig->Merge(changeKeyV, configuration);
565 }
566 HILOG_DEBUG("Config dump after merge: %{public}s", contextConfig->GetName().c_str());
567 }
568 ConfigurationUpdated();
569 }
570
ConfigurationUpdated()571 void JsServiceExtension::ConfigurationUpdated()
572 {
573 HILOG_DEBUG("called.");
574 HandleScope handleScope(jsRuntime_);
575 auto& nativeEngine = jsRuntime_.GetNativeEngine();
576
577 // Notify extension context
578 auto fullConfig = GetContext()->GetConfiguration();
579 if (!fullConfig) {
580 HILOG_ERROR("configuration is nullptr.");
581 return;
582 }
583
584 napi_value napiConfiguration = OHOS::AppExecFwk::WrapConfiguration(
585 reinterpret_cast<napi_env>(&nativeEngine), *fullConfig);
586 NativeValue* jsConfiguration = reinterpret_cast<NativeValue*>(napiConfiguration);
587 CallObjectMethod("onConfigurationUpdated", &jsConfiguration, ARGC_ONE);
588 CallObjectMethod("onConfigurationUpdate", &jsConfiguration, ARGC_ONE);
589 JsExtensionContext::ConfigurationUpdated(&nativeEngine, shellContextRef_, fullConfig);
590 }
591
Dump(const std::vector<std::string> & params,std::vector<std::string> & info)592 void JsServiceExtension::Dump(const std::vector<std::string> ¶ms, std::vector<std::string> &info)
593 {
594 Extension::Dump(params, info);
595 HILOG_INFO("call");
596 HandleScope handleScope(jsRuntime_);
597 auto& nativeEngine = jsRuntime_.GetNativeEngine();
598 // create js array object of params
599 NativeValue* arrayValue = nativeEngine.CreateArray(params.size());
600 NativeArray* array = ConvertNativeValueTo<NativeArray>(arrayValue);
601 uint32_t index = 0;
602 for (const auto ¶m : params) {
603 array->SetElement(index++, CreateJsValue(nativeEngine, param));
604 }
605 NativeValue* argv[] = { arrayValue };
606
607 if (!jsObj_) {
608 HILOG_WARN("Not found ServiceExtension.js");
609 return;
610 }
611
612 NativeValue* value = jsObj_->Get();
613 NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
614 if (obj == nullptr) {
615 HILOG_ERROR("Failed to get ServiceExtension object");
616 return;
617 }
618
619 NativeValue* method = obj->GetProperty("onDump");
620 if (method == nullptr || method->TypeOf() != NATIVE_FUNCTION) {
621 method = obj->GetProperty("dump");
622 if (method == nullptr || method->TypeOf() != NATIVE_FUNCTION) {
623 HILOG_ERROR("Failed to get onConnect from ServiceExtension object");
624 return;
625 }
626 }
627 HILOG_INFO("JsServiceExtension::CallFunction onConnect, success");
628 NativeValue* dumpInfo = nativeEngine.CallFunction(value, method, argv, ARGC_ONE);
629 if (dumpInfo == nullptr) {
630 HILOG_ERROR("dumpInfo nullptr.");
631 return;
632 }
633 NativeArray* dumpInfoNative = ConvertNativeValueTo<NativeArray>(dumpInfo);
634 if (dumpInfoNative == nullptr) {
635 HILOG_ERROR("dumpInfoNative nullptr.");
636 return;
637 }
638 for (uint32_t i = 0; i < dumpInfoNative->GetLength(); i++) {
639 std::string dumpInfoStr;
640 if (!ConvertFromJsValue(nativeEngine, dumpInfoNative->GetElement(i), dumpInfoStr)) {
641 HILOG_ERROR("Parse dumpInfoStr failed");
642 return;
643 }
644 info.push_back(dumpInfoStr);
645 }
646 HILOG_DEBUG("Dump info size: %{public}zu", info.size());
647 }
648
649 #ifdef SUPPORT_GRAPHICS
OnCreate(Rosen::DisplayId displayId)650 void JsServiceExtension::OnCreate(Rosen::DisplayId displayId)
651 {
652 HILOG_DEBUG("OnCreate.");
653 }
654
OnDestroy(Rosen::DisplayId displayId)655 void JsServiceExtension::OnDestroy(Rosen::DisplayId displayId)
656 {
657 HILOG_DEBUG("OnDestroy.");
658 }
659
OnChange(Rosen::DisplayId displayId)660 void JsServiceExtension::OnChange(Rosen::DisplayId displayId)
661 {
662 HILOG_DEBUG("displayId: %{public}" PRIu64"", displayId);
663 auto context = GetContext();
664 if (context == nullptr) {
665 HILOG_ERROR("Context is invalid.");
666 return;
667 }
668
669 auto contextConfig = context->GetConfiguration();
670 if (contextConfig == nullptr) {
671 HILOG_ERROR("Configuration is invalid.");
672 return;
673 }
674
675 HILOG_DEBUG("Config dump: %{public}s", contextConfig->GetName().c_str());
676 bool configChanged = false;
677 auto configUtils = std::make_shared<ConfigurationUtils>();
678 configUtils->UpdateDisplayConfig(displayId, contextConfig, context->GetResourceManager(), configChanged);
679 HILOG_DEBUG("Config dump after update: %{public}s", contextConfig->GetName().c_str());
680
681 if (configChanged) {
682 auto jsServiceExtension = std::static_pointer_cast<JsServiceExtension>(shared_from_this());
683 auto task = [jsServiceExtension]() {
684 if (jsServiceExtension) {
685 jsServiceExtension->ConfigurationUpdated();
686 }
687 };
688 if (handler_ != nullptr) {
689 handler_->PostTask(task);
690 }
691 }
692
693 HILOG_DEBUG("finished.");
694 }
695 #endif
696 } // AbilityRuntime
697 } // OHOS
698