Rework container management
* based on liblxc now * container is managed by a management process which needs to run as root. LXC will take care of strict confinement of this container. We still don't allow any direct hardware access. * `anbox shell` command is gone. Same functionality can be archive with the lxc-attach command.
This commit is contained in:
parent
32d7f4ba5f
commit
2b25f6f5bb
44 changed files with 1116 additions and 503 deletions
|
|
@ -57,5 +57,9 @@ prepare_filesystem &
|
|||
echo "Waiting for filesystem being prepared ..."
|
||||
wait $!
|
||||
|
||||
ln -sf /dev/sockets/qemu_pipe /dev/qemu_pipe
|
||||
ln -sf /dev/sockets/qemud /dev/qemud
|
||||
ln -sf /dev/sockets/anbox_bridge /dev/anbox_bridge
|
||||
|
||||
echo "Starting real init now ..."
|
||||
/init
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ include_directories(
|
|||
${DBUS_CPP_INCLUDE_DIRS}
|
||||
${DBUS_INCLUDE_DIRS}
|
||||
${SDL2_INCLUDE_DIRS}
|
||||
${LXC_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
|
|
@ -37,9 +38,6 @@ set(SOURCES
|
|||
anbox/daemon.cpp
|
||||
anbox/config.cpp
|
||||
anbox/not_reachable.cpp
|
||||
anbox/namespace_attacher.cpp
|
||||
anbox/container.cpp
|
||||
anbox/container_connector.cpp
|
||||
anbox/application_manager.h
|
||||
|
||||
anbox/common/fd.cpp
|
||||
|
|
@ -48,6 +46,12 @@ set(SOURCES
|
|||
anbox/common/wait_handle.cpp
|
||||
anbox/common/dispatcher.cpp
|
||||
|
||||
anbox/container/service.cpp
|
||||
anbox/container/client.cpp
|
||||
anbox/container/container.cpp
|
||||
anbox/container/lxc_container.cpp
|
||||
|
||||
anbox/network/credentials.cpp
|
||||
anbox/network/message_sender.h
|
||||
anbox/network/message_receiver.h
|
||||
anbox/network/message_processor.h
|
||||
|
|
@ -59,6 +63,8 @@ set(SOURCES
|
|||
anbox/network/socket_messenger.cpp
|
||||
anbox/network/delegate_message_processor.h
|
||||
anbox/network/delegate_connection_creator.h
|
||||
anbox/network/local_socket_messenger.cpp
|
||||
anbox/network/socket_helper.cpp
|
||||
|
||||
anbox/graphics/opengles_message_processor.cpp
|
||||
anbox/graphics/gl_renderer_server.cpp
|
||||
|
|
@ -101,10 +107,11 @@ set(SOURCES
|
|||
|
||||
anbox/cmds/version.cpp
|
||||
anbox/cmds/run.cpp
|
||||
anbox/cmds/shell.cpp
|
||||
anbox/cmds/install_app.cpp
|
||||
anbox/cmds/launch_app.cpp
|
||||
anbox/cmds/reset.cpp
|
||||
anbox/cmds/container_manager.cpp
|
||||
anbox/cmds/start_container.cpp
|
||||
|
||||
anbox/do_not_copy_or_move.h
|
||||
anbox/optional.h
|
||||
|
|
@ -114,10 +121,9 @@ add_library(anbox-core ${SOURCES})
|
|||
target_link_libraries(anbox-core
|
||||
${Boost_LDFLAGS}
|
||||
${Boost_LIBRARIES}
|
||||
${MIRCLIENT_LDFLAGS}
|
||||
${MIRCLIENT_LIBRARIES}
|
||||
${DBUS_CPP_LIBRARIES}
|
||||
${SDL2_LIBRARIES}
|
||||
${LXC_LIBRARIES}
|
||||
pthread
|
||||
process-cpp
|
||||
OpenglRender
|
||||
|
|
@ -127,12 +133,8 @@ add_executable(anbox main.cpp)
|
|||
target_link_libraries(anbox
|
||||
anbox-core)
|
||||
|
||||
add_executable(anbox-container container_main.cpp)
|
||||
target_link_libraries(anbox-container
|
||||
bwrap)
|
||||
|
||||
install(
|
||||
TARGETS anbox anbox-container
|
||||
TARGETS anbox
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib/static)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ void AndroidApiStub::install(const std::string &path) {
|
|||
fs::copy(path, target_path);
|
||||
|
||||
const auto container_path = utils::string_format("%s/%s",
|
||||
config::container_share_path(), fs::path(path).filename().string());
|
||||
config::container_android_share_path(), fs::path(path).filename().string());
|
||||
|
||||
auto c = std::make_shared<Request<protobuf::bridge::Void>>();
|
||||
protobuf::bridge::InstallApplication message;
|
||||
|
|
|
|||
45
src/anbox/cmds/container_manager.cpp
Normal file
45
src/anbox/cmds/container_manager.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/cmds/container_manager.h"
|
||||
#include "anbox/container/service.h"
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include "core/posix/signal.h"
|
||||
|
||||
anbox::cmds::ContainerManager::ContainerManager()
|
||||
: CommandWithFlagsAndAction{cli::Name{"container-manager"}, cli::Usage{"container-manager"}, cli::Description{"Start the container manager service"}}
|
||||
{
|
||||
action([](const cli::Command::Context& ctxt) {
|
||||
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 service = container::Service::create(rt);
|
||||
|
||||
rt->start();
|
||||
trap->run();
|
||||
rt->stop();
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
|
@ -15,24 +15,22 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_CONTAINER_CONNECTOR_H_
|
||||
#define ANBOX_CONTAINER_CONNECTOR_H_
|
||||
#ifndef ANBOX_CMDS_CONTAINER_MANAGER_H_
|
||||
#define ANBOX_CMDS_CONTAINER_MANAGER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "anbox/cli.h"
|
||||
|
||||
namespace anbox {
|
||||
class NamespaceAttacher;
|
||||
class ContainerConnector {
|
||||
namespace cmds {
|
||||
class ContainerManager : public cli::CommandWithFlagsAndAction {
|
||||
public:
|
||||
ContainerConnector(int pid = -1);
|
||||
~ContainerConnector();
|
||||
|
||||
int run(const std::string &path);
|
||||
|
||||
private:
|
||||
int pid_;
|
||||
std::shared_ptr<NamespaceAttacher> namespaces_;
|
||||
ContainerManager();
|
||||
};
|
||||
} // namespace
|
||||
} // namespace cmds
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/container.h"
|
||||
#include "anbox/config.h"
|
||||
#include "anbox/common/dispatcher.h"
|
||||
#include "anbox/cmds/run.h"
|
||||
|
|
@ -36,6 +35,7 @@
|
|||
#include "anbox/ubuntu/platform_api_skeleton.h"
|
||||
#include "anbox/ubuntu/window_creator.h"
|
||||
#include "anbox/dbus/skeleton/service.h"
|
||||
#include "anbox/container/client.h"
|
||||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
|
|
@ -65,7 +65,6 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
: CommandWithFlagsAndAction{cli::Name{"run"}, cli::Usage{"run"}, cli::Description{"Run the the anbox system"}},
|
||||
bus_factory_(bus_factory)
|
||||
{
|
||||
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_));
|
||||
|
|
@ -75,11 +74,6 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
flag(cli::make_flag(cli::Name{"icon"}, cli::Description{"Icon of the application to run"}, icon_));
|
||||
|
||||
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) {
|
||||
|
|
@ -87,6 +81,10 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
trap->stop();
|
||||
});
|
||||
|
||||
utils::ensure_paths({
|
||||
config::socket_path(),
|
||||
});
|
||||
|
||||
auto rt = Runtime::create();
|
||||
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
|
||||
|
||||
|
|
@ -99,14 +97,14 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
// 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()),
|
||||
utils::string_format("%s/qemud", config::socket_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()),
|
||||
utils::string_format("%s/qemu_pipe", config::socket_path()),
|
||||
rt,
|
||||
std::make_shared<qemu::PipeConnectionCreator>(rt,
|
||||
renderer->socket_path(),
|
||||
|
|
@ -115,7 +113,7 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
|
||||
|
||||
auto bridge_connector = std::make_shared<network::PublishedSocketConnector>(
|
||||
utils::string_format("%s/anbox_bridge", config::data_path()),
|
||||
utils::string_format("%s/anbox_bridge", config::socket_path()),
|
||||
rt,
|
||||
std::make_shared<bridge::ConnectionCreator>(rt,
|
||||
[&](const std::shared_ptr<network::MessageSender> &sender) {
|
||||
|
|
@ -148,36 +146,8 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
return std::make_shared<bridge::PlatformMessageProcessor>(sender, server, pending_calls);
|
||||
}));
|
||||
|
||||
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.bind_paths.insert({bridge_connector->socket_file(), "/dev/anbox_bridge"});
|
||||
container::Client container(rt);
|
||||
|
||||
input_manager->generate_mappings(spec.bind_paths);
|
||||
|
||||
// A place where we can exchange files with the container
|
||||
spec.bind_paths.insert({config::host_share_path(), config::container_share_path()});
|
||||
|
||||
spec.bind_paths.insert({ config::host_android_data_path(), "/data" });
|
||||
spec.bind_paths.insert({ config::host_android_cache_path(), "/cache" });
|
||||
spec.bind_paths.insert({ config::host_android_storage_path(), "/storage" });
|
||||
|
||||
spec.temporary_dirs.push_back("/dev/input");
|
||||
|
||||
// NOTE: We're not mapping /dev/alarm here as if its not available
|
||||
// Android will automatically use its timerfd based fallback
|
||||
// implementation instead.
|
||||
|
||||
// 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);
|
||||
|
||||
auto bus = bus_factory_();
|
||||
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
||||
|
|
@ -185,11 +155,7 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
|
|||
auto skeleton = anbox::dbus::skeleton::Service::create_for_bus(bus, android_api_stub);
|
||||
|
||||
rt->start();
|
||||
container->start();
|
||||
|
||||
trap->run();
|
||||
|
||||
container->stop();
|
||||
rt->stop();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ public:
|
|||
|
||||
private:
|
||||
BusFactory bus_factory_;
|
||||
std::string rootfs_;
|
||||
std::string desktop_file_hint_;
|
||||
std::string apk_;
|
||||
std::string package_;
|
||||
|
|
|
|||
49
src/anbox/cmds/start_container.cpp
Normal file
49
src/anbox/cmds/start_container.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/cmds/start_container.h"
|
||||
#include "anbox/container/lxc_container.h"
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include "core/posix/signal.h"
|
||||
|
||||
anbox::cmds::StartContainer::StartContainer()
|
||||
: CommandWithFlagsAndAction{cli::Name{"start-container"}, cli::Usage{"start-container"}, cli::Description{"Start a container"}}
|
||||
{
|
||||
action([](const cli::Command::Context& ctxt) {
|
||||
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();
|
||||
|
||||
rt->start();
|
||||
|
||||
auto container = std::make_shared<container::LxcContainer>();
|
||||
container->start();
|
||||
|
||||
trap->run();
|
||||
container->stop();
|
||||
rt->stop();
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
|
@ -15,8 +15,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_CMDS_SHELL_H_
|
||||
#define ANBOX_CMDS_SHELL_H_
|
||||
#ifndef ANBOX_CMDS_START_CONTAINER_H_
|
||||
#define ANBOX_CMDS_START_CONTAINER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
|
@ -26,12 +26,9 @@
|
|||
|
||||
namespace anbox {
|
||||
namespace cmds {
|
||||
class Shell : public cli::CommandWithFlagsAndAction {
|
||||
class StartContainer : public cli::CommandWithFlagsAndAction {
|
||||
public:
|
||||
Shell();
|
||||
|
||||
private:
|
||||
int pid_;
|
||||
StartContainer();
|
||||
};
|
||||
} // namespace cmds
|
||||
} // namespace anbox
|
||||
|
|
@ -24,48 +24,113 @@
|
|||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
std::string prefix_dir_from_env(const std::string &path, const std::string &env_var) {
|
||||
static auto snap_data_path = anbox::utils::get_env_value(env_var, "");
|
||||
auto result = path;
|
||||
if (!snap_data_path.empty())
|
||||
result = anbox::utils::string_format("%s/%s", snap_data_path, path);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
namespace anbox {
|
||||
namespace config {
|
||||
std::string data_path() {
|
||||
std::string in_snap_dir(const std::string &path) {
|
||||
return prefix_dir_from_env(path, "SNAP");
|
||||
}
|
||||
|
||||
std::string in_snap_data_dir(const std::string &path) {
|
||||
return prefix_dir_from_env(path, "SNAP_DATA");
|
||||
}
|
||||
|
||||
std::string in_snap_user_data_dir(const std::string &path) {
|
||||
return prefix_dir_from_env(path, "SNAP_USER_DATA");
|
||||
}
|
||||
|
||||
std::string home_path() {
|
||||
static std::string path;
|
||||
if (path.length() == 0) {
|
||||
const auto home_path = utils::get_env_value("HOME", "/home/phablet");
|
||||
path = utils::string_format("%s/.local/share/anbox", home_path);
|
||||
fs::create_directories(fs::path(path));
|
||||
if (path.empty()) {
|
||||
path = utils::get_env_value("HOME", "");
|
||||
if (path.empty())
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("No home directory specified"));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string host_share_path() {
|
||||
std::string runtime_dir() {
|
||||
static std::string path;
|
||||
if (path.length() == 0)
|
||||
path = utils::string_format("%s/share", data_path());
|
||||
if (path.empty()) {
|
||||
path = utils::get_env_value("XDG_RUNTIME_DIR", "");
|
||||
if (path.empty())
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("No runtime directory specified"));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string container_share_path() {
|
||||
return "/data/anbox-share";
|
||||
std::string state_dir() {
|
||||
static std::string path = "/var/lib";
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string log_path() {
|
||||
static std::string path = in_snap_data_dir(utils::string_format("%s/anbox/", state_dir()));
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string socket_path() {
|
||||
|
||||
static std::string path = utils::string_format("%s/anbox/sockets", runtime_dir());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string data_path() {
|
||||
static std::string path = utils::string_format("%s/.local/share/anbox/data", home_path());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string rootfs_path() {
|
||||
static std::string path = in_snap_dir(utils::string_format("%s/anbox/rootfs", state_dir()));
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string container_config_path() {
|
||||
static std::string path = in_snap_data_dir(utils::string_format("%s/anbox/containers", state_dir()));
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string container_socket_path() {
|
||||
std::string path = "/run/anbox-container.socket";
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string host_share_path() {
|
||||
static std::string path = utils::string_format("%s/android-share", data_path());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string host_input_device_path() {
|
||||
static std::string path = utils::string_format("%s/input-devices", data_path());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string host_android_data_path() {
|
||||
static std::string path;
|
||||
if (path.length() == 0)
|
||||
path = utils::string_format("%s/android-data", data_path());
|
||||
static std::string path = utils::string_format("%s/android-data", data_path());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string host_android_cache_path() {
|
||||
static std::string path;
|
||||
if (path.length() == 0)
|
||||
path = utils::string_format("%s/android-cache", data_path());
|
||||
static std::string path = utils::string_format("%s/android-cache", data_path());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string host_android_storage_path() {
|
||||
static std::string path;
|
||||
if (path.length() == 0)
|
||||
path = utils::string_format("%s/android-storage", data_path());
|
||||
static std::string path = utils::string_format("%s/android-storage", data_path());
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string container_android_share_path() {
|
||||
return "/data/anbox-share";
|
||||
}
|
||||
} // namespace config
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -22,12 +22,21 @@
|
|||
|
||||
namespace anbox {
|
||||
namespace config {
|
||||
std::string in_snap_dir(const std::string &path);
|
||||
std::string in_snap_data_dir(const std::string &path);
|
||||
std::string in_snap_user_data_dir(const std::string &path);
|
||||
std::string data_path();
|
||||
std::string rootfs_path();
|
||||
std::string log_path();
|
||||
std::string socket_path();
|
||||
std::string container_config_path();
|
||||
std::string container_socket_path();
|
||||
std::string host_share_path();
|
||||
std::string container_share_path();
|
||||
std::string host_input_device_path();
|
||||
std::string host_android_data_path();
|
||||
std::string host_android_cache_path();
|
||||
std::string host_android_storage_path();
|
||||
std::string container_android_share_path();
|
||||
} // namespace config
|
||||
} // namespace anbox
|
||||
|
||||
|
|
|
|||
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* 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 <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#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"
|
||||
|
||||
#include <grp.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace anbox {
|
||||
|
||||
Container::Spec Container::Spec::Default() {
|
||||
Spec spec;
|
||||
spec.init_command = "/anbox-init.sh";
|
||||
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> args = {
|
||||
// We need to setup user mapping here as lxc-usernsexec will not
|
||||
// map our current user to root which we need to allow our container
|
||||
// to access files we've created and mapped into it
|
||||
"-m", utils::string_format("u:0:%d:1", getuid()),
|
||||
"-m", utils::string_format("g:0:%d:1", getgid()),
|
||||
// For all other users inside the container we're using a subuid/
|
||||
// subgid range which is defined on the host.
|
||||
"-m", "u:1:100000:65536",
|
||||
"-m", "g:1:100000:65536",
|
||||
"--",
|
||||
utils::string_format("%s/usr/bin/anbox-container", utils::get_env_value("SNAP", "")),
|
||||
"--bind", spec_.rootfs_path, "/",
|
||||
"--dev", "/dev",
|
||||
"--proc", "/proc",
|
||||
"--unshare-ipc",
|
||||
"--unshare-pid",
|
||||
"--unshare-uts",
|
||||
"--chdir", "/",
|
||||
"--pid-file", utils::string_format("%s/pid", config::data_path()),
|
||||
};
|
||||
|
||||
for (const auto &dir : spec_.temporary_dirs) {
|
||||
args.push_back("--tmpfs");
|
||||
args.push_back(dir);
|
||||
}
|
||||
|
||||
for (const auto &path : spec_.dev_bind_paths) {
|
||||
args.push_back("--dev-bind");
|
||||
args.push_back(path);
|
||||
args.push_back(path);
|
||||
}
|
||||
|
||||
for (const auto &path : spec_.bind_paths) {
|
||||
args.push_back("--bind");
|
||||
args.push_back(path.first);
|
||||
args.push_back(path.second);
|
||||
}
|
||||
|
||||
for (const auto &env : spec_.environment) {
|
||||
args.push_back("--setenv");
|
||||
args.push_back(env.first);
|
||||
args.push_back(env.second);
|
||||
}
|
||||
|
||||
args.push_back(spec_.init_command);
|
||||
|
||||
std::map<std::string,std::string> env = {
|
||||
// lxc-usernsexec needs this as otherwise it doesn't find the
|
||||
// newuidmap/newgidmap utilities it uses to setup the user
|
||||
// namespace
|
||||
{ "PATH", "/usr/bin" },
|
||||
};
|
||||
|
||||
child_ = core::posix::exec(
|
||||
utils::string_format("%s/usr/bin/lxc-usernsexec", utils::get_env_value("SNAP", "")),
|
||||
args, env, 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
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
@ -15,24 +15,17 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "core/posix/signal.h"
|
||||
|
||||
#include "anbox/logger.h"
|
||||
#include "anbox/container/client.h"
|
||||
#include "anbox/config.h"
|
||||
#include "anbox/container_connector.h"
|
||||
#include "anbox/cmds/shell.h"
|
||||
#include "anbox/logger.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"}},
|
||||
pid_(-1)
|
||||
{
|
||||
flag(cli::make_flag(cli::Name{"pid"}, cli::Description{"PID of container to attach to"}, pid_));
|
||||
action([this](const cli::Command::Context &) {
|
||||
ContainerConnector connector(pid_);
|
||||
return connector.run("/system/bin/sh");
|
||||
});
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
Client::Client(const std::shared_ptr<Runtime> &rt) :
|
||||
messenger_(config::container_socket_path(), rt) {
|
||||
}
|
||||
|
||||
Client::~Client() {
|
||||
}
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
37
src/anbox/container/client.h
Normal file
37
src/anbox/container/client.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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_CLIENT_H_
|
||||
#define ANBOX_CONTAINER_CLIENT_H_
|
||||
|
||||
#include "anbox/network/local_socket_messenger.h"
|
||||
#include "anbox/runtime.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
class Client {
|
||||
public:
|
||||
Client(const std::shared_ptr<Runtime> &rt);
|
||||
~Client();
|
||||
|
||||
private:
|
||||
network::LocalSocketMessenger messenger_;
|
||||
};
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
25
src/anbox/container/container.cpp
Normal file
25
src/anbox/container/container.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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/container.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
Container::~Container() {
|
||||
}
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
47
src/anbox/container/container.h
Normal file
47
src/anbox/container/container.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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_CONTAINER_H_
|
||||
#define ANBOX_CONTAINER_CONTAINER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
class Container {
|
||||
public:
|
||||
virtual ~Container();
|
||||
|
||||
enum class State {
|
||||
inactive,
|
||||
running,
|
||||
};
|
||||
|
||||
// Start the container in background
|
||||
virtual void start() = 0;
|
||||
|
||||
// Stop a running container
|
||||
virtual void stop() = 0;
|
||||
|
||||
// Get the current container state
|
||||
virtual State state() = 0;
|
||||
};
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
169
src/anbox/container/lxc_container.cpp
Normal file
169
src/anbox/container/lxc_container.cpp
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* 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/lxc_container.h"
|
||||
#include "anbox/utils.h"
|
||||
#include "anbox/config.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
namespace {
|
||||
static constexpr char *kAndroidShellCommand{"/system/bin/ls"};
|
||||
}
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
LxcContainer::LxcContainer() :
|
||||
state_(State::inactive),
|
||||
container_(nullptr) {
|
||||
utils::ensure_paths({
|
||||
config::container_config_path(),
|
||||
config::log_path(),
|
||||
config::host_share_path(),
|
||||
config::host_android_data_path(),
|
||||
config::host_android_cache_path(),
|
||||
config::host_android_storage_path(),
|
||||
config::host_input_device_path(),
|
||||
});
|
||||
}
|
||||
|
||||
LxcContainer::~LxcContainer() {
|
||||
if (container_)
|
||||
lxc_container_put(container_);
|
||||
}
|
||||
|
||||
void LxcContainer::start() {
|
||||
if (getuid() != 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("You have to start the container as root"));
|
||||
|
||||
if (container_ && container_->is_running(container_))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Container already started"));
|
||||
|
||||
if (!container_) {
|
||||
DEBUG("Containers are stored in %s", config::container_config_path());
|
||||
|
||||
// Remove container config to be be able to rewrite it
|
||||
::unlink(utils::string_format("%s/default/config", config::container_config_path()).c_str());
|
||||
|
||||
container_ = lxc_container_new("default", config::container_config_path().c_str());
|
||||
if (!container_)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to create LXC container instance"));
|
||||
}
|
||||
|
||||
// We drop all not needed capabilities
|
||||
set_config_item("lxc.cap.drop", "mac_admin mac_override sys_time sys_module sys_rawio");
|
||||
|
||||
// We can mount proc/sys as rw here as we will run the container unprivileged in the end
|
||||
set_config_item("lxc.mount.auto", "proc:mixed sys:mixed cgroup:mixed");
|
||||
|
||||
set_config_item("lxc.autodev", "1");
|
||||
set_config_item("lxc.pts", "1024");
|
||||
set_config_item("lxc.tty", "0");
|
||||
set_config_item("lxc.utsname", "anbox");
|
||||
|
||||
set_config_item("lxc.group.devices.deny","");
|
||||
set_config_item("lxc.group.devices.allow","");
|
||||
|
||||
// We can't move bind-mounts, so don't use /dev/lxc/
|
||||
set_config_item("lxc.devttydir", "");
|
||||
|
||||
set_config_item("lxc.environment", "PATH=/system/bin:/system/sbin:/system/xbin");
|
||||
|
||||
set_config_item("lxc.init_cmd", "/anbox-init.sh");
|
||||
set_config_item("lxc.rootfs.backend", "dir");
|
||||
|
||||
DEBUG("Using rootfs path %s", config::rootfs_path());
|
||||
set_config_item("lxc.rootfs", config::rootfs_path());
|
||||
|
||||
set_config_item("lxc.loglevel", "0");
|
||||
set_config_item("lxc.logfile", utils::string_format("%s/container.log", config::log_path()).c_str());
|
||||
|
||||
#if 0
|
||||
// Android uses namespaces as well so we have to allow nested namespaces for LXC
|
||||
// which are otherwise forbidden by AppArmor.
|
||||
set_config_item("lxc.aa_profile", "lxc-container-default-with-nesting");
|
||||
#else
|
||||
// FIXME: when using the nested profile we still get various denials from things
|
||||
// Android tries to do but isn't allowed to. We need to look into those and see
|
||||
// how we can switch back to a confined way of running the container.
|
||||
set_config_item("lxc.aa_profile", "unconfined");
|
||||
#endif
|
||||
|
||||
std::map<std::string,std::string> bind_mount_dirs = {
|
||||
{ config::host_share_path(), config::container_android_share_path() },
|
||||
{ config::host_android_data_path(), "data" },
|
||||
{ config::host_android_cache_path(), "cache" },
|
||||
{ config::host_android_storage_path(), "storage" },
|
||||
{ config::host_input_device_path(), "dev/input" },
|
||||
};
|
||||
|
||||
for (const auto &item : bind_mount_dirs) {
|
||||
set_config_item("lxc.mount.entry",
|
||||
utils::string_format("%s %s none bind,create=dir,optional 0 0", item.first, item.second));
|
||||
}
|
||||
|
||||
std::map<std::string,std::string> bind_mount_files = {
|
||||
{ "/dev/binder", "dev/binder" },
|
||||
{ "/dev/ashmem", "dev/ashmem" },
|
||||
{ utils::string_format("%s/qemu_pipe", config::socket_path()), "dev/qemu_pipe" },
|
||||
{ utils::string_format("%s/qemud", config::socket_path()), "dev/qemud" },
|
||||
{ utils::string_format("%s/anbox_bridge", config::socket_path()), "dev/anbox_bridge" },
|
||||
};
|
||||
|
||||
for (const auto &item : bind_mount_files) {
|
||||
set_config_item("lxc.mount.entry",
|
||||
utils::string_format("%s %s none bind,create=file,optional 0 0", item.first, item.second));
|
||||
}
|
||||
|
||||
if (!container_->save_config(container_, nullptr))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to save container configuration"));
|
||||
|
||||
if (not container_->start(container_, 0, nullptr))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to start container"));
|
||||
|
||||
DEBUG("Container successfully started");
|
||||
}
|
||||
|
||||
void LxcContainer::stop() {
|
||||
if (not container_ || not container_->is_running(container_))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Cannot stop container as it is not running"));
|
||||
|
||||
if (not container_->stop(container_))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to stop container"));
|
||||
|
||||
DEBUG("Container successfully stopped");
|
||||
}
|
||||
|
||||
void LxcContainer::set_config_item(const std::string &key, const std::string &value) {
|
||||
if (!container_->set_config_item(container_, key.c_str(), value.c_str()))
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to configure LXC container"));
|
||||
}
|
||||
|
||||
Container::State LxcContainer::state() {
|
||||
return state_;
|
||||
}
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
47
src/anbox/container/lxc_container.h
Normal file
47
src/anbox/container/lxc_container.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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_LXC_CONTAINER_H_
|
||||
#define ANBOX_CONTAINER_LXC_CONTAINER_H_
|
||||
|
||||
#include "anbox/container/container.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <lxc/lxccontainer.h>
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
class LxcContainer : public Container {
|
||||
public:
|
||||
LxcContainer();
|
||||
~LxcContainer();
|
||||
|
||||
void start() override;
|
||||
void stop() override;
|
||||
State state() override;
|
||||
|
||||
private:
|
||||
void set_config_item(const std::string &key, const std::string &value);
|
||||
|
||||
State state_;
|
||||
lxc_container *container_;
|
||||
};
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
112
src/anbox/container/service.cpp
Normal file
112
src/anbox/container/service.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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/service.h"
|
||||
#include "anbox/network/delegate_connection_creator.h"
|
||||
#include "anbox/network/delegate_message_processor.h"
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
#include "anbox/qemu/null_message_processor.h"
|
||||
#include "anbox/container/lxc_container.h"
|
||||
#include "anbox/config.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
std::shared_ptr<Service> Service::create(const std::shared_ptr<Runtime> &rt) {
|
||||
auto sp = std::make_shared<Service>(rt);
|
||||
|
||||
auto delegate_connector = std::make_shared<network::DelegateConnectionCreator>(
|
||||
[sp](std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) {
|
||||
sp->new_client(socket);
|
||||
});
|
||||
|
||||
sp->connector_ = std::make_shared<network::PublishedSocketConnector>(
|
||||
config::container_socket_path(), rt, delegate_connector);
|
||||
|
||||
// Make sure others can connect to our socket
|
||||
::chmod(config::container_socket_path().c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
|
||||
sp->connections_->set_observer(sp);
|
||||
|
||||
DEBUG("Everything setup. Waiting for incoming connections.");
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
Service::Service(const std::shared_ptr<Runtime> &rt) :
|
||||
dispatcher_(anbox::common::create_dispatcher_for_runtime(rt)),
|
||||
next_connection_id_(0),
|
||||
connections_(std::make_shared<network::Connections<network::SocketConnection>>()) {
|
||||
}
|
||||
|
||||
Service::~Service() {
|
||||
}
|
||||
|
||||
void Service::connection_added(int id) {
|
||||
}
|
||||
|
||||
void Service::connection_removed(int id) {
|
||||
stop_container();
|
||||
}
|
||||
|
||||
void Service::start_container() {
|
||||
if (backend_)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Container is already running"));
|
||||
|
||||
backend_ = std::make_shared<LxcContainer>();
|
||||
backend_->start();
|
||||
}
|
||||
|
||||
void Service::stop_container() {
|
||||
if (not backend_)
|
||||
return;
|
||||
|
||||
backend_->stop();
|
||||
backend_.reset();
|
||||
}
|
||||
|
||||
int Service::next_id() {
|
||||
return next_connection_id_++;
|
||||
}
|
||||
|
||||
void Service::new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) {
|
||||
if (connections_->size() >= 1) {
|
||||
socket->close();
|
||||
return;
|
||||
}
|
||||
|
||||
auto const messenger = std::make_shared<network::SocketMessenger>(socket);
|
||||
auto const& connection = std::make_shared<network::SocketConnection>(
|
||||
messenger, messenger, next_id(), connections_,
|
||||
std::make_shared<qemu::NullMessageProcessor>());
|
||||
|
||||
connections_->add(connection);
|
||||
connection->read_next_message();
|
||||
|
||||
// To get access to the sockets the application manager
|
||||
// services creates we need to make sure we're running
|
||||
// against the right runtime directory here. Its a bit
|
||||
// hacky but works for now.
|
||||
auto creds = messenger->creds();
|
||||
setenv("XDG_RUNTIME_DIR", utils::string_format("/run/user/%d", creds.uid()).c_str(), 1);
|
||||
|
||||
DEBUG("Got connection from pid %d", creds.pid());
|
||||
|
||||
start_container();
|
||||
}
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
58
src/anbox/container/service.h
Normal file
58
src/anbox/container/service.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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_SERVICE_H_
|
||||
#define ANBOX_CONTAINER_SERVICE_H_
|
||||
|
||||
#include "anbox/network/published_socket_connector.h"
|
||||
#include "anbox/network/connections.h"
|
||||
#include "anbox/network/socket_connection.h"
|
||||
#include "anbox/network/credentials.h"
|
||||
#include "anbox/container/container.h"
|
||||
#include "anbox/common/dispatcher.h"
|
||||
#include "anbox/runtime.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace container {
|
||||
class Service : public network::Connections<network::SocketConnection>::Observer,
|
||||
public std::enable_shared_from_this<Service> {
|
||||
public:
|
||||
static std::shared_ptr<Service> create(const std::shared_ptr<Runtime> &rt);
|
||||
|
||||
Service(const std::shared_ptr<Runtime> &rt);
|
||||
~Service();
|
||||
|
||||
void connection_added(int id) override;
|
||||
void connection_removed(int id) override;
|
||||
|
||||
private:
|
||||
int next_id();
|
||||
void new_client(std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket);
|
||||
|
||||
void start_container();
|
||||
void stop_container();
|
||||
|
||||
std::shared_ptr<common::Dispatcher> dispatcher_;
|
||||
std::shared_ptr<network::PublishedSocketConnector> connector_;
|
||||
std::atomic<int> next_connection_id_;
|
||||
std::shared_ptr<network::Connections<network::SocketConnection>> const connections_;
|
||||
std::shared_ptr<Container> backend_;
|
||||
};
|
||||
} // namespace container
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* 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/namespace_attacher.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>
|
||||
#include <grp.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace anbox {
|
||||
ContainerConnector::ContainerConnector(int pid) :
|
||||
pid_(pid) {
|
||||
}
|
||||
|
||||
ContainerConnector::~ContainerConnector() {
|
||||
}
|
||||
|
||||
int ContainerConnector::run(const std::string &path) {
|
||||
int pid = pid_;
|
||||
if (pid == -1)
|
||||
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<NamespaceType>{
|
||||
NamespaceType::user,
|
||||
NamespaceType::mount,
|
||||
NamespaceType::pid,
|
||||
NamespaceType::uts,
|
||||
NamespaceType::ipc,
|
||||
}, pid);
|
||||
|
||||
// A few things we want to preset in our env within the container shell
|
||||
std::map<std::string, std::string> env = {
|
||||
{ "ANDROID_ROOT", "/system" },
|
||||
{ "ANDROID_DATA", "/data" },
|
||||
};
|
||||
|
||||
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"));
|
||||
|
||||
setuid(0);
|
||||
setgid(0);
|
||||
setgroups(0, nullptr);
|
||||
|
||||
chdir("/");
|
||||
});
|
||||
|
||||
child.wait_for(core::posix::wait::Flags::untraced);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
@ -24,10 +24,11 @@
|
|||
|
||||
#include "anbox/cmds/version.h"
|
||||
#include "anbox/cmds/run.h"
|
||||
#include "anbox/cmds/shell.h"
|
||||
#include "anbox/cmds/install_app.h"
|
||||
#include "anbox/cmds/launch_app.h"
|
||||
#include "anbox/cmds/reset.h"
|
||||
#include "anbox/cmds/container_manager.h"
|
||||
#include "anbox/cmds/start_container.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
|
@ -39,34 +40,19 @@ Daemon::Daemon() :
|
|||
|
||||
cmd.command(std::make_shared<cmds::Version>())
|
||||
.command(std::make_shared<cmds::Run>())
|
||||
.command(std::make_shared<cmds::Shell>())
|
||||
.command(std::make_shared<cmds::InstallApp>())
|
||||
.command(std::make_shared<cmds::LaunchApp>())
|
||||
.command(std::make_shared<cmds::Reset>());
|
||||
.command(std::make_shared<cmds::Reset>())
|
||||
.command(std::make_shared<cmds::ContainerManager>())
|
||||
.command(std::make_shared<cmds::StartContainer>());
|
||||
}
|
||||
|
||||
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());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
void Daemon::ensure_data_path() {
|
||||
std::vector<std::string> paths = {
|
||||
config::data_path(),
|
||||
config::host_share_path(),
|
||||
config::host_android_data_path(),
|
||||
config::host_android_cache_path(),
|
||||
config::host_android_storage_path()
|
||||
};
|
||||
|
||||
for (const auto &path: paths) {
|
||||
if (!fs::is_directory(fs::path(path)))
|
||||
fs::create_directories(fs::path(path));
|
||||
}
|
||||
}
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ public:
|
|||
int Run(const std::vector<std::string> &arguments);
|
||||
|
||||
private:
|
||||
void ensure_data_path();
|
||||
|
||||
cli::CommandWithSubcommands cmd;
|
||||
};
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -154,8 +154,7 @@ std::string Device::socket_path() const {
|
|||
return connector_->socket_file();
|
||||
}
|
||||
|
||||
int Device::next_id()
|
||||
{
|
||||
int Device::next_id() {
|
||||
return next_connection_id_++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,22 +39,13 @@ std::shared_ptr<Device> Manager::create_device() {
|
|||
return device;
|
||||
}
|
||||
|
||||
void Manager::generate_mappings(std::map<std::string,std::string> &target) {
|
||||
for (const auto &iter : devices_) {
|
||||
target.insert({
|
||||
iter.second->socket_path(),
|
||||
(boost::format("/dev/input/event%1%") % iter.first).str(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t Manager::next_id() {
|
||||
static std::uint32_t next_id = 0;
|
||||
return next_id++;
|
||||
}
|
||||
|
||||
std::string Manager::build_device_path(const std::uint32_t &id) {
|
||||
return (boost::format("%1%/input_device_%2%") % config::data_path() % id).str();
|
||||
return (boost::format("%1%/event%2%") % config::host_input_device_path() % id).str();
|
||||
}
|
||||
|
||||
} // namespace input
|
||||
|
|
|
|||
|
|
@ -32,8 +32,6 @@ public:
|
|||
|
||||
std::shared_ptr<Device> create_device();
|
||||
|
||||
void generate_mappings(std::map<std::string,std::string> &target);
|
||||
|
||||
private:
|
||||
std::uint32_t next_id();
|
||||
std::string build_device_path(const std::uint32_t &id);
|
||||
|
|
|
|||
|
|
@ -29,19 +29,34 @@ template<class Connection>
|
|||
class Connections
|
||||
{
|
||||
public:
|
||||
class Observer {
|
||||
public:
|
||||
virtual void connection_added(int id) = 0;
|
||||
virtual void connection_removed(int id) = 0;
|
||||
};
|
||||
|
||||
Connections() {}
|
||||
~Connections() { clear(); }
|
||||
|
||||
void set_observer(const std::shared_ptr<Observer> &o)
|
||||
{
|
||||
observer = o;
|
||||
}
|
||||
|
||||
void add(std::shared_ptr<Connection> const& connection)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
connections.insert({connection->id(), connection});
|
||||
if (observer)
|
||||
observer->connection_added(connection->id());
|
||||
}
|
||||
|
||||
void remove(int id)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
connections.erase(id);
|
||||
if (observer)
|
||||
observer->connection_removed(id);
|
||||
}
|
||||
|
||||
bool includes(int id) const
|
||||
|
|
@ -72,6 +87,7 @@ private:
|
|||
|
||||
std::mutex mutex;
|
||||
std::map<int, std::shared_ptr<Connection>> connections;
|
||||
std::shared_ptr<Observer> observer;
|
||||
};
|
||||
} // namespace anbox
|
||||
} // namespace network
|
||||
|
|
|
|||
40
src/anbox/network/credentials.cpp
Normal file
40
src/anbox/network/credentials.cpp
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "anbox/network/credentials.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
Credentials::Credentials(pid_t pid, uid_t uid, gid_t gid) :
|
||||
pid_{pid},
|
||||
uid_{uid},
|
||||
gid_{gid} {
|
||||
}
|
||||
|
||||
pid_t Credentials::pid() const {
|
||||
return pid_;
|
||||
}
|
||||
|
||||
uid_t Credentials::uid() const {
|
||||
return uid_;
|
||||
}
|
||||
|
||||
gid_t Credentials::gid() const {
|
||||
return gid_;
|
||||
}
|
||||
} // namespace network
|
||||
} // namespace anbox
|
||||
43
src/anbox/network/credentials.h
Normal file
43
src/anbox/network/credentials.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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_CREDENTIALS_H_
|
||||
#define ANBOX_NETWORK_CREDENTIALS_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
class Credentials {
|
||||
public:
|
||||
Credentials(pid_t pid, uid_t uid, gid_t gid);
|
||||
|
||||
pid_t pid() const;
|
||||
uid_t uid() const;
|
||||
gid_t gid() const;
|
||||
|
||||
private:
|
||||
Credentials() = delete;
|
||||
|
||||
pid_t pid_;
|
||||
uid_t uid_;
|
||||
gid_t gid_;
|
||||
};
|
||||
} // namespace network
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
59
src/anbox/network/local_socket_messenger.cpp
Normal file
59
src/anbox/network/local_socket_messenger.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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/local_socket_messenger.h"
|
||||
#include "anbox/network/socket_helper.h"
|
||||
#include "anbox/utils.h"
|
||||
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
LocalSocketMessenger::LocalSocketMessenger(const std::string &path,
|
||||
const std::shared_ptr<Runtime> &rt) :
|
||||
socket_(std::make_shared<boost::asio::local::stream_protocol::socket>(rt->service())) {
|
||||
|
||||
boost::system::error_code err;
|
||||
socket_->connect(boost::asio::local::stream_protocol::endpoint(path), err);
|
||||
if (err) {
|
||||
const auto msg = utils::string_format("Failed to connect to socket %s: %s", path, err.message());
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error(msg));
|
||||
}
|
||||
|
||||
messenger_ = std::make_shared<SocketMessenger>(socket_);
|
||||
}
|
||||
|
||||
LocalSocketMessenger::~LocalSocketMessenger() {
|
||||
}
|
||||
|
||||
void LocalSocketMessenger::send(char const* data, size_t length) {
|
||||
messenger_->send(data, length);
|
||||
}
|
||||
|
||||
void LocalSocketMessenger::async_receive_msg(AnboxReadHandler const& handle, boost::asio::mutable_buffers_1 const &buffer) {
|
||||
messenger_->async_receive_msg(handle, buffer);
|
||||
}
|
||||
|
||||
boost::system::error_code LocalSocketMessenger::receive_msg(boost::asio::mutable_buffers_1 const& buffer) {
|
||||
return messenger_->receive_msg(buffer);
|
||||
}
|
||||
|
||||
size_t LocalSocketMessenger::available_bytes() {
|
||||
return messenger_->available_bytes();
|
||||
}
|
||||
} // namespace network
|
||||
} // namespace anbox
|
||||
48
src/anbox/network/local_socket_messenger.h
Normal file
48
src/anbox/network/local_socket_messenger.h
Normal 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_LOCAL_SOCKET_MESSENGER_H_
|
||||
#define ANBOX_NETWORK_LOCAL_SOCKET_MESSENGER_H_
|
||||
|
||||
#include "anbox/network/socket_messenger.h"
|
||||
#include "anbox/network/message_sender.h"
|
||||
#include "anbox/network/message_receiver.h"
|
||||
#include "anbox/runtime.h"
|
||||
|
||||
#include <boost/asio/local/stream_protocol.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
class LocalSocketMessenger : public MessageSender,
|
||||
public MessageReceiver {
|
||||
public:
|
||||
LocalSocketMessenger(const std::string &path, const std::shared_ptr<Runtime> &rt);
|
||||
~LocalSocketMessenger();
|
||||
|
||||
void send(char const* data, size_t length) override;
|
||||
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_;
|
||||
std::shared_ptr<SocketMessenger> messenger_;
|
||||
};
|
||||
} // namespace network
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -15,73 +15,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#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"
|
||||
#include "anbox/network/socket_helper.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 {
|
||||
|
|
@ -90,7 +29,7 @@ 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)),
|
||||
socket_file_(remove_socket_if_stale(socket_file)),
|
||||
runtime_(rt),
|
||||
connection_creator_(connection_creator),
|
||||
acceptor_(rt->service(), socket_file_) {
|
||||
|
|
|
|||
86
src/anbox/network/socket_helper.cpp
Normal file
86
src/anbox/network/socket_helper.cpp
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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/socket_helper.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
#include <boost/exception/errinfo_errno.hpp>
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
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_socket_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 network
|
||||
} // namespace anbox
|
||||
31
src/anbox/network/socket_helper.h
Normal file
31
src/anbox/network/socket_helper.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_NETWORK_SOCKET_HELPER_H_
|
||||
#define ANBOX_NETWORK_SOCKET_HELPER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
bool socket_file_exists(std::string const& filename);
|
||||
bool socket_exists(std::string const& socket_name);
|
||||
std::string remove_socket_if_stale(std::string const& socket_name);
|
||||
} // namespace network
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -46,6 +46,18 @@ SocketMessenger::SocketMessenger(std::shared_ptr<ba::local::stream_protocol::soc
|
|||
socket->set_option(option);
|
||||
}
|
||||
|
||||
Credentials SocketMessenger::creds() const {
|
||||
struct ucred cr;
|
||||
socklen_t cl = sizeof(cr);
|
||||
|
||||
auto status = getsockopt(socket_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl);
|
||||
|
||||
if (status)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to query client socket credentials"));
|
||||
|
||||
return {cr.pid, cr.uid, cr.gid};
|
||||
}
|
||||
|
||||
void SocketMessenger::send(char const* data, size_t length)
|
||||
{
|
||||
VariableLengthArray<serialization_buffer_size> whole_message{length};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "anbox/common/fd_sets.h"
|
||||
#include "anbox/network/message_sender.h"
|
||||
#include "anbox/network/message_receiver.h"
|
||||
#include "anbox/network/credentials.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace network {
|
||||
|
|
@ -32,7 +33,9 @@ class SocketMessenger : public MessageSender,
|
|||
public:
|
||||
SocketMessenger(std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket);
|
||||
|
||||
void send(char const* data, size_t length);
|
||||
Credentials creds() const;
|
||||
|
||||
void send(char const* data, size_t length) override;
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ void BootPropertiesMessageProcessor::list_properties() {
|
|||
|
||||
// TODO(morphis): Using HDPI here for now but should be adjusted to the device
|
||||
// we're running on.
|
||||
"ro.sf.lcd_density=480",
|
||||
"ro.sf.lcd_density=200",
|
||||
|
||||
// libhwui detects that we support certain GLESv3 extensions which
|
||||
// we don't yet support in our host channel so we have to disable
|
||||
|
|
|
|||
|
|
@ -461,7 +461,7 @@ void Window::process_input_event(const SDL_Event &event) {
|
|||
mouse_events.push_back({ EV_SYN, SYN_REPORT, 0 });
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
mouse_events.push_back({ EV_REL, REL_WHEEL, static_cast<std::int32_t>(event.wheel.direction) });
|
||||
mouse_events.push_back({ EV_REL, REL_WHEEL, static_cast<std::int32_t>(event.wheel.y) });
|
||||
break;
|
||||
case SDL_KEYDOWN: {
|
||||
const auto code = convert_sdl_scancode_to_evdev(event.key.keysym.scancode);
|
||||
|
|
|
|||
|
|
@ -25,29 +25,34 @@ namespace anbox {
|
|||
namespace ubuntu {
|
||||
WindowCreator::WindowCreator(const std::shared_ptr<input::Manager> &input_manager) :
|
||||
graphics::WindowCreator(input_manager),
|
||||
input_manager_(input_manager) {
|
||||
input_manager_(input_manager),
|
||||
event_thread_running_(false) {
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) < 0)
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("Failed to initialize SDL"));
|
||||
|
||||
event_thread = std::thread(&WindowCreator::process_events, this);
|
||||
event_thread_ = std::thread(&WindowCreator::process_events, this);
|
||||
}
|
||||
|
||||
WindowCreator::~WindowCreator() {
|
||||
event_thread_running_ = false;
|
||||
event_thread_.join();
|
||||
}
|
||||
|
||||
void WindowCreator::process_window_event(const SDL_Event &event) {
|
||||
}
|
||||
|
||||
void WindowCreator::process_events() {
|
||||
while(true) {
|
||||
event_thread_running_ = true;
|
||||
|
||||
while(event_thread_running_) {
|
||||
SDL_Event event;
|
||||
while (SDL_WaitEvent(&event)) {
|
||||
while (SDL_WaitEventTimeout(&event, 100)) {
|
||||
switch (event.type) {
|
||||
case SDL_QUIT:
|
||||
// FIXME once one of our windows is closed we need to decide what
|
||||
// to do base on the configuration we're running in.
|
||||
break;
|
||||
// FIXME: We exit here only as long as we don't have multi window
|
||||
// support.
|
||||
BOOST_THROW_EXCEPTION(std::runtime_error("User closed main application window"));
|
||||
case SDL_WINDOWEVENT:
|
||||
process_window_event(event);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -48,7 +48,8 @@ private:
|
|||
std::shared_ptr<input::Manager> input_manager_;
|
||||
std::map<EGLNativeWindowType,std::shared_ptr<Window>> windows_;
|
||||
std::shared_ptr<Window> current_window_;
|
||||
std::thread event_thread;
|
||||
std::thread event_thread_;
|
||||
bool event_thread_running_;
|
||||
};
|
||||
} // namespace bridge
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "anbox/utils.h"
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace anbox {
|
||||
namespace utils {
|
||||
|
||||
|
|
@ -139,5 +141,11 @@ std::string get_env_value(const std::string &name, const std::string &default_va
|
|||
return std::string(value);
|
||||
}
|
||||
|
||||
void ensure_paths(const std::vector<std::string> &paths) {
|
||||
for (const auto &path: paths) {
|
||||
if (!fs::is_directory(fs::path(path)))
|
||||
fs::create_directories(fs::path(path));
|
||||
}
|
||||
}
|
||||
} // namespace utils
|
||||
} // namespace anbox
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ std::string hex_dump(const uint8_t *data, uint32_t size);
|
|||
|
||||
std::string get_env_value(const std::string &name, const std::string &default_value = "");
|
||||
|
||||
void ensure_paths(const std::vector<std::string> &paths);
|
||||
|
||||
template<typename... Types>
|
||||
static std::string string_format(const std::string& fmt_str, Types&&... args);
|
||||
} // namespace utils
|
||||
|
|
|
|||
|
|
@ -15,8 +15,12 @@
|
|||
*
|
||||
*/
|
||||
|
||||
extern "C" int bwrap_main(int argc, char **argv);
|
||||
#include "anbox/container/service.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return bwrap_main(argc, argv);
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
anbox::container::Service service;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue