2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "DllLoaderContainer.h"
14 #include "Win32DllLoader.h"
17 #include "filesystem/File.h"
18 #include "utils/StringUtils.h"
19 #include "utils/URIUtils.h"
20 #include "utils/log.h"
22 #if defined(TARGET_WINDOWS)
23 #define ENV_PARTIAL_PATH \
24 "special://xbmcbin/;" \
25 "special://xbmcbin/system/;" \
26 "special://xbmcbin/system/python/;" \
28 "special://xbmc/system/;" \
29 "special://xbmc/system/python/"
31 #define ENV_PARTIAL_PATH \
32 "special://xbmcbin/system/;" \
33 "special://xbmcbin/system/players/mplayer/;" \
34 "special://xbmcbin/system/players/VideoPlayer/;" \
35 "special://xbmcbin/system/players/paplayer/;" \
36 "special://xbmcbin/system/python/;" \
37 "special://xbmc/system/;" \
38 "special://xbmc/system/players/mplayer/;" \
39 "special://xbmc/system/players/VideoPlayer/;" \
40 "special://xbmc/system/players/paplayer/;" \
41 "special://xbmc/system/python/"
43 #if defined(TARGET_DARWIN)
44 #define ENV_PATH ENV_PARTIAL_PATH \
45 ";special://frameworks/"
47 #define ENV_PATH ENV_PARTIAL_PATH
50 //Define this to get logging on all calls to load/unload of dlls
54 using namespace XFILE
;
56 LibraryLoader
* DllLoaderContainer::m_dlls
[64] = {};
57 int DllLoaderContainer::m_iNrOfDlls
= 0;
59 LibraryLoader
* DllLoaderContainer::GetModule(const char* sName
)
61 for (int i
= 0; i
< m_iNrOfDlls
&& m_dlls
[i
] != NULL
; i
++)
63 if (StringUtils::CompareNoCase(m_dlls
[i
]->GetName(), sName
) == 0)
65 if (!m_dlls
[i
]->IsSystemDll() &&
66 StringUtils::CompareNoCase(m_dlls
[i
]->GetFileName(), sName
) == 0)
73 LibraryLoader
* DllLoaderContainer::GetModule(const HMODULE hModule
)
75 for (int i
= 0; i
< m_iNrOfDlls
&& m_dlls
[i
] != NULL
; i
++)
77 if (m_dlls
[i
]->GetHModule() == hModule
) return m_dlls
[i
];
82 LibraryLoader
* DllLoaderContainer::LoadModule(const char* sName
, const char* sCurrentDir
/*=NULL*/, bool bLoadSymbols
/*=false*/)
84 LibraryLoader
* pDll
=NULL
;
86 if (IsSystemDll(sName
))
88 pDll
= GetModule(sName
);
92 std::string strPath
=sCurrentDir
;
94 pDll
= GetModule(strPath
.c_str());
99 pDll
= GetModule(sName
);
104 pDll
= FindModule(sName
, sCurrentDir
, bLoadSymbols
);
106 else if (!pDll
->IsSystemDll())
111 CLog::Log(LOGDEBUG
, "Already loaded Dll {} at 0x{:x}", pDll
->GetFileName(), pDll
);
119 LibraryLoader
* DllLoaderContainer::FindModule(const char* sName
, const char* sCurrentDir
, bool bLoadSymbols
)
121 if (URIUtils::IsInArchive(sName
))
124 std::string newName
= "special://temp/";
125 newName
+= url
.GetFileName();
126 CFile::Copy(sName
, newName
);
127 return FindModule(newName
.c_str(), sCurrentDir
, bLoadSymbols
);
130 if (CURL::IsFullPath(sName
))
131 { // Has a path, just try to load
132 return LoadDll(sName
, bLoadSymbols
);
135 else if (strcmp(sName
, "xbmc.so") == 0)
136 return LoadDll(sName
, bLoadSymbols
);
138 else if (sCurrentDir
)
139 { // in the path of the parent dll?
140 std::string strPath
=sCurrentDir
;
143 if (CFile::Exists(strPath
))
144 return LoadDll(strPath
.c_str(), bLoadSymbols
);
147 // in environment variable?
148 std::vector
<std::string
> vecEnv
;
150 #if defined(TARGET_ANDROID)
151 std::string systemLibs
= getenv("KODI_ANDROID_SYSTEM_LIBS");
152 vecEnv
= StringUtils::Split(systemLibs
, ':');
153 std::string localLibs
= getenv("KODI_ANDROID_LIBS");
154 vecEnv
.insert(vecEnv
.begin(),localLibs
);
156 vecEnv
= StringUtils::Split(ENV_PATH
, ';');
158 LibraryLoader
* pDll
= NULL
;
160 for (std::vector
<std::string
>::const_iterator i
= vecEnv
.begin(); i
!= vecEnv
.end(); ++i
)
162 std::string strPath
= *i
;
163 URIUtils::AddSlashAtEnd(strPath
);
166 CLog::Log(LOGDEBUG
, "Searching for the dll {} in directory {}", sName
, strPath
);
171 // Have we already loaded this dll
172 if ((pDll
= GetModule(strPath
.c_str())) != NULL
)
175 if (CFile::Exists(strPath
))
176 return LoadDll(strPath
.c_str(), bLoadSymbols
);
179 // can't find it in any of our paths - could be a system dll
180 if ((pDll
= LoadDll(sName
, bLoadSymbols
)) != NULL
)
183 CLog::Log(LOGDEBUG
, "Dll {} was not found in path", sName
);
187 void DllLoaderContainer::ReleaseModule(LibraryLoader
*& pDll
)
191 if (pDll
->IsSystemDll())
193 CLog::Log(LOGFATAL
, "{} is a system dll and should never be released", pDll
->GetName());
197 int iRefCount
=pDll
->DecrRef();
202 CLog::Log(LOGDEBUG
, "Releasing Dll {}", pDll
->GetFileName());
205 if (!pDll
->HasSymbols())
212 CLog::Log(LOGINFO
, "{} has symbols loaded and can never be unloaded", pDll
->GetName());
217 CLog::Log(LOGDEBUG
, "Dll {} is still referenced with a count of {}", pDll
->GetFileName(),
223 LibraryLoader
* DllLoaderContainer::LoadDll(const char* sName
, bool bLoadSymbols
)
227 CLog::Log(LOGDEBUG
, "Loading dll {}", sName
);
230 LibraryLoader
* pLoader
;
232 pLoader
= new SoLoader(sName
, bLoadSymbols
);
233 #elif defined(TARGET_WINDOWS)
234 pLoader
= new Win32DllLoader(sName
, false);
239 CLog::Log(LOGERROR
, "Unable to create dll {}", sName
);
243 if (!pLoader
->Load())
252 bool DllLoaderContainer::IsSystemDll(const char* sName
)
254 for (int i
= 0; i
< m_iNrOfDlls
&& m_dlls
[i
] != NULL
; i
++)
256 if (m_dlls
[i
]->IsSystemDll() && StringUtils::CompareNoCase(m_dlls
[i
]->GetName(), sName
) == 0)
263 void DllLoaderContainer::RegisterDll(LibraryLoader
* pDll
)
265 for (LibraryLoader
*& dll
: m_dlls
)
276 void DllLoaderContainer::UnRegisterDll(LibraryLoader
* pDll
)
280 if (pDll
->IsSystemDll())
282 CLog::Log(LOGFATAL
, "{} is a system dll and should never be removed", pDll
->GetName());
286 // remove from the list
287 bool bRemoved
= false;
288 for (int i
= 0; i
< m_iNrOfDlls
&& m_dlls
[i
]; i
++)
290 if (m_dlls
[i
] == pDll
) bRemoved
= true;
291 if (bRemoved
&& i
+ 1 < m_iNrOfDlls
)
293 m_dlls
[i
] = m_dlls
[i
+ 1];
299 m_dlls
[m_iNrOfDlls
] = NULL
;