Initial work

This commit is contained in:
Simon Fels 2016-05-26 22:38:57 +02:00 • committed by Simon Fels
commit 3222551702
374 changed files with 40290 additions and 0 deletions

71
src/CMakeLists.txt Normal file
View file

@ -0,0 +1,71 @@
include_directories(
${Boost_INCLUDE_DIRS}
${GLIB_INCLUDE_DIRS}
${GIO_INCLUDE_DIRS}
${GIO-UNIX_INCLUDE_DIRS}
${CMAKE_SOURCE_DIR}/src
${CMAKE_SOURCE_DIR}/external/process-cpp-minimal/include
${CMAKE_SOURCE_DIR}/external/android-emugl/host/include
)
set(SOURCES
anbox/logger.cpp
anbox/utils.cpp
anbox/cli.cpp
anbox/runtime.cpp
anbox/version.cpp
anbox/daemon.cpp
anbox/config.cpp
anbox/pid_persister.cpp
anbox/container.cpp
anbox/container_connector.cpp
anbox/common/fd.cpp
anbox/common/fd_sets.h
anbox/common/variable_length_array.h
anbox/network/message_sender.h
anbox/network/message_receiver.h
anbox/network/message_processor.h
anbox/network/connector.h
anbox/network/connection_creator.h
anbox/network/qemu_pipe_connection_creator.cpp
anbox/network/published_socket_connector.cpp
anbox/network/connections.h
anbox/network/socket_connection.cpp
anbox/network/socket_messenger.cpp
anbox/network/delegate_message_processor.h
anbox/graphics/opengles_message_processor.cpp
anbox/graphics/gl_renderer_server.cpp
anbox/support/null_message_processor.cpp
anbox/support/boot_properties_message_processor.cpp
anbox/support/hwcontrol_message_processor.cpp
anbox/cmds/version.cpp
anbox/cmds/run.cpp
anbox/cmds/shell.cpp
anbox/do_not_copy_or_move.h
anbox/optional.h
anbox/defer_action.h)
add_library(anbox-core ${SOURCES})
target_link_libraries(anbox-core
${Boost_LDFLAGS}
${Boost_LIBRARIES}
pthread
process-cpp
bwrap
OpenglRender)
add_executable(anbox main.cpp)
target_link_libraries(anbox
anbox-core)
install(
TARGETS anbox
RUNTIME DESTINATION sbin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)

275
src/anbox/cli.cpp Normal file
View file

@ -0,0 +1,275 @@
/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Thomas Voß <thomas.voss@canonical.com>
*
*/
#include <boost/format.hpp>
#include <boost/program_options.hpp>
#include "anbox/cli.h"
namespace cli = anbox::cli;
namespace po = boost::program_options;
namespace {
namespace pattern {
static constexpr const char* help_for_command_with_subcommands =
"NAME:\n"
" %1% - %2%\n"
"\n"
"USAGE:\n"
" %3% [command options] [arguments...]";
static constexpr const char* commands = "COMMANDS:";
static constexpr const char* command = " %1% %2%";
static constexpr const char* options = "OPTIONS:";
static constexpr const char* option = " --%1% %2%";
}
void add_to_desc_for_flags(po::options_description& desc, const std::set<cli::Flag::Ptr>& flags)
{
for (auto flag : flags)
{
auto v = po::value<std::string>()->notifier([flag](const std::string& s)
{
flag->notify(s);
});
desc.add_options()(flag->name().as_string().c_str(), v, flag->description().as_string().c_str());
}
}
}
std::vector<std::string> cli::args(int argc, char **argv)
{
std::vector<std::string> result;
for (int i = 1; i < argc; i++) result.push_back(argv[i]);
return result;
}
const cli::Name& cli::Flag::name() const
{
return name_;
}
const cli::Description& cli::Flag::description() const
{
return description_;
}
cli::Flag::Flag(const Name& name, const Description& description)
: name_{name},
description_{description}
{
}
cli::Command::FlagsWithInvalidValue::FlagsWithInvalidValue() : std::runtime_error{"Flags with invalid value"}
{
}
cli::Command::FlagsMissing::FlagsMissing() : std::runtime_error{"Flags are missing in command invocation"}
{
}
cli::Name cli::Command::name() const
{
return name_;
}
cli::Usage cli::Command::usage() const
{
return usage_;
}
cli::Description cli::Command::description() const
{
return description_;
}
cli::Command::Command(const cli::Name& name, const cli::Usage& usage, const cli::Description& description)
: name_(name),
usage_(usage),
description_(description)
{
}
cli::CommandWithSubcommands::CommandWithSubcommands(const Name& name, const Usage& usage, const Description& description)
: Command{name, usage, description}
{
command(std::make_shared<cmd::Help>(*this));
}
cli::CommandWithSubcommands& cli::CommandWithSubcommands::command(const Command::Ptr& command)
{
commands_[command->name().as_string()] = command;
return *this;
}
cli::CommandWithSubcommands& cli::CommandWithSubcommands::flag(const Flag::Ptr& flag)
{
flags_.insert(flag);
return *this;
}
void cli::CommandWithSubcommands::help(std::ostream& out)
{
out << boost::format(pattern::help_for_command_with_subcommands)
% name().as_string() % usage().as_string()
% name().as_string() << std::endl;
if (flags_.size() > 0)
{
out << std::endl << pattern::options << std::endl;
for (const auto& flag : flags_)
out << boost::format(pattern::option) % flag->name() % flag->description() << std::endl;
}
if (commands_.size() > 0)
{
out << std::endl << pattern::commands << std::endl;
for (const auto& cmd : commands_)
out << boost::format(pattern::command) % cmd.second->name() % cmd.second->description() << std::endl;
}
}
int cli::CommandWithSubcommands::run(const cli::Command::Context& ctxt)
{
po::positional_options_description pdesc;
pdesc.add("command", 1);
po::options_description desc("Options");
desc.add_options()("command", po::value<std::string>()->required(), "the command to be executed");
add_to_desc_for_flags(desc, flags_);
try
{
po::variables_map vm;
auto parsed = po::command_line_parser(ctxt.args)
.options(desc)
.positional(pdesc)
.style(po::command_line_style::unix_style)
.allow_unregistered()
.run();
po::store(parsed, vm);
po::notify(vm);
return commands_[vm["command"].as<std::string>()]->run(cli::Command::Context
{
ctxt.cin,
ctxt.cout,
po::collect_unrecognized(parsed.options, po::include_positional)
});
}
catch (const po::error& e)
{
ctxt.cout << e.what() << std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
cli::CommandWithFlagsAndAction::CommandWithFlagsAndAction(const Name& name, const Usage& usage, const Description& description)
: Command{name, usage, description}
{
}
cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::flag(const Flag::Ptr& flag)
{
flags_.insert(flag);
return *this;
}
cli::CommandWithFlagsAndAction& cli::CommandWithFlagsAndAction::action(const Action& action)
{
action_ = action;
return *this;
}
int cli::CommandWithFlagsAndAction::run(const Context& ctxt)
{
po::options_description cd(name().as_string());
bool help_requested{false};
cd.add_options()("help", po::bool_switch(&help_requested), "produces a help message");
add_to_desc_for_flags(cd, flags_);
try
{
po::variables_map vm;
auto parsed = po::command_line_parser(ctxt.args).options(cd).style(po::command_line_style::unix_style).allow_unregistered().run();
po::store(parsed, vm);
po::notify(vm);
if (help_requested)
{
help(ctxt.cout);
return EXIT_SUCCESS;
}
return action_(cli::Command::Context
{
ctxt.cin,
ctxt.cout,
po::collect_unrecognized(parsed.options, po::exclude_positional)
});
}
catch (const po::error& e)
{
ctxt.cout << e.what() << std::endl;
help(ctxt.cout);
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
void cli::CommandWithFlagsAndAction::help(std::ostream& out)
{
out << boost::format(pattern::help_for_command_with_subcommands)
% name().as_string() % description().as_string()
% name().as_string() << std::endl;
if (flags_.size() > 0)
{
out << std::endl << boost::format(pattern::options) << std::endl;
for (const auto& flag : flags_)
out << boost::format(pattern::option) % flag->name() % flag->description() << std::endl;
}
}
cli::cmd::Help::Help(Command& cmd)
: Command{cli::Name{"help"}, cli::Usage{"prints a short help message"}, cli::Description{"prints a short help message"}},
command{cmd}
{
}
// From Command
int cli::cmd::Help::run(const Context &context)
{
command.help(context.cout);
return EXIT_FAILURE;
}
void cli::cmd::Help::help(std::ostream &out)
{
command.help(out);
}

356
src/anbox/cli.h Normal file
View file

@ -0,0 +1,356 @@
/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Thomas Voß <thomas.voss@canonical.com>
*
*/
#ifndef BIOMETRY_UTIL_CLI_H_
#define BIOMETRY_UTIL_CLI_H_
#include <iomanip>
#include <iostream>
#include <memory>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include "anbox/do_not_copy_or_move.h"
#include "anbox/optional.h"
namespace anbox {
namespace cli {
template<std::size_t max>
class SizeConstrainedString
{
public:
SizeConstrainedString(const std::string& s) : s{s}
{
if(s.size() > max)
throw std::logic_error{"Max size exceeded " + std::to_string(max)};
}
const std::string& as_string() const
{
return s;
}
operator std::string() const
{
return s;
}
private:
std::string s;
};
template<std::size_t max>
bool operator<(const SizeConstrainedString<max>& lhs, const SizeConstrainedString<max>& rhs)
{
return lhs.as_string() < rhs.as_string();
}
template<std::size_t max>
bool operator==(const SizeConstrainedString<max>& lhs, const SizeConstrainedString<max>& rhs)
{
return lhs.as_string() == rhs.as_string();
}
template<std::size_t max>
std::ostream& operator<<(std::ostream& out, const SizeConstrainedString<max>& scs)
{
return out << std::setw(max) << std::left << scs.as_string();
}
// We are imposing size constraints to ensure a consistent CLI layout.
typedef SizeConstrainedString<20> Name;
typedef SizeConstrainedString<60> Usage;
typedef SizeConstrainedString<60> Description;
/// @brief Flag models an input parameter to a command.
class Flag : public DoNotCopyOrMove
{
public:
// Safe us some typing.
typedef std::shared_ptr<Flag> Ptr;
/// @brief notify announces a new value to the flag.
virtual void notify(const std::string& value) = 0;
/// @brief name returns the name of the Flag.
const Name& name() const;
/// @brief description returns a human-readable description of the flag.
const Description& description() const;
protected:
/// @brief Flag creates a new instance, initializing name and description
/// from the given values.
Flag(const Name& name, const Description& description);
private:
Name name_;
Description description_;
};
/// @brief TypedFlag implements Flag relying on operator<< and operator>> to read/write values to/from strings.
template<typename T>
class TypedFlag : public Flag
{
public:
typedef std::shared_ptr<TypedFlag<T>> Ptr;
TypedFlag(const Name& name, const Description& description) : Flag{name, description}
{
}
/// @brief value installs the given value in the flag.
TypedFlag& value(const T& value)
{
value_ = value;
return *this;
}
/// @brief value returns the optional value associated with the flag.
const Optional<T>& value() const
{
return value_;
}
/// @brief notify tries to unwrap a value of type T from value.
void notify(const std::string& s) override
{
std::stringstream ss{s};
T value; ss >> value;
value_ = value;
}
private:
Optional<T> value_;
};
/// @brief TypedReferenceFlag implements Flag, relying on operator<</>> to convert to/from string representations,
/// updating the given mutable reference to a value of type T.
template<typename T>
class TypedReferenceFlag : public Flag
{
public:
// Safe us some typing.
typedef std::shared_ptr<TypedReferenceFlag<T>> Ptr;
/// @brief TypedReferenceFlag initializes a new instance with name, description and value.
TypedReferenceFlag(const Name& name, const Description& description, T& value)
: Flag{name, description},
value_{value}
{
}
/// @brief notify tries to unwrap a value of type T from value,
/// relying on operator>> to read from given string s.
void notify(const std::string& s) override
{
std::stringstream ss{s};
ss >> value_.get();
}
private:
std::reference_wrapper<T> value_;
};
/// @brief OptionalTypedReferenceFlag handles Optional<T> references, making sure that
/// a value is always read on notify, even if the Optional<T> wasn't initialized previously.
template<typename T>
class OptionalTypedReferenceFlag : public Flag
{
public:
typedef std::shared_ptr<OptionalTypedReferenceFlag<T>> Ptr;
OptionalTypedReferenceFlag(const Name& name, const Description& description, Optional<T>& value)
: Flag{name, description},
value_{value}
{
}
/// @brief notify tries to unwrap a value of type T from value.
void notify(const std::string& s) override
{
std::stringstream ss{s}; T value; ss >> value;
value_.get() = value;
}
private:
std::reference_wrapper<Optional<T>> value_;
};
/// @brief Command abstracts an individual command available from the daemon.
class Command : public DoNotCopyOrMove
{
public:
// Safe us some typing
typedef std::shared_ptr<Command> Ptr;
/// @brief FlagsMissing is thrown if at least one required flag is missing.
struct FlagsMissing : public std::runtime_error
{
/// @brief FlagsMissing initializes a new instance.
FlagsMissing();
};
/// @brief FlagsWithWrongValue is thrown if a value passed on the command line is invalid.
struct FlagsWithInvalidValue : public std::runtime_error
{
/// @brief FlagsWithInvalidValue initializes a new instance.
FlagsWithInvalidValue();
};
/// @brief Context bundles information passed to Command::run invocations.
struct Context
{
std::istream& cin; ///< The std::istream that should be used for reading.
std::ostream& cout; ///< The std::ostream that should be used for writing.
std::vector<std::string> args; ///< The command line args.
};
/// @brief name returns the Name of the command.
virtual Name name() const;
/// @brief usage returns a short usage string for the command.
virtual Usage usage() const;
/// @brief description returns a longer string explaining the command.
virtual Description description() const;
/// @brief run puts the command to execution.
virtual int run(const Context& context) = 0;
/// @brief help prints information about a command to out.
virtual void help(std::ostream& out) = 0;
protected:
/// @brief Command initializes a new instance with the given name, usage and description.
Command(const Name& name, const Usage& usage, const Description& description);
/// @brief name adjusts the name of the command to n.
// virtual void name(const Name& n);
/// @brief usage adjusts the usage string of the comand to u.
// virtual void usage(const Usage& u);
/// @brief description adjusts the description string of the command to d.
// virtual void description(const Description& d);
private:
Name name_;
Usage usage_;
Description description_;
};
/// @brief CommandWithSubcommands implements Command, selecting one of a set of actions.
class CommandWithSubcommands : public Command
{
public:
typedef std::shared_ptr<CommandWithSubcommands> Ptr;
typedef std::function<int(const Context&)> Action;
/// @brief CommandWithSubcommands initializes a new instance with the given name, usage and description
CommandWithSubcommands(const Name& name, const Usage& usage, const Description& description);
/// @brief command adds the given command to the set of known commands.
CommandWithSubcommands& command(const Command::Ptr& command);
/// @brief flag adds the given flag to the set of known flags.
CommandWithSubcommands& flag(const Flag::Ptr& flag);
// From Command
int run(const Context& context) override;
void help(std::ostream &out) override;
private:
std::unordered_map<std::string, Command::Ptr> commands_;
std::set<Flag::Ptr> flags_;
};
/// @brief CommandWithFlagsAction implements Command, executing an Action after handling
class CommandWithFlagsAndAction : public Command
{
public:
typedef std::shared_ptr<CommandWithFlagsAndAction> Ptr;
typedef std::function<int(const Context&)> Action;
/// @brief CommandWithFlagsAndAction initializes a new instance with the given name, usage and description
CommandWithFlagsAndAction(const Name& name, const Usage& usage, const Description& description);
/// @brief flag adds the given flag to the set of known flags.
CommandWithFlagsAndAction& flag(const Flag::Ptr& flag);
/// @brief action installs the given action.
CommandWithFlagsAndAction& action(const Action& action);
// From Command
int run(const Context& context) override;
void help(std::ostream &out) override;
private:
std::set<Flag::Ptr> flags_;
Action action_;
};
namespace cmd
{
/// @brief HelpFor prints a help message for the given command on execution.
class Help : public Command
{
public:
/// @brief HelpFor initializes a new instance with the given reference to a cmd.
explicit Help(Command& cmd);
// From Command
int run(const Context &context) override;
void help(std::ostream &out) override;
private:
/// @cond
Command& command;
/// @endcond
};
}
/// @brief args returns a vector of strings assembled from argc and argv.
std::vector<std::string> args(int argc, char** argv);
/// @brief make_flag returns a flag with the given name and description.
template<typename T>
typename TypedFlag<T>::Ptr make_flag(const Name& name, const Description& description)
{
return std::make_shared<TypedFlag<T>>(name, description);
}
/// @brief make_flag returns a flag with the given name and description, notifying updates to value.
template<typename T>
typename TypedReferenceFlag<T>::Ptr make_flag(const Name& name, const Description& desc, T& value)
{
return std::make_shared<TypedReferenceFlag<T>>(name, desc, value);
}
/// @brief make_flag returns a flag with the given name and description, updating the given optional value.
template<typename T>
typename OptionalTypedReferenceFlag<T>::Ptr make_flag(const Name& name, const Description& desc, Optional<T>& value)
{
return std::make_shared<OptionalTypedReferenceFlag<T>>(name, desc, value);
}
} // namespace cli
} // namespace anbox
#endif

111
src/anbox/cmds/run.cpp Normal file
View file

@ -0,0 +1,111 @@
/*
* 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 <boost/filesystem.hpp>
#include "core/posix/signal.h"
#include "anbox/logger.h"
#include "anbox/runtime.h"
#include "anbox/container.h"
#include "anbox/config.h"
#include "anbox/pid_persister.h"
#include "anbox/cmds/run.h"
#include "anbox/network/published_socket_connector.h"
#include "anbox/network/qemu_pipe_connection_creator.h"
#include "anbox/graphics/gl_renderer_server.h"
#include <sys/prctl.h>
namespace fs = boost::filesystem;
namespace {
class NullConnectionCreator : public anbox::network::ConnectionCreator {
public:
void create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket) override {
WARNING("Not implemented");
socket->close();
}
};
}
anbox::cmds::Run::Run()
: CommandWithFlagsAndAction{cli::Name{"run"}, cli::Usage{"run"}, cli::Description{"Run the the anbox system"}}
{
flag(cli::make_flag(cli::Name{"rootfs"}, cli::Description{"Path to Android rootfs"}, rootfs_));
// Just for the purpose to allow QtMir (or unity8) to find this on our /proc/*/cmdline
// for proper confinement etc.
flag(cli::make_flag(cli::Name{"desktop_file_hint"}, cli::Description{"Desktop file hint for QtMir/Unity8"}, desktop_file_hint_));
action([this](const cli::Command::Context &ctx) {
if (rootfs_.empty() || !fs::is_directory(fs::path(rootfs_))) {
ctx.cout << "Not valid rootfs path provided" << std::endl;
return EXIT_FAILURE;
}
auto trap = core::posix::trap_signals_for_process({core::posix::Signal::sig_term,
core::posix::Signal::sig_int});
trap->signal_raised().connect([trap](const core::posix::Signal &signal) {
INFO("Signal %i received. Good night.", static_cast<int>(signal));
trap->stop();
});
auto rt = Runtime::create();
auto renderer = std::make_shared<graphics::GLRendererServer>();
renderer->start();
// Socket which will be used by the qemud service inside the Android
// container for things like sensors, vibrtator etc.
auto qemud_connector = std::make_shared<network::PublishedSocketConnector>(
utils::string_format("%s/qemud", config::data_path()),
rt,
std::make_shared<NullConnectionCreator>());
// The qemu pipe is used as a very fast communication channel between guest
// and host for things like the GLES emulation/translation, the RIL or ADB.
auto qemu_pipe_connector = std::make_shared<network::PublishedSocketConnector>(
utils::string_format("%s/qemu_pipe", config::data_path()),
rt,
std::make_shared<network::QemuPipeConnectionCreator>(rt, renderer->socket_path()));
auto spec = Container::Spec::Default();
spec.rootfs_path = rootfs_;
spec.bind_paths.insert({qemud_connector->socket_file(), "/dev/qemud"});
spec.bind_paths.insert({qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"});
spec.temporary_dirs.push_back("/data");
// We isolate the container from accessing binder nodes of the host
// through the IPC namespace which gets support for binder with extra
// patches we require.
spec.dev_bind_paths.push_back("/dev/binder");
// Required for shared memory allocations. TODO(morphis): Letting the guest
// access should be ok but needs more investigation.
spec.dev_bind_paths.push_back("/dev/ashmem");
auto container = Container::create(spec);
rt->start();
container->start();
trap->run();
container->stop();
rt->stop();
return EXIT_SUCCESS;
});
}

40
src/anbox/cmds/run.h Normal file
View file

@ -0,0 +1,40 @@
/*
* 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_CMDS_RUN_H_
#define ANBOX_CMDS_RUN_H_
#include <functional>
#include <iostream>
#include <memory>
#include "anbox/cli.h"
namespace anbox {
namespace cmds {
class Run : public cli::CommandWithFlagsAndAction {
public:
Run();
private:
std::string rootfs_;
std::string desktop_file_hint_;
};
} // namespace cmds
} // namespace anbox
#endif

36
src/anbox/cmds/shell.cpp Normal file
View file

@ -0,0 +1,36 @@
/*
* 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 <boost/filesystem.hpp>
#include "core/posix/signal.h"
#include "anbox/logger.h"
#include "anbox/config.h"
#include "anbox/container_connector.h"
#include "anbox/cmds/shell.h"
namespace fs = boost::filesystem;
anbox::cmds::Shell::Shell()
: CommandWithFlagsAndAction{cli::Name{"shell"}, cli::Usage{"shell"}, cli::Description{"Open a shell within the Anbox container"}}
{
action([this](const cli::Command::Context &ctx) {
ContainerConnector connector;
return connector.run("/system/bin/sh");
});
}

39
src/anbox/cmds/shell.h Normal file
View file

@ -0,0 +1,39 @@
/*
* 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_CMDS_RUN_QEMU_H_
#define ANBOX_CMDS_RUN_QEMU_H_
#include <functional>
#include <iostream>
#include <memory>
#include "anbox/cli.h"
namespace anbox {
namespace cmds {
class Shell : public cli::CommandWithFlagsAndAction {
public:
Shell();
private:
std::string rootfs_;
};
} // namespace cmds
} // namespace anbox
#endif

View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Thomas Voß <thomas.voss@canonical.com>
*
*/
#include "anbox/cmds/version.h"
#include "anbox/version.h"
anbox::cmds::Version::Version()
: CommandWithFlagsAndAction{cli::Name{"version"}, cli::Usage{"version"}, cli::Description{"print the version of the daemon"}}
{
action([](const cli::Command::Context& ctxt)
{
std::uint32_t major, minor, patch;
anbox::version(major, minor, patch);
ctxt.cout << "anbox " << major << "." << minor << "." << patch << std::endl;
return 0;
});
}

38
src/anbox/cmds/version.h Normal file
View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Thomas Voß <thomas.voss@canonical.com>
*
*/
#ifndef ANBOX_CMDS_VERSION_H_
#define ANBOX_CMDS_VERSION_H_
#include <functional>
#include <iostream>
#include <memory>
#include "anbox/cli.h"
namespace anbox {
namespace cmds {
class Version : public cli::CommandWithFlagsAndAction {
public:
Version();
};
} // namespace cmds
} // namespace anbox
#endif

61
src/anbox/common/fd.cpp Normal file
View file

@ -0,0 +1,61 @@
/*
* Copyright © 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
*/
#include "anbox/common/fd.h"
#include <unistd.h>
#include <algorithm>
namespace anbox {
Fd::Fd() :
Fd{invalid}
{
}
Fd::Fd(IntOwnedFd fd) :
fd{std::make_shared<int>(fd.int_owned_fd)}
{
}
Fd::Fd(int raw_fd) :
fd{new int{raw_fd},
[](int* fd)
{
if (!fd) return;
if (*fd > Fd::invalid) ::close(*fd);
delete fd;
}}
{
}
Fd::Fd(Fd&& other) :
fd{std::move(other.fd)}
{
}
Fd& Fd::operator=(Fd other)
{
std::swap(fd, other.fd);
return *this;
}
Fd::operator int() const
{
if (fd) return *fd;
return invalid;
}
} // namespace anbox

50
src/anbox/common/fd.h Normal file
View file

@ -0,0 +1,50 @@
/*
* Copyright © 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
*/
#ifndef ANBOX_COMMON_FD_H_
#define ANBOX_COMMON_FD_H_
#include <memory>
namespace anbox {
struct IntOwnedFd
{
int int_owned_fd;
};
class Fd
{
public:
//transfer ownership of the POD-int to the object. The int no longer needs close()ing,
//and has the lifetime of the Fd object.
explicit Fd(int fd);
explicit Fd(IntOwnedFd);
static int const invalid{-1};
Fd(); //Initializes fd to the anbox::Fd::invalid;
Fd(Fd&&);
Fd(Fd const&) = default;
Fd& operator=(Fd);
//bit of a convenient kludge. take care not to close or otherwise destroy the FD.
operator int() const;
private:
std::shared_ptr<int> fd;
};
} // namespace anbox
#endif

View file

@ -0,0 +1,31 @@
/*
* Copyright © 2013 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Robert Carr <robert.carr@canonical.com>
*/
#ifndef ANBOX_COMMON_FD_SETS_H_
#define ANBOX_COMMON_FD_SETS_H_
#include <vector>
#include <initializer_list>
#include "anbox/common/fd.h"
namespace anbox {
typedef std::vector<std::vector<Fd>> FdSets;
} // namespace anbox
#endif

View file

@ -0,0 +1,61 @@
/*
* Copyright © 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
*/
#ifndef ANBOX_COMMON_VARIABLE_LENGTH_ARRAY_H_
#define ANBOX_COMMON_VARIABLE_LENGTH_ARRAY_H_
#include <sys/types.h>
#include <memory>
namespace anbox {
template <size_t BuiltInBufferSize>
class VariableLengthArray
{
public:
explicit VariableLengthArray(size_t size) : size_{size}
{
/* Don't call resize if the initial values of member variables are valid */
if (size > BuiltInBufferSize) resize(size);
}
void resize(size_t size)
{
if (size > BuiltInBufferSize)
effective_buffer = BufferUPtr{new unsigned char[size], heap_deleter};
else
effective_buffer = BufferUPtr{builtin_buffer, null_deleter};
size_ = size;
}
unsigned char* data() const { return effective_buffer.get(); }
size_t size() const { return size_; }
private:
typedef std::unique_ptr<unsigned char,void (*)(unsigned char*)> BufferUPtr;
static void null_deleter(unsigned char*) {}
static void heap_deleter(unsigned char* b) { delete[] b; }
unsigned char builtin_buffer[BuiltInBufferSize];
BufferUPtr effective_buffer{builtin_buffer, null_deleter};
size_t size_;
};
} // namespace anbox
#endif

29
src/anbox/config.cpp Normal file
View file

@ -0,0 +1,29 @@
/*
* 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 <cstring>
#include "anbox/config.h"
namespace anbox {
namespace config {
std::string data_path() {
// TODO(morphis): replace with proper compile time constant
return "/home/phablet/.local/share/anbox/";
}
} // namespace config
} // namespace anbox

30
src/anbox/config.h Normal file
View file

@ -0,0 +1,30 @@
/*
* 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_CONFIG_H_
#define ANBOX_CONFIG_H_
#include <string>
namespace anbox {
namespace config {
std::string BubblewrapPath();
std::string data_path();
} // namespace config
} // namespace anbox
#endif

123
src/anbox/container.cpp Normal file
View file

@ -0,0 +1,123 @@
/*
* 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 <unistd.h>
#include <boost/filesystem.hpp>
#include "core/posix/fork.h"
#include "core/posix/exec.h"
#include "anbox/utils.h"
#include "anbox/logger.h"
#include "anbox/config.h"
#include "anbox/container.h"
#include "anbox/common/fd.h"
extern "C" int bwrap_main(int argc, char **argv);
namespace fs = boost::filesystem;
namespace anbox {
Container::Spec Container::Spec::Default() {
Spec spec;
spec.init_command = "/init";
spec.environment.insert({"PATH", "/system/bin:/system/sbin:/system/xbin"});
return spec;
}
std::shared_ptr<Container> Container::create(const Container::Spec &spec) {
return std::shared_ptr<Container>(new Container{spec});
}
Container::Container(const Container::Spec &spec) :
spec_(spec),
child_(core::posix::ChildProcess::invalid()),
child_group_(core::posix::ProcessGroup::invalid()) {
}
Container::~Container() {
stop();
}
void Container::start() {
std::vector<std::string> arguments = {
"--ro-bind", spec_.rootfs_path, "/",
"--dev", "/dev",
"--proc", "/proc",
"--unshare-user",
"--unshare-ipc",
"--unshare-pid",
"--unshare-net",
"--unshare-uts",
// We will take UID 0 (root) inside the container
"--uid", "0",
// We will take GID 0 (root) inside the container
"--gid", "0",
"--chdir", "/",
"--pid-file", utils::string_format("%s/pid", config::data_path()),
};
for (const auto &dir : spec_.temporary_dirs) {
arguments.push_back("--tmpfs");
arguments.push_back(dir);
}
for (const auto &path : spec_.dev_bind_paths) {
arguments.push_back("--dev-bind");
arguments.push_back(path);
arguments.push_back(path);
}
for (const auto &path : spec_.bind_paths) {
arguments.push_back("--bind");
arguments.push_back(path.first);
arguments.push_back(path.second);
}
for (const auto &env : spec_.environment) {
arguments.push_back("--setenv");
arguments.push_back(env.first);
arguments.push_back(env.second);
}
arguments.push_back(spec_.init_command);
child_ = core::posix::fork([&]() {
char **it, **pargv;
it = pargv = new char*[arguments.size() + 2];
*it = strdup("bwrap");
it++;
for (auto arg : arguments) {
*it = ::strdup(arg.c_str());
it++;
}
*it = nullptr;
if (bwrap_main(arguments.size() + 1, pargv))
return core::posix::exit::Status::failure;
return core::posix::exit::Status::success;
}, core::posix::StandardStream::empty);
child_group_ = child_.process_group_or_throw();
}
void Container::stop() {
child_group_.send_signal_or_throw(core::posix::Signal::sig_kill);
}
} // namespace anbox

65
src/anbox/container.h Normal file
View file

@ -0,0 +1,65 @@
/*
* 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_H_
#define ANBOX_CONTAINER_H_
#include <string>
#include <vector>
#include <map>
#include <memory.h>
#include "core/posix/child_process.h"
#include "anbox/do_not_copy_or_move.h"
#include "anbox/runtime.h"
#include <sys/types.h>
namespace anbox {
class Container : public DoNotCopyOrMove,
public std::enable_shared_from_this<Container> {
public:
class Spec {
public:
static Spec Default();
std::string rootfs_path;
std::string init_command;
std::vector<std::string> temporary_dirs;
std::map<std::string,std::string> bind_paths;
std::vector<std::string> dev_bind_paths;
std::map<std::string,std::string> environment;
};
static std::shared_ptr<Container> create(const Spec &spec);
virtual ~Container();
void start();
void stop();
private:
Container(const Container::Spec &spec);
Spec spec_;
core::posix::ChildProcess child_;
core::posix::ProcessGroup child_group_;
};
} // namespace anbox
#endif

View file

@ -0,0 +1,148 @@
/*
* 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_connector.h"
#include "anbox/config.h"
#include "anbox/utils.h"
#include "anbox/logger.h"
#include "core/posix/exec.h"
#include <boost/filesystem.hpp>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
namespace fs = boost::filesystem;
namespace {
class NamespaceAttacher {
public:
enum class ns_type {
user,
pid,
uts,
mount,
ipc,
net,
};
static std::string ns_type_to_string(ns_type type) {
switch (type) {
case ns_type::user:
return "user";
case ns_type::pid:
return "pid";
case ns_type::uts:
return "uts";
case ns_type::mount:
return "mnt";
case ns_type::ipc:
return "ipc";
case ns_type::net:
return "net";
default:
break;
}
BOOST_THROW_EXCEPTION(std::runtime_error("Unknown namespace type"));
}
NamespaceAttacher(const std::vector<ns_type> &types, pid_t pid) :
pid_(pid) {
attach(types);
}
~NamespaceAttacher() {
}
private:
void attach(const std::vector<ns_type> &types) {
std::vector<int> fds;
for (const auto &type : types) {
const auto path = anbox::utils::string_format("/proc/%lu/ns/%s", pid_, ns_type_to_string(type));
if (!fs::exists(fs::path(path)))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open namespace file"));
const auto fd = ::open(path.c_str(), O_RDONLY);
if (fd < 0)
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to open namespace file"));
fds.push_back(fd);
}
for (const auto &fd : fds) {
if (::setns(fd, 0) == -1)
BOOST_THROW_EXCEPTION(std::runtime_error("Could not attach to namespace"));
::close(fd);
}
}
pid_t pid_;
};
}
namespace anbox {
ContainerConnector::ContainerConnector() {
}
ContainerConnector::~ContainerConnector() {
}
int ContainerConnector::run(const std::string &path) {
const auto pid = std::stol(utils::read_file_if_exists_or_throw(
utils::string_format("%s/pid", config::data_path())));
if (!fs::is_directory(fs::path(utils::string_format("/proc/%i", pid))))
BOOST_THROW_EXCEPTION(std::runtime_error("Container isn't running"));
namespaces_ = std::make_shared<NamespaceAttacher>(std::vector<NamespaceAttacher::ns_type>{
NamespaceAttacher::ns_type::user,
NamespaceAttacher::ns_type::mount,
NamespaceAttacher::ns_type::pid,
NamespaceAttacher::ns_type::uts,
NamespaceAttacher::ns_type::ipc,
NamespaceAttacher::ns_type::net,
}, pid);
// A few things we want to preset in our env within the container shell
std::map<std::string, std::string> env = {
{ "ANDROID_ROOT", "/" }
};
auto child = core::posix::exec(path, {}, env, core::posix::StandardStream::empty, [this]() {
// We're now in the namespace bwrap spawns up for the container which has
// a /newroot directory pointing to the new root filesystem we get from
// Android and is what we need to change to in order to work within
// the Anroid system.
if (::chroot("/newroot") != 0)
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to enter container root filesystem"));
chdir("/");
});
child.wait_for(core::posix::wait::Flags::untraced);
return EXIT_SUCCESS;
}
} // namespace

View file

@ -0,0 +1,40 @@
/*
* 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_CONNECTOR_H_
#define ANBOX_CONTAINER_CONNECTOR_H_
#include <memory>
namespace {
class NamespaceAttacher;
}
namespace anbox {
class ContainerConnector {
public:
ContainerConnector();
~ContainerConnector();
int run(const std::string &path);
private:
std::shared_ptr<NamespaceAttacher> namespaces_;
};
} // namespace
#endif

55
src/anbox/daemon.cpp Normal file
View file

@ -0,0 +1,55 @@
/*
* 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 <sys/prctl.h>
#include <signal.h>
#include "anbox/logger.h"
#include "anbox/daemon.h"
#include "anbox/config.h"
#include "anbox/cmds/version.h"
#include "anbox/cmds/run.h"
#include "anbox/cmds/shell.h"
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
namespace anbox {
Daemon::Daemon() :
cmd{cli::Name{"anbox"}, cli::Usage{"anbox"}, cli::Description{"The Android in a Box runtime"}} {
cmd.command(std::make_shared<cmds::Version>())
.command(std::make_shared<cmds::Run>())
.command(std::make_shared<cmds::Shell>());
}
int Daemon::Run(const std::vector<std::string> &arguments)
try {
ensure_data_path();
return cmd.run({std::cin, std::cout, arguments});
}
catch(std::exception &err) {
ERROR("%s", err.what());
}
void Daemon::ensure_data_path() {
if (!fs::is_directory(fs::path(config::data_path())))
fs::create_directories(fs::path(config::data_path()));
}
} // namespace anbox

41
src/anbox/daemon.h Normal file
View file

@ -0,0 +1,41 @@
/*
* 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_DAEMON_H_
#define ANBOX_DAEMON_H_
#include <vector>
#include <string>
#include "anbox/do_not_copy_or_move.h"
#include "anbox/cli.h"
namespace anbox {
class Daemon : public DoNotCopyOrMove {
public:
Daemon();
int Run(const std::vector<std::string> &arguments);
private:
void ensure_data_path();
cli::CommandWithSubcommands cmd;
};
} // namespace anbox
#endif

44
src/anbox/defer_action.h Normal file
View file

@ -0,0 +1,44 @@
/*
* 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_DEFER_ACTION_H_
#define ANBOX_DEFER_ACTION_H_
#include <functional>
#include "anbox/do_not_copy_or_move.h"
namespace anbox {
class DeferAction : public DoNotCopyOrMove {
public:
DeferAction(const std::function<void()> action) :
action_(action) {
}
~DeferAction() {
if (action_)
action_();
}
private:
std::function<void()> action_;
};
} // namespace anbox
#endif

View file

@ -0,0 +1,38 @@
/*
* 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_DO_NOT_COPY_OR_MOVE_H_
#define ANBOX_DO_NOT_COPY_OR_MOVE_H_
namespace anbox {
class DoNotCopyOrMove
{
public:
DoNotCopyOrMove(const DoNotCopyOrMove&) = delete;
DoNotCopyOrMove(DoNotCopyOrMove&&) = delete;
virtual ~DoNotCopyOrMove() = default;
DoNotCopyOrMove& operator=(const DoNotCopyOrMove&) = delete;
DoNotCopyOrMove& operator=(DoNotCopyOrMove&&) = delete;
protected:
DoNotCopyOrMove() = default;
};
}
#endif

View file

@ -0,0 +1,79 @@
/*
* 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/logger.h"
#include "anbox/graphics/gl_renderer_server.h"
#include "OpenglRender/render_api.h"
#include <boost/throw_exception.hpp>
#include <stdexcept>
#include <cstdarg>
namespace anbox {
namespace graphics {
GLRendererServer::GLRendererServer() {
// Force the host EGL/GLES libraries as translator implementation
::setenv("ANDROID_EGL_LIB", "libEGL.so.1", 1);
::setenv("ANDROID_GLESv1_LIB", "libGLESv1_CM.so.1", 1);
::setenv("ANDROID_GLESv2_LIB", "libGLESv2.so.2", 1);
if (!initLibrary())
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize OpenGL renderer"));
setStreamMode(RENDER_API_STREAM_MODE_UNIX);
}
GLRendererServer::~GLRendererServer() {
destroyOpenGLSubwindow();
stopOpenGLRenderer();
}
void logger_write(const char *format, ...) {
char message[2048];
va_list args;
va_start(args, format);
vsnprintf(message, sizeof(message) - 1, format, args);
va_end(args);
DEBUG("%s", message);
}
void GLRendererServer::start() {
emugl_logger_struct log_funcs;
log_funcs.coarse = logger_write;
log_funcs.fine = logger_write;
char server_addr[256] = { 0 };
if (!initOpenGLRenderer(1080, 1920, true, server_addr, sizeof(server_addr), log_funcs, logger_write))
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to setup OpenGL renderer"));
socket_path_ = server_addr;
DEBUG("socket path %s", socket_path_);
// Create the window we use for rendering the output we get from the
// Android container. This will internally construct a Mir surface
// and use the host EGL/GLES libraries for rendering.
showOpenGLSubwindow(0, 0, 0, 1080, 1920, 1080, 1920, 1.0f, 0);
}
std::string GLRendererServer::socket_path() const {
return socket_path_;
}
} // namespace graphics
} // 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_GRAPHICS_GL_RENDERER_SERVER_H_
#define ANBOX_GRAPHICS_GL_RENDERER_SERVER_H_
#include <string>
namespace anbox {
namespace graphics {
class GLRendererServer {
public:
GLRendererServer();
~GLRendererServer();
void start();
std::string socket_path() const;
private:
std::string socket_path_;
};
} // namespace graphics
} // namespace anbox
#endif

View file

@ -0,0 +1,64 @@
/*
* 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/logger.h"
#include "anbox/graphics/opengles_message_processor.h"
#include "anbox/network/socket_messenger.h"
#include "anbox/network/connections.h"
#include "anbox/network/delegate_message_processor.h"
namespace anbox {
namespace graphics {
OpenGlesMessageProcessor::OpenGlesMessageProcessor(const std::string &renderer_socket_path,
const std::shared_ptr<Runtime> &rt,
const std::shared_ptr<network::SocketMessenger> &messenger) :
client_messenger_(messenger) {
connect_and_attach(renderer_socket_path, rt);
}
OpenGlesMessageProcessor::~OpenGlesMessageProcessor() {
}
void OpenGlesMessageProcessor::connect_and_attach(const std::string &socket_path,
const std::shared_ptr<Runtime> &rt) {
auto socket = std::make_shared<boost::asio::local::stream_protocol::socket>(rt->service());
socket->connect(boost::asio::local::stream_protocol::endpoint(socket_path));
messenger_ = std::make_shared<network::SocketMessenger>(socket);
renderer_ = std::make_shared<network::SocketConnection>(
messenger_,
0,
std::make_shared<network::Connections<network::SocketConnection>>(),
std::make_shared<network::DelegateMessageProcessor>([&](const std::vector<std::uint8_t> &data) {
client_messenger_->send(reinterpret_cast<const char*>(data.data()), data.size());
return true;
}));
renderer_->read_next_message();
}
bool OpenGlesMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
messenger_->send(reinterpret_cast<const char*>(data.data()), data.size());
return true;
}
} // namespace graphics
} // namespace anbox

View file

@ -0,0 +1,52 @@
/*
* 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_GRAPHICS_OPENGLES_MESSAGE_PROCESSOR_H_
#define ANBOX_GRAPHICS_OPENGLES_MESSAGE_PROCESSOR_H_
#include <memory>
#include <boost/asio.hpp>
#include "anbox/runtime.h"
#include "anbox/network/message_processor.h"
#include "anbox/network/socket_messenger.h"
#include "anbox/network/socket_connection.h"
namespace anbox {
namespace graphics {
class OpenGlesMessageProcessor : public network::MessageProcessor {
public:
OpenGlesMessageProcessor(const std::string &renderer_socket_path,
const std::shared_ptr<Runtime> &rt,
const std::shared_ptr<network::SocketMessenger> &messenger);
~OpenGlesMessageProcessor();
bool process_data(const std::vector<std::uint8_t> &data) override;
private:
void connect_and_attach(const std::string &socket_path,
const std::shared_ptr<Runtime> &rt);
std::shared_ptr<network::SocketMessenger> client_messenger_;
std::shared_ptr<network::SocketMessenger> messenger_;
std::shared_ptr<network::SocketConnection> renderer_;
};
} // namespace graphics
} // namespace anbox
#endif

154
src/anbox/logger.cpp Normal file
View file

@ -0,0 +1,154 @@
/*
* Copyright (C) 2015 Canonical, Ltd.
*
* 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 <thread>
#define BOOST_LOG_DYN_LINK
#include <boost/date_time.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/manipulators.hpp>
#include <boost/log/utility/setup.hpp>
#include "anbox/logger.h"
namespace {
namespace attrs {
BOOST_LOG_ATTRIBUTE_KEYWORD(Severity, "anbox::Severity", anbox::Logger::Severity)
BOOST_LOG_ATTRIBUTE_KEYWORD(Location, "Location", anbox::Logger::Location)
BOOST_LOG_ATTRIBUTE_KEYWORD(Timestamp, "Timestamp", boost::posix_time::ptime)
}
struct BoostLogLogger : public anbox::Logger {
BoostLogLogger() :
initialized_(false) {
}
void Init(const anbox::Logger::Severity &severity = anbox::Logger::Severity::kWarning) override {
if (initialized_)
return;
boost::log::formatter formatter = boost::log::expressions::stream
<< "[" << attrs::Severity << " "
<< boost::log::expressions::format_date_time< boost::posix_time::ptime >("Timestamp", "%Y-%m-%d %H:%M:%S")
<< "] "
<< boost::log::expressions::if_(boost::log::expressions::has_attr(attrs::Location))
[
boost::log::expressions::stream << "[" << attrs::Location << "] "
]
<< boost::log::expressions::smessage;
boost::log::core::get()->remove_all_sinks();
auto logger = boost::log::add_console_log(std::cout);
logger->set_formatter(formatter);
// FIXME need to enable this once we found how we wrap this
// properly into our service architecture. For now left as
// it is.
boost::ignore_unused_variable_warning(severity);
// logger->set_filter(attrs::Severity < severity);
initialized_ = true;
}
void Log(Severity severity, const std::string& message, const boost::optional<Location> &loc) {
if (!initialized_)
Init();
if (auto rec = boost::log::trivial::logger::get().open_record()) {
boost::log::record_ostream out{rec};
out << boost::log::add_value(attrs::Severity, severity)
<< boost::log::add_value(attrs::Timestamp, boost::posix_time::microsec_clock::universal_time())
<< message;
if (loc) {
// We have to pass in a temporary as boost::log (<= 1.55) expects a
// mutable reference to be passed to boost::log::add_value(...).
auto tmp = *loc;
out << boost::log::add_value(attrs::Location, tmp);
}
boost::log::trivial::logger::get().push_record(std::move(rec));
}
}
private:
bool initialized_;
};
std::shared_ptr<anbox::Logger>& MutableInstance() {
static std::shared_ptr<anbox::Logger> instance{new BoostLogLogger()};
return instance;
}
void SetInstance(const std::shared_ptr<anbox::Logger>& logger) {
MutableInstance() = logger;
}
}
namespace anbox {
void Logger::Trace(const std::string& message, const boost::optional<Location>& location) {
Log(Severity::kTrace, message, location);
}
void Logger::Debug(const std::string& message, const boost::optional<Location>& location) {
Log(Severity::kDebug, message, location);
}
void Logger::Info(const std::string& message, const boost::optional<Location>& location) {
Log(Severity::kInfo, message, location);
}
void Logger::Warning(const std::string& message, const boost::optional<Location>& location) {
Log(Severity::kWarning, message, location);
}
void Logger::Error(const std::string& message, const boost::optional<Location>& location) {
Log(Severity::kError, message, location);
}
void Logger::Fatal(const std::string& message, const boost::optional<Location>& location) {
Log(Severity::kFatal, message, location);
}
std::ostream& operator<<(std::ostream& strm, anbox::Logger::Severity severity) {
switch (severity) {
case anbox::Logger::Severity::kTrace: return strm << "TT";
case anbox::Logger::Severity::kDebug: return strm << "DD";
case anbox::Logger::Severity::kInfo: return strm << "II";
case anbox::Logger::Severity::kWarning: return strm << "WW";
case anbox::Logger::Severity::kError: return strm << "EE";
case anbox::Logger::Severity::kFatal: return strm << "FF";
default: return strm << static_cast<uint>(severity);
}
}
std::ostream& operator<<(std::ostream& out, const Logger::Location &location) {
return out << utils::string_format("%s:%d@%s", boost::filesystem::path(location.file).filename().string(), location.line, location.function);
}
Logger& Log() {
return *MutableInstance();
}
void SetLogger(const std::shared_ptr<Logger>& logger) {
SetInstance(logger);
}
} // namespace anbox

118
src/anbox/logger.h Normal file
View file

@ -0,0 +1,118 @@
/*
* Copyright (C) 2015 Canonical, Ltd.
*
* 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_LOGGER_H_
#define ANBOX_LOGGER_H_
#include <boost/optional.hpp>
#include <string>
#include <memory.h>
#include "anbox/do_not_copy_or_move.h"
#include "anbox/utils.h"
namespace anbox {
// A Logger enables persisting of messages describing & explaining the
// state of the system.
class Logger : public DoNotCopyOrMove {
public:
// Severity enumerates all known severity levels
// applicable to log messages.
enum class Severity {
kTrace,
kDebug,
kInfo,
kWarning,
kError,
kFatal
};
// A Location describes the origin of a log message.
struct Location {
std::string file; // The name of the file that contains the log message.
std::string function; // The function that contains the log message.
std::uint32_t line; // The line in file that resulted in the log message.
};
virtual void Init(const Severity &severity = Severity::kWarning) = 0;
virtual void Log(Severity severity, const std::string &message, const boost::optional<Location>& location) = 0;
virtual void Trace(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
virtual void Debug(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
virtual void Info(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
virtual void Warning(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
virtual void Error(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
virtual void Fatal(const std::string& message, const boost::optional<Location>& location = boost::optional<Location>{});
template<typename... T>
void Tracef(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
Trace(utils::string_format(pattern, std::forward<T>(args)...), location);
}
template<typename... T>
void Debugf(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
Debug(utils::string_format(pattern, std::forward<T>(args)...), location);
}
template<typename... T>
void Infof(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
Info(utils::string_format(pattern, std::forward<T>(args)...), location);
}
template<typename... T>
void Warningf(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
Warning(utils::string_format(pattern, std::forward<T>(args)...), location);
}
template<typename... T>
void Errorf(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
Error(utils::string_format(pattern, std::forward<T>(args)...), location);
}
template<typename... T>
void Fatalf(const boost::optional<Location>& location, const std::string& pattern, T&&...args) {
Fatal(utils::string_format(pattern, std::forward<T>(args)...), location);
}
protected:
Logger() = default;
};
// operator<< inserts severity into out.
std::ostream& operator<<(std::ostream& out, Logger::Severity severity);
// operator<< inserts location into out.
std::ostream& operator<<(std::ostream& out, const Logger::Location &location);
// Log returns the mcs-wide configured logger instance.
// Save to call before/after main.
Logger& Log();
// SetLog installs the given logger as mcs-wide default logger.
void SetLogger(const std::shared_ptr<Logger>& logger);
}
#define TRACE(...) anbox::Log().Tracef(anbox::Logger::Location{__FILE__, __FUNCTION__, __LINE__}, __VA_ARGS__)
#define DEBUG(...) anbox::Log().Debugf(anbox::Logger::Location{__FILE__, __FUNCTION__, __LINE__}, __VA_ARGS__)
#define INFO(...) anbox::Log().Infof(anbox::Logger::Location{__FILE__, __FUNCTION__, __LINE__}, __VA_ARGS__)
#define WARNING(...) anbox::Log().Warningf(anbox::Logger::Location{__FILE__, __FUNCTION__, __LINE__}, __VA_ARGS__)
#define ERROR(...) anbox::Log().Errorf(anbox::Logger::Location{__FILE__, __FUNCTION__, __LINE__}, __VA_ARGS__)
#define FATAL(...) anbox::Log().Fatalf(anbox::Logger::Location{__FILE__, __FUNCTION__, __LINE__}, __VA_ARGS__)
#endif

View file

@ -0,0 +1,31 @@
/*
* 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/network/connection_context.h"
namespace anbox {
namespace network {
ConnectionContext::ConnectionContext(
std::function<void()> const connect_handler,
Connector const* connector) :
connect_handler(connect_handler),
connector(connector) {
}
} // namespace anbox
} // namespace network

View file

@ -0,0 +1,48 @@
/*
* Copyright © 2014 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Alan Griffiths <alan@octopull.co.uk>
*/
#ifndef ANBOX_NETWORK_CONNECTION_CONTEXT_H_
#define ANBOX_NETWORK_CONNECTION_CONTEXT_H_
#include <functional>
#include <memory>
namespace anbox {
namespace network {
class Connector;
class ConnectionContext
{
public:
ConnectionContext(Connector const* connector) :
ConnectionContext([](){}, connector) {}
ConnectionContext(
std::function<void()> const connect_handler,
Connector const* connector);
int fd_for_new_client(std::function<void()> const& connect_handler) const;
void handle_client_connect() const { connect_handler(); }
private:
std::function<void()> const connect_handler;
Connector const* const connector;
};
} // namespace anbox
} // namespace network
#endif

View file

@ -0,0 +1,16 @@
/*
* 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/>.
*
*/

View file

@ -0,0 +1,35 @@
/*
* 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_NETWORK_CONNECTION_CREATOR_H_
#define ANBOX_NETWORK_CONNECTION_CREATOR_H_
#include <boost/asio.hpp>
#include <memory>
#include "anbox/do_not_copy_or_move.h"
namespace anbox {
namespace network {
class ConnectionCreator : public DoNotCopyOrMove {
public:
virtual void create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket) = 0;
};
} // namespace anbox
} // namespace network
#endif

View file

@ -0,0 +1,71 @@
/*
* Copyright © 2012-2014 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Alan Griffiths <alan@octopull.co.uk>
*/
#ifndef ANBOX_NETWORK_CONNECTIONS_H_
#define ANBOX_NETWORK_CONNECTIONS_H_
#include <memory>
#include <mutex>
#include <map>
namespace anbox {
namespace network {
template<class Connection>
class Connections
{
public:
Connections() {}
~Connections() { clear(); }
void add(std::shared_ptr<Connection> const& connection)
{
std::unique_lock<std::mutex> lock(mutex);
connections[connection->id()] = connection;
}
void remove(int id)
{
std::unique_lock<std::mutex> lock(mutex);
connections.erase(id);
}
bool includes(int id) const
{
std::unique_lock<std::mutex> lock(mutex);
return connections.find(id) != connections.end();
}
void clear()
{
std::unique_lock<std::mutex> lock(mutex);
connections.clear();
}
private:
Connections(Connections const&) = delete;
Connections& operator =(Connections const&) = delete;
std::mutex mutex;
std::map<int, std::shared_ptr<Connection>> connections;
};
} // namespace anbox
} // namespace network
#endif

View file

@ -0,0 +1,29 @@
/*
* 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_NETWORK_CONNECTOR_H
#define ANBOX_NETWORK_CONNECTOR_H
namespace anbox {
namespace network {
class Connector {
public:
};
} // namespace network
} // namespace anbox
#endif

View file

@ -0,0 +1,48 @@
/*
* 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_NETWORK_DELEGATE_MESSAGE_PROCESSOR_H_
#define ANBOX_NETWORK_DELEGATE_MESSAGE_PROCESSOR_H_
#include "anbox/network/message_processor.h"
#include <functional>
namespace anbox {
namespace network {
class DelegateMessageProcessor : public MessageProcessor {
public:
DelegateMessageProcessor(std::function<bool(const std::vector<std::uint8_t>&)> delegate) :
delegate_(delegate) {
}
bool process_data(const std::vector<std::uint8_t> &data) override {
if (!delegate_)
return false;
return delegate_(data);
}
private:
std::function<bool(const std::vector<std::uint8_t>&)> delegate_;
};
} // namespace network
} // namespace anbox
#endif

View file

@ -0,0 +1,192 @@
/*
* Copyright © 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
*/
#include "anbox/network/fd_socket_transmission.h"
#include "anbox/common/variable_length_array.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <boost/throw_exception.hpp>
#include <boost/exception/errinfo_errno.hpp>
#include <stdexcept>
namespace anbox {
socket_error::socket_error(std::string const& message) :
std::system_error(errno, std::system_category(), message)
{
}
socket_disconnected_error::socket_disconnected_error(std::string const& message) :
std::system_error(errno, std::system_category(), message)
{
}
fd_reception_error::fd_reception_error(std::string const& message) :
std::runtime_error(message)
{
}
void send_fds(
Fd const& socket,
std::vector<Fd> const& fds)
{
if (fds.size() > 0)
{
// We send dummy data
struct iovec iov;
char dummy_iov_data = 'M';
iov.iov_base = &dummy_iov_data;
iov.iov_len = 1;
// Allocate space for control message
static auto const builtin_n_fds = 5;
static auto const builtin_cmsg_space = CMSG_SPACE(builtin_n_fds * sizeof(int));
auto const fds_bytes = fds.size() * sizeof(int);
VariableLengthArray<builtin_cmsg_space> control{CMSG_SPACE(fds_bytes)};
// Silence valgrind uninitialized memory complaint
memset(control.data(), 0, control.size());
// Message to send
struct msghdr header;
header.msg_name = NULL;
header.msg_namelen = 0;
header.msg_iov = &iov;
header.msg_iovlen = 1;
header.msg_controllen = control.size();
header.msg_control = control.data();
header.msg_flags = 0;
// Control message contains file descriptors
struct cmsghdr *message = CMSG_FIRSTHDR(&header);
message->cmsg_len = CMSG_LEN(fds_bytes);
message->cmsg_level = SOL_SOCKET;
message->cmsg_type = SCM_RIGHTS;
int* const data = reinterpret_cast<int*>(CMSG_DATA(message));
int i = 0;
for (auto& fd : fds)
data[i++] = fd;
auto const sent = sendmsg(socket, &header, MSG_NOSIGNAL);
if (sent < 0)
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to send fds: " + std::string(strerror(errno))));
}
}
bool socket_error_is_transient(int error_code)
{
return (error_code == EINTR);
}
void receive_data(Fd const& socket, void* buffer, size_t bytes_requested, std::vector<Fd>& fds)
{
if (bytes_requested == 0)
BOOST_THROW_EXCEPTION(std::logic_error("Attempted to receive 0 bytes"));
size_t bytes_read{0};
unsigned fds_read{0};
while (bytes_read < bytes_requested)
{
// Store the data in the buffer requested
struct iovec iov;
iov.iov_base = static_cast<uint8_t*>(buffer) + bytes_read;
iov.iov_len = bytes_requested - bytes_read;
// Allocate space for control message
static auto const builtin_n_fds = 5;
static auto const builtin_cmsg_space = CMSG_SPACE(builtin_n_fds * sizeof(int));
auto const fds_bytes = (fds.size() - fds_read) * sizeof(int);
VariableLengthArray<builtin_cmsg_space> control{CMSG_SPACE(fds_bytes)};
// Message to read
struct msghdr header;
header.msg_name = NULL;
header.msg_namelen = 0;
header.msg_iov = &iov;
header.msg_iovlen = 1;
header.msg_controllen = control.size();
header.msg_control = control.data();
header.msg_flags = 0;
ssize_t const result = recvmsg(socket, &header, MSG_NOSIGNAL | MSG_WAITALL);
if (result == 0)
BOOST_THROW_EXCEPTION(socket_disconnected_error("Failed to read message from server: server has shutdown"));
if (result < 0)
{
if (socket_error_is_transient(errno))
continue;
if (errno == EAGAIN)
continue;
if (errno == EPIPE)
BOOST_THROW_EXCEPTION(
boost::enable_error_info(socket_disconnected_error("Failed to read message from server"))
<< boost::errinfo_errno(errno));
BOOST_THROW_EXCEPTION(
boost::enable_error_info(socket_error("Failed to read message from server"))
<< boost::errinfo_errno(errno));
}
bytes_read += result;
// If we get a proper control message, copy the received
// file descriptors back to the caller
struct cmsghdr const* const cmsg = CMSG_FIRSTHDR(&header);
if (cmsg)
{
if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SCM_CREDENTIALS))
BOOST_THROW_EXCEPTION(fd_reception_error("received SCM_CREDENTIALS when expecting fd"));
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS)
BOOST_THROW_EXCEPTION(fd_reception_error("Invalid control message for receiving file descriptors"));
int const* const data = reinterpret_cast<int const*>CMSG_DATA(cmsg);
ptrdiff_t const header_size = reinterpret_cast<char const*>(data) - reinterpret_cast<char const*>(cmsg);
int const nfds = (cmsg->cmsg_len - header_size) / sizeof(int);
// NOTE: This relies on the file descriptor cmsg being read
// (and written) atomically.
if (cmsg->cmsg_len > CMSG_LEN(fds_bytes) || (header.msg_flags & MSG_CTRUNC))
{
for (int i = 0; i < nfds; i++)
::close(data[i]);
BOOST_THROW_EXCEPTION(std::runtime_error("Received more fds than expected"));
}
// We can't properly pass Fds through google::protobuf::Message,
// which is where these get shoved.
//
// When we have our own RPC generator plugin and aren't using deprecated
// Protobuf features this can go away.
for (int i = 0; i < nfds; i++)
fds[fds_read + i] = Fd{IntOwnedFd{data[i]}};
fds_read += nfds;
}
}
if (fds_read < fds.size())
{
for (auto fd : fds)
if (fd >= 0)
::close(fd);
fds.clear();
BOOST_THROW_EXCEPTION(std::runtime_error("Received fewer fds than expected"));
}
}
} // namespace anbox

View file

@ -0,0 +1,50 @@
/*
* Copyright © 2014 Canonical Ltd.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser 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 warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
*/
#ifndef ANBOX_NETWORK_FD_SOCKET_TRANSMISSION_H_
#define ANBOX_NETWORK_FD_SOCKET_TRANSMISSION_H_
#include "anbox/common/fd.h"
#include <vector>
#include <system_error>
#include <stdexcept>
namespace anbox
{
struct socket_error : std::system_error
{
socket_error(std::string const& message);
};
struct socket_disconnected_error : std::system_error
{
socket_disconnected_error(std::string const& message);
};
struct fd_reception_error : std::runtime_error
{
fd_reception_error(std::string const& message);
};
bool socket_error_is_transient(int error_code);
void send_fds(Fd const& socket, std::vector<Fd> const& fd);
void receive_data(Fd const& socket, void* buffer, size_t bytes_requested, std::vector<Fd>& fds);
}
#endif

View file

@ -0,0 +1,34 @@
/*
* 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_NETWORK_MESSAGE_PROCESSOR_H
#define ANBOX_NETWORK_MESSAGE_PROCESSOR_H
#include <vector>
#include <cstdint>
namespace anbox {
namespace network {
class MessageProcessor {
public:
virtual ~MessageProcessor() { }
virtual bool process_data(const std::vector<std::uint8_t> &data) = 0;
};
} // namespace network
} // namespace anbox
#endif

View file

@ -0,0 +1,48 @@
/*
* Copyright © 2013-2014 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
*/
#ifndef ANBOX_NETWORK_MESSAGE_RECEIVER_H_
#define ANBOX_NETWORK_MESSAGE_RECEIVER_H_
#include <vector>
#include <functional>
#include <boost/asio.hpp>
#include "anbox/common/fd.h"
namespace anbox {
namespace network {
class MessageReceiver
{
public:
//receive message from the socket. 'handler' will be called when 'buffer' has been filled with exactly 'size'
typedef std::function<void(boost::system::error_code const&, size_t)> AnboxReadHandler;
virtual void async_receive_msg(AnboxReadHandler const& handler, boost::asio::mutable_buffers_1 const& buffer) = 0;
virtual boost::system::error_code receive_msg(boost::asio::mutable_buffers_1 const& buffer) = 0;
virtual size_t available_bytes() = 0;
protected:
MessageReceiver() = default;
virtual ~MessageReceiver() = default;
MessageReceiver(MessageReceiver const&) = delete;
MessageReceiver& operator=(MessageReceiver const&) = delete;
};
} // namespace network
} // namespace anbox
#endif

View file

@ -0,0 +1,40 @@
/*
* Copyright © 2012 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Alan Griffiths <alan@octopull.co.uk>
*/
#ifndef ANBOX_NETWORK_MESSAGE_SENDER_H_
#define ANBOX_NETWORK_MESSAGE_SENDER_H_
#include <sys/types.h>
namespace anbox {
namespace network {
class MessageSender
{
public:
virtual void send(char const* data, size_t length) = 0;
protected:
MessageSender() = default;
virtual ~MessageSender() = default;
MessageSender(MessageSender const&) = delete;
MessageSender& operator=(MessageSender const&) = delete;
};
} // namespace anbox
} // namespace network
#endif

View file

@ -0,0 +1,124 @@
/*
* 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 <sys/stat.h>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <boost/exception/errinfo_errno.hpp>
#include "anbox/network/published_socket_connector.h"
#include "anbox/network/connection_context.h"
namespace {
bool socket_file_exists(std::string const& filename)
{
struct stat statbuf;
bool exists = (0 == stat(filename.c_str(), &statbuf));
/* Avoid removing non-socket files */
bool is_socket_type = (statbuf.st_mode & S_IFMT) == S_IFSOCK;
return exists && is_socket_type;
}
bool socket_exists(std::string const& socket_name)
{
try
{
std::string socket_path{socket_name};
/* In case an abstract socket name exists with the same name*/
socket_path.insert(std::begin(socket_path), ' ');
/* If the name is contained in this table, it signifies
* a process is truly using that socket connection
*/
std::ifstream socket_names_file("/proc/net/unix");
std::string line;
while (std::getline(socket_names_file, line))
{
auto index = line.find(socket_path);
/* check for complete match */
if (index != std::string::npos &&
(index + socket_path.length()) == line.length())
{
return true;
}
}
}
catch (...)
{
/* Assume the socket exists */
return true;
}
return false;
}
std::string remove_if_stale(std::string const& socket_name)
{
if (socket_file_exists(socket_name) && !socket_exists(socket_name))
{
if (std::remove(socket_name.c_str()) != 0)
{
BOOST_THROW_EXCEPTION(
boost::enable_error_info(
std::runtime_error("Failed removing stale socket file")) << boost::errinfo_errno(errno));
}
}
return socket_name;
}
}
namespace anbox {
namespace network {
PublishedSocketConnector::PublishedSocketConnector(
const std::string& socket_file,
const std::shared_ptr<Runtime> &rt,
const std::shared_ptr<ConnectionCreator> &connection_creator) :
socket_file_(remove_if_stale(socket_file)),
runtime_(rt),
connection_creator_(connection_creator),
acceptor_(rt->service(), socket_file_) {
start_accept();
}
PublishedSocketConnector::~PublishedSocketConnector() {
}
void PublishedSocketConnector::start_accept() {
auto socket = std::make_shared<boost::asio::local::stream_protocol::socket>(runtime_->service());
acceptor_.async_accept(
*socket,
[this, socket](boost::system::error_code const& err) {
on_new_connection(socket, err);
});
}
void PublishedSocketConnector::on_new_connection(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket,
boost::system::error_code const& err) {
if (!err)
connection_creator_->create_connection_for(socket);
start_accept();
}
} // namespace network
} // namespace anbox

View file

@ -0,0 +1,56 @@
/*
* 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_PUBLISHEDSOCKETCONNECTOR_H
#define ANBOX_PUBLISHEDSOCKETCONNECTOR_H
#include <boost/asio/local/stream_protocol.hpp>
#include "anbox/do_not_copy_or_move.h"
#include "anbox/runtime.h"
#include "anbox/network/connector.h"
#include "anbox/network/connection_creator.h"
namespace anbox {
namespace network {
class PublishedSocketConnector : public DoNotCopyOrMove,
public Connector {
public:
explicit PublishedSocketConnector(
const std::string& socket_file,
const std::shared_ptr<Runtime> &rt,
const std::shared_ptr<ConnectionCreator> &connection_creator);
~PublishedSocketConnector() noexcept;
std::string socket_file() const { return socket_file_; }
private:
void start_accept();
void on_new_connection(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket,
boost::system::error_code const& err);
const std::string socket_file_;
std::shared_ptr<Runtime> runtime_;
std::shared_ptr<ConnectionCreator> connection_creator_;
boost::asio::local::stream_protocol::acceptor acceptor_;
};
} // namespace network
} // namespace anbox
#endif

View file

@ -0,0 +1,103 @@
/*
* 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 <string>
#include "anbox/logger.h"
#include "anbox/network/qemu_pipe_connection_creator.h"
#include "anbox/network/socket_messenger.h"
#include "anbox/graphics/opengles_message_processor.h"
#include "anbox/support/boot_properties_message_processor.h"
#include "anbox/support/null_message_processor.h"
namespace ba = boost::asio;
namespace anbox {
namespace network {
QemuPipeConnectionCreator::QemuPipeConnectionCreator(const std::shared_ptr<Runtime> &rt,
const std::string &renderer_socket_path) :
runtime_(rt),
next_connection_id_(0),
connections_(std::make_shared<Connections<SocketConnection>>()),
renderer_socket_path_(renderer_socket_path) {
}
QemuPipeConnectionCreator::~QemuPipeConnectionCreator() {
}
void QemuPipeConnectionCreator::create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket) {
auto const messenger = std::make_shared<SocketMessenger>(socket);
const auto type = identify_client(messenger);
auto const processor = create_processor(type, messenger);
if (!processor)
BOOST_THROW_EXCEPTION(std::runtime_error("Unhandled client type"));
auto const& connection = std::make_shared<SocketConnection>(messenger, next_id(), connections_, processor);
connections_->add(connection);
connection->read_next_message();
DEBUG("id %i", connection->id());
}
QemuPipeConnectionCreator::client_type QemuPipeConnectionCreator::identify_client(
std::shared_ptr<SocketMessenger> const& messenger) {
// The client will identify itself as first thing by writing a string
// in the format 'pipe:<name>[:<arguments>]\0' to the channel.
std::vector<char> buffer;
for (;;) {
unsigned char byte[1] = { 0 };
const auto err = messenger->receive_msg(ba::buffer(byte, 1));
if (err)
break;
buffer.push_back(byte[0]);
if (byte[0] == 0x0)
break;
}
std::string identifier_and_args = buffer.data();
DEBUG("identifier %s", identifier_and_args);
if (utils::string_starts_with(identifier_and_args, "pipe:opengles"))
return client_type::opengles;
// Even if 'boot-properties' is an argument to the service 'qemud' here we
// take this as a own service instance as that is what it is.
else if (utils::string_starts_with(identifier_and_args, "pipe:qemud:boot-properties"))
return client_type::qemud_boot_properties;
return client_type::invalid;
}
std::shared_ptr<MessageProcessor> QemuPipeConnectionCreator::create_processor(const client_type &type, const std::shared_ptr<SocketMessenger> &messenger) {
if (type == client_type::opengles)
return std::make_shared<graphics::OpenGlesMessageProcessor>(renderer_socket_path_, runtime_, messenger);
else if (type == client_type::qemud_boot_properties)
return std::make_shared<support::BootPropertiesMessageProcessor>(messenger);
return std::make_shared<support::NullMessageProcessor>();
}
int QemuPipeConnectionCreator::next_id()
{
return next_connection_id_.fetch_add(1);
}
} // namespace anbox
} // namespace network

View file

@ -0,0 +1,67 @@
/*
* 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_NETWORK_QEMU_PIPE_CONNECTION_CREATOR_H_
#define ANBOX_NETWORK_QEMU_PIPE_CONNECTION_CREATOR_H_
#include <boost/asio.hpp>
#include <memory>
#include "anbox/do_not_copy_or_move.h"
#include "anbox/runtime.h"
#include "anbox/network/connections.h"
#include "anbox/network/socket_connection.h"
#include "anbox/network/connection_creator.h"
#include "anbox/network/socket_messenger.h"
namespace anbox {
namespace network {
class QemuPipeConnectionCreator : public ConnectionCreator {
public:
QemuPipeConnectionCreator(
const std::shared_ptr<Runtime> &rt,
const std::string &renderer_socket_path);
~QemuPipeConnectionCreator() noexcept;
void create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket) override;
enum class client_type {
invalid,
opengles,
qemud_boot_properties,
};
private:
int next_id();
client_type identify_client(std::shared_ptr<SocketMessenger> const& messenger);
std::shared_ptr<MessageProcessor> create_processor(
const client_type &type, const std::shared_ptr<SocketMessenger> &messenger);
std::shared_ptr<Runtime> runtime_;
std::atomic<int> next_connection_id_;
std::shared_ptr<Connections<SocketConnection>> const connections_;
std::string renderer_socket_path_;
};
} // namespace anbox
} // namespace network
#endif

View file

@ -0,0 +1,88 @@
/*
* Copyright © 2012 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Alan Griffiths <alan@octopull.co.uk>
*/
#include "anbox/logger.h"
#include "anbox/network/socket_connection.h"
#include "anbox/network/message_sender.h"
#include "anbox/network/message_receiver.h"
#include <boost/signals2.hpp>
#include <boost/throw_exception.hpp>
#include <stdexcept>
#include <sys/types.h>
#include <sys/socket.h>
namespace ba = boost::asio;
namespace bs = boost::system;
namespace anbox {
namespace network {
SocketConnection::SocketConnection(
std::shared_ptr<MessageReceiver> const& message_receiver,
int id_,
std::shared_ptr<Connections<SocketConnection>> const& connections,
std::shared_ptr<MessageProcessor> const& processor)
: message_receiver_(message_receiver),
id_(id_),
connections_(connections),
processor_(processor)
{
}
SocketConnection::~SocketConnection() noexcept
{
}
void SocketConnection::read_next_message()
{
auto callback = std::bind(&SocketConnection::on_read_size,
this, std::placeholders::_1, std::placeholders::_2);
message_receiver_->async_receive_msg(callback, ba::buffer(buffer_));
}
void SocketConnection::on_read_size(const boost::system::error_code& error, std::size_t bytes_read)
{
if (error)
{
connections_->remove(id());
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();
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

View file

@ -0,0 +1,60 @@
/*
* Copyright © 2012-2014 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Alan Griffiths <alan@octopull.co.uk>
*/
#ifndef ANBOX_NETWORK_SOCKET_CONNECTION_H_
#define ANBOX_NETWORK_SOCKET_CONNECTION_H_
#include "anbox/network/connections.h"
#include "anbox/network/message_receiver.h"
#include "anbox/network/message_processor.h"
#include <boost/asio.hpp>
#include <sys/types.h>
namespace anbox {
namespace network {
class SocketConnection
{
public:
SocketConnection(
std::shared_ptr<MessageReceiver> const& message_receiver,
int id,
std::shared_ptr<Connections<SocketConnection>> const& connections,
std::shared_ptr<MessageProcessor> const& processor);
~SocketConnection() noexcept;
int id() const { return id_; }
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_;
int const id_;
std::shared_ptr<Connections<SocketConnection>> const connections_;
std::shared_ptr<MessageProcessor> const processor_;
std::array<std::uint8_t, 8192> buffer_;
};
} // namespace anbox
} // namespace network
#endif

View file

@ -0,0 +1,99 @@
/*
* Copyright © 2013-2014 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
*/
#include "anbox/network/socket_messenger.h"
#include "anbox/common/variable_length_array.h"
#include "anbox/logger.h"
#include <boost/throw_exception.hpp>
#include <errno.h>
#include <string.h>
#include <stdexcept>
namespace bs = boost::system;
namespace ba = boost::asio;
namespace {
/// Buffers need to be big enough to support messages
unsigned int const serialization_buffer_size = 2048;
}
namespace anbox {
namespace network {
SocketMessenger::SocketMessenger(std::shared_ptr<ba::local::stream_protocol::socket> const& socket)
: socket(socket),
socket_fd{IntOwnedFd{socket->native_handle()}}
{
socket->non_blocking(true);
boost::asio::socket_base::send_buffer_size option(64*1024);
socket->set_option(option);
}
void SocketMessenger::send(char const* data, size_t length)
{
VariableLengthArray<serialization_buffer_size> whole_message{length};
std::copy(data, data + length, whole_message.data());
try {
std::unique_lock<std::mutex> lg(message_lock);
ba::write(*socket,
ba::buffer(whole_message.data(), whole_message.size()),
boost::asio::transfer_all());
}
catch (std::exception &err) {
ERROR("Failed to write message: %s", err.what());
}
}
void SocketMessenger::async_receive_msg(
AnboxReadHandler const& handler,
ba::mutable_buffers_1 const& buffer)
{
socket->async_read_some(buffer, handler);
}
bs::error_code SocketMessenger::receive_msg(
ba::mutable_buffers_1 const& buffer)
{
bs::error_code e;
size_t nread = 0;
while (nread < ba::buffer_size(buffer))
{
nread += boost::asio::read(
*socket,
ba::mutable_buffers_1{buffer + nread},
e);
if (e && e != ba::error::would_block)
break;
}
return e;
}
size_t SocketMessenger::available_bytes()
{
boost::asio::socket_base::bytes_readable command{true};
socket->io_control(command);
return command.get();
}
} // namespace network
} // namespace anbox

View file

@ -0,0 +1,51 @@
/*
* Copyright © 2013-2014 Canonical Ltd.
*
* 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 warranty of
* MERCHANTABILITY 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/>.
*
* Authored by: Kevin DuBois <kevin.dubois@canonical.com>
*/
#ifndef ANBOX_NETWORK_SOCKET_MESSENGER_H_
#define ANBOX_NETWORK_SOCKET_MESSENGER_H_
#include <mutex>
#include "anbox/common/fd_sets.h"
#include "anbox/network/message_sender.h"
#include "anbox/network/message_receiver.h"
namespace anbox {
namespace network {
class SocketMessenger : public MessageSender,
public MessageReceiver {
public:
SocketMessenger(std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket);
void send(char const* data, size_t length);
void async_receive_msg(AnboxReadHandler const& handle, boost::asio::mutable_buffers_1 const &buffer) override;
boost::system::error_code receive_msg(boost::asio::mutable_buffers_1 const& buffer) override;
size_t available_bytes() override;
private:
std::shared_ptr<boost::asio::local::stream_protocol::socket> socket;
anbox::Fd socket_fd;
std::mutex message_lock;
};
} // namespace network
} // namespace anbox
#endif

View file

@ -0,0 +1,74 @@
/*
* 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/common/variable_length_array.h"
#include "anbox/network/stream_socket_transport.h"
#include "anbox/network/fd_socket_transmission.h"
#include <system_error>
#include <errno.h>
#include <sys/epoll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <boost/exception/errinfo_errno.hpp>
#include <boost/throw_exception.hpp>
namespace anbox {
namespace network {
StreamSocketTransport::StreamSocketTransport(const std::string &socket_path,
const std::shared_ptr<Runtime> &rt) :
socket_(std::make_shared<boost::asio::local::stream_protocol::socket>(rt->service())),
{
socket_.connect(boost::asio::local::stream_protocol::endpoint(socket_path));
read_next_message();
}
void StreamSocketTransport::register_observer(std::shared_ptr<Observer> const& observer)
{
this->observer_ = observer;
}
void StreamSocketTransport::unregister_observer(std::shared_ptr<Observer> const& observer)
{
if (this->observer_ != observer)
return;
this->observer_.reset();
}
void StreamSocketTransport::send_message(std::vector<uint8_t> const& buffer)
{
}
void StreamSocketTransport::read_next_message() {
auto callback = std::bind(&StreamSocketTransport::on_read_size,
this,
std::placeholders::_1,
std::placeholders::_2);
}
void StreamSocketTransport::on_read_size(const boost::system::error_code& ec, std::size_t bytes_read) {
}
} // namespace network
} // namespace anbox

View file

@ -0,0 +1,66 @@
/*
* 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_STREAM_SOCKET_TRANSPORT_H_
#define ANBOX_STREAM_SOCKET_TRANSPORT_H_
#include "anbox/common/fd.h"
#include "anbox/runtime.h"
#include "anbox/network/socket_messenger.h"
#include <memory>
#include <boost/asio.hpp>
namespace anbox {
namespace network {
class StreamSocketTransport
{
public:
class Observer {
public:
Observer() = default;
virtual ~Observer() = default;
virtual void on_data_available() = 0;
virtual void on_disconnected() = 0;
Observer(Observer const&) = delete;
Observer& operator=(Observer const&) = delete;
};
StreamSocketTransport(const std::string &socket_path,
const std::shared_ptr<Runtime> &rt);
void register_observer(std::shared_ptr<Observer> const& observer_);
void unregister_observer(std::shared_ptr<Observer> const& observer_);
void send_message(std::vector<uint8_t> const& buffer);
void read_next_message();
private:
void on_read_size(const boost::system::error_code& ec, std::size_t bytes_read);
std::shared_ptr<Observer> observer_;
std::shared_ptr<boost::asio::local::stream_protocol::socket> socket_;
SocketMessenger messenger_;
};
} // namespace network
} // namespace anbox
#endif // STREAM_SOCKET_TRANSPORT_H_

32
src/anbox/optional.h Normal file
View file

@ -0,0 +1,32 @@
/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Thomas Voß <thomas.voss@canonical.com>
*
*/
#ifndef ANBOX_OPTIONAL_H_
#define ANBOX_OPTIONAL_H_
#include <boost/optional.hpp>
#include <boost/optional/optional_io.hpp>
namespace anbox
{
template<typename T>
using Optional = boost::optional<T>;
}
#endif

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 <fstream>
#include <boost/filesystem.hpp>
#include "anbox/config.h"
#include "anbox/utils.h"
#include "anbox/pid_persister.h"
namespace fs = boost::filesystem;
namespace anbox {
PidPersister::PidPersister() :
path_(utils::string_format("%s/pid", config::data_path())) {
if (fs::exists(fs::path(path_)))
std::remove(path_.c_str());
std::ofstream file;
file.open(path_);
file << getpid();
file.close();
}
PidPersister::~PidPersister() {
std::remove(path_.c_str());
}
} // namespace anbox

34
src/anbox/pid_persister.h Normal file
View file

@ -0,0 +1,34 @@
/*
* 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_PID_PERSISTER_H_
#define ANBOX_PID_PERSISTER_H_
#include <string>
namespace anbox {
class PidPersister {
public:
PidPersister();
~PidPersister();
private:
std::string path_;
};
} // namespace anbox
#endif

100
src/anbox/runtime.cpp Normal file
View file

@ -0,0 +1,100 @@
/*
* 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 <iostream>
#include "anbox/logger.h"
#include "anbox/runtime.h"
namespace
{
// exception_safe_run runs service, catching all exceptions and
// restarting operation until an explicit shutdown has been requested.
//
// TODO(tvoss): Catching all exceptions is risky as they might signal unrecoverable
// errors. We should enable calling code to decide whether an exception should be considered
// fatal or not.
void exception_safe_run(boost::asio::io_service& service) {
while (true) {
try {
service.run();
// a clean return from run only happens in case of
// stop() being called (we are keeping the service alive with
// a service::work instance).
break;
}
catch (const std::exception& e) {
std::cerr << "test" << e.what();
}
catch (...) {
std::cerr << "Unknown exception caught while executing boost::asio::io_service";
}
}
}
}
namespace anbox {
std::shared_ptr<Runtime> Runtime::create(std::uint32_t pool_size) {
return std::shared_ptr<Runtime>(new Runtime(pool_size));
}
Runtime::Runtime(std::uint32_t pool_size) :
pool_size_{pool_size},
service_{pool_size_},
strand_{service_},
keep_alive_{service_} {
}
Runtime::~Runtime() {
try {
stop();
}
catch(...) {
// Dropping all exceptions to satisfy the nothrow guarantee.
}
}
void Runtime::start() {
for (unsigned int i = 0; i < pool_size_; i++)
workers_.push_back(std::thread{exception_safe_run, std::ref(service_)});
}
void Runtime::stop() {
service_.stop();
for (auto& worker : workers_)
if (worker.joinable())
worker.join();
}
std::function<void(std::function<void()>)> Runtime::to_dispatcher_functional()
{
// We have to make sure that we stay alive for as long as
// calling code requires the dispatcher to work.
auto sp = shared_from_this();
return [sp](std::function<void()> task)
{
sp->strand_.post(task);
};
}
boost::asio::io_service& Runtime::service() {
return service_;
}
} // namespace anbox

77
src/anbox/runtime.h Normal file
View file

@ -0,0 +1,77 @@
/*
* 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_RUNTIME_H_
#define ANBOX_RUNTIME_H_
#include <boost/asio.hpp>
#include <functional>
#include <memory.h>
#include <thread>
#include "anbox/do_not_copy_or_move.h"
namespace anbox {
// We bundle our "global" runtime dependencies here, specifically
// a dispatcher to decouple multiple in-process providers from one
// another , forcing execution to a well known set of threads.
class Runtime : public DoNotCopyOrMove,
public std::enable_shared_from_this<Runtime> {
public:
// Our default concurrency setup.
static constexpr const std::uint32_t worker_threads = 2;
// create returns a Runtime instance with pool_size worker threads
// executing the underlying service.
static std::shared_ptr<Runtime> create(std::uint32_t pool_size = worker_threads);
// Tears down the runtime, stopping all worker threads.
~Runtime() noexcept(true);
// start executes the underlying io_service on a thread pool with
// the size configured at creation time.
void start();
// stop cleanly shuts down a Runtime instance,
// joining all worker threads.
void stop();
// to_dispatcher_functional returns a function for integration
// with components that expect a dispatcher for operation.
std::function<void(std::function<void()>)> to_dispatcher_functional();
// service returns the underlying boost::asio::io_service that is executed
// by the Runtime.
boost::asio::io_service& service();
private:
// Runtime constructs a new instance, firing up pool_size
// worker threads.
Runtime(std::uint32_t pool_size);
std::uint32_t pool_size_;
boost::asio::io_service service_;
boost::asio::io_service::strand strand_;
boost::asio::io_service::work keep_alive_;
std::vector<std::thread> workers_;
};
} // namespace anbox
#endif

View file

@ -0,0 +1,113 @@
/*
* 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/logger.h"
#include "anbox/support/boot_properties_message_processor.h"
#include "anbox/network/socket_messenger.h"
#include "anbox/network/connections.h"
#include "anbox/network/delegate_message_processor.h"
#include <string.h>
namespace ba = boost::asio;
namespace {
static constexpr const long header_size{4};
}
namespace anbox {
namespace support {
BootPropertiesMessageProcessor::BootPropertiesMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
messenger_(messenger) {
}
BootPropertiesMessageProcessor::~BootPropertiesMessageProcessor() {
}
bool BootPropertiesMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
for (const auto &byte : data)
buffer_.push_back(byte);
process_commands();
return true;
}
void BootPropertiesMessageProcessor::process_commands() {
while (true) {
if (buffer_.size() < header_size)
break;
char header[header_size] = { 0 };
::memcpy(header, buffer_.data(), header_size);
unsigned int body_size = 0;
::sscanf(header, "%04x", &body_size);
if (body_size != buffer_.size() - header_size)
break;
std::string command;
// Make sure we only copy as much bytes as we have to and not more
command.insert(0, reinterpret_cast<const char*>(buffer_.data()) + header_size, body_size);
if (command == "list")
list_properties();
else
DEBUG("Unknown command '%s'", command);
const auto consumed = header_size + body_size;
buffer_.erase(buffer_.begin(), buffer_.begin() + consumed);
const auto remaining = buffer_.size() - consumed;
if (remaining <= 0)
break;
}
}
void BootPropertiesMessageProcessor::list_properties() {
std::vector<std::string> properties = {
// Simple indicator to say we're anbox and if needed things in the container
// can adjust to this. Normally everything should detect we're qemu which
// should be enough for the simple cases.
"ro.anbox=1",
"ro.hardware=goldfish",
// Needed to let the gralloc HAL load the right implementation
"ro.kernel.qemu.gles=1",
// Needed from different parts of the system in order to load
// the right implementation for qemu
"ro.kernel.qemu=1",
// TODO(morphis): Using HDPI here for now but should be adjusted to the device
// we're running on.
"qemu.sf.lcd_density=240"
};
for (const auto &prop : properties) {
char header[header_size + 1];
std::snprintf(header, header_size + 1, "%04x", prop.length());
messenger_->send(header, header_size);
messenger_->send(prop.c_str(), prop.length());
}
// Send terminating NULL byte
messenger_->send(static_cast<const char*>(""), 1);
}
} // namespace support
} // namespace anbox

View file

@ -0,0 +1,49 @@
/*
* 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_SUPPORT_BOOT_PROPERTIES_MESSAGE_PROCESSOR_H_
#define ANBOX_SUPPORT_BOOT_PROPERTIES_MESSAGE_PROCESSOR_H_
#include <memory>
#include <boost/asio.hpp>
#include "anbox/runtime.h"
#include "anbox/network/message_processor.h"
#include "anbox/network/socket_messenger.h"
#include "anbox/network/socket_connection.h"
namespace anbox {
namespace support {
class BootPropertiesMessageProcessor : public network::MessageProcessor {
public:
BootPropertiesMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
~BootPropertiesMessageProcessor();
bool process_data(const std::vector<std::uint8_t> &data) override;
private:
void process_commands();
void list_properties();
std::shared_ptr<network::SocketMessenger> messenger_;
std::vector<std::uint8_t> buffer_;
};
} // namespace graphics
} // namespace anbox
#endif

View file

@ -0,0 +1,82 @@
/*
* 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/logger.h"
#include "anbox/support/hwcontrol_message_processor.h"
#include "anbox/network/socket_messenger.h"
#include "anbox/network/connections.h"
#include <string.h>
namespace ba = boost::asio;
namespace {
static constexpr const long header_size{4};
}
namespace anbox {
namespace support {
HwControlMessageProcessor::HwControlMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger) :
messenger_(messenger) {
}
HwControlMessageProcessor::~HwControlMessageProcessor() {
}
bool HwControlMessageProcessor::process_data(const std::vector<std::uint8_t> &data) {
for (const auto &byte : data)
buffer_.push_back(byte);
process_commands();
return true;
}
void HwControlMessageProcessor::process_commands() {
while (true) {
if (buffer_.size() < header_size)
break;
char header[header_size] = { 0 };
::memcpy(header, buffer_.data(), header_size);
unsigned int body_size = 0;
::sscanf(header, "%04x", &body_size);
if (body_size != buffer_.size() - header_size)
break;
std::string command;
// Make sure we only copy as much bytes as we have to and not more
command.insert(0, reinterpret_cast<const char*>(buffer_.data()) + header_size, body_size);
if (command == "power:screen_state:wake")
DEBUG("Got screen wake command");
else if (command == "power:screen_state:standby")
DEBUG("Got screen standby command");
else
DEBUG("Unknown command '%s'", command);
const auto consumed = header_size + body_size;
buffer_.erase(buffer_.begin(), buffer_.begin() + consumed);
const auto remaining = buffer_.size() - consumed;
if (remaining <= 0)
break;
}
}
} // namespace support
} // namespace anbox

View file

@ -0,0 +1,48 @@
/*
* 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_SUPPORT_HWCONTROL_MESSAGE_PROCESSOR_H_
#define ANBOX_SUPPORT_HWCONTROL_MESSAGE_PROCESSOR_H_
#include <memory>
#include <boost/asio.hpp>
#include "anbox/runtime.h"
#include "anbox/network/message_processor.h"
#include "anbox/network/socket_messenger.h"
#include "anbox/network/socket_connection.h"
namespace anbox {
namespace support {
class HwControlMessageProcessor : public network::MessageProcessor {
public:
HwControlMessageProcessor(const std::shared_ptr<network::SocketMessenger> &messenger);
~HwControlMessageProcessor();
bool process_data(const std::vector<std::uint8_t> &data) override;
private:
void process_commands();
std::shared_ptr<network::SocketMessenger> messenger_;
std::vector<std::uint8_t> buffer_;
};
} // namespace graphics
} // namespace anbox
#endif

View file

@ -0,0 +1,34 @@
/*
* 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/support/null_message_processor.h"
#include <string.h>
namespace anbox {
namespace support {
NullMessageProcessor::NullMessageProcessor() {
}
NullMessageProcessor::~NullMessageProcessor() {
}
bool NullMessageProcessor::process_data(const std::vector<std::uint8_t>&) {
return true;
}
} // namespace support
} // namespace anbox

View file

@ -0,0 +1,40 @@
/*
* 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_SUPPORT_NULL_MESSAGE_PROCESSOR_H_
#define ANBOX_SUPPORT_NULL_MESSAGE_PROCESSOR_H_
#include <memory>
#include <boost/asio.hpp>
#include "anbox/runtime.h"
#include "anbox/network/message_processor.h"
namespace anbox {
namespace support {
class NullMessageProcessor : public network::MessageProcessor {
public:
NullMessageProcessor();
~NullMessageProcessor();
bool process_data(const std::vector<std::uint8_t> &data) override;
};
} // namespace graphics
} // namespace anbox
#endif

136
src/anbox/utils.cpp Normal file
View file

@ -0,0 +1,136 @@
/*
* 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 <boost/filesystem.hpp>
#include <boost/throw_exception.hpp>
#include <fstream>
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <fcntl.h>
#include "anbox/utils.h"
namespace anbox {
namespace utils {
std::vector<std::string> collect_arguments(int argc, char **argv) {
std::vector<std::string> result;
for (int i = 1; i < argc; i++) result.push_back(argv[i]);
return result;
}
std::string read_file_if_exists_or_throw(const std::string &file_path) {
if (!boost::filesystem::is_regular(boost::filesystem::path(file_path)))
BOOST_THROW_EXCEPTION(std::runtime_error("File does not exist"));
std::ifstream file;
file.open(file_path, std::ifstream::in);
std::string content;
file >> content;
file.close();
return content;
}
bool write_to_file(const std::string &file_path, const std::string &content) {
std::ofstream of;
of.open(file_path, std::ofstream::out);
of << content;
of.close();
return true;
}
int write_to_fd(int fd, const char *content, ssize_t len) {
while (len > 0) {
const auto res = write (fd, content, len);
if (res < 0 && errno == EINTR)
continue;
if (res <= 0) {
if (res == 0) /* Unexpected short write, should not happen when writing to a file */
errno = ENOSPC;
return -1;
}
len -= res;
content += res;
}
return 0;
}
int write_file_at(int dirfd, const char *path, const char *content) {
const auto fd = openat (dirfd, path, O_RDWR | O_CLOEXEC, 0);
if (fd == -1)
return -1;
auto res = 0;
if (content)
res = write_to_fd (fd, content, strlen (content));
const auto errsv = errno;
close (fd);
errno = errsv;
return res;
}
bool string_starts_with(const std::string &text, const std::string &prefix) {
return text.compare(0, prefix.size(), prefix) == 0;
}
std::string hex_dump(const uint8_t *data, uint32_t size) {
unsigned char buff[17];
const uint8_t *pc = data;
std::stringstream buffer;
if (size == 0) {
buffer << "NULL" << std::endl;
return buffer.str();
}
uint32_t i;
for (i = 0; i < size; i++) {
if ((i % 16) == 0) {
if (i != 0)
buffer << string_format(" %s", buff) << std::endl;
buffer << string_format("%02x ", i);
}
buffer << string_format(" %02x", static_cast<int>(pc[i]));
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
while ((i % 16) != 0) {
buffer << " ";
i++;
}
buffer << string_format(" %s", buff) << std::endl;
return buffer.str();
}
} // namespace utils
} // namespace anbox

66
src/anbox/utils.h Normal file
View file

@ -0,0 +1,66 @@
/*
* 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_UTILS_H_
#define ANBOX_UTILS_H_
#include <boost/format.hpp>
#include <vector>
#include <string>
namespace anbox {
namespace utils {
std::vector<std::string> collect_arguments(int argc, char **argv);
std::string read_file_if_exists_or_throw(const std::string &file_path);
bool write_to_file(const std::string &file_path, const std::string &content = "");
int write_to_fd(int fd, const char *content, ssize_t len);
int write_file_at(int dirfd, const char *path, const char *content);
bool string_starts_with(const std::string &text, const std::string &prefix);
std::string hex_dump(const uint8_t *data, uint32_t size);
template<typename... Types>
static std::string string_format(const std::string& fmt_str, Types&&... args);
} // namespace utils
} // namespace anbox
namespace impl {
// Base case, just return the passed in boost::format instance.
inline boost::format& string_format(boost::format& f)
{
return f;
}
// Sprintf recursively walks the parameter pack at compile time.
template <typename Head, typename... Tail>
inline boost::format& string_format(boost::format& f, Head const& head, Tail&&... tail) {
return string_format(f % head, std::forward<Tail>(tail)...);
}
} // namespace impl
template <typename... Types>
inline std::string anbox::utils::string_format(const std::string& format, Types&&... args) {
boost::format f(format);
return impl::string_format(f, std::forward<Types>(args)...).str();
}
#endif

27
src/anbox/version.cpp Normal file
View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Thomas Voß <thomas.voss@canonical.com>
*
*/
#include "anbox/version.h"
void anbox::version(std::uint32_t& major, std::uint32_t& minor, std::uint32_t& patch)
{
major = anbox::build::version_major;
minor = anbox::build::version_minor;
patch = anbox::build::version_patch;
}

42
src/anbox/version.h Normal file
View file

@ -0,0 +1,42 @@
/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authored by: Thomas Voß <thomas.voss@canonical.com>
*
*/
#ifndef ANBOX_VERSION_H_
#define ANBOX_VERSION_H_
#include <cstdint>
namespace anbox {
namespace build {
/// @brief version_major marks the major version of the library. The constant is meant to be used
/// by client code both at build and runtime, enabling version checks.
static constexpr const std::uint32_t version_major{1};
/// @brief version_major marks the minor version of the library. The constant is meant to be used
/// by client code both at build and runtime, enabling version checks.
static constexpr const std::uint32_t version_minor{0};
/// @brief version_patch marks the major version of the library. The constant is meant to be used
/// by client code both at build and runtime, enabling version checks.
static constexpr const std::uint32_t version_patch{1};
} // namespace build
/// @brief version queries the version of the library, placing the result in major, minor and patch.
void version(std::uint32_t& major, std::uint32_t& minor, std::uint32_t& patch);
} // namespace build
#endif // ANBOX_VERSION_H_

24
src/main.cpp Normal file
View file

@ -0,0 +1,24 @@
/*
* 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/daemon.h"
#include "anbox/utils.h"
int main(int argc, char **argv) {
anbox::Daemon daemon;
return daemon.Run(anbox::utils::collect_arguments(argc, argv));
}