Add RPC communication between container manager and client

This commit is contained in:
Simon Fels 2016-08-17 11:31:13 +02:00
commit 3d05c50c8b
24 changed files with 542 additions and 104 deletions

View file

@ -23,11 +23,18 @@ protobuf_generate_cpp(
GENERATED_PROTOBUF_BRIDGE_SRCS GENERATED_PROTOBUF_BRIDGE_HDRS GENERATED_PROTOBUF_BRIDGE_SRCS GENERATED_PROTOBUF_BRIDGE_HDRS
anbox/protobuf/anbox_bridge.proto) anbox/protobuf/anbox_bridge.proto)
protobuf_generate_cpp(
GENERATED_PROTOBUF_CONTAINER_SRCS GENERATED_PROTOBUF_CONTAINER_HDRS
anbox/protobuf/anbox_container.proto)
add_library(anbox-protobuf add_library(anbox-protobuf
${GENERATED_PROTOBUF_BRIDGE_SRCS} ${GENERATED_PROTOBUF_BRIDGE_SRCS}
${GENERATED_PROTOBUF_BRIDGE_HDRS} ${GENERATED_PROTOBUF_BRIDGE_HDRS}
${GENERATED_PROTOBUF_RPC_SRCS} ${GENERATED_PROTOBUF_RPC_SRCS}
${GENERATED_PROTOBUF_RPC_HDRS} ${GENERATED_PROTOBUF_RPC_HDRS}
${GENERATED_PROTOBUF_CONTAINER_SRCS}
${GENERATED_PROTOBUF_CONTAINER_HDRS}
anbox/protobuf/google_protobuf_guard.cpp) anbox/protobuf/google_protobuf_guard.cpp)
target_link_libraries(anbox-protobuf target_link_libraries(anbox-protobuf
${PROTOBUF_LITE_LIBRARIES}) ${PROTOBUF_LITE_LIBRARIES})
@ -51,8 +58,12 @@ set(SOURCES
anbox/container/service.cpp anbox/container/service.cpp
anbox/container/client.cpp anbox/container/client.cpp
anbox/container/configuration.h
anbox/container/container.cpp anbox/container/container.cpp
anbox/container/lxc_container.cpp anbox/container/lxc_container.cpp
anbox/container/management_api_stub.cpp
anbox/container/management_api_skeleton.cpp
anbox/container/management_api_message_processor.cpp
anbox/network/credentials.cpp anbox/network/credentials.cpp
anbox/network/message_sender.h anbox/network/message_sender.h

View file

@ -147,7 +147,23 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
})); }));
container::Client container(rt); container::Client container(rt);
container::Configuration container_configuration;
container_configuration.bind_mounts = {
{ qemud_connector->socket_file(), "/dev/qemud" },
{ qemu_pipe_connector->socket_file(), "/dev/qemu_pipe" },
{ bridge_connector->socket_file(), "/dev/anbox_bridge" },
{ config::host_share_path(), config::container_android_share_path()},
{ config::host_android_data_path(), "/data" },
{ config::host_android_cache_path(), "/cache" },
{ config::host_android_storage_path(), "/storage" },
{ config::host_input_device_path(), "/dev/input" },
{ "/dev/binder", "/dev/binder" },
{ "/dev/ashmem", "/dev/ashmem" },
};
dispatcher->dispatch([&]() {
container.start_container(container_configuration);
});
auto bus = bus_factory_(); auto bus = bus_factory_();
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service())); bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));

View file

@ -37,11 +37,7 @@ anbox::cmds::StartContainer::StartContainer()
rt->start(); rt->start();
auto container = std::make_shared<container::LxcContainer>();
container->start();
trap->run(); trap->run();
container->stop();
rt->stop(); rt->stop();
return 0; return 0;

View file

@ -41,14 +41,14 @@ std::string in_snap_dir(const std::string &path) {
} }
std::string in_snap_data_dir(const std::string &path) { std::string in_snap_data_dir(const std::string &path) {
return prefix_dir_from_env(path, "SNAP_DATA"); return prefix_dir_from_env(path, "SNAP_COMMON");
} }
std::string in_snap_user_data_dir(const std::string &path) { std::string in_snap_user_data_dir(const std::string &path) {
return prefix_dir_from_env(path, "SNAP_USER_DATA"); return prefix_dir_from_env(path, "SNAP_USER_COMMON");
} }
std::string home_path() { std::string home_dir() {
static std::string path; static std::string path;
if (path.empty()) { if (path.empty()) {
path = utils::get_env_value("HOME", ""); path = utils::get_env_value("HOME", "");
@ -69,7 +69,7 @@ std::string runtime_dir() {
} }
std::string state_dir() { std::string state_dir() {
static std::string path = "/var/lib"; static std::string path = in_snap_data_dir("/var/lib");
return path; return path;
} }
@ -85,7 +85,7 @@ std::string socket_path() {
} }
std::string data_path() { std::string data_path() {
static std::string path = utils::string_format("%s/.local/share/anbox/data", home_path()); static std::string path = utils::string_format("%s/.anbox/data", home_dir());
return path; return path;
} }
@ -104,13 +104,13 @@ std::string container_socket_path() {
return path; return path;
} }
std::string host_share_path() { std::string host_input_device_path() {
static std::string path = utils::string_format("%s/android-share", data_path()); static std::string path = utils::string_format("%s/anbox/input-devices", runtime_dir());
return path; return path;
} }
std::string host_input_device_path() { std::string host_share_path() {
static std::string path = utils::string_format("%s/input-devices", data_path()); static std::string path = utils::string_format("%s/android-share", data_path());
return path; return path;
} }

View file

@ -16,16 +16,53 @@
*/ */
#include "anbox/container/client.h" #include "anbox/container/client.h"
#include "anbox/container/management_api_stub.h"
#include "anbox/network/local_socket_messenger.h"
#include "anbox/rpc/pending_call_cache.h"
#include "anbox/rpc/channel.h"
#include "anbox/rpc/message_processor.h"
#include "anbox/config.h" #include "anbox/config.h"
#include "anbox/logger.h" #include "anbox/logger.h"
namespace ba = boost::asio;
namespace bs = boost::system;
namespace anbox { namespace anbox {
namespace container { namespace container {
Client::Client(const std::shared_ptr<Runtime> &rt) : Client::Client(const std::shared_ptr<Runtime> &rt) :
messenger_(config::container_socket_path(), rt) { messenger_(std::make_shared<network::LocalSocketMessenger>(config::container_socket_path(), rt)),
pending_calls_(std::make_shared<rpc::PendingCallCache>()),
rpc_channel_(std::make_shared<rpc::Channel>(pending_calls_, messenger_)),
management_api_(std::make_shared<ManagementApiStub>(rpc_channel_)),
processor_(std::make_shared<rpc::MessageProcessor>(messenger_, pending_calls_)) {
read_next_message();
} }
Client::~Client() { Client::~Client() {
} }
void Client::start_container(const Configuration &configuration) {
management_api_->start_container(configuration);
}
void Client::read_next_message()
{
auto callback = std::bind(&Client::on_read_size,
this, std::placeholders::_1, std::placeholders::_2);
messenger_->async_receive_msg(callback, ba::buffer(buffer_));
}
void Client::on_read_size(const boost::system::error_code& error, std::size_t bytes_read)
{
if (error)
BOOST_THROW_EXCEPTION(std::runtime_error(error.message()));
std::vector<std::uint8_t> data(bytes_read);
std::copy(buffer_.data(), buffer_.data() + bytes_read, data.data());
if (processor_->process_data(data))
read_next_message();
}
} // namespace container } // namespace container
} // namespace anbox } // namespace anbox

View file

@ -18,18 +18,37 @@
#ifndef ANBOX_CONTAINER_CLIENT_H_ #ifndef ANBOX_CONTAINER_CLIENT_H_
#define ANBOX_CONTAINER_CLIENT_H_ #define ANBOX_CONTAINER_CLIENT_H_
#include "anbox/network/local_socket_messenger.h"
#include "anbox/runtime.h" #include "anbox/runtime.h"
#include "anbox/container/configuration.h"
namespace anbox { namespace anbox {
namespace rpc {
class PendingCallCache;
class Channel;
class MessageProcessor;
} // namespace rpc
namespace network {
class LocalSocketMessenger;
} // namespace network
namespace container { namespace container {
class ManagementApiStub;
class Client { class Client {
public: public:
Client(const std::shared_ptr<Runtime> &rt); Client(const std::shared_ptr<Runtime> &rt);
~Client(); ~Client();
void start_container(const Configuration &configuration);
private: private:
network::LocalSocketMessenger messenger_; void read_next_message();
void on_read_size(const boost::system::error_code& ec, std::size_t bytes_read);
std::shared_ptr<network::LocalSocketMessenger> messenger_;
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<rpc::Channel> rpc_channel_;
std::shared_ptr<ManagementApiStub> management_api_;
std::shared_ptr<rpc::MessageProcessor> processor_;
std::array<std::uint8_t, 8192> buffer_;
}; };
} // namespace container } // namespace container
} // namespace anbox } // namespace anbox

View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_CONTAINER_CONFIGURATION_H_
#define ANBOX_CONTAINER_CONFIGURATION_H_
#include <string>
#include <map>
namespace anbox {
namespace container {
struct Configuration {
std::map<std::string,std::string> bind_mounts;
};
} // namespace container
} // namespace anbox
#endif

View file

@ -18,8 +18,10 @@
#ifndef ANBOX_CONTAINER_CONTAINER_H_ #ifndef ANBOX_CONTAINER_CONTAINER_H_
#define ANBOX_CONTAINER_CONTAINER_H_ #define ANBOX_CONTAINER_CONTAINER_H_
#include "anbox/container/configuration.h"
#include <string> #include <string>
#include <vector> #include <map>
namespace anbox { namespace anbox {
namespace container { namespace container {
@ -33,7 +35,7 @@ public:
}; };
// Start the container in background // Start the container in background
virtual void start() = 0; virtual void start(const Configuration &configuration) = 0;
// Stop a running container // Stop a running container
virtual void stop() = 0; virtual void stop() = 0;

View file

@ -24,15 +24,14 @@
#include <map> #include <map>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include <boost/filesystem.hpp>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/capability.h> #include <sys/capability.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/prctl.h> #include <sys/prctl.h>
namespace { namespace fs = boost::filesystem;
static constexpr char *kAndroidShellCommand{"/system/bin/ls"};
}
namespace anbox { namespace anbox {
namespace container { namespace container {
@ -46,16 +45,19 @@ LxcContainer::LxcContainer() :
config::host_android_data_path(), config::host_android_data_path(),
config::host_android_cache_path(), config::host_android_cache_path(),
config::host_android_storage_path(), config::host_android_storage_path(),
config::host_input_device_path(),
}); });
} }
LxcContainer::~LxcContainer() { LxcContainer::~LxcContainer() {
DEBUG("");
stop();
if (container_) if (container_)
lxc_container_put(container_); lxc_container_put(container_);
} }
void LxcContainer::start() { void LxcContainer::start(const Configuration &configuration) {
if (getuid() != 0) if (getuid() != 0)
BOOST_THROW_EXCEPTION(std::runtime_error("You have to start the container as root")); BOOST_THROW_EXCEPTION(std::runtime_error("You have to start the container as root"));
@ -112,30 +114,21 @@ void LxcContainer::start() {
set_config_item("lxc.aa_profile", "unconfined"); set_config_item("lxc.aa_profile", "unconfined");
#endif #endif
std::map<std::string,std::string> bind_mount_dirs = { for (const auto &bind_mount : configuration.bind_mounts) {
{ config::host_share_path(), config::container_android_share_path() }, std::string create_type = "file";
{ config::host_android_data_path(), "data" },
{ config::host_android_cache_path(), "cache" }, if (fs::is_directory(bind_mount.first))
{ config::host_android_storage_path(), "storage" }, create_type = "dir";
{ config::host_input_device_path(), "dev/input" },
}; auto target_path = bind_mount.second;
// LXC wants target paths relative to the container rootfs so
// prividing an absolute path doesn't work.
if (utils::string_starts_with(target_path, "/"))
target_path.erase(0, 1);
for (const auto &item : bind_mount_dirs) {
set_config_item("lxc.mount.entry", set_config_item("lxc.mount.entry",
utils::string_format("%s %s none bind,create=dir,optional 0 0", item.first, item.second)); utils::string_format("%s %s none bind,create=%s,optional 0 0",
} bind_mount.first, target_path, create_type));
std::map<std::string,std::string> bind_mount_files = {
{ "/dev/binder", "dev/binder" },
{ "/dev/ashmem", "dev/ashmem" },
{ utils::string_format("%s/qemu_pipe", config::socket_path()), "dev/qemu_pipe" },
{ utils::string_format("%s/qemud", config::socket_path()), "dev/qemud" },
{ utils::string_format("%s/anbox_bridge", config::socket_path()), "dev/anbox_bridge" },
};
for (const auto &item : bind_mount_files) {
set_config_item("lxc.mount.entry",
utils::string_format("%s %s none bind,create=file,optional 0 0", item.first, item.second));
} }
if (!container_->save_config(container_, nullptr)) if (!container_->save_config(container_, nullptr))
@ -144,6 +137,8 @@ void LxcContainer::start() {
if (not container_->start(container_, 0, nullptr)) if (not container_->start(container_, 0, nullptr))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to start container")); BOOST_THROW_EXCEPTION(std::runtime_error("Failed to start container"));
state_ = Container::State::running;
DEBUG("Container successfully started"); DEBUG("Container successfully started");
} }
@ -154,6 +149,8 @@ void LxcContainer::stop() {
if (not container_->stop(container_)) if (not container_->stop(container_))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to stop container")); BOOST_THROW_EXCEPTION(std::runtime_error("Failed to stop container"));
state_ = Container::State::inactive;
DEBUG("Container successfully stopped"); DEBUG("Container successfully stopped");
} }

View file

@ -31,7 +31,7 @@ public:
LxcContainer(); LxcContainer();
~LxcContainer(); ~LxcContainer();
void start() override; void start(const Configuration &configuration) override;
void stop() override; void stop() override;
State state() override; State state() override;

View file

@ -0,0 +1,45 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/container/management_api_message_processor.h"
#include "anbox/container/management_api_skeleton.h"
#include "anbox/rpc/template_message_processor.h"
#include "anbox_bridge.pb.h"
#include "anbox_container.pb.h"
namespace anbox {
namespace container {
ManagementApiMessageProcessor::ManagementApiMessageProcessor(const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<ManagementApiSkeleton> &server) :
rpc::MessageProcessor(sender, pending_calls),
server_(server) {
}
ManagementApiMessageProcessor::~ManagementApiMessageProcessor() {
}
void ManagementApiMessageProcessor::dispatch(rpc::Invocation const& invocation) {
if (invocation.method_name() == "start_container")
invoke(this, server_.get(), &ManagementApiSkeleton::start_container, invocation);
}
void ManagementApiMessageProcessor::process_event_sequence(const std::string&) {
}
} // namespace container
} // namespace anbox

View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_CONTAINER_MANAGEMENT_API_MESSAGE_PROCESSOR_H_
#define ANBOX_CONTAINER_MANAGEMENT_API_MESSAGE_PROCESSOR_H_
#include "anbox/rpc/message_processor.h"
namespace anbox {
namespace container {
class ManagementApiSkeleton;
class ManagementApiMessageProcessor : public rpc::MessageProcessor {
public:
ManagementApiMessageProcessor(const std::shared_ptr<network::MessageSender> &sender,
const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<ManagementApiSkeleton> &server);
~ManagementApiMessageProcessor();
void dispatch(rpc::Invocation const& invocation) override;
void process_event_sequence(const std::string &event) override;
private:
std::shared_ptr<ManagementApiSkeleton> server_;
};
} // namespace anbox
} // namespace network
#endif

View file

@ -0,0 +1,69 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/container/management_api_skeleton.h"
#include "anbox/container/container.h"
#include "anbox/container/configuration.h"
#include "anbox/defer_action.h"
#include "anbox/utils.h"
#include "anbox/logger.h"
#include "anbox_rpc.pb.h"
#include "anbox_container.pb.h"
namespace anbox {
namespace container {
ManagementApiSkeleton::ManagementApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<Container> &container) :
pending_calls_(pending_calls),
container_(container) {
}
ManagementApiSkeleton::~ManagementApiSkeleton() {
}
void ManagementApiSkeleton::start_container(anbox::protobuf::container::StartContainer const *request,
anbox::protobuf::rpc::Void *response,
google::protobuf::Closure *done) {
if (container_->state() == Container::State::running) {
response->set_error("Container is already running");
done->Run();
return;
}
Configuration container_configuration;
const auto configuration = request->configuration();
for (int n = 0; n < configuration.bind_mounts_size(); n++) {
const auto bind_mount = configuration.bind_mounts(n);
container_configuration.bind_mounts.insert({ bind_mount.source(), bind_mount.target() });
}
try {
container_->start(container_configuration);
}
catch (std::exception &err) {
response->set_error(utils::string_format("Failed to start container: %s", err.what()));
}
DEBUG("");
done->Run();
}
} // namespace container
} // namespace anbox

View file

@ -0,0 +1,60 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_CONTAINER_MANAGEMENT_API_SKELETON_H_
#define ANBOX_CONTAINER_MANAGEMENT_API_SKELETON_H_
#include <memory>
namespace google {
namespace protobuf {
class Closure;
} // namespace protobuf
} // namespace google
namespace anbox {
namespace protobuf {
namespace rpc {
class Void;
} // namespace rpc
namespace container {
class StartContainer;
} // namespace container
} // namespace protobuf
namespace rpc {
class PendingCallCache;
} // namespace rpc
namespace container {
class Container;
class ManagementApiSkeleton {
public:
ManagementApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<Container> &container);
~ManagementApiSkeleton();
void start_container(anbox::protobuf::container::StartContainer const *request,
anbox::protobuf::rpc::Void *response,
google::protobuf::Closure *done);
private:
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<Container> container_;
};
} // namespace container
} // namespace anbox
#endif

View file

@ -0,0 +1,70 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/container/management_api_stub.h"
#include "anbox/rpc/channel.h"
#include "anbox/logger.h"
#include "anbox_rpc.pb.h"
#include "anbox_container.pb.h"
namespace anbox {
namespace container {
ManagementApiStub::ManagementApiStub(const std::shared_ptr<rpc::Channel> &channel) :
channel_(channel) {
}
ManagementApiStub::~ManagementApiStub() {
}
void ManagementApiStub::start_container(const Configuration &configuration) {
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::container::StartContainer message;
auto message_configuration = new protobuf::container::Configuration;
for (const auto item : configuration.bind_mounts) {
auto bind_mount_message = message_configuration->add_bind_mounts();
bind_mount_message->set_source(item.first);
bind_mount_message->set_target(item.second);
}
message.set_allocated_configuration(message_configuration);
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
start_wait_handle_.expect_result();
}
channel_->call_method("start_container",
&message,
c->response.get(),
google::protobuf::NewCallback(this, &ManagementApiStub::container_started, c.get()));
start_wait_handle_.wait_for_all();
if (c->response->has_error())
throw std::runtime_error(c->response->error());
}
void ManagementApiStub::container_started(Request<protobuf::rpc::Void> *request) {
(void) request;
DEBUG("");
start_wait_handle_.result_received();
}
} // namespace container
} // namespace anbox

View file

@ -0,0 +1,61 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_CONTAINER_MANAGEMENT_API_STUB_H_
#define ANBOX_CONTAINER_MANAGEMENT_API_STUB_H_
#include "anbox/do_not_copy_or_move.h"
#include "anbox/container/configuration.h"
#include "anbox/common/wait_handle.h"
#include <memory>
namespace anbox {
namespace protobuf {
namespace rpc {
class Void;
} // namespace rpc
} // namespace protobuf
namespace rpc {
class Channel;
} // namespace rpc
namespace container {
class ManagementApiStub : public DoNotCopyOrMove {
public:
ManagementApiStub(const std::shared_ptr<rpc::Channel> &channel);
~ManagementApiStub();
void start_container(const Configuration &configuration);
private:
template<typename Response>
struct Request {
Request() : response(std::make_shared<Response>()), success(true) { }
std::shared_ptr<Response> response;
bool success;
};
void container_started(Request<protobuf::rpc::Void> *request);
mutable std::mutex mutex_;
std::shared_ptr<rpc::Channel> channel_;
common::WaitHandle start_wait_handle_;
};
} // namespace container
} // namespace anbox
#endif

View file

@ -20,7 +20,11 @@
#include "anbox/network/delegate_message_processor.h" #include "anbox/network/delegate_message_processor.h"
#include "anbox/network/socket_messenger.h" #include "anbox/network/socket_messenger.h"
#include "anbox/qemu/null_message_processor.h" #include "anbox/qemu/null_message_processor.h"
#include "anbox/rpc/pending_call_cache.h"
#include "anbox/rpc/channel.h"
#include "anbox/container/lxc_container.h" #include "anbox/container/lxc_container.h"
#include "anbox/container/management_api_message_processor.h"
#include "anbox/container/management_api_skeleton.h"
#include "anbox/config.h" #include "anbox/config.h"
#include "anbox/logger.h" #include "anbox/logger.h"
@ -40,8 +44,6 @@ std::shared_ptr<Service> Service::create(const std::shared_ptr<Runtime> &rt) {
// Make sure others can connect to our socket // Make sure others can connect to our socket
::chmod(config::container_socket_path().c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); ::chmod(config::container_socket_path().c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
sp->connections_->set_observer(sp);
DEBUG("Everything setup. Waiting for incoming connections."); DEBUG("Everything setup. Waiting for incoming connections.");
return sp; return sp;
@ -54,29 +56,7 @@ Service::Service(const std::shared_ptr<Runtime> &rt) :
} }
Service::~Service() { Service::~Service() {
} DEBUG("");
void Service::connection_added(int id) {
}
void Service::connection_removed(int id) {
stop_container();
}
void Service::start_container() {
if (backend_)
BOOST_THROW_EXCEPTION(std::runtime_error("Container is already running"));
backend_ = std::make_shared<LxcContainer>();
backend_->start();
}
void Service::stop_container() {
if (not backend_)
return;
backend_->stop();
backend_.reset();
} }
int Service::next_id() { int Service::next_id() {
@ -90,23 +70,21 @@ void Service::new_client(std::shared_ptr<boost::asio::local::stream_protocol::so
} }
auto const messenger = std::make_shared<network::SocketMessenger>(socket); auto const messenger = std::make_shared<network::SocketMessenger>(socket);
DEBUG("Got connection from pid %d", messenger->creds().pid());
auto pending_calls = std::make_shared<rpc::PendingCallCache>();
auto rpc_channel = std::make_shared<rpc::Channel>(pending_calls, messenger);
auto server = std::make_shared<container::ManagementApiSkeleton>(
pending_calls, std::make_shared<LxcContainer>());
auto processor = std::make_shared<container::ManagementApiMessageProcessor>(
messenger, pending_calls, server);
auto const& connection = std::make_shared<network::SocketConnection>( auto const& connection = std::make_shared<network::SocketConnection>(
messenger, messenger, next_id(), connections_, messenger, messenger, next_id(), connections_, processor);
std::make_shared<qemu::NullMessageProcessor>());
connections_->add(connection); connections_->add(connection);
connection->read_next_message(); connection->read_next_message();
// To get access to the sockets the application manager
// services creates we need to make sure we're running
// against the right runtime directory here. Its a bit
// hacky but works for now.
auto creds = messenger->creds();
setenv("XDG_RUNTIME_DIR", utils::string_format("/run/user/%d", creds.uid()).c_str(), 1);
DEBUG("Got connection from pid %d", creds.pid());
start_container();
} }
} // namespace container } // namespace container
} // namespace anbox } // namespace anbox

View file

@ -28,24 +28,17 @@
namespace anbox { namespace anbox {
namespace container { namespace container {
class Service : public network::Connections<network::SocketConnection>::Observer, class Service : public std::enable_shared_from_this<Service> {
public std::enable_shared_from_this<Service> {
public: public:
static std::shared_ptr<Service> create(const std::shared_ptr<Runtime> &rt); static std::shared_ptr<Service> create(const std::shared_ptr<Runtime> &rt);
Service(const std::shared_ptr<Runtime> &rt); Service(const std::shared_ptr<Runtime> &rt);
~Service(); ~Service();
void connection_added(int id) override;
void connection_removed(int id) override;
private: private:
int next_id(); int next_id();
void new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket); void new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket);
void start_container();
void stop_container();
std::shared_ptr<common::Dispatcher> dispatcher_; std::shared_ptr<common::Dispatcher> dispatcher_;
std::shared_ptr<network::PublishedSocketConnector> connector_; std::shared_ptr<network::PublishedSocketConnector> connector_;
std::atomic<int> next_connection_id_; std::atomic<int> next_connection_id_;

View file

@ -19,6 +19,7 @@
#include "anbox/input/device.h" #include "anbox/input/device.h"
#include "anbox/runtime.h" #include "anbox/runtime.h"
#include "anbox/config.h" #include "anbox/config.h"
#include "anbox/utils.h"
#include <boost/format.hpp> #include <boost/format.hpp>
@ -26,6 +27,7 @@ namespace anbox {
namespace input { namespace input {
Manager::Manager(const std::shared_ptr<Runtime> &runtime) : Manager::Manager(const std::shared_ptr<Runtime> &runtime) :
runtime_(runtime) { runtime_(runtime) {
utils::ensure_paths({ config::host_input_device_path() });
} }
Manager::~Manager() { Manager::~Manager() {

View file

@ -80,15 +80,6 @@ void SocketConnection::on_read_size(const boost::system::error_code& error, std:
else else
connections_->remove(id()); connections_->remove(id());
} }
void SocketConnection::on_response_sent(bs::error_code const& error, std::size_t)
{
if (error)
{
connections_->remove(id());
BOOST_THROW_EXCEPTION(std::runtime_error(error.message()));
}
}
} // namespace anbox } // namespace anbox
} // namespace network } // namespace network

View file

@ -48,7 +48,6 @@ public:
void read_next_message(); void read_next_message();
private: private:
void on_response_sent(boost::system::error_code const& error, std::size_t);
void on_read_size(const boost::system::error_code& ec, std::size_t bytes_read); void on_read_size(const boost::system::error_code& ec, std::size_t bytes_read);
std::shared_ptr<MessageReceiver> const message_receiver_; std::shared_ptr<MessageReceiver> const message_receiver_;

View file

@ -0,0 +1,15 @@
option optimize_for = LITE_RUNTIME;
package anbox.protobuf.container;
message Configuration {
message BindMount {
required string source = 1;
required string target = 2;
}
repeated BindMount bind_mounts = 1;
}
message StartContainer {
required Configuration configuration = 1;
}

View file

@ -20,6 +20,7 @@
#include "anbox/rpc/make_protobuf_object.h" #include "anbox/rpc/make_protobuf_object.h"
#include "anbox/rpc/constants.h" #include "anbox/rpc/constants.h"
#include "anbox/common/variable_length_array.h" #include "anbox/common/variable_length_array.h"
#include "anbox/logger.h"
#include "anbox_rpc.pb.h" #include "anbox_rpc.pb.h"
@ -64,6 +65,8 @@ bool MessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
buffer_.erase(buffer_.begin(), buffer_.begin() + header_size); buffer_.erase(buffer_.begin(), buffer_.begin() + header_size);
DEBUG("type %d", message_type);
if (message_type == MessageType::invocation) { if (message_type == MessageType::invocation) {
anbox::protobuf::rpc::Invocation raw_invocation; anbox::protobuf::rpc::Invocation raw_invocation;
raw_invocation.ParseFromArray(buffer_.data(), message_size); raw_invocation.ParseFromArray(buffer_.data(), message_size);

View file

@ -57,8 +57,8 @@ public:
void send_response(::google::protobuf::uint32 id, google::protobuf::MessageLite *response); void send_response(::google::protobuf::uint32 id, google::protobuf::MessageLite *response);
virtual void dispatch(Invocation const& invocation) = 0; virtual void dispatch(Invocation const& invocation) { }
virtual void process_event_sequence(const std::string &event) = 0; virtual void process_event_sequence(const std::string &event) { }
private: private:
std::shared_ptr<network::MessageSender> sender_; std::shared_ptr<network::MessageSender> sender_;