1 /*
2 * Copyright (c) 2025 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 #ifndef COMPONENT_MANAGER_H
17 #define COMPONENT_MANAGER_H
18
19 #include <memory>
20 #include <dlfcn.h>
21 #include <nocopyable.h>
22
23 #include "define_multimodal.h"
24 #include "i_context.h"
25
26 #undef MMI_LOG_DOMAIN
27 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
28 #undef MMI_LOG_TAG
29 #define MMI_LOG_TAG "ComponentManager"
30
31 namespace OHOS {
32 namespace MMI {
33
34 // Loading、unloading and bookkeeping of modules.
35 class ComponentManager final {
36 private:
37 template<typename IComponent>
38 using CreateComponent = IComponent* (*)(IContext *context);
39
40 template<typename IComponent>
41 using DestroyComponent = void (*)(IComponent *);
42
43 public:
44 template<typename IComponent>
45 class Component final {
46 public:
47 Component(IContext *context, void *handle);
48 Component(Component &&other);
49 ~Component();
50 DISALLOW_COPY(Component);
51
52 Component<IComponent>& operator=(Component<IComponent> &&other);
53 void operator()(IComponent *instance);
54 IComponent* GetInstance();
55
56 private:
57 void DeleteInstance(IComponent *instance);
58 void Unload();
59
60 IContext *context_ { nullptr };
61 void *handle_ { nullptr };
62 IComponent *instance_ { nullptr };
63 };
64
65 ComponentManager() = default;
66 ~ComponentManager() = default;
67 DISALLOW_COPY_AND_MOVE(ComponentManager);
68
69 template<typename IComponent>
70 static std::unique_ptr<IComponent, Component<IComponent>> LoadLibrary(IContext *context, const char *libPath);
71 };
72
73 template<typename IComponent>
Component(IContext * context,void * handle)74 ComponentManager::Component<IComponent>::Component(IContext *context, void *handle)
75 : context_(context), handle_(handle)
76 {}
77
78 template<typename IComponent>
~Component()79 ComponentManager::Component<IComponent>::~Component()
80 {
81 Unload();
82 }
83
84 template<typename IComponent>
Component(ComponentManager::Component<IComponent> && other)85 ComponentManager::Component<IComponent>::Component(ComponentManager::Component<IComponent> &&other)
86 : context_(other.context_), handle_(other.handle_), instance_(other.instance_)
87 {
88 other.context_ = nullptr;
89 other.handle_ = nullptr;
90 other.instance_ = nullptr;
91 }
92
93 template<typename IComponent>
94 ComponentManager::Component<IComponent>& ComponentManager::Component<IComponent>::operator=(
95 Component<IComponent> &&other)
96 {
97 if (&other == this) {
98 return *this;
99 }
100 Unload();
101 context_ = other.context_;
102 handle_ = other.handle_;
103 instance_ = other.instance_;
104 other.context_ = nullptr;
105 other.handle_ = nullptr;
106 other.instance_ = nullptr;
107 return *this;
108 }
109
110 template<typename IComponent>
operator()111 void ComponentManager::Component<IComponent>::operator()(IComponent *instance)
112 {
113 DeleteInstance(instance);
114 }
115
116 template<typename IComponent>
GetInstance()117 IComponent* ComponentManager::Component<IComponent>::GetInstance()
118 {
119 if (instance_ != nullptr) {
120 return instance_;
121 }
122 ::dlerror();
123 CreateComponent<IComponent> create =
124 reinterpret_cast<CreateComponent<IComponent>>(::dlsym(handle_, "CreateInstance"));
125 if (auto err = ::dlerror(); err != nullptr) {
126 MMI_HILOGE("dlsym('CreateInstance') fail: %{public}s", err);
127 return nullptr;
128 }
129 instance_ = create(context_);
130 return instance_;
131 }
132
133 template<typename IComponent>
DeleteInstance(IComponent * instance)134 void ComponentManager::Component<IComponent>::DeleteInstance(IComponent *instance)
135 {
136 if ((handle_ == nullptr) || (instance_ == nullptr) || (instance_ != instance)) {
137 return;
138 }
139 ::dlerror();
140 DestroyComponent<IComponent> destroy =
141 reinterpret_cast<DestroyComponent<IComponent>>(::dlsym(handle_, "DestroyInstance"));
142 if (auto err = ::dlerror(); err != nullptr) {
143 MMI_HILOGE("dlsym('DestroyInstance') fail: %{public}s", err);
144 return;
145 }
146 destroy(instance_);
147 instance_ = nullptr;
148 }
149
150 template<typename IComponent>
Unload()151 void ComponentManager::Component<IComponent>::Unload()
152 {
153 if (handle_ != nullptr) {
154 DeleteInstance(instance_);
155 if (::dlclose(handle_) != RET_OK) {
156 MMI_HILOGE("dlclose fail: %{public}s", ::dlerror());
157 }
158 handle_ = nullptr;
159 }
160 }
161
162 template<typename IComponent>
LoadLibrary(IContext * context,const char * libPath)163 std::unique_ptr<IComponent, ComponentManager::Component<IComponent>> ComponentManager::LoadLibrary(
164 IContext *context, const char *libPath)
165 {
166 if (libPath == nullptr) {
167 MMI_HILOGE("libPath is null");
168 return { nullptr, ComponentManager::Component<IComponent>(nullptr, nullptr) };
169 }
170 void *handle = ::dlopen(libPath, RTLD_NOW);
171 if (handle == nullptr) {
172 if (auto err = ::dlerror(); err != nullptr) {
173 MMI_HILOGE("dlopen fail for %{public}s: %{public}s", libPath, err);
174 } else {
175 MMI_HILOGE("dlopen fail for %{public}s", libPath);
176 }
177 return { nullptr, ComponentManager::Component<IComponent>(nullptr, nullptr) };
178 }
179 Component<IComponent> plugin(context, handle);
180 return { plugin.GetInstance(), std::move(plugin) };
181 }
182 } // namespace MMI
183 } // namespace OHOS
184 #endif // COMPONENT_MANAGER_H
185