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 <utility>
26
27 #include "camera_log.h"
28
29 namespace OHOS {
30 namespace CameraStandard {
31 using namespace std;
32
33 enum AsyncLoadingState : int32_t { NONE, PREPARE, LOADING };
34
35 static const uint32_t HANDLE_MASK = 0xffffffff;
36 static mutex g_libMutex;
37 static map<const string, shared_ptr<Dynamiclib>> g_dynamiclibMap = {};
38 static map<const string, weak_ptr<Dynamiclib>> g_weakDynamiclibMap = {};
39
40 static mutex g_asyncLoadingMutex;
41 static condition_variable g_asyncLiblockCondition;
42 static AsyncLoadingState g_isAsyncLoading = AsyncLoadingState::NONE;
43
Dynamiclib(const string & libName)44 Dynamiclib::Dynamiclib(const string& libName) : libName_(libName)
45 {
46 CAMERA_SYNC_TRACE;
47 MEDIA_INFO_LOG("Dynamiclib::Dynamiclib dlopen %{public}s", libName_.c_str());
48 libHandle_ = dlopen(libName_.c_str(), RTLD_NOW);
49 CHECK_ERROR_RETURN_LOG(
50 libHandle_ == nullptr, "Dynamiclib::Dynamiclib dlopen name:%{public}s return null", libName_.c_str());
51 MEDIA_INFO_LOG("Dynamiclib::Dynamiclib dlopen %{public}s success handle:%{public}u", libName_.c_str(),
52 static_cast<uint32_t>(HANDLE_MASK & reinterpret_cast<uintptr_t>(libHandle_)));
53 }
54
~Dynamiclib()55 Dynamiclib::~Dynamiclib()
56 {
57 CAMERA_SYNC_TRACE;
58 if (libHandle_ != nullptr) {
59 int ret = dlclose(libHandle_);
60 MEDIA_INFO_LOG("Dynamiclib::~Dynamiclib dlclose name:%{public}s handle:%{public}u result:%{public}d",
61 libName_.c_str(), static_cast<uint32_t>(HANDLE_MASK & reinterpret_cast<uintptr_t>(libHandle_)), ret);
62 libHandle_ = nullptr;
63 }
64 }
65
IsLoaded()66 bool Dynamiclib::IsLoaded()
67 {
68 return libHandle_ != nullptr;
69 }
70
GetFunction(const string & functionName)71 void* Dynamiclib::GetFunction(const string& functionName)
72 {
73 CAMERA_SYNC_TRACE;
74 CHECK_ERROR_RETURN_RET_LOG(
75 !IsLoaded(), nullptr, "Dynamiclib::GetFunction fail libname:%{public}s not loaded", libName_.c_str());
76
77 void* handle = dlsym(libHandle_, functionName.c_str());
78 CHECK_ERROR_RETURN_RET_LOG(
79 handle == nullptr, nullptr, "Dynamiclib::GetFunction fail function:%{public}s not find", functionName.c_str());
80 MEDIA_INFO_LOG("Dynamiclib::GetFunction %{public}s success", functionName.c_str());
81 return handle;
82 }
GetDynamiclibNoLock(const string & libName)83 shared_ptr<Dynamiclib> CameraDynamicLoader::GetDynamiclibNoLock(const string& libName)
84 {
85 auto loadedIterator = g_dynamiclibMap.find(libName);
86 if (loadedIterator != g_dynamiclibMap.end()) {
87 MEDIA_INFO_LOG("Dynamiclib::GetDynamiclib %{public}s by cache", libName.c_str());
88 return loadedIterator->second;
89 }
90
91 shared_ptr<Dynamiclib> dynamiclib = nullptr;
92 auto loadedWeakIterator = g_weakDynamiclibMap.find(libName);
93 if (loadedWeakIterator != g_weakDynamiclibMap.end()) {
94 dynamiclib = loadedWeakIterator->second.lock();
95 }
96 if (dynamiclib != nullptr) {
97 MEDIA_INFO_LOG("Dynamiclib::GetDynamiclib %{public}s by weak cache", libName.c_str());
98 } else {
99 dynamiclib = make_shared<Dynamiclib>(libName);
100 }
101 CHECK_ERROR_RETURN_RET_LOG(
102 !dynamiclib->IsLoaded(), nullptr, "CameraDynamicLoader::GetDynamiclib name:%{public}s fail", libName.c_str());
103 g_dynamiclibMap.emplace(pair<const string, shared_ptr<Dynamiclib>>(libName, dynamiclib));
104 MEDIA_INFO_LOG("Dynamiclib::GetDynamiclib %{public}s load first", libName.c_str());
105 return dynamiclib;
106 }
107
GetDynamiclib(const string & libName)108 shared_ptr<Dynamiclib> CameraDynamicLoader::GetDynamiclib(const string& libName)
109 {
110 CAMERA_SYNC_TRACE;
111 lock_guard<mutex> lock(g_libMutex);
112 return GetDynamiclibNoLock(libName);
113 }
114
LoadDynamiclibAsync(const std::string & libName)115 void CameraDynamicLoader::LoadDynamiclibAsync(const std::string& libName)
116 {
117 CAMERA_SYNC_TRACE;
118 unique_lock<mutex> asyncLock(g_asyncLoadingMutex);
119 MEDIA_INFO_LOG("CameraDynamicLoader::LoadDynamiclibAsync %{public}s", libName.c_str());
120 if (g_isAsyncLoading != AsyncLoadingState::NONE) {
121 MEDIA_INFO_LOG("CameraDynamicLoader::LoadDynamiclibAsync %{public}s is loading", libName.c_str());
122 return;
123 }
124 g_isAsyncLoading = AsyncLoadingState::PREPARE;
125 thread asyncThread = thread([libName]() {
126 unique_lock<mutex> lock(g_libMutex);
127 {
128 unique_lock<mutex> asyncLock(g_asyncLoadingMutex);
129 g_isAsyncLoading = AsyncLoadingState::LOADING;
130 g_asyncLiblockCondition.notify_all();
131 }
132 GetDynamiclibNoLock(libName);
133 {
134 unique_lock<mutex> asyncLock(g_asyncLoadingMutex);
135 g_isAsyncLoading = AsyncLoadingState::NONE;
136 }
137 MEDIA_INFO_LOG("CameraDynamicLoader::LoadDynamiclibAsync %{public}s finish", libName.c_str());
138 });
139 asyncThread.detach();
140 g_asyncLiblockCondition.wait(asyncLock, []() { return g_isAsyncLoading != AsyncLoadingState::PREPARE; });
141 }
142
FreeDynamiclib(const string & libName)143 void CameraDynamicLoader::FreeDynamiclib(const string& libName)
144 {
145 CAMERA_SYNC_TRACE;
146 lock_guard<mutex> lock(g_libMutex);
147 auto loadedIterator = g_dynamiclibMap.find(libName);
148 CHECK_ERROR_RETURN(loadedIterator == g_dynamiclibMap.end());
149 MEDIA_INFO_LOG("Dynamiclib::FreeDynamiclib %{public}s lib use count is:%{public}d", libName.c_str(),
150 static_cast<int32_t>(loadedIterator->second.use_count()));
151
152 weak_ptr<Dynamiclib> weaklib = loadedIterator->second;
153 g_weakDynamiclibMap[libName] = weaklib;
154 g_dynamiclibMap.erase(loadedIterator);
155 }
156 } // namespace CameraStandard
157 } // namespace OHOS