Instruction file imported from rdkcentral/entservices-account (
.github/instructions/Plugin.instructions.md). Copyright stays with the author.
Instructions summary
- Interface Implementation
- Service Registration
- JSON-RPC Stub Registration
- Handling Out-of-Process Plugin Failures
Interface Implementation
Requirement
Each plugin must implement the appropriate Thunder interfaces.
-> PluginHost::IPlugin – Mandatory for all plugins.
-> PluginHost::IDispatcher or derive from PluginHost::JSONRPC – Mandatory If the plugin handles JSON-RPC.
-> Custom interfaces (like IHdcpProfile for HdcpProfile plugin) must be added to ThunderInterfaces for RPC.
-> PluginHost::IWeb – If the plugin handles web requests.
Example
BEGIN_INTERFACE_MAP(HdcpProfile)
INTERFACE_ENTRY(PluginHost::IPlugin)
INTERFACE_ENTRY(PluginHost::IDispatcher)
INTERFACE_AGGREGATE(Exchange::IHdcpProfile, _hdcpProfile)
END_INTERFACE_MAP
Service Registration
Requirement
All Thunder services must be registered using the SERVICE_REGISTRATION macro with name, major, minor and patch versions of service. Register the service using the following macro:
SERVICE_REGISTRATION(ServiceName, MAJOR, MINOR, PATCH)
For better readability, it is always good to define the following plugin metadata which is not mandatory:
-
Precondition - List of Thunder subsystems that must be active in order for the plugin to activate. This can also be set in Plugin.conf.in file.
-
Terminations - List of Thunder subsystems that will cause the plugin to deactivate if they are marked inactive whilst the plugin is running.
-
Controls - List of the subsystems that are controlled by the plugin.
Example
namespace WPEFramework {
namespace {
static Plugin::Metadata<Plugin::HdcpProfile> metadata(
API_VERSION_NUMBER_MAJOR,
API_VERSION_NUMBER_MINOR,
API_VERSION_NUMBER_PATCH,
{}, // Preconditions
{}, // Terminations
{} // Controls
);
}
namespace Plugin {
// Register HdcpProfile service with Thunder
SERVICE_REGISTRATION(HdcpProfile,API_VERSION_NUMBER_MAJOR,API_VERSION_NUMBER_MINOR,API_VERSION_NUMBER_PATCH);
}
}
JSON-RPC Stub Registration
Requirement
If the plugin includes <interfaces/IPluginName*.h>, <interfaces/JsonData_PluginName.h>, and <interfaces/JPluginName.h> and inherits from PluginHost::JsonRPC, then it provides JSON‑RPC support and uses autogenerated JSON‑RPC stubs.
These autogenerated stubs are the Exchange::J* C++ classes (for example, Exchange::JHdcpProfile and JsonData_HdcpProfile.h) that are produced by the Thunder JSON‑RPC code generator from the IPluginName* interface headers; they expose the C++ interface over JSON‑RPC so you do not have to call Register() for each method manually.
Plugins using autogenerated JSON-RPC stubs (Exchange::J* classes) must register and unregister them in Initialize() and Deinitialize() methods.It should not be done in constructor and destructor.
In Initialize():
Exchange::JHdcpProfile::Register(*this, _hdcpProfile);
In Deinitialize():
Exchange::JHdcpProfile::Unregister(*this);
It is strongly recommended to use the autogenerated JSON-RPC stubs rather than registering the json-rpc methods manually as below.
RDKShell::RDKShell()
...
{
.....
Register(RDKSHELL_METHOD_MOVE_TO_FRONT, &RDKShell::moveToFrontWrapper, this);
Register(RDKSHELL_METHOD_MOVE_TO_BACK, &RDKShell::moveToBackWrapper, this);
...
}
Handling Out-of-Process Plugin Failures
Requirement
- If the plugin runs as out-of-process, then it should implement RPC::IRemoteConnection::"INotification interface inside your plugin.
Example
class TestPlugin : public PluginHost::IPlugin, public PluginHost::JSONRPC {
private:
class Notification : public RPC::IRemoteConnection::INotification {
public:
explicit Notification(TestPlugin* parent)
: _parent(*parent)
{
ASSERT(parent != nullptr);
}
~Notification() override = default;
Notification(Notification&&) = delete;
Notification(const Notification&) = delete;
Notification& operator=(Notification&&) = delete;
Notification& operator=(const Notification&) = delete;
public:
void Activated(RPC::IRemoteConnection* /* connection */) override
{
}
void Deactivated(RPC::IRemoteConnection* connectionId) override
{
_parent.Deactivated(connectionId);
}
BEGIN_INTERFACE_MAP(Notification)
INTERFACE_ENTRY(RPC::IRemoteConnection::INotification)
END_INTERFACE_MAP
private:
TestPlugin& _parent;
};
public:
TestPlugin()
: _connectionId(0)
, _service(nullptr)
, _testPlugin(nullptr)
, _notification(this)
{
}
~TestPlugin() override = default;
TestPlugin(TestPlugin&&) = delete;
TestPlugin(const TestPlugin&) = delete;
TestPlugin& operator=(TestPlugin&&) = delete;
TestPlugin& operator=(const TestPlugin&) = delete;
BEGIN_INTERFACE_MAP(TestPlugin)
INTERFACE_ENTRY(PluginHost::IPlugin)
INTERFACE_ENTRY(PluginHost::IDispatcher)
INTERFACE_AGGREGATE(Exchange::ITestPlugin, _testPlugin)
END_INTERFACE_MAP
public:
// IPlugin methods
const string Initialize(PluginHost::IShell* service) override;
void Deinitialize(PluginHost::IShell* service) override;
string Information() const override;
private:
void Deactivated(RPC::IRemoteConnection* connection);
private:
uint32_t _connectionId;
PluginHost::IShell* _service;
Exchange::ITestPlugin* _testPlugin;
Core::Sink<Notification> _notification;
};
- It should be registered during Initialize() to get itself notified when the remote process connects or disconnects.
Example
const string TestPlugin::Initialize(PluginHost::IShell* service)
{
// Register for COM-RPC connection/disconnection notifications
_service->Register(&_notification);
}