sandbox: support for local state-report handling

Fixes #3647
This commit is contained in:
Norman Feske 2020-02-11 16:42:31 +01:00 committed by Christian Helmuth
parent 725d16e18e
commit 9b0fbf000e
5 changed files with 115 additions and 49 deletions

View File

@ -32,6 +32,18 @@ class Genode::Sandbox : Noncopyable
template <typename>
class Local_service;
/**
* Interface invoked each time an interesting state change occurs
*
* The handler is supposed to inspect the state as provided by
* the 'generate_state_report' method and respond by adjusting
* the sandbox configuration via 'apply_config'.
*/
struct State_handler : Interface
{
virtual void handle_sandbox_state() = 0;
};
private:
friend class Local_service_base;
@ -46,9 +58,16 @@ class Genode::Sandbox : Noncopyable
public:
Sandbox(Env &env);
Sandbox(Env &, State_handler &);
void apply_config(Xml_node const &);
/**
* Generate state report as configured by the <report> config node
*
* \throw Xml_generator::Buffer_exceeded
*/
void generate_state_report(Xml_generator &) const;
};

View File

@ -15,6 +15,7 @@
#include <base/component.h>
#include <base/attached_rom_dataspace.h>
#include <os/sandbox.h>
#include <os/reporter.h>
namespace Init {
@ -24,11 +25,11 @@ namespace Init {
}
struct Init::Main
struct Init::Main : Sandbox::State_handler
{
Env &_env;
Sandbox _sandbox { _env };
Sandbox _sandbox { _env, *this };
Attached_rom_dataspace _config { _env, "config" };
@ -37,15 +38,62 @@ struct Init::Main
Signal_handler<Main> _resource_avail_handler {
_env.ep(), *this, &Main::_handle_resource_avail };
Constructible<Reporter> _reporter { };
size_t _report_buffer_size = 0;
void _handle_config()
{
_config.update();
_sandbox.apply_config(_config.xml());
Xml_node const config = _config.xml();
bool reporter_enabled = false;
config.with_sub_node("report", [&] (Xml_node report) {
reporter_enabled = true;
/* (re-)construct reporter whenever the buffer size is changed */
Number_of_bytes const buffer_size =
report.attribute_value("buffer", Number_of_bytes(4096));
if (buffer_size != _report_buffer_size || !_reporter.constructed()) {
_report_buffer_size = buffer_size;
_reporter.construct(_env, "state", "state", _report_buffer_size);
}
});
if (_reporter.constructed())
_reporter->enabled(reporter_enabled);
_sandbox.apply_config(config);
}
Signal_handler<Main> _config_handler {
_env.ep(), *this, &Main::_handle_config };
/**
* Sandbox::State_handler interface
*/
void handle_sandbox_state() override
{
try {
Reporter::Xml_generator xml(*_reporter, [&] () {
_sandbox.generate_state_report(xml); });
}
catch (Xml_generator::Buffer_exceeded) {
error("state report exceeds maximum size");
/* try to reflect the error condition as state report */
try {
Reporter::Xml_generator xml(*_reporter, [&] () {
xml.attribute("error", "report buffer exceeded"); });
}
catch (...) { }
}
}
Main(Env &env) : _env(env)
{
_config.sigh(_config_handler);

View File

@ -145,7 +145,7 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer,
*/
Cap_quota default_caps() override { return _default_caps; }
State_reporter _state_reporter { _env, *this };
State_reporter _state_reporter;
Heartbeat _heartbeat { _env, _children, _state_reporter };
@ -157,12 +157,19 @@ struct Genode::Sandbox::Library : ::Sandbox::State_reporter::Producer,
Server _server { _env, _heap, _child_services, _state_reporter };
Library(Env &env, Heap &heap, Registry<Local_service> &local_services)
Library(Env &env, Heap &heap, Registry<Local_service> &local_services,
State_handler &state_handler)
:
_env(env), _heap(heap), _local_services(local_services)
_env(env), _heap(heap), _local_services(local_services),
_state_reporter(_env, *this, state_handler)
{ }
void apply_config(Xml_node const &);
void generate_state_report(Xml_generator &xml) const
{
_state_reporter.generate(xml);
}
};
@ -612,9 +619,15 @@ void Genode::Sandbox::apply_config(Xml_node const &config)
}
Genode::Sandbox::Sandbox(Env &env)
void Genode::Sandbox::generate_state_report(Xml_generator &xml) const
{
_library.generate_state_report(xml);
}
Genode::Sandbox::Sandbox(Env &env, State_handler &state_handler)
:
_heap(env.ram(), env.rm()),
_library(*new (_heap) Library(env, _heap, _local_services))
_library(*new (_heap) Library(env, _heap, _local_services, state_handler))
{ }

View File

@ -15,14 +15,15 @@
#define _LIB__SANDBOX__STATE_REPORTER_H_
/* Genode includes */
#include <os/reporter.h>
#include <timer_session/connection.h>
#include <os/sandbox.h>
/* local includes */
#include "report.h"
namespace Sandbox { class State_reporter; }
class Sandbox::State_reporter : public Report_update_trigger
{
public:
@ -35,14 +36,12 @@ class Sandbox::State_reporter : public Report_update_trigger
private:
using State_handler = Genode::Sandbox::State_handler;
Env &_env;
Producer &_producer;
Constructible<Reporter> _reporter { };
size_t _buffer_size = 0;
Reconstructible<Report_detail> _report_detail { };
uint64_t _report_delay_ms = 0;
@ -68,62 +67,43 @@ class Sandbox::State_reporter : public Report_update_trigger
bool _scheduled = false;
State_handler &_state_handler;
void _handle_timer()
{
_scheduled = false;
try {
Reporter::Xml_generator xml(*_reporter, [&] () {
if (_version.valid())
xml.attribute("version", _version);
_producer.produce_state_report(xml, *_report_detail);
});
}
catch(Xml_generator::Buffer_exceeded) {
error("state report exceeds maximum size");
/* try to reflect the error condition as state report */
try {
Reporter::Xml_generator xml(*_reporter, [&] () {
xml.attribute("error", "report buffer exceeded"); });
}
catch (...) { }
}
_state_handler.handle_sandbox_state();
}
public:
State_reporter(Env &env, Producer &producer)
State_reporter(Env &env, Producer &producer, State_handler &state_handler)
:
_env(env), _producer(producer)
_env(env), _producer(producer),
_state_handler(state_handler)
{ }
void generate(Xml_generator &xml) const
{
if (_version.valid())
xml.attribute("version", _version);
if (_report_detail.constructed())
_producer.produce_state_report(xml, *_report_detail);
}
void apply_config(Xml_node config)
{
try {
Xml_node report = config.sub_node("report");
/* (re-)construct reporter whenever the buffer size is changed */
Number_of_bytes const buffer_size =
report.attribute_value("buffer", Number_of_bytes(4096));
if (buffer_size != _buffer_size || !_reporter.constructed()) {
_buffer_size = buffer_size;
_reporter.construct(_env, "state", "state", _buffer_size);
}
_report_detail.construct(report);
_report_delay_ms = report.attribute_value("delay_ms", 100UL);
_reporter->enabled(true);
}
catch (Xml_node::Nonexistent_sub_node) {
_report_detail.construct();
_report_delay_ms = 0;
if (_reporter.constructed())
_reporter->enabled(false);
}
bool trigger_update = false;

View File

@ -48,7 +48,13 @@ struct Test::Main : Sandbox::Local_service_base::Wakeup
Heap _heap { _env.ram(), _env.rm() };
Sandbox _sandbox { _env };
struct State_handler : Sandbox::State_handler
{
void handle_sandbox_state() override { }
} _state_handler { };
Sandbox _sandbox { _env, _state_handler };
typedef Sandbox::Local_service<Log_session_component> Log_service;