From 520be6e4bc0eb3f90480f5e789af6fa87676226f Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Thu, 30 Jun 2016 00:10:56 +0200 Subject: [PATCH] Wait for RPC call response before we return back to the caller --- src/CMakeLists.txt | 1 + src/anbox/bridge/platform_api_proxy.cpp | 48 ++++++++++--- src/anbox/bridge/platform_api_proxy.h | 18 +++-- src/anbox/common/wait_handle.cpp | 92 +++++++++++++++++++++++++ src/anbox/common/wait_handle.h | 54 +++++++++++++++ 5 files changed, 197 insertions(+), 16 deletions(-) create mode 100644 src/anbox/common/wait_handle.cpp create mode 100644 src/anbox/common/wait_handle.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ecfb119..d6ec191 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,6 +44,7 @@ set(SOURCES anbox/common/fd.cpp anbox/common/fd_sets.h anbox/common/variable_length_array.h + anbox/common/wait_handle.cpp anbox/network/message_sender.h anbox/network/message_receiver.h diff --git a/src/anbox/bridge/platform_api_proxy.cpp b/src/anbox/bridge/platform_api_proxy.cpp index c239fdc..6841fab 100644 --- a/src/anbox/bridge/platform_api_proxy.cpp +++ b/src/anbox/bridge/platform_api_proxy.cpp @@ -62,42 +62,62 @@ void PlatformApiProxy::install(const std::string &path) { const auto container_path = utils::string_format("%s/%s", config::container_share_path(), fs::path(path).filename().string()); - auto c = std::make_shared>(); + auto c = std::make_shared>(); protobuf::bridge::InstallApplication message; message.set_path(container_path); + { + std::lock_guard lock(mutex_); + install_wait_handle_.expect_result(); + } + channel_->call_method("install_application", &message, c->response.get(), google::protobuf::NewCallback(this, &PlatformApiProxy::application_installed, c.get())); + + install_wait_handle_.wait_for_all(); + + if (c->response->has_error()) + throw std::runtime_error(c->response->error()); } -void PlatformApiProxy::application_installed(Request *request) { - DEBUG(""); +void PlatformApiProxy::application_installed(Request *request) { + install_wait_handle_.result_received(); } void PlatformApiProxy::launch(const std::string &package, const std::string &activity) { ensure_rpc_channel(); - auto c = std::make_shared>(); + auto c = std::make_shared>(); protobuf::bridge::LaunchApplication message; message.set_package_name(package); message.set_activity(activity); + { + std::lock_guard lock(mutex_); + launch_wait_handle_.expect_result(); + } + channel_->call_method("launch_application", &message, c->response.get(), google::protobuf::NewCallback(this, &PlatformApiProxy::application_launched, c.get())); + + launch_wait_handle_.wait_for_all(); + + if (c->response->has_error()) + throw std::runtime_error(c->response->error()); } -void PlatformApiProxy::application_launched(Request *request) { - DEBUG(""); +void PlatformApiProxy::application_launched(Request *request) { + launch_wait_handle_.result_received(); } void PlatformApiProxy::set_dns_servers(const std::string &domain, const std::vector &servers) { ensure_rpc_channel(); - auto c = std::make_shared>(); + auto c = std::make_shared>(); protobuf::bridge::SetDnsServers message; message.set_domain(domain); @@ -107,14 +127,24 @@ void PlatformApiProxy::set_dns_servers(const std::string &domain, const std::vec server_message->set_address(server); } + { + std::lock_guard lock(mutex_); + set_dns_servers_wait_handle_.expect_result(); + } + channel_->call_method("set_dns_servers", &message, c->response.get(), google::protobuf::NewCallback(this, &PlatformApiProxy::dns_servers_set, c.get())); + + set_dns_servers_wait_handle_.wait_for_all(); + + if (c->response->has_error()) + throw std::runtime_error(c->response->error()); } -void PlatformApiProxy::dns_servers_set(Request *request) { - DEBUG(""); +void PlatformApiProxy::dns_servers_set(Request *request) { + set_dns_servers_wait_handle_.result_received(); } } // namespace bridge } // namespace anbox diff --git a/src/anbox/bridge/platform_api_proxy.h b/src/anbox/bridge/platform_api_proxy.h index a2d0271..25c8447 100644 --- a/src/anbox/bridge/platform_api_proxy.h +++ b/src/anbox/bridge/platform_api_proxy.h @@ -19,6 +19,7 @@ #define ANBOX_ANDROID_APPLICATION_MANAGER_H_ #include "anbox/application_manager.h" +#include "anbox/common/wait_handle.h" #include #include @@ -26,9 +27,7 @@ namespace anbox { namespace protobuf { namespace bridge { -class InstallApplication; -class LaunchApplication; -class SetDnsServers; +class Void; } // namespace bridge } // namespace protobuf namespace bridge { @@ -51,15 +50,20 @@ private: template struct Request { - Request() : response(std::make_shared()) { } + Request() : response(std::make_shared()), success(true) { } std::shared_ptr response; + bool success; }; - void application_installed(Request *request); - void application_launched(Request *request); - void dns_servers_set(Request *request); + void application_installed(Request *request); + void application_launched(Request *request); + void dns_servers_set(Request *request); + mutable std::mutex mutex_; std::shared_ptr channel_; + common::WaitHandle install_wait_handle_; + common::WaitHandle launch_wait_handle_; + common::WaitHandle set_dns_servers_wait_handle_; }; } // namespace bridge } // namespace anbox diff --git a/src/anbox/common/wait_handle.cpp b/src/anbox/common/wait_handle.cpp new file mode 100644 index 0000000..d3bb509 --- /dev/null +++ b/src/anbox/common/wait_handle.cpp @@ -0,0 +1,92 @@ +/* + * Copyright © 2012-2014 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Kevin DuBois + * Daniel van Vugt + */ + +#include "anbox/common/wait_handle.h" + +namespace anbox { +namespace common { +WaitHandle::WaitHandle() : + guard(), + wait_condition(), + expecting(0), + received(0) +{ +} + +WaitHandle::~WaitHandle() +{ +} + +void WaitHandle::expect_result() +{ + std::lock_guard lock(guard); + + expecting++; +} + +void WaitHandle::result_received() +{ + std::lock_guard lock(guard); + + received++; + wait_condition.notify_all(); +} + +void WaitHandle::wait_for_all() // wait for all results you expect +{ + std::unique_lock lock(guard); + + wait_condition.wait(lock, [&]{ return received == expecting; }); + + received = 0; + expecting = 0; +} + +void WaitHandle::wait_for_pending(std::chrono::milliseconds limit) +{ + std::unique_lock lock(guard); + + wait_condition.wait_for(lock, limit, [&]{ return received == expecting; }); +} + + +void WaitHandle::wait_for_one() // wait for any single result +{ + std::unique_lock lock(guard); + + wait_condition.wait(lock, [&]{ return received != 0; }); + + --received; + --expecting; +} + +bool WaitHandle::has_result() +{ + std::lock_guard lock(guard); + + return received > 0; +} + +bool WaitHandle::is_pending() +{ + std::unique_lock lock(guard); + return expecting > 0 && received != expecting; +} +} // namespace common +} // namespace anbox diff --git a/src/anbox/common/wait_handle.h b/src/anbox/common/wait_handle.h new file mode 100644 index 0000000..13e3cd8 --- /dev/null +++ b/src/anbox/common/wait_handle.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2012 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Thomas Guest + * Daniel van Vugt + */ + +#ifndef ANBOX_COMMON_WAIT_HANDLE_H_ +#define ANBOX_COMMON_WAIT_HANDLE_H_ + +#include +#include +#include + +namespace anbox { +namespace common { +struct WaitHandle +{ +public: + WaitHandle(); + ~WaitHandle(); + + void expect_result(); + void result_received(); + void wait_for_all(); + void wait_for_one(); + void wait_for_pending(std::chrono::milliseconds limit); + + bool has_result(); + bool is_pending(); + +private: + std::mutex guard; + std::condition_variable wait_condition; + + int expecting; + int received; +}; +} // namespace common +} // namespace anbox + +#endif