1 /*
2 * Copyright (c) 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 "camera_dynamic_loader.h"
17
18 #include <cstddef>
19 #include <cstdint>
20 #include <dlfcn.h>
21 #include <map>
22 #include <memory>
23 #include <mutex>
24 #include <thread>
25 #include <unordered_set>
26 #include <utility>
27
28 #include "camera_log.h"
29 #include "common_timer_errors.h"
30 #include "camera_simple_timer.h"
31
32 namespace OHOS {
33 namespace CameraStandard {
34 using namespace std;
35 namespace {
36 enum AsyncLoadingState : int32_t { NONE, PREPARE, LOADING };
37 enum DynamiclibState : int32_t { UNLOAD, LOADED };
38
39 static const uint32_t HANDLE_MASK = 0xff0000ff;
40
41 static mutex g_libStateMutex;
42 static condition_variable g_libStateCondition;
43 static map<const string, DynamiclibState> g_dynamiclibStateMap = {};
44
45 static mutex g_libMutex;
46 static map<const string, shared_ptr<Dynamiclib>> g_dynamiclibMap = {};
47 static map<const string, weak_ptr<Dynamiclib>> g_weakDynamiclibMap = {};
48
49 static mutex g_delayedCloseTimerMutex;
50 static map<const string, shared_ptr<SimpleTimer>> g_delayedCloseTimerMap = {};
51
52 static mutex g_asyncLoadingMutex;
53 static condition_variable g_asyncLiblockCondition;
54 static AsyncLoadingState g_isAsyncLoading = AsyncLoadingState::NONE;
55
GetDelayedCloseTimer(const string & libName)56 shared_ptr<SimpleTimer> GetDelayedCloseTimer(const string& libName)
57 {
58 lock_guard<mutex> lock(g_delayedCloseTimerMutex);
59 auto it = g_delayedCloseTimerMap.find(libName);
60 CHECK_RETURN_RET(it == g_delayedCloseTimerMap.end(), nullptr);
61 return it->second;
62 }
63
SetDelayedCloseTimer(const string & libName,shared_ptr<SimpleTimer> timer)64 void SetDelayedCloseTimer(const string& libName, shared_ptr<SimpleTimer> timer)
65 {
66 lock_guard<mutex> lock(g_delayedCloseTimerMutex);
67 g_delayedCloseTimerMap[libName] = timer;
68 }
69
RemoveDelayedCloseTimer(const string & libName)70 void RemoveDelayedCloseTimer(const string& libName)
71 {
72 lock_guard<mutex> lock(g_delayedCloseTimerMutex);
73 auto it = g_delayedCloseTimerMap.find(libName);
74 CHECK_RETURN(it == g_delayedCloseTimerMap.end());
75 g_delayedCloseTimerMap.erase(it);
76 }
77
UpdateDynamiclibState(const string & libName,DynamiclibState state)78 void UpdateDynamiclibState(const string& libName, DynamiclibState state)
79 {
80 lock_guard<mutex> lock(g_libStateMutex);
81 auto it = g_dynamiclibStateMap.find(libName);
82 if (it == g_dynamiclibStateMap.end()) {
83 g_dynamiclibStateMap.insert({ libName, state });
84 } else {
85 it->second = state;
86 }
87 g_libStateCondition.notify_all();
88 }
89
WaitDynamiclibState(const string & libName,DynamiclibState targetState)90 void WaitDynamiclibState(const string& libName, DynamiclibState targetState)
91 {
92 static const int32_t WAIT_TIME_OUT = 5000;
93 unique_lock<mutex> lock(g_libStateMutex);
94 auto it = g_dynamiclibStateMap.find(libName);
95 if (it == g_dynamiclibStateMap.end()) {
96 return;
97 }
98 g_libStateCondition.wait_for(lock, chrono::milliseconds(WAIT_TIME_OUT), [&libName, targetState]() {
99 auto it = g_dynamiclibStateMap.find(libName);
100 return it == g_dynamiclibStateMap.end() || it->second == targetState;
101 });
102 }
103 } // namespace
104
Dynamiclib(const string & libName)105 Dynamiclib::Dynamiclib(const string& libName) : libName_(libName)
106 {
107 CAMERA_SYNC_TRACE;
108 WaitDynamiclibState(libName, UNLOAD);
109 MEDIA_INFO_LOG("Dynamiclib::Dynamiclib dlopen %{public}s", libName_.c_str());
110 libHandle_ = dlopen(libName_.c_str(), RTLD_NOW);
111 CHECK_RETURN_ELOG(
112 libHandle_ == nullptr, "Dynamiclib::Dynamiclib dlopen name:%{public}s return null", libName_.c_str());
113 MEDIA_INFO_LOG("Dynamiclib::Dynamiclib dlopen %{public}s success handle:%{public}u", libName_.c_str(),
114 static_cast<uint32_t>(HANDLE_MASK & reinterpret_cast<uintptr_t>(libHandle_)));
115 UpdateDynamiclibState(libName, LOADED);
116 }
117
~Dynamiclib()118 Dynamiclib::~Dynamiclib()
119 {
120 CAMERA_SYNC_TRACE;
121 CHECK_RETURN(libHandle_ == nullptr);
122 int ret = dlclose(libHandle_);
123 MEDIA_INFO_LOG("Dynamiclib::~Dynamiclib dlclose name:%{public}s handle:%{public}u result:%{public}d",
124 libName_.c_str(), static_cast<uint32_t>(HANDLE_MASK & reinterpret_cast<uintptr_t>(libHandle_)), ret);
125 libHandle_ = nullptr;
126 UpdateDynamiclibState(libName_, UNLOAD);
127 }
128
IsLoaded()129 bool Dynamiclib::IsLoaded()
130 {
131 return libHandle_ != nullptr;
132 }
133
GetFunction(const string & functionName)134 void* Dynamiclib::GetFunction(const string& functionName)
135 {
136 CAMERA_SYNC_TRACE;
137 CHECK_RETURN_RET_ELOG(
138 !IsLoaded(), nullptr, "Dynamiclib::GetFunction fail libname:%{public}s not loaded", libName_.c_str());
139
140 void* handle = dlsym(libHandle_, functionName.c_str());
141 CHECK_RETURN_RET_ELOG(
142 handle == nullptr, nullptr, "Dynamiclib::GetFunction fail function:%{public}s not find", functionName.c_str());
143 MEDIA_INFO_LOG("Dynamiclib::GetFunction %{public}s success", functionName.c_str());
144 return handle;
145 }
GetDynamiclibNoLock(const string & libName)146 shared_ptr<Dynamiclib> CameraDynamicLoader::GetDynamiclibNoLock(const string& libName)
147 {
148 auto loadedIterator = g_dynamiclibMap.find(libName);
149 if (loadedIterator != g_dynamiclibMap.end()) {
150 MEDIA_INFO_LOG("Dynamiclib::GetDynamiclib %{public}s by cache", libName.c_str());
151 return loadedIterator->second;
152 }
153
154 shared_ptr<Dynamiclib> dynamiclib = nullptr;
155 auto loadedWeakIterator = g_weakDynamiclibMap.find(libName);
156 if (loadedWeakIterator != g_weakDynamiclibMap.end()) {
157 dynamiclib = loadedWeakIterator->second.lock();
158 }
159 if (dynamiclib != nullptr) {
160 MEDIA_INFO_LOG("Dynamiclib::GetDynamiclib %{public}s by weak cache", libName.c_str());
161 } else {
162 dynamiclib = make_shared<Dynamiclib>(libName);
163 }
164 CHECK_RETURN_RET_ELOG(
165 !dynamiclib->IsLoaded(), nullptr, "CameraDynamicLoader::GetDynamiclib name:%{public}s fail", libName.c_str());
166 g_dynamiclibMap.emplace(pair<const string, shared_ptr<Dynamiclib>>(libName, dynamiclib));
167 MEDIA_INFO_LOG("Dynamiclib::GetDynamiclib %{public}s load first", libName.c_str());
168 return dynamiclib;
169 }
170
GetDynamiclib(const string & libName)171 shared_ptr<Dynamiclib> CameraDynamicLoader::GetDynamiclib(const string& libName)
172 {
173 CAMERA_SYNC_TRACE;
174 lock_guard<mutex> lock(g_libMutex);
175 return GetDynamiclibNoLock(libName);
176 }
177
LoadDynamiclibAsync(const std::string & libName)178 void CameraDynamicLoader::LoadDynamiclibAsync(const std::string& libName)
179 {
180 CAMERA_SYNC_TRACE;
181 unique_lock<mutex> asyncLock(g_asyncLoadingMutex);
182 MEDIA_INFO_LOG("CameraDynamicLoader::LoadDynamiclibAsync %{public}s", libName.c_str());
183 if (g_isAsyncLoading != AsyncLoadingState::NONE) {
184 MEDIA_INFO_LOG("CameraDynamicLoader::LoadDynamiclibAsync %{public}s is loading", libName.c_str());
185 return;
186 }
187 g_isAsyncLoading = AsyncLoadingState::PREPARE;
188 thread asyncThread = thread([libName]() {
189 CancelFreeDynamicLibDelayed(libName);
190 unique_lock<mutex> lock(g_libMutex);
191 {
192 unique_lock<mutex> asyncLock(g_asyncLoadingMutex);
193 g_isAsyncLoading = AsyncLoadingState::LOADING;
194 g_asyncLiblockCondition.notify_all();
195 }
196 GetDynamiclibNoLock(libName);
197 {
198 unique_lock<mutex> asyncLock(g_asyncLoadingMutex);
199 g_isAsyncLoading = AsyncLoadingState::NONE;
200 }
201 MEDIA_INFO_LOG("CameraDynamicLoader::LoadDynamiclibAsync %{public}s finish", libName.c_str());
202 });
203 asyncThread.detach();
204 g_asyncLiblockCondition.wait(asyncLock, []() { return g_isAsyncLoading != AsyncLoadingState::PREPARE; });
205 }
206
FreeDynamiclibNoLock(const string & libName)207 void CameraDynamicLoader::FreeDynamiclibNoLock(const string& libName)
208 {
209 CAMERA_SYNC_TRACE;
210 auto loadedIterator = g_dynamiclibMap.find(libName);
211 CHECK_RETURN(loadedIterator == g_dynamiclibMap.end());
212 MEDIA_INFO_LOG("Dynamiclib::FreeDynamiclib %{public}s lib use count is:%{public}d", libName.c_str(),
213 static_cast<int32_t>(loadedIterator->second.use_count()));
214
215 weak_ptr<Dynamiclib> weaklib = loadedIterator->second;
216 g_weakDynamiclibMap[libName] = weaklib;
217 g_dynamiclibMap.erase(loadedIterator);
218 }
219
CancelFreeDynamicLibDelayed(const std::string & libName)220 void CameraDynamicLoader::CancelFreeDynamicLibDelayed(const std::string& libName)
221 {
222 auto closeTimer = GetDelayedCloseTimer(libName);
223 CHECK_RETURN(!closeTimer);
224 // Cancel old task
225 bool isCancelSuccess = closeTimer->CancelTask();
226 MEDIA_INFO_LOG("CameraDynamicLoader::CancelFreeDynamicLibDelayed %{public}s CancelTask success:%{public}d",
227 libName.c_str(), isCancelSuccess);
228 RemoveDelayedCloseTimer(libName);
229 }
230
FreeDynamicLibDelayed(const std::string & libName,uint32_t delayMs)231 void CameraDynamicLoader::FreeDynamicLibDelayed(const std::string& libName, uint32_t delayMs)
232 {
233 MEDIA_INFO_LOG(
234 "CameraDynamicLoader::FreeDynamicLibDelayed %{public}s delayMs:%{public}d", libName.c_str(), delayMs);
235 CancelFreeDynamicLibDelayed(libName);
236 shared_ptr<SimpleTimer> closeTimer = make_shared<SimpleTimer>([&, libName]() {
237 lock_guard<mutex> lock(g_libMutex);
238 FreeDynamiclibNoLock(libName);
239 });
240 bool isStartSuccess = closeTimer->StartTask(delayMs);
241
242 SetDelayedCloseTimer(libName, closeTimer);
243 MEDIA_INFO_LOG("CameraDynamicLoader::FreeDynamicLibDelayed %{public}s StartTask success:%{public}d",
244 libName.c_str(), isStartSuccess);
245 }
246 } // namespace CameraStandard
247 } // namespace OHOS
248