diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..d8cedb8 --- /dev/null +++ b/Android.mk @@ -0,0 +1,50 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := libprocess-cpp-minimal +LOCAL_SRC_FILES := \ + external/process-cpp-minimal/src/core/posix/process.cpp \ + external/process-cpp-minimal/src/core/posix/process_group.cpp \ + external/process-cpp-minimal/src/core/posix/signal.cpp \ + external/process-cpp-minimal/src/core/posix/signalable.cpp \ + external/process-cpp-minimal/src/core/posix/standard_stream.cpp \ + external/process-cpp-minimal/src/core/posix/wait.cpp +LOCAL_CFLAGS := \ + -fexceptions +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/external/process-cpp-minimal/include +include $(BUILD_STATIC_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE := anboxd +LOCAL_SRC_FILES := \ + android/service/main.cpp \ + android/service/daemon.cpp \ + android/service/host_connector.cpp \ + android/service/local_socket_connection.cpp \ + android/service/message_processor.cpp \ + src/anbox/common/fd.cpp \ + src/anbox/bridge/message_processor.cpp \ + src/anbox/bridge/pending_call_cache.cpp \ + src/anbox/bridge/rpc_channel.cpp \ + src/anbox/protobuf/bridge.proto +proto_header_dir := $(call local-generated-sources-dir)/proto/$(LOCAL_PATH)/src/anbox/protobuf +LOCAL_C_INCLUDES += \ + $(proto_header_dir) \ + $(LOCAL_PATH)/external/process-cpp-minimal/include \ + $(LOCAL_PATH)/src \ + $(LOCAL_PATH)/android/service +LOCAL_EXPORT_C_INCLUDE_DIRS += $(proto_header_dir) +LOCAL_STATIC_LIBRARIES := \ + libprocess-cpp-minimal +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libprotobuf-cpp-lite \ + libsysutils +LOCAL_CFLAGS := \ + -fexceptions \ + -std=c++1y +include $(BUILD_EXECUTABLE) diff --git a/CMakeLists.txt b/CMakeLists.txt index 93ca169..484f293 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ find_package(PkgConfig) find_package(Threads) find_package(EGL REQUIRED) find_package(GLESv2 REQUIRED) +find_package(Protobuf REQUIRED) # TODO(morphis): make mir an optional requirement so we can also add support # for X11, wayland, ... at a later point if needed. diff --git a/android/Android.mk b/android/Android.mk deleted file mode 100644 index 0e62562..0000000 --- a/android/Android.mk +++ /dev/null @@ -1,43 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional -LOCAL_SRC_FILES = \ - jni/anbox_support.cpp \ - jni/application_manager.cpp \ - jni/jni_helper.cpp -LOCAL_C_INCLUDES := \ - $(JNI_H_INCLUDE) \ - libcore/include -LOCAL_SHARED_LIBRARIES := \ - liblog \ - libnativehelper -LOCAL_MODULE := libanbox_support - -include $(BUILD_SHARED_LIBRARY) - -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := optional -LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java -LOCAL_SRC_FILES := $(call all-java-files-under, java) -LOCAL_JAVA_LIBRARIES := telephony-common -LOCAL_JNI_SHARED_LIBRARIES := \ - libanbox_support -# Block certain packages from being installed -# LOCAL_OVERRIDES_PACKAGES := \ -# SystemUI \ -# Home \ -# Launcher2 \ -# Calculator \ -# BasicDreams \ -# Calendar \ -# PrintSpooler \ -# WallpaperCropper -LOCAL_PACKAGE_NAME := anboxd -LOCAL_CERTIFICATE := platform -LOCAL_PRIVILEGED_MODULE := true - -include $(BUILD_PACKAGE) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 0775045..15b84a1 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -1,4 +1,21 @@ +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src + ${CMAKE_BINARY_DIR}/src) + set(ANBOXD_SOURCES + ${CMAKE_SOURCE_DIR}/src/anbox/bridge/message_processor.cpp + ${CMAKE_SOURCE_DIR}/src/anbox/bridge/pending_call_cache.cpp + ${CMAKE_SOURCE_DIR}/src/anbox/common/fd.cpp + service/server.cpp + service/message_processor.cpp + service/local_socket_connection.cpp + service/host_connector.cpp + service/daemon.cpp service/main.cpp) add_executable(anboxd ${ANBOXD_SOURCES}) +target_link_libraries(anboxd + pthread + process-cpp + anbox-protobuf) diff --git a/android/service/daemon.cpp b/android/service/daemon.cpp new file mode 100644 index 0000000..012b3ab --- /dev/null +++ b/android/service/daemon.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "android/service/daemon.h" +#include "android/service/host_connector.h" + +#include "core/posix/signal.h" + +#include + +#include + +namespace anbox { +namespace android { +Daemon::Daemon() { +} + +Daemon::~Daemon() { +} + +int Daemon::run() { + 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&) { + trap->stop(); + }); + + auto host_connector = std::make_shared(); + + trap->run(); + + return EXIT_SUCCESS; +} +} // namespace android +} // namespace anbox diff --git a/android/service/daemon.h b/android/service/daemon.h new file mode 100644 index 0000000..84f2bd1 --- /dev/null +++ b/android/service/daemon.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_ANDROID_DAEMON_H_ +#define ANBOX_ANDROID_DAEMON_H_ + +namespace anbox { +namespace android { +class Daemon { +public: + Daemon(); + ~Daemon(); + + int run(); +}; +} // namespace android +} // namespace anbox + +#endif diff --git a/android/service/host_connector.cpp b/android/service/host_connector.cpp new file mode 100644 index 0000000..d5d4454 --- /dev/null +++ b/android/service/host_connector.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "android/service/host_connector.h" +#include "android/service/local_socket_connection.h" +#include "android/service/message_processor.h" +#include "android/service/server.h" + +#include +#include + +namespace anbox { +namespace android { +HostConnector::HostConnector() : + socket_(std::make_shared("/dev/anbox_bridge")), + pending_calls_(std::make_shared()), + server_(std::make_shared()), + message_processor_(std::make_shared(socket_, pending_calls_, server_)), + running_(false) { +} + +HostConnector::~HostConnector() { +} + +void HostConnector::start() { + if (running_) + return; + + running_.exchange(true); + thread_ = std::thread(std::bind(&HostConnector::main_loop, this)); +} + +void HostConnector::stop() { + if (!running_.exchange(false)) + return; + + thread_.join(); +} + +void HostConnector::main_loop() { + while (running_) { + std::array buffer; + const auto bytes_read = socket_->read_all(buffer.data(), buffer.size()); + if (bytes_read == 0) + break; + + // MessageProcessor wants an vector so give it what it wants until + // we refactor this. + std::vector data; + for (auto n = 0; n < bytes_read; n++) + data.push_back(buffer[n]); + + if (!message_processor_->process_data(data)) + break; + } + + // FIXME notify our core that we've stopped +} +} // namespace android +} // namespace anbox diff --git a/android/service/host_connector.h b/android/service/host_connector.h new file mode 100644 index 0000000..5f84282 --- /dev/null +++ b/android/service/host_connector.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_ANDROID_HOST_CONNECTOR_H_ +#define ANBOX_ANDROID_HOST_CONNECTOR_H_ + +#include +#include +#include + +namespace anbox { +namespace bridge { +class PendingCallCache; +} // namespace bridge +namespace android { +class LocalSocketConnection; +class MessageProcessor; +class Server; +class HostConnector { +public: + HostConnector(); + ~HostConnector(); + + void start(); + void stop(); + +private: + void main_loop(); + + std::shared_ptr socket_; + std::shared_ptr pending_calls_; + std::shared_ptr server_; + std::shared_ptr message_processor_; + std::thread thread_; + std::atomic running_; +}; +} // namespace android +} // namespace anbox + +#endif diff --git a/android/service/local_socket_connection.cpp b/android/service/local_socket_connection.cpp new file mode 100644 index 0000000..12e6248 --- /dev/null +++ b/android/service/local_socket_connection.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "android/service/local_socket_connection.h" + +#include +#include +#include +#include +#include + +namespace { +bool socket_error_is_transient(int error_code) { + return (error_code == EINTR); +} +} + +namespace anbox { +namespace android { +LocalSocketConnection::LocalSocketConnection(const std::string &path) : + fd_(Fd::invalid) { + + struct sockaddr_un socket_address; + memset(&socket_address, 0, sizeof(socket_address)); + + socket_address.sun_family = AF_UNIX; + memcpy(socket_address.sun_path, path.data(), path.size()); + + fd_ = Fd{socket(AF_UNIX, SOCK_STREAM, 0)}; + if (connect(fd_, reinterpret_cast(&socket_address), sizeof(socket_address)) < 0) + throw std::runtime_error("Failed to connect to server socket"); +} + +LocalSocketConnection::~LocalSocketConnection() { + if (fd_ > 0) + ::close(fd_); +} + +ssize_t LocalSocketConnection::read_all(std::uint8_t *buffer, const size_t &size) { + ssize_t bytes_read = ::recv(fd_, reinterpret_cast(buffer), size, 0); + return bytes_read; +} + +void LocalSocketConnection::send(char const* data, size_t length) { + size_t bytes_written{0}; + + while(bytes_written < length) { + ssize_t const result = ::send(fd_, + data + bytes_written, + length - bytes_written, + MSG_NOSIGNAL); + if (result < 0) { + if (socket_error_is_transient(errno)) + continue; + else + throw std::runtime_error("Failed to send message to server"); + } + + bytes_written += result; + } +} +} // namespace android +} // namespace anbox diff --git a/android/service/local_socket_connection.h b/android/service/local_socket_connection.h new file mode 100644 index 0000000..79fa7a0 --- /dev/null +++ b/android/service/local_socket_connection.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_ANDROID_LOCAL_SOCKET_CONNECTION_H_ +#define ANBOX_ANDROID_LOCAL_SOCKET_CONNECTION_H_ + +#include +#include + +#include "anbox/common/fd.h" +#include "anbox/network/message_sender.h" + +namespace anbox { +namespace android { +class LocalSocketConnection : public network::MessageSender { +public: + LocalSocketConnection(const std::string &path); + ~LocalSocketConnection(); + + ssize_t read_all(std::uint8_t *buffer, const size_t &size); + void send(char const* data, size_t length) override; + +private: + Fd fd_; +}; +} // namespace android +} // namespace anbox + +#endif diff --git a/android/service/main.cpp b/android/service/main.cpp index ca60629..1220879 100644 --- a/android/service/main.cpp +++ b/android/service/main.cpp @@ -15,6 +15,9 @@ * */ +#include "android/service/daemon.h" + int main(int, char**) { - return 0; + anbox::android::Daemon daemon; + return daemon.run(); } diff --git a/android/service/message_processor.cpp b/android/service/message_processor.cpp new file mode 100644 index 0000000..b89fb7b --- /dev/null +++ b/android/service/message_processor.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "android/service/message_processor.h" +#include "android/service/server.h" + +#include "anbox/bridge/template_message_processor.h" + +namespace anbox { +namespace android { +MessageProcessor::MessageProcessor(const std::shared_ptr &sender, + const std::shared_ptr &pending_calls, + const std::shared_ptr &server) : + bridge::MessageProcessor(sender, pending_calls), + server_(server) { +} + +MessageProcessor::~MessageProcessor() { +} + +void MessageProcessor::dispatch(bridge::Invocation const& invocation) { + if (invocation.method_name() == "install_application") + invoke(this, server_.get(), &Server::install_application, invocation); + else if (invocation.method_name() == "launch_application") + invoke(this, server_.get(), &Server::launch_application, invocation); +} + +void MessageProcessor::process_event_sequence(const std::string&) { +} +} // namespace anbox +} // namespace network diff --git a/android/service/message_processor.h b/android/service/message_processor.h new file mode 100644 index 0000000..89a393b --- /dev/null +++ b/android/service/message_processor.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_ANDROID_MESSAGE_PROCESSOR_H_ +#define ANBOX_ANDROID_MESSAGE_PROCESSOR_H_ + +#include "anbox/bridge/message_processor.h" + +namespace anbox { +namespace android { +class Server; +class MessageProcessor : public bridge::MessageProcessor { +public: + MessageProcessor(const std::shared_ptr &sender, + const std::shared_ptr &pending_calls, + const std::shared_ptr &server); + ~MessageProcessor(); + + void dispatch(bridge::Invocation const& invocation) override; + void process_event_sequence(const std::string &event) override; + +private: + std::shared_ptr server_; +}; +} // namespace anbox +} // namespace network + +#endif diff --git a/android/service/server.cpp b/android/service/server.cpp new file mode 100644 index 0000000..4e93ad4 --- /dev/null +++ b/android/service/server.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "android/service/server.h" + +#include "anbox_bridge.pb.h" + +namespace anbox { +namespace android { +Server::Server() { +} + +Server::~Server() { +} + +void Server::install_application(anbox::protobuf::bridge::InstallApplication const *request, + anbox::protobuf::bridge::Void *response, + google::protobuf::Closure *done) { + (void) request; + (void) response; + + done->Run(); +} + +void Server::launch_application(anbox::protobuf::bridge::LaunchApplication const *request, + anbox::protobuf::bridge::Void *response, + google::protobuf::Closure *done) { + (void) request; + (void) response; + + done->Run(); +} + +} // namespace anbox +} // namespace network diff --git a/android/service/server.h b/android/service/server.h new file mode 100644 index 0000000..69e868c --- /dev/null +++ b/android/service/server.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_ANDROID_SERVER_H_ +#define ANBOX_ANDROID_SERVER_H_ + +namespace google { +namespace protobuf { +class Closure; +} // namespace protobuf +} // namespace google + +namespace anbox { +namespace protobuf { +namespace bridge { +class InstallApplication; +class LaunchApplication; +class Void; +} // namespace bridge +} // namespace protobuf +namespace android { +class Server { +public: + Server(); + ~Server(); + + void install_application(anbox::protobuf::bridge::InstallApplication const *request, + anbox::protobuf::bridge::Void *response, + google::protobuf::Closure *done); + + void launch_application(anbox::protobuf::bridge::LaunchApplication const *request, + anbox::protobuf::bridge::Void *response, + google::protobuf::Closure *done); +}; +} // namespace android +} // namespace anbox + +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3633eeb..77d10f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,20 @@ include_directories( ${CMAKE_SOURCE_DIR}/external/android-emugl/host/include ) +set(PROTOBUF_SOURCES + anbox/protobuf/anbox_bridge.proto) + +protobuf_generate_cpp( + GENERATED_PROTOBUF_SRCS GENERATED_PROTOBUF_HDRS + ${PROTOBUF_SOURCES}) + +add_library(anbox-protobuf + ${GENERATED_PROTOBUF_SRCS} + ${GENERATED_PROTOBUF_HDRS} + anbox/protobuf/google_protobuf_guard.cpp) +target_link_libraries(anbox-protobuf + ${PROTOBUF_LITE_LIBRARIES}) + set(SOURCES anbox/logger.cpp anbox/utils.cpp @@ -56,6 +70,18 @@ set(SOURCES anbox/support/sensors_message_processor.cpp anbox/support/camera_message_processor.cpp anbox/support/fingerprint_message_processor.cpp + anbox/support/gsm_message_processor.cpp + anbox/support/at_parser.cpp + + anbox/bridge/constants.h + anbox/bridge/connection_creator.cpp + anbox/bridge/message_processor.cpp + anbox/bridge/template_message_processor.h + anbox/bridge/pending_call_cache.cpp + anbox/bridge/make_protobuf_object.h + anbox/bridge/platform_message_processor.cpp + anbox/bridge/platform_server.cpp + anbox/bridge/rpc_channel.cpp anbox/ubuntu/platform_server.cpp anbox/ubuntu/mir_display_connection.cpp @@ -82,7 +108,8 @@ target_link_libraries(anbox-core add_executable(anbox main.cpp) target_link_libraries(anbox - anbox-core) + anbox-core + anbox-protobuf) add_executable(anbox-container container_main.cpp) target_link_libraries(anbox-container diff --git a/src/anbox/bridge/connection_creator.cpp b/src/anbox/bridge/connection_creator.cpp new file mode 100644 index 0000000..70f1c48 --- /dev/null +++ b/src/anbox/bridge/connection_creator.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + + +#include "anbox/bridge/connection_creator.h" +#include "anbox/bridge/message_processor.h" +#include "anbox/network/socket_messenger.h" +#include "anbox/logger.h" + +#include + +namespace ba = boost::asio; + +namespace anbox { +namespace bridge { +ConnectionCreator::ConnectionCreator(const std::shared_ptr &rt, const MessageProcessorFactory &factory) : + runtime_(rt), + next_connection_id_(0), + connections_(std::make_shared>()), + message_processor_factory_(factory) { +} + +ConnectionCreator::~ConnectionCreator() { +} + +void ConnectionCreator::create_connection_for( + std::shared_ptr const& socket) { + + if (connections_->size() >= 1) { + socket->close(); + WARNING("A second client tried to connect. Denied request as we already have one" + "and only allow a single client"); + return; + } + + DEBUG(""); + + auto const messenger = std::make_shared(socket); + auto const processor = message_processor_factory_(messenger); + + auto const& connection = std::make_shared( + messenger, messenger, next_id(), connections_, processor); + connections_->add(connection); + connection->read_next_message(); +} + +int ConnectionCreator::next_id() +{ + return next_connection_id_.fetch_add(1); +} + +} // namespace anbox +} // namespace network diff --git a/src/anbox/bridge/connection_creator.h b/src/anbox/bridge/connection_creator.h new file mode 100644 index 0000000..892468b --- /dev/null +++ b/src/anbox/bridge/connection_creator.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_BRIDGE_CONNECTION_CREATOR_H_ +#define ANBOX_BRIDGE_CONNECTION_CREATOR_H_ + +#include + +#include + +#include "anbox/do_not_copy_or_move.h" +#include "anbox/runtime.h" +#include "anbox/network/connections.h" +#include "anbox/network/socket_connection.h" +#include "anbox/network/connection_creator.h" +#include "anbox/network/socket_messenger.h" + +namespace anbox { +namespace bridge { +class ConnectionCreator : public network::ConnectionCreator { +public: + typedef std::function(const std::shared_ptr&)> MessageProcessorFactory; + + ConnectionCreator( + const std::shared_ptr &rt, const MessageProcessorFactory &factory); + ~ConnectionCreator() noexcept; + + void create_connection_for( + std::shared_ptr const& socket) override; + +private: + int next_id(); + + std::shared_ptr runtime_; + std::atomic next_connection_id_; + std::shared_ptr> const connections_; + MessageProcessorFactory message_processor_factory_; +}; +} // namespace anbox +} // namespace network + +#endif diff --git a/src/anbox/bridge/constants.h b/src/anbox/bridge/constants.h new file mode 100644 index 0000000..a75d6e2 --- /dev/null +++ b/src/anbox/bridge/constants.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_BRIDGE_CONSTANTS_H_ +#define ANBOX_BRIDGE_CONSTANTS_H_ + +namespace anbox { +namespace bridge { +static constexpr const long header_size{3}; +static constexpr unsigned int const serialization_buffer_size{2048}; + +enum MessageType { + invocation = 0, + response = 1, +}; +} // namespace anbox +} // namespace network + +#endif diff --git a/src/anbox/bridge/make_protobuf_object.h b/src/anbox/bridge/make_protobuf_object.h new file mode 100644 index 0000000..50b98ef --- /dev/null +++ b/src/anbox/bridge/make_protobuf_object.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2015 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: Alberto Aguirre + */ + +#ifndef ANBOX_BRIDGE_MAKE_PROTOBUF_OBJECT_H_ +#define ANBOX_BRIDGE_MAKE_PROTOBUF_OBJECT_H_ + +#include + +namespace anbox { +namespace bridge { +template +auto make_protobuf_object() { + return std::unique_ptr{ProtobufType::default_instance().New()}; +} + +template +auto make_protobuf_object(ProtobufType const& from) { + auto object = make_protobuf_object(); + object->CopyFrom(from); + return object; +} +} // namespace bridge +} // namespace anbox + +#endif diff --git a/src/anbox/bridge/message_processor.cpp b/src/anbox/bridge/message_processor.cpp new file mode 100644 index 0000000..9872f9d --- /dev/null +++ b/src/anbox/bridge/message_processor.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "anbox/bridge/message_processor.h" +#include "anbox/bridge/template_message_processor.h" +#include "anbox/bridge/make_protobuf_object.h" +#include "anbox/bridge/constants.h" +#include "anbox/common/variable_length_array.h" + +#include "anbox_bridge.pb.h" + +namespace anbox { +namespace bridge { +const ::std::string& Invocation::method_name() const { + return invocation_.method_name(); +} + +const ::std::string& Invocation::parameters() const { + return invocation_.parameters(); +} + +google::protobuf::uint32 Invocation::id() const { + return invocation_.id(); +} + +MessageProcessor::MessageProcessor(const std::shared_ptr &sender, + const std::shared_ptr &pending_calls) : + sender_(sender), + pending_calls_(pending_calls) { +} + +MessageProcessor::~MessageProcessor() { +} + +bool MessageProcessor::process_data(const std::vector &data) { + for (const auto &byte : data) + buffer_.push_back(byte); + + unsigned char const high = buffer_[0]; + unsigned char const low = buffer_[1]; + size_t const message_size = (high << 8) + low; + unsigned char const message_type = buffer_[2]; + + // If we don't have yet all bytes for a new message return and wait + // until we have all. + if (buffer_.size() - header_size < message_size) + return true; + + buffer_.erase(buffer_.begin(), buffer_.begin() + header_size); + + if (message_type == MessageType::invocation) { + anbox::protobuf::bridge::Invocation raw_invocation; + raw_invocation.ParseFromArray(buffer_.data(), message_size); + + buffer_.erase(buffer_.begin(), buffer_.begin() + message_size); + + dispatch(Invocation(raw_invocation)); + } + else if (message_type == MessageType::response) { + auto result = make_protobuf_object(); + result->ParseFromArray(buffer_.data(), message_size); + + buffer_.erase(buffer_.begin(), buffer_.end() + message_size); + + for (int i = 0; i != result->events_size(); ++i) + process_event_sequence(result->events(i)); + + pending_calls_->complete_response(*result); + } + + return true; +} + +void MessageProcessor::send_response(::google::protobuf::uint32 id, google::protobuf::MessageLite *response) { + VariableLengthArray send_response_buffer( + static_cast(response->ByteSize())); + + response->SerializeWithCachedSizesToArray(send_response_buffer.data()); + + anbox::protobuf::bridge::Result send_response_result; + send_response_result.set_id(id); + send_response_result.set_response(send_response_buffer.data(), send_response_buffer.size()); + + send_response_buffer.resize(send_response_result.ByteSize()); + send_response_result.SerializeWithCachedSizesToArray(send_response_buffer.data()); + + const size_t size = send_response_buffer.size(); + const unsigned char header_bytes[header_size] = { + static_cast((size >> 8) & 0xff), + static_cast((size >> 0) & 0xff), + MessageType::response, + }; + + std::vector send_buffer(sizeof(header_bytes) + size); + std::copy(header_bytes, + header_bytes + sizeof(header_bytes), + send_buffer.begin()); + std::copy(send_response_buffer.data(), + send_response_buffer.data() + send_response_buffer.size(), + send_buffer.begin() + sizeof(header_bytes)); + + sender_->send(reinterpret_cast(send_buffer.data()), send_buffer.size()); +} +} // namespace anbox +} // namespace network diff --git a/src/anbox/bridge/message_processor.h b/src/anbox/bridge/message_processor.h new file mode 100644 index 0000000..c2c3c53 --- /dev/null +++ b/src/anbox/bridge/message_processor.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_BRIDGE_MESSAGE_PROCESSOR_H_ +#define ANBOX_BRIDGE_MESSAGE_PROCESSOR_H_ + +#include "anbox/network/message_processor.h" +#include "anbox/network/message_sender.h" +#include "anbox/bridge/pending_call_cache.h" + +#include + +#include +#include + +namespace anbox { +namespace protobuf { +namespace bridge { +class Invocation; +} // namespace bridge +} // namespace protobuf +namespace bridge { +class Invocation +{ +public: + Invocation(anbox::protobuf::bridge::Invocation const& invocation) : + invocation_(invocation) {} + + const ::std::string& method_name() const; + const ::std::string& parameters() const; + google::protobuf::uint32 id() const; +private: + anbox::protobuf::bridge::Invocation const& invocation_; +}; + +class MessageProcessor : public network::MessageProcessor { +public: + MessageProcessor(const std::shared_ptr &sender, + const std::shared_ptr &pending_calls); + ~MessageProcessor(); + + bool process_data(const std::vector &data) override; + + void send_response(::google::protobuf::uint32 id, google::protobuf::MessageLite *response); + + virtual void dispatch(Invocation const& invocation) = 0; + virtual void process_event_sequence(const std::string &event) = 0; + +private: + std::shared_ptr sender_; + std::vector buffer_; + std::shared_ptr pending_calls_; +}; +} // namespace bridge +} // namespace anbox + +#endif diff --git a/src/anbox/bridge/pending_call_cache.cpp b/src/anbox/bridge/pending_call_cache.cpp new file mode 100644 index 0000000..577b4aa --- /dev/null +++ b/src/anbox/bridge/pending_call_cache.cpp @@ -0,0 +1,72 @@ +/* + * 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: Alan Griffiths + */ + +#include "anbox/bridge/pending_call_cache.h" + +#include "anbox_bridge.pb.h" + +namespace anbox { +namespace bridge { +PendingCallCache::PendingCallCache() { +} + +void PendingCallCache::save_completion_details(anbox::protobuf::bridge::Invocation const &invocation, + google::protobuf::MessageLite *response, + google::protobuf::Closure *complete) { + std::unique_lock lock(mutex_); + pending_calls_[invocation.id()] = PendingCall(response, complete); +} + +void PendingCallCache::populate_message_for_result(anbox::protobuf::bridge::Result &result, + std::function const& populator) { + std::unique_lock lock(mutex_); + populator(pending_calls_.at(result.id()).response); +} + +void PendingCallCache::complete_response(anbox::protobuf::bridge::Result& result) { + PendingCall completion; + + { + std::unique_lock lock(mutex_); + auto call = pending_calls_.find(result.id()); + if (call != pending_calls_.end()) { + completion = call->second; + pending_calls_.erase(call); + } + } + + if (completion.complete) + completion.complete->Run(); +} + +void PendingCallCache::force_completion() { + std::unique_lock lock(mutex_); + for (auto& call : pending_calls_) { + auto& completion = call.second; + completion.complete->Run(); + } + + pending_calls_.erase(pending_calls_.begin(), pending_calls_.end()); +} + +bool PendingCallCache::empty() const { + std::unique_lock lock(mutex_); + return pending_calls_.empty(); +} +} // namespace bridge +} // namespace anbox diff --git a/src/anbox/bridge/pending_call_cache.h b/src/anbox/bridge/pending_call_cache.h new file mode 100644 index 0000000..4a1e30d --- /dev/null +++ b/src/anbox/bridge/pending_call_cache.h @@ -0,0 +1,77 @@ +/* + * 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: Alan Griffiths + */ + +#ifndef ANBOX_BRIDGE_PENDING_CALL_CACHE_ +#define ANBOX_BRIDGE_PENDING_CALL_CACHE_ + +#include +#include +#include + +namespace google { +namespace protobuf { +class Closure; +class MessageLite; +} // namespace protobuf +} // namespace google + +namespace anbox { +namespace protobuf { +namespace bridge { +class Invocation; +class Result; +} // namespace bridge +} // namespace protobuf +namespace bridge { +class PendingCallCache { +public: + PendingCallCache(); + + void save_completion_details(anbox::protobuf::bridge::Invocation const &invocation, + google::protobuf::MessageLite *response, + google::protobuf::Closure *complete); + void populate_message_for_result(anbox::protobuf::bridge::Result &result, + std::function const& populator); + void complete_response(anbox::protobuf::bridge::Result& result); + void force_completion(); + bool empty() const; + +private: + struct PendingCall { + PendingCall(google::protobuf::MessageLite *response, + google::protobuf::Closure *target) : + response(response), + complete(target) { + } + + PendingCall() : + response(0), + complete() { + } + + google::protobuf::MessageLite *response; + google::protobuf::Closure *complete; + }; + + std::mutex mutable mutex_; + std::map pending_calls_; +}; +} // namespace bridge +} // namespace anbox + +#endif diff --git a/src/anbox/bridge/platform_message_processor.cpp b/src/anbox/bridge/platform_message_processor.cpp new file mode 100644 index 0000000..8edac86 --- /dev/null +++ b/src/anbox/bridge/platform_message_processor.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "anbox/bridge/platform_message_processor.h" +#include "anbox/bridge/platform_server.h" +#include "anbox/bridge/template_message_processor.h" + +#include "anbox_bridge.pb.h" + +namespace anbox { +namespace bridge { +PlatformMessageProcessor::PlatformMessageProcessor(const std::shared_ptr &sender, + const std::shared_ptr &server, + const std::shared_ptr &pending_calls) : + MessageProcessor(sender, pending_calls), + server_(server) { +} + +PlatformMessageProcessor::~PlatformMessageProcessor() { +} + +void PlatformMessageProcessor::dispatch(Invocation const& invocation) { + if (invocation.method_name() == "handle_notification") { + invoke(this, server_.get(), &PlatformServer::handle_notification, invocation); + } +} + +void PlatformMessageProcessor::process_event_sequence(const std::string&) { +} +} // namespace anbox +} // namespace network diff --git a/src/anbox/bridge/platform_message_processor.h b/src/anbox/bridge/platform_message_processor.h new file mode 100644 index 0000000..34c5328 --- /dev/null +++ b/src/anbox/bridge/platform_message_processor.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_BRIDGE_PLATFORM_MESSAGE_PROCESSOR_H_ +#define ANBOX_BRIDGE_PLATFORM_MESSAGE_PROCESSOR_H_ + +#include "anbox/bridge/message_processor.h" + +namespace anbox { +namespace bridge { +class PlatformServer; +class PlatformMessageProcessor : public MessageProcessor { +public: + PlatformMessageProcessor(const std::shared_ptr &sender, + const std::shared_ptr &server, + const std::shared_ptr &pending_calls); + ~PlatformMessageProcessor(); + + void dispatch(Invocation const& invocation) override; + void process_event_sequence(const std::string &event) override; + +private: + std::shared_ptr server_; +}; +} // namespace anbox +} // namespace network + +#endif diff --git a/src/anbox/bridge/platform_server.cpp b/src/anbox/bridge/platform_server.cpp new file mode 100644 index 0000000..5476dc3 --- /dev/null +++ b/src/anbox/bridge/platform_server.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "anbox/bridge/platform_server.h" +#include "anbox/logger.h" + +#include "anbox_bridge.pb.h" + +namespace anbox { +namespace bridge { +PlatformServer::PlatformServer(const std::shared_ptr &pending_calls) : + pending_calls_(pending_calls) { +} + +PlatformServer::~PlatformServer() { +} +} // namespace bridge +} // namespace anbox diff --git a/src/anbox/bridge/platform_server.h b/src/anbox/bridge/platform_server.h new file mode 100644 index 0000000..9745e03 --- /dev/null +++ b/src/anbox/bridge/platform_server.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_BRIDGE_PLATFORM_SERVER_H_ +#define ANBOX_BRIDGE_PLATFORM_SERVER_H_ + +#include + +namespace google { +namespace protobuf { +class Closure; +} // namespace protobuf +} // namespace google + +namespace anbox { +namespace protobuf { +namespace bridge { +class Notification; +class Void; +} // namespace bridge +} // namespace protobuf +namespace bridge { +class PendingCallCache; +class PlatformServer { +public: + PlatformServer(const std::shared_ptr &pending_calls); + virtual ~PlatformServer(); + + virtual void handle_notification(anbox::protobuf::bridge::Notification const *request, + anbox::protobuf::bridge::Void *response, + google::protobuf::Closure *done) = 0; + +private: + std::shared_ptr pending_calls_; +}; +} // namespace bridge +} // namespace anbox + +#endif diff --git a/src/anbox/bridge/rpc_channel.cpp b/src/anbox/bridge/rpc_channel.cpp new file mode 100644 index 0000000..e951d5f --- /dev/null +++ b/src/anbox/bridge/rpc_channel.cpp @@ -0,0 +1,94 @@ +/* + * Copyright © 2012 Canonical Ltd. + * © 2016 Simon Fels + * + * 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: Alan Griffiths + */ + +#include "anbox/bridge/rpc_channel.h" +#include "anbox/bridge/pending_call_cache.h" +#include "anbox/bridge/constants.h" +#include "anbox/common/variable_length_array.h" +#include "anbox/network/message_sender.h" + +#include "anbox_bridge.pb.h" + +namespace anbox { +namespace bridge { +RpcChannel::RpcChannel(const std::shared_ptr &pending_calls, + const std::shared_ptr &sender) : + pending_calls_(pending_calls), + sender_(sender) { +} + +RpcChannel::~RpcChannel() { +} + +void RpcChannel::call_method(std::string const& method_name, + google::protobuf::MessageLite const *parameters, + google::protobuf::MessageLite *response, + google::protobuf::Closure *complete) { + auto const &invocation = invocation_for(method_name, parameters); + pending_calls_->save_completion_details(invocation, response, complete); + send_message(invocation); +} + +protobuf::bridge::Invocation RpcChannel::invocation_for(std::string const& method_name, + google::protobuf::MessageLite const* request) { + + anbox::VariableLengthArray<2048> buffer{static_cast(request->ByteSize())}; + + request->SerializeWithCachedSizesToArray(buffer.data()); + + anbox::protobuf::bridge::Invocation invoke; + + invoke.set_id(next_id()); + invoke.set_method_name(method_name); + invoke.set_parameters(buffer.data(), buffer.size()); + + return invoke; +} + +void RpcChannel::send_message(anbox::protobuf::bridge::Invocation const& invocation) { + const size_t size = invocation.ByteSize(); + const unsigned char header_bytes[header_size] = { + static_cast((size >> 8) & 0xff), + static_cast((size >> 0) & 0xff), + MessageType::invocation, + }; + + std::vector send_buffer(sizeof(header_bytes) + size); + std::copy(header_bytes, header_bytes + sizeof(header_bytes), send_buffer.begin()); + invocation.SerializeToArray(send_buffer.data() + sizeof(header_bytes), size); + + try { + std::lock_guard lock(write_mutex_); + sender_->send(reinterpret_cast(send_buffer.data()), send_buffer.size()); + } + catch (std::runtime_error const&) { + notify_disconnected(); + throw; + } +} + +void RpcChannel::notify_disconnected() { + pending_calls_->force_completion(); +} + +int RpcChannel::next_id() { + return next_message_id_.fetch_add(1); +} +} // namespace bridge +} // namespace anbox diff --git a/src/anbox/bridge/rpc_channel.h b/src/anbox/bridge/rpc_channel.h new file mode 100644 index 0000000..0db3ee9 --- /dev/null +++ b/src/anbox/bridge/rpc_channel.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_BRIDGE_RPC_CHANNEL_H_ +#define ANBOX_BRIDGE_RPC_CHANNEL_H_ + +#include +#include +#include + +namespace google { +namespace protobuf { +class Closure; +class MessageLite; +} // namespace protobuf +} // namespace google + + +namespace anbox { +namespace protobuf { +namespace bridge { +class Invocation; +} // namespace bridge +} // namespace protobuf +namespace network { +class MessageSender; +} // namespace network +namespace bridge { +class PendingCallCache; +class RpcChannel { +public: + RpcChannel(const std::shared_ptr &pending_calls, + const std::shared_ptr &sender); + ~RpcChannel(); + + void call_method(std::string const& method_name, + google::protobuf::MessageLite const *parameters, + google::protobuf::MessageLite *response, + google::protobuf::Closure *complete); + +private: + protobuf::bridge::Invocation invocation_for( + std::string const& method_name, + google::protobuf::MessageLite const* request); + void send_message(anbox::protobuf::bridge::Invocation const& invocation); + int next_id(); + void notify_disconnected(); + + std::atomic next_message_id_; + std::shared_ptr pending_calls_; + std::shared_ptr sender_; + std::mutex write_mutex_; +}; +} // namespace bridge +} // namespace anbox + +#endif diff --git a/src/anbox/bridge/template_message_processor.h b/src/anbox/bridge/template_message_processor.h new file mode 100644 index 0000000..fed6a04 --- /dev/null +++ b/src/anbox/bridge/template_message_processor.h @@ -0,0 +1,80 @@ +/* + * Copyright © 2014 Canonical Ltd. + * + * 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 warranty of + * MERCHANTABILITY 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 . + * + * Authored by: Alan Griffiths + */ + +#ifndef ANBOX_BRIDGE_TEMPLATE_MESSAGE_PROCESSOR_H_ +#define ANBOX_BRIDGE_TEMPLATE_MESSAGE_PROCESSOR_H_ + +#include + +#include "anbox/bridge/message_processor.h" + +#include "anbox_bridge.pb.h" + +namespace anbox { +namespace bridge { +// Utility metafunction result_ptr_t<> allows invoke() to pick the right +// send_response() overload. The base template resolves to the prototype +// "send_response(::google::protobuf::uint32 id, ::google::protobuf::Message* response)" +// Client code may specialize result_ptr_t to resolve to another overload. +template struct result_ptr_t +{ typedef ::google::protobuf::MessageLite* type; }; + +// Boiler plate for unpacking a parameter message, invoking a server function, and +// sending the result message. Assumes the existence of Self::send_response(). +template +void invoke( + Self* self, + Bridge* bridge, + void (BridgeX::*function)( + ParameterMessage const* request, + ResultMessage* response, + ::google::protobuf::Closure* done), + Invocation const& invocation) +{ + ParameterMessage parameter_message; + if (!parameter_message.ParseFromString(invocation.parameters())) + throw std::runtime_error("Failed to parse message parameters!"); + ResultMessage result_message; + + try + { + std::unique_ptr callback( + google::protobuf::NewPermanentCallback< + Self, + ::google::protobuf::uint32, + typename result_ptr_t::type>( + self, + &Self::send_response, + invocation.id(), + &result_message)); + + (bridge->*function)( + ¶meter_message, + &result_message, + callback.get()); + } + catch (std::exception const& x) + { + result_message.set_error(std::string("Error processing request: ") + x.what()); + self->send_response(invocation.id(), &result_message); + } +} +} // namespace bridge +} // namespace anbox + +#endif diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index 2448271..ba4b9ad 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -29,6 +29,9 @@ #include "anbox/network/qemu_pipe_connection_creator.h" #include "anbox/graphics/gl_renderer_server.h" #include "anbox/input/manager.h" +#include "anbox/bridge/connection_creator.h" +#include "anbox/bridge/platform_message_processor.h" +#include "anbox/bridge/rpc_channel.h" #include "anbox/ubuntu/platform_server.h" #include "anbox/ubuntu/window_creator.h" @@ -89,10 +92,22 @@ anbox::cmds::Run::Run() rt, std::make_shared(rt, renderer->socket_path())); + auto bridge_connector = std::make_shared( + utils::string_format("%s/anbox_bridge", config::data_path()), + rt, + std::make_shared(rt, + [](const std::shared_ptr &sender) { + auto pending_calls = std::make_shared(); + auto rpc_channel = std::make_shared(pending_calls, sender); + auto server = std::make_shared(pending_calls); + return std::make_shared(sender, server, pending_calls); + })); + auto spec = Container::Spec::Default(); spec.rootfs_path = rootfs_; spec.bind_paths.insert({qemud_connector->socket_file(), "/dev/qemud"}); spec.bind_paths.insert({qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"}); + spec.bind_paths.insert({bridge_connector->socket_file(), "/dev/anbox_bridge"}); input_manager->generate_mappings(spec.bind_paths); diff --git a/src/anbox/cmds/shell.h b/src/anbox/cmds/shell.h index daa9969..4a8d4f3 100644 --- a/src/anbox/cmds/shell.h +++ b/src/anbox/cmds/shell.h @@ -15,8 +15,8 @@ * */ -#ifndef ANBOX_CMDS_RUN_QEMU_H_ -#define ANBOX_CMDS_RUN_QEMU_H_ +#ifndef ANBOX_CMDS_SHELL_H_ +#define ANBOX_CMDS_SHELL_H_ #include #include diff --git a/src/anbox/network/socket_messenger.cpp b/src/anbox/network/socket_messenger.cpp index 22199ed..ea27921 100644 --- a/src/anbox/network/socket_messenger.cpp +++ b/src/anbox/network/socket_messenger.cpp @@ -51,7 +51,7 @@ void SocketMessenger::send(char const* data, size_t length) VariableLengthArray whole_message{length}; std::copy(data, data + length, whole_message.data()); - while (true) { + for (;;) { try { std::unique_lock lg(message_lock); ba::write(*socket, @@ -62,10 +62,6 @@ void SocketMessenger::send(char const* data, size_t length) if (err.code() == boost::asio::error::try_again) continue; } - catch (const std::exception &err) { - ERROR("Could not write message: %s", err.what()); - } - break; } } diff --git a/src/anbox/protobuf/anbox_bridge.proto b/src/anbox/protobuf/anbox_bridge.proto new file mode 100644 index 0000000..bc4898a --- /dev/null +++ b/src/anbox/protobuf/anbox_bridge.proto @@ -0,0 +1,43 @@ +option optimize_for = LITE_RUNTIME; + +package anbox.protobuf.bridge; + +message Invocation { + required uint32 id = 1; + required string method_name = 2; + required bytes parameters = 3; + required uint32 protocol_version = 4; +} + +message Result { + optional uint32 id = 1; + optional bytes response = 2; + repeated bytes events = 3; +} + +message StructuredError { + optional uint32 domain = 1; + optional uint32 code = 2; +} + +message Void { + optional string error = 127; + optional StructuredError structured_error = 128; +} + +message Notification { + required string package_name = 1; + required string category = 2; + required string title = 3; + optional string ticker_text = 4; + optional string text = 5; +} + +message InstallApplication { + required string path = 1; +} + +message LaunchApplication { + required string package_name = 1; + optional string activity = 2; +} diff --git a/src/anbox/protobuf/google_protobuf_guard.cpp b/src/anbox/protobuf/google_protobuf_guard.cpp new file mode 100644 index 0000000..e450da9 --- /dev/null +++ b/src/anbox/protobuf/google_protobuf_guard.cpp @@ -0,0 +1,40 @@ +/* + * 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: Alan Griffiths + */ + +#include + +extern "C" int __attribute__((constructor)) +init_google_protobuf() +{ + GOOGLE_PROTOBUF_VERIFY_VERSION; + return 0; +} + +extern "C" int __attribute__((destructor)) +shutdown_google_protobuf() +{ + google::protobuf::ShutdownProtobufLibrary(); + return 0; +} + +// Preserve ABI +namespace anbox { namespace protobuf { void google_protobuf_guard(); }} + +void anbox::protobuf::google_protobuf_guard() +{ +} diff --git a/src/anbox/ubuntu/platform_server.cpp b/src/anbox/ubuntu/platform_server.cpp new file mode 100644 index 0000000..0f8b317 --- /dev/null +++ b/src/anbox/ubuntu/platform_server.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#include "anbox/ubuntu/platform_server.h" +#include "anbox/logger.h" + +#include "bridge.pb.h" + +namespace anbox { +namespace ubuntu { +PlatformServer::PlatformServer(const std::shared_ptr &pending_calls) : + bridge::PlatformServer(pending_calls) { +} + +PlatformServer::~PlatformServer() { +} + +void PlatformServer::handle_notification(anbox::protobuf::bridge::Notification const *request, + anbox::protobuf::bridge::Void *response, + google::protobuf::Closure *done) { + (void) request; + (void) response; + DEBUG(""); + done->Run(); +} + +} // namespace ubuntu +} // namespace anbox diff --git a/src/anbox/ubuntu/platform_server.h b/src/anbox/ubuntu/platform_server.h new file mode 100644 index 0000000..e9f6001 --- /dev/null +++ b/src/anbox/ubuntu/platform_server.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2016 Simon Fels + * + * 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 . + * + */ + +#ifndef ANBOX_UBUNTU_PLATFORM_SERVER_H_ +#define ANBOX_UBUNTU_PLATFORM_SERVER_H_ + +#include "anbox/bridge/platform_server.h" + +namespace anbox { +namespace ubuntu { +class PlatformServer : public bridge::PlatformServer { +public: + PlatformServer(const std::shared_ptr &pending_calls); + virtual ~PlatformServer(); + + void handle_notification(anbox::protobuf::bridge::Notification const *request, + anbox::protobuf::bridge::Void *response, + google::protobuf::Closure *done) override; +}; +} // namespace bridge +} // namespace anbox + +#endif