Add RPC communication between container manager and client
This commit is contained in:
parent
51e9cfa777
commit
3d05c50c8b
24 changed files with 542 additions and 104 deletions
|
|
@ -23,11 +23,18 @@ protobuf_generate_cpp(
|
|||
GENERATED_PROTOBUF_BRIDGE_SRCS GENERATED_PROTOBUF_BRIDGE_HDRS
|
||||
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
|
||||
${GENERATED_PROTOBUF_BRIDGE_SRCS}
|
||||
${GENERATED_PROTOBUF_BRIDGE_HDRS}
|
||||
${GENERATED_PROTOBUF_RPC_SRCS}
|
||||
${GENERATED_PROTOBUF_RPC_HDRS}
|
||||
${GENERATED_PROTOBUF_CONTAINER_SRCS}
|
||||
${GENERATED_PROTOBUF_CONTAINER_HDRS}
|
||||
anbox/protobuf/google_protobuf_guard.cpp)
|
||||
target_link_libraries(anbox-protobuf
|
||||
${PROTOBUF_LITE_LIBRARIES})
|
||||
|
|
@ -51,8 +58,12 @@ set(SOURCES
|
|||
|
||||
anbox/container/service.cpp
|
||||
anbox/container/client.cpp
|
||||
anbox/container/configuration.h
|
||||
anbox/container/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/message_sender.h
|
||||
|
|
|
|||
|
|
@ -147,7 +147,23 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
}));
|
||||
|
||||
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_();
|
||||
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
||||
|
|
|
|||
|
|
@ -37,11 +37,7 @@ anbox::cmds::StartContainer::StartContainer()
|
|||
|
||||
rt->start();
|
||||
|
||||
auto container = std::make_shared<container::LxcContainer>();
|
||||
container->start();
|
||||
|
||||
trap->run();
|
||||
container->stop();
|
||||
rt->stop();
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -41,14 +41,14 @@ std::string in_snap_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) {
|
||||
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;
|
||||
if (path.empty()) {
|
||||
path = utils::get_env_value("HOME", "");
|
||||
|
|
@ -69,7 +69,7 @@ std::string runtime_dir() {
|
|||
}
|
||||
|
||||
std::string state_dir() {
|
||||
static std::string path = "/var/lib";
|
||||
static std::string path = in_snap_data_dir("/var/lib");
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
@ -85,7 +85,7 @@ std::string socket_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;
|
||||
}
|
||||
|
||||
|
|
@ -104,13 +104,13 @@ std::string container_socket_path() {
|
|||
return path;
|
||||
}
|
||||
|
||||
std::string host_share_path() {
|
||||
static std::string path = utils::string_format("%s/android-share", data_path());
|
||||
std::string host_input_device_path() {
|
||||
static std::string path = utils::string_format("%s/anbox/input-devices", runtime_dir());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string host_input_device_path() {
|
||||
static std::string path = utils::string_format("%s/input-devices", data_path());
|
||||
std::string host_share_path() {
|
||||
static std::string path = utils::string_format("%s/android-share", data_path());
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,16 +16,53 @@
|
|||
*/
|
||||
|
||||
#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/logger.h"
|
||||
|
||||
namespace ba = boost::asio;
|
||||
namespace bs = boost::system;
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
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() {
|
||||
}
|
||||
|
||||
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 anbox
|
||||
|
|
|
|||
|
|
@ -18,18 +18,37 @@
|
|||
#ifndef ANBOX_CONTAINER_CLIENT_H_
|
||||
#define ANBOX_CONTAINER_CLIENT_H_
|
||||
|
||||
#include "anbox/network/local_socket_messenger.h"
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/container/configuration.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace rpc {
|
||||
class PendingCallCache;
|
||||
class Channel;
|
||||
class MessageProcessor;
|
||||
} // namespace rpc
|
||||
namespace network {
|
||||
class LocalSocketMessenger;
|
||||
} // namespace network
|
||||
namespace container {
|
||||
class ManagementApiStub;
|
||||
class Client {
|
||||
public:
|
||||
Client(const std::shared_ptr<Runtime> &rt);
|
||||
~Client();
|
||||
|
||||
void start_container(const Configuration &configuration);
|
||||
|
||||
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 anbox
|
||||
|
|
|
|||
32
src/anbox/container/configuration.h
Normal file
32
src/anbox/container/configuration.h
Normal 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
|
||||
|
|
@ -18,8 +18,10 @@
|
|||
#ifndef ANBOX_CONTAINER_CONTAINER_H_
|
||||
#define ANBOX_CONTAINER_CONTAINER_H_
|
||||
|
||||
#include "anbox/container/configuration.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
|
|
@ -33,7 +35,7 @@ public:
|
|||
};
|
||||
|
||||
// Start the container in background
|
||||
virtual void start() = 0;
|
||||
virtual void start(const Configuration &configuration) = 0;
|
||||
|
||||
// Stop a running container
|
||||
virtual void stop() = 0;
|
||||
|
|
|
|||
|
|
@ -24,15 +24,14 @@
|
|||
#include <map>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
namespace {
|
||||
static constexpr char *kAndroidShellCommand{"/system/bin/ls"};
|
||||
}
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
|
|
@ -46,16 +45,19 @@ LxcContainer::LxcContainer() :
|
|||
config::host_android_data_path(),
|
||||
config::host_android_cache_path(),
|
||||
config::host_android_storage_path(),
|
||||
config::host_input_device_path(),
|
||||
});
|
||||
}
|
||||
|
||||
LxcContainer::~LxcContainer() {
|
||||
DEBUG("");
|
||||
|
||||
stop();
|
||||
|
||||
if (container_)
|
||||
lxc_container_put(container_);
|
||||
}
|
||||
|
||||
void LxcContainer::start() {
|
||||
void LxcContainer::start(const Configuration &configuration) {
|
||||
if (getuid() != 0)
|
||||
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");
|
||||
#endif
|
||||
|
||||
std::map<std::string,std::string> bind_mount_dirs = {
|
||||
{ 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" },
|
||||
};
|
||||
for (const auto &bind_mount : configuration.bind_mounts) {
|
||||
std::string create_type = "file";
|
||||
|
||||
if (fs::is_directory(bind_mount.first))
|
||||
create_type = "dir";
|
||||
|
||||
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",
|
||||
utils::string_format("%s %s none bind,create=dir,optional 0 0", item.first, item.second));
|
||||
}
|
||||
|
||||
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));
|
||||
utils::string_format("%s %s none bind,create=%s,optional 0 0",
|
||||
bind_mount.first, target_path, create_type));
|
||||
}
|
||||
|
||||
if (!container_->save_config(container_, nullptr))
|
||||
|
|
@ -144,6 +137,8 @@ void LxcContainer::start() {
|
|||
if (not container_->start(container_, 0, nullptr))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to start container"));
|
||||
|
||||
state_ = Container::State::running;
|
||||
|
||||
DEBUG("Container successfully started");
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +149,8 @@ void LxcContainer::stop() {
|
|||
if (not container_->stop(container_))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to stop container"));
|
||||
|
||||
state_ = Container::State::inactive;
|
||||
|
||||
DEBUG("Container successfully stopped");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ public:
|
|||
LxcContainer();
|
||||
~LxcContainer();
|
||||
|
||||
void start() override;
|
||||
void start(const Configuration &configuration) override;
|
||||
void stop() override;
|
||||
State state() override;
|
||||
|
||||
|
|
|
|||
45
src/anbox/container/management_api_message_processor.cpp
Normal file
45
src/anbox/container/management_api_message_processor.cpp
Normal 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
|
||||
42
src/anbox/container/management_api_message_processor.h
Normal file
42
src/anbox/container/management_api_message_processor.h
Normal 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
|
||||
69
src/anbox/container/management_api_skeleton.cpp
Normal file
69
src/anbox/container/management_api_skeleton.cpp
Normal 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
|
||||
60
src/anbox/container/management_api_skeleton.h
Normal file
60
src/anbox/container/management_api_skeleton.h
Normal 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
|
||||
70
src/anbox/container/management_api_stub.cpp
Normal file
70
src/anbox/container/management_api_stub.cpp
Normal 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
|
||||
61
src/anbox/container/management_api_stub.h
Normal file
61
src/anbox/container/management_api_stub.h
Normal 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
|
||||
|
|
@ -20,7 +20,11 @@
|
|||
#include "anbox/network/delegate_message_processor.h"
|
||||
#include "anbox/network/socket_messenger.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/management_api_message_processor.h"
|
||||
#include "anbox/container/management_api_skeleton.h"
|
||||
#include "anbox/config.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
|
||||
::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.");
|
||||
|
||||
return sp;
|
||||
|
|
@ -54,29 +56,7 @@ Service::Service(const std::shared_ptr<Runtime> &rt) :
|
|||
}
|
||||
|
||||
Service::~Service() {
|
||||
}
|
||||
|
||||
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();
|
||||
DEBUG("");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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>(
|
||||
messenger, messenger, next_id(), connections_,
|
||||
std::make_shared<qemu::NullMessageProcessor>());
|
||||
messenger, messenger, next_id(), connections_, processor);
|
||||
|
||||
connections_->add(connection);
|
||||
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 anbox
|
||||
|
|
|
|||
|
|
@ -28,24 +28,17 @@
|
|||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
class Service : public network::Connections<network::SocketConnection>::Observer,
|
||||
public std::enable_shared_from_this<Service> {
|
||||
class Service : public std::enable_shared_from_this<Service> {
|
||||
public:
|
||||
static std::shared_ptr<Service> create(const std::shared_ptr<Runtime> &rt);
|
||||
|
||||
Service(const std::shared_ptr<Runtime> &rt);
|
||||
~Service();
|
||||
|
||||
void connection_added(int id) override;
|
||||
void connection_removed(int id) override;
|
||||
|
||||
private:
|
||||
int next_id();
|
||||
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<network::PublishedSocketConnector> connector_;
|
||||
std::atomic<int> next_connection_id_;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "anbox/input/device.h"
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/config.h"
|
||||
#include "anbox/utils.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
|
|
@ -26,6 +27,7 @@ namespace anbox {
|
|||
namespace input {
|
||||
Manager::Manager(const std::shared_ptr<Runtime> &runtime) :
|
||||
runtime_(runtime) {
|
||||
utils::ensure_paths({ config::host_input_device_path() });
|
||||
}
|
||||
|
||||
Manager::~Manager() {
|
||||
|
|
|
|||
|
|
@ -80,15 +80,6 @@ void SocketConnection::on_read_size(const boost::system::error_code& error, std:
|
|||
else
|
||||
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 network
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ public:
|
|||
void read_next_message();
|
||||
|
||||
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);
|
||||
|
||||
std::shared_ptr<MessageReceiver> const message_receiver_;
|
||||
|
|
|
|||
15
src/anbox/protobuf/anbox_container.proto
Normal file
15
src/anbox/protobuf/anbox_container.proto
Normal 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;
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
#include "anbox/rpc/make_protobuf_object.h"
|
||||
#include "anbox/rpc/constants.h"
|
||||
#include "anbox/common/variable_length_array.h"
|
||||
#include "anbox/logger.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);
|
||||
|
||||
DEBUG("type %d", message_type);
|
||||
|
||||
if (message_type == MessageType::invocation) {
|
||||
anbox::protobuf::rpc::Invocation raw_invocation;
|
||||
raw_invocation.ParseFromArray(buffer_.data(), message_size);
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ public:
|
|||
|
||||
void send_response(::google::protobuf::uint32 id, google::protobuf::MessageLite *response);
|
||||
|
||||
virtual void dispatch(Invocation const& invocation) = 0;
|
||||
virtual void process_event_sequence(const std::string &event) = 0;
|
||||
virtual void dispatch(Invocation const& invocation) { }
|
||||
virtual void process_event_sequence(const std::string &event) { }
|
||||
|
||||
private:
|
||||
std::shared_ptr<network::MessageSender> sender_;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue