2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali/internal/addons/linux/addon-manager-impl-linux.h>
20 #include <dali/devel-api/adaptor-framework/environment-variable.h>
21 #include <dali/internal/system/common/environment-variables.h>
24 #include <dali/integration-api/debug.h>
37 AddOnManagerLinux::AddOnManagerLinux() = default;
39 AddOnManagerLinux::~AddOnManagerLinux() = default;
41 void AddOnManagerLinux::RegisterAddOnDispatchTable( const AddOnDispatchTable* dispatchTable )
43 mAddOnNames.emplace_back(dispatchTable->name);
44 mAddOnCache.emplace_back();
45 mAddOnCache.back().GetGlobalProc = dispatchTable->GetGlobalProc;
46 mAddOnCache.back().GetInstanceProc = dispatchTable->GetInstanceProc;
47 mAddOnCache.back().GetAddOnInfo = dispatchTable->GetAddOnInfo;
49 auto& callbacks = mAddOnCache.back().lifecycleCallbacks;
50 auto initEvent = [&callbacks](uint32_t event, void(*fn)() ) {
51 callbacks[event].function = fn;
52 callbacks[event].initialized = true;
55 initEvent( LifecycleCallback::EVENT_START, dispatchTable->OnStart );
56 initEvent( LifecycleCallback::EVENT_STOP, dispatchTable->OnStop );
57 initEvent( LifecycleCallback::EVENT_PAUSE, dispatchTable->OnPause );
58 initEvent( LifecycleCallback::EVENT_RESUME, dispatchTable->OnResume );
61 std::vector<std::string> AddOnManagerLinux::EnumerateAddOns()
63 if( mAddOnNames.empty() )
65 // AddOn libs must be separated with ':' character
66 const char *addonsLibs = Dali::EnvironmentVariable::GetEnvironmentVariable( DALI_ENV_ADDONS_LIBS );
72 // Get the path where addon libs are stored
73 const char *addonsPath = Dali::EnvironmentVariable::GetEnvironmentVariable( DALI_ENV_ADDONS_PATH );
74 std::string addonsPathStr(addonsPath ? addonsPath : "/usr/lib");
77 std::string addonLibsStr(addonsLibs);
78 std::vector<std::string> results;
79 results.emplace_back();
81 std::find_if(addonLibsStr.begin(), addonLibsStr.end(), [&results](char &c)
85 results.emplace_back();
94 const char *EXTENSION_PATH = (addonsPath) ? addonsPath : "/usr/lib";
96 for (auto &name : results)
98 std::string fullPath(EXTENSION_PATH);
102 // open lib, look for essential symbols. The libary is opened with RTLD_DEEPBIND flag
103 // to make sure the local symbol table is going to be used during lookup first.
104 auto* handle = dlopen(fullPath.c_str(), RTLD_DEEPBIND|RTLD_LAZY);
107 auto& cacheEntry = mAddOnCache.back();
109 cacheEntry.GetAddOnInfo(info);
110 cacheEntry.info = info;
111 cacheEntry.addOnLib = fullPath;
112 cacheEntry.libHandle = handle;
113 cacheEntry.opened = false;
117 DALI_LOG_ERROR("Can't open library: %s, error: %s\n", fullPath.c_str(), dlerror());
124 bool AddOnManagerLinux::GetAddOnInfo(const std::string& name, AddOnInfo& info )
126 if( mAddOnNames.empty() )
131 if( mAddOnNames.empty() )
136 auto iter = std::find_if( mAddOnCache.begin(), mAddOnCache.end(), [name]( AddOnCacheEntry& item )
138 return (item.info.name == name);
141 if (iter == mAddOnCache.end())
150 std::vector<Dali::AddOnLibrary> AddOnManagerLinux::LoadAddOns( const std::vector<std::string>& addonNames )
152 std::vector<AddOnLibrary> retval{};
153 retval.resize( addonNames.size() );
154 std::fill( retval.begin(), retval.end(), nullptr );
156 if( mAddOnCache.empty() )
159 if(mAddOnCache.empty())
167 for( const auto& name : addonNames )
171 auto iter = std::find_if( mAddOnCache.begin(), mAddOnCache.end(), [&index, name]( AddOnCacheEntry& item )
174 return (item.info.name == name);
177 if(iter == mAddOnCache.end())
182 if(!iter->opened && iter->libHandle)
184 // Open library, pull symbols and keep the handle
189 // Store cache index of extension for indirect calling
190 // Stored number in this implementation is always +1 (0 is nullptr, unsuccessful)
191 retval[nameIndex-1] = reinterpret_cast<void*>( index );
197 void* AddOnManagerLinux::GetGlobalProc( const Dali::AddOnLibrary& addonHandle, const char* procName )
204 auto index = (intptr_t(addonHandle));
205 const auto& entry = mAddOnCache[ index-1 ];
207 if(entry.opened && entry.libHandle )
209 // First call into dispatch table
210 auto retval = entry.GetGlobalProc( procName );
214 retval = dlsym( entry.libHandle, procName );
220 DALI_LOG_ERROR("AddOn: GetGlobalProc() library failed!\n");
225 void* AddOnManagerLinux::GetInstanceProc( const Dali::AddOnLibrary& addonHandle, const char* procName )
232 auto index = (intptr_t(addonHandle));
233 const auto& entry = mAddOnCache[ index-1 ];
234 if(entry.opened && entry.libHandle )
236 // First call into dispatch table
237 auto retval = entry.GetInstanceProc( procName );
241 retval = dlsym( entry.libHandle, procName );
248 void AddOnManagerLinux::Pause()
250 InvokeLifecycleFunction( LifecycleCallback::EVENT_PAUSE );
253 void AddOnManagerLinux::Resume()
255 InvokeLifecycleFunction( LifecycleCallback::EVENT_RESUME );
258 void AddOnManagerLinux::Start()
260 InvokeLifecycleFunction( LifecycleCallback::EVENT_START );
263 void AddOnManagerLinux::Stop()
265 InvokeLifecycleFunction( LifecycleCallback::EVENT_STOP );
268 void AddOnManagerLinux::InvokeLifecycleFunction( uint32_t lifecycleEvent )
270 for( auto& entry : mAddOnCache )
272 auto& callback = entry.lifecycleCallbacks[lifecycleEvent];
274 // If AddOn didn't auto-register try to pull symbols
275 // directly out of the addon
276 if(!callback.initialized)
278 callback.function = reinterpret_cast<decltype(callback.function)>(entry.GetGlobalProc(callback.functionName.c_str()));
279 callback.initialized = true;
281 if(callback.function)
288 } // namespace Internal