1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components_ng/pattern/plugin/plugin_pattern.h"
17
18 #include <string>
19
20 #ifdef OS_ACCOUNT_EXISTS
21 #include "os_account_manager.h"
22 #endif // OS_ACCOUNT_EXISTS
23 #include "flutter/lib/ui/ui_dart_state.h"
24
25 #include "base/log/log_wrapper.h"
26 #include "base/utils/utils.h"
27 #include "core/common/plugin_manager.h"
28 #include "core/components/plugin/plugin_component_manager.h"
29 #include "core/components/plugin/plugin_sub_container.h"
30 #include "core/components/plugin/render_plugin.h"
31 #include "core/components/plugin/resource/plugin_manager_delegate.h"
32 #include "core/components_ng/pattern/plugin/plugin_event_hub.h"
33 #include "core/components_ng/render/adapter/rosen_render_context.h"
34
35 namespace OHOS::Ace::NG {
36
37 namespace {
38 #ifndef OS_ACCOUNT_EXISTS
39 constexpr int32_t DEFAULT_OS_ACCOUNT_ID = 0; // 0 is the default id when there is no os_account part
40 #endif // OS_ACCOUNT_EXISTS
41
GetActiveAccountIds(std::vector<int32_t> & userIds)42 ErrCode GetActiveAccountIds(std::vector<int32_t>& userIds)
43 {
44 userIds.clear();
45 #ifdef OS_ACCOUNT_EXISTS
46 return AccountSA::OsAccountManager::QueryActiveOsAccountIds(userIds);
47 #else // OS_ACCOUNT_EXISTS
48 LOGE("os account part not exists, use default id.");
49 userIds.push_back(DEFAULT_OS_ACCOUNT_ID);
50 return ERR_OK;
51 #endif // OS_ACCOUNT_EXISTS
52 }
53 constexpr char JS_EXT[] = ".js";
54 constexpr char ETS_EXT[] = ".ets";
55 constexpr size_t SIZE_OF_ETS_EXT = 4;
56 } // namespace
57
~PluginPattern()58 PluginPattern::~PluginPattern()
59 {
60 pluginManagerBridge_.Reset();
61 if (pluginSubContainer_) {
62 auto currentId = pluginSubContainer_->GetInstanceId();
63 PluginManager::GetInstance().RemovePluginSubContainer(currentId);
64 PluginManager::GetInstance().RemovePluginParentContainer(currentId);
65 pluginSubContainer_->Destroy();
66 pluginSubContainer_.Reset();
67 }
68 }
69
OnAttachToFrameNode()70 void PluginPattern::OnAttachToFrameNode()
71 {
72 auto host = GetHost();
73 CHECK_NULL_VOID(host);
74 host->GetRenderContext()->SetClipToFrame(true);
75 InitPluginManagerDelegate();
76 }
77
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)78 bool PluginPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
79 {
80 if (config.skipMeasure && config.skipLayout) {
81 return false;
82 }
83
84 auto size = dirty->GetGeometryNode()->GetFrameSize();
85 auto host = GetHost();
86 CHECK_NULL_RETURN(host, false);
87 auto layoutProperty = host->GetLayoutProperty<PluginLayoutProperty>();
88 CHECK_NULL_RETURN(layoutProperty, false);
89 auto info = layoutProperty->GetRequestPluginInfo().value_or(RequestPluginInfo());
90 info.width = Dimension(size.Width());
91 info.height = Dimension(size.Height());
92 layoutProperty->UpdateRequestPluginInfo(info);
93 auto data = layoutProperty->GetData().value_or("");
94 if (info.bundleName != pluginInfo_.bundleName || info.abilityName != pluginInfo_.abilityName ||
95 info.moduleName != pluginInfo_.moduleName || info.pluginName != pluginInfo_.pluginName ||
96 info.dimension != pluginInfo_.dimension || data_ != data) {
97 pluginInfo_ = info;
98 data_ = data;
99 LOGI(" pluginInfo_ = info; pluginInfo_.width:: %{public}lf, pluginInfo_.height:: %{public}lf",
100 pluginInfo_.width.Value(), pluginInfo_.height.Value());
101 } else {
102 // for update pluguin component
103 if (pluginInfo_.allowUpdate != info.allowUpdate) {
104 pluginInfo_.allowUpdate = info.allowUpdate;
105 if (pluginSubContainer_) {
106 pluginSubContainer_->SetAllowUpdate(pluginInfo_.allowUpdate);
107 }
108 }
109
110 if (pluginInfo_.width != info.width || pluginInfo_.height != info.height) {
111 pluginInfo_.width = info.width;
112 pluginInfo_.height = info.height;
113 if (pluginSubContainer_) {
114 pluginSubContainer_->SetPluginPattern(WeakClaim(this));
115 pluginSubContainer_->UpdateRootElementSize();
116 pluginSubContainer_->UpdateSurfaceSize();
117 }
118 }
119 return false;
120 }
121 CreatePluginSubContainer();
122 if (pluginManagerBridge_) {
123 pluginManagerBridge_->AddPlugin(host->GetContext(), info);
124 }
125 return false;
126 }
127
InitPluginManagerDelegate()128 void PluginPattern::InitPluginManagerDelegate()
129 {
130 CHECK_NULL_VOID(!pluginManagerBridge_);
131 auto host = GetHost();
132 CHECK_NULL_VOID(host);
133 auto context = host->GetContext();
134 CHECK_NULL_VOID(context);
135 pluginManagerBridge_ = AceType::MakeRefPtr<PluginManagerDelegate>(context);
136 int32_t instanceID = context->GetInstanceId();
137 pluginManagerBridge_->AddPluginCompleteCallback([weak = WeakClaim(this), instanceID]() {
138 ContainerScope scope(instanceID);
139 auto plugin = weak.Upgrade();
140 CHECK_NULL_VOID(plugin);
141 auto host = plugin->GetHost();
142 CHECK_NULL_VOID(host);
143 auto uiTaskExecutor =
144 SingleTaskExecutor::Make(host->GetContext()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
145 uiTaskExecutor.PostTask([weak, instanceID] {
146 ContainerScope scope(instanceID);
147 auto plugin = weak.Upgrade();
148 CHECK_NULL_VOID(plugin);
149 plugin->FireOnCompleteEvent();
150 });
151 });
152 pluginManagerBridge_->AddPluginUpdateCallback([weak = WeakClaim(this), instanceID](int64_t id, std::string data) {
153 ContainerScope scope(instanceID);
154 auto plugin = weak.Upgrade();
155 CHECK_NULL_VOID(plugin);
156 auto host = plugin->GetHost();
157 CHECK_NULL_VOID(host);
158 auto uiTaskExecutor =
159 SingleTaskExecutor::Make(host->GetContext()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
160 uiTaskExecutor.PostTask([id, data, weak] {
161 auto plugin = weak.Upgrade();
162 CHECK_NULL_VOID(plugin);
163 plugin->GetPluginSubContainer()->UpdatePlugin(data);
164 });
165 });
166 pluginManagerBridge_->AddPluginErrorCallback(
167 [weak = WeakClaim(this), instanceID](std::string code, std::string msg) {
168 ContainerScope scope(instanceID);
169 auto plugin = weak.Upgrade();
170 CHECK_NULL_VOID(plugin);
171 auto host = plugin->GetHost();
172 CHECK_NULL_VOID(host);
173 auto uiTaskExecutor =
174 SingleTaskExecutor::Make(host->GetContext()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
175 uiTaskExecutor.PostTask([code, msg, weak, instanceID] {
176 ContainerScope scope(instanceID);
177 auto plugin = weak.Upgrade();
178 CHECK_NULL_VOID(plugin);
179 plugin->FireOnErrorEvent(code, msg);
180 });
181 });
182 }
183
CreatePluginSubContainer()184 void PluginPattern::CreatePluginSubContainer()
185 {
186 auto host = GetHost();
187 CHECK_NULL_VOID(host);
188 auto context = host->GetContext();
189 CHECK_NULL_VOID(context);
190 auto layoutProperty = host->GetLayoutProperty<PluginLayoutProperty>();
191 CHECK_NULL_VOID(layoutProperty);
192
193 auto parentcontainerId = Container::CurrentId();
194 while (parentcontainerId >= MIN_PLUGIN_SUBCONTAINER_ID) {
195 parentcontainerId = PluginManager::GetInstance().GetPluginParentContainerId(parentcontainerId);
196 }
197
198 if (pluginSubContainer_) {
199 auto currentId = pluginSubContainer_->GetInstanceId();
200 PluginManager::GetInstance().RemovePluginSubContainer(currentId);
201 PluginManager::GetInstance().RemovePluginParentContainer(currentId);
202 pluginSubContainer_->Destroy();
203 pluginSubContainer_.Reset();
204 }
205 auto pluginSubContainerId_ = PluginManager::GetInstance().GetPluginSubContainerId();
206 pluginSubContainer_ = AceType::MakeRefPtr<PluginSubContainer>(context, pluginSubContainerId_);
207 CHECK_NULL_VOID(pluginSubContainer_);
208
209 PluginManager::GetInstance().AddPluginSubContainer(pluginSubContainerId_, pluginSubContainer_);
210 PluginManager::GetInstance().AddPluginParentContainer(pluginSubContainerId_, parentcontainerId);
211 flutter::UIDartState::Current()->AddPluginParentContainer(pluginSubContainerId_, parentcontainerId);
212 pluginSubContainer_->Initialize();
213 pluginSubContainer_->SetPluginPattern(WeakClaim(this));
214 pluginSubContainer_->SetPluginNode(GetHost());
215 auto weak = WeakClaim(this);
216 auto pattern = weak.Upgrade();
217 auto host_ = pattern->GetHost();
218 CHECK_NULL_VOID(host_);
219 auto uiTaskExecutor = SingleTaskExecutor::Make(host_->GetContext()->GetTaskExecutor(), TaskExecutor::TaskType::UI);
220
221 int32_t instanceID = context->GetInstanceId();
222 uiTaskExecutor.PostTask([this, weak, instanceID] {
223 ContainerScope scope(instanceID);
224 auto pluginPattern = weak.Upgrade();
225 CHECK_NULL_VOID(pluginPattern);
226 auto pluginSubContainer = pluginPattern->GetPluginSubContainer();
227 RequestPluginInfo info = pluginPattern->GetPluginRequestInfo();
228 CHECK_NULL_VOID(pluginSubContainer);
229 auto packagePathStr = pluginPattern->GetPackagePath(weak, info);
230 pluginSubContainer_->RunPlugin(
231 packagePathStr, info.moduleName, info.source, info.moduleResPath, pluginPattern->GetData());
232 });
233 }
234
GetDrawDelegate()235 std::unique_ptr<DrawDelegate> PluginPattern::GetDrawDelegate()
236 {
237 auto drawDelegate = std::make_unique<DrawDelegate>();
238 drawDelegate->SetDrawRSFrameCallback(
239 [weak = WeakClaim(this)](std::shared_ptr<RSNode>& node, const Rect& /* dirty */) {
240 auto plugin = weak.Upgrade();
241 CHECK_NULL_VOID(plugin);
242 auto host = plugin->GetHost();
243 CHECK_NULL_VOID(host);
244 auto context = DynamicCast<NG::RosenRenderContext>(host->GetRenderContext());
245 CHECK_NULL_VOID(context);
246 auto rsNode = context->GetRSNode();
247 CHECK_NULL_VOID(rsNode);
248 if (node) {
249 node->SetBackgroundColor(Color::TRANSPARENT.GetValue());
250 }
251 rsNode->AddChild(node, -1);
252 host->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
253 });
254 return drawDelegate;
255 }
256
FireOnCompleteEvent() const257 void PluginPattern::FireOnCompleteEvent() const
258 {
259 LOGI("FireOnCompleteEvent");
260 auto host = GetHost();
261 CHECK_NULL_VOID(host);
262 auto eventHub = host->GetEventHub<PluginEventHub>();
263 CHECK_NULL_VOID(eventHub);
264 auto json = JsonUtil::Create(true);
265 eventHub->FireOnComplete(json->ToString());
266 }
267
FireOnErrorEvent(const std::string & code,const std::string & msg) const268 void PluginPattern::FireOnErrorEvent(const std::string& code, const std::string& msg) const
269 {
270 LOGI("FireOnErrorEvent code: %{public}s, msg: %{public}s", code.c_str(), msg.c_str());
271 auto host = GetHost();
272 CHECK_NULL_VOID(host);
273 auto eventHub = host->GetEventHub<PluginEventHub>();
274 CHECK_NULL_VOID(eventHub);
275 auto json = JsonUtil::Create(true);
276 json->Put("errcode", code.c_str());
277 json->Put("msg", msg.c_str());
278 eventHub->FireOnError(json->ToString());
279 }
280
OnActionEvent(const std::string & action) const281 void PluginPattern::OnActionEvent(const std::string& action) const
282 {
283 LOGI("OnActionEvent action: %{public}s", action.c_str());
284 auto eventAction = JsonUtil::ParseJsonString(action);
285 if (!eventAction->IsValid()) {
286 LOGE("get event action failed");
287 return;
288 }
289 auto actionType = eventAction->GetValue("action");
290 if (!actionType->IsValid()) {
291 LOGE("get event key failed");
292 return;
293 }
294
295 auto type = actionType->GetString();
296 if (type != "router" && type != "message") {
297 LOGE("undefined event type");
298 return;
299 }
300
301 CHECK_NULL_VOID_NOLOG(pluginManagerBridge_);
302 pluginManagerBridge_->OnActionEvent(action);
303 }
304
ISAllowUpdate() const305 bool PluginPattern::ISAllowUpdate() const
306 {
307 auto host = GetHost();
308 CHECK_NULL_RETURN(host, true);
309 auto property = host->GetLayoutProperty<PluginLayoutProperty>();
310 CHECK_NULL_RETURN(property, true);
311 auto pluginInfo = property->GetRequestPluginInfo();
312 CHECK_NULL_RETURN(property, true);
313 return pluginInfo->allowUpdate;
314 }
315
SplitString(const std::string & str,char tag,std::vector<std::string> & strList) const316 void PluginPattern::SplitString(const std::string& str, char tag, std::vector<std::string>& strList) const
317 {
318 std::string subStr;
319 for (size_t i = 0; i < str.length(); i++) {
320 if (tag == str[i]) {
321 if (!subStr.empty()) {
322 strList.push_back(subStr);
323 subStr.clear();
324 }
325 } else {
326 subStr.push_back(str[i]);
327 }
328 }
329 if (!subStr.empty()) {
330 strList.push_back(subStr);
331 }
332 }
333
GetPackagePath(const WeakPtr<PluginPattern> & weak,RequestPluginInfo & info) const334 std::string PluginPattern::GetPackagePath(const WeakPtr<PluginPattern>& weak, RequestPluginInfo& info) const
335 {
336 std::string packagePathStr;
337 size_t pos = info.pluginName.rfind(JS_EXT);
338 size_t pos_ets = info.pluginName.rfind(ETS_EXT);
339 if (pos_ets != std::string::npos && info.pluginName.substr(pos_ets) == ETS_EXT) {
340 info.pluginName = info.pluginName.substr(0, info.pluginName.length() - SIZE_OF_ETS_EXT);
341 info.pluginName = info.pluginName + JS_EXT;
342 }
343 if (info.pluginName.front() == '/' && pos != std::string::npos && info.pluginName.substr(pos) == JS_EXT) {
344 packagePathStr = GetPackagePathByAbsolutePath(weak, info);
345 } else {
346 packagePathStr = GetPackagePathByWant(weak, info);
347 }
348 return packagePathStr;
349 }
350
GetPackagePathByWant(const WeakPtr<PluginPattern> & weak,RequestPluginInfo & info) const351 std::string PluginPattern::GetPackagePathByWant(const WeakPtr<PluginPattern>& weak, RequestPluginInfo& info) const
352 {
353 std::string packagePathStr;
354 auto pluginPattern = weak.Upgrade();
355 CHECK_NULL_RETURN(pluginPattern, packagePathStr);
356 std::vector<std::string> strList;
357 pluginPattern->SplitString(info.bundleName, '/', strList);
358
359 std::vector<int32_t> userIds;
360 ErrCode errCode = GetActiveAccountIds(userIds);
361 if (errCode != ERR_OK) {
362 LOGE("Query Active OsAccountIds failed!");
363 pluginPattern->FireOnErrorEvent("1", "Query Active OsAccountIds failed!");
364 return packagePathStr;
365 }
366 GetModuleNameByWant(weak, info);
367 packagePathStr = GerPackagePathByBms(weak, info, strList, userIds);
368
369 return packagePathStr;
370 }
GetPackagePathByAbsolutePath(const WeakPtr<PluginPattern> & weak,RequestPluginInfo & info) const371 std::string PluginPattern::GetPackagePathByAbsolutePath(
372 const WeakPtr<PluginPattern>& weak, RequestPluginInfo& info) const
373 {
374 std::string packagePathStr;
375 auto pluginPattern = weak.Upgrade();
376 CHECK_NULL_RETURN_NOLOG(pluginPattern, packagePathStr);
377 std::string assets = "assets/js/";
378 size_t posAssets = info.pluginName.rfind(assets);
379 if (posAssets != std::string::npos) {
380 packagePathStr = info.pluginName.substr(0, posAssets);
381 size_t posModule = info.pluginName.find("/", posAssets + assets.size());
382 if (posModule != std::string::npos) {
383 info.moduleName =
384 info.pluginName.substr(posAssets + assets.size(), posModule - (posAssets + assets.size()));
385 info.source = info.pluginName.substr(posModule);
386 } else {
387 info.moduleName = "/";
388 info.source = info.pluginName.substr(posAssets + assets.size());
389 }
390 } else {
391 size_t pos = info.pluginName.rfind("/");
392 packagePathStr = info.pluginName.substr(0, pos + 1);
393 info.source = info.pluginName.substr(pos + 1);
394 info.moduleName = "/";
395 }
396 return packagePathStr;
397 }
398
GetModuleNameByWant(const WeakPtr<PluginPattern> & weak,RequestPluginInfo & info) const399 void PluginPattern::GetModuleNameByWant(const WeakPtr<PluginPattern>& weak, RequestPluginInfo& info) const
400 {
401 auto pluginPattern = weak.Upgrade();
402 CHECK_NULL_VOID(pluginPattern);
403 std::vector<std::string> strList;
404 pluginPattern->SplitString(info.pluginName, '&', strList);
405 if (strList.empty()) {
406 LOGE("Template source is empty.");
407 pluginPattern->FireOnErrorEvent("1", "Template source is empty.");
408 return;
409 }
410 if (strList.size() == 1) {
411 if (info.pluginName.rfind(JS_EXT) != std::string::npos) {
412 info.moduleName = "default";
413 info.source = info.pluginName;
414 } else {
415 info.moduleName = info.pluginName;
416 }
417 } else {
418 auto pos = strList[0].rfind(JS_EXT);
419 size_t pos_ets = info.pluginName.rfind(ETS_EXT);
420 if (pos_ets != std::string::npos && info.pluginName.substr(pos_ets) == ETS_EXT) {
421 info.pluginName = info.pluginName.substr(0, info.pluginName.length() - SIZE_OF_ETS_EXT);
422 info.pluginName = info.pluginName + JS_EXT;
423 }
424 if (pos != std::string::npos && (strList[0].substr(pos) == JS_EXT)) {
425 info.source = strList[1];
426 }
427 info.moduleName = strList[0];
428 }
429 }
430
GerPackagePathByBms(const WeakPtr<PluginPattern> & weak,RequestPluginInfo & info,const std::vector<std::string> & strList,const std::vector<int32_t> & userIds) const431 std::string PluginPattern::GerPackagePathByBms(const WeakPtr<PluginPattern>& weak, RequestPluginInfo& info,
432 const std::vector<std::string>& strList, const std::vector<int32_t>& userIds) const
433 {
434 std::string packagePathStr;
435 auto pluginPattern = weak.Upgrade();
436 CHECK_NULL_RETURN(pluginPattern, packagePathStr);
437 auto bms = PluginComponentManager::GetInstance()->GetBundleManager();
438 if (!bms) {
439 LOGE("Bms bundleManager is nullptr.");
440 pluginPattern->FireOnErrorEvent("1", "Bms bundleManager is nullptr.");
441 return packagePathStr;
442 }
443
444 if (strList.empty()) {
445 LOGE("App bundleName or abilityName is empty.");
446 pluginPattern->FireOnErrorEvent("1", "App bundleName is empty.");
447 return packagePathStr;
448 }
449 if (strList.size() == 1) {
450 AppExecFwk::BundleInfo bundleInfo;
451 bool ret = bms->GetBundleInfo(strList[0], AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, bundleInfo,
452 userIds.size() > 0 ? userIds[0] : AppExecFwk::Constants::UNSPECIFIED_USERID);
453 if (!ret) {
454 LOGE("Bms get bundleName failed!");
455 pluginPattern->FireOnErrorEvent("1", "Bms get bundleName failed!");
456 return packagePathStr;
457 }
458 if (bundleInfo.moduleResPaths.size() == 1) {
459 info.moduleResPath = bundleInfo.moduleResPaths[0];
460 } else {
461 LOGE("Bms moduleResPaths is empty.");
462 pluginPattern->FireOnErrorEvent("1", "Bms moduleResPaths is empty.");
463 return packagePathStr;
464 }
465 packagePathStr = bundleInfo.applicationInfo.entryDir + "/";
466 } else {
467 AAFwk::Want want;
468 AppExecFwk::AbilityInfo abilityInfo;
469 AppExecFwk::ElementName element("", strList[0], strList[1]);
470 want.SetElement(element);
471 bool ret = bms->QueryAbilityInfo(want, AppExecFwk::AbilityInfoFlag::GET_ABILITY_INFO_DEFAULT,
472 userIds.size() > 0 ? userIds[0] : AppExecFwk::Constants::UNSPECIFIED_USERID, abilityInfo);
473 if (!ret) {
474 LOGE("Bms get abilityInfo failed!");
475 pluginPattern->FireOnErrorEvent("1", "Bms get bundleName failed!");
476 return packagePathStr;
477 }
478 packagePathStr = abilityInfo.applicationInfo.codePath + "/" + abilityInfo.package + "/";
479 info.moduleResPath = abilityInfo.resourcePath;
480 }
481 return packagePathStr;
482 }
483
GetPluginSubContainer() const484 const RefPtr<PluginSubContainer>& PluginPattern::GetPluginSubContainer() const
485 {
486 return pluginSubContainer_;
487 };
488 } // namespace OHOS::Ace::NG
489