blob: dc0c30997434a9a9e93a060b882e9b77eedb8e07 [file] [log] [blame]
Jorge E. Moreira4750e542020-01-07 14:35:35 -08001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Jorge E. Moreirae049b792019-12-18 18:17:48 -080017#include <source/TouchSink.h>
18
19#include <https/SafeCallbackable.h>
20#include <https/Support.h>
Jorge E. Moreira2a6ab082019-12-11 18:41:58 -080021
22#include <android-base/logging.h>
Jorge E. Moreirae049b792019-12-18 18:17:48 -080023
24#include <linux/input.h>
25#include <linux/uinput.h>
26
27#include <sys/socket.h>
Jorge E. Moreiraf45e3552019-12-04 17:52:04 -080028#include <unistd.h>
Jorge E. Moreirae049b792019-12-18 18:17:48 -080029
30namespace android {
31
32namespace {
33// TODO de-dup this from vnc server and here
34struct virtio_input_event {
35 uint16_t type;
36 uint16_t code;
37 int32_t value;
38};
39
40template <typename T>
41void SendEvent(int32_t x, int32_t y, int32_t down,
42 std::function<void(const void*, size_t)> sender) {
43 std::vector<T> events = {{.type = EV_ABS, .code = ABS_X, .value = x},
44 {.type = EV_ABS, .code = ABS_Y, .value = y},
45 {.type = EV_KEY, .code = BTN_TOUCH, .value = down},
46 {.type = EV_SYN, .code = 0, .value = 0}};
47 sender(events.data(), events.size() * sizeof(T));
48}
49
50template <typename T>
51void SendMTEvent(int32_t /* id */, int32_t x, int32_t y, int32_t initial_down,
52 int32_t /* slot */,
53 std::function<void(const void*, size_t)> sender) {
54 // TODO(b/124121375): multitouch
55 SendEvent<T>(x, y, initial_down, sender);
56}
57}
58
59TouchSink::TouchSink(std::shared_ptr<RunLoop> runLoop, int serverFd,
60 bool write_virtio_input)
61 : mRunLoop(runLoop),
62 mServerFd(serverFd),
63 mClientFd(-1),
64 mSendPending(false) {
65 if (mServerFd >= 0) {
66 makeFdNonblocking(mServerFd);
67 }
68 if (write_virtio_input) {
69 send_event_ = [this](int32_t x, int32_t y, bool down) {
70 SendEvent<virtio_input_event>(
71 x, y, down, [this](const void* b, size_t l) { sendRawEvents(b, l); });
72 };
73 send_mt_event_ = [this](int32_t id, int32_t x, int32_t y, bool initialDown,
74 int32_t slot) {
75 SendMTEvent<virtio_input_event>(
76 id, x, y, initialDown, slot,
77 [this](const void* b, size_t l) { sendRawEvents(b, l); });
78 };
79 } else {
80 send_event_ = [this](int32_t x, int32_t y, bool down) {
81 SendEvent<input_event>(
82 x, y, down, [this](const void* b, size_t l) { sendRawEvents(b, l); });
83 };
84 send_mt_event_ = [this](int32_t id, int32_t x, int32_t y, bool initialDown,
85 int32_t slot) {
86 SendMTEvent<input_event>(
87 id, x, y, initialDown, slot,
88 [this](const void* b, size_t l) { sendRawEvents(b, l); });
89 };
90 }
91}
92
93TouchSink::~TouchSink() {
94 if (mClientFd >= 0) {
95 mRunLoop->cancelSocket(mClientFd);
96
97 close(mClientFd);
98 mClientFd = -1;
99 }
100
101 if (mServerFd >= 0) {
102 mRunLoop->cancelSocket(mServerFd);
103
104 close(mServerFd);
105 mServerFd = -1;
106 }
107}
108
109void TouchSink::start() {
110 if (mServerFd < 0) {
111 return;
112 }
113
114 mRunLoop->postSocketRecv(
115 mServerFd,
116 makeSafeCallback(this, &TouchSink::onServerConnection));
117}
118
119void TouchSink::onServerConnection() {
120 int s = accept(mServerFd, nullptr, nullptr);
121
122 if (s >= 0) {
123 if (mClientFd >= 0) {
124 LOG(INFO) << "Rejecting client, we already have one.";
125
126 // We already have a client.
127 close(s);
128 s = -1;
129 } else {
130 LOG(INFO) << "Accepted client socket " << s << ".";
131
132 makeFdNonblocking(s);
133
134 mClientFd = s;
135 }
136 }
137
138 mRunLoop->postSocketRecv(
139 mServerFd,
140 makeSafeCallback(this, &TouchSink::onServerConnection));
141}
142
Jorge E. Moreirae049b792019-12-18 18:17:48 -0800143
Jorge E. Moreira2a6ab082019-12-11 18:41:58 -0800144void TouchSink::onAccessUnit(const std::shared_ptr<InputEvent> &accessUnit) {
145 bool down = accessUnit->down != 0;
146 int x = accessUnit->x;
147 int y = accessUnit->y;
Jorge E. Moreirae049b792019-12-18 18:17:48 -0800148
149 LOG(VERBOSE)
Jorge E. Moreira2a6ab082019-12-11 18:41:58 -0800150 << "Received touch (down="
151 << down
Jorge E. Moreirae049b792019-12-18 18:17:48 -0800152 << ", x="
153 << x
154 << ", y="
Jorge E. Moreira2a6ab082019-12-11 18:41:58 -0800155 << y;
Jorge E. Moreirae049b792019-12-18 18:17:48 -0800156
Jorge E. Moreira2a6ab082019-12-11 18:41:58 -0800157 send_event_(x, y, down);
Jorge E. Moreirae049b792019-12-18 18:17:48 -0800158}
159
160void TouchSink::sendRawEvents(const void* evt_buffer, size_t size) {
161 if (size <= 0) return;
162
163 std::lock_guard autoLock(mLock);
164
165 if (mClientFd < 0) {
166 return;
167 }
168
169 size_t offset = mOutBuffer.size();
170 mOutBuffer.resize(offset + size);
171 memcpy(mOutBuffer.data() + offset, evt_buffer, size);
172
173 if (!mSendPending) {
174 mSendPending = true;
175
176 mRunLoop->postSocketSend(
177 mClientFd,
178 makeSafeCallback(this, &TouchSink::onSocketSend));
179 }
180}
181
182void TouchSink::onSocketSend() {
183 std::lock_guard autoLock(mLock);
184
185 CHECK(mSendPending);
186 mSendPending = false;
187
188 if (mClientFd < 0) {
189 return;
190 }
191
192 ssize_t n;
193 while (!mOutBuffer.empty()) {
194 do {
195 n = ::send(mClientFd, mOutBuffer.data(), mOutBuffer.size(), 0);
196 } while (n < 0 && errno == EINTR);
197
198 if (n <= 0) {
199 break;
200 }
201
202 mOutBuffer.erase(mOutBuffer.begin(), mOutBuffer.begin() + n);
203 }
204
205 if ((n < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || n == 0) {
206 LOG(ERROR) << "Client is gone.";
207
208 // Client is gone.
209 mRunLoop->cancelSocket(mClientFd);
210
211 close(mClientFd);
212 mClientFd = -1;
213 return;
214 }
215
216 if (!mOutBuffer.empty()) {
217 mSendPending = true;
218 mRunLoop->postSocketSend(
219 mClientFd,
220 makeSafeCallback(this, &TouchSink::onSocketSend));
221 }
222}
223
224} // namespace android
225