• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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