Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
13c3ec9
[PluginInitService] Initial commit
MFransen69 Jun 27, 2025
7e6eace
[PluginInitService] now make it go in parallel
MFransen69 Jun 30, 2025
13fb06a
[PluginInitService] improved queue logging
MFransen69 Jun 30, 2025
a95b1dc
[PluginInitService] more fixes
MFransen69 Jun 30, 2025
0525c54
[PluginInitService] Final changes after testing
MFransen69 Jul 1, 2025
d76a674
[PluginInitService] More final changes :)
MFransen69 Jul 1, 2025
6b520f8
[PluginInitService] gcc fixes
MFransen69 Jul 1, 2025
ec8ebf7
[PluginInitService] update
MFransen69 Jul 1, 2025
f56bbcc
[PluginInitService] fixed some typos
MFransen69 Jul 1, 2025
b6a1bf1
[PluginInitializerService] forgot one explicit
MFransen69 Jul 1, 2025
7cb15a2
Merge branch 'master' into development/PIS
MFransen69 Jul 1, 2025
91e2b88
[PluginInitService] Update copyrights
MFransen69 Jul 2, 2025
56f9447
[ThunderNanoservices] add RDK management credit to Notice file
MFransen69 Jul 2, 2025
b589b1d
[PluginInitService] first set of fixes after review
MFransen69 Jul 4, 2025
7298ebb
[PluginInitService] Improve startup handling
MFransen69 Jul 5, 2025
224e3dd
[PluginInitService] More changes
MFransen69 Jul 6, 2025
d95d335
[PluginInitService] more changes
MFransen69 Jul 8, 2025
a289052
[PluginInitService] more fixes
MFransen69 Jul 8, 2025
55c8250
[PluginInitService] And more fixes
MFransen69 Jul 9, 2025
8751ba5
[PLuginInitService] and even more changes
MFransen69 Jul 9, 2025
f53fd59
[PluginInitService] update
MFransen69 Jul 10, 2025
b0e0bb1
[PluginInitService] it builds again...
MFransen69 Jul 10, 2025
4ce6981
[PluginInitService] code complete beforen internal review
MFransen69 Jul 10, 2025
b0b7cc0
[PluginInitService] Fixes after selfreview
MFransen69 Jul 10, 2025
3d7f39c
[PluginInitService] first run again
MFransen69 Jul 11, 2025
32e4c0c
[PluginInitService] adding activationresult job
MFransen69 Jul 12, 2025
91b2344
[PluginInitService] fix typos
MFransen69 Jul 12, 2025
55a3391
[PluginInitService] okay most complex (failing preconditions) case s…
MFransen69 Jul 12, 2025
b3896fd
[PluginInitService] fix typo
MFransen69 Jul 12, 2025
84728ed
[PluginInitService] add some useful comment
MFransen69 Jul 12, 2025
2128acf
[PluginInitService] update some comments
MFransen69 Jul 12, 2025
1370c67
[PluginInitService] blocked bool does no longer need to be atomic
MFransen69 Jul 12, 2025
8aaf227
[PluginInitService] make it log queue info morem consistent (as the cost
MFransen69 Jul 12, 2025
232c121
[PluginInitSerice] fix abba and cancelall (not complete)
MFransen69 Jul 12, 2025
c61dd6b
[PluginInitService] initial decoupling notifications
MFransen69 Jul 12, 2025
bf04e37
[PluginInitService] First few tests look promosing
MFransen69 Jul 13, 2025
d0cc95a
[PlugInitService] add some usefull coments
MFransen69 Jul 13, 2025
073dfce
Merge branch 'master' into development/PIS
MFransen69 Jul 13, 2025
2a384c2
[PluginInitService] more comments and small fixes
MFransen69 Jul 13, 2025
4d55d97
[PluginInitService] Ordering
MFransen69 Jul 13, 2025
feee9b0
[PluginInitService] small fixes
MFransen69 Jul 13, 2025
fb9b31a
Merge branch 'master' into development/PIS
MFransen69 Sep 2, 2025
c164948
[PluginInitServiece] add some useful comment
MFransen69 Sep 8, 2025
14c3d4d
Merge branch 'master' into development/PIS
MFransen69 Sep 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ option(PLUGIN_WEBSERVER "Include WebServer plugin" OFF)
option(PLUGIN_WEBSHELL "Include WebShell plugin" OFF)
option(PLUGIN_WIFICONTROL "Include WifiControl plugin" OFF)
option(PLUGIN_FILETRANSFER "Include FileTransfer plugin" OFF)
option(PLUGIN_PLUGININITIALIZERSERVICE "Include PluginInitializerService plugin" OFF)


if(ENABLE_STRICT_COMPILER_SETTINGS)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
Expand Down Expand Up @@ -268,5 +270,9 @@ if(PLUGIN_FILETRANSFER)
add_subdirectory(FileTransfer)
endif()

if(PLUGIN_PLUGININITIALIZERSERVICE)
add_subdirectory(PluginInitializerService)
endif()

add_subdirectory(examples)
add_subdirectory(tests)
3 changes: 3 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ Licensed under the BSD-2 license
Copyright (C) 2014 Igalia S.L.
Licensed under the BSD-2 license

Copyright 2025 RDK Management
Licensed under the Apache License, V2.0

Copyright (C) 2012 Raphael Kubo da Costa <[email protected]>
Licensed under the BSD-2 license

Expand Down
65 changes: 65 additions & 0 deletions PluginInitializerService/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# If not stated otherwise in this file or this component's license file the
# following copyright and licenses apply:
#
# Copyright 2025 RDK Management
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

project(PluginInitializerService)

cmake_minimum_required(VERSION 3.15)

find_package(Thunder)

project_version(1.0.0)

set(MODULE_NAME ${NAMESPACE}${PROJECT_NAME})

message("Setup ${MODULE_NAME} v${PROJECT_VERSION}")

set(PLUGIN_PLUGININITIALIZERSERVICE_STARTMODE "Activated" CACHE STRING "Automatically start PluginInitializerService plugin")
set(PLUGIN_PLUGININITIALIZERSERVICE_MAXPARALLEL "2" CACHE STRING "Maximum number of plugins that can be started in parallel")
set(PLUGIN_PLUGININITIALIZERSERVICE_DEFAULTMAXRETRIES "10" CACHE STRING "Default maximum number of retries used starting a plugin")
set(PLUGIN_PLUGININITIALIZERSERVICE_DEFAULTDELAY "500" CACHE STRING "Default delay between retries starting a plugin (ms)")

if(BUILD_REFERENCE)
add_definitions(-DBUILD_REFERENCE=${BUILD_REFERENCE})
endif()

find_package(${NAMESPACE}Plugins REQUIRED)
find_package(${NAMESPACE}Messaging REQUIRED)
find_package(CompileSettingsDebug CONFIG REQUIRED)

add_library(${MODULE_NAME} SHARED
PluginInitializerService.cpp
Module.cpp
)

set_target_properties(${MODULE_NAME} PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES)

target_link_libraries(${MODULE_NAME}
PRIVATE
CompileSettingsDebug::CompileSettingsDebug
${NAMESPACE}Plugins::${NAMESPACE}Plugins
${NAMESPACE}Messaging::${NAMESPACE}Messaging)

target_include_directories(${MODULE_NAME}
PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>)

install(TARGETS ${MODULE_NAME}
DESTINATION ${CMAKE_INSTALL_LIBDIR}/${STORAGE_DIRECTORY}/plugins COMPONENT ${NAMESPACE}_Runtime)

write_config()
22 changes: 22 additions & 0 deletions PluginInitializerService/Module.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
* Copyright 2025 RDK Management
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "Module.h"

MODULE_NAME_DECLARATION(BUILD_REFERENCE)
31 changes: 31 additions & 0 deletions PluginInitializerService/Module.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
* Copyright 2025 RDK Management
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#ifndef MODULE_NAME
#define MODULE_NAME Plugin_PluginInitializerService
#endif

#include <core/core.h>
#include <plugins/plugins.h>
#include <messaging/messaging.h>

#undef EXTERNAL
#define EXTERNAL
9 changes: 9 additions & 0 deletions PluginInitializerService/PluginInitializerService.conf.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
startmode = "@PLUGIN_PLUGININITIALIZERSERVICE_STARTMODE@"

configuration = JSON()
if "@PLUGIN_PLUGININITIALIZERSERVICE_MAXPARALLEL@":
configuration.add("maxparallel", "@PLUGIN_PLUGININITIALIZERSERVICE_MAXPARALLEL@")

configuration.add("maxretries", "@PLUGIN_PLUGININITIALIZERSERVICE_DEFAULTMAXRETRIES@")
configuration.add("delay", "@PLUGIN_PLUGININITIALIZERSERVICE_DEFAULTDELAY@")

165 changes: 165 additions & 0 deletions PluginInitializerService/PluginInitializerService.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/*
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
* Copyright 2025 RDK Management
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "PluginInitializerService.h"

namespace Thunder {
namespace Plugin {

namespace {

static Metadata<PluginInitializerService>metadata(
// Version
1, 0, 0,
// Preconditions
{},
// Terminations
{},
// Controls
{}
);
}

const string PluginInitializerService::Initialize(PluginHost::IShell* service) {
string message;

ASSERT(service != nullptr);
ASSERT(_service == nullptr);

Config config;
config.FromString(service->ConfigLine());
const Exchange::Controller::IMetadata* metadata = service->QueryInterfaceByCallsign<Exchange::Controller::IMetadata>(_T(""));
ASSERT(metadata != nullptr);

Exchange::Controller::IMetadata::Data::BuildInfo buildinfo{};
VARIABLE_IS_NOT_USED Core::hresult result = metadata->BuildInfo(buildinfo);
metadata->Release();
metadata = nullptr;
ASSERT(result == Core::ERROR_NONE);

if (config.MaxParallel.IsSet() == true) {
_maxparallel = config.MaxParallel.Value();
if ((_maxparallel == 0) || (_maxparallel > (buildinfo.ThreadPoolCount-1))) {
message = _T("maxparallel configured incorrectly");
}
} else {
_maxparallel = ((buildinfo.ThreadPoolCount / 2) > 0 ? (buildinfo.ThreadPoolCount / 2) : 1 );
}
_maxretries = config.MaxRetries.Value();
_delay = config.Delay.Value();

if (message.empty() == true) {
_service = service;
_service->AddRef();
}

// note we will not register for the plugin state notifications here but only do that when it actually needed later on, and more importantly also stop listening when there are no more plugins to start
// (this to make sure hat even if this plugin is not deactivated when there are no more plugins to start it will not give any unnecessary overhead like constantly being notified on plugin state transitions)

return (message);
}

void PluginInitializerService::Deinitialize(PluginHost::IShell* service VARIABLE_IS_NOT_USED)
{
ASSERT((_service == nullptr) || (_service == service));

CancelAll();

if (_service != nullptr) {
_service->Release();
_service = nullptr;
}
}

string PluginInitializerService::Information() const {
return (string());
}

// note we will not specifically handle the connection from the client and the plugin being closed after we stored the callback.
// worst case: the connection being closed without abort called but in that case we will call the callback on a dead proxy and then
// release it, so no leaks (no need to go through the trouble to handle the dangling proxies here)
Core::hresult PluginInitializerService::Activate(const string& callsign, const Core::OptionalType<uint8_t>& maxnumberretries, const Core::OptionalType<uint16_t>& delay, IPluginAsyncStateControl::IActivationCallback* const cb)
{
TRACE(Trace::Information, (_T("Plugin Activate request received for plugin [%s]"), callsign.c_str()));

Core::hresult result = Core::ERROR_NONE;

PluginHost::IShell* requestedpluginShell = _service->QueryInterfaceByCallsign<PluginHost::IShell>(callsign);

if (requestedpluginShell != nullptr) {
PluginHost::IShell::state state = requestedpluginShell->State();
if ((state == PluginHost::IShell::DEACTIVATED) ||
(state == PluginHost::IShell::DEACTIVATION) ||
(state == PluginHost::IShell::ACTIVATION) || // this and the PRECONDITION are rather special cases, These plugin were already request to activate somewhere else, as we cannot just send a success notification (they might fail to initialize) we'll take them into account, if it was the result of a previous PluginInitializerService we'll find out anyway.
(state == PluginHost::IShell::PRECONDITION) ) // note PRECONDITION can be both reached during deactivation and activation, for the purpose here it does not matter, we only have to monitor if the activation succeeds and report back or monitor deinitialization failure and retry
{
TRACE(Trace::Information, (_T("Plugin Activate request received for plugin [%s] in state [%s]"), callsign.c_str(), Core::EnumerateType<PluginHost::IShell::state>(state).Data()));
if (NewPluginStarter(requestedpluginShell
, (maxnumberretries.IsSet() == true ? maxnumberretries.Value() : _maxretries)
, (delay.IsSet() == true ? delay.Value() : _delay)
, cb) == true) {
TRACE(Trace::DetailedInfo, (_T("Plugin start entry created for plugin [%s]"), callsign.c_str()));
} else {
TRACE(Trace::Warning, (_T("Plugin start entry not created for plugin [%s], there was already a pending request for this plugin"), callsign.c_str()));
result = Core::ERROR_INPROGRESS;
}
} else if ((state == PluginHost::IShell::ACTIVATED) ||
(state == PluginHost::IShell::HIBERNATED)) {
TRACE(Trace::Warning, (_T("Plugin Activate received for plugin [%s] that was already active, state [%s]"), callsign.c_str(), Core::EnumerateType<PluginHost::IShell::state>(state).Data()));

if (cb != nullptr)
{
TRACE(Trace::DetailedInfo, (_T("Result callback success called for plugin [%s]"), callsign.c_str()));
cb->Finished(callsign, Exchange::IPluginAsyncStateControl::IActivationCallback::state::SUCCESS, 0);
}
} else { // DESTROYED || UNAVAILABLE
TRACE(Trace::Error, (_T("Could not start activating plugin [%s] as it is in an illegal state [%s]"), callsign.c_str(), Core::EnumerateType<PluginHost::IShell::state>(state).Data()));
result = Core::ERROR_ILLEGAL_STATE;
}

requestedpluginShell->Release();
requestedpluginShell = nullptr;

} else {
TRACE(Trace::Error, (_T("Could not start activating plugin [%s] as it is unknown"), callsign.c_str()));
result = Core::ERROR_NOT_EXIST;
}

return result;
}

Core::hresult PluginInitializerService::AbortActivate(const string& callsign)
{
TRACE(Trace::Information, (_T("Plugin Abort Activate request received for plugin [%s]"), callsign.c_str()));

Core::hresult result = Core::ERROR_NONE;

if (CancelPluginStarter(callsign) == true) {
TRACE(Trace::DetailedInfo, (_T("Plugin Activate request was canceled for plugin [%s]"), callsign.c_str()));
} else {
// note this is not necessarily an error, the abort request could just have crossed the successful activation (or failure to do so for that matter) so it was just removed from the list
TRACE(Trace::Warning, (_T("Plugin Abort Activate request: plugin was not in activation list [%s]"), callsign.c_str()));
result = Core::ERROR_NOT_EXIST;
}

return result;
}

} // Plugin
} // Thunder
Loading
Loading