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 sdl2 REQUIRED)
|
||||||
pkg_check_modules(SDL2_IMAGE SDL2_image 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(DBUS dbus-1 REQUIRED)
|
||||||
pkg_check_modules(LXC lxc REQUIRED)
|
pkg_check_modules(LXC lxc REQUIRED)
|
||||||
pkg_check_modules(PROPERTIES_CPP properties-cpp 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
|
# FIXME mir support is currently broken due to mir's API
|
||||||
# being broken with recent landings in Ubuntu 16.04
|
# being broken with recent landings in Ubuntu 16.04
|
||||||
# pkg_check_modules(MIRCLIENT mirclient)
|
# pkg_check_modules(MIRCLIENT mirclient)
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ include_directories(
|
||||||
${PROPERTIES_CPP_INCLUDE_DIRS}
|
${PROPERTIES_CPP_INCLUDE_DIRS}
|
||||||
${LXC_INCLUDE_DIRS}
|
${LXC_INCLUDE_DIRS}
|
||||||
${MIRCLIENT_INCLUDE_DIRS}
|
${MIRCLIENT_INCLUDE_DIRS}
|
||||||
|
${LIBSYSTEMD_INCLUDE_DIRS}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
${CMAKE_SOURCE_DIR}
|
${CMAKE_SOURCE_DIR}
|
||||||
${CMAKE_SOURCE_DIR}/src
|
${CMAKE_SOURCE_DIR}/src
|
||||||
|
|
@ -195,11 +196,16 @@ set(SOURCES
|
||||||
anbox/bridge/platform_api_skeleton.cpp
|
anbox/bridge/platform_api_skeleton.cpp
|
||||||
anbox/bridge/android_api_stub.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/interface.h
|
||||||
anbox/dbus/codecs.h
|
|
||||||
anbox/dbus/skeleton/service.cpp
|
anbox/dbus/skeleton/service.cpp
|
||||||
|
anbox/dbus/skeleton/service.h
|
||||||
anbox/dbus/skeleton/application_manager.cpp
|
anbox/dbus/skeleton/application_manager.cpp
|
||||||
|
anbox/dbus/skeleton/application_manager.h
|
||||||
anbox/dbus/stub/application_manager.cpp
|
anbox/dbus/stub/application_manager.cpp
|
||||||
|
anbox/dbus/stub/application_manager.h
|
||||||
|
|
||||||
anbox/application/launcher_storage.cpp
|
anbox/application/launcher_storage.cpp
|
||||||
anbox/application/database.cpp
|
anbox/application/database.cpp
|
||||||
|
|
@ -210,6 +216,8 @@ set(SOURCES
|
||||||
anbox/cmds/container_manager.cpp
|
anbox/cmds/container_manager.cpp
|
||||||
anbox/cmds/launch.cpp
|
anbox/cmds/launch.cpp
|
||||||
anbox/cmds/system_info.cpp
|
anbox/cmds/system_info.cpp
|
||||||
|
anbox/cmds/wait_ready.cpp
|
||||||
|
anbox/cmds/wait_ready.h
|
||||||
|
|
||||||
anbox/utils/environment_file.cpp
|
anbox/utils/environment_file.cpp
|
||||||
|
|
||||||
|
|
@ -233,6 +241,8 @@ target_link_libraries(anbox-core
|
||||||
${LXC_LIBRARIES}
|
${LXC_LIBRARIES}
|
||||||
${MIRCLIENT_LDFLAGS}
|
${MIRCLIENT_LDFLAGS}
|
||||||
${MIRCLIENT_LIBRARIES}
|
${MIRCLIENT_LIBRARIES}
|
||||||
|
${LIBSYSTEMD_LDFLAGS}
|
||||||
|
${LIBSYSTEMD_LIBRARIES}
|
||||||
pthread
|
pthread
|
||||||
process-cpp
|
process-cpp
|
||||||
emugl_common
|
emugl_common
|
||||||
|
|
|
||||||
|
|
@ -16,29 +16,30 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "anbox/cmds/launch.h"
|
#include "anbox/cmds/launch.h"
|
||||||
#include "anbox/common/wait_handle.h"
|
|
||||||
#include "anbox/dbus/stub/application_manager.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/ui/splash_screen.h"
|
||||||
#include "anbox/system_configuration.h"
|
#include "anbox/system_configuration.h"
|
||||||
#include "anbox/runtime.h"
|
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
#include <core/dbus/asio/executor.h>
|
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
|
||||||
|
|
||||||
#include "core/posix/exec.h"
|
#include "core/posix/exec.h"
|
||||||
#include "core/posix/fork.h"
|
#include "core/posix/fork.h"
|
||||||
#include "core/posix/signal.h"
|
#include "core/posix/signal.h"
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const boost::posix_time::seconds max_wait_timeout{240};
|
constexpr unsigned int max_session_mgr_wait_attempts{10};
|
||||||
const int max_restart_attempts{3};
|
const std::chrono::seconds session_mgr_wait_interval{5};
|
||||||
const std::chrono::seconds restart_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) {
|
static int redirect_to_null(int flags, int fd) {
|
||||||
int fd2;
|
int fd2;
|
||||||
if ((fd2 = open("/dev/null", flags)) < 0)
|
if ((fd2 = open("/dev/null", flags)) < 0)
|
||||||
|
|
@ -53,6 +54,73 @@ static int redirect_to_null(int flags, int fd) {
|
||||||
close(fd2);
|
close(fd2);
|
||||||
return fd;
|
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) {
|
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"},
|
cli::Description{"Use system instead of session DBus"},
|
||||||
use_system_dbus_));
|
use_system_dbus_));
|
||||||
|
|
||||||
|
|
||||||
action([this](const cli::Command::Context&) {
|
action([this](const cli::Command::Context&) {
|
||||||
if (!intent_.valid()) {
|
if (!intent_.valid()) {
|
||||||
ERROR("The intent you provided is invalid. Please provide a correct launch intent.");
|
ERROR("The intent you provided is invalid. Please provide a correct launch intent.");
|
||||||
|
|
@ -104,144 +173,54 @@ anbox::cmds::Launch::Launch()
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto trap = core::posix::trap_signals_for_process({core::posix::Signal::sig_term, core::posix::Signal::sig_int});
|
auto bus_type = anbox::dbus::Bus::Type::Session;
|
||||||
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;
|
|
||||||
if (use_system_dbus_)
|
if (use_system_dbus_)
|
||||||
bus_type = core::dbus::WellKnownBus::system;
|
bus_type = anbox::dbus::Bus::Type::System;
|
||||||
|
auto bus = std::make_shared<anbox::dbus::Bus>(bus_type);
|
||||||
auto bus = std::make_shared<core::dbus::Bus>(bus_type);
|
|
||||||
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
|
||||||
|
|
||||||
std::shared_ptr<ui::SplashScreen> ss;
|
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
|
if (!launch_session_manager())
|
||||||
// session manager process we also attempt to start it on our own
|
return EXIT_FAILURE;
|
||||||
// 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.");
|
|
||||||
|
|
||||||
// Give us a splash screen as long as we're trying to connect
|
// Give us a splash screen as long as we're trying to connect
|
||||||
// with the session manager so the user knows something is
|
// with the session manager so the user knows something is
|
||||||
// happening after he started Anbox.
|
// happening after he started Anbox.
|
||||||
if (!ss)
|
ss = std::make_shared<ui::SplashScreen>();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!stub) {
|
unsigned int n = 0;
|
||||||
ERROR("Couldn't get a connection with the session manager");
|
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;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = false;
|
// If we have a splash screen now is the time to drop it as we're
|
||||||
auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt);
|
// going to launch the real application now.
|
||||||
dispatcher->dispatch([&]() {
|
ss.reset();
|
||||||
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();
|
|
||||||
|
|
||||||
|
const auto success = try_launch_activity(app_mgr);
|
||||||
return success ? EXIT_SUCCESS : EXIT_FAILURE;
|
return success ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ class Launch : public cli::CommandWithFlagsAndAction {
|
||||||
Launch();
|
Launch();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool launch_session_manager();
|
||||||
bool try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub);
|
bool try_launch_activity(const std::shared_ptr<dbus::stub::ApplicationManager> &stub);
|
||||||
|
|
||||||
android::Intent intent_;
|
android::Intent intent_;
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
#include "anbox/common/dispatcher.h"
|
#include "anbox/common/dispatcher.h"
|
||||||
#include "anbox/system_configuration.h"
|
#include "anbox/system_configuration.h"
|
||||||
#include "anbox/container/client.h"
|
#include "anbox/container/client.h"
|
||||||
|
#include "anbox/dbus/bus.h"
|
||||||
#include "anbox/dbus/skeleton/service.h"
|
#include "anbox/dbus/skeleton/service.h"
|
||||||
#include "anbox/input/manager.h"
|
#include "anbox/input/manager.h"
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
|
|
@ -49,8 +50,6 @@
|
||||||
|
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
|
|
||||||
#include <core/dbus/asio/executor.h>
|
|
||||||
#include <core/dbus/bus.h>
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
namespace fs = boost::filesystem;
|
namespace fs = boost::filesystem;
|
||||||
|
|
@ -140,13 +139,12 @@ anbox::cmds::SessionManager::SessionManager()
|
||||||
if (!standalone_) {
|
if (!standalone_) {
|
||||||
container_ = std::make_shared<container::Client>(rt);
|
container_ = std::make_shared<container::Client>(rt);
|
||||||
container_->register_terminate_handler([&]() {
|
container_->register_terminate_handler([&]() {
|
||||||
WARNING("Lost connection to container manager, terminating.");
|
WARNING("Lost connection to container manager, terminating.");
|
||||||
trap->stop();
|
trap->stop();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto input_manager = std::make_shared<input::Manager>(rt);
|
auto input_manager = std::make_shared<input::Manager>(rt);
|
||||||
|
|
||||||
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
|
auto android_api_stub = std::make_shared<bridge::AndroidApiStub>();
|
||||||
|
|
||||||
auto display_frame = graphics::Rect::Invalid;
|
auto display_frame = graphics::Rect::Invalid;
|
||||||
|
|
@ -244,18 +242,21 @@ anbox::cmds::SessionManager::SessionManager()
|
||||||
{"/dev/fuse", "/dev/fuse"},
|
{"/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_)
|
if (use_system_dbus_)
|
||||||
bus_type = core::dbus::WellKnownBus::system;
|
bus_type = anbox::dbus::Bus::Type::System;
|
||||||
|
auto bus = std::make_shared<anbox::dbus::Bus>(bus_type);
|
||||||
auto bus = std::make_shared<core::dbus::Bus>(bus_type);
|
|
||||||
bus->install_executor(core::dbus::asio::make_executor(bus, rt->service()));
|
|
||||||
|
|
||||||
auto skeleton = anbox::dbus::skeleton::Service::create_for_bus(bus, app_manager);
|
auto skeleton = anbox::dbus::skeleton::Service::create_for_bus(bus, app_manager);
|
||||||
|
|
||||||
|
bus->run_async();
|
||||||
|
|
||||||
rt->start();
|
rt->start();
|
||||||
trap->run();
|
trap->run();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <core/dbus/bus.h>
|
|
||||||
|
|
||||||
#include "anbox/graphics/gl_renderer_server.h"
|
#include "anbox/graphics/gl_renderer_server.h"
|
||||||
#include "anbox/graphics/rect.h"
|
#include "anbox/graphics/rect.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ class SystemInformation {
|
||||||
EGLConfig config;
|
EGLConfig config;
|
||||||
int n;
|
int n;
|
||||||
if (s_egl.eglChooseConfig(display, config_attribs, &config, 1, &n) && n > 0) {
|
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);
|
auto context = s_egl.eglCreateContext(display, config, nullptr, attribs);
|
||||||
if (context != EGL_NO_CONTEXT) {
|
if (context != EGL_NO_CONTEXT) {
|
||||||
// We require surfaceless-context support here for now. If eglMakeCurrent fails
|
// 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(
|
void ManagementApiSkeleton::start_container(
|
||||||
anbox::protobuf::container::StartContainer const *request,
|
anbox::protobuf::container::StartContainer const *request,
|
||||||
anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done) {
|
anbox::protobuf::rpc::Void *response, google::protobuf::Closure *done) {
|
||||||
|
DEBUG("");
|
||||||
|
|
||||||
if (container_->state() == Container::State::running) {
|
if (container_->state() == Container::State::running) {
|
||||||
response->set_error("Container is already running");
|
response->set_error("Container is already running");
|
||||||
done->Run();
|
done->Run();
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "anbox/cmds/system_info.h"
|
#include "anbox/cmds/system_info.h"
|
||||||
#include "anbox/cmds/launch.h"
|
#include "anbox/cmds/launch.h"
|
||||||
#include "anbox/cmds/version.h"
|
#include "anbox/cmds/version.h"
|
||||||
|
#include "anbox/cmds/wait_ready.h"
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
|
@ -40,8 +41,8 @@ Daemon::Daemon()
|
||||||
.command(std::make_shared<cmds::SessionManager>())
|
.command(std::make_shared<cmds::SessionManager>())
|
||||||
.command(std::make_shared<cmds::Launch>())
|
.command(std::make_shared<cmds::Launch>())
|
||||||
.command(std::make_shared<cmds::ContainerManager>())
|
.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);
|
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_
|
#ifndef ANBOX_DBUS_INTERFACE_H_
|
||||||
#define 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 anbox {
|
||||||
namespace dbus {
|
namespace dbus {
|
||||||
namespace interface {
|
namespace interface {
|
||||||
struct Service {
|
struct Service {
|
||||||
static inline std::string name() { return "org.anbox"; }
|
static inline const char* name() { return "org.anbox"; }
|
||||||
static inline std::string path() { return "/"; }
|
static inline const char* path() { return "/org/anbox"; }
|
||||||
};
|
};
|
||||||
struct ApplicationManager {
|
struct ApplicationManager {
|
||||||
static inline std::string name() { return "org.anbox.ApplicationManager"; }
|
static inline const char* name() { return "org.anbox.ApplicationManager"; }
|
||||||
struct Methods {
|
struct Methods {
|
||||||
struct Launch {
|
struct Launch {
|
||||||
static inline std::string name() { return "Launch"; }
|
static inline const char* 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 Properties {
|
struct Properties {
|
||||||
DBUS_CPP_READABLE_PROPERTY_DEF(Ready, ApplicationManager, bool)
|
struct Ready {
|
||||||
|
static inline const char* name() { return "Ready"; }
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} // namespace interface
|
} // namespace interface
|
||||||
} // namespace dbus
|
} // namespace dbus
|
||||||
} // namespace anbox
|
} // 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
|
#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/dbus/skeleton/application_manager.h"
|
||||||
#include "anbox/android/intent.h"
|
|
||||||
#include "anbox/dbus/interface.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 "anbox/logger.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <core/property.h>
|
#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 anbox {
|
||||||
namespace dbus {
|
namespace dbus {
|
||||||
namespace skeleton {
|
namespace skeleton {
|
||||||
ApplicationManager::ApplicationManager(
|
const sd_bus_vtable ApplicationManager::vtable[] = {
|
||||||
const core::dbus::Bus::Ptr &bus, const core::dbus::Object::Ptr &object,
|
sdbus::vtable::start(0),
|
||||||
const std::shared_ptr<anbox::application::Manager> &impl)
|
sdbus::vtable::method("Launch", "a{sv}s", "", ApplicationManager::method_launch, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
: bus_(bus), object_(object), impl_(impl),
|
sdbus::vtable::property("Ready", "b", ApplicationManager::property_ready_get, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||||
properties_{ object_->get_property<anbox::dbus::interface::ApplicationManager::Properties::Ready>() },
|
sdbus::vtable::end()
|
||||||
signals_{ object_->get_signal<core::dbus::interfaces::Properties::Signals::PropertiesChanged>() } {
|
};
|
||||||
|
|
||||||
object_->install_method_handler<anbox::dbus::interface::ApplicationManager::Methods::Launch>(
|
int ApplicationManager::method_launch(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
|
||||||
[this](const core::dbus::Message::Ptr &msg) {
|
auto r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}");
|
||||||
auto reader = msg->reader();
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
android::Intent intent;
|
android::Intent intent;
|
||||||
reader >> intent.action;
|
|
||||||
reader >> intent.uri;
|
|
||||||
reader >> intent.type;
|
|
||||||
reader >> intent.flags;
|
|
||||||
reader >> intent.package;
|
|
||||||
reader >> intent.component;
|
|
||||||
|
|
||||||
std::int32_t left, top, right, bottom;
|
while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
|
||||||
reader >> left;
|
const char *key = nullptr;
|
||||||
reader >> top;
|
|
||||||
reader >> right;
|
|
||||||
reader >> bottom;
|
|
||||||
graphics::Rect launch_bounds{left, top, right, bottom};
|
|
||||||
|
|
||||||
wm::Stack::Id stack = wm::Stack::Id::Default;
|
r = sd_bus_message_read(m, "s", &key);
|
||||||
reader >> stack;
|
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 {
|
r = sd_bus_message_exit_container(m);
|
||||||
launch(intent, launch_bounds, stack);
|
if (r < 0)
|
||||||
reply = core::dbus::Message::make_method_return(msg);
|
return r;
|
||||||
} catch (std::exception const &err) {
|
|
||||||
reply = core::dbus::Message::make_error(msg, "org.anbox.Error.Failed",
|
|
||||||
err.what());
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
impl_->ready().changed().connect([&](bool value) {
|
||||||
properties_.ready->set(value);
|
(void) value;
|
||||||
on_property_value_changed<anbox::dbus::interface::ApplicationManager::Properties::Ready>(value);
|
|
||||||
|
sd_bus_emit_properties_changed(bus_->raw(),
|
||||||
|
interface::Service::path(),
|
||||||
|
interface::ApplicationManager::name(),
|
||||||
|
interface::ApplicationManager::Properties::Ready::name(),
|
||||||
|
nullptr);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationManager::~ApplicationManager() {}
|
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,
|
void ApplicationManager::launch(const android::Intent &intent,
|
||||||
const graphics::Rect &launch_bounds,
|
const graphics::Rect &launch_bounds,
|
||||||
const wm::Stack::Id &stack) {
|
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);
|
impl_->launch(intent, launch_bounds, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,22 +19,16 @@
|
||||||
#define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_
|
#define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_
|
||||||
|
|
||||||
#include "anbox/application/manager.h"
|
#include "anbox/application/manager.h"
|
||||||
|
#include "anbox/dbus/bus.h"
|
||||||
|
|
||||||
#include <core/dbus/bus.h>
|
#include <memory>
|
||||||
#include <core/dbus/object.h>
|
|
||||||
#include <core/dbus/service.h>
|
|
||||||
#include <core/dbus/property.h>
|
|
||||||
|
|
||||||
#include "anbox/dbus/interface.h"
|
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace dbus {
|
namespace dbus {
|
||||||
namespace skeleton {
|
namespace skeleton {
|
||||||
class ApplicationManager : public anbox::application::Manager {
|
class ApplicationManager : public anbox::application::Manager {
|
||||||
public:
|
public:
|
||||||
ApplicationManager(const core::dbus::Bus::Ptr &bus,
|
ApplicationManager(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl);
|
||||||
const core::dbus::Object::Ptr &object,
|
|
||||||
const std::shared_ptr<anbox::application::Manager> &impl);
|
|
||||||
~ApplicationManager();
|
~ApplicationManager();
|
||||||
|
|
||||||
void launch(const android::Intent &intent,
|
void launch(const android::Intent &intent,
|
||||||
|
|
@ -44,20 +38,15 @@ class ApplicationManager : public anbox::application::Manager {
|
||||||
core::Property<bool>& ready() override;
|
core::Property<bool>& ready() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename Property>
|
static const sd_bus_vtable vtable[];
|
||||||
void on_property_value_changed(const typename Property::ValueType& value);
|
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_;
|
BusPtr bus_;
|
||||||
core::dbus::Service::Ptr service_;
|
|
||||||
core::dbus::Object::Ptr object_;
|
|
||||||
std::shared_ptr<anbox::application::Manager> impl_;
|
std::shared_ptr<anbox::application::Manager> impl_;
|
||||||
struct {
|
sd_bus_slot *obj_slot_ = nullptr;
|
||||||
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_;
|
|
||||||
};
|
};
|
||||||
} // namespace skeleton
|
} // namespace skeleton
|
||||||
} // namespace dbus
|
} // namespace dbus
|
||||||
|
|
|
||||||
|
|
@ -15,29 +15,33 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "anbox/dbus/skeleton/service.h"
|
|
||||||
#include "anbox/dbus/interface.h"
|
#include "anbox/dbus/interface.h"
|
||||||
|
#include "anbox/dbus/skeleton/service.h"
|
||||||
#include "anbox/dbus/skeleton/application_manager.h"
|
#include "anbox/dbus/skeleton/application_manager.h"
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace dbus {
|
namespace dbus {
|
||||||
namespace skeleton {
|
namespace skeleton {
|
||||||
std::shared_ptr<Service> Service::create_for_bus(
|
std::shared_ptr<Service> Service::create_for_bus(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl) {
|
||||||
const core::dbus::Bus::Ptr &bus,
|
return std::shared_ptr<Service>(new Service(bus, impl));
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::Service(
|
Service::Service(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl)
|
||||||
const core::dbus::Bus::Ptr &bus, const core::dbus::Service::Ptr &service,
|
: bus_{bus} {
|
||||||
const core::dbus::Object::Ptr &object,
|
if (!bus_)
|
||||||
const std::shared_ptr<anbox::application::Manager> &application_manager)
|
throw std::invalid_argument("Missing bus object");
|
||||||
: bus_(bus),
|
|
||||||
service_(service),
|
const auto r = sd_bus_request_name(bus_->raw(),
|
||||||
object_(object),
|
interface::Service::name(),
|
||||||
application_manager_(std::make_shared<ApplicationManager>(bus_, object_, application_manager)) {}
|
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() {}
|
Service::~Service() {}
|
||||||
} // namespace skeleton
|
} // namespace skeleton
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,14 @@
|
||||||
#define ANBOX_DBUS_SKELETON_SERVICE_H_
|
#define ANBOX_DBUS_SKELETON_SERVICE_H_
|
||||||
|
|
||||||
#include "anbox/application/manager.h"
|
#include "anbox/application/manager.h"
|
||||||
|
#include "anbox/dbus/bus.h"
|
||||||
#include "anbox/do_not_copy_or_move.h"
|
#include "anbox/do_not_copy_or_move.h"
|
||||||
|
|
||||||
#include <core/dbus/bus.h>
|
#include <atomic>
|
||||||
#include <core/dbus/object.h>
|
#include <memory>
|
||||||
#include <core/dbus/service.h>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <systemd/sd-bus.h>
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace dbus {
|
namespace dbus {
|
||||||
|
|
@ -31,20 +34,14 @@ namespace skeleton {
|
||||||
class ApplicationManager;
|
class ApplicationManager;
|
||||||
class Service : public DoNotCopyOrMove {
|
class Service : public DoNotCopyOrMove {
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<Service> create_for_bus(
|
static std::shared_ptr<Service> create_for_bus(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl);
|
||||||
const core::dbus::Bus::Ptr &bus,
|
|
||||||
const std::shared_ptr<anbox::application::Manager> &application_manager);
|
|
||||||
|
|
||||||
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();
|
~Service();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::dbus::Bus::Ptr bus_;
|
Service(const BusPtr& bus, const std::shared_ptr<anbox::application::Manager> &impl);
|
||||||
core::dbus::Service::Ptr service_;
|
|
||||||
core::dbus::Object::Ptr object_;
|
BusPtr bus_;
|
||||||
std::shared_ptr<application::Manager> application_manager_;
|
std::shared_ptr<application::Manager> application_manager_;
|
||||||
};
|
};
|
||||||
} // namespace skeleton
|
} // namespace skeleton
|
||||||
|
|
|
||||||
|
|
@ -15,44 +15,108 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "anbox/dbus/stub/application_manager.h"
|
|
||||||
#include "anbox/dbus/interface.h"
|
#include "anbox/dbus/interface.h"
|
||||||
#include "anbox/dbus/codecs.h"
|
#include "anbox/dbus/stub/application_manager.h"
|
||||||
#include "anbox/logger.h"
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace dbus {
|
namespace dbus {
|
||||||
namespace stub {
|
namespace stub {
|
||||||
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const core::dbus::Bus::Ptr &bus) {
|
std::shared_ptr<ApplicationManager> ApplicationManager::create_for_bus(const BusPtr& bus) {
|
||||||
auto service = core::dbus::Service::use_service_or_throw_if_not_available(bus, anbox::dbus::interface::Service::name());
|
return std::shared_ptr<ApplicationManager>(new ApplicationManager(bus));
|
||||||
auto object = service->object_for_path(anbox::dbus::interface::Service::path());
|
|
||||||
return std::make_shared<ApplicationManager>(bus, service, object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
|
ApplicationManager::ApplicationManager(const BusPtr& bus)
|
||||||
const core::dbus::Service::Ptr &service,
|
: bus_(bus) {
|
||||||
const core::dbus::Object::Ptr &object)
|
|
||||||
: bus_(bus), service_(service), object_(object),
|
|
||||||
properties_{ object_->get_property<anbox::dbus::interface::ApplicationManager::Properties::Ready>() } {
|
|
||||||
|
|
||||||
// Forward changes on the dbus property to our users
|
if (!bus_->has_service_with_name(interface::Service::name()))
|
||||||
ready_.install([&]() { return properties_.ready->get(); });
|
throw std::runtime_error("Application manager service is not running yet");
|
||||||
properties_.ready->changed().connect([&](bool value) { ready_.set(value); });
|
|
||||||
|
update_properties();
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationManager::~ApplicationManager() {}
|
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,
|
void ApplicationManager::launch(const android::Intent &intent,
|
||||||
const graphics::Rect &launch_bounds,
|
const graphics::Rect &launch_bounds,
|
||||||
const wm::Stack::Id &stack) {
|
const wm::Stack::Id &stack) {
|
||||||
auto result = object_->invoke_method_synchronously<
|
(void) launch_bounds;
|
||||||
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);
|
|
||||||
|
|
||||||
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() {
|
core::Property<bool>& ApplicationManager::ready() {
|
||||||
|
|
|
||||||
|
|
@ -19,24 +19,17 @@
|
||||||
#define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_
|
#define ANBOX_DBUS_SKELETON_APPLICATION_MANAGER_H_
|
||||||
|
|
||||||
#include "anbox/application/manager.h"
|
#include "anbox/application/manager.h"
|
||||||
|
#include "anbox/dbus/bus.h"
|
||||||
|
|
||||||
#include <core/dbus/bus.h>
|
#include <memory>
|
||||||
#include <core/dbus/object.h>
|
|
||||||
#include <core/dbus/service.h>
|
|
||||||
|
|
||||||
#include "anbox/dbus/interface.h"
|
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace dbus {
|
namespace dbus {
|
||||||
namespace stub {
|
namespace stub {
|
||||||
class ApplicationManager : public anbox::application::Manager {
|
class ApplicationManager : public anbox::application::Manager {
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<ApplicationManager> create_for_bus(
|
static std::shared_ptr<ApplicationManager> create_for_bus(const BusPtr& bus);
|
||||||
const core::dbus::Bus::Ptr &bus);
|
|
||||||
|
|
||||||
ApplicationManager(const core::dbus::Bus::Ptr &bus,
|
|
||||||
const core::dbus::Service::Ptr &service,
|
|
||||||
const core::dbus::Object::Ptr &object);
|
|
||||||
~ApplicationManager();
|
~ApplicationManager();
|
||||||
|
|
||||||
void launch(const android::Intent &intent,
|
void launch(const android::Intent &intent,
|
||||||
|
|
@ -45,14 +38,13 @@ class ApplicationManager : public anbox::application::Manager {
|
||||||
|
|
||||||
core::Property<bool>& ready() override;
|
core::Property<bool>& ready() override;
|
||||||
|
|
||||||
|
void update_properties();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
core::dbus::Bus::Ptr bus_;
|
ApplicationManager(const BusPtr& bus);
|
||||||
core::dbus::Service::Ptr service_;
|
|
||||||
core::dbus::Object::Ptr object_;
|
BusPtr bus_;
|
||||||
core::Property<bool> ready_;
|
core::Property<bool> ready_;
|
||||||
struct {
|
|
||||||
std::shared_ptr<core::dbus::Property<anbox::dbus::interface::ApplicationManager::Properties::Ready>> ready;
|
|
||||||
} properties_;
|
|
||||||
};
|
};
|
||||||
} // namespace stub
|
} // namespace stub
|
||||||
} // namespace dbus
|
} // namespace dbus
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ bool AudioSink::connect_audio() {
|
||||||
spec_.freq = 44100;
|
spec_.freq = 44100;
|
||||||
spec_.format = AUDIO_S16;
|
spec_.format = AUDIO_S16;
|
||||||
spec_.channels = 2;
|
spec_.channels = 2;
|
||||||
spec_.samples = 4096;
|
spec_.samples = 1024;
|
||||||
spec_.callback = &AudioSink::on_data_requested;
|
spec_.callback = &AudioSink::on_data_requested;
|
||||||
spec_.userdata = this;
|
spec_.userdata = this;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue