提交 f75a9f4f 编写于 作者: S Simon Fels

Implement input event forwarding

上级 309fd302
......@@ -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
......
......@@ -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 <sys/prctl.h>
......@@ -67,9 +67,9 @@ anbox::cmds::Run::Run()
auto rt = Runtime::create();
auto input_channel = std::make_shared<InputChannel>();
auto input_manager = std::make_shared<input::Manager>(rt);
auto renderer = std::make_shared<graphics::GLRendererServer>(input_channel);
auto renderer = std::make_shared<graphics::GLRendererServer>(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);
......
......@@ -28,8 +28,8 @@
namespace anbox {
namespace graphics {
GLRendererServer::GLRendererServer(const std::shared_ptr<InputChannel> &input_channel) :
window_creator_(std::make_shared<MirNativeWindowCreator>(input_channel)) {
GLRendererServer::GLRendererServer(const std::shared_ptr<input::Manager> &input_manager) :
window_creator_(std::make_shared<MirNativeWindowCreator>(input_manager)) {
// Force the host EGL/GLES libraries as translator implementation
::setenv("ANDROID_EGL_LIB", "libEGL.so.1", 1);
......
......@@ -22,13 +22,15 @@
#include <memory>
namespace anbox {
class InputChannel;
namespace input {
class Manager;
}
namespace graphics {
class MirNativeWindowCreator;
class GLRendererServer {
public:
GLRendererServer(const std::shared_ptr<InputChannel> &input_channel);
GLRendererServer(const std::shared_ptr<input::Manager> &input_manager);
~GLRendererServer();
void start();
......
......@@ -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 <boost/throw_exception.hpp>
namespace anbox {
namespace graphics {
MirNativeWindowCreator::MirNativeWindowCreator(const std::shared_ptr<InputChannel> &input_channel) :
input_channel_(input_channel),
MirNativeWindowCreator::MirNativeWindowCreator(const std::shared_ptr<input::Manager> &input_manager) :
input_manager_(input_manager),
display_connection_(std::make_shared<MirDisplayConnection>()) {
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<MirWindow>(display_connection_, input_channel_);
auto window = std::make_shared<MirWindow>(display_connection_, input_manager_);
windows_.insert({window->native_window(), window});
return window->native_window();
......
......@@ -24,8 +24,9 @@
#include <map>
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<InputChannel> &input_channel);
MirNativeWindowCreator(const std::shared_ptr<input::Manager> &input_channel);
virtual ~MirNativeWindowCreator();
EGLNativeWindowType create_window(int x, int y, int width, int height) override;
......@@ -42,7 +43,7 @@ public:
std::shared_ptr<MirDisplayConnection> display() const;
private:
std::shared_ptr<InputChannel> input_channel_;
std::shared_ptr<input::Manager> input_manager_;
std::shared_ptr<MirDisplayConnection> display_connection_;
std::map<EGLNativeWindowType,std::shared_ptr<MirWindow>> windows_;
};
......
......@@ -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<MirDisplayConnection> &display, const std::shared_ptr<InputChannel> &input_channel) :
input_channel_(input_channel),
MirWindow::MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<input::Manager> &input_manager) :
native_window_(0),
surface_(nullptr) {
......@@ -60,13 +60,119 @@ MirWindow::MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const
auto surface_buffer_stream = mir_surface_get_buffer_stream(surface_);
native_window_ = reinterpret_cast<EGLNativeWindowType>(
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<int> 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<int>::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<input::Device::Event> 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<std::int32_t>(x) });
events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast<std::int32_t>(y) });
events.push_back({ EV_ABS, ABS_MT_TOUCH_MAJOR, static_cast<std::int32_t>(touch_major) });
events.push_back({ EV_ABS, ABS_MT_TOUCH_MINOR, static_cast<std::int32_t>(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<std::int32_t>(x) });
events.push_back({ EV_ABS, ABS_MT_POSITION_Y, static_cast<std::int32_t>(y) });
events.push_back({ EV_ABS, ABS_MT_TOUCH_MAJOR, static_cast<std::int32_t>(touch_major) });
events.push_back({ EV_ABS, ABS_MT_TOUCH_MINOR, static_cast<std::int32_t>(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) {
......
......@@ -27,14 +27,16 @@
#include <memory>
namespace anbox {
class InputChannel;
namespace input {
class Manager;
class Device;
}
namespace graphics {
class MirDisplayConnection;
class MirWindow {
public:
MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<InputChannel> &input_channel);
MirWindow(const std::shared_ptr<MirDisplayConnection> &display, const std::shared_ptr<input::Manager> &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<InputChannel> input_channel_;
std::shared_ptr<input::Device> input_device_;
EGLNativeWindowType native_window_;
MirSurface *surface_;
};
......
......@@ -43,6 +43,7 @@ void OpenGlesMessageProcessor::connect_and_attach(const std::string &socket_path
messenger_ = std::make_shared<network::SocketMessenger>(socket);
renderer_ = std::make_shared<network::SocketConnection>(
messenger_,
messenger_,
0,
std::make_shared<network::Connections<network::SocketConnection>>(),
......
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/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 <time.h>
namespace anbox {
namespace input {
std::shared_ptr<Device> Device::create(const std::string &path, const std::shared_ptr<Runtime> &runtime) {
auto sp = std::make_shared<Device>();
auto delegate_connector = std::make_shared<network::DelegateConnectionCreator>(
[sp](std::shared_ptr<boost::asio::local::stream_protocol::socket> const &socket) {
sp->new_client(socket);
});
sp->connector_ = std::make_shared<network::PublishedSocketConnector>(path, runtime, delegate_connector);
return sp;
}
Device::Device() :
next_connection_id_(0),
connections_(std::make_shared<network::Connections<network::SocketConnection>>()) {
::memset(&info_, 0, sizeof(info_));
}
Device::~Device() {
}
void Device::send_events(const std::vector<Event> &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<const char*>(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<boost::asio::local::stream_protocol::socket> const &socket) {
auto const messenger = std::make_shared<network::SocketMessenger>(socket);
auto const& connection = std::make_shared<network::SocketConnection>(
messenger, messenger, next_id(), connections_,
std::make_shared<support::NullMessageProcessor>());
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<char const*>(&info_), sizeof(info_));
}
} // namespace input
} // namespace anbox
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_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 <vector>
#include <linux/input.h>
namespace anbox {
namespace input {
class Device : public std::enable_shared_from_this<Device> {
public:
static std::shared_ptr<Device> create(const std::string &path, const std::shared_ptr<Runtime> &runtime);
Device();
~Device();
struct Event {
std::uint16_t type;
std::uint16_t code;
std::int32_t value;
};
void send_events(const std::vector<Event> &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<boost::asio::local::stream_protocol::socket> 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<network::PublishedSocketConnector> connector_;
std::atomic<int> next_connection_id_;
std::shared_ptr<network::Connections<network::SocketConnection>> const connections_;
Info info_;
};
} // namespace input
} // namespace anbox
#endif
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/input/manager.h"
#include "anbox/input/device.h"
#include "anbox/runtime.h"
#include "anbox/config.h"
#include <boost/format.hpp>
namespace anbox {
namespace input {
Manager::Manager(const std::shared_ptr<Runtime> &runtime) :
runtime_(runtime) {
}
Manager::~Manager() {
}
std::shared_ptr<Device> 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<std::string,std::string> &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
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_INPUT_MANAGER_H_
#define ANBOX_INPUT_MANAGER_H_
#include <memory>
#include <map>
namespace anbox {
class Runtime;
namespace input {
class Device;
class Manager {
public:
Manager(const std::shared_ptr<Runtime> &runtime);
~Manager();
std::shared_ptr<Device> create_device();
void generate_mappings(std::map<std::string,std::string> &target);
private:
std::uint32_t next_id();
std::string build_device_path(const std::uint32_t &id);
std::shared_ptr<Runtime> runtime_;
std::map<std::uint32_t,std::shared_ptr<Device>> devices_;
};
} // namespace input
} // namespace anbox
#endif
......@@ -35,7 +35,7 @@ public:
void add(std::shared_ptr<Connection> const& connection)
{
std::unique_lock<std::mutex> 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<Connection> at(size_t n)
{
return connections.at(n);
}
private:
Connections(Connections const&) = delete;
......
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_NETWORK_DELEGATE_CONNECTION_CREATOR_H_
#define ANBOX_NETWORK_DELEGATE_CONNECTION_CREATOR_H_
#include "anbox/network/connection_creator.h"
#include <boost/asio.hpp>
#include <functional>
namespace anbox {
namespace network {
class DelegateConnectionCreator : public ConnectionCreator {
public:
DelegateConnectionCreator(std::function<void(std::shared_ptr<boost::asio::local::stream_protocol::socket> const&)> delegate) :
delegate_(delegate) {
}
void create_connection_for(
std::shared_ptr<boost::asio::local::stream_protocol::socket> const& socket) override {
if (delegate_)
delegate_(socket);
else
socket->close();
}
private:
std::function<void(std::shared_ptr<boost::asio::local::stream_protocol::socket> const&)> delegate_;
};
} // namespace network
} // namespace anbox
#endif
......@@ -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<SocketConnection>(messenger, next_id(), connections_, processor);
auto const& connection = std::make_shared<SocketConnection>(
messenger, messenger, next_id(), connections_, processor);
connections_->add(connection);
connection->read_next_message();
......
......@@ -37,10 +37,12 @@ namespace anbox {
namespace network {
SocketConnection::SocketConnection(
std::shared_ptr<MessageReceiver> const& message_receiver,
std::shared_ptr<MessageSender> const& message_sender,
int id_,
std::shared_ptr<Connections<SocketConnection>> const& connections,
std::shared_ptr<MessageProcessor> 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,
......
......@@ -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 <boost/asio.hpp>
......@@ -34,6 +35,7 @@ class SocketConnection
public:
SocketConnection(
std::shared_ptr<MessageReceiver> const& message_receiver,
std::shared_ptr<MessageSender> const& message_sender,
int id,
std::shared_ptr<Connections<SocketConnection>> const& connections,
std::shared_ptr<MessageProcessor> 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<MessageReceiver> const message_receiver_;
std::shared_ptr<MessageSender> const message_sender_;
int const id_;
std::shared_ptr<Connections<SocketConnection>> const connections_;
std::shared_ptr<MessageProcessor> const processor_;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册