1 /*
2  * Copyright (c) 2021-2024 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_business_error.h"
19 #include "ability_handler.h"
20 #include "ability_info.h"
21 #include "ability_manager_client.h"
22 #include "configuration_utils.h"
23 #include "hitrace_meter.h"
24 #include "hilog_tag_wrapper.h"
25 #include "insight_intent_execute_param.h"
26 #include "insight_intent_execute_result.h"
27 #include "insight_intent_executor_info.h"
28 #include "insight_intent_executor_mgr.h"
29 #include "js_extension_common.h"
30 #include "js_extension_context.h"
31 #include "js_runtime.h"
32 #include "js_runtime_utils.h"
33 #include "js_service_extension_context.h"
34 #include "napi/native_api.h"
35 #include "napi/native_node_api.h"
36 #include "napi_common_configuration.h"
37 #include "napi_common_want.h"
38 #include "napi_remote_object.h"
39 #ifdef SUPPORT_GRAPHICS
40 #include "iservice_registry.h"
41 #include "system_ability_definition.h"
42 #include "window_scene.h"
43 #endif
44 
45 namespace OHOS {
46 namespace AbilityRuntime {
47 namespace {
48 constexpr size_t ARGC_ONE = 1;
49 constexpr size_t ARGC_TWO = 2;
50 }
51 
52 namespace {
GetNativeRemoteObject(napi_env env,napi_value obj)53 sptr<IRemoteObject> GetNativeRemoteObject(napi_env env, napi_value obj)
54 {
55     if (env == nullptr || obj == nullptr) {
56         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null obj");
57         return nullptr;
58     }
59     napi_valuetype type;
60     napi_typeof(env, obj, &type);
61     if (type == napi_undefined || type == napi_null) {
62         TAG_LOGE(AAFwkTag::SERVICE_EXT, "obj type invalid");
63         return nullptr;
64     }
65     if (type != napi_object) {
66         TAG_LOGE(AAFwkTag::SERVICE_EXT, "obj not object");
67         return nullptr;
68     }
69     return NAPI_ohos_rpc_getNativeRemoteObject(env, obj);
70 }
71 
PromiseCallback(napi_env env,napi_callback_info info)72 napi_value PromiseCallback(napi_env env, napi_callback_info info)
73 {
74     void *data = nullptr;
75     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data), nullptr);
76     auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<> *>(data);
77     callbackInfo->Call();
78     AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo);
79     data = nullptr;
80     return nullptr;
81 }
82 
OnConnectPromiseCallback(napi_env env,napi_callback_info info)83 napi_value OnConnectPromiseCallback(napi_env env, napi_callback_info info)
84 {
85     TAG_LOGD(AAFwkTag::SERVICE_EXT, "enter");
86     void *data = nullptr;
87     size_t argc = ARGC_MAX_COUNT;
88     napi_value argv[ARGC_MAX_COUNT] = {nullptr};
89     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, &argc, argv, nullptr, &data), nullptr);
90     auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *>(data);
91     sptr<IRemoteObject> service = nullptr;
92     if (argc > 0) {
93         service = GetNativeRemoteObject(env, argv[0]);
94     }
95     callbackInfo->Call(service);
96     AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>>::Destroy(callbackInfo);
97     data = nullptr;
98     TAG_LOGD(AAFwkTag::SERVICE_EXT, "end");
99     return nullptr;
100 }
101 }
102 
103 using namespace OHOS::AppExecFwk;
104 
AttachServiceExtensionContext(napi_env env,void * value,void *)105 napi_value AttachServiceExtensionContext(napi_env env, void *value, void *)
106 {
107     if (value == nullptr) {
108         TAG_LOGW(AAFwkTag::SERVICE_EXT, "invalid param");
109         return nullptr;
110     }
111     auto ptr = reinterpret_cast<std::weak_ptr<ServiceExtensionContext> *>(value)->lock();
112     if (ptr == nullptr) {
113         TAG_LOGW(AAFwkTag::SERVICE_EXT, "invalid context");
114         return nullptr;
115     }
116     napi_value object = CreateJsServiceExtensionContext(env, ptr);
117     auto sysModule = JsRuntime::LoadSystemModuleByEngine(env,
118         "application.ServiceExtensionContext", &object, 1);
119     if (sysModule == nullptr) {
120         TAG_LOGW(AAFwkTag::SERVICE_EXT, "load module failed");
121         return nullptr;
122     }
123     auto contextObj = sysModule->GetNapiValue();
124     napi_coerce_to_native_binding_object(
125         env, contextObj, DetachCallbackFunc, AttachServiceExtensionContext, value, nullptr);
126     auto workContext = new (std::nothrow) std::weak_ptr<ServiceExtensionContext>(ptr);
127     auto res = napi_wrap(env, contextObj, workContext,
128         [](napi_env, void *data, void *) {
129             TAG_LOGD(AAFwkTag::SERVICE_EXT, "Finalizer for weak_ptr service extension context is called");
130             delete static_cast<std::weak_ptr<ServiceExtensionContext> *>(data);
131         },
132         nullptr, nullptr);
133     if (res != napi_ok && workContext != nullptr) {
134         TAG_LOGE(AAFwkTag::SERVICE_EXT, "napi_wrap failed:%{public}d", res);
135         delete workContext;
136         return nullptr;
137     }
138     return contextObj;
139 }
140 
Create(const std::unique_ptr<Runtime> & runtime)141 JsServiceExtension* JsServiceExtension::Create(const std::unique_ptr<Runtime>& runtime)
142 {
143     return new JsServiceExtension(static_cast<JsRuntime&>(*runtime));
144 }
145 
JsServiceExtension(JsRuntime & jsRuntime)146 JsServiceExtension::JsServiceExtension(JsRuntime& jsRuntime) : jsRuntime_(jsRuntime) {}
~JsServiceExtension()147 JsServiceExtension::~JsServiceExtension()
148 {
149     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
150     auto context = GetContext();
151     if (context) {
152         context->Unbind();
153     }
154 
155     jsRuntime_.FreeNativeReference(std::move(jsObj_));
156     jsRuntime_.FreeNativeReference(std::move(shellContextRef_));
157 }
158 
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)159 void JsServiceExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
160     const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
161     const sptr<IRemoteObject> &token)
162 {
163     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
164     ServiceExtension::Init(record, application, handler, token);
165     std::string srcPath = "";
166     GetSrcPath(srcPath);
167     if (srcPath.empty()) {
168         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get srcPath failed");
169         return;
170     }
171 
172     std::string moduleName(Extension::abilityInfo_->moduleName);
173     moduleName.append("::").append(abilityInfo_->name);
174     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called, moduleName:%{public}s,srcPath:%{public}s",
175         moduleName.c_str(), srcPath.c_str());
176     HandleScope handleScope(jsRuntime_);
177     auto env = jsRuntime_.GetNapiEnv();
178 
179     jsObj_ = jsRuntime_.LoadModule(
180         moduleName, srcPath, abilityInfo_->hapPath, abilityInfo_->compileMode == CompileMode::ES_MODULE);
181     if (jsObj_ == nullptr) {
182         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null jsObj_");
183         return;
184     }
185 
186     TAG_LOGD(AAFwkTag::SERVICE_EXT, "ConvertNativeValueTo");
187     napi_value obj = jsObj_->GetNapiValue();
188     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
189         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get JsServiceExtension obj failed");
190         return;
191     }
192 
193     BindContext(env, obj);
194 
195     SetExtensionCommon(JsExtensionCommon::Create(jsRuntime_, static_cast<NativeReference&>(*jsObj_), shellContextRef_));
196 
197     handler_ = handler;
198     auto context = GetContext();
199     auto appContext = Context::GetApplicationContext();
200     if (context != nullptr && appContext != nullptr) {
201         auto appConfig = appContext->GetConfiguration();
202         if (appConfig != nullptr) {
203             TAG_LOGD(AAFwkTag::SERVICE_EXT, "Original config dump: %{public}s", appConfig->GetName().c_str());
204             context->SetConfiguration(std::make_shared<Configuration>(*appConfig));
205         }
206     }
207     ListenWMS();
208 }
209 
ListenWMS()210 void JsServiceExtension::ListenWMS()
211 {
212 #ifdef SUPPORT_GRAPHICS
213     TAG_LOGD(AAFwkTag::SERVICE_EXT, "RegisterDisplayListener");
214     auto abilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
215     if (abilityManager == nullptr) {
216         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get SaMgr failed");
217         return;
218     }
219 
220     auto jsServiceExtension = std::static_pointer_cast<JsServiceExtension>(shared_from_this());
221     displayListener_ = sptr<JsServiceExtensionDisplayListener>::MakeSptr(jsServiceExtension);
222     if (displayListener_ == nullptr) {
223         TAG_LOGE(AAFwkTag::SERVICE_EXT, "create displayListener failed");
224         return;
225     }
226 
227     auto context = GetContext();
228     if (context == nullptr || context->GetToken() == nullptr) {
229         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Param invalid");
230         return;
231     }
232 
233     saStatusChangeListener_ =
234         sptr<SystemAbilityStatusChangeListener>::MakeSptr(displayListener_, context->GetToken());
235     if (saStatusChangeListener_ == nullptr) {
236         TAG_LOGE(AAFwkTag::SERVICE_EXT, "create status change listener failed");
237         return;
238     }
239 
240     auto ret = abilityManager->SubscribeSystemAbility(WINDOW_MANAGER_SERVICE_ID, saStatusChangeListener_);
241     if (ret != 0) {
242         TAG_LOGE(AAFwkTag::SERVICE_EXT, "subscribe system ability error:%{public}d.", ret);
243     }
244 #endif
245 }
246 
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)247 void JsServiceExtension::SystemAbilityStatusChangeListener::OnAddSystemAbility(int32_t systemAbilityId,
248     const std::string& deviceId)
249 {
250     TAG_LOGD(AAFwkTag::SERVICE_EXT, "systemAbilityId: %{public}d add", systemAbilityId);
251     if (systemAbilityId == WINDOW_MANAGER_SERVICE_ID) {
252         TAG_LOGI(AAFwkTag::SERVICE_EXT, "RegisterDisplayInfoChangedListener");
253         Rosen::WindowManager::GetInstance().RegisterDisplayInfoChangedListener(token_, tmpDisplayListener_);
254     }
255 }
256 
BindContext(napi_env env,napi_value obj)257 void JsServiceExtension::BindContext(napi_env env, napi_value obj)
258 {
259     auto context = GetContext();
260     if (context == nullptr) {
261         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get context failed");
262         return;
263     }
264     TAG_LOGD(AAFwkTag::SERVICE_EXT, "call");
265     napi_value contextObj = CreateJsServiceExtensionContext(env, context);
266     shellContextRef_ = JsRuntime::LoadSystemModuleByEngine(env, "application.ServiceExtensionContext",
267         &contextObj, ARGC_ONE);
268     if (shellContextRef_ == nullptr) {
269         TAG_LOGE(AAFwkTag::SERVICE_EXT, "load module failed");
270         return;
271     }
272     contextObj = shellContextRef_->GetNapiValue();
273     if (!CheckTypeForNapiValue(env, contextObj, napi_object)) {
274         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get context native obj failed");
275         return;
276     }
277     auto workContext = new (std::nothrow) std::weak_ptr<ServiceExtensionContext>(context);
278     napi_coerce_to_native_binding_object(
279         env, contextObj, DetachCallbackFunc, AttachServiceExtensionContext, workContext, nullptr);
280     TAG_LOGD(AAFwkTag::SERVICE_EXT, "Bind");
281     context->Bind(jsRuntime_, shellContextRef_.get());
282     napi_set_named_property(env, obj, "context", contextObj);
283 
284     auto res = napi_wrap(env, contextObj, workContext,
285         [](napi_env, void* data, void*) {
286             delete static_cast<std::weak_ptr<ServiceExtensionContext>*>(data);
287         },
288         nullptr, nullptr);
289     if (res != napi_ok && workContext != nullptr) {
290         TAG_LOGE(AAFwkTag::SERVICE_EXT, "napi_wrap failed:%{public}d", res);
291         delete workContext;
292         return;
293     }
294     TAG_LOGD(AAFwkTag::SERVICE_EXT, "end");
295 }
296 
OnStart(const AAFwk::Want & want)297 void JsServiceExtension::OnStart(const AAFwk::Want &want)
298 {
299     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
300     Extension::OnStart(want);
301     TAG_LOGI(AAFwkTag::SERVICE_EXT, "call");
302 
303     auto context = GetContext();
304     if (context != nullptr) {
305         int32_t  displayId = static_cast<int32_t>(Rosen::DisplayManager::GetInstance().GetDefaultDisplayId());
306         displayId = want.GetIntParam(Want::PARAM_RESV_DISPLAY_ID, displayId);
307         TAG_LOGD(AAFwkTag::SERVICE_EXT, "displayId %{public}d", displayId);
308         auto configUtils = std::make_shared<ConfigurationUtils>();
309         configUtils->InitDisplayConfig(displayId, context->GetConfiguration(), context->GetResourceManager());
310     }
311 
312     HandleScope handleScope(jsRuntime_);
313     napi_env env = jsRuntime_.GetNapiEnv();
314 
315     // display config has changed, need update context.config
316     if (context != nullptr) {
317         JsExtensionContext::ConfigurationUpdated(env, shellContextRef_, context->GetConfiguration());
318     }
319 
320     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
321     napi_value argv[] = {napiWant};
322     CallObjectMethod("onCreate", argv, ARGC_ONE);
323     TAG_LOGD(AAFwkTag::SERVICE_EXT, "ok");
324 }
325 
OnStop()326 void JsServiceExtension::OnStop()
327 {
328     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
329     ServiceExtension::OnStop();
330     TAG_LOGD(AAFwkTag::SERVICE_EXT, "call");
331     CallObjectMethod("onDestroy");
332     bool ret = ConnectionManager::GetInstance().DisconnectCaller(GetContext()->GetToken());
333     if (ret) {
334         ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid());
335         TAG_LOGD(AAFwkTag::SERVICE_EXT, "service extension connection not disconnected");
336     }
337     TAG_LOGI(AAFwkTag::SERVICE_EXT, "UnregisterDisplayInfoChangedListener");
338     auto context = GetContext();
339     if (context == nullptr || context->GetToken() == nullptr) {
340         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Param invalid");
341         return;
342     }
343     Rosen::WindowManager::GetInstance()
344         .UnregisterDisplayInfoChangedListener(context->GetToken(), displayListener_);
345 #ifdef SUPPORT_GRAPHICS
346     if (saStatusChangeListener_) {
347         auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
348         if (saMgr) {
349             saMgr->UnSubscribeSystemAbility(WINDOW_MANAGER_SERVICE_ID, saStatusChangeListener_);
350         } else {
351             TAG_LOGW(AAFwkTag::SERVICE_EXT, "OnStop SaMgr null");
352         }
353     }
354 #endif //SUPPORT_GRAPHICS
355     TAG_LOGD(AAFwkTag::SERVICE_EXT, "ok");
356 }
357 
OnConnect(const AAFwk::Want & want)358 sptr<IRemoteObject> JsServiceExtension::OnConnect(const AAFwk::Want &want)
359 {
360     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
361     HandleScope handleScope(jsRuntime_);
362     napi_value result = CallOnConnect(want);
363     napi_env env = jsRuntime_.GetNapiEnv();
364     auto remoteObj = GetNativeRemoteObject(env, result);
365     if (remoteObj == nullptr) {
366         TAG_LOGE(AAFwkTag::SERVICE_EXT, "remoteObj null");
367     }
368     return remoteObj;
369 }
370 
OnConnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> * callbackInfo,bool & isAsyncCallback)371 sptr<IRemoteObject> JsServiceExtension::OnConnect(const AAFwk::Want &want,
372     AppExecFwk::AbilityTransactionCallbackInfo<sptr<IRemoteObject>> *callbackInfo, bool &isAsyncCallback)
373 {
374     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
375     HandleScope handleScope(jsRuntime_);
376     napi_env env = jsRuntime_.GetNapiEnv();
377     napi_value result = CallOnConnect(want);
378     bool isPromise = CheckPromise(result);
379     if (!isPromise) {
380         isAsyncCallback = false;
381         sptr<IRemoteObject> remoteObj = GetNativeRemoteObject(env, result);
382         if (remoteObj == nullptr) {
383             TAG_LOGE(AAFwkTag::SERVICE_EXT, "remoteObj null");
384         }
385         return remoteObj;
386     }
387 
388     bool callResult = false;
389     do {
390         if (!CheckTypeForNapiValue(env, result, napi_object)) {
391             TAG_LOGE(AAFwkTag::SERVICE_EXT, "CallPromise, error to convert native value to NativeObject");
392             break;
393         }
394         napi_value then = nullptr;
395         napi_get_named_property(env, result, "then", &then);
396         if (then == nullptr) {
397             TAG_LOGE(AAFwkTag::SERVICE_EXT, "CallPromise, error to get property then");
398             break;
399         }
400         bool isCallable = false;
401         napi_is_callable(env, then, &isCallable);
402         if (!isCallable) {
403             TAG_LOGE(AAFwkTag::SERVICE_EXT, "CallPromise, property then not callable");
404             break;
405         }
406         napi_value promiseCallback = nullptr;
407         napi_create_function(env, "promiseCallback", strlen("promiseCallback"),
408             OnConnectPromiseCallback, callbackInfo, &promiseCallback);
409         napi_value argv[1] = { promiseCallback };
410         napi_call_function(env, result, then, 1, argv, nullptr);
411         callResult = true;
412     } while (false);
413 
414     if (!callResult) {
415         TAG_LOGE(AAFwkTag::SERVICE_EXT, "error to call promise");
416         isAsyncCallback = false;
417     } else {
418         isAsyncCallback = true;
419     }
420     return nullptr;
421 }
422 
OnDisconnect(const AAFwk::Want & want)423 void JsServiceExtension::OnDisconnect(const AAFwk::Want &want)
424 {
425     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
426     HandleScope handleScope(jsRuntime_);
427     Extension::OnDisconnect(want);
428     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
429     CallOnDisconnect(want, false);
430     TAG_LOGD(AAFwkTag::SERVICE_EXT, "end");
431 }
432 
OnDisconnect(const AAFwk::Want & want,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo,bool & isAsyncCallback)433 void JsServiceExtension::OnDisconnect(const AAFwk::Want &want,
434     AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback)
435 {
436     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
437     HandleScope handleScope(jsRuntime_);
438     Extension::OnDisconnect(want);
439     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
440     napi_value result = CallOnDisconnect(want, true);
441     bool isPromise = CheckPromise(result);
442     if (!isPromise) {
443         isAsyncCallback = false;
444         return;
445     }
446     bool callResult = CallPromise(result, callbackInfo);
447     if (!callResult) {
448         TAG_LOGE(AAFwkTag::SERVICE_EXT, "error to call promise");
449         isAsyncCallback = false;
450     } else {
451         isAsyncCallback = true;
452     }
453 
454     TAG_LOGD(AAFwkTag::SERVICE_EXT, "end");
455 }
456 
OnCommand(const AAFwk::Want & want,bool restart,int startId)457 void JsServiceExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId)
458 {
459     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
460     Extension::OnCommand(want, restart, startId);
461     TAG_LOGD(AAFwkTag::SERVICE_EXT, "restart=%{public}s,startId=%{public}d",
462         restart ? "true" : "false",
463         startId);
464     // wrap want
465     HandleScope handleScope(jsRuntime_);
466     napi_env env = jsRuntime_.GetNapiEnv();
467     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
468     // wrap startId
469     napi_value napiStartId = nullptr;
470     napi_create_int32(env, startId, &napiStartId);
471     napi_value argv[] = {napiWant, napiStartId};
472     CallObjectMethod("onRequest", argv, ARGC_TWO);
473     TAG_LOGD(AAFwkTag::SERVICE_EXT, "ok");
474 }
475 
HandleInsightIntent(const AAFwk::Want & want)476 bool JsServiceExtension::HandleInsightIntent(const AAFwk::Want &want)
477 {
478     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
479     auto callback = std::make_unique<InsightIntentExecutorAsyncCallback>();
480     callback.reset(InsightIntentExecutorAsyncCallback::Create());
481     if (callback == nullptr) {
482         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Create async callback failed");
483         return false;
484     }
485     auto executeParam = std::make_shared<AppExecFwk::InsightIntentExecuteParam>();
486     bool ret = AppExecFwk::InsightIntentExecuteParam::GenerateFromWant(want, *executeParam);
487     if (!ret) {
488         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Generate execute param failed");
489         InsightIntentExecutorMgr::TriggerCallbackInner(std::move(callback),
490             static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM));
491         return false;
492     }
493     TAG_LOGD(AAFwkTag::SERVICE_EXT, "Insight bundleName: %{public}s, moduleName: %{public}s, abilityName: %{public}s"
494         "insightIntentName: %{public}s, executeMode: %{public}d, intentId: %{public}" PRIu64 "",
495         executeParam->bundleName_.c_str(), executeParam->moduleName_.c_str(), executeParam->abilityName_.c_str(),
496         executeParam->insightIntentName_.c_str(), executeParam->executeMode_, executeParam->insightIntentId_);
497     auto asyncCallback = [weak = weak_from_this(), intentId = executeParam->insightIntentId_]
498         (AppExecFwk::InsightIntentExecuteResult result) {
499         TAG_LOGD(AAFwkTag::SERVICE_EXT, "intentId %{public}" PRIu64"", intentId);
500         auto extension = weak.lock();
501         if (extension == nullptr) {
502             TAG_LOGE(AAFwkTag::SERVICE_EXT, "null extension");
503             return;
504         }
505         auto ret = extension->OnInsightIntentExecuteDone(intentId, result);
506         if (!ret) {
507             TAG_LOGE(AAFwkTag::SERVICE_EXT, "OnInsightIntentExecuteDone failed");
508         }
509     };
510     callback->Push(asyncCallback);
511     InsightIntentExecutorInfo executorInfo;
512     ret = GetInsightIntentExecutorInfo(want, executeParam, executorInfo);
513     if (!ret) {
514         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Get Intent executor failed");
515         InsightIntentExecutorMgr::TriggerCallbackInner(std::move(callback),
516             static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM));
517         return false;
518     }
519     ret = DelayedSingleton<InsightIntentExecutorMgr>::GetInstance()->ExecuteInsightIntent(
520         jsRuntime_, executorInfo, std::move(callback));
521     if (!ret) {
522         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Execute insight intent failed");
523         return false;
524     }
525     return true;
526 }
527 
GetInsightIntentExecutorInfo(const Want & want,const std::shared_ptr<AppExecFwk::InsightIntentExecuteParam> & executeParam,InsightIntentExecutorInfo & executorInfo)528 bool JsServiceExtension::GetInsightIntentExecutorInfo(const Want &want,
529     const std::shared_ptr<AppExecFwk::InsightIntentExecuteParam> &executeParam,
530     InsightIntentExecutorInfo &executorInfo)
531 {
532     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
533     auto context = GetContext();
534     if (executeParam == nullptr || context == nullptr || abilityInfo_ == nullptr) {
535         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Param invalid");
536         return false;
537     }
538 
539     const WantParams &wantParams = want.GetParams();
540     executorInfo.srcEntry = wantParams.GetStringParam(AppExecFwk::INSIGHT_INTENT_SRC_ENTRY);
541     executorInfo.hapPath = abilityInfo_->hapPath;
542     executorInfo.esmodule = abilityInfo_->compileMode == AppExecFwk::CompileMode::ES_MODULE;
543     executorInfo.token = context->GetToken();
544     executorInfo.executeParam = executeParam;
545     return true;
546 }
547 
OnInsightIntentExecuteDone(uint64_t intentId,const AppExecFwk::InsightIntentExecuteResult & result)548 bool JsServiceExtension::OnInsightIntentExecuteDone(uint64_t intentId,
549     const AppExecFwk::InsightIntentExecuteResult &result)
550 {
551     TAG_LOGI(AAFwkTag::SERVICE_EXT, "Notify execute done, intentId %{public}" PRIu64"", intentId);
552     auto context = GetContext();
553     if (context == nullptr) {
554         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null context");
555         return false;
556     }
557     auto token = context->GetToken();
558     if (token == nullptr) {
559         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null token");
560         return false;
561     }
562     auto ret = AAFwk::AbilityManagerClient::GetInstance()->ExecuteInsightIntentDone(token, intentId, result);
563     if (ret != ERR_OK) {
564         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Notify execute done failed");
565         return false;
566     }
567     return true;
568 }
569 
CallObjectMethod(const char * name,napi_value const * argv,size_t argc)570 napi_value JsServiceExtension::CallObjectMethod(const char* name, napi_value const* argv, size_t argc)
571 {
572     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, std::string("CallObjectMethod:") + name);
573     TAG_LOGD(AAFwkTag::SERVICE_EXT, "name:%{public}s", name);
574 
575     if (!jsObj_) {
576         TAG_LOGW(AAFwkTag::SERVICE_EXT, "Not found ServiceExtension.js");
577         return nullptr;
578     }
579 
580     HandleScope handleScope(jsRuntime_);
581     napi_env env = jsRuntime_.GetNapiEnv();
582 
583     napi_value obj = jsObj_->GetNapiValue();
584     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
585         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get ServiceExtension obj failed");
586         return nullptr;
587     }
588 
589     napi_value method = nullptr;
590     napi_get_named_property(env, obj, name, &method);
591     if (!CheckTypeForNapiValue(env, method, napi_function)) {
592         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get '%{public}s' from ServiceExtension obj failed", name);
593         return nullptr;
594     }
595     TAG_LOGI(AAFwkTag::SERVICE_EXT, "CallFunction(%{public}s) ok", name);
596     napi_value result = nullptr;
597     napi_status status = napi_call_function(env, obj, method, argc, argv, &result);
598     if (status != napi_ok) {
599         TAG_LOGE(AAFwkTag::SERVICE_EXT, "call js func failed: %{public}d", status);
600     }
601     return result;
602 }
603 
GetSrcPath(std::string & srcPath)604 void JsServiceExtension::GetSrcPath(std::string &srcPath)
605 {
606     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
607     if (!Extension::abilityInfo_->isModuleJson) {
608         /* temporary compatibility api8 + config.json */
609         srcPath.append(Extension::abilityInfo_->package);
610         srcPath.append("/assets/js/");
611         if (!Extension::abilityInfo_->srcPath.empty()) {
612             srcPath.append(Extension::abilityInfo_->srcPath);
613         }
614         srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
615         return;
616     }
617 
618     if (!Extension::abilityInfo_->srcEntrance.empty()) {
619         srcPath.append(Extension::abilityInfo_->moduleName + "/");
620         srcPath.append(Extension::abilityInfo_->srcEntrance);
621         srcPath.erase(srcPath.rfind('.'));
622         srcPath.append(".abc");
623     }
624 }
625 
CallOnConnect(const AAFwk::Want & want)626 napi_value JsServiceExtension::CallOnConnect(const AAFwk::Want &want)
627 {
628     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
629     Extension::OnConnect(want);
630     TAG_LOGD(AAFwkTag::SERVICE_EXT, "call");
631     napi_env env = jsRuntime_.GetNapiEnv();
632     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
633     napi_value argv[] = {napiWant};
634     if (!jsObj_) {
635         TAG_LOGW(AAFwkTag::SERVICE_EXT, "Not found ServiceExtension.js");
636         return nullptr;
637     }
638 
639     napi_value obj = jsObj_->GetNapiValue();
640     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
641         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get ServiceExtension obj failed");
642         return nullptr;
643     }
644 
645     napi_value method = nullptr;
646     napi_get_named_property(env, obj, "onConnect", &method);
647     if (method == nullptr) {
648         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get onConnect from ServiceExtension obj failed");
649         return nullptr;
650     }
651     napi_value remoteNative = nullptr;
652     TAG_LOGI(AAFwkTag::SERVICE_EXT, "Call onConnect");
653     napi_status status = napi_call_function(env, obj, method, ARGC_ONE, argv, &remoteNative);
654     if (status != napi_ok) {
655         TAG_LOGE(AAFwkTag::SERVICE_EXT, "call js func failed %{public}d", status);
656     }
657     if (remoteNative == nullptr) {
658         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null remoteNative");
659     }
660     TAG_LOGD(AAFwkTag::SERVICE_EXT, "ok");
661     return remoteNative;
662 }
663 
CallOnDisconnect(const AAFwk::Want & want,bool withResult)664 napi_value JsServiceExtension::CallOnDisconnect(const AAFwk::Want &want, bool withResult)
665 {
666     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
667     HandleEscape handleEscape(jsRuntime_);
668     napi_env env = jsRuntime_.GetNapiEnv();
669     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
670     napi_value argv[] = { napiWant };
671     if (!jsObj_) {
672         TAG_LOGW(AAFwkTag::SERVICE_EXT, "Not found ServiceExtension.js");
673         return nullptr;
674     }
675 
676     napi_value obj = jsObj_->GetNapiValue();
677     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
678         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get ServiceExtension obj failed");
679         return nullptr;
680     }
681 
682     napi_value method = nullptr;
683     napi_get_named_property(env, obj, "onDisconnect", &method);
684     if (method == nullptr) {
685         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get onDisconnect from ServiceExtension obj failed");
686         return nullptr;
687     }
688     TAG_LOGI(AAFwkTag::SERVICE_EXT, "Call onDisconnect");
689     if (withResult) {
690         napi_value result = nullptr;
691         napi_status status = napi_call_function(env, obj, method, ARGC_ONE, argv, &result);
692         if (status != napi_ok) {
693             TAG_LOGE(AAFwkTag::SERVICE_EXT, "call js func failed %{public}d", status);
694         }
695         return handleEscape.Escape(result);
696     } else {
697         napi_status status = napi_call_function(env, obj, method, ARGC_ONE, argv, nullptr);
698         if (status != napi_ok) {
699             TAG_LOGE(AAFwkTag::SERVICE_EXT, "call js func failed %{public}d", status);
700         }
701         return nullptr;
702     }
703 }
704 
CheckPromise(napi_value result)705 bool JsServiceExtension::CheckPromise(napi_value result)
706 {
707     if (result == nullptr) {
708         TAG_LOGD(AAFwkTag::SERVICE_EXT, "null result, no need to call promise");
709         return false;
710     }
711     napi_env env = jsRuntime_.GetNapiEnv();
712     bool isPromise = false;
713     napi_is_promise(env, result, &isPromise);
714     if (!isPromise) {
715         TAG_LOGD(AAFwkTag::SERVICE_EXT, "result not promise, no need to call promise");
716         return false;
717     }
718     return true;
719 }
720 
CallPromise(napi_value result,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo)721 bool JsServiceExtension::CallPromise(napi_value result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo)
722 {
723     napi_env env = jsRuntime_.GetNapiEnv();
724     if (!CheckTypeForNapiValue(env, result, napi_object)) {
725         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Error to convert native value to NativeObject");
726         return false;
727     }
728     napi_value then = nullptr;
729     napi_get_named_property(env, result, "then", &then);
730     if (then == nullptr) {
731         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Error to get property: then");
732         return false;
733     }
734     bool isCallable = false;
735     napi_is_callable(env, then, &isCallable);
736     if (!isCallable) {
737         TAG_LOGE(AAFwkTag::SERVICE_EXT, "Property then is not callable");
738         return false;
739     }
740     HandleScope handleScope(jsRuntime_);
741     napi_value promiseCallback = nullptr;
742     napi_create_function(env, "promiseCallback", strlen("promiseCallback"), PromiseCallback,
743         callbackInfo, &promiseCallback);
744     napi_value argv[1] = { promiseCallback };
745     napi_call_function(env, result, then, 1, argv, nullptr);
746     TAG_LOGD(AAFwkTag::SERVICE_EXT, "end");
747     return true;
748 }
749 
OnConfigurationUpdated(const AppExecFwk::Configuration & configuration)750 void JsServiceExtension::OnConfigurationUpdated(const AppExecFwk::Configuration& configuration)
751 {
752     HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
753     ServiceExtension::OnConfigurationUpdated(configuration);
754     TAG_LOGD(AAFwkTag::SERVICE_EXT, "call");
755     auto context = GetContext();
756     if (context == nullptr) {
757         TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid Context");
758         return;
759     }
760 
761     auto contextConfig = context->GetConfiguration();
762     if (contextConfig != nullptr) {
763         TAG_LOGD(AAFwkTag::SERVICE_EXT, "Config dump: %{public}s", contextConfig->GetName().c_str());
764         std::vector<std::string> changeKeyV;
765         contextConfig->CompareDifferent(changeKeyV, configuration);
766         if (!changeKeyV.empty()) {
767             contextConfig->Merge(changeKeyV, configuration);
768         }
769         TAG_LOGD(AAFwkTag::SERVICE_EXT, "Config dump after merge: %{public}s", contextConfig->GetName().c_str());
770     }
771     ConfigurationUpdated();
772 }
773 
ConfigurationUpdated()774 void JsServiceExtension::ConfigurationUpdated()
775 {
776     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
777     HandleScope handleScope(jsRuntime_);
778     napi_env env = jsRuntime_.GetNapiEnv();
779 
780     // Notify extension context
781     auto fullConfig = GetContext()->GetConfiguration();
782     if (!fullConfig) {
783         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null configuration");
784         return;
785     }
786 
787     napi_value napiConfiguration = OHOS::AppExecFwk::WrapConfiguration(env, *fullConfig);
788     CallObjectMethod("onConfigurationUpdated", &napiConfiguration, ARGC_ONE);
789     CallObjectMethod("onConfigurationUpdate", &napiConfiguration, ARGC_ONE);
790     JsExtensionContext::ConfigurationUpdated(env, shellContextRef_, fullConfig);
791 }
792 
Dump(const std::vector<std::string> & params,std::vector<std::string> & info)793 void JsServiceExtension::Dump(const std::vector<std::string> &params, std::vector<std::string> &info)
794 {
795     Extension::Dump(params, info);
796     TAG_LOGD(AAFwkTag::SERVICE_EXT, "call");
797     HandleScope handleScope(jsRuntime_);
798     napi_env env = jsRuntime_.GetNapiEnv();
799     // create js array object of params
800     napi_value argv[] = { CreateNativeArray(env, params) };
801 
802     if (!jsObj_) {
803         TAG_LOGW(AAFwkTag::SERVICE_EXT, "Not found ServiceExtension.js");
804         return;
805     }
806 
807     napi_value obj = jsObj_->GetNapiValue();
808     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
809         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get ServiceExtension obj failed");
810         return;
811     }
812 
813     napi_value method = nullptr;
814     napi_get_named_property(env, obj, "onDump", &method);
815     if (!CheckTypeForNapiValue(env, method, napi_function)) {
816         method = nullptr;
817         napi_get_named_property(env, obj, "dump", &method);
818         if (!CheckTypeForNapiValue(env, method, napi_function)) {
819             TAG_LOGE(AAFwkTag::SERVICE_EXT, "get onConnect from ServiceExtension obj failed");
820             return;
821         }
822     }
823     TAG_LOGD(AAFwkTag::SERVICE_EXT, "success");
824     napi_value dumpInfo = nullptr;
825     napi_call_function(env, obj, method, ARGC_ONE, argv, &dumpInfo);
826     if (dumpInfo == nullptr) {
827         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null dumpInfo");
828         return;
829     }
830     uint32_t len = 0;
831     napi_get_array_length(env, dumpInfo, &len);
832     for (uint32_t i = 0; i < len; i++) {
833         std::string dumpInfoStr;
834         napi_value element = nullptr;
835         napi_get_element(env, dumpInfo, i, &element);
836         if (!ConvertFromJsValue(env, element, dumpInfoStr)) {
837             TAG_LOGE(AAFwkTag::SERVICE_EXT, "Parse dumpInfoStr failed");
838             return;
839         }
840         info.push_back(dumpInfoStr);
841     }
842     TAG_LOGD(AAFwkTag::SERVICE_EXT, "Dump info size: %{public}zu", info.size());
843 }
844 
845 #ifdef SUPPORT_GRAPHICS
OnCreate(Rosen::DisplayId displayId)846 void JsServiceExtension::OnCreate(Rosen::DisplayId displayId)
847 {
848     TAG_LOGD(AAFwkTag::SERVICE_EXT, "enter");
849 }
850 
OnDestroy(Rosen::DisplayId displayId)851 void JsServiceExtension::OnDestroy(Rosen::DisplayId displayId)
852 {
853     TAG_LOGD(AAFwkTag::SERVICE_EXT, "exit");
854 }
855 
OnDisplayInfoChange(const sptr<IRemoteObject> & token,Rosen::DisplayId displayId,float density,Rosen::DisplayOrientation orientation)856 void JsServiceExtension::OnDisplayInfoChange(const sptr<IRemoteObject>& token, Rosen::DisplayId displayId,
857     float density, Rosen::DisplayOrientation orientation)
858 {
859     TAG_LOGI(AAFwkTag::SERVICE_EXT, "displayId: %{public}" PRIu64, displayId);
860     auto context = GetContext();
861     if (context == nullptr) {
862         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null context");
863         return;
864     }
865 
866     auto contextConfig = context->GetConfiguration();
867     if (contextConfig == nullptr) {
868         TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid Configuration");
869         return;
870     }
871 
872     TAG_LOGD(AAFwkTag::SERVICE_EXT, "Config dump: %{public}s", contextConfig->GetName().c_str());
873     bool configChanged = false;
874     auto configUtils = std::make_shared<ConfigurationUtils>();
875     configUtils->UpdateDisplayConfig(displayId, contextConfig, context->GetResourceManager(), configChanged);
876     TAG_LOGD(AAFwkTag::SERVICE_EXT, "Config dump after update: %{public}s", contextConfig->GetName().c_str());
877 
878     if (configChanged) {
879         auto jsServiceExtension = std::static_pointer_cast<JsServiceExtension>(shared_from_this());
880         auto task = [jsServiceExtension]() {
881             if (jsServiceExtension) {
882                 jsServiceExtension->ConfigurationUpdated();
883             }
884         };
885         if (handler_ != nullptr) {
886             handler_->PostTask(task, "JsServiceExtension:OnChange");
887         }
888     }
889 
890     TAG_LOGD(AAFwkTag::SERVICE_EXT, "finished");
891 }
892 
OnChange(Rosen::DisplayId displayId)893 void JsServiceExtension::OnChange(Rosen::DisplayId displayId)
894 {
895     TAG_LOGD(AAFwkTag::SERVICE_EXT, "displayId: %{public}" PRIu64"", displayId);
896     auto context = GetContext();
897     if (context == nullptr) {
898         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null context");
899         return;
900     }
901 
902     auto contextConfig = context->GetConfiguration();
903     if (contextConfig == nullptr) {
904         TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid Configuration");
905         return;
906     }
907 
908     TAG_LOGD(AAFwkTag::SERVICE_EXT, "Config dump: %{public}s", contextConfig->GetName().c_str());
909     bool configChanged = false;
910     auto configUtils = std::make_shared<ConfigurationUtils>();
911     configUtils->UpdateDisplayConfig(displayId, contextConfig, context->GetResourceManager(), configChanged);
912     TAG_LOGD(AAFwkTag::SERVICE_EXT, "Config dump after update: %{public}s", contextConfig->GetName().c_str());
913 
914     if (configChanged) {
915         auto jsServiceExtension = std::static_pointer_cast<JsServiceExtension>(shared_from_this());
916         auto task = [jsServiceExtension]() {
917             if (jsServiceExtension) {
918                 jsServiceExtension->ConfigurationUpdated();
919             }
920         };
921         if (handler_ != nullptr) {
922             handler_->PostTask(task, "JsServiceExtension:OnChange");
923         }
924     }
925 
926     TAG_LOGD(AAFwkTag::SERVICE_EXT, "finished");
927 }
928 #endif
929 } // AbilityRuntime
930 } // OHOS
931