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