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