From f75a9f4f1ce517c5ccb200253ed1b19576ba9f2a Mon Sep 17 00:00:00 2001 From: Simon Fels Date: Wed, 22 Jun 2016 19:05:57 +0200 Subject: [PATCH] Implement input event forwarding --- src/CMakeLists.txt | 4 + src/anbox/cmds/run.cpp | 18 +- src/anbox/graphics/gl_renderer_server.cpp | 4 +- src/anbox/graphics/gl_renderer_server.h | 6 +- .../graphics/mir_native_window_creator.cpp | 11 +- .../graphics/mir_native_window_creator.h | 9 +- src/anbox/graphics/mir_window.cpp | 114 +++++++++++- src/anbox/graphics/mir_window.h | 10 +- .../graphics/opengles_message_processor.cpp | 1 + src/anbox/input/device.cpp | 173 ++++++++++++++++++ src/anbox/input/device.h | 99 ++++++++++ src/anbox/input/manager.cpp | 61 ++++++ src/anbox/input/manager.h | 47 +++++ src/anbox/network/connections.h | 11 +- .../network/delegate_connection_creator.h | 47 +++++ .../network/qemu_pipe_connection_creator.cpp | 3 +- src/anbox/network/socket_connection.cpp | 6 + src/anbox/network/socket_connection.h | 4 + 18 files changed, 590 insertions(+), 38 deletions(-) create mode 100644 src/anbox/input/device.cpp create mode 100644 src/anbox/input/device.h create mode 100644 src/anbox/input/manager.cpp create mode 100644 src/anbox/input/manager.h create mode 100644 src/anbox/network/delegate_connection_creator.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f335159a..65ad03fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -40,6 +40,7 @@ set(SOURCES anbox/network/socket_connection.cpp anbox/network/socket_messenger.cpp anbox/network/delegate_message_processor.h + anbox/network/delegate_connection_creator.h anbox/graphics/opengles_message_processor.cpp anbox/graphics/mir_display_connection.cpp @@ -47,6 +48,9 @@ set(SOURCES anbox/graphics/mir_native_window_creator.cpp anbox/graphics/gl_renderer_server.cpp + anbox/input/manager.cpp + anbox/input/device.cpp + anbox/support/null_message_processor.cpp anbox/support/qemud_message_processor.cpp anbox/support/boot_properties_message_processor.cpp diff --git a/src/anbox/cmds/run.cpp b/src/anbox/cmds/run.cpp index e239f3bb..61110213 100644 --- a/src/anbox/cmds/run.cpp +++ b/src/anbox/cmds/run.cpp @@ -28,7 +28,7 @@ #include "anbox/network/published_socket_connector.h" #include "anbox/network/qemu_pipe_connection_creator.h" #include "anbox/graphics/gl_renderer_server.h" -#include "anbox/input_channel.h" +#include "anbox/input/manager.h" #include @@ -67,9 +67,9 @@ anbox::cmds::Run::Run() auto rt = Runtime::create(); - auto input_channel = std::make_shared(); + auto input_manager = std::make_shared(rt); - auto renderer = std::make_shared(input_channel); + auto renderer = std::make_shared(input_manager); renderer->start(); // Socket which will be used by the qemud service inside the Android @@ -91,6 +91,8 @@ anbox::cmds::Run::Run() spec.bind_paths.insert({qemud_connector->socket_file(), "/dev/qemud"}); spec.bind_paths.insert({qemu_pipe_connector->socket_file(), "/dev/qemu_pipe"}); + input_manager->generate_mappings(spec.bind_paths); + spec.temporary_dirs.push_back("/data"); spec.temporary_dirs.push_back("/cache"); spec.temporary_dirs.push_back("/storage"); @@ -102,16 +104,6 @@ anbox::cmds::Run::Run() // Required for shared memory allocations. TODO(morphis): Letting the guest // access should be ok but needs more investigation. spec.dev_bind_paths.push_back("/dev/ashmem"); - // Our uinput based event node should get root:android_input assigned on Ubuntu - // which is enough for our phablet user (being root inside the container) to - // read event data from it. - // FIXME(morphis): Need to reenable this once we have both sides prepared - // for an socket based approach. - // spec.dev_bind_paths.push_back({input_channel->dev_path()}); - // Until then we forward just the host input device which needs to have - // proper permissions (insecure!!!) for this. - // $ sudo chmod 666 /dev/input/event7 - spec.dev_bind_paths.push_back({"/dev/input/event7"}); auto container = Container::create(spec); diff --git a/src/anbox/graphics/gl_renderer_server.cpp b/src/anbox/graphics/gl_renderer_server.cpp index f5cfc391..af4a4f8e 100644 --- a/src/anbox/graphics/gl_renderer_server.cpp +++ b/src/anbox/graphics/gl_renderer_server.cpp @@ -28,8 +28,8 @@ namespace anbox { namespace graphics { -GLRendererServer::GLRendererServer(const std::shared_ptr &input_channel) : - window_creator_(std::make_shared(input_channel)) { +GLRendererServer::GLRendererServer(const std::shared_ptr &input_manager) : + window_creator_(std::make_shared(input_manager)) { // Force the host EGL/GLES libraries as translator implementation ::setenv("ANDROID_EGL_LIB", "libEGL.so.1", 1); diff --git a/src/anbox/graphics/gl_renderer_server.h b/src/anbox/graphics/gl_renderer_server.h index 795f98ab..afc3cf29 100644 --- a/src/anbox/graphics/gl_renderer_server.h +++ b/src/anbox/graphics/gl_renderer_server.h @@ -22,13 +22,15 @@ #include namespace anbox { -class InputChannel; +namespace input { +class Manager; +} namespace graphics { class MirNativeWindowCreator; class GLRendererServer { public: - GLRendererServer(const std::shared_ptr &input_channel); + GLRendererServer(const std::shared_ptr &input_manager); ~GLRendererServer(); void start(); diff --git a/src/anbox/graphics/mir_native_window_creator.cpp b/src/anbox/graphics/mir_native_window_creator.cpp index 43197cc8..a8577304 100644 --- a/src/anbox/graphics/mir_native_window_creator.cpp +++ b/src/anbox/graphics/mir_native_window_creator.cpp @@ -18,18 +18,15 @@ #include "anbox/graphics/mir_native_window_creator.h" #include "anbox/graphics/mir_display_connection.h" #include "anbox/graphics/mir_window.h" -#include "anbox/input_channel.h" +#include "anbox/input/manager.h" #include namespace anbox { namespace graphics { -MirNativeWindowCreator::MirNativeWindowCreator(const std::shared_ptr &input_channel) : - input_channel_(input_channel), +MirNativeWindowCreator::MirNativeWindowCreator(const std::shared_ptr &input_manager) : + input_manager_(input_manager), display_connection_(std::make_shared()) { - - input_channel_->setup(display_connection_->horizontal_resolution(), - display_connection_->vertical_resolution()); } MirNativeWindowCreator::~MirNativeWindowCreator() { @@ -44,7 +41,7 @@ EGLNativeWindowType MirNativeWindowCreator::create_window(int x, int y, int widt if (windows_.size() > 0) BOOST_THROW_EXCEPTION(std::runtime_error("We currently only allow a single native window")); - auto window = std::make_shared(display_connection_, input_channel_); + auto window = std::make_shared(display_connection_, input_manager_); windows_.insert({window->native_window(), window}); return window->native_window(); diff --git a/src/anbox/graphics/mir_native_window_creator.h b/src/anbox/graphics/mir_native_window_creator.h index 47e9bdfa..2c7f3ebf 100644 --- a/src/anbox/graphics/mir_native_window_creator.h +++ b/src/anbox/graphics/mir_native_window_creator.h @@ -24,8 +24,9 @@ #include namespace anbox { -class InputChannel; - +namespace input { +class Manager; +} namespace graphics { class MirDisplayConnection; @@ -33,7 +34,7 @@ class MirWindow; class MirNativeWindowCreator : public SubWindowHandler { public: - MirNativeWindowCreator(const std::shared_ptr &input_channel); + MirNativeWindowCreator(const std::shared_ptr &input_channel); virtual ~MirNativeWindowCreator(); EGLNativeWindowType create_window(int x, int y, int width, int height) override; @@ -42,7 +43,7 @@ public: std::shared_ptr display() const; private: - std::shared_ptr input_channel_; + std::shared_ptr input_manager_; std::shared_ptr display_connection_; std::map> windows_; }; diff --git a/src/anbox/graphics/mir_window.cpp b/src/anbox/graphics/mir_window.cpp index 7ed3719a..8d50183c 100644 --- a/src/anbox/graphics/mir_window.cpp +++ b/src/anbox/graphics/mir_window.cpp @@ -18,12 +18,12 @@ #include "anbox/graphics/mir_window.h" #include "anbox/graphics/mir_display_connection.h" #include "anbox/logger.h" -#include "anbox/input_channel.h" +#include "anbox/input/manager.h" +#include "anbox/input/device.h" namespace anbox { namespace graphics { -MirWindow::MirWindow(const std::shared_ptr &display, const std::shared_ptr &input_channel) : - input_channel_(input_channel), +MirWindow::MirWindow(const std::shared_ptr &display, const std::shared_ptr &input_manager) : native_window_(0), surface_(nullptr) { @@ -60,13 +60,119 @@ MirWindow::MirWindow(const std::shared_ptr &display, const auto surface_buffer_stream = mir_surface_get_buffer_stream(surface_); native_window_ = reinterpret_cast( mir_buffer_stream_get_egl_native_window(surface_buffer_stream)); + + // Create our touch panel input device + input_device_ = input_manager->create_device(); + input_device_->set_name("mir-touchpanel"); + input_device_->set_driver_version(1); + input_device_->set_input_id({ BUS_VIRTUAL, 1, 1, 1 }); + input_device_->set_physical_location("none"); + input_device_->set_abs_bit(ABS_MT_TRACKING_ID); + input_device_->set_abs_bit(ABS_MT_SLOT); + input_device_->set_abs_bit(ABS_MT_POSITION_X); + input_device_->set_abs_bit(ABS_MT_POSITION_Y); + input_device_->set_prop_bit(INPUT_PROP_DIRECT); + input_device_->set_abs_min(ABS_MT_POSITION_X, 0); + input_device_->set_abs_max(ABS_MT_POSITION_X, display->horizontal_resolution()); + input_device_->set_abs_min(ABS_MT_POSITION_Y, 0); + input_device_->set_abs_max(ABS_MT_POSITION_Y, display->vertical_resolution()); + input_device_->set_abs_max(ABS_MT_SLOT, 10); + input_device_->set_abs_max(ABS_MT_TRACKING_ID, 255); + input_device_->set_key_bit(BTN_TOUCH); + input_device_->set_key_bit(BTN_TOOL_FINGER); } MirWindow::~MirWindow() { } +static std::vector slot_to_fingerId; + +int find_slot(int id) +{ + auto iter = std::find(slot_to_fingerId.begin(), slot_to_fingerId.end(), id); + if (iter != slot_to_fingerId.end()) + return std::distance(slot_to_fingerId.begin(), iter); + + std::vector::size_type i; + for(i = 0;i < slot_to_fingerId.size();i++) { + if (slot_to_fingerId[i] == -1) { + slot_to_fingerId[i] = id; + return i; + } + } + + slot_to_fingerId.resize(slot_to_fingerId.size()+1); + slot_to_fingerId[slot_to_fingerId.size()-1] = id; + + return slot_to_fingerId.size() - 1; +} + +void erase_slot(int id) +{ + auto it = find(slot_to_fingerId.begin(), slot_to_fingerId.end(), id); + + if (it != slot_to_fingerId.end()) { + auto index = std::distance(slot_to_fingerId.begin(), it); + slot_to_fingerId[index] = -1; + if (index == slot_to_fingerId.size()-1) { + while (slot_to_fingerId[index] == -1) { + slot_to_fingerId.resize(index); + index--; + } + } + } +} + void MirWindow::handle_touch_event(MirTouchEvent const* touch_event) { - const auto action = mir_touch_event_action(touch_event, 0); + const auto point_count = mir_touch_event_point_count(touch_event); + + for (int n = 0; n < point_count; n++) { + const auto id = mir_touch_event_id(touch_event, n); + const auto slot = find_slot(id); + const auto x = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_x); + const auto y = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_y); + const auto pressure = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_pressure); + const auto touch_major = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_touch_major); + const auto touch_minor = mir_touch_event_axis_value(touch_event, n, mir_touch_axis_touch_minor); + + DEBUG("Event: id %d, slot %d, x %f, y %f, pressure %f", + id, slot, x, y, pressure); + + std::vector events; + + switch (mir_touch_event_action(touch_event, n)) { + case mir_touch_action_up: + events.push_back({ EV_ABS, ABS_MT_SLOT, slot }); + events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, -1 }); + events.push_back({ EV_KEY, BTN_TOUCH, 0 }); + events.push_back({ EV_KEY, BTN_TOOL_FINGER, 0 }); + events.push_back({ EV_SYN, SYN_REPORT, 0 }); + erase_slot(id); + break; + case mir_touch_action_down: + events.push_back({ EV_ABS, ABS_MT_SLOT, slot }); + events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, id }); + events.push_back({ EV_ABS, ABS_MT_POSITION_X, static_cast(x) }); + events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast(y) }); + events.push_back({ EV_ABS, ABS_MT_TOUCH_MAJOR, static_cast(touch_major) }); + events.push_back({ EV_ABS, ABS_MT_TOUCH_MINOR, static_cast(touch_minor) }); + events.push_back({ EV_SYN, SYN_REPORT, 0 }); + break; + case mir_touch_action_change: + events.push_back({ EV_ABS, ABS_MT_SLOT, slot }); + events.push_back({ EV_ABS, ABS_MT_TRACKING_ID, id }); + events.push_back({ EV_KEY, BTN_TOUCH, 1 }); + events.push_back({ EV_KEY, BTN_TOOL_FINGER, 1 }); + events.push_back({ EV_ABS, ABS_MT_POSITION_X, static_cast(x) }); + events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast(y) }); + events.push_back({ EV_ABS, ABS_MT_TOUCH_MAJOR, static_cast(touch_major) }); + events.push_back({ EV_ABS, ABS_MT_TOUCH_MINOR, static_cast(touch_minor) }); + events.push_back({ EV_SYN, SYN_REPORT, 0 }); + break; + } + + input_device_->send_events(events); + } } void MirWindow::handle_input_event(MirInputEvent const* input_event) { diff --git a/src/anbox/graphics/mir_window.h b/src/anbox/graphics/mir_window.h index 45665f6a..da6c6141 100644 --- a/src/anbox/graphics/mir_window.h +++ b/src/anbox/graphics/mir_window.h @@ -27,14 +27,16 @@ #include namespace anbox { -class InputChannel; - +namespace input { +class Manager; +class Device; +} namespace graphics { class MirDisplayConnection; class MirWindow { public: - MirWindow(const std::shared_ptr &display, const std::shared_ptr &input_channel); + MirWindow(const std::shared_ptr &display, const std::shared_ptr &input_manager); ~MirWindow(); EGLNativeWindowType native_window() const; @@ -45,7 +47,7 @@ private: void handle_input_event(MirInputEvent const* input_event); void handle_touch_event(MirTouchEvent const* touch_event); - std::shared_ptr input_channel_; + std::shared_ptr input_device_; EGLNativeWindowType native_window_; MirSurface *surface_; }; diff --git a/src/anbox/graphics/opengles_message_processor.cpp b/src/anbox/graphics/opengles_message_processor.cpp index 37d81bcb..e15c35f9 100644 --- a/src/anbox/graphics/opengles_message_processor.cpp +++ b/src/anbox/graphics/opengles_message_processor.cpp @@ -43,6 +43,7 @@ void OpenGlesMessageProcessor::connect_and_attach(const std::string &socket_path messenger_ = std::make_shared(socket); renderer_ = std::make_shared( + messenger_, messenger_, 0, std::make_shared>(), diff --git a/src/anbox/input/device.cpp b/src/anbox/input/device.cpp new file mode 100644 index 00000000..0dce8c58 --- /dev/null +++ b/src/anbox/input/device.cpp @@ -0,0 +1,173 @@ +/* + * 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/input/device.h" +#include "anbox/network/delegate_connection_creator.h" +#include "anbox/network/delegate_message_processor.h" +#include "anbox/network/socket_messenger.h" +#include "anbox/support/null_message_processor.h" +#include "anbox/logger.h" + +#include + +namespace anbox { +namespace input { +std::shared_ptr Device::create(const std::string &path, const std::shared_ptr &runtime) { + auto sp = std::make_shared(); + + auto delegate_connector = std::make_shared( + [sp](std::shared_ptr const &socket) { + sp->new_client(socket); + }); + + sp->connector_ = std::make_shared(path, runtime, delegate_connector); + + return sp; +} + +Device::Device() : + next_connection_id_(0), + connections_(std::make_shared>()) { + ::memset(&info_, 0, sizeof(info_)); +} + +Device::~Device() { +} + +void Device::send_events(const std::vector &events) { + struct CompatEvent { + // NOTE: A bit dirty but as we're running currently a 64 bit container + // struct input_event has a different size. We rebuild the struct here + // to reach the correct size. + std::uint64_t sec; + std::uint64_t usec; + std::uint16_t type; + std::uint16_t code; + std::uint32_t value; + }; + + struct timespec spec; + clock_gettime(CLOCK_MONOTONIC, &spec); + + auto data = new CompatEvent[events.size()]; + int n = 0; + for (const auto &event : events) { + data[n].sec = spec.tv_sec; + data[n].usec = spec.tv_nsec / 1000; + data[n].type = event.type; + data[n].code = event.code; + data[n].value = event.value; + + DEBUG("Event: time %lld, type %d, code %d, value %d", + data[n].sec * 1000000000LL + data[n].usec * 1000LL, + event.type, event.code, event.value); + + n++; + } + + for (auto n = 0; n < connections_->size(); n++) { + connections_->at(n)->send(reinterpret_cast(data), + events.size() * sizeof(struct CompatEvent)); + } +} + +void Device::set_name(const std::string &name) { + snprintf(info_.name, 80, "%s", name.c_str()); +} + +void Device::set_driver_version(const int &version) { + info_.driver_version = version; +} + +void Device::set_input_id(const struct input_id &id) { + info_.id.bustype = id.bustype; + info_.id.product = id.product; + info_.id.vendor = id.vendor; + info_.id.version = id.version; +} + +void Device::set_physical_location(const std::string &physical_location) { + snprintf(info_.physical_location, 80, "%s", physical_location.c_str()); +} + +void Device::set_key_bit(const std::uint8_t &bit) { + set_bit(info_.key_bitmask, bit); +} + +void Device::set_abs_bit(const std::uint8_t &bit) { + set_bit(info_.abs_bitmask, bit); +} + +void Device::set_rel_bit(const std::uint8_t &bit) { + set_bit(info_.rel_bitmask, bit); +} + +void Device::set_sw_bit(const std::uint8_t &bit) { + set_bit(info_.sw_bitmask, bit); +} + +void Device::set_led_bit(const std::uint8_t &bit) { + set_bit(info_.led_bitmask, bit); +} + +void Device::set_ff_bit(const std::uint8_t &bit) { + set_bit(info_.ff_bitmask, bit); +} + +void Device::set_prop_bit(const std::uint8_t &bit) { + set_bit(info_.prop_bitmask, bit); +} + +void Device::set_abs_min(const std::uint8_t &bit, const std::uint32_t &value) { + info_.abs_min[bit] = value; +} + +void Device::set_abs_max(const std::uint8_t &bit, const std::uint32_t &value) { + info_.abs_max[bit] = value; +} + +void Device::set_bit(std::uint8_t *array, const std::uint8_t &bit) { + array[bit/8] |= (1 << (bit % 8)); +} + +void Device::set_unique_id(const std::string &unique_id) { + snprintf(info_.unique_id, 80, "%s", unique_id.c_str()); +} + +std::string Device::socket_path() const { + return connector_->socket_file(); +} + +int Device::next_id() +{ + return next_connection_id_++; +} + +void Device::new_client(std::shared_ptr const &socket) { + auto const messenger = std::make_shared(socket); + auto const& connection = std::make_shared( + messenger, messenger, next_id(), connections_, + std::make_shared()); + + connections_->add(connection); + + // Send all necessary information about our device so that the remote + // side can properly configure itself for this input device + connection->send(reinterpret_cast(&info_), sizeof(info_)); +} +} // namespace input +} // namespace anbox diff --git a/src/anbox/input/device.h b/src/anbox/input/device.h new file mode 100644 index 00000000..2d4a7d8d --- /dev/null +++ b/src/anbox/input/device.h @@ -0,0 +1,99 @@ +/* + * 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_INPUT_DEVICE_H_ +#define ANBOX_INPUT_DEVICE_H_ + +#include "anbox/network/published_socket_connector.h" +#include "anbox/network/connections.h" +#include "anbox/network/socket_connection.h" +#include "anbox/runtime.h" + +#include + +#include + +namespace anbox { +namespace input { +class Device : public std::enable_shared_from_this { +public: + static std::shared_ptr create(const std::string &path, const std::shared_ptr &runtime); + + Device(); + ~Device(); + + struct Event { + std::uint16_t type; + std::uint16_t code; + std::int32_t value; + }; + + void send_events(const std::vector &events); + void send_event(const std::uint16_t &code, const std::uint16_t &event, const std::int32_t &value); + + void set_name(const std::string &name); + void set_driver_version(const int &version); + void set_input_id(const struct input_id &id); + void set_physical_location(const std::string &physical_location); + void set_unique_id(const std::string &unique_id); + void set_key_bit(const std::uint8_t &bit); + void set_abs_bit(const std::uint8_t &bit); + void set_rel_bit(const std::uint8_t &bit); + void set_sw_bit(const std::uint8_t &bit); + void set_led_bit(const std::uint8_t &bit); + void set_ff_bit(const std::uint8_t &bit); + void set_prop_bit(const std::uint8_t &bit); + + void set_abs_min(const std::uint8_t &bit, const std::uint32_t &value); + void set_abs_max(const std::uint8_t &bit, const std::uint32_t &value); + + std::string socket_path() const; + +private: + int next_id(); + void new_client(std::shared_ptr const &socket); + + // NOTE: If you modify this struct you have to modify the version on + // the Android side too. See frameworks/native/services/inputflinger/EventHub.cpp + struct Info { + char name[80]; + int driver_version; + struct input_id id; + char physical_location[80]; + char unique_id[80]; + std::uint8_t key_bitmask[(KEY_MAX + 1) / 8]; + std::uint8_t abs_bitmask[(ABS_MAX + 1) / 8]; + std::uint8_t rel_bitmask[(REL_MAX + 1) / 8]; + std::uint8_t sw_bitmask[(SW_MAX + 1) / 8]; + std::uint8_t led_bitmask[(LED_MAX + 1) / 8]; + std::uint8_t ff_bitmask[(FF_MAX + 1) / 8]; + std::uint8_t prop_bitmask[(INPUT_PROP_MAX + 1) / 8]; + std::uint32_t abs_max[ABS_CNT]; + std::uint32_t abs_min[ABS_CNT]; + }; + + void set_bit(std::uint8_t *array, const std::uint8_t &bit); + + std::shared_ptr connector_; + std::atomic next_connection_id_; + std::shared_ptr> const connections_; + Info info_; +}; +} // namespace input +} // namespace anbox + +#endif diff --git a/src/anbox/input/manager.cpp b/src/anbox/input/manager.cpp new file mode 100644 index 00000000..d4238f4e --- /dev/null +++ b/src/anbox/input/manager.cpp @@ -0,0 +1,61 @@ +/* + * 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/input/manager.h" +#include "anbox/input/device.h" +#include "anbox/runtime.h" +#include "anbox/config.h" + +#include + +namespace anbox { +namespace input { +Manager::Manager(const std::shared_ptr &runtime) : + runtime_(runtime) { +} + +Manager::~Manager() { +} + +std::shared_ptr Manager::create_device() { + const auto id = next_id(); + const auto path = build_device_path(id); + auto device = Device::create(path, runtime_); + devices_.insert({id, device}); + return device; +} + +void Manager::generate_mappings(std::map &target) { + for (const auto &iter : devices_) { + target.insert({ + iter.second->socket_path(), + (boost::format("/dev/input/event%1%") % iter.first).str(), + }); + } +} + +std::uint32_t Manager::next_id() { + static std::uint32_t next_id = 0; + return next_id++; +} + +std::string Manager::build_device_path(const std::uint32_t &id) { + return (boost::format("%1%/input_device_%2%") % config::data_path() % id).str(); +} + +} // namespace input +} // namespace anbox diff --git a/src/anbox/input/manager.h b/src/anbox/input/manager.h new file mode 100644 index 00000000..59203689 --- /dev/null +++ b/src/anbox/input/manager.h @@ -0,0 +1,47 @@ +/* + * 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_INPUT_MANAGER_H_ +#define ANBOX_INPUT_MANAGER_H_ + +#include +#include + +namespace anbox { +class Runtime; +namespace input { +class Device; +class Manager { +public: + Manager(const std::shared_ptr &runtime); + ~Manager(); + + std::shared_ptr create_device(); + + void generate_mappings(std::map &target); + +private: + std::uint32_t next_id(); + std::string build_device_path(const std::uint32_t &id); + + std::shared_ptr runtime_; + std::map> devices_; +}; +} // namespace input +} // namespace anbox + +#endif diff --git a/src/anbox/network/connections.h b/src/anbox/network/connections.h index a98d6582..dcc96188 100644 --- a/src/anbox/network/connections.h +++ b/src/anbox/network/connections.h @@ -35,7 +35,7 @@ public: void add(std::shared_ptr const& connection) { std::unique_lock lock(mutex); - connections[connection->id()] = connection; + connections.insert({connection->id(), connection}); } void remove(int id) @@ -56,6 +56,15 @@ public: connections.clear(); } + size_t size() + { + return connections.size(); + } + + std::shared_ptr at(size_t n) + { + return connections.at(n); + } private: Connections(Connections const&) = delete; diff --git a/src/anbox/network/delegate_connection_creator.h b/src/anbox/network/delegate_connection_creator.h new file mode 100644 index 00000000..b9a66ddb --- /dev/null +++ b/src/anbox/network/delegate_connection_creator.h @@ -0,0 +1,47 @@ +/* + * 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_NETWORK_DELEGATE_CONNECTION_CREATOR_H_ +#define ANBOX_NETWORK_DELEGATE_CONNECTION_CREATOR_H_ + +#include "anbox/network/connection_creator.h" +#include + +#include + +namespace anbox { +namespace network { +class DelegateConnectionCreator : public ConnectionCreator { +public: + DelegateConnectionCreator(std::function const&)> delegate) : + delegate_(delegate) { + } + + void create_connection_for( + std::shared_ptr const& socket) override { + if (delegate_) + delegate_(socket); + else + socket->close(); + } +private: + std::function const&)> delegate_; +}; +} // namespace network +} // namespace anbox + +#endif diff --git a/src/anbox/network/qemu_pipe_connection_creator.cpp b/src/anbox/network/qemu_pipe_connection_creator.cpp index b548c514..d6b95f78 100644 --- a/src/anbox/network/qemu_pipe_connection_creator.cpp +++ b/src/anbox/network/qemu_pipe_connection_creator.cpp @@ -52,7 +52,8 @@ void QemuPipeConnectionCreator::create_connection_for( if (!processor) BOOST_THROW_EXCEPTION(std::runtime_error("Unhandled client type")); - auto const& connection = std::make_shared(messenger, next_id(), connections_, processor); + auto const& connection = std::make_shared( + messenger, messenger, next_id(), connections_, processor); connections_->add(connection); connection->read_next_message(); diff --git a/src/anbox/network/socket_connection.cpp b/src/anbox/network/socket_connection.cpp index 80c37d50..b439e8c8 100644 --- a/src/anbox/network/socket_connection.cpp +++ b/src/anbox/network/socket_connection.cpp @@ -37,10 +37,12 @@ namespace anbox { namespace network { SocketConnection::SocketConnection( std::shared_ptr const& message_receiver, + std::shared_ptr const& message_sender, int id_, std::shared_ptr> const& connections, std::shared_ptr const& processor) : message_receiver_(message_receiver), + message_sender_(message_sender), id_(id_), connections_(connections), processor_(processor) @@ -51,6 +53,10 @@ SocketConnection::~SocketConnection() noexcept { } +void SocketConnection::send(char const* data, size_t length) { + message_sender_->send(data, length); +} + void SocketConnection::read_next_message() { auto callback = std::bind(&SocketConnection::on_read_size, diff --git a/src/anbox/network/socket_connection.h b/src/anbox/network/socket_connection.h index ad619b03..8a792433 100644 --- a/src/anbox/network/socket_connection.h +++ b/src/anbox/network/socket_connection.h @@ -21,6 +21,7 @@ #include "anbox/network/connections.h" #include "anbox/network/message_receiver.h" +#include "anbox/network/message_sender.h" #include "anbox/network/message_processor.h" #include @@ -34,6 +35,7 @@ class SocketConnection public: SocketConnection( std::shared_ptr const& message_receiver, + std::shared_ptr const& message_sender, int id, std::shared_ptr> const& connections, std::shared_ptr const& processor); @@ -42,6 +44,7 @@ public: int id() const { return id_; } + void send(char const* data, size_t length); void read_next_message(); private: @@ -49,6 +52,7 @@ private: void on_read_size(const boost::system::error_code& ec, std::size_t bytes_read); std::shared_ptr const message_receiver_; + std::shared_ptr const message_sender_; int const id_; std::shared_ptr> const connections_; std::shared_ptr const processor_; -- GitLab