Integration#
Configuration#
The Launch Manager is currently configured with a single json file. See Configuration and Configuration examples for details about the Launch Manager configuration format.
Generating flatbuffer file#
The json configuration has to be converted to a flatbuffer file before it can be used by the Launch Manager.
The provided bazel function launch_manager_config handles the compilation
of the json configuration to flatbuffer files.
load("@score_lifecycle//:defs.bzl", "launch_manager_config")
# This is your launch manager json configuration
exports_files(["lm_config.json"])
# Afterwards, you can refer to the generated flatbuffer files with :example_config_gen
# The generated flatbuffer file has identical as the json configuration file, but with ".bin" file ending (example: "lm_config.bin")
launch_manager_config(
name ="example_config_gen",
config="//scripts/config_mapping:lm_config.json"
)
Location of the configuration file#
The Launch Manager can be started with a CLI flag defining the absolute or relative path to the configuration file:
launch_manager -c <config path>
Example: launch_manager -c /opt/launch_manager/etc/lm_config.bin
If -c is not specified, the Launch Manager will attempt to load the
configuration from the default path etc/launch_manager_config.bin.
State manager mw::com config#
An example mw::com config is provided with the following target
//score/launch_manager:example_com_config.
This is a single config that includes both Launch Manager and the
State Manager instance definition so they can be used by both.
For more information about the mw::com configuraiton please refer
to their documentation and tutorial at documentaiton
https://eclipse-score.github.io/communication/v0.5.0/score/mw/com/doc/tutorial/chapter_2/README.html#separate-configuration-files-for-provider-and-consumer
LmControlService service type#
LmControlService service type
{
"serviceTypes": [
{
"serviceTypeName": "/score/mw/lifecycle/LmControlService",
"version": {
"major": 1,
"minor": 0
},
"bindings": [
{
"binding": "SHM",
"serviceId": 7101,
"events": [
{
"eventName": "ActivationResult",
"eventId": 1
}
],
"methods": [
{
"methodName": "ActivateRunTarget",
"methodId": 2
},
{
"methodName": "GetActiveRunTarget",
"methodId": 3
}
]
}
]
}
],
"serviceInstances": [
{
"instanceSpecifier": "LaunchManager/StateManager/Instance",
"serviceTypeName": "/score/mw/lifecycle/LmControlService",
"version": {
"major": 1,
"minor": 0
},
"instances": [
{
"instanceId": 1,
"asil-level": "QM",
"binding": "SHM",
"events": [
{
"eventName": "ActivationResult",
"numberOfSampleSlots": 8,
"maxSubscribers": 1
}
],
"methods": [
{
"methodName": "ActivateRunTarget",
"queueSize": 1
},
{
"methodName": "GetActiveRunTarget",
"queueSize": 1
}
]
}
]
},
{
"instanceSpecifier": "StateManager/LaunchManager/Instance",
"serviceTypeName": "/score/mw/lifecycle/LmControlService",
"version": {
"major": 1,
"minor": 0
},
"instances": [
{
"instanceId": 1,
"asil-level": "QM",
"binding": "SHM",
"events": [
{
"eventName": "ActivationResult"
}
],
"methods": [
{
"methodName": "ActivateRunTarget",
"queueSize": 1
},
{
"methodName": "GetActiveRunTarget",
"queueSize": 1
}
]
}
]
}
],
"global": {
"asil-level": "QM"
}
}
Service types#
serviceTypeName
.serviceTypes[].serviceTypeName: "/score/mw/lifecycle/LmControlService"- This is the name of the Launch Manager service.version
.serviceTypes[].version: { "major": 1, "minor": 0 }- This is the version of the service interface.binding
.serviceTypes[].bindings[].binding: "SHM"- This is the communication mechanism..serviceTypes[].bindings[].serviceId: 7101- This is the numeric identifier of the service for this binding. Note this can be changed to any number, however has to be unique to any other service used by this application.events
.serviceTypes[].bindings[].events[]- Events offered by the service. Each event has a name and a numeric id. Note the ID can be changed to any number, however has to be unique to any other binding used by this application.{ "eventName": "ActivationResult", "eventId": 1 }
methods
.serviceTypes[].bindings[].methods[]- Methods offered by the service. Each method has a name and a numeric id. Note the ID can be changed to any number, however has to be unique to any other binding used by this application.{ "methodName": "ActivateRunTarget", "methodId": 2 }, { "methodName": "GetActiveRunTarget", "methodId": 3 }
Service instances#
The serviceInstances array defines the concrete instances of a service type.
Wwo instances of LmControlService are required, one used by the
Launch Manager (LaunchManager/StateManager/Instance) and one used by the
State Manager (StateManager/LaunchManager/Instance).
instanceSpecifier
.serviceInstances[].instanceSpecifier: "LaunchManager/StateManager/Instance"- This is the name an application uses to look up the instance.serviceTypeName
.serviceInstances[].serviceTypeName: "/score/mw/lifecycle/LmControlService"- This is the service type the instance is created from. It must match aserviceTypeNameinserviceTypes.version
.serviceInstances[].version: { "major": 1, "minor": 0 }- This is the version of the service type and must match the one inserviceTypes.instances
.serviceInstances[].instances[].instanceId- Numeric identifier of the instance. Note the ID can be changed to any number, however has to be unique to any other instance used by this application..serviceInstances[].instances[].asil-level- Safety integrity level of the instance, EitherQMorASIL-B..serviceInstances[].instances[].binding- Communication mechanism, shall beSHM..serviceInstances[].instances[].events[]- Per-method settings, for each methodmethodName..serviceInstances[].instances[].numberOfSampleSlots- Number of sample slots allocated for the event. This is only configured on the server instance i.e.LaunchManager/StateManager/Instance..serviceInstances[].instances[].maxSubscribers- Maximum number of simultaneous subscribers. This is only configured on the server instance i.e.LaunchManager/StateManager/Instance..serviceInstances[].instances[].methods[]- Per-method settings, for each methodmethodName..serviceInstances[].instances[].queueSize- Number of calls that can be queued for the method.{ "instanceId": 1, "asil-level": "QM", "binding": "SHM", "events": [ { "eventName": "ActivationResult", "numberOfSampleSlots": 8, "maxSubscribers": 1 } ], "methods": [ { "methodName": "ActivateRunTarget", "queueSize": 1 } ] }
global
.global.asil-level: "QM"This is the default safety integrity level for the whole configuration.
Implementation#
Starting a process#
A reporting process must signal to the Launch Manager that it has started successfully by calling the lifecycle API for the language it is implemented in.
A ready_timeout_ms can be configured for each component.
If the process does not report Running within that timeout, the Launch
Manager terminates the process and registers an error.
Stopping a process#
A process can be configured to terminate in 2 ways:
Self-terminating - The process terminates whenever it wants.
Non-self-terminating - The process remains alive until LCM requests the process to end using a
SIGTERMsignal.
For a process to support being terminated by LCM, it needs to respond to
a SIGTERM signal by ending ongoing tasks, freeing resources and
exiting.
Note that a Self-terminating also recieves the SIGTERM signal when LCM
decides to deactivate it.
If a process does not terminate after receiving a SIGTERM, and a
shutdown_timeout_ms is configured, then after the timeout is fired a
SIGKILL is sent and the process is forcefully terminated.
Examples#
C Reporting Process
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include "score/mw/lifecycle/report_running.h"
const struct timespec interval = {
.tv_sec = 0,
.tv_nsec = 50000000,
};
volatile sig_atomic_t exitRequested = 0;
static void sigTermHandler(int signal)
{
exitRequested = 1;
}
int main(int argc, char* argv[]){
assert(signal(SIGTERM, sigTermHandler));
// report running
int8_t result = score_mw_lifecycle_report_running();
// check report was successful
if(result != 0){
printf("Failed to report kRunning to LCM! Terminating");
return 1;
}
// wait until lm wants to terminate
while(exitRequested == 0){
nanosleep(&interval, NULL);
}
return 0;
}
C++ Reporting Process
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
#include <unistd.h>
#include <atomic>
#include <cassert>
#include <csignal>
#include <cstdlib>
#include <iostream>
#include <score/mw/lifecycle/report_running.h>
volatile std::sig_atomic_t exitRequested{0};
void sigTermHandler(int)
{
exitRequested = 1;
}
int main(int argc, char* argv[])
{
// register signal handler so that lcm can request a termination
assert(signal(SIGTERM, sigTermHandler));
// report running state
score::mw::lifecycle::report_running();
// do some work
// wait until lm wants to terminate
while (exitRequested == 0)
{
pause();
}
return EXIT_SUCCESS;
}
Rust Reporting Process
// *******************************************************************************
// Copyright (c) 2026 Contributors to the Eclipse Foundation
//
// See the NOTICE file(s) distributed with this work for additional
// information regarding copyright ownership.
//
// This program and the accompanying materials are made available under the
// terms of the Apache License Version 2.0 which is available at
// <https://www.apache.org/licenses/LICENSE-2.0>
//
// SPDX-License-Identifier: Apache-2.0
// *******************************************************************************
use std::sync::atomic::{AtomicBool, Ordering};
const SIGTERM: i32 = 15;
static STOP: AtomicBool = AtomicBool::new(false);
extern "C" {
fn signal(signum: i32, handler: extern "C" fn(i32)) -> usize;
}
extern "C" fn sigterm_handler(_: i32) {
STOP.store(true, Ordering::Relaxed);
}
fn main() -> Result<(), &'static str> {
// register signal handler so that lcm can request a termination
unsafe {
signal(SIGTERM, sigterm_handler);
}
// report running and check result
if !lifecycle_client_rs::report_running() {
return Err("Failed to report execution state");
}
// do work until lm wants to terminate
while !STOP.load(Ordering::Relaxed) {
std::thread::sleep(std::time::Duration::from_millis(100));
}
Ok(())
}
The Lifecycle Interface also offers the run_application API, which
removes the boilerplate from a reporting process.
It:
- Handles the SIGTERM signal.
- Structures the application into an initialization phase and a running phase.
- Reports the Running state in the background once initialization is done.
C++ Lifecycle Application
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
#include <cstdlib>
#include <score/mw/lifecycle/application.h>
#include <score/mw/lifecycle/runapplication.h>
class LifecycleApp final : public score::mw::lifecycle::Application
{
public:
// called before the process reports Running to the Launch Manager
std::int32_t Initialize(const score::mw::lifecycle::ApplicationContext& appCtx) override
{
// read arguments and set up resources here
return EXIT_SUCCESS;
}
// called once initialization succeeded, returns when termination is requested
std::int32_t Run(const score::cpp::stop_token& stopToken) override
{
while (!stopToken.stop_requested())
{
// do some work
}
return EXIT_SUCCESS;
}
};
int main(int argc, char** argv)
{
return score::mw::lifecycle::run_application<LifecycleApp>(argc, argv);
}
State management#
A State Manager is an application that decides which run-targets shall be
active by communicating with the Launch Manager using the ILmControl
interface.
The State Manager is itself a managed component.
Before calling activate_run_target, it must report the Running state to the
Launch Manager via any of the Lifecycle Interfaces.
Otherwise, the Launch Manager does not consider the State
Manager ready, which can lead to errors.
Additionally, the State Manager component must have
application_profile.application_type set to State_Manager.
Example#
State Manager example
/********************************************************************************
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
********************************************************************************/
#include <unistd.h>
#include <atomic>
#include <cassert>
#include <chrono>
#include <csignal>
#include <iostream>
#include "score/mw/com/runtime.h"
#include "score/string_manipulation/arguments/arguments.h"
#include <score/mw/lifecycle/ilm_control.hpp>
#include <score/mw/lifecycle/report_running.h>
using namespace std::literals::chrono_literals;
/// Used to signal if the startup run target switch was succesfull.
std::atomic<bool> startup_finished{false};
/// Used if a termination was requested from a signal.
std::atomic<bool> exitRequested{false};
void signalHandler(int signal)
{
exitRequested = true;
}
int main(int argc, const char* argv[])
{
// initialize com, needed if you are giving the mw_conf.json as an argument
score::mw::com::runtime::InitializeRuntime(score::string_manipulation::GetArguments(argc, argv));
// register signal handler and assert success
assert(signal(SIGTERM, signalHandler));
// report running to LM
score::mw::lifecycle::report_running();
// create a client
auto client_result = score::mw::lifecycle::ILmControl::Create("StateManager/LaunchManager/Instance");
if (!client_result.has_value())
{
std::cerr << "Failed to create client " << client_result.error() << std::endl;
return EXIT_FAILURE;
}
// get the client from the result
std::unique_ptr<score::mw::lifecycle::ILmControl> client = std::move(client_result).value();
// register a method that gets called when a run target is switched
const auto register_result = client->register_run_target_activation_callback(
[]([[maybe_unused]] score::mw::lifecycle::RunTargetActivationSource source,
score::mw::lifecycle::RunTargetName target) {
// signal that the startup was completed
if (source == score::mw::lifecycle::RunTargetActivationSource::kInitialActivation)
{
std::cout << "Initial activation succesfull! activated run target " << target << std::endl;
startup_finished.store(true);
}
else
{
std::cout << "Successfully activated Run Target " << target << std::endl;
}
});
if (!register_result.has_value())
{
std::cerr << "Failed to register activation callback " << register_result.error() << std::endl;
return EXIT_FAILURE;
}
while (startup_finished.load())
{
std::this_thread::sleep_for(100ms);
}
// activate a different run target
const auto result = client->activate_run_target(score::mw::lifecycle::RunTargetName{"Running"}, true);
if (result.has_value())
{
std::cout << "Successfully requested Run Target " << std::endl;
}
else
{
std::cerr << "Requesting Run Target "
<< " failed with error: " << result.error().Message() << std::endl;
}
// wait until lm wants to terminate
while (!exitRequested)
{
pause();
}
return EXIT_SUCCESS;
}