Skip to content

Commit

Permalink
[PATCH] [Binary Addon] provide API versions to addon for better
Browse files Browse the repository at this point in the history
 downgrade handling
  • Loading branch information
StormTrooper committed Feb 13, 2019
1 parent a3d9ba1 commit cd84d5f
Showing 1 changed file with 287 additions and 0 deletions.
287 changes: 287 additions & 0 deletions package/mediacenter-next-osmc/patches/rbp-010-pull-api.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
From 64a933b29acd42e094815b95b088336dbc540056 Mon Sep 17 00:00:00 2001
From: peak3d <pfau@peak3d.de>
Date: Mon, 4 Feb 2019 09:01:46 +0100
Subject: [PATCH] [Binary Addon] provide API versions to addon for better
downgrade handling

---
xbmc/DynamicDll.h | 6 ++-
xbmc/addons/binary-addons/AddonDll.cpp | 38 ++++++++++++-----
xbmc/addons/binary-addons/DllAddon.h | 8 ++++
.../include/kodi/AddonBase.h | 41 ++++++++++++++++---
.../include/kodi/xbmc_addon_dll.h | 5 +++
5 files changed, 82 insertions(+), 16 deletions(-)

diff --git a/xbmc/DynamicDll.h b/xbmc/DynamicDll.h
index 4f51a99b7e28..3a7c535a3b81 100644
--- a/xbmc/DynamicDll.h
+++ b/xbmc/DynamicDll.h
@@ -125,7 +125,7 @@ public: \
public: \
virtual result name args override \
{ \
- return m_##name args2; \
+ return m_##name ? m_##name args2 : (result) 0; \
}

#define DEFINE_METHOD_LINKAGE0(result, linkage, name) \
@@ -403,6 +403,10 @@ public: \
if (!m_dll->ResolveExport( #dllmethod , & m_##method##_ptr )) \
return false;

+#define RESOLVE_METHOD_RENAME_OPTIONAL(dllmethod, method) \
+ m_##method##_ptr = nullptr; \
+ m_dll->ResolveExport( #dllmethod , & m_##method##_ptr );
+
#define RESOLVE_METHOD_RENAME_FP(dllmethod, method) \
if (!m_dll->ResolveExport( #dllmethod , & method##_ptr )) \
return false;
diff --git a/xbmc/addons/binary-addons/AddonDll.cpp b/xbmc/addons/binary-addons/AddonDll.cpp
index 0562cc157043..2fb2c2cd843f 100644
--- a/xbmc/addons/binary-addons/AddonDll.cpp
+++ b/xbmc/addons/binary-addons/AddonDll.cpp
@@ -215,7 +215,10 @@ ADDON_STATUS CAddonDll::Create(ADDON_TYPE type, void* funcTable, void* info)

/* Call Create to make connections, initializing data or whatever is
needed to become the AddOn running */
- ADDON_STATUS status = m_pDll->Create(m_pHelpers->GetCallbacks(), info);
+ ADDON_STATUS status = m_pDll->CreateEx_available()
+ ? m_pDll->CreateEx(m_pHelpers->GetCallbacks(), kodi::addon::GetTypeVersion(ADDON_GLOBAL_MAIN), info)
+ : m_pDll->Create(m_pHelpers->GetCallbacks(), info);
+
if (status == ADDON_STATUS_OK)
{
m_initialized = true;
@@ -263,7 +266,10 @@ ADDON_STATUS CAddonDll::Create(KODI_HANDLE firstKodiInstance)

/* Call Create to make connections, initializing data or whatever is
needed to become the AddOn running */
- ADDON_STATUS status = m_pDll->Create(&m_interface, nullptr);
+ ADDON_STATUS status = m_pDll->CreateEx_available()
+ ? m_pDll->CreateEx(&m_interface, kodi::addon::GetTypeVersion(ADDON_GLOBAL_MAIN), nullptr)
+ : m_pDll->Create(&m_interface, nullptr);
+
if (status == ADDON_STATUS_OK)
{
m_initialized = true;
@@ -323,7 +329,11 @@ ADDON_STATUS CAddonDll::CreateInstance(ADDON_TYPE instanceType, const std::strin
return ADDON_STATUS_PERMANENT_FAILURE;

KODI_HANDLE addonInstance;
- status = m_interface.toAddon->create_instance(instanceType, instanceID.c_str(), instance, &addonInstance, parentInstance);
+ if (!m_interface.toAddon->create_instance_ex)
+ status = m_interface.toAddon->create_instance(instanceType, instanceID.c_str(), instance, &addonInstance, parentInstance);
+ else
+ status = m_interface.toAddon->create_instance_ex(instanceType, instanceID.c_str(), instance, &addonInstance, parentInstance, kodi::addon::GetTypeVersion(instanceType));
+
if (status == ADDON_STATUS_OK)
{
m_usedInstances[instanceID] = std::make_pair(instanceType, addonInstance);
@@ -334,6 +344,9 @@ ADDON_STATUS CAddonDll::CreateInstance(ADDON_TYPE instanceType, const std::strin

void CAddonDll::DestroyInstance(const std::string& instanceID)
{
+ if (m_usedInstances.empty())
+ return;
+
auto it = m_usedInstances.find(instanceID);
if (it != m_usedInstances.end())
{
@@ -450,6 +463,9 @@ bool CAddonDll::CheckAPIVersion(int type)
/* check the API version */
AddonVersion kodiMinVersion(kodi::addon::GetTypeMinVersion(type));
AddonVersion addonVersion(m_pDll->GetAddonTypeVersion(type));
+ AddonVersion addonMinVersion = m_pDll->GetAddonTypeMinVersion_available()
+ ? AddonVersion(m_pDll->GetAddonTypeMinVersion(type))
+ : addonVersion;

/* Check the global usage from addon
* if not used from addon becomes "0.0.0" returned
@@ -461,13 +477,15 @@ bool CAddonDll::CheckAPIVersion(int type)
* present.
*/
if (kodiMinVersion > addonVersion ||
- addonVersion > AddonVersion(kodi::addon::GetTypeVersion(type)))
- {
- CLog::Log(LOGERROR, "Add-on '%s' is using an incompatible API version for type '%s'. Kodi API min version = '%s', add-on API version '%s'",
- Name().c_str(),
- kodi::addon::GetTypeName(type),
- kodiMinVersion.asString().c_str(),
- addonVersion.asString().c_str());
+ addonMinVersion > AddonVersion(kodi::addon::GetTypeVersion(type)))
+ {
+ CLog::Log(LOGERROR, "Add-on '{}' is using an incompatible API version for type '{}'. Kodi API min version = '{}/{}', add-on API version '{}/{}'",
+ Name(),
+ kodi::addon::GetTypeName(type),
+ kodi::addon::GetTypeVersion(type),
+ kodiMinVersion.asString(),
+ addonMinVersion.asString(),
+ addonVersion.asString());

CEventLog &eventLog = CServiceBroker::GetEventLog();
eventLog.AddWithNotification(EventPtr(new CNotificationEvent(Name(), 24152, EventLevel::Error)));
diff --git a/xbmc/addons/binary-addons/DllAddon.h b/xbmc/addons/binary-addons/DllAddon.h
index 7350b2ee2ff6..806c0f49a876 100644
--- a/xbmc/addons/binary-addons/DllAddon.h
+++ b/xbmc/addons/binary-addons/DllAddon.h
@@ -17,10 +17,12 @@ class DllAddonInterface
virtual ~DllAddonInterface() = default;
virtual void GetAddon(void* pAddon) =0;
virtual ADDON_STATUS Create(void *cb, void *info) =0;
+ virtual ADDON_STATUS CreateEx(void *cb, const char* globalApiVersion, void *info) = 0;
virtual void Destroy() =0;
virtual ADDON_STATUS GetStatus() =0;
virtual ADDON_STATUS SetSetting(const char *settingName, const void *settingValue) =0;
virtual const char* GetAddonTypeVersion(int type)=0;
+ virtual const char* GetAddonTypeMinVersion(int type) = 0;
};

class DllAddon : public DllDynamic, public DllAddonInterface
@@ -28,18 +30,24 @@ class DllAddon : public DllDynamic, public DllAddonInterface
public:
DECLARE_DLL_WRAPPER_TEMPLATE(DllAddon)
DEFINE_METHOD2(ADDON_STATUS, Create, (void* p1, void* p2))
+ DEFINE_METHOD3(ADDON_STATUS, CreateEx, (void* p1, const char* p2, void* p3))
+ bool CreateEx_available() { return m_CreateEx != nullptr; }
DEFINE_METHOD0(void, Destroy)
DEFINE_METHOD0(ADDON_STATUS, GetStatus)
DEFINE_METHOD2(ADDON_STATUS, SetSetting, (const char *p1, const void *p2))
DEFINE_METHOD1(void, GetAddon, (void* p1))
DEFINE_METHOD1(const char*, GetAddonTypeVersion, (int p1))
+ DEFINE_METHOD1(const char*, GetAddonTypeMinVersion, (int p1))
+ bool GetAddonTypeMinVersion_available() { return m_GetAddonTypeMinVersion != nullptr; }
BEGIN_METHOD_RESOLVE()
RESOLVE_METHOD_RENAME(get_addon,GetAddon)
RESOLVE_METHOD_RENAME(ADDON_Create, Create)
+ RESOLVE_METHOD_RENAME_OPTIONAL(ADDON_CreateEx, CreateEx)
RESOLVE_METHOD_RENAME(ADDON_Destroy, Destroy)
RESOLVE_METHOD_RENAME(ADDON_GetStatus, GetStatus)
RESOLVE_METHOD_RENAME(ADDON_SetSetting, SetSetting)
RESOLVE_METHOD_RENAME(ADDON_GetTypeVersion, GetAddonTypeVersion)
+ RESOLVE_METHOD_RENAME_OPTIONAL(ADDON_GetTypeMinVersion, GetAddonTypeMinVersion)
END_METHOD_RESOLVE()
};

diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h
index 8e45693a16b6..5325ebfea2ad 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/AddonBase.h
@@ -193,6 +193,7 @@ typedef struct KodiToAddonFuncTable_Addon
ADDON_STATUS (*create_instance)(int instanceType, const char* instanceID, KODI_HANDLE instance, KODI_HANDLE* addonInstance, KODI_HANDLE parent);
void (*destroy_instance)(int instanceType, KODI_HANDLE instance);
ADDON_STATUS (*set_setting)(const char *settingName, const void *settingValue);
+ ADDON_STATUS(*create_instance_ex)(int instanceType, const char* instanceID, KODI_HANDLE instance, KODI_HANDLE* addonInstance, KODI_HANDLE parent, const char* version);
} KodiToAddonFuncTable_Addon;

/*
@@ -251,6 +252,11 @@ class IAddonInstance
return ADDON_STATUS_NOT_IMPLEMENTED;
}

+ virtual ADDON_STATUS CreateInstanceEx(int instanceType, std::string instanceID, KODI_HANDLE instance, KODI_HANDLE& addonInstance, const std::string &version)
+ {
+ return CreateInstance(instanceType, instanceID, instance, addonInstance);
+ }
+
const ADDON_TYPE m_type;
};
} /* namespace addon */
@@ -292,6 +298,9 @@ class ATTRIBUTE_HIDDEN CAddonBase
CAddonBase::m_interface->toAddon->create_instance = ADDONBASE_CreateInstance;
CAddonBase::m_interface->toAddon->destroy_instance = ADDONBASE_DestroyInstance;
CAddonBase::m_interface->toAddon->set_setting = ADDONBASE_SetSetting;
+ // If version is present, we know that kodi has create_instance_ex implemented
+ if (!CAddonBase::m_strGlobalApiVersion.empty())
+ CAddonBase::m_interface->toAddon->create_instance_ex = ADDONBASE_CreateInstanceEx;
}

virtual ~CAddonBase() = default;
@@ -320,8 +329,14 @@ class ATTRIBUTE_HIDDEN CAddonBase
return ADDON_STATUS_UNKNOWN;
}

+ virtual ADDON_STATUS CreateInstanceEx(int instanceType, std::string instanceID, KODI_HANDLE instance, KODI_HANDLE& addonInstance, const std::string &version)
+ {
+ return CreateInstance(instanceType, instanceID, instance, addonInstance);
+ }
+
/* Global variables of class */
static AddonGlobalInterface* m_interface; // Interface function table to hold addresses on add-on and from kodi
+ static std::string m_strGlobalApiVersion;

/*private:*/ /* Needed public as long the old call functions becomes used! */
static inline void ADDONBASE_Destroy()
@@ -338,17 +353,22 @@ class ATTRIBUTE_HIDDEN CAddonBase
}

static inline ADDON_STATUS ADDONBASE_CreateInstance(int instanceType, const char* instanceID, KODI_HANDLE instance, KODI_HANDLE* addonInstance, KODI_HANDLE parent)
+ {
+ return ADDONBASE_CreateInstanceEx(instanceType, instanceID, instance, addonInstance, parent, nullptr);
+ }
+
+ static inline ADDON_STATUS ADDONBASE_CreateInstanceEx(int instanceType, const char* instanceID, KODI_HANDLE instance, KODI_HANDLE* addonInstance, KODI_HANDLE parent, const char* version)
{
ADDON_STATUS status = ADDON_STATUS_NOT_IMPLEMENTED;
if (parent != nullptr)
- status = static_cast<IAddonInstance*>(parent)->CreateInstance(instanceType, instanceID, instance, *addonInstance);
+ status = static_cast<IAddonInstance*>(parent)->CreateInstanceEx(instanceType, instanceID, instance, *addonInstance, version);
if (status == ADDON_STATUS_NOT_IMPLEMENTED)
- status = CAddonBase::m_interface->addonBase->CreateInstance(instanceType, instanceID, instance, *addonInstance);
+ status = CAddonBase::m_interface->addonBase->CreateInstanceEx(instanceType, instanceID, instance, *addonInstance, version);
if (*addonInstance == nullptr)
- throw std::logic_error("kodi::addon::CAddonBase CreateInstance returns a empty instance pointer!");
+ throw std::logic_error("kodi::addon::CAddonBase CreateInstanceEx returns a empty instance pointer!");

if (static_cast<::kodi::addon::IAddonInstance*>(*addonInstance)->m_type != instanceType)
- throw std::logic_error("kodi::addon::CAddonBase CreateInstance with difference on given and returned instance type!");
+ throw std::logic_error("kodi::addon::CAddonBase CreateInstanceEx with difference on given and returned instance type!");

return status;
}
@@ -650,6 +670,11 @@ inline void* GetInterface(const std::string &name, const std::string &version)
kodi::addon::CAddonBase::m_interface->addonBase = new AddonClass; \
return kodi::addon::CAddonBase::m_interface->addonBase->Create(); \
} \
+ extern "C" __declspec(dllexport) ADDON_STATUS ADDON_CreateEx(KODI_HANDLE addonInterface, const char* globalApiVersion, void *unused) \
+ { \
+ kodi::addon::CAddonBase::m_strGlobalApiVersion = globalApiVersion; \
+ return ADDON_Create(addonInterface, unused); \
+ } \
extern "C" __declspec(dllexport) void ADDON_Destroy() \
{ \
kodi::addon::CAddonBase::ADDONBASE_Destroy(); \
@@ -666,4 +691,10 @@ inline void* GetInterface(const std::string &name, const std::string &version)
{ \
return kodi::addon::GetTypeVersion(type); \
} \
- AddonGlobalInterface* kodi::addon::CAddonBase::m_interface = nullptr;
+ extern "C" __declspec(dllexport) const char* ADDON_GetTypeMinVersion(int type) \
+ { \
+ return kodi::addon::GetTypeMinVersion(type); \
+ } \
+ AddonGlobalInterface* kodi::addon::CAddonBase::m_interface = nullptr; \
+ std::string kodi::addon::CAddonBase::m_strGlobalApiVersion;
+
diff --git a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_addon_dll.h b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_addon_dll.h
index e9e7d9ac871c..ce2bc9801ec0 100644
--- a/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_addon_dll.h
+++ b/xbmc/addons/kodi-addon-dev-kit/include/kodi/xbmc_addon_dll.h
@@ -15,6 +15,7 @@ extern "C" {
#endif

ADDON_STATUS __declspec(dllexport) ADDON_Create(void *callbacks, void* props);
+ ADDON_STATUS __declspec(dllexport) ADDON_CreateEx(void *callbacks, const char* globalApiVersion, void* props);
void __declspec(dllexport) ADDON_Destroy();
ADDON_STATUS __declspec(dllexport) ADDON_GetStatus();
ADDON_STATUS __declspec(dllexport) ADDON_SetSetting(const char *settingName, const void *settingValue);
@@ -22,6 +23,10 @@ extern "C" {
{
return kodi::addon::GetTypeVersion(type);
}
+ __declspec(dllexport) const char* ADDON_GetTypeMinVersion(int type)
+ {
+ return kodi::addon::GetTypeMinVersion(type);
+ }

#ifdef __cplusplus
};

0 comments on commit cd84d5f

Please sign in to comment.