1 /*
2  * Copyright (c) 2023-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_auto_fill_extension.h"
17 
18 #include "ability_context.h"
19 #include "ability_delegator_registry.h"
20 #include "ability_info.h"
21 #include "ability_manager_client.h"
22 #include "ability_start_setting.h"
23 #include "connection_manager.h"
24 #include "context.h"
25 #include "hitrace_meter.h"
26 #include "hilog_tag_wrapper.h"
27 #include "int_wrapper.h"
28 #include "js_auto_fill_extension_util.h"
29 #include "js_auto_fill_extension_context.h"
30 #include "js_fill_request_callback.h"
31 #include "js_save_request_callback.h"
32 #include "js_extension_common.h"
33 #include "js_extension_context.h"
34 #include "js_runtime.h"
35 #include "js_runtime_utils.h"
36 #include "js_ui_extension_content_session.h"
37 #include "napi/native_api.h"
38 #include "napi/native_node_api.h"
39 #include "napi_common_configuration.h"
40 #include "napi_common_util.h"
41 #include "napi_common_want.h"
42 #include "napi_remote_object.h"
43 #include "string_wrapper.h"
44 #include "want_params_wrapper.h"
45 
46 namespace OHOS {
47 namespace AbilityRuntime {
48 namespace {
49 constexpr size_t ARGC_ONE = 1;
50 constexpr size_t ARGC_TWO = 2;
51 constexpr size_t ARGC_THREE = 3;
52 constexpr const char *WANT_PARAMS_AUTO_FILL_CMD = "ohos.ability.params.autoFillCmd";
53 constexpr static char WANT_PARAMS_AUTO_FILL_EVENT_KEY[] = "ability.want.params.AutoFillEvent";
54 constexpr const char *WANT_PARAMS_CUSTOM_DATA = "ohos.ability.params.customData";
55 constexpr const char *WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY = "ohos.ability.params.popupWindow";
56 }
AttachAutoFillExtensionContext(napi_env env,void * value,void *)57 napi_value AttachAutoFillExtensionContext(napi_env env, void *value, void *)
58 {
59     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
60     if (value == nullptr) {
61         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid param");
62         return nullptr;
63     }
64 
65     auto ptr = reinterpret_cast<std::weak_ptr<AutoFillExtensionContext> *>(value)->lock();
66     if (ptr == nullptr) {
67         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid context");
68         return nullptr;
69     }
70     napi_value object = JsAutoFillExtensionContext::CreateJsAutoFillExtensionContext(env, ptr);
71     auto systemModule = JsRuntime::LoadSystemModuleByEngine(env, "application.AutoFillExtensionContext", &object, 1);
72     if (systemModule == nullptr) {
73         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Load system module failed");
74         return nullptr;
75     }
76     auto contextObj = systemModule->GetNapiValue();
77     if (contextObj == nullptr) {
78         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Load context error");
79         return nullptr;
80     }
81     napi_coerce_to_native_binding_object(
82         env, contextObj, DetachCallbackFunc, AttachAutoFillExtensionContext, value, nullptr);
83 
84     auto workContext = new (std::nothrow) std::weak_ptr<AutoFillExtensionContext>(ptr);
85     if (workContext != nullptr) {
86         auto status = napi_wrap(env, contextObj, workContext,
87             [](napi_env, void *data, void *) {
88               TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Finalizer for weak_ptr ui extension context is called");
89               delete static_cast<std::weak_ptr<AutoFillExtensionContext> *>(data);
90             },
91             nullptr, nullptr);
92         if (status != napi_ok) {
93             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "wrap ui extension context failed: %{public}d", status);
94             delete workContext;
95             return nullptr;
96         }
97     }
98 
99     return contextObj;
100 }
101 
Create(const std::unique_ptr<Runtime> & runtime)102 JsAutoFillExtension *JsAutoFillExtension::Create(const std::unique_ptr<Runtime> &runtime)
103 {
104     return new (std::nothrow) JsAutoFillExtension(static_cast<JsRuntime&>(*runtime));
105 }
106 
JsAutoFillExtension(JsRuntime & jsRuntime)107 JsAutoFillExtension::JsAutoFillExtension(JsRuntime& jsRuntime) : jsRuntime_(jsRuntime)
108 {
109 }
110 
~JsAutoFillExtension()111 JsAutoFillExtension::~JsAutoFillExtension()
112 {
113     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Destructor");
114     auto context = GetContext();
115     if (context) {
116         context->Unbind();
117     }
118 
119     jsRuntime_.FreeNativeReference(std::move(jsObj_));
120     jsRuntime_.FreeNativeReference(std::move(shellContextRef_));
121     for (auto &item : contentSessions_) {
122         jsRuntime_.FreeNativeReference(std::move(item.second));
123     }
124     contentSessions_.clear();
125 
126     for (auto &callback : callbacks_) {
127         jsRuntime_.FreeNativeReference(std::move(callback.second));
128     }
129     callbacks_.clear();
130 }
131 
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)132 void JsAutoFillExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
133     const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
134     const sptr<IRemoteObject> &token)
135 {
136     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
137     AutoFillExtension::Init(record, application, handler, token);
138     if (abilityInfo_ == nullptr || abilityInfo_->srcEntrance.empty()) {
139         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Init ability info failed");
140         return;
141     }
142     std::string srcPath(abilityInfo_->moduleName + "/");
143     srcPath.append(abilityInfo_->srcEntrance);
144     srcPath.erase(srcPath.rfind('.'));
145     srcPath.append(".abc");
146 
147     std::string moduleName(abilityInfo_->moduleName);
148     moduleName.append("::").append(abilityInfo_->name);
149     HandleScope handleScope(jsRuntime_);
150     auto env = jsRuntime_.GetNapiEnv();
151 
152     jsObj_ = jsRuntime_.LoadModule(
153         moduleName, srcPath, abilityInfo_->hapPath, abilityInfo_->compileMode == CompileMode::ES_MODULE);
154     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "LoadModule moduleName:%{public}s, srcPath:%{public}s, hapPath:%{public}s",
155         moduleName.c_str(), srcPath.c_str(),  abilityInfo_->hapPath.c_str());
156     if (jsObj_ == nullptr) {
157         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null jsObj_");
158         return;
159     }
160 
161     napi_value obj = jsObj_->GetNapiValue();
162     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
163         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "get js auto fill extension obj failed");
164         return;
165     }
166 
167     BindContext(env, obj);
168 
169     SetExtensionCommon(
170         JsExtensionCommon::Create(jsRuntime_, static_cast<NativeReference&>(*jsObj_), shellContextRef_));
171 }
172 
BindContext(napi_env env,napi_value obj)173 void JsAutoFillExtension::BindContext(napi_env env, napi_value obj)
174 {
175     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
176     auto context = GetContext();
177     if (context == nullptr) {
178         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "get context failed");
179         return;
180     }
181     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Create js auto fill extension context");
182     context->SetAutoFillExtensionCallback(std::static_pointer_cast<JsAutoFillExtension>(shared_from_this()));
183     napi_value contextObj = JsAutoFillExtensionContext::CreateJsAutoFillExtensionContext(env, context);
184     if (contextObj == nullptr) {
185         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Create js ui extension context failed");
186         return;
187     }
188 
189     shellContextRef_ = JsRuntime::LoadSystemModuleByEngine(
190         env, "application.AutoFillExtensionContext", &contextObj, ARGC_ONE);
191     if (shellContextRef_ == nullptr) {
192         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "LoadSystemModuleByEngine failed");
193         return;
194     }
195     contextObj = shellContextRef_->GetNapiValue();
196     if (!CheckTypeForNapiValue(env, contextObj, napi_object)) {
197         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "get context native obj failed");
198         return;
199     }
200     auto workContext = new (std::nothrow) std::weak_ptr<AutoFillExtensionContext>(context);
201     if (workContext == nullptr) {
202         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null workContext");
203         return;
204     }
205     napi_coerce_to_native_binding_object(
206         env, contextObj, DetachCallbackFunc, AttachAutoFillExtensionContext, workContext, nullptr);
207     context->Bind(jsRuntime_, shellContextRef_.get());
208     napi_set_named_property(env, obj, "context", contextObj);
209     auto status = napi_wrap(env, contextObj, workContext,
210         [](napi_env, void* data, void*) {
211             TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Finalizer for weak_ptr ui extension context is called");
212             delete static_cast<std::weak_ptr<AutoFillExtensionContext>*>(data);
213         },
214         nullptr, nullptr);
215     if (status != napi_ok) {
216         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "wrap ui extension context failed: %{public}d", status);
217         delete workContext;
218     }
219 }
220 
OnStart(const AAFwk::Want & want)221 void JsAutoFillExtension::OnStart(const AAFwk::Want &want)
222 {
223     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
224     Extension::OnStart(want);
225     HandleScope handleScope(jsRuntime_);
226     napi_env env = jsRuntime_.GetNapiEnv();
227     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
228     napi_value argv[] = { napiWant };
229     CallObjectMethod("onCreate", argv, ARGC_ONE);
230 }
231 
OnStop()232 void JsAutoFillExtension::OnStop()
233 {
234     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
235     AutoFillExtension::OnStop();
236     HandleScope handleScope(jsRuntime_);
237     CallObjectMethod("onDestroy");
238     OnStopCallBack();
239 }
240 
OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo,bool & isAsyncCallback)241 void JsAutoFillExtension::OnStop(AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo, bool &isAsyncCallback)
242 {
243     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
244     if (callbackInfo == nullptr) {
245         isAsyncCallback = false;
246         OnStop();
247         return;
248     }
249 
250     AutoFillExtension::OnStop();
251     HandleScope handleScope(jsRuntime_);
252     napi_value result = CallObjectMethod("onDestroy", nullptr, 0, true);
253     if (!CheckPromise(result)) {
254         OnStopCallBack();
255         isAsyncCallback = false;
256         return;
257     }
258 
259     std::weak_ptr<Extension> weakPtr = shared_from_this();
260     auto asyncCallback = [extensionWeakPtr = weakPtr]() {
261         auto JsAutoFillExtension = extensionWeakPtr.lock();
262         if (JsAutoFillExtension == nullptr) {
263             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null Extension");
264             return;
265         }
266         JsAutoFillExtension->OnStopCallBack();
267     };
268     callbackInfo->Push(asyncCallback);
269     isAsyncCallback = CallPromise(result, callbackInfo);
270     if (!isAsyncCallback) {
271         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "call promise failed");
272         OnStopCallBack();
273     }
274 }
275 
OnStopCallBack()276 void JsAutoFillExtension::OnStopCallBack()
277 {
278     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
279     auto context = GetContext();
280     if (context == nullptr) {
281         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "get context failed");
282         return;
283     }
284 
285     bool ret = ConnectionManager::GetInstance().DisconnectCaller(context->GetToken());
286     if (ret) {
287         ConnectionManager::GetInstance().ReportConnectionLeakEvent(getpid(), gettid());
288         TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "service connection not disconnected");
289     }
290 
291     auto applicationContext = Context::GetApplicationContext();
292     if (applicationContext != nullptr) {
293         std::shared_ptr<NativeReference> sharedJsObj = std::move(jsObj_);
294         applicationContext->DispatchOnAbilityDestroy(sharedJsObj);
295     }
296 }
297 
CheckPromise(napi_value result)298 bool JsAutoFillExtension::CheckPromise(napi_value result)
299 {
300     if (result == nullptr) {
301         TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "null result, no need to call promise");
302         return false;
303     }
304 
305     napi_env env = jsRuntime_.GetNapiEnv();
306     bool isPromise = false;
307     napi_is_promise(env, result, &isPromise);
308     if (!isPromise) {
309         TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "not promise, no need to call promise");
310         return false;
311     }
312     return true;
313 }
314 
PromiseCallback(napi_env env,napi_callback_info info)315 napi_value PromiseCallback(napi_env env, napi_callback_info info)
316 {
317     void *data = nullptr;
318     NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, nullptr, nullptr, nullptr, &data), nullptr);
319     auto *callbackInfo = static_cast<AppExecFwk::AbilityTransactionCallbackInfo<> *>(data);
320     if (callbackInfo == nullptr) {
321         TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Invalid input info");
322         return nullptr;
323     }
324     callbackInfo->Call();
325     AppExecFwk::AbilityTransactionCallbackInfo<>::Destroy(callbackInfo);
326     data = nullptr;
327     return nullptr;
328 }
329 
CallPromise(napi_value result,AppExecFwk::AbilityTransactionCallbackInfo<> * callbackInfo)330 bool JsAutoFillExtension::CallPromise(napi_value result, AppExecFwk::AbilityTransactionCallbackInfo<> *callbackInfo)
331 {
332     auto env = jsRuntime_.GetNapiEnv();
333     if (!CheckTypeForNapiValue(env, result, napi_object)) {
334         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to convert native value to NativeObject");
335         return false;
336     }
337     napi_value then = nullptr;
338     napi_get_named_property(env, result, "then", &then);
339     if (then == nullptr) {
340         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to get property: then");
341         return false;
342     }
343     bool isCallable = false;
344     napi_is_callable(env, then, &isCallable);
345     if (!isCallable) {
346         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Property then not callable");
347         return false;
348     }
349     HandleScope handleScope(jsRuntime_);
350     napi_value promiseCallback = nullptr;
351     napi_create_function(env, "promiseCallback", strlen("promiseCallback"), PromiseCallback,
352         callbackInfo, &promiseCallback);
353     napi_value argv[1] = { promiseCallback };
354     napi_call_function(env, result, then, 1, argv, nullptr);
355     return true;
356 }
357 
OnCommandWindow(const AAFwk::Want & want,const sptr<AAFwk::SessionInfo> & sessionInfo,AAFwk::WindowCommand winCmd)358 void JsAutoFillExtension::OnCommandWindow(
359     const AAFwk::Want &want, const sptr<AAFwk::SessionInfo> &sessionInfo, AAFwk::WindowCommand winCmd)
360 {
361     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
362     if (sessionInfo == nullptr) {
363         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo");
364         return;
365     }
366     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Begin. persistentId: %{private}d, winCmd: %{public}d",
367         sessionInfo->persistentId, winCmd);
368     Extension::OnCommandWindow(want, sessionInfo, winCmd);
369     switch (winCmd) {
370         case AAFwk::WIN_CMD_FOREGROUND:
371             ForegroundWindow(want, sessionInfo);
372             break;
373         case AAFwk::WIN_CMD_BACKGROUND:
374             BackgroundWindow(sessionInfo);
375             break;
376         case AAFwk::WIN_CMD_DESTROY:
377             DestroyWindow(sessionInfo);
378             break;
379         default:
380             TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Unsupported cmd");
381             break;
382     }
383     OnCommandWindowDone(sessionInfo, winCmd);
384 }
385 
OnCommandWindowDone(const sptr<AAFwk::SessionInfo> & sessionInfo,AAFwk::WindowCommand winCmd)386 void JsAutoFillExtension::OnCommandWindowDone(const sptr<AAFwk::SessionInfo> &sessionInfo, AAFwk::WindowCommand winCmd)
387 {
388     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
389     auto context = GetContext();
390     if (context == nullptr) {
391         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to get context");
392         return;
393     }
394     AAFwk::AbilityCommand abilityCmd;
395     if (uiWindowMap_.empty()) {
396         abilityCmd = AAFwk::ABILITY_CMD_DESTROY;
397     } else if (foregroundWindows_.empty()) {
398         abilityCmd = AAFwk::ABILITY_CMD_BACKGROUND;
399     } else {
400         abilityCmd = AAFwk::ABILITY_CMD_FOREGROUND;
401     }
402     AAFwk::AbilityManagerClient::GetInstance()->ScheduleCommandAbilityWindowDone(
403         context->GetToken(), sessionInfo, winCmd, abilityCmd);
404     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "End");
405 }
406 
OnCommand(const AAFwk::Want & want,bool restart,int startId)407 void JsAutoFillExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId)
408 {
409     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Begin");
410     Extension::OnCommand(want, restart, startId);
411     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "begin restart= %{public}s, startId= %{public}d.",
412         restart ? "true" : "false", startId);
413     // wrap want
414     HandleScope handleScope(jsRuntime_);
415     napi_env env = jsRuntime_.GetNapiEnv();
416     napi_value napiWant = OHOS::AppExecFwk::WrapWant(env, want);
417     // wrap startId
418     napi_value napiStartId = nullptr;
419     napi_create_int32(env, startId, &napiStartId);
420     napi_value argv[] = {napiWant, napiStartId};
421     CallObjectMethod("onRequest", argv, ARGC_TWO);
422     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "End");
423 }
424 
OnForeground(const Want & want,sptr<AAFwk::SessionInfo> sessionInfo)425 void JsAutoFillExtension::OnForeground(const Want &want, sptr<AAFwk::SessionInfo> sessionInfo)
426 {
427     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
428     Extension::OnForeground(want, sessionInfo);
429     ForegroundWindow(want, sessionInfo);
430     HandleScope handleScope(jsRuntime_);
431     CallObjectMethod("onForeground");
432 }
433 
OnBackground()434 void JsAutoFillExtension::OnBackground()
435 {
436     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
437     HandleScope handleScope(jsRuntime_);
438     CallObjectMethod("onBackground");
439     Extension::OnBackground();
440 }
441 
OnReloadInModal(const sptr<AAFwk::SessionInfo> & sessionInfo,const CustomData & customData)442 int32_t JsAutoFillExtension::OnReloadInModal(const sptr<AAFwk::SessionInfo> &sessionInfo, const CustomData &customData)
443 {
444     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
445     if (!isPopup_) {
446         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "current window type not popup");
447         return ERR_INVALID_OPERATION;
448     }
449 
450     if (sessionInfo == nullptr) {
451         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo");
452         return ERR_NULL_OBJECT;
453     }
454 
455     AAFwk::WantParamWrapper wrapper(customData.data);
456     auto customDataString = wrapper.ToString();
457     auto obj = sessionInfo->sessionToken;
458     auto &uiWindow = uiWindowMap_[obj];
459     if (uiWindow == nullptr) {
460         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null uiWindow");
461         return ERR_NULL_OBJECT;
462     }
463     AAFwk::WantParams wantParams;
464     wantParams.SetParam(WANT_PARAMS_AUTO_FILL_CMD,
465         AAFwk::Integer::Box(static_cast<int32_t>(AutoFillCommand::RELOAD_IN_MODAL)));
466     wantParams.SetParam(WANT_PARAMS_CUSTOM_DATA, AAFwk::String::Box(customDataString));
467     auto ret = static_cast<int32_t>(uiWindow->TransferExtensionData(wantParams));
468     if (ret != ERR_OK) {
469         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Transfer extension data failed");
470         return ERR_INVALID_OPERATION;
471     }
472     return ERR_OK;
473 }
474 
UpdateRequest(const AAFwk::WantParams & wantParams)475 void JsAutoFillExtension::UpdateRequest(const AAFwk::WantParams &wantParams)
476 {
477     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
478     HandleScope handleScope(jsRuntime_);
479     napi_env env = jsRuntime_.GetNapiEnv();
480     napi_value request = JsAutoFillExtensionUtil::WrapUpdateRequest(wantParams, env);
481     if (request == nullptr) {
482         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to create update request");
483         return;
484     }
485     napi_value argv[] = { request };
486     CallObjectMethod("onUpdateRequest", argv, ARGC_ONE);
487 }
488 
HandleAutoFillCreate(const AAFwk::Want & want,const sptr<AAFwk::SessionInfo> & sessionInfo)489 bool JsAutoFillExtension::HandleAutoFillCreate(const AAFwk::Want &want, const sptr<AAFwk::SessionInfo> &sessionInfo)
490 {
491     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
492     if (sessionInfo == nullptr || sessionInfo->sessionToken == nullptr) {
493         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid sessionInfo");
494         return false;
495     }
496     auto obj = sessionInfo->sessionToken;
497     if (uiWindowMap_.find(obj) == uiWindowMap_.end()) {
498         sptr<Rosen::WindowOption> option = new Rosen::WindowOption();
499         auto context = GetContext();
500         if (context == nullptr || context->GetAbilityInfo() == nullptr) {
501             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to get context");
502             return false;
503         }
504         option->SetWindowName(context->GetBundleName() + context->GetAbilityInfo()->name);
505         option->SetWindowType(Rosen::WindowType::WINDOW_TYPE_UI_EXTENSION);
506         option->SetWindowSessionType(Rosen::WindowSessionType::EXTENSION_SESSION);
507         option->SetParentId(sessionInfo->hostWindowId);
508         option->SetRealParentId(sessionInfo->realHostWindowId);
509         option->SetParentWindowType(static_cast<Rosen::WindowType>(sessionInfo->parentWindowType));
510         option->SetUIExtensionUsage(static_cast<uint32_t>(sessionInfo->uiExtensionUsage));
511         auto uiWindow = Rosen::Window::Create(option, GetContext(), sessionInfo->sessionToken);
512         if (uiWindow == nullptr) {
513             TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Create uiWindow error");
514             return false;
515         }
516         HandleScope handleScope(jsRuntime_);
517         napi_env env = jsRuntime_.GetNapiEnv();
518         napi_value nativeContentSession =
519             JsUIExtensionContentSession::CreateJsUIExtensionContentSession(env, sessionInfo, uiWindow);
520         napi_ref ref = nullptr;
521         napi_create_reference(env, nativeContentSession, 1, &ref);
522         contentSessions_.emplace(
523             obj, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
524         CallJsOnRequest(want, sessionInfo, uiWindow);
525         uiWindowMap_[obj] = uiWindow;
526         context->SetSessionInfo(sessionInfo);
527     }
528     return true;
529 }
530 
ForegroundWindow(const AAFwk::Want & want,const sptr<AAFwk::SessionInfo> & sessionInfo)531 void JsAutoFillExtension::ForegroundWindow(const AAFwk::Want &want, const sptr<AAFwk::SessionInfo> &sessionInfo)
532 {
533     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
534     if (sessionInfo == nullptr) {
535         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo");
536         return;
537     }
538 
539     auto context = GetContext();
540     if (context == nullptr) {
541         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to get context");
542         return;
543     }
544 
545     if (want.HasParameter(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY)) {
546         isPopup_ = want.GetBoolParam(WANT_PARAMS_AUTO_FILL_POPUP_WINDOW_KEY, false);
547     }
548 
549     if (!HandleAutoFillCreate(want, sessionInfo)) {
550         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "HandleAutoFillCreate failed");
551         return;
552     }
553     auto obj = sessionInfo->sessionToken;
554     auto& uiWindow = uiWindowMap_[obj];
555     if (uiWindow) {
556         uiWindow->Show();
557         TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "uiWindow show");
558         foregroundWindows_.emplace(obj);
559 
560         RegisterTransferComponentDataListener(uiWindow);
561         AAFwk::WantParams wantParams;
562         wantParams.SetParam(WANT_PARAMS_AUTO_FILL_EVENT_KEY, AAFwk::Integer::Box(
563             static_cast<int32_t>(JsAutoFillExtensionUtil::AutoFillResultCode::CALLBACK_REMOVE_TIME_OUT)));
564         uiWindow->TransferExtensionData(wantParams);
565     }
566 }
567 
BackgroundWindow(const sptr<AAFwk::SessionInfo> & sessionInfo)568 void JsAutoFillExtension::BackgroundWindow(const sptr<AAFwk::SessionInfo> &sessionInfo)
569 {
570     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
571     if (sessionInfo == nullptr || sessionInfo->sessionToken == nullptr) {
572         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid sessionInfo");
573         return;
574     }
575     auto obj = sessionInfo->sessionToken;
576     if (uiWindowMap_.find(obj) == uiWindowMap_.end()) {
577         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Fail to find ui window");
578         return;
579     }
580     auto& uiWindow = uiWindowMap_[obj];
581     if (uiWindow) {
582         uiWindow->Hide();
583         foregroundWindows_.erase(obj);
584     }
585 }
586 
DestroyWindow(const sptr<AAFwk::SessionInfo> & sessionInfo)587 void JsAutoFillExtension::DestroyWindow(const sptr<AAFwk::SessionInfo> &sessionInfo)
588 {
589     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
590     if (sessionInfo == nullptr || sessionInfo->sessionToken == nullptr) {
591         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid sessionInfo");
592         return;
593     }
594     auto obj = sessionInfo->sessionToken;
595     if (uiWindowMap_.find(obj) == uiWindowMap_.end()) {
596         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Wrong to find uiWindow");
597         return;
598     }
599     if (contentSessions_.find(obj) != contentSessions_.end() && contentSessions_[obj] != nullptr) {
600         HandleScope handleScope(jsRuntime_);
601         napi_value argv[] = {contentSessions_[obj]->GetNapiValue()};
602         CallObjectMethod("onSessionDestroy", argv, ARGC_ONE);
603     }
604     auto& uiWindow = uiWindowMap_[obj];
605     if (uiWindow) {
606         uiWindow->Destroy();
607     }
608     uiWindowMap_.erase(obj);
609     foregroundWindows_.erase(obj);
610     contentSessions_.erase(obj);
611     callbacks_.erase(obj);
612 }
613 
CallObjectMethod(const char * name,napi_value const * argv,size_t argc,bool withResult)614 napi_value JsAutoFillExtension::CallObjectMethod(const char *name, napi_value const *argv, size_t argc, bool withResult)
615 {
616     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Called, name: (%{public}s)", name);
617     if (!jsObj_) {
618         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Not found AutoFillExtension.js");
619         return nullptr;
620     }
621 
622     HandleEscape handleEscape(jsRuntime_);
623     napi_env env = jsRuntime_.GetNapiEnv();
624 
625     napi_value obj = jsObj_->GetNapiValue();
626     if (!CheckTypeForNapiValue(env, obj, napi_object)) {
627         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "get auto fill extension obj failed");
628         return nullptr;
629     }
630 
631     napi_value method = nullptr;
632     napi_get_named_property(env, obj, name, &method);
633     if (!CheckTypeForNapiValue(env, method, napi_function)) {
634         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "get '%{public}s' from auto fill extension obj failed", name);
635         return nullptr;
636     }
637     if (withResult) {
638         napi_value result = nullptr;
639         napi_call_function(env, obj, method, argc, argv, &result);
640         return handleEscape.Escape(result);
641     }
642     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Call func: (%{public}s) success", name);
643     napi_call_function(env, obj, method, argc, argv, nullptr);
644     return nullptr;
645 }
646 
CallJsOnRequest(const AAFwk::Want & want,const sptr<AAFwk::SessionInfo> & sessionInfo,const sptr<Rosen::Window> & uiWindow)647 void JsAutoFillExtension::CallJsOnRequest(
648     const AAFwk::Want &want, const sptr<AAFwk::SessionInfo> &sessionInfo, const sptr<Rosen::Window> &uiWindow)
649 {
650     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
651     if (sessionInfo == nullptr) {
652         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null sessionInfo");
653         return;
654     }
655     HandleScope handleScope(jsRuntime_);
656     napi_env env = jsRuntime_.GetNapiEnv();
657     if (env == nullptr) {
658         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null env");
659         return;
660     }
661     napi_value nativeContentSession =
662         JsUIExtensionContentSession::CreateJsUIExtensionContentSession(env, sessionInfo, uiWindow);
663     if (nativeContentSession == nullptr) {
664         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to create session");
665         return;
666     }
667     napi_ref ref = nullptr;
668     napi_create_reference(env, nativeContentSession, 1, &ref);
669     contentSessions_.emplace(
670         sessionInfo->sessionToken, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
671 
672     napi_value request = JsAutoFillExtensionUtil::WrapFillRequest(want, env);
673     if (request == nullptr) {
674         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "null fill request");
675         return;
676     }
677 
678     napi_value callback = nullptr;
679     auto cmdValue = want.GetIntParam(WANT_PARAMS_AUTO_FILL_CMD, 0);
680     if (cmdValue == AutoFillCommand::SAVE) {
681         callback = JsSaveRequestCallback::CreateJsSaveRequestCallback(env, sessionInfo, uiWindow);
682         napi_value argv[] = { nativeContentSession, request, callback };
683         CallObjectMethod("onSaveRequest", argv, ARGC_THREE);
684     } else if (cmdValue == AutoFillCommand::FILL || cmdValue == AutoFillCommand::RELOAD_IN_MODAL) {
685         callback = JsFillRequestCallback::CreateJsFillRequestCallback(env, sessionInfo, uiWindow);
686         napi_value argv[] = { nativeContentSession, request, callback };
687         CallObjectMethod("onFillRequest", argv, ARGC_THREE);
688     } else {
689         TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "Invalid auto fill request type");
690         return;
691     }
692 
693     napi_ref callbackRef = nullptr;
694     napi_create_reference(env, callback, 1, &callbackRef);
695     callbacks_.emplace(sessionInfo->sessionToken,
696         std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(callbackRef)));
697 }
698 
RegisterTransferComponentDataListener(const sptr<Rosen::Window> & uiWindow)699 void JsAutoFillExtension::RegisterTransferComponentDataListener(const sptr<Rosen::Window> &uiWindow)
700 {
701     TAG_LOGD(AAFwkTag::AUTOFILL_EXT, "called");
702     if (uiWindow == nullptr) {
703         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Invalid ui window obj");
704         return;
705     }
706 
707     auto handler = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
708     if (handler == nullptr) {
709         TAG_LOGE(AAFwkTag::AUTOFILL_EXT, "Failed to create event handler");
710         return;
711     }
712     uiWindow->RegisterTransferComponentDataListener([this, handler](
713         const AAFwk::WantParams &wantParams) {
714             handler->PostTask([this, wantParams]() {
715                 JsAutoFillExtension::UpdateRequest(wantParams);
716                 }, "JsAutoFillExtension:UpdateRequest");
717     });
718 }
719 } // namespace AbilityRuntime
720 } // namespace OHOS
721