Skip to content

Commit 5e46851

Browse files
committed
Merge branch 'release/1.8.1'
2 parents 6f33cda + cac8c8b commit 5e46851

9 files changed

+951
-0
lines changed

.github/copilot-instructions.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
### Review Comment Linking Guidelines
2+
3+
When writing review comments based on custom instructions located in .github/instructions/**.instructions.md, include a direct GitHub link to the exact violated guideline in the respective instruction file. Use the following format:
4+
5+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/<instruction-file>.instructions.md#guideline-section-name
6+
7+
## Examples
8+
9+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/Plugin.instructions.md#interface-implementation
10+
11+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/Pluginlifecycle.instructions.md#deactivated
12+
13+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/Pluginimplementation.instructions.md#inter-plugin-communication
14+
15+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/Pluginmodule.instructions.md#module-name-convention
16+
17+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/Pluginconfig.instructions.md#plugin-configuration
18+
19+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/Plugincmake.instructions.md#namespace-usage
20+
21+
Refer: https://github.com/rdkcentral/entservices-softwareupdate/blob/develop/.github/instructions/PluginOnboardingCompliance.instructions.md#coverity-scan-inclusion-and-test-workflow-updates-for-new-plugins
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
---
2+
description: Guidelines for C++ files and header files that share the same name as their parent folder.
3+
applyTo: "**/*.cpp,**/*.h"
4+
---
5+
6+
# Instructions summary
7+
1. [Interface Implementation](#interface-implementation)
8+
2. [Service Registration](#service-registration)
9+
3. [JSON-RPC Stub Registration](#json-rpc-stub-registration)
10+
4. [Handling Out-of-Process Plugin Failures](#handling-out-of-process-plugin-failures)
11+
12+
### Interface Implementation
13+
14+
### Requirement
15+
16+
Each plugin must implement the appropriate Thunder interfaces.
17+
18+
-> PluginHost::IPlugin – Mandatory for all plugins.
19+
20+
-> PluginHost::IDispatcher or derive from PluginHost::JSONRPC – Mandatory If the plugin handles JSON-RPC.
21+
22+
-> Custom interfaces (like IHdcpProfile for HdcpProfile plugin) must be added to ThunderInterfaces for RPC.
23+
24+
-> PluginHost::IWeb – If the plugin handles web requests.
25+
26+
27+
### Example
28+
29+
```cpp
30+
BEGIN_INTERFACE_MAP(HdcpProfile)
31+
INTERFACE_ENTRY(PluginHost::IPlugin)
32+
INTERFACE_ENTRY(PluginHost::IDispatcher)
33+
INTERFACE_AGGREGATE(Exchange::IHdcpProfile, _hdcpProfile)
34+
END_INTERFACE_MAP
35+
```
36+
37+
### Service Registration
38+
39+
### Requirement
40+
41+
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:
42+
43+
```
44+
SERVICE_REGISTRATION(ServiceName, MAJOR, MINOR, PATCH)
45+
```
46+
47+
For better readability, it is always good to define the following plugin metadata which is not mandatory:
48+
49+
- **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.
50+
51+
- **Terminations** - List of Thunder subsystems that will cause the plugin to deactivate if they are marked inactive whilst the plugin is running.
52+
53+
- **Controls** - List of the subsystems that are controlled by the plugin.
54+
55+
### Example
56+
57+
```cpp
58+
namespace WPEFramework {
59+
namespace {
60+
static Plugin::Metadata<Plugin::HdcpProfile> metadata(
61+
API_VERSION_NUMBER_MAJOR,
62+
API_VERSION_NUMBER_MINOR,
63+
API_VERSION_NUMBER_PATCH,
64+
{}, // Preconditions
65+
{}, // Terminations
66+
{} // Controls
67+
);
68+
}
69+
70+
namespace Plugin {
71+
// Register HdcpProfile service with Thunder
72+
SERVICE_REGISTRATION(HdcpProfile,API_VERSION_NUMBER_MAJOR,API_VERSION_NUMBER_MINOR,API_VERSION_NUMBER_PATCH);
73+
}
74+
}
75+
```
76+
77+
### JSON-RPC Stub Registration
78+
79+
### Requirement
80+
81+
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.
82+
83+
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.
84+
85+
Plugins using autogenerated JSON-RPC stubs (Exchange::J* classes) must register and unregister them in Initialize() and Deinitialize() methods. Do not register or unregister them in the constructor or destructor.
86+
87+
In Initialize():
88+
89+
```cpp
90+
Exchange::JHdcpProfile::Register(*this, _hdcpProfile);
91+
```
92+
93+
In Deinitialize():
94+
95+
```cpp
96+
Exchange::JHdcpProfile::Unregister(*this);
97+
```
98+
99+
It is strongly recommended to use the autogenerated JSON-RPC stubs rather than registering the json-rpc methods manually as below.
100+
101+
```cpp
102+
RDKShell::RDKShell()
103+
...
104+
{
105+
.....
106+
Register(RDKSHELL_METHOD_MOVE_TO_FRONT, &RDKShell::moveToFrontWrapper, this);
107+
Register(RDKSHELL_METHOD_MOVE_TO_BACK, &RDKShell::moveToBackWrapper, this);
108+
...
109+
}
110+
```
111+
112+
### Handling Out-of-Process Plugin Failures
113+
114+
### Requirement
115+
116+
- If the plugin runs as out-of-process, then it should implement RPC::IRemoteConnection::INotification interface inside your plugin.
117+
118+
### Example
119+
120+
```cpp
121+
class TestPlugin : public PluginHost::IPlugin, public PluginHost::JSONRPC {
122+
private:
123+
class Notification : public RPC::IRemoteConnection::INotification {
124+
public:
125+
explicit Notification(TestPlugin* parent)
126+
: _parent(*parent)
127+
{
128+
ASSERT(parent != nullptr);
129+
}
130+
131+
~Notification() override = default;
132+
133+
Notification(Notification&&) = delete;
134+
Notification(const Notification&) = delete;
135+
Notification& operator=(Notification&&) = delete;
136+
Notification& operator=(const Notification&) = delete;
137+
138+
public:
139+
void Activated(RPC::IRemoteConnection* /* connection */) override
140+
{
141+
}
142+
void Deactivated(RPC::IRemoteConnection* connectionId) override
143+
{
144+
_parent.Deactivated(connectionId);
145+
}
146+
147+
BEGIN_INTERFACE_MAP(Notification)
148+
INTERFACE_ENTRY(RPC::IRemoteConnection::INotification)
149+
END_INTERFACE_MAP
150+
151+
private:
152+
TestPlugin& _parent;
153+
};
154+
155+
public:
156+
TestPlugin()
157+
: _connectionId(0)
158+
, _service(nullptr)
159+
, _testPlugin(nullptr)
160+
, _notification(this)
161+
{
162+
}
163+
~TestPlugin() override = default;
164+
165+
TestPlugin(TestPlugin&&) = delete;
166+
TestPlugin(const TestPlugin&) = delete;
167+
TestPlugin& operator=(TestPlugin&&) = delete;
168+
TestPlugin& operator=(const TestPlugin&) = delete;
169+
170+
BEGIN_INTERFACE_MAP(TestPlugin)
171+
INTERFACE_ENTRY(PluginHost::IPlugin)
172+
INTERFACE_ENTRY(PluginHost::IDispatcher)
173+
INTERFACE_AGGREGATE(Exchange::ITestPlugin, _testPlugin)
174+
END_INTERFACE_MAP
175+
176+
public:
177+
// IPlugin methods
178+
const string Initialize(PluginHost::IShell* service) override;
179+
void Deinitialize(PluginHost::IShell* service) override;
180+
string Information() const override;
181+
182+
private:
183+
void Deactivated(RPC::IRemoteConnection* connection);
184+
185+
private:
186+
uint32_t _connectionId;
187+
PluginHost::IShell* _service;
188+
Exchange::ITestPlugin* _testPlugin;
189+
Core::Sink<Notification> _notification;
190+
};
191+
```
192+
193+
- It should be registered during Initialize() to get itself notified when the remote process connects or disconnects.
194+
195+
### Example
196+
197+
```cpp
198+
const string TestPlugin::Initialize(PluginHost::IShell* service)
199+
{
200+
// Register for COM-RPC connection/disconnection notifications
201+
_service->Register(&_notification);
202+
}
203+
```
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
applyTo: "CMakeLists.txt"
3+
---
4+
5+
## Requirement
6+
7+
### Coverity Scan Inclusion and Test Workflow Updates for New Plugins
8+
9+
When adding a new plugin in `CMakeLists.txt`, you **must** also update the following to guarantee the plugin is included in all required test and Coverity analysis workflows:
10+
11+
- **CI Workflow Files:**
12+
- `L1-tests.yml`
13+
- `L2-tests.yml`
14+
- `L2-tests-oop.yml`
15+
- **Coverity Build Script:**
16+
- `cov_build.sh`
17+
18+
**Example:**
19+
20+
1. **CMake Plugin Registration Example**
21+
22+
If you add your plugin in `CMakeLists.txt` as:
23+
```cmake
24+
if (PLUGIN_RESOURCEMANAGER)
25+
add_subdirectory(ResourceManager)
26+
endif()
27+
if (PLUGIN_MY_NEW_PLUGIN)
28+
add_subdirectory(MyNewPlugin)
29+
endif()
30+
```
31+
2. **Update Coverity Build Script**
32+
33+
Add your plugin’s flag in the build command in `cov_build.sh`:
34+
```bash
35+
cmake \
36+
-DPLUGIN_CORE=ON \
37+
-DPLUGIN_LEGACY=ON \
38+
# <-- NEW PLUGIN FLAG
39+
-DPLUGIN_MY_NEW_PLUGIN=ON \
40+
.
41+
```
42+
This ensures Coverity runs on your new plugin.
43+
44+
3. **Update Test Workflow YAMLs**
45+
46+
Ensure each test workflow references your new plugin using the **DPLUGIN_<PLUGINNAME>** CMake flag in their build/test step. For example, in `L1-tests.yml`:
47+
```yaml
48+
jobs:
49+
build-test:
50+
runs-on: ubuntu-22.04
51+
steps:
52+
- name: Configure with new plugin
53+
run: |
54+
cmake \
55+
-DPLUGIN_CORE=ON \
56+
-DPLUGIN_MY_NEW_PLUGIN=ON \
57+
.
58+
- name: Run tests
59+
run: |
60+
ctest
61+
```
62+
Repeat similar additions in `L2-tests.yml` and `L2-tests-oop.yml`.
63+
64+
**Summary:**
65+
Whenever a new plugin is registered via `CMakeLists.txt`, always update:
66+
- `cov_build.sh` (add plugin flag to Coverity scan build step)
67+
- All test CI workflows (`L1-tests.yml`, `L2-tests.yml`, `L2-tests-oop.yml`) to include your plugin flag so that your plugin’s code quality and tests are assured!
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
---
2+
applyTo: "**/CMakeLists.txt"
3+
---
4+
5+
### NAMESPACE Usage
6+
7+
### Requirement
8+
9+
All CMake targets, install paths, export sets,find_package and references must use the ${NAMESPACE} variable instead of hardcoded framework names (e.g., WPEFrameworkCore, WPEFrameworkPlugins).
10+
This ensures smooth upgrades (e.g., WPEFramework → Thunder) and prevents regressions.
11+
12+
### Correct Example
13+
14+
```cmake
15+
set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME})
16+
17+
find_package(${NAMESPACE}Plugins REQUIRED)
18+
19+
find_package(${NAMESPACE}Definitions REQUIRED)
20+
21+
target_link_libraries(${MODULE_NAME}
22+
PRIVATE
23+
CompileSettingsDebug::CompileSettingsDebug
24+
${NAMESPACE}Plugins::${NAMESPACE}Plugins
25+
${NAMESPACE}Definitions::${NAMESPACE}Definitions)
26+
```
27+
28+
29+
### Incorrect Example
30+
31+
```cmake
32+
set(MODULE_NAME WPEFramework${PLUGIN_NAME})
33+
34+
find_package(WPEFrameworkPlugins REQUIRED)
35+
36+
find_package(WPEFrameworkDefinitions REQUIRED)
37+
38+
target_link_libraries(${MODULE_NAME}
39+
PRIVATE
40+
CompileSettingsDebug::CompileSettingsDebug
41+
WPEFrameworkPlugins::WPEFrameworkPlugins
42+
WPEFrameworkDefinitions::WPEFrameworkDefinitions)
43+
```
44+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
applyTo: "**/*.conf.in"
3+
---
4+
5+
### Plugin Configuration
6+
7+
### Requirement
8+
9+
- Each plugin must define a <PluginName>.conf.in file that includes the following mandatory properties:
10+
11+
- **autostart**: Indicates whether the plugin should start automatically when the framework boots. This should be set to false by default.
12+
13+
- **callsign**: A unique identifier used to reference the plugin within the framework. Every callsign must be defined with a prefix of org.rdk and it must be followed by the ENT Service name written in PascalCase (e.g., org.rdk.PersistentStore).
14+
15+
- **Custom properties**: Any additional configuration parameters required by the plugin. These are passed during activation via PluginHost::IShell::ConfigLine(). The following structural configuration elements are commonly defined:
16+
- startuporder - Specifies the order in which plugins are started, relative to others.
17+
- precondition - If these preconditions aren't met, the plugin stays in the Preconditions state and activates automatically once they are satisfied. It is recommended to define the precondition if the plugin depends on other subsystems being active.
18+
- mode - Defines the execution mode of the plugin.
19+
20+
### Plugin Mode Determination
21+
22+
If the plugin's mode is set to OFF, it is treated as in-process.
23+
24+
If no mode is specified, the plugin defaults to in-process.
25+
26+
If the mode is explicitly set to LOCAL, the plugin runs out-of-process.
27+
28+
The plugin mode is configured in the plugin's CMakeLists.txt file.
29+
30+
- **locator** - Update with the name of the library (.so) that contains the actual plugin Implementation code.
31+
32+
### Example
33+
34+
<PluginName>.conf.in
35+
36+
```
37+
precondition = ["Platform"]
38+
callsign = "org.rdk.HdcpProfile"
39+
autostart = "@PLUGIN_HDCPPROFILE_AUTOSTART@"
40+
startuporder = "@PLUGIN_HDCPPROFILE_STARTUPORDER@"
41+
42+
configuration = JSON()
43+
rootobject = JSON()
44+
45+
rootobject.add("mode", "@PLUGIN_HDCPPROFILE_MODE@")
46+
rootobject.add("locator", "lib@[email protected]")
47+
48+
configuration.add("root", rootobject)
49+
```

0 commit comments

Comments
 (0)