dbus: use systemd dbus support instead of out dated dbus-cpp
dbus-cpp was dropped from 18.04 as it is not maintained anymore so we should migrate to something more stable with a long term perspective. libsystemd fits in nicely here as it has a nice and clean dbus implementation which is battle tested and can be easily integrated into our existing C++ code base.
This commit is contained in:
parent
14774c0177
commit
f1480bfb91
22 changed files with 785 additions and 329 deletions
|
|
@ -65,10 +65,10 @@ find_package(Protobuf REQUIRED)
|
|||
|
||||
pkg_check_modules(SDL2 sdl2 REQUIRED)
|
||||
pkg_check_modules(SDL2_IMAGE SDL2_image REQUIRED)
|
||||
pkg_check_modules(DBUS_CPP dbus-cpp REQUIRED)
|
||||
pkg_check_modules(DBUS dbus-1 REQUIRED)
|
||||
pkg_check_modules(LXC lxc REQUIRED)
|
||||
pkg_check_modules(PROPERTIES_CPP properties-cpp REQUIRED)
|
||||
pkg_check_modules(LIBSYSTEMD libsystemd REQUIRED)
|
||||
# FIXME mir support is currently broken due to mir's API
|
||||
# being broken with recent landings in Ubuntu 16.04
|
||||
# pkg_check_modules(MIRCLIENT mirclient)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ include_directories(
|
|||
${PROPERTIES_CPP_INCLUDE_DIRS}
|
||||
${LXC_INCLUDE_DIRS}
|
||||
${MIRCLIENT_INCLUDE_DIRS}
|
||||
${LIBSYSTEMD_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/src
|
||||
|
|
@ -195,11 +196,16 @@ set(SOURCES
|
|||
anbox/bridge/platform_api_skeleton.cpp
|
||||
anbox/bridge/android_api_stub.cpp
|
||||
|
||||
anbox/dbus/bus.cpp
|
||||
anbox/dbus/bus.h
|
||||
anbox/dbus/sd_bus_helpers.h
|
||||
anbox/dbus/interface.h
|
||||
anbox/dbus/codecs.h
|
||||
anbox/dbus/skeleton/service.cpp
|
||||
anbox/dbus/skeleton/service.h
|
||||
anbox/dbus/skeleton/application_manager.cpp
|
||||
anbox/dbus/skeleton/application_manager.h
|
||||
anbox/dbus/stub/application_manager.cpp
|
||||
anbox/dbus/stub/application_manager.h
|
||||
|
||||
anbox/application/launcher_storage.cpp
|
||||
anbox/application/database.cpp
|
||||
|
|
@ -210,6 +216,8 @@ set(SOURCES
|
|||
anbox/cmds/container_manager.cpp
|
||||
anbox/cmds/launch.cpp
|
||||
anbox/cmds/system_info.cpp
|
||||
anbox/cmds/wait_ready.cpp
|
||||
anbox/cmds/wait_ready.h
|
||||
|
||||
anbox/utils/environment_file.cpp
|
||||
|
||||
|
|
@ -233,6 +241,8 @@ target_link_libraries(anbox-core
|
|||
${LXC_LIBRARIES}
|
||||
${MIRCLIENT_LDFLAGS}
|
||||
${MIRCLIENT_LIBRARIES}
|
||||
${LIBSYSTEMD_LDFLAGS}
|
||||
${LIBSYSTEMD_LIBRARIES}
|
||||
pthread
|
||||
process-cpp
|
||||
emugl_common
|
||||
|
|
|
|||
|
|
@ -16,29 +16,30 @@
|
|||
*/
|
||||
|
||||
#include "anbox/cmds/launch.h"
|
||||
#include "anbox/common/wait_handle.h"
|
||||
#include "anbox/dbus/stub/application_manager.h"
|
||||
#include "anbox/common/dispatcher.h"
|
||||
#include "anbox/dbus/interface.h"
|
||||
#include "anbox/ui/splash_screen.h"
|
||||
#include "anbox/system_configuration.h"
|
||||
#include "anbox/runtime.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <core/dbus/asio/executor.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "core/posix/exec.h"
|
||||
#include "core/posix/fork.h"
|
||||
#include "core/posix/signal.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace {
|
||||
const boost::posix_time::seconds max_wait_timeout{240};
|
||||
const int max_restart_attempts{3};
|
||||
const std::chrono::seconds restart_interval{5};
|
||||
constexpr unsigned int max_session_mgr_wait_attempts{10};
|
||||
const std::chrono::seconds session_mgr_wait_interval{5};
|
||||
constexpr unsigned int max_dbus_service_wait_attempts{10};
|
||||
const std::chrono::seconds dbus_service_wait_interval{5};
|
||||
|
||||
#if 0
|
||||
static int redirect_to_null(int flags, int fd) {
|
||||
int fd2;
|
||||
if ((fd2 = open("/dev/null", flags)) < 0)
|
||||
|
|
@ -53,6 +54,73 @@ static int redirect_to_null(int flags, int fd) {
|
|||
close(fd2);
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
bool anbox::cmds::Launch::launch_session_manager() {
|
||||
std::vector<std::string> args = {"session-manager"};
|
||||
std::map<std::string,std::string> env;
|
||||
core::posix::this_process::env::for_each([&](const std::string &name, const std::string &value) {
|
||||
env.insert({name, value});
|
||||
});
|
||||
|
||||
const auto exe_path = utils::process_get_exe_path(::getpid());
|
||||
if (!fs::exists(exe_path)) {
|
||||
ERROR("Can't find correct anbox executable to run. Found %s but does not exist", exe_path);
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
auto flags = core::posix::StandardStream::empty;
|
||||
auto child = core::posix::fork([&]() {
|
||||
|
||||
#if 0
|
||||
// We redirect all in/out/err to /dev/null as they can't be seen
|
||||
// anywhere. All logging output will directly go to syslog as we
|
||||
// will become a session leader below which will get us rid of a
|
||||
// controlling terminal.
|
||||
if (redirect_to_null(O_RDONLY, 0) < 0 ||
|
||||
redirect_to_null(O_WRONLY, 1) < 0 ||
|
||||
redirect_to_null(O_WRONLY, 2) < 0) {
|
||||
ERROR("Failed to redirect stdout/stderr/stdin: %s", strerror(errno));
|
||||
return core::posix::exit::Status::failure;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// As we forked one time already we're sure that our process is
|
||||
// not the session leader anymore so we can safely become the
|
||||
// new one and lead the process group.
|
||||
if (setsid() < 0) {
|
||||
ERROR("Failed to become new session leader: %s", strerror(errno));
|
||||
return core::posix::exit::Status::failure;
|
||||
}
|
||||
|
||||
umask(0077);
|
||||
|
||||
if (chdir("/") < 0) {
|
||||
ERROR("Failed to change current directory: %s", strerror(errno));
|
||||
return core::posix::exit::Status::failure;
|
||||
}
|
||||
|
||||
auto grandchild = core::posix::exec(exe_path, args, env, flags);
|
||||
grandchild.dont_kill_on_cleanup();
|
||||
return core::posix::exit::Status::success;
|
||||
}, flags);
|
||||
|
||||
// We don't wait for the grandchild but the child as we use double forking
|
||||
// here to break through the process hierarchy and make the grandchild a
|
||||
// direct child of the init process so it keeps running on its own and
|
||||
// indepent of our short living process here.
|
||||
child.wait_for(core::posix::wait::Flags::untraced);
|
||||
|
||||
DEBUG("Started session manager, will now try to connect ..");
|
||||
}
|
||||
catch (...) {
|
||||
ERROR("Failed to start session manager instance");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool anbox::cmds::Launch::try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub) {
|
||||
|
|
@ -96,6 +164,7 @@ anbox::cmds::Launch::Launch()
|
|||
cli::Description{"Use system instead of session DBus"},
|
||||
use_system_dbus_));
|
||||
|
||||
|
||||
action([this](const cli::Command::Context&) {
|
||||
if (!intent_.valid()) {
|
||||
ERROR("The intent you provided is invalid. Please provide a correct launch intent.");
|
||||
|
|
@ -104,144 +173,54 @@ anbox::cmds::Launch::Launch()
|
|||
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 bus_type = core::dbus::WellKnownBus::session;
|
||||
auto bus_type = anbox::dbus::Bus::Type::Session;
|
||||
if (use_system_dbus_)
|
||||
bus_type = core::dbus::WellKnownBus::system;
|
||||
|
||||
auto bus = std::make_shared<core::dbus::Bus>(bus_type);
|
||||
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
||||
bus_type = anbox::dbus::Bus::Type::System;
|
||||
auto bus = std::make_shared<anbox::dbus::Bus>(bus_type);
|
||||
|
||||
std::shared_ptr<ui::SplashScreen> ss;
|
||||
if (!bus->has_service_with_name(dbus::interface::Service::name())) {
|
||||
DEBUG("Session manager is not yet running, trying to start it");
|
||||
|
||||
// Instead of relying on the user session init system to start our
|
||||
// session manager process we also attempt to start it on our own
|
||||
// if not already running. This will help to mitigate problems with
|
||||
// a crashing or a not yet started session manager instance.
|
||||
std::shared_ptr<dbus::stub::ApplicationManager> stub;
|
||||
for (auto n = 0; n < max_restart_attempts; n++) {
|
||||
try {
|
||||
stub = dbus::stub::ApplicationManager::create_for_bus(bus);
|
||||
break;
|
||||
} catch (std::exception &err) {
|
||||
WARNING("Anbox session manager service isn't running, trying to start it.");
|
||||
if (!launch_session_manager())
|
||||
return EXIT_FAILURE;
|
||||
|
||||
// Give us a splash screen as long as we're trying to connect
|
||||
// with the session manager so the user knows something is
|
||||
// happening after he started Anbox.
|
||||
if (!ss)
|
||||
ss = std::make_shared<ui::SplashScreen>();
|
||||
|
||||
std::vector<std::string> args = {"session-manager"};
|
||||
|
||||
std::map<std::string,std::string> env;
|
||||
core::posix::this_process::env::for_each([&](const std::string &name, const std::string &value) {
|
||||
env.insert({name, value});
|
||||
});
|
||||
|
||||
const auto exe_path = utils::process_get_exe_path(::getpid());
|
||||
if (!fs::exists(exe_path)) {
|
||||
ERROR("Can't find correct anbox executable to run. Found %s but does not exist", exe_path);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
auto flags = core::posix::StandardStream::empty;
|
||||
auto child = core::posix::fork([&]() {
|
||||
// We redirect all in/out/err to /dev/null as they can't be seen
|
||||
// anywhere. All logging output will directly go to syslog as we
|
||||
// will become a session leader below which will get us rid of a
|
||||
// controlling terminal.
|
||||
if (redirect_to_null(O_RDONLY, 0) < 0 ||
|
||||
redirect_to_null(O_WRONLY, 1) < 0 ||
|
||||
redirect_to_null(O_WRONLY, 2) < 0) {
|
||||
ERROR("Failed to redirect stdout/stderr/stdin: %s", strerror(errno));
|
||||
return core::posix::exit::Status::failure;
|
||||
}
|
||||
|
||||
// As we forked one time already we're sure that our process is
|
||||
// not the session leader anymore so we can safely become the
|
||||
// new one and lead the process group.
|
||||
if (setsid() < 0) {
|
||||
ERROR("Failed to become new session leader: %s", strerror(errno));
|
||||
return core::posix::exit::Status::failure;
|
||||
}
|
||||
|
||||
umask(0077);
|
||||
|
||||
if (chdir("/") < 0) {
|
||||
ERROR("Failed to change current directory: %s", strerror(errno));
|
||||
return core::posix::exit::Status::failure;
|
||||
}
|
||||
|
||||
auto grandchild = core::posix::exec(exe_path, args, env, flags);
|
||||
grandchild.dont_kill_on_cleanup();
|
||||
return core::posix::exit::Status::success;
|
||||
}, flags);
|
||||
|
||||
// We don't wait for the grandchild but the child as we use double forking
|
||||
// here to break through the process hierarchy and make the grandchild a
|
||||
// direct child of the init process so it keeps running on its own and
|
||||
// indepent of our short living process here.
|
||||
child.wait_for(core::posix::wait::Flags::untraced);
|
||||
|
||||
DEBUG("Started session manager, will now try to connect ..");
|
||||
}
|
||||
catch (...) {
|
||||
ERROR("Failed to start session manager instance");
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(restart_interval);
|
||||
}
|
||||
// Give us a splash screen as long as we're trying to connect
|
||||
// with the session manager so the user knows something is
|
||||
// happening after he started Anbox.
|
||||
ss = std::make_shared<ui::SplashScreen>();
|
||||
}
|
||||
|
||||
if (!stub) {
|
||||
ERROR("Couldn't get a connection with the session manager");
|
||||
unsigned int n = 0;
|
||||
while (n < max_dbus_service_wait_attempts) {
|
||||
if (bus->has_service_with_name(dbus::interface::Service::name()))
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(dbus_service_wait_interval);
|
||||
n++;
|
||||
}
|
||||
|
||||
auto app_mgr = dbus::stub::ApplicationManager::create_for_bus(bus);
|
||||
n = 0;
|
||||
while (n < max_session_mgr_wait_attempts) {
|
||||
app_mgr->update_properties();
|
||||
if (app_mgr->ready().get())
|
||||
break;
|
||||
|
||||
std::this_thread::sleep_for(session_mgr_wait_interval);
|
||||
n++;
|
||||
}
|
||||
|
||||
if (!app_mgr->ready()) {
|
||||
ERROR("Session manager failed to become ready");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
|
||||
dispatcher->dispatch([&]() {
|
||||
if (stub->ready()) {
|
||||
ss.reset();
|
||||
success = try_launch_activity(stub);
|
||||
trap->stop();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("Android hasn't fully booted yet. Waiting a bit ..");
|
||||
|
||||
stub->ready().changed().connect([&](bool ready) {
|
||||
if (!ready)
|
||||
return;
|
||||
ss.reset();
|
||||
success = try_launch_activity(stub);
|
||||
trap->stop();
|
||||
});
|
||||
});
|
||||
|
||||
boost::asio::deadline_timer timer(rt->service());
|
||||
timer.expires_from_now(max_wait_timeout);
|
||||
timer.async_wait([&](const boost::system::error_code&) {
|
||||
WARNING("Stopped waiting as we've already waited for too long. Something");
|
||||
WARNING("is wrong with your setup or the container has failed to boot.");
|
||||
WARNING("If you think you found a bug please don't hesitate to file on");
|
||||
WARNING("at https://github.com/anbox/anbox/issues/new");
|
||||
trap->stop();
|
||||
});
|
||||
|
||||
rt->start();
|
||||
trap->run();
|
||||
rt->stop();
|
||||
// If we have a splash screen now is the time to drop it as we're
|
||||
// going to launch the real application now.
|
||||
ss.reset();
|
||||
|
||||
const auto success = try_launch_activity(app_mgr);
|
||||
return success ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class Launch : public cli::CommandWithFlagsAndAction {
|
|||
Launch();
|
||||
|
||||
private:
|
||||
bool launch_session_manager();
|
||||
bool try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub);
|
||||
|
||||
android::Intent intent_;
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "anbox/common/dispatcher.h"
|
||||
#include "anbox/system_configuration.h"
|
||||
#include "anbox/container/client.h"
|
||||
#include "anbox/dbus/bus.h"
|
||||
#include "anbox/dbus/skeleton/service.h"
|
||||
#include "anbox/input/manager.h"
|
||||
#include "anbox/logger.h"
|
||||
|
|
@ -49,8 +50,6 @@
|
|||
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#include <core/dbus/asio/executor.h>
|
||||
#include <core/dbus/bus.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
|
@ -140,13 +139,12 @@ anbox::cmds::SessionManager::SessionManager()
|
|||
if (!standalone_) {
|
||||
container_ = std::make_shared<container::Client>(rt);
|
||||
container_->register_terminate_handler([&]() {
|
||||
WARNING("Lost connection to container manager, terminating.");
|
||||
trap->stop();
|
||||
});
|
||||
WARNING("Lost connection to container manager, terminating.");
|
||||
trap->stop();
|
||||
});
|
||||
}
|
||||
|
||||
auto input_manager = std::make_shared<input::Manager>(rt);
|
||||
|
||||
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
|
||||
|
||||
auto display_frame = graphics::Rect::Invalid;
|
||||
|
|
@ -244,18 +242,21 @@ anbox::cmds::SessionManager::SessionManager()
|
|||
{"/dev/fuse", "/dev/fuse"},
|
||||
};
|
||||
|
||||
dispatcher->dispatch([&]() { container_->start(container_configuration); });
|
||||
dispatcher->dispatch([&]() {
|
||||
DEBUG("Starting container");
|
||||
container_->start(container_configuration);
|
||||
});
|
||||
}
|
||||
|
||||
auto bus_type = core::dbus::WellKnownBus::session;
|
||||
auto bus_type = anbox::dbus::Bus::Type::Session;
|
||||
if (use_system_dbus_)
|
||||
bus_type = core::dbus::WellKnownBus::system;
|
||||
|
||||
auto bus = std::make_shared<core::dbus::Bus>(bus_type);
|
||||
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
||||
bus_type = anbox::dbus::Bus::Type::System;
|
||||
auto bus = std::make_shared<anbox::dbus::Bus>(bus_type);
|
||||
|
||||
auto skeleton = anbox::dbus::skeleton::Service::create_for_bus(bus, app_manager);
|
||||
|
||||
bus->run_async();
|
||||
|
||||
rt->start();
|
||||
trap->run();
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@
|
|||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <core/dbus/bus.h>
|
||||
|
||||
#include "anbox/graphics/gl_renderer_server.h"
|
||||
#include "anbox/graphics/rect.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class SystemInformation {
|
|||
EGLConfig config;
|
||||
int n;
|
||||
if (s_egl.eglChooseConfig(display, config_attribs, &config, 1, &n) && n > 0) {
|
||||
GLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE};
|
||||
GLint attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
|
||||
auto context = s_egl.eglCreateContext(display, config, nullptr, attribs);
|
||||
if (context != EGL_NO_CONTEXT) {
|
||||
// We require surfaceless-context support here for now. If eglMakeCurrent fails
|
||||
|
|
|
|||
56
src/anbox/cmds/wait_ready.cpp
Normal file
56
src/anbox/cmds/wait_ready.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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/wait_ready.h"
|
||||
#include "anbox/dbus/stub/application_manager.h"
|
||||
|
||||
namespace {
|
||||
constexpr const unsigned int max_wait_attempts{30};
|
||||
}
|
||||
|
||||
anbox::cmds::WaitReady::WaitReady()
|
||||
: CommandWithFlagsAndAction{
|
||||
cli::Name{"wait-ready"}, cli::Usage{"wait-ready"},
|
||||
cli::Description{"Wait until the Android system has successfully booted"}} {
|
||||
|
||||
flag(cli::make_flag(cli::Name{"use-system-dbus"},
|
||||
cli::Description{"Use system instead of session DBus"},
|
||||
use_system_dbus_));
|
||||
|
||||
action([this](const cli::Command::Context&) {
|
||||
auto bus_type = anbox::dbus::Bus::Type::Session;
|
||||
if (use_system_dbus_)
|
||||
bus_type = anbox::dbus::Bus::Type::System;
|
||||
auto bus = std::make_shared<anbox::dbus::Bus>(bus_type);
|
||||
|
||||
auto stub = dbus::stub::ApplicationManager::create_for_bus(bus);
|
||||
|
||||
unsigned int n = 0;
|
||||
while (n < max_wait_attempts) {
|
||||
stub->update_properties();
|
||||
if (stub->ready().get())
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds{1});
|
||||
n++;
|
||||
}
|
||||
|
||||
return EXIT_FAILURE;
|
||||
});
|
||||
}
|
||||
39
src/anbox/cmds/wait_ready.h
Normal file
39
src/anbox/cmds/wait_ready.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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_WAIT_READY_H_
|
||||
#define ANBOX_CMDS_WAIT_READY_H_
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include "anbox/cli.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace cmds {
|
||||
class WaitReady : public cli::CommandWithFlagsAndAction {
|
||||
public:
|
||||
WaitReady();
|
||||
|
||||
private:
|
||||
bool use_system_dbus_ = false;
|
||||
};
|
||||
} // namespace cmds
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -37,6 +37,8 @@ ManagementApiSkeleton::~ManagementApiSkeleton() {}
|
|||
void ManagementApiSkeleton::start_container(
|
||||
anbox::protobuf::container::StartContainer const *request,
|
||||
anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done) {
|
||||
DEBUG("");
|
||||
|
||||
if (container_->state() == Container::State::running) {
|
||||
response->set_error("Container is already running");
|
||||
done->Run();
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "anbox/cmds/system_info.h"
|
||||
#include "anbox/cmds/launch.h"
|
||||
#include "anbox/cmds/version.h"
|
||||
#include "anbox/cmds/wait_ready.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
|
|
@ -40,8 +41,8 @@ Daemon::Daemon()
|
|||
.command(std::make_shared<cmds::SessionManager>())
|
||||
.command(std::make_shared<cmds::Launch>())
|
||||
.command(std::make_shared<cmds::ContainerManager>())
|
||||
.command(std::make_shared<cmds::SystemInfo>());
|
||||
|
||||
.command(std::make_shared<cmds::SystemInfo>())
|
||||
.command(std::make_shared<cmds::WaitReady>());
|
||||
|
||||
Log().Init(anbox::Logger::Severity::kWarning);
|
||||
|
||||
|
|
|
|||
86
src/anbox/dbus/bus.cpp
Normal file
86
src/anbox/dbus/bus.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/dbus/bus.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
Bus::Bus(Type type) :
|
||||
type_{type} {
|
||||
|
||||
int ret = 0;
|
||||
switch (type) {
|
||||
case Type::Session:
|
||||
ret = sd_bus_open_user(&bus_);
|
||||
break;
|
||||
case Type::System:
|
||||
ret = sd_bus_open_system(&bus_);
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument("Invalid bus type");
|
||||
}
|
||||
|
||||
if (ret < 0 || !bus_)
|
||||
throw std::runtime_error("Failed to connect to DBus");
|
||||
}
|
||||
|
||||
Bus::~Bus() {
|
||||
stop();
|
||||
|
||||
if (bus_)
|
||||
sd_bus_unref(bus_);
|
||||
}
|
||||
|
||||
bool Bus::has_service_with_name(const std::string &name) {
|
||||
auto r = sd_bus_get_name_creds(bus_,
|
||||
name.c_str(),
|
||||
0,
|
||||
nullptr);
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
sd_bus* Bus::raw() {
|
||||
return bus_;
|
||||
}
|
||||
|
||||
void Bus::run_async() {
|
||||
running_ = true;
|
||||
worker_thread_ = std::thread(&Bus::worker_main, this);
|
||||
}
|
||||
|
||||
void Bus::stop() {
|
||||
running_ = false;
|
||||
if (worker_thread_.joinable())
|
||||
worker_thread_.join();
|
||||
}
|
||||
|
||||
void Bus::worker_main() {
|
||||
while (running_) {
|
||||
auto ret = sd_bus_process(bus_, nullptr);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (ret > 0)
|
||||
continue;
|
||||
|
||||
ret = sd_bus_wait(bus_, 1000 * 500);
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace dbus
|
||||
} // namespace anbox
|
||||
60
src/anbox/dbus/bus.h
Normal file
60
src/anbox/dbus/bus.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 3, as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranties of
|
||||
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_DBUS_BUS_H_
|
||||
#define ANBOX_DBUS_BUS_H_
|
||||
|
||||
#include "anbox/do_not_copy_or_move.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
class Bus : public DoNotCopyOrMove {
|
||||
public:
|
||||
enum class Type {
|
||||
System,
|
||||
Session
|
||||
};
|
||||
|
||||
Bus(Type type);
|
||||
~Bus();
|
||||
|
||||
sd_bus* raw();
|
||||
|
||||
bool has_service_with_name(const std::string& name);
|
||||
void run_async();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
void worker_main();
|
||||
|
||||
Type type_;
|
||||
sd_bus *bus_ = nullptr;
|
||||
std::thread worker_thread_;
|
||||
std::atomic_bool running_{false};
|
||||
};
|
||||
using BusPtr = std::shared_ptr<Bus>;
|
||||
} // namespace dbus
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -18,51 +18,28 @@
|
|||
#ifndef ANBOX_DBUS_INTERFACE_H_
|
||||
#define ANBOX_DBUS_INTERFACE_H_
|
||||
|
||||
#include <core/dbus/macros.h>
|
||||
#include <core/dbus/property.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
namespace interface {
|
||||
struct Service {
|
||||
static inline std::string name() { return "org.anbox"; }
|
||||
static inline std::string path() { return "/"; }
|
||||
static inline const char* name() { return "org.anbox"; }
|
||||
static inline const char* path() { return "/org/anbox"; }
|
||||
};
|
||||
struct ApplicationManager {
|
||||
static inline std::string name() { return "org.anbox.ApplicationManager"; }
|
||||
static inline const char* name() { return "org.anbox.ApplicationManager"; }
|
||||
struct Methods {
|
||||
struct Launch {
|
||||
static inline std::string name() { return "Launch"; }
|
||||
typedef anbox::dbus::interface::ApplicationManager Interface;
|
||||
typedef void ResultType;
|
||||
static inline std::chrono::milliseconds default_timeout() {
|
||||
return std::chrono::seconds{60};
|
||||
}
|
||||
};
|
||||
struct Launch {
|
||||
static inline const char* name() { return "Launch"; }
|
||||
};
|
||||
};
|
||||
struct Properties {
|
||||
DBUS_CPP_READABLE_PROPERTY_DEF(Ready, ApplicationManager, bool)
|
||||
struct Ready {
|
||||
static inline const char* name() { return "Ready"; }
|
||||
};
|
||||
};
|
||||
};
|
||||
} // namespace interface
|
||||
} // namespace dbus
|
||||
} // namespace anbox
|
||||
|
||||
namespace core {
|
||||
namespace dbus {
|
||||
namespace traits {
|
||||
template <>
|
||||
struct Service<anbox::dbus::interface::ApplicationManager> {
|
||||
static inline const std::string& interface_name() {
|
||||
static const std::string s{"org.anbox.ApplicationManager"};
|
||||
return s;
|
||||
}
|
||||
};
|
||||
} // namespace traits
|
||||
} // namespace dbus
|
||||
} // namespace core
|
||||
|
||||
#endif
|
||||
|
|
|
|||
121
src/anbox/dbus/sd_bus_helpers.h
Normal file
121
src/anbox/dbus/sd_bus_helpers.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (C) 2018 OpenBMC
|
||||
*
|
||||
* Taken from https://github.com/openbmc/sdbusplus/blob/master/sdbusplus/vtable.hpp
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ANBOX_DBUS_SD_BUS_HELPERS_H_
|
||||
#define ANBOX_DBUS_SD_BUS_HELPERS_H_
|
||||
|
||||
#include <systemd/sd-bus-vtable.h>
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
namespace sdbus {
|
||||
namespace vtable {
|
||||
constexpr sd_bus_vtable start(uint64_t flags)
|
||||
{
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_START;
|
||||
v.flags = flags;
|
||||
v.x.start = decltype(v.x.start){sizeof(sd_bus_vtable)};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable end() {
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_END;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable method_o(const char* member, const char* signature,
|
||||
const char* result,
|
||||
sd_bus_message_handler_t handler, size_t offset,
|
||||
uint64_t flags) {
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_METHOD;
|
||||
v.flags = flags;
|
||||
v.x.method = decltype(v.x.method){member, signature, result, handler, offset};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable method(const char* member, const char* signature,
|
||||
const char* result, sd_bus_message_handler_t handler,
|
||||
uint64_t flags) {
|
||||
return method_o(member, signature, result, handler, 0, flags);
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable signal(const char* member, const char* signature, uint64_t flags) {
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_SIGNAL;
|
||||
v.flags = flags;
|
||||
v.x.signal = decltype(v.x.signal){member, signature};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable property(const char* member, const char* signature,
|
||||
sd_bus_property_get_t get,
|
||||
uint64_t flags) {
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_PROPERTY;
|
||||
v.flags = flags;
|
||||
v.x.property = decltype(v.x.property){member, signature, get, nullptr, 0};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable property(const char* member, const char* signature,
|
||||
sd_bus_property_get_t get,
|
||||
sd_bus_property_set_t set,
|
||||
uint64_t flags) {
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_WRITABLE_PROPERTY;
|
||||
v.flags = flags;
|
||||
v.x.property = decltype(v.x.property){member, signature, get, set, 0};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable property_o(const char* member, const char* signature,
|
||||
size_t offset, uint64_t flags) {
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_PROPERTY;
|
||||
v.flags = flags;
|
||||
v.x.property = decltype(v.x.property){member, signature, nullptr, nullptr, offset};
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
constexpr sd_bus_vtable property_o(const char* member, const char* signature,
|
||||
sd_bus_property_set_t set, size_t offset,
|
||||
uint64_t flags)
|
||||
{
|
||||
sd_bus_vtable v{};
|
||||
v.type = _SD_BUS_VTABLE_WRITABLE_PROPERTY;
|
||||
v.flags = flags;
|
||||
v.x.property = decltype(v.x.property){member, signature, nullptr, set, offset};
|
||||
|
||||
return v;
|
||||
}
|
||||
} // namespace vtable
|
||||
} // namespace sd_bus
|
||||
} // namespace dbus
|
||||
} // namespace anbox
|
||||
|
||||
#endif
|
||||
|
|
@ -16,85 +16,164 @@
|
|||
*/
|
||||
|
||||
#include "anbox/dbus/skeleton/application_manager.h"
|
||||
#include "anbox/android/intent.h"
|
||||
#include "anbox/dbus/interface.h"
|
||||
#include "anbox/dbus/codecs.h"
|
||||
#include "anbox/dbus/sd_bus_helpers.h"
|
||||
#include "anbox/android/intent.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <core/property.h>
|
||||
|
||||
namespace {
|
||||
int parse_string_from_message(sd_bus_message *m, std::string &str) {
|
||||
const char *contents = nullptr;
|
||||
auto r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *value;
|
||||
r = sd_bus_message_read(m, "s", &value);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
str = value;
|
||||
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
namespace skeleton {
|
||||
ApplicationManager::ApplicationManager(
|
||||
const core::dbus::Bus::Ptr &bus, const core::dbus::Object::Ptr &object,
|
||||
const std::shared_ptr<anbox::application::Manager> &impl)
|
||||
: bus_(bus), object_(object), impl_(impl),
|
||||
properties_{ object_->get_property<anbox::dbus::interface::ApplicationManager::Properties::Ready>() },
|
||||
signals_{ object_->get_signal<core::dbus::interfaces::Properties::Signals::PropertiesChanged>() } {
|
||||
const sd_bus_vtable ApplicationManager::vtable[] = {
|
||||
sdbus::vtable::start(0),
|
||||
sdbus::vtable::method("Launch", "a{sv}s", "", ApplicationManager::method_launch, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
sdbus::vtable::property("Ready", "b", ApplicationManager::property_ready_get, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
sdbus::vtable::end()
|
||||
};
|
||||
|
||||
object_->install_method_handler<anbox::dbus::interface::ApplicationManager::Methods::Launch>(
|
||||
[this](const core::dbus::Message::Ptr &msg) {
|
||||
auto reader = msg->reader();
|
||||
int ApplicationManager::method_launch(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||||
auto r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
android::Intent intent;
|
||||
reader >> intent.action;
|
||||
reader >> intent.uri;
|
||||
reader >> intent.type;
|
||||
reader >> intent.flags;
|
||||
reader >> intent.package;
|
||||
reader >> intent.component;
|
||||
android::Intent intent;
|
||||
|
||||
std::int32_t left, top, right, bottom;
|
||||
reader >> left;
|
||||
reader >> top;
|
||||
reader >> right;
|
||||
reader >> bottom;
|
||||
graphics::Rect launch_bounds{left, top, right, bottom};
|
||||
while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
|
||||
const char *key = nullptr;
|
||||
|
||||
wm::Stack::Id stack = wm::Stack::Id::Default;
|
||||
reader >> stack;
|
||||
r = sd_bus_message_read(m, "s", &key);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
core::dbus::Message::Ptr reply;
|
||||
if (strcmp(key, "package") == 0) {
|
||||
r = parse_string_from_message(m, intent.package);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (strcmp(key, "component") == 0) {
|
||||
r = parse_string_from_message(m, intent.component);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (strcmp(key, "action") == 0) {
|
||||
r = parse_string_from_message(m, intent.action);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (strcmp(key, "type") == 0) {
|
||||
r = parse_string_from_message(m, intent.type);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (strcmp(key, "uri") == 0) {
|
||||
r = parse_string_from_message(m, intent.uri);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
launch(intent, launch_bounds, stack);
|
||||
reply = core::dbus::Message::make_method_return(msg);
|
||||
} catch (std::exception const &err) {
|
||||
reply = core::dbus::Message::make_error(msg, "org.anbox.Error.Failed",
|
||||
err.what());
|
||||
}
|
||||
r = sd_bus_message_exit_container(m);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
bus_->send(reply);
|
||||
});
|
||||
const char *stack = nullptr;
|
||||
r = sd_bus_message_read(m, "s", &stack);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
wm::Stack::Id launch_stack = wm::Stack::Id::Default;
|
||||
if (stack && strlen(stack) > 0) {
|
||||
auto s = std::string(stack);
|
||||
std::istringstream i(s);
|
||||
i >> launch_stack;
|
||||
}
|
||||
|
||||
if (intent.package.length() == 0) {
|
||||
sd_bus_error_set_const(ret_error, "org.anbox.InvalidArgument", "No package specified");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
auto thiz = static_cast<ApplicationManager*>(userdata);
|
||||
try {
|
||||
thiz->launch(intent, graphics::Rect::Invalid, launch_stack);
|
||||
} catch (std::exception &err) {
|
||||
ERROR("Failed to launch application: %s", err.what());
|
||||
sd_bus_error_set_const(ret_error, "org.anbox.InternalError", err.what());
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return sd_bus_reply_method_return(m, "");
|
||||
}
|
||||
|
||||
int ApplicationManager::property_ready_get(sd_bus *bus, const char *path, const char *interface,
|
||||
const char *property, sd_bus_message *reply,
|
||||
void *userdata, sd_bus_error *ret_error) {
|
||||
|
||||
(void) bus;
|
||||
(void) path;
|
||||
(void) interface;
|
||||
(void) property;
|
||||
(void) ret_error;
|
||||
|
||||
auto thiz = static_cast<ApplicationManager*>(userdata);
|
||||
|
||||
return sd_bus_message_append(reply, "b", thiz->impl_->ready().get());
|
||||
}
|
||||
|
||||
ApplicationManager::ApplicationManager(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl)
|
||||
: bus_(bus), impl_(impl) {
|
||||
|
||||
const auto r = sd_bus_add_object_vtable(bus_->raw(),
|
||||
&obj_slot_,
|
||||
interface::Service::path(),
|
||||
interface::ApplicationManager::name(),
|
||||
vtable,
|
||||
this);
|
||||
if (r < 0)
|
||||
std::runtime_error("Failed to setup application manager DBus service");
|
||||
|
||||
// Forward AndroidApi status to our dbus property
|
||||
properties_.ready->install([&]() { return impl_->ready().get(); });
|
||||
impl_->ready().changed().connect([&](bool value) {
|
||||
properties_.ready->set(value);
|
||||
on_property_value_changed<anbox::dbus::interface::ApplicationManager::Properties::Ready>(value);
|
||||
(void) value;
|
||||
|
||||
sd_bus_emit_properties_changed(bus_->raw(),
|
||||
interface::Service::path(),
|
||||
interface::ApplicationManager::name(),
|
||||
interface::ApplicationManager::Properties::Ready::name(),
|
||||
nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
ApplicationManager::~ApplicationManager() {}
|
||||
|
||||
template<typename Property>
|
||||
void ApplicationManager::on_property_value_changed(const typename Property::ValueType& value)
|
||||
{
|
||||
typedef std::map<std::string, core::dbus::types::Variant> Dictionary;
|
||||
|
||||
static const std::vector<std::string> the_empty_list_of_invalidated_properties;
|
||||
|
||||
Dictionary dict; dict[Property::name()] = core::dbus::types::Variant::encode(value);
|
||||
|
||||
signals_.properties_changed->emit(
|
||||
std::make_tuple(core::dbus::traits::Service<anbox::dbus::interface::ApplicationManager>::interface_name(),
|
||||
dict, the_empty_list_of_invalidated_properties));
|
||||
}
|
||||
|
||||
void ApplicationManager::launch(const android::Intent &intent,
|
||||
const graphics::Rect &launch_bounds,
|
||||
const wm::Stack::Id &stack) {
|
||||
if (!impl_->ready())
|
||||
throw std::runtime_error("Anbox not yet ready to launch applications");
|
||||
|
||||
DEBUG("Launching %s", intent);
|
||||
impl_->launch(intent, launch_bounds, stack);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,22 +19,16 @@
|
|||
#define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_
|
||||
|
||||
#include "anbox/application/manager.h"
|
||||
#include "anbox/dbus/bus.h"
|
||||
|
||||
#include <core/dbus/bus.h>
|
||||
#include <core/dbus/object.h>
|
||||
#include <core/dbus/service.h>
|
||||
#include <core/dbus/property.h>
|
||||
|
||||
#include "anbox/dbus/interface.h"
|
||||
#include <memory>
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
namespace skeleton {
|
||||
class ApplicationManager : public anbox::application::Manager {
|
||||
public:
|
||||
ApplicationManager(const core::dbus::Bus::Ptr &bus,
|
||||
const core::dbus::Object::Ptr &object,
|
||||
const std::shared_ptr<anbox::application::Manager> &impl);
|
||||
ApplicationManager(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl);
|
||||
~ApplicationManager();
|
||||
|
||||
void launch(const android::Intent &intent,
|
||||
|
|
@ -44,20 +38,15 @@ class ApplicationManager : public anbox::application::Manager {
|
|||
core::Property<bool>& ready() override;
|
||||
|
||||
private:
|
||||
template<typename Property>
|
||||
void on_property_value_changed(const typename Property::ValueType& value);
|
||||
static const sd_bus_vtable vtable[];
|
||||
static int method_launch(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
|
||||
static int property_ready_get(sd_bus *bus, const char *path, const char *interface,
|
||||
const char *property, sd_bus_message *reply, void *userdata,
|
||||
sd_bus_error *ret_error);
|
||||
|
||||
core::dbus::Bus::Ptr bus_;
|
||||
core::dbus::Service::Ptr service_;
|
||||
core::dbus::Object::Ptr object_;
|
||||
BusPtr bus_;
|
||||
std::shared_ptr<anbox::application::Manager> impl_;
|
||||
struct {
|
||||
std::shared_ptr<core::dbus::Property<anbox::dbus::interface::ApplicationManager::Properties::Ready>> ready;
|
||||
} properties_;
|
||||
struct {
|
||||
core::dbus::Signal<core::dbus::interfaces::Properties::Signals::PropertiesChanged,
|
||||
core::dbus::interfaces::Properties::Signals::PropertiesChanged::ArgumentType>::Ptr properties_changed;
|
||||
} signals_;
|
||||
sd_bus_slot *obj_slot_ = nullptr;
|
||||
};
|
||||
} // namespace skeleton
|
||||
} // namespace dbus
|
||||
|
|
|
|||
|
|
@ -15,29 +15,33 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "anbox/dbus/skeleton/service.h"
|
||||
#include "anbox/dbus/interface.h"
|
||||
#include "anbox/dbus/skeleton/service.h"
|
||||
#include "anbox/dbus/skeleton/application_manager.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
namespace skeleton {
|
||||
std::shared_ptr<Service> Service::create_for_bus(
|
||||
const core::dbus::Bus::Ptr &bus,
|
||||
const std::shared_ptr<anbox::application::Manager> &application_manager) {
|
||||
auto service = core::dbus::Service::add_service(bus, anbox::dbus::interface::Service::name());
|
||||
auto object = service->add_object_for_path(anbox::dbus::interface::Service::path());
|
||||
return std::make_shared<Service>(bus, service, object, application_manager);
|
||||
std::shared_ptr<Service> Service::create_for_bus(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl) {
|
||||
return std::shared_ptr<Service>(new Service(bus, impl));
|
||||
}
|
||||
|
||||
Service::Service(
|
||||
const core::dbus::Bus::Ptr &bus, const core::dbus::Service::Ptr &service,
|
||||
const core::dbus::Object::Ptr &object,
|
||||
const std::shared_ptr<anbox::application::Manager> &application_manager)
|
||||
: bus_(bus),
|
||||
service_(service),
|
||||
object_(object),
|
||||
application_manager_(std::make_shared<ApplicationManager>(bus_, object_, application_manager)) {}
|
||||
Service::Service(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl)
|
||||
: bus_{bus} {
|
||||
if (!bus_)
|
||||
throw std::invalid_argument("Missing bus object");
|
||||
|
||||
const auto r = sd_bus_request_name(bus_->raw(),
|
||||
interface::Service::name(),
|
||||
0);
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to request DBus service name");
|
||||
|
||||
DEBUG("Successfully acquired DBus service name");
|
||||
|
||||
application_manager_ = std::make_shared<ApplicationManager>(bus, impl);
|
||||
}
|
||||
|
||||
Service::~Service() {}
|
||||
} // namespace skeleton
|
||||
|
|
|
|||
|
|
@ -19,11 +19,14 @@
|
|||
#define ANBOX_DBUS_SKELETON_SERVICE_H_
|
||||
|
||||
#include "anbox/application/manager.h"
|
||||
#include "anbox/dbus/bus.h"
|
||||
#include "anbox/do_not_copy_or_move.h"
|
||||
|
||||
#include <core/dbus/bus.h>
|
||||
#include <core/dbus/object.h>
|
||||
#include <core/dbus/service.h>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
#include <systemd/sd-bus.h>
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
|
|
@ -31,20 +34,14 @@ namespace skeleton {
|
|||
class ApplicationManager;
|
||||
class Service : public DoNotCopyOrMove {
|
||||
public:
|
||||
static std::shared_ptr<Service> create_for_bus(
|
||||
const core::dbus::Bus::Ptr &bus,
|
||||
const std::shared_ptr<anbox::application::Manager> &application_manager);
|
||||
static std::shared_ptr<Service> create_for_bus(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl);
|
||||
|
||||
Service(
|
||||
const core::dbus::Bus::Ptr &bus, const core::dbus::Service::Ptr &service,
|
||||
const core::dbus::Object::Ptr &object,
|
||||
const std::shared_ptr<anbox::application::Manager> &application_manager);
|
||||
~Service();
|
||||
|
||||
private:
|
||||
core::dbus::Bus::Ptr bus_;
|
||||
core::dbus::Service::Ptr service_;
|
||||
core::dbus::Object::Ptr object_;
|
||||
Service(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl);
|
||||
|
||||
BusPtr bus_;
|
||||
std::shared_ptr<application::Manager> application_manager_;
|
||||
};
|
||||
} // namespace skeleton
|
||||
|
|
|
|||
|
|
@ -15,44 +15,108 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "anbox/dbus/stub/application_manager.h"
|
||||
#include "anbox/dbus/interface.h"
|
||||
#include "anbox/dbus/codecs.h"
|
||||
#include "anbox/dbus/stub/application_manager.h"
|
||||
#include "anbox/logger.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
namespace stub {
|
||||
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const core::dbus::Bus::Ptr &bus) {
|
||||
auto service = core::dbus::Service::use_service_or_throw_if_not_available(bus, anbox::dbus::interface::Service::name());
|
||||
auto object = service->object_for_path(anbox::dbus::interface::Service::path());
|
||||
return std::make_shared<ApplicationManager>(bus, service, object);
|
||||
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const BusPtr& bus) {
|
||||
return std::shared_ptr<ApplicationManager>(new ApplicationManager(bus));
|
||||
}
|
||||
|
||||
ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
|
||||
const core::dbus::Service::Ptr &service,
|
||||
const core::dbus::Object::Ptr &object)
|
||||
: bus_(bus), service_(service), object_(object),
|
||||
properties_{ object_->get_property<anbox::dbus::interface::ApplicationManager::Properties::Ready>() } {
|
||||
ApplicationManager::ApplicationManager(const BusPtr& bus)
|
||||
: bus_(bus) {
|
||||
|
||||
// Forward changes on the dbus property to our users
|
||||
ready_.install([&]() { return properties_.ready->get(); });
|
||||
properties_.ready->changed().connect([&](bool value) { ready_.set(value); });
|
||||
if (!bus_->has_service_with_name(interface::Service::name()))
|
||||
throw std::runtime_error("Application manager service is not running yet");
|
||||
|
||||
update_properties();
|
||||
}
|
||||
|
||||
ApplicationManager::~ApplicationManager() {}
|
||||
|
||||
void ApplicationManager::update_properties() {
|
||||
bool ready = false;
|
||||
const auto r = sd_bus_get_property_trivial(bus_->raw(),
|
||||
interface::Service::name(),
|
||||
interface::Service::path(),
|
||||
interface::ApplicationManager::name(),
|
||||
interface::ApplicationManager::Properties::Ready::name(),
|
||||
nullptr,
|
||||
'b',
|
||||
&ready);
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to retrieve ready property from application manager");
|
||||
|
||||
ready_.set(ready);
|
||||
}
|
||||
|
||||
void ApplicationManager::launch(const android::Intent &intent,
|
||||
const graphics::Rect &launch_bounds,
|
||||
const wm::Stack::Id &stack) {
|
||||
auto result = object_->invoke_method_synchronously<
|
||||
anbox::dbus::interface::ApplicationManager::Methods::Launch,
|
||||
anbox::dbus::interface::ApplicationManager::Methods::Launch::ResultType>(
|
||||
intent.action, intent.uri, intent.type, intent.flags, intent.package,
|
||||
intent.component, launch_bounds.left(), launch_bounds.top(),
|
||||
launch_bounds.right(), launch_bounds.bottom(), stack);
|
||||
(void) launch_bounds;
|
||||
|
||||
if (result.is_error()) throw std::runtime_error(result.error().print());
|
||||
sd_bus_message *m = nullptr;
|
||||
auto r = sd_bus_message_new_method_call(bus_->raw(),
|
||||
&m,
|
||||
interface::Service::name(),
|
||||
interface::Service::path(),
|
||||
interface::ApplicationManager::name(),
|
||||
interface::ApplicationManager::Methods::Launch::name());
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
|
||||
r = sd_bus_message_open_container(m, 'a', "{sv}");
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
|
||||
if (intent.package.length() > 0) {
|
||||
r = sd_bus_message_append(m, "{sv}", "package", "s", intent.package.c_str());
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
}
|
||||
|
||||
if (intent.component.length() > 0) {
|
||||
r = sd_bus_message_append(m, "{sv}", "component", "s", intent.component.c_str());
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
}
|
||||
|
||||
if (intent.action.length() > 0) {
|
||||
r = sd_bus_message_append(m, "{sv}", "action", "s", intent.action.c_str());
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
}
|
||||
|
||||
if (intent.type.length() > 0) {
|
||||
r = sd_bus_message_append(m, "{sv}", "type", "s", intent.type.c_str());
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
}
|
||||
|
||||
if (intent.uri.length() > 0) {
|
||||
r = sd_bus_message_append(m, "{sv}", "uri", "s", intent.uri.c_str());
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
}
|
||||
|
||||
r = sd_bus_message_close_container(m);
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
|
||||
std::ostringstream launch_stack;
|
||||
launch_stack << stack;
|
||||
r = sd_bus_message_append(m, "s", launch_stack.str().c_str());
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to construct DBus message");
|
||||
|
||||
r = sd_bus_call(bus_->raw(), m, 0, nullptr, nullptr);
|
||||
if (r < 0)
|
||||
throw std::runtime_error("Failed to call Anbox application manager");
|
||||
}
|
||||
|
||||
core::Property<bool>& ApplicationManager::ready() {
|
||||
|
|
|
|||
|
|
@ -19,24 +19,17 @@
|
|||
#define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_
|
||||
|
||||
#include "anbox/application/manager.h"
|
||||
#include "anbox/dbus/bus.h"
|
||||
|
||||
#include <core/dbus/bus.h>
|
||||
#include <core/dbus/object.h>
|
||||
#include <core/dbus/service.h>
|
||||
|
||||
#include "anbox/dbus/interface.h"
|
||||
#include <memory>
|
||||
|
||||
namespace anbox {
|
||||
namespace dbus {
|
||||
namespace stub {
|
||||
class ApplicationManager : public anbox::application::Manager {
|
||||
public:
|
||||
static std::shared_ptr<ApplicationManager> create_for_bus(
|
||||
const core::dbus::Bus::Ptr &bus);
|
||||
static std::shared_ptr<ApplicationManager> create_for_bus(const BusPtr& bus);
|
||||
|
||||
ApplicationManager(const core::dbus::Bus::Ptr &bus,
|
||||
const core::dbus::Service::Ptr &service,
|
||||
const core::dbus::Object::Ptr &object);
|
||||
~ApplicationManager();
|
||||
|
||||
void launch(const android::Intent &intent,
|
||||
|
|
@ -45,14 +38,13 @@ class ApplicationManager : public anbox::application::Manager {
|
|||
|
||||
core::Property<bool>& ready() override;
|
||||
|
||||
void update_properties();
|
||||
|
||||
private:
|
||||
core::dbus::Bus::Ptr bus_;
|
||||
core::dbus::Service::Ptr service_;
|
||||
core::dbus::Object::Ptr object_;
|
||||
ApplicationManager(const BusPtr& bus);
|
||||
|
||||
BusPtr bus_;
|
||||
core::Property<bool> ready_;
|
||||
struct {
|
||||
std::shared_ptr<core::dbus::Property<anbox::dbus::interface::ApplicationManager::Properties::Ready>> ready;
|
||||
} properties_;
|
||||
};
|
||||
} // namespace stub
|
||||
} // namespace dbus
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ bool AudioSink::connect_audio() {
|
|||
spec_.freq = 44100;
|
||||
spec_.format = AUDIO_S16;
|
||||
spec_.channels = 2;
|
||||
spec_.samples = 4096;
|
||||
spec_.samples = 1024;
|
||||
spec_.callback = &AudioSink::on_data_requested;
|
||||
spec_.userdata = this;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue