1 /*
2 * Copyright (c) 2021-2023 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 "adapter/preview/entrance/ace_container.h"
17
18 #include <functional>
19
20 #ifndef ENABLE_ROSEN_BACKEND
21 #include "flutter/lib/ui/ui_dart_state.h"
22
23 #include "adapter/preview/entrance/dir_asset_provider.h"
24 #include "core/common/flutter/flutter_asset_manager.h"
25 #include "core/common/flutter/flutter_task_executor.h"
26 #else // ENABLE_ROSEN_BACKEND == true
27 #include "adapter/preview/entrance/rs_dir_asset_provider.h"
28 #include "core/common/flutter/flutter_task_executor.h"
29 #include "core/common/rosen/rosen_asset_manager.h"
30 #endif
31
32 #include "native_engine/native_engine.h"
33
34 #include "adapter/preview/entrance/ace_application_info.h"
35 #include "adapter/preview/osal/stage_card_parser.h"
36 #include "base/log/ace_trace.h"
37 #include "base/log/event_report.h"
38 #include "base/log/log.h"
39 #include "base/utils/system_properties.h"
40 #include "base/utils/utils.h"
41 #include "bridge/card_frontend/card_frontend.h"
42 #include "bridge/card_frontend/card_frontend_declarative.h"
43 #include "bridge/card_frontend/form_frontend_declarative.h"
44 #include "bridge/common/utils/engine_helper.h"
45 #include "bridge/declarative_frontend/declarative_frontend.h"
46 #include "bridge/js_frontend/engine/common/js_engine_loader.h"
47 #include "bridge/js_frontend/js_frontend.h"
48 #include "core/common/ace_engine.h"
49 #include "core/common/ace_view.h"
50 #include "core/common/container_scope.h"
51 #include "core/common/platform_bridge.h"
52 #include "core/common/platform_window.h"
53 #include "core/common/text_field_manager.h"
54 #include "core/common/window.h"
55 #include "core/components/theme/app_theme.h"
56 #include "core/components/theme/theme_constants.h"
57 #include "core/components/theme/theme_manager_impl.h"
58 #include "core/components_ng/pattern/text_field/text_field_manager.h"
59 #include "core/components_ng/render/adapter/rosen_window.h"
60 #include "core/pipeline/base/element.h"
61 #include "core/pipeline/pipeline_context.h"
62 #include "core/pipeline_ng/pipeline_context.h"
63 #include "previewer/include/window.h"
64
65 namespace OHOS::Ace::Platform {
66 namespace {
67 const char LANGUAGE_TAG[] = "language";
68 const char COUNTRY_TAG[] = "countryOrRegion";
69 const char DIRECTION_TAG[] = "dir";
70 const char UNICODE_SETTING_TAG[] = "unicodeSetting";
71 const char LOCALE_DIR_LTR[] = "ltr";
72 const char LOCALE_DIR_RTL[] = "rtl";
73 const char LOCALE_KEY[] = "locale";
74 } // namespace
75
76 std::once_flag AceContainer::onceFlag_;
77 bool AceContainer::isComponentMode_ = false;
AceContainer(int32_t instanceId,FrontendType type,bool useNewPipeline,bool useCurrentEventRunner)78 AceContainer::AceContainer(int32_t instanceId, FrontendType type, bool useNewPipeline, bool useCurrentEventRunner)
79 : instanceId_(instanceId), messageBridge_(AceType::MakeRefPtr<PlatformBridge>()), type_(type)
80 {
81 LOGI("Using %{public}s pipeline context ...", (useNewPipeline ? "new" : "old"));
82 if (useNewPipeline) {
83 SetUseNewPipeline();
84 }
85 ThemeConstants::InitDeviceType();
86 #ifndef ENABLE_ROSEN_BACKEND
87 auto state = flutter::UIDartState::Current()->GetStateById(instanceId);
88 auto flutterTaskExecutor = Referenced::MakeRefPtr<FlutterTaskExecutor>(state->GetTaskRunners());
89 if (type_ != FrontendType::DECLARATIVE_JS && type_ != FrontendType::ETS_CARD) {
90 flutterTaskExecutor->InitJsThread();
91 }
92 #else
93 auto flutterTaskExecutor = Referenced::MakeRefPtr<FlutterTaskExecutor>();
94 flutterTaskExecutor->InitPlatformThread(useCurrentEventRunner);
95 // No need to create JS Thread for DECLARATIVE_JS
96 if (type_ != FrontendType::DECLARATIVE_JS && type_ != FrontendType::ETS_CARD) {
97 flutterTaskExecutor->InitJsThread();
98 } else {
99 GetSettings().useUIAsJSThread = true;
100 }
101 #endif
102 taskExecutor_ = flutterTaskExecutor;
103 }
104
Initialize()105 void AceContainer::Initialize()
106 {
107 ContainerScope scope(instanceId_);
108 if (type_ != FrontendType::DECLARATIVE_JS && type_ != FrontendType::ETS_CARD) {
109 InitializeFrontend();
110 }
111 }
112
Destroy()113 void AceContainer::Destroy()
114 {
115 ContainerScope scope(instanceId_);
116 LOGI("AceContainer::Destroy begin");
117 if (!pipelineContext_) {
118 LOGE("no context find in %{private}d container", instanceId_);
119 return;
120 }
121 if (!taskExecutor_) {
122 LOGE("no taskExecutor find in %{private}d container", instanceId_);
123 return;
124 }
125 auto weak = AceType::WeakClaim(AceType::RawPtr(pipelineContext_));
126 taskExecutor_->PostTask(
127 [weak]() {
128 auto context = weak.Upgrade();
129 if (context == nullptr) {
130 LOGE("context is nullptr");
131 return;
132 }
133 context->Destroy();
134 },
135 TaskExecutor::TaskType::UI);
136
137 RefPtr<Frontend> frontend;
138 frontend_.Swap(frontend);
139 if (frontend && taskExecutor_) {
140 taskExecutor_->PostTask(
141 [frontend]() {
142 frontend->UpdateState(Frontend::State::ON_DESTROY);
143 frontend->Destroy();
144 },
145 TaskExecutor::TaskType::JS);
146 }
147
148 messageBridge_.Reset();
149 resRegister_.Reset();
150 assetManager_.Reset();
151 pipelineContext_.Reset();
152 aceView_ = nullptr;
153 LOGI("AceContainer::Destroy end");
154 }
155
DestroyView()156 void AceContainer::DestroyView()
157 {
158 if (aceView_ != nullptr) {
159 delete aceView_;
160 aceView_ = nullptr;
161 }
162 }
163
InitializeFrontend()164 void AceContainer::InitializeFrontend()
165 {
166 if (type_ == FrontendType::JS) {
167 frontend_ = Frontend::Create();
168 auto jsFrontend = AceType::DynamicCast<JsFrontend>(frontend_);
169 auto jsEngine = Framework::JsEngineLoader::Get().CreateJsEngine(GetInstanceId());
170 EngineHelper::AddEngine(instanceId_, jsEngine);
171 jsFrontend->SetJsEngine(jsEngine);
172 jsFrontend->SetNeedDebugBreakPoint(AceApplicationInfo::GetInstance().IsNeedDebugBreakPoint());
173 jsFrontend->SetDebugVersion(AceApplicationInfo::GetInstance().IsDebugVersion());
174 } else if (type_ == FrontendType::DECLARATIVE_JS) {
175 frontend_ = AceType::MakeRefPtr<DeclarativeFrontend>();
176 auto declarativeFrontend = AceType::DynamicCast<DeclarativeFrontend>(frontend_);
177 auto& loader = Framework::JsEngineLoader::GetDeclarative();
178 RefPtr<Framework::JsEngine> jsEngine;
179 if (GetSettings().usingSharedRuntime) {
180 jsEngine = loader.CreateJsEngineUsingSharedRuntime(instanceId_, sharedRuntime_);
181 } else {
182 jsEngine = loader.CreateJsEngine(instanceId_);
183 }
184 EngineHelper::AddEngine(instanceId_, jsEngine);
185 declarativeFrontend->SetJsEngine(jsEngine);
186 declarativeFrontend->SetPageProfile(pageProfile_);
187 } else if (type_ == FrontendType::JS_CARD) {
188 AceApplicationInfo::GetInstance().SetCardType();
189 frontend_ = AceType::MakeRefPtr<CardFrontend>();
190 } else if (type_ == FrontendType::ETS_CARD) {
191 frontend_ = AceType::MakeRefPtr<FormFrontendDeclarative>();
192 auto cardFrontend = AceType::DynamicCast<FormFrontendDeclarative>(frontend_);
193 auto jsEngine = Framework::JsEngineLoader::GetDeclarative().CreateJsEngine(instanceId_);
194 EngineHelper::AddEngine(instanceId_, jsEngine);
195 cardFrontend->SetJsEngine(jsEngine);
196 cardFrontend->SetPageProfile(pageProfile_);
197 cardFrontend->SetRunningCardId(0);
198 cardFrontend->SetIsFormRender(true);
199 cardFrontend->SetTaskExecutor(taskExecutor_);
200 SetIsFRSCardContainer(true);
201 } else {
202 LOGE("Frontend type not supported");
203 return;
204 }
205 ACE_DCHECK(frontend_);
206 frontend_->DisallowPopLastPage();
207 frontend_->Initialize(type_, taskExecutor_);
208 if (assetManager_) {
209 frontend_->SetAssetManager(assetManager_);
210 }
211 }
212
RunNativeEngineLoop()213 void AceContainer::RunNativeEngineLoop()
214 {
215 taskExecutor_->PostTask([frontend = frontend_]() { frontend->RunNativeEngineLoop(); }, TaskExecutor::TaskType::JS);
216 // After the JS thread executes frontend ->RunNativeEngineLoop(),
217 // it is thrown back into the Platform thread queue to form a loop.
218 taskExecutor_->PostTask([this]() { RunNativeEngineLoop(); }, TaskExecutor::TaskType::PLATFORM);
219 }
220
InitializeStageAppConfig(const std::string & assetPath,const std::string & bundleName,const std::string & moduleName,const std::string & compileMode)221 void AceContainer::InitializeStageAppConfig(const std::string& assetPath, const std::string& bundleName,
222 const std::string& moduleName, const std::string& compileMode)
223 {
224 bool isBundle = (compileMode != "esmodule");
225 auto declarativeFrontend = AceType::DynamicCast<DeclarativeFrontend>(frontend_);
226 CHECK_NULL_VOID(declarativeFrontend);
227 declarativeFrontend->InitializeModuleSearcher(bundleName, moduleName, assetPath, isBundle);
228
229 auto formFrontend = AceType::DynamicCast<FormFrontendDeclarative>(frontend_);
230 CHECK_NULL_VOID(formFrontend);
231 formFrontend->SetBundleName(bundleName);
232 formFrontend->SetModuleName(moduleName);
233 formFrontend->SetIsBundle(isBundle);
234 }
235
SetStageCardConfig(const std::string & pageProfile,const std::string & selectUrl)236 void AceContainer::SetStageCardConfig(const std::string& pageProfile, const std::string& selectUrl)
237 {
238 std::string fullPageProfile = pageProfile + ".json";
239 std::string formConfigs;
240 RefPtr<StageCardParser> stageCardParser = AceType::MakeRefPtr<StageCardParser>();
241 if (!Framework::GetAssetContentImpl(assetManager_, fullPageProfile, formConfigs)) {
242 LOGI("Can not load the form config.");
243 return;
244 }
245 const std::string prefix("./js/");
246 stageCardParser->Parse(formConfigs, prefix + selectUrl);
247 auto cardFront = static_cast<CardFrontend*>(RawPtr(frontend_));
248 if (cardFront) {
249 cardFront->SetFormSrc(selectUrl);
250 cardFront->SetCardWindowConfig(stageCardParser->GetWindowConfig());
251 }
252 }
253
InitializeCallback()254 void AceContainer::InitializeCallback()
255 {
256 ACE_FUNCTION_TRACE();
257
258 ACE_DCHECK(aceView_ && taskExecutor_ && pipelineContext_);
259
260 auto weak = AceType::WeakClaim(AceType::RawPtr(pipelineContext_));
261 auto&& touchEventCallback = [weak, id = instanceId_](
262 const TouchEvent& event, const std::function<void()>& ignoreMark) {
263 ContainerScope scope(id);
264 auto context = weak.Upgrade();
265 if (context == nullptr) {
266 LOGE("context is nullptr");
267 return;
268 }
269 context->GetTaskExecutor()->PostTask(
270 [context, event]() { context->OnTouchEvent(event); }, TaskExecutor::TaskType::UI);
271 };
272 aceView_->RegisterTouchEventCallback(touchEventCallback);
273
274 auto&& keyEventCallback = [weak, id = instanceId_](const KeyEvent& event) {
275 ContainerScope scope(id);
276 auto context = weak.Upgrade();
277 if (context == nullptr) {
278 LOGE("context is nullptr");
279 return false;
280 }
281 bool result = false;
282 context->GetTaskExecutor()->PostSyncTask(
283 [context, event, &result]() { result = context->OnKeyEvent(event); }, TaskExecutor::TaskType::UI);
284 return result;
285 };
286 aceView_->RegisterKeyEventCallback(keyEventCallback);
287
288 auto&& mouseEventCallback = [weak, id = instanceId_](
289 const MouseEvent& event, const std::function<void()>& ignoreMark) {
290 ContainerScope scope(id);
291 auto context = weak.Upgrade();
292 if (context == nullptr) {
293 LOGE("context is nullptr");
294 return;
295 }
296 context->GetTaskExecutor()->PostTask(
297 [context, event]() { context->OnMouseEvent(event); }, TaskExecutor::TaskType::UI);
298 };
299 aceView_->RegisterMouseEventCallback(mouseEventCallback);
300
301 auto&& axisEventCallback = [weak, id = instanceId_](
302 const AxisEvent& event, const std::function<void()>& ignoreMark) {
303 ContainerScope scope(id);
304 auto context = weak.Upgrade();
305 if (context == nullptr) {
306 LOGE("context is nullptr");
307 return;
308 }
309 context->GetTaskExecutor()->PostTask(
310 [context, event]() { context->OnAxisEvent(event); }, TaskExecutor::TaskType::UI);
311 };
312 aceView_->RegisterAxisEventCallback(axisEventCallback);
313
314 auto&& rotationEventCallback = [weak, id = instanceId_](const RotationEvent& event) {
315 ContainerScope scope(id);
316 auto context = weak.Upgrade();
317 if (context == nullptr) {
318 LOGE("context is nullptr");
319 return false;
320 }
321 bool result = false;
322 context->GetTaskExecutor()->PostSyncTask(
323 [context, event, &result]() { result = context->OnRotationEvent(event); }, TaskExecutor::TaskType::UI);
324 return result;
325 };
326 aceView_->RegisterRotationEventCallback(rotationEventCallback);
327
328 auto&& cardViewPositionCallback = [weak, instanceId = instanceId_](int id, float offsetX, float offsetY) {
329 ContainerScope scope(instanceId);
330 auto context = AceType::DynamicCast<PipelineContext>(weak.Upgrade());
331 if (context == nullptr) {
332 LOGE("context is nullptr");
333 return;
334 }
335 context->GetTaskExecutor()->PostSyncTask(
336 [context, id, offsetX, offsetY]() { context->SetCardViewPosition(id, offsetX, offsetY); },
337 TaskExecutor::TaskType::UI);
338 };
339 aceView_->RegisterCardViewPositionCallback(cardViewPositionCallback);
340
341 auto&& cardViewParamsCallback = [weak, id = instanceId_](const std::string& key, bool focus) {
342 ContainerScope scope(id);
343 auto context = AceType::DynamicCast<PipelineContext>(weak.Upgrade());
344 if (context == nullptr) {
345 LOGE("context is nullptr");
346 return;
347 }
348 context->GetTaskExecutor()->PostSyncTask(
349 [context, key, focus]() { context->SetCardViewAccessibilityParams(key, focus); },
350 TaskExecutor::TaskType::UI);
351 };
352 aceView_->RegisterCardViewAccessibilityParamsCallback(cardViewParamsCallback);
353
354 auto&& viewChangeCallback = [weak, id = instanceId_](int32_t width, int32_t height, WindowSizeChangeReason type,
355 const std::shared_ptr<Rosen::RSTransaction>& rsTransaction) {
356 ContainerScope scope(id);
357 auto context = weak.Upgrade();
358 if (context == nullptr) {
359 LOGE("context is nullptr");
360 return;
361 }
362 ACE_SCOPED_TRACE("ViewChangeCallback(%d, %d)", width, height);
363 context->GetTaskExecutor()->PostTask(
364 [context, width, height, type, rsTransaction]() {
365 context->OnSurfaceChanged(width, height, type, rsTransaction);
366 },
367 TaskExecutor::TaskType::UI);
368 };
369 aceView_->RegisterViewChangeCallback(viewChangeCallback);
370
371 auto&& densityChangeCallback = [weak, id = instanceId_](double density) {
372 ContainerScope scope(id);
373 auto context = weak.Upgrade();
374 if (context == nullptr) {
375 LOGE("context is nullptr");
376 return;
377 }
378 ACE_SCOPED_TRACE("DensityChangeCallback(%lf)", density);
379 context->GetTaskExecutor()->PostTask(
380 [context, density]() { context->OnSurfaceDensityChanged(density); }, TaskExecutor::TaskType::UI);
381 };
382 aceView_->RegisterDensityChangeCallback(densityChangeCallback);
383
384 auto&& systemBarHeightChangeCallback = [weak, id = instanceId_](double statusBar, double navigationBar) {
385 ContainerScope scope(id);
386 auto context = weak.Upgrade();
387 if (context == nullptr) {
388 LOGE("context is nullptr");
389 return;
390 }
391 ACE_SCOPED_TRACE("SystemBarHeightChangeCallback(%lf, %lf)", statusBar, navigationBar);
392 context->GetTaskExecutor()->PostTask(
393 [context, statusBar, navigationBar]() { context->OnSystemBarHeightChanged(statusBar, navigationBar); },
394 TaskExecutor::TaskType::UI);
395 };
396 aceView_->RegisterSystemBarHeightChangeCallback(systemBarHeightChangeCallback);
397
398 auto&& surfaceDestroyCallback = [weak, id = instanceId_]() {
399 ContainerScope scope(id);
400 auto context = weak.Upgrade();
401 if (context == nullptr) {
402 LOGE("context is nullptr");
403 return;
404 }
405 context->GetTaskExecutor()->PostTask(
406 [context]() { context->OnSurfaceDestroyed(); }, TaskExecutor::TaskType::UI);
407 };
408 aceView_->RegisterSurfaceDestroyCallback(surfaceDestroyCallback);
409
410 auto&& idleCallback = [weak, id = instanceId_](int64_t deadline) {
411 ContainerScope scope(id);
412 auto context = weak.Upgrade();
413 if (context == nullptr) {
414 LOGE("context is nullptr");
415 return;
416 }
417 context->GetTaskExecutor()->PostTask(
418 [context, deadline]() { context->OnIdle(deadline); }, TaskExecutor::TaskType::UI);
419 };
420 aceView_->RegisterIdleCallback(idleCallback);
421 }
422
CreateContainer(int32_t instanceId,FrontendType type,bool useNewPipeline,bool useCurrentEventRunner)423 void AceContainer::CreateContainer(
424 int32_t instanceId, FrontendType type, bool useNewPipeline, bool useCurrentEventRunner)
425 {
426 auto aceContainer = AceType::MakeRefPtr<AceContainer>(instanceId, type, useNewPipeline, useCurrentEventRunner);
427 AceEngine::Get().AddContainer(aceContainer->GetInstanceId(), aceContainer);
428 aceContainer->Initialize();
429 ContainerScope scope(instanceId);
430 auto front = aceContainer->GetFrontend();
431 if (front) {
432 front->UpdateState(Frontend::State::ON_CREATE);
433 front->SetJsMessageDispatcher(aceContainer);
434 }
435 auto platMessageBridge = aceContainer->GetMessageBridge();
436 platMessageBridge->SetJsMessageDispatcher(aceContainer);
437 }
438
DestroyContainer(int32_t instanceId)439 void AceContainer::DestroyContainer(int32_t instanceId)
440 {
441 auto container = AceEngine::Get().GetContainer(instanceId);
442 if (!container) {
443 LOGE("no AceContainer with id %{private}d in AceEngine", instanceId);
444 return;
445 }
446 container->Destroy();
447 // unregister watchdog before stop thread to avoid UI_BLOCK report
448 AceEngine::Get().UnRegisterFromWatchDog(instanceId);
449 auto taskExecutor = container->GetTaskExecutor();
450 if (taskExecutor) {
451 taskExecutor->PostSyncTask([] { LOGI("Wait UI thread..."); }, TaskExecutor::TaskType::UI);
452 taskExecutor->PostSyncTask([] { LOGI("Wait JS thread..."); }, TaskExecutor::TaskType::JS);
453 }
454 container->DestroyView(); // Stop all threads(ui,gpu,io) for current ability.
455 EngineHelper::RemoveEngine(instanceId);
456 AceEngine::Get().RemoveContainer(instanceId);
457 }
458
RunPage(int32_t instanceId,int32_t pageId,const std::string & url,const std::string & params)459 bool AceContainer::RunPage(int32_t instanceId, int32_t pageId, const std::string& url, const std::string& params)
460 {
461 ACE_FUNCTION_TRACE();
462 auto container = AceEngine::Get().GetContainer(instanceId);
463 if (!container) {
464 return false;
465 }
466
467 ContainerScope scope(instanceId);
468 auto front = container->GetFrontend();
469 if (front) {
470 auto type = front->GetType();
471 if ((type == FrontendType::JS) || (type == FrontendType::DECLARATIVE_JS) || (type == FrontendType::JS_CARD) ||
472 (type == FrontendType::ETS_CARD)) {
473 front->RunPage(pageId, url, params);
474 return true;
475 } else {
476 LOGE("Frontend type not supported when runpage");
477 EventReport::SendAppStartException(AppStartExcepType::FRONTEND_TYPE_ERR);
478 return false;
479 }
480 }
481 return false;
482 }
483
UpdateResourceConfiguration(const std::string & jsonStr)484 void AceContainer::UpdateResourceConfiguration(const std::string& jsonStr)
485 {
486 ContainerScope scope(instanceId_);
487 uint32_t updateFlags = 0;
488 auto resConfig = resourceInfo_.GetResourceConfiguration();
489 if (!resConfig.UpdateFromJsonString(jsonStr, updateFlags) || !updateFlags) {
490 return;
491 }
492 resourceInfo_.SetResourceConfiguration(resConfig);
493 if (ResourceConfiguration::TestFlag(updateFlags, ResourceConfiguration::COLOR_MODE_UPDATED_FLAG)) {
494 SystemProperties::SetColorMode(resConfig.GetColorMode());
495 if (frontend_) {
496 frontend_->SetColorMode(resConfig.GetColorMode());
497 }
498 }
499 if (!pipelineContext_) {
500 return;
501 }
502 auto themeManager = pipelineContext_->GetThemeManager();
503 if (!themeManager) {
504 return;
505 }
506 themeManager->UpdateConfig(resConfig);
507 taskExecutor_->PostTask(
508 [weakThemeManager = WeakPtr<ThemeManager>(themeManager), colorScheme = colorScheme_, config = resConfig,
509 weakContext = WeakPtr<PipelineBase>(pipelineContext_)]() {
510 auto themeManager = weakThemeManager.Upgrade();
511 auto context = weakContext.Upgrade();
512 if (!themeManager || !context) {
513 return;
514 }
515 themeManager->LoadResourceThemes();
516 themeManager->ParseSystemTheme();
517 themeManager->SetColorScheme(colorScheme);
518 context->RefreshRootBgColor();
519 context->UpdateFontWeightScale();
520 context->SetFontScale(config.GetFontRatio());
521 },
522 TaskExecutor::TaskType::UI);
523 if (frontend_) {
524 frontend_->RebuildAllPages();
525 }
526 }
527
NativeOnConfigurationUpdated(int32_t instanceId)528 void AceContainer::NativeOnConfigurationUpdated(int32_t instanceId)
529 {
530 auto container = GetContainerInstance(instanceId);
531 if (!container) {
532 return;
533 }
534 ContainerScope scope(instanceId);
535 auto front = container->GetFrontend();
536 if (!front) {
537 return;
538 }
539
540 std::unique_ptr<JsonValue> value = JsonUtil::Create(true);
541 value->Put("fontScale", container->GetResourceConfiguration().GetFontRatio());
542 value->Put("colorMode", SystemProperties::GetColorMode() == ColorMode::LIGHT ? "light" : "dark");
543 auto declarativeFrontend = AceType::DynamicCast<DeclarativeFrontend>(front);
544 if (declarativeFrontend) {
545 container->UpdateResourceConfiguration(value->ToString());
546 declarativeFrontend->OnConfigurationUpdated(value->ToString());
547 return;
548 }
549
550 std::unique_ptr<JsonValue> localeValue = JsonUtil::Create(false);
551 localeValue->Put(LANGUAGE_TAG, AceApplicationInfo::GetInstance().GetLanguage().c_str());
552 localeValue->Put(COUNTRY_TAG, AceApplicationInfo::GetInstance().GetCountryOrRegion().c_str());
553 localeValue->Put(
554 DIRECTION_TAG, AceApplicationInfo::GetInstance().IsRightToLeft() ? LOCALE_DIR_RTL : LOCALE_DIR_LTR);
555 localeValue->Put(UNICODE_SETTING_TAG, AceApplicationInfo::GetInstance().GetUnicodeSetting().c_str());
556 value->Put(LOCALE_KEY, localeValue);
557 front->OnConfigurationUpdated(value->ToString());
558 }
559
Dispatch(const std::string & group,std::vector<uint8_t> && data,int32_t id,bool replyToComponent) const560 void AceContainer::Dispatch(
561 const std::string& group, std::vector<uint8_t>&& data, int32_t id, bool replyToComponent) const
562 {}
563
FetchResponse(const ResponseData responseData,const int32_t callbackId) const564 void AceContainer::FetchResponse(const ResponseData responseData, const int32_t callbackId) const
565 {
566 auto container = AceType::DynamicCast<AceContainer>(AceEngine::Get().GetContainer(0));
567 if (!container) {
568 LOGE("FetchResponse container is null!");
569 return;
570 }
571 ContainerScope scope(instanceId_);
572 auto front = container->GetFrontend();
573 auto type = container->GetType();
574 if (type == FrontendType::JS) {
575 auto jsFrontend = AceType::DynamicCast<JsFrontend>(front);
576 if (jsFrontend) {
577 jsFrontend->TransferJsResponseDataPreview(callbackId, ACTION_SUCCESS, responseData);
578 }
579 } else if (type == FrontendType::DECLARATIVE_JS) {
580 auto declarativeFrontend = AceType::DynamicCast<DeclarativeFrontend>(front);
581 if (declarativeFrontend) {
582 declarativeFrontend->TransferJsResponseDataPreview(callbackId, ACTION_SUCCESS, responseData);
583 }
584 } else {
585 LOGE("Frontend type not supported");
586 return;
587 }
588 }
589
CallCurlFunction(const RequestData requestData,const int32_t callbackId) const590 void AceContainer::CallCurlFunction(const RequestData requestData, const int32_t callbackId) const
591 {
592 auto container = AceType::DynamicCast<AceContainer>(AceEngine::Get().GetContainer(ACE_INSTANCE_ID));
593 if (!container) {
594 LOGE("CallCurlFunction container is null!");
595 return;
596 }
597
598 ContainerScope scope(instanceId_);
599 taskExecutor_->PostTask(
600 [container, requestData, callbackId]() mutable {
601 ResponseData responseData;
602 if (FetchManager::GetInstance().Fetch(requestData, callbackId, responseData)) {
603 container->FetchResponse(responseData, callbackId);
604 }
605 },
606 TaskExecutor::TaskType::BACKGROUND);
607 }
608
DispatchPluginError(int32_t callbackId,int32_t errorCode,std::string && errorMessage) const609 void AceContainer::DispatchPluginError(int32_t callbackId, int32_t errorCode, std::string&& errorMessage) const
610 {
611 auto front = GetFrontend();
612 if (!front) {
613 LOGE("the front jni is nullptr");
614 return;
615 }
616
617 ContainerScope scope(instanceId_);
618 taskExecutor_->PostTask(
619 [front, callbackId, errorCode, errorMessage = std::move(errorMessage)]() mutable {
620 front->TransferJsPluginGetError(callbackId, errorCode, std::move(errorMessage));
621 },
622 TaskExecutor::TaskType::BACKGROUND);
623 }
624
AddRouterChangeCallback(int32_t instanceId,const OnRouterChangeCallback & onRouterChangeCallback)625 void AceContainer::AddRouterChangeCallback(int32_t instanceId, const OnRouterChangeCallback& onRouterChangeCallback)
626 {
627 auto container = GetContainerInstance(instanceId);
628 if (!container) {
629 return;
630 }
631 ContainerScope scope(instanceId);
632 if (!container->pipelineContext_) {
633 LOGE("container pipelineContext not init");
634 return;
635 }
636 container->pipelineContext_->AddRouterChangeCallback(onRouterChangeCallback);
637 }
638
639 #ifndef ENABLE_ROSEN_BACKEND
AddAssetPath(int32_t instanceId,const std::string & packagePath,const std::vector<std::string> & paths)640 void AceContainer::AddAssetPath(
641 int32_t instanceId, const std::string& packagePath, const std::vector<std::string>& paths)
642 {
643 auto container = GetContainerInstance(instanceId);
644 CHECK_NULL_VOID(container);
645
646 if (!container->assetManager_) {
647 RefPtr<FlutterAssetManager> flutterAssetManager = Referenced::MakeRefPtr<FlutterAssetManager>();
648 container->assetManager_ = flutterAssetManager;
649 if (container->frontend_) {
650 container->frontend_->SetAssetManager(flutterAssetManager);
651 }
652 }
653
654 for (const auto& path : paths) {
655 LOGD("Current path is: %{private}s", path.c_str());
656 auto dirAssetProvider = AceType::MakeRefPtr<DirAssetProvider>(
657 path, std::make_unique<flutter::DirectoryAssetBundle>(
658 fml::OpenDirectory(path.c_str(), false, fml::FilePermission::kRead)));
659 container->assetManager_->PushBack(std::move(dirAssetProvider));
660 }
661 }
662 #else
AddAssetPath(int32_t instanceId,const std::string & packagePath,const std::vector<std::string> & paths)663 void AceContainer::AddAssetPath(
664 int32_t instanceId, const std::string& packagePath, const std::vector<std::string>& paths)
665 {
666 auto container = GetContainerInstance(instanceId);
667 CHECK_NULL_VOID(container);
668
669 if (!container->assetManager_) {
670 RefPtr<RSAssetManager> rsAssetManager = Referenced::MakeRefPtr<RSAssetManager>();
671 container->assetManager_ = rsAssetManager;
672 if (container->frontend_) {
673 container->frontend_->SetAssetManager(rsAssetManager);
674 }
675 }
676
677 for (const auto& path : paths) {
678 LOGD("Current path is: %{private}s", path.c_str());
679 auto dirAssetProvider = AceType::MakeRefPtr<RSDirAssetProvider>(path);
680 container->assetManager_->PushBack(std::move(dirAssetProvider));
681 }
682 }
683 #endif
684
SetResourcesPathAndThemeStyle(int32_t instanceId,const std::string & systemResourcesPath,const std::string & appResourcesPath,const int32_t & themeId,const ColorMode & colorMode)685 void AceContainer::SetResourcesPathAndThemeStyle(int32_t instanceId, const std::string& systemResourcesPath,
686 const std::string& appResourcesPath, const int32_t& themeId, const ColorMode& colorMode)
687 {
688 auto container = GetContainerInstance(instanceId);
689 if (!container) {
690 return;
691 }
692 ContainerScope scope(instanceId);
693 auto resConfig = container->resourceInfo_.GetResourceConfiguration();
694 resConfig.SetColorMode(static_cast<OHOS::Ace::ColorMode>(colorMode));
695 container->resourceInfo_.SetResourceConfiguration(resConfig);
696 container->resourceInfo_.SetPackagePath(appResourcesPath);
697 container->resourceInfo_.SetSystemPackagePath(systemResourcesPath);
698 container->resourceInfo_.SetThemeId(themeId);
699 }
700
UpdateDeviceConfig(const DeviceConfig & deviceConfig)701 void AceContainer::UpdateDeviceConfig(const DeviceConfig& deviceConfig)
702 {
703 ContainerScope scope(instanceId_);
704 SystemProperties::InitDeviceType(deviceConfig.deviceType);
705 SystemProperties::SetDeviceOrientation(deviceConfig.orientation == DeviceOrientation::PORTRAIT ? 0 : 1);
706 SystemProperties::SetResolution(deviceConfig.density);
707 SystemProperties::SetColorMode(deviceConfig.colorMode);
708 auto resConfig = resourceInfo_.GetResourceConfiguration();
709 if (resConfig.GetDeviceType() == deviceConfig.deviceType &&
710 resConfig.GetOrientation() == deviceConfig.orientation && resConfig.GetDensity() == deviceConfig.density &&
711 resConfig.GetColorMode() == deviceConfig.colorMode && resConfig.GetFontRatio() == deviceConfig.fontRatio) {
712 return;
713 } else {
714 resConfig.SetDeviceType(deviceConfig.deviceType);
715 resConfig.SetOrientation(deviceConfig.orientation);
716 resConfig.SetDensity(deviceConfig.density);
717 resConfig.SetColorMode(deviceConfig.colorMode);
718 resConfig.SetFontRatio(deviceConfig.fontRatio);
719 if (frontend_) {
720 frontend_->SetColorMode(deviceConfig.colorMode);
721 }
722 }
723 resourceInfo_.SetResourceConfiguration(resConfig);
724 if (!pipelineContext_) {
725 return;
726 }
727 auto themeManager = pipelineContext_->GetThemeManager();
728 if (!themeManager) {
729 return;
730 }
731 themeManager->UpdateConfig(resConfig);
732 taskExecutor_->PostTask(
733 [weakThemeManager = WeakPtr<ThemeManager>(themeManager), colorScheme = colorScheme_,
734 weakContext = WeakPtr<PipelineBase>(pipelineContext_)]() {
735 auto themeManager = weakThemeManager.Upgrade();
736 auto context = weakContext.Upgrade();
737 if (!themeManager || !context) {
738 return;
739 }
740 themeManager->LoadResourceThemes();
741 themeManager->ParseSystemTheme();
742 themeManager->SetColorScheme(colorScheme);
743 context->RefreshRootBgColor();
744 },
745 TaskExecutor::TaskType::UI);
746 }
747
748 #ifndef ENABLE_ROSEN_BACKEND
SetView(AceViewPreview * view,double density,int32_t width,int32_t height)749 void AceContainer::SetView(AceViewPreview* view, double density, int32_t width, int32_t height)
750 {
751 if (view == nullptr) {
752 return;
753 }
754
755 auto container = AceType::DynamicCast<AceContainer>(AceEngine::Get().GetContainer(view->GetInstanceId()));
756 if (!container) {
757 return;
758 }
759 auto platformWindow = PlatformWindow::Create(view);
760 if (!platformWindow) {
761 LOGE("Create PlatformWindow failed!");
762 return;
763 }
764
765 std::unique_ptr<Window> window = std::make_unique<Window>(std::move(platformWindow));
766 container->AttachView(std::move(window), view, density, width, height);
767 }
768 #else
SetView(AceViewPreview * view,sptr<Rosen::Window> rsWindow,double density,int32_t width,int32_t height,UIEnvCallback callback)769 void AceContainer::SetView(AceViewPreview* view, sptr<Rosen::Window> rsWindow, double density, int32_t width,
770 int32_t height, UIEnvCallback callback)
771 {
772 CHECK_NULL_VOID(view);
773 auto container = AceType::DynamicCast<AceContainer>(AceEngine::Get().GetContainer(view->GetInstanceId()));
774 CHECK_NULL_VOID(container);
775 auto taskExecutor = container->GetTaskExecutor();
776 CHECK_NULL_VOID(taskExecutor);
777 auto window = std::make_unique<NG::RosenWindow>(rsWindow, taskExecutor, view->GetInstanceId());
778 container->AttachView(std::move(window), view, density, width, height, callback);
779 }
780 #endif
781
782 #ifndef ENABLE_ROSEN_BACKEND
AttachView(std::unique_ptr<Window> window,AceViewPreview * view,double density,int32_t width,int32_t height)783 void AceContainer::AttachView(
784 std::unique_ptr<Window> window, AceViewPreview* view, double density, int32_t width, int32_t height)
785 {
786 ContainerScope scope(instanceId_);
787 aceView_ = view;
788 auto instanceId = aceView_->GetInstanceId();
789
790 auto state = flutter::UIDartState::Current()->GetStateById(instanceId);
791 ACE_DCHECK(state != nullptr);
792 auto flutterTaskExecutor = AceType::DynamicCast<FlutterTaskExecutor>(taskExecutor_);
793 flutterTaskExecutor->InitOtherThreads(state->GetTaskRunners());
794 if (type_ == FrontendType::DECLARATIVE_JS) {
795 // For DECLARATIVE_JS frontend display UI in JS thread temporarily.
796 flutterTaskExecutor->InitJsThread(false);
797 InitializeFrontend();
798 auto front = GetFrontend();
799 if (front) {
800 front->UpdateState(Frontend::State::ON_CREATE);
801 front->SetJsMessageDispatcher(AceType::Claim(this));
802 }
803 }
804 resRegister_ = aceView_->GetPlatformResRegister();
805 auto pipelineContext = AceType::MakeRefPtr<PipelineContext>(
806 std::move(window), taskExecutor_, assetManager_, resRegister_, frontend_, instanceId);
807 pipelineContext->SetRootSize(density, width, height);
808 pipelineContext->SetTextFieldManager(AceType::MakeRefPtr<TextFieldManager>());
809 pipelineContext->SetIsRightToLeft(AceApplicationInfo::GetInstance().IsRightToLeft());
810 pipelineContext->SetMessageBridge(messageBridge_);
811 pipelineContext->SetWindowModal(windowModal_);
812 pipelineContext->SetDrawDelegate(aceView_->GetDrawDelegate());
813 pipelineContext->SetIsJsCard(type_ == FrontendType::JS_CARD);
814 pipelineContext_ = pipelineContext;
815 InitializeCallback();
816
817 ThemeConstants::InitDeviceType();
818 // Only init global resource here, construct theme in UI thread
819 auto themeManager = AceType::MakeRefPtr<ThemeManagerImpl>();
820 if (themeManager) {
821 pipelineContext_->SetThemeManager(themeManager);
822 // Init resource, load theme map.
823 themeManager->InitResource(resourceInfo_);
824 themeManager->LoadSystemTheme(resourceInfo_.GetThemeId());
825 taskExecutor_->PostTask(
826 [themeManager, assetManager = assetManager_, colorScheme = colorScheme_, aceView = aceView_]() {
827 themeManager->ParseSystemTheme();
828 themeManager->SetColorScheme(colorScheme);
829 themeManager->LoadCustomTheme(assetManager);
830 // get background color from theme
831 aceView->SetBackgroundColor(themeManager->GetBackgroundColor());
832 },
833 TaskExecutor::TaskType::UI);
834 }
835
836 auto weak = AceType::WeakClaim(AceType::RawPtr(pipelineContext_));
837 taskExecutor_->PostTask(
838 [weak]() {
839 auto context = weak.Upgrade();
840 if (context == nullptr) {
841 LOGE("context is nullptr");
842 return;
843 }
844 context->SetupRootElement();
845 },
846 TaskExecutor::TaskType::UI);
847 aceView_->Launch();
848
849 frontend_->AttachPipelineContext(pipelineContext_);
850 auto cardFronted = AceType::DynamicCast<CardFrontend>(frontend_);
851 if (cardFronted) {
852 cardFronted->SetDensity(static_cast<double>(density));
853 taskExecutor_->PostTask(
854 [weak, width, height]() {
855 auto context = weak.Upgrade();
856 if (context == nullptr) {
857 LOGE("context is nullptr");
858 return;
859 }
860 context->OnSurfaceChanged(width, height);
861 },
862 TaskExecutor::TaskType::UI);
863 }
864
865 AceEngine::Get().RegisterToWatchDog(instanceId, taskExecutor_, GetSettings().useUIAsJSThread);
866 }
867 #else
AttachView(std::unique_ptr<Window> window,AceViewPreview * view,double density,int32_t width,int32_t height,UIEnvCallback callback)868 void AceContainer::AttachView(std::unique_ptr<Window> window, AceViewPreview* view, double density, int32_t width,
869 int32_t height, UIEnvCallback callback)
870 {
871 ContainerScope scope(instanceId_);
872 aceView_ = view;
873 auto instanceId = aceView_->GetInstanceId();
874
875 auto flutterTaskExecutor = AceType::DynamicCast<FlutterTaskExecutor>(taskExecutor_);
876 CHECK_NULL_VOID(flutterTaskExecutor);
877 flutterTaskExecutor->InitOtherThreads(aceView_->GetThreadModel());
878 if (type_ == FrontendType::DECLARATIVE_JS || type_ == FrontendType::ETS_CARD) {
879 // For DECLARATIVE_JS frontend display UI in JS thread temporarily.
880 flutterTaskExecutor->InitJsThread(false);
881 InitializeFrontend();
882 auto front = AceType::DynamicCast<DeclarativeFrontend>(GetFrontend());
883 if (front) {
884 front->UpdateState(Frontend::State::ON_CREATE);
885 front->SetJsMessageDispatcher(AceType::Claim(this));
886 auto weak = WeakPtr(front->GetJsEngine());
887 taskExecutor_->PostTask(
888 [weak, containerSdkPath = containerSdkPath_]() {
889 auto jsEngine = weak.Upgrade();
890 CHECK_NULL_VOID(jsEngine);
891 auto* nativeEngine = jsEngine->GetNativeEngine();
892 CHECK_NULL_VOID(nativeEngine);
893 auto* moduleManager = nativeEngine->GetModuleManager();
894 CHECK_NULL_VOID(moduleManager);
895 moduleManager->SetPreviewSearchPath(containerSdkPath);
896 },
897 TaskExecutor::TaskType::JS);
898 }
899 }
900 resRegister_ = aceView_->GetPlatformResRegister();
901 if (useNewPipeline_) {
902 LOGI("New pipeline version creating...");
903 pipelineContext_ = AceType::MakeRefPtr<NG::PipelineContext>(
904 std::move(window), taskExecutor_, assetManager_, resRegister_, frontend_, instanceId);
905 pipelineContext_->SetTextFieldManager(AceType::MakeRefPtr<NG::TextFieldManagerNG>());
906 } else {
907 pipelineContext_ = AceType::MakeRefPtr<PipelineContext>(
908 std::move(window), taskExecutor_, assetManager_, resRegister_, frontend_, instanceId);
909 pipelineContext_->SetTextFieldManager(AceType::MakeRefPtr<TextFieldManager>());
910 }
911 pipelineContext_->SetRootSize(density, width, height);
912 pipelineContext_->SetIsRightToLeft(AceApplicationInfo::GetInstance().IsRightToLeft());
913 pipelineContext_->SetMessageBridge(messageBridge_);
914 pipelineContext_->SetWindowModal(windowModal_);
915 pipelineContext_->SetDrawDelegate(aceView_->GetDrawDelegate());
916 pipelineContext_->SetIsJsCard(type_ == FrontendType::JS_CARD);
917 if (installationFree_ && !isComponentMode_) {
918 LOGD("installationFree:%{public}d, labelId:%{public}d", installationFree_, labelId_);
919 pipelineContext_->SetInstallationFree(installationFree_);
920 pipelineContext_->SetAppLabelId(labelId_);
921 }
922 pipelineContext_->OnShow();
923 InitializeCallback();
924
925 auto cardFrontend = AceType::DynamicCast<FormFrontendDeclarative>(frontend_);
926 if (cardFrontend) {
927 pipelineContext_->SetIsFormRender(true);
928 cardFrontend->SetLoadCardCallBack(WeakPtr<PipelineBase>(pipelineContext_));
929 }
930
931 ThemeConstants::InitDeviceType();
932 // Only init global resource here, construct theme in UI thread
933 auto themeManager = AceType::MakeRefPtr<ThemeManagerImpl>();
934 if (themeManager) {
935 pipelineContext_->SetThemeManager(themeManager);
936 // Init resource, load theme map.
937 themeManager->InitResource(resourceInfo_);
938 themeManager->LoadSystemTheme(resourceInfo_.GetThemeId());
939 taskExecutor_->PostTask(
940 [themeManager, assetManager = assetManager_, colorScheme = colorScheme_, aceView = aceView_]() {
941 themeManager->ParseSystemTheme();
942 themeManager->SetColorScheme(colorScheme);
943 themeManager->LoadCustomTheme(assetManager);
944 // get background color from theme
945 aceView->SetBackgroundColor(themeManager->GetBackgroundColor());
946 },
947 TaskExecutor::TaskType::UI);
948 }
949 if (!useNewPipeline_) {
950 taskExecutor_->PostTask(
951 [context = pipelineContext_, callback]() {
952 CHECK_NULL_VOID(callback);
953 callback(AceType::DynamicCast<PipelineContext>(context));
954 },
955 TaskExecutor::TaskType::UI);
956 }
957
958 auto weak = AceType::WeakClaim(AceType::RawPtr(pipelineContext_));
959 taskExecutor_->PostTask(
960 [weak]() {
961 auto context = weak.Upgrade();
962 if (context == nullptr) {
963 LOGE("context is nullptr");
964 return;
965 }
966 context->SetupRootElement();
967 },
968 TaskExecutor::TaskType::UI);
969 aceView_->Launch();
970
971 frontend_->AttachPipelineContext(pipelineContext_);
972 auto cardFronted = AceType::DynamicCast<CardFrontend>(frontend_);
973 if (cardFronted) {
974 cardFronted->SetDensity(static_cast<double>(density));
975 taskExecutor_->PostTask(
976 [weak, width, height]() {
977 auto context = weak.Upgrade();
978 if (context == nullptr) {
979 LOGE("context is nullptr");
980 return;
981 }
982 context->OnSurfaceChanged(width, height);
983 },
984 TaskExecutor::TaskType::UI);
985 }
986
987 AceEngine::Get().RegisterToWatchDog(instanceId, taskExecutor_, GetSettings().useUIAsJSThread);
988 }
989 #endif
990
GetContainerInstance(int32_t instanceId)991 RefPtr<AceContainer> AceContainer::GetContainerInstance(int32_t instanceId)
992 {
993 auto container = AceType::DynamicCast<AceContainer>(AceEngine::Get().GetContainer(instanceId));
994 return container;
995 }
996
GetContentInfo(int32_t instanceId)997 std::string AceContainer::GetContentInfo(int32_t instanceId)
998 {
999 auto container = AceEngine::Get().GetContainer(instanceId);
1000 CHECK_NULL_RETURN_NOLOG(container, "");
1001 ContainerScope scope(instanceId);
1002 auto front = container->GetFrontend();
1003 CHECK_NULL_RETURN_NOLOG(front, "");
1004 return front->GetContentInfo();
1005 }
1006
LoadDocument(const std::string & url,const std::string & componentName)1007 void AceContainer::LoadDocument(const std::string& url, const std::string& componentName)
1008 {
1009 ContainerScope scope(instanceId_);
1010 if (type_ != FrontendType::DECLARATIVE_JS) {
1011 LOGE("component preview not supported");
1012 return;
1013 }
1014 auto frontend = AceType::DynamicCast<OHOS::Ace::DeclarativeFrontend>(frontend_);
1015 if (!frontend) {
1016 LOGE("frontend is null, AceContainer::LoadDocument failed");
1017 return;
1018 }
1019 auto jsEngine = frontend->GetJsEngine();
1020 if (!jsEngine) {
1021 LOGE("jsEngine is null, AceContainer::LoadDocument failed");
1022 return;
1023 }
1024 taskExecutor_->PostTask(
1025 [front = frontend, componentName, url, jsEngine]() {
1026 front->SetPagePath(url);
1027 jsEngine->ReplaceJSContent(url, componentName);
1028 },
1029 TaskExecutor::TaskType::JS);
1030 }
1031 } // namespace OHOS::Ace::Platform
1032