diff --git a/src/anbox/application_manager.h b/src/anbox/application_manager.h index e826449..0a21a29 100644 --- a/src/anbox/application_manager.h +++ b/src/anbox/application_manager.h @@ -24,10 +24,13 @@ #include +#include + namespace anbox { class ApplicationManager : public DoNotCopyOrMove { public: virtual void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) = 0; + virtual core::Property& ready() = 0; }; } // namespace anbox diff --git a/src/anbox/bridge/android_api_stub.cpp b/src/anbox/bridge/android_api_stub.cpp index 30a9854..2a471d5 100644 --- a/src/anbox/bridge/android_api_stub.cpp +++ b/src/anbox/bridge/android_api_stub.cpp @@ -92,6 +92,10 @@ void AndroidApiStub::launch(const android::Intent &intent, if (c->response->has_error()) throw std::runtime_error(c->response->error()); } +core::Property& AndroidApiStub::ready() { + return ready_; +} + void AndroidApiStub::application_launched( Request *request) { (void)request; diff --git a/src/anbox/bridge/android_api_stub.h b/src/anbox/bridge/android_api_stub.h index 35d7eab..0bb6a5c 100644 --- a/src/anbox/bridge/android_api_stub.h +++ b/src/anbox/bridge/android_api_stub.h @@ -43,13 +43,14 @@ class AndroidApiStub : public anbox::ApplicationManager { void set_rpc_channel(const std::shared_ptr &channel); void reset_rpc_channel(); - void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) override; - void set_focused_task(const std::int32_t &id); void remove_task(const std::int32_t &id); void resize_task(const std::int32_t &id, const anbox::graphics::Rect &rect, const std::int32_t &resize_mode); + void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) override; + core::Property& ready() override; + private: void ensure_rpc_channel(); @@ -72,6 +73,7 @@ class AndroidApiStub : public anbox::ApplicationManager { common::WaitHandle remove_task_handle_; common::WaitHandle resize_task_handle_; graphics::Rect launch_bounds_ = graphics::Rect::Invalid; + core::Property ready_; }; } // namespace bridge } // namespace anbox diff --git a/src/anbox/cmds/launch.cpp b/src/anbox/cmds/launch.cpp index 6e611d3..2a3671a 100644 --- a/src/anbox/cmds/launch.cpp +++ b/src/anbox/cmds/launch.cpp @@ -16,14 +16,24 @@ */ #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/runtime.h" +#include "anbox/logger.h" #include #include +#include "core/posix/signal.h" + namespace fs = boost::filesystem; +namespace { +const boost::posix_time::seconds max_wait_timeout{30}; +} + anbox::cmds::Launch::Launch() : CommandWithFlagsAndAction{ cli::Name{"launch"}, cli::Usage{"launch"}, @@ -46,13 +56,69 @@ anbox::cmds::Launch::Launch() intent_.component)); action([this](const cli::Command::Context&) { - auto bus = - std::make_shared(core::dbus::WellKnownBus::session); - bus->install_executor(core::dbus::asio::make_executor(bus)); - auto stub = dbus::stub::ApplicationManager::create_for_bus(bus); + 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(signal)); + trap->stop(); + }); - stub->launch(intent_); + auto rt = Runtime::create(); - return EXIT_SUCCESS; + auto bus = std::make_shared(core::dbus::WellKnownBus::session); + bus->install_executor(core::dbus::asio::make_executor(bus, rt->service())); + + std::shared_ptr stub; + try { + stub = dbus::stub::ApplicationManager::create_for_bus(bus); + } catch (...) { + ERROR("Anbox session manager service isn't running!"); + return EXIT_FAILURE; + } + + auto dispatcher = anbox::common::create_dispatcher_for_runtime(rt); + + bool success = false; + + dispatcher->dispatch([&]() { + if (stub->ready()) { + try { + stub->launch(intent_); + success = true; + } catch (std::exception &err) { + ERROR("err %s", err.what()); + } + trap->stop(); + return; + } + + DEBUG("Android hasn't fully booted yet. Waiting a bit.."); + + stub->ready().changed().connect([&](bool ready) { + if (!ready) + return; + try { + stub->launch(intent_); + success = true; + } catch (std::exception &err) { + ERROR("Failed to launch activity: %s", err.what()); + success = false; + } + 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("Stop waiting as we're already waiting for too long. Something is wrong"); + WARNING("with your setup and the container may have failed to boot."); + trap->stop(); + }); + + rt->start(); + trap->run(); + rt->stop(); + + return success ? EXIT_SUCCESS : EXIT_FAILURE; }); } diff --git a/src/anbox/cmds/session_manager.cpp b/src/anbox/cmds/session_manager.cpp index f0bd059..dcf0592 100644 --- a/src/anbox/cmds/session_manager.cpp +++ b/src/anbox/cmds/session_manager.cpp @@ -176,8 +176,10 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) auto server = std::make_shared( pending_calls, policy, window_manager, launcher_storage); - server->register_boot_finished_handler( - [&]() { DEBUG("Android successfully booted"); }); + server->register_boot_finished_handler([&]() { + DEBUG("Android successfully booted"); + android_api_stub->ready().set(true); + }); return std::make_shared( sender, server, pending_calls); })); diff --git a/src/anbox/dbus/interface.h b/src/anbox/dbus/interface.h index cbd9566..dee679c 100644 --- a/src/anbox/dbus/interface.h +++ b/src/anbox/dbus/interface.h @@ -19,6 +19,7 @@ #define ANBOX_DBUS_INTERFACE_H_ #include +#include #include #include @@ -42,6 +43,9 @@ struct ApplicationManager { } }; }; + struct Properties { + DBUS_CPP_READABLE_PROPERTY_DEF(Ready, ApplicationManager, bool) + }; }; } // namespace interface } // namespace dbus diff --git a/src/anbox/dbus/skeleton/application_manager.cpp b/src/anbox/dbus/skeleton/application_manager.cpp index 980390e..31ec7dc 100644 --- a/src/anbox/dbus/skeleton/application_manager.cpp +++ b/src/anbox/dbus/skeleton/application_manager.cpp @@ -20,15 +20,19 @@ #include "anbox/dbus/interface.h" #include "anbox/logger.h" +#include + namespace anbox { namespace dbus { namespace skeleton { ApplicationManager::ApplicationManager( const core::dbus::Bus::Ptr &bus, const core::dbus::Object::Ptr &object, const std::shared_ptr &impl) - : bus_(bus), object_(object), impl_(impl) { - object_->install_method_handler< - anbox::dbus::interface::ApplicationManager::Methods::Launch>( + : bus_(bus), object_(object), impl_(impl), + properties_{ object_->get_property() }, + signals_{ object_->get_signal() } { + + object_->install_method_handler( [this](const core::dbus::Message::Ptr &msg) { auto reader = msg->reader(); @@ -59,13 +63,38 @@ ApplicationManager::ApplicationManager( bus_->send(reply); }); + + // 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(value); + }); } ApplicationManager::~ApplicationManager() {} +template +void ApplicationManager::on_property_value_changed(const typename Property::ValueType& value) +{ + typedef std::map Dictionary; + + static const std::vector 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::interface_name(), + dict, the_empty_list_of_invalidated_properties)); +} + void ApplicationManager::launch(const android::Intent &intent, const graphics::Rect &launch_bounds) { impl_->launch(intent, launch_bounds); } + +core::Property& ApplicationManager::ready() { + return impl_->ready(); +} } // namespace skeleton } // namespace dbus } // namespace anbox diff --git a/src/anbox/dbus/skeleton/application_manager.h b/src/anbox/dbus/skeleton/application_manager.h index 03c5e40..c72f40b 100644 --- a/src/anbox/dbus/skeleton/application_manager.h +++ b/src/anbox/dbus/skeleton/application_manager.h @@ -23,6 +23,9 @@ #include #include #include +#include + +#include "anbox/dbus/interface.h" namespace anbox { namespace dbus { @@ -35,12 +38,23 @@ class ApplicationManager : public anbox::ApplicationManager { ~ApplicationManager(); void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) override; + core::Property& ready() override; private: + template + void on_property_value_changed(const typename Property::ValueType& value); + core::dbus::Bus::Ptr bus_; core::dbus::Service::Ptr service_; core::dbus::Object::Ptr object_; std::shared_ptr impl_; + struct { + std::shared_ptr> ready; + } properties_; + struct { + core::dbus::Signal::Ptr properties_changed; + } signals_; }; } // namespace skeleton } // namespace dbus diff --git a/src/anbox/dbus/skeleton/service.cpp b/src/anbox/dbus/skeleton/service.cpp index c205896..75e0580 100644 --- a/src/anbox/dbus/skeleton/service.cpp +++ b/src/anbox/dbus/skeleton/service.cpp @@ -39,8 +39,7 @@ Service::Service( : bus_(bus), service_(service), object_(object), - application_manager_(std::make_shared( - bus_, object_, application_manager)) {} + application_manager_(std::make_shared(bus_, object_, application_manager)) {} Service::~Service() {} } // namespace skeleton diff --git a/src/anbox/dbus/stub/application_manager.cpp b/src/anbox/dbus/stub/application_manager.cpp index ca395dd..ec4b21e 100644 --- a/src/anbox/dbus/stub/application_manager.cpp +++ b/src/anbox/dbus/stub/application_manager.cpp @@ -22,19 +22,22 @@ namespace anbox { namespace dbus { namespace stub { -std::shared_ptr ApplicationManager::create_for_bus( - const core::dbus::Bus::Ptr &bus) { - auto service = core::dbus::Service::use_service( - bus, anbox::dbus::interface::Service::name()); - auto object = - service->add_object_for_path(anbox::dbus::interface::Service::path()); +std::shared_ptr 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->add_object_for_path(anbox::dbus::interface::Service::path()); return std::make_shared(bus, service, object); } 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) {} + : bus_(bus), service_(service), object_(object), + properties_{ object_->get_property() } { + + // Forward changes on the dbus property to our users + ready_.install([&]() { return properties_.ready->get(); }); + properties_.ready->changed().connect([&](bool value) { ready_.set(value); }); +} ApplicationManager::~ApplicationManager() {} @@ -48,6 +51,10 @@ void ApplicationManager::launch(const android::Intent &intent, const graphics::R if (result.is_error()) throw std::runtime_error(result.error().print()); } + +core::Property& ApplicationManager::ready() { + return ready_; +} } // namespace skeleton } // namespace dbus } // namespace anbox diff --git a/src/anbox/dbus/stub/application_manager.h b/src/anbox/dbus/stub/application_manager.h index ee85917..bb44358 100644 --- a/src/anbox/dbus/stub/application_manager.h +++ b/src/anbox/dbus/stub/application_manager.h @@ -24,6 +24,8 @@ #include #include +#include "anbox/dbus/interface.h" + namespace anbox { namespace dbus { namespace stub { @@ -38,11 +40,16 @@ class ApplicationManager : public anbox::ApplicationManager { ~ApplicationManager(); void launch(const android::Intent &intent, const graphics::Rect &launch_bounds = graphics::Rect::Invalid) override; + core::Property& ready() override; private: core::dbus::Bus::Ptr bus_; core::dbus::Service::Ptr service_; core::dbus::Object::Ptr object_; + core::Property ready_; + struct { + std::shared_ptr> ready; + } properties_; }; } // namespace stub } // namespace dbus