blob: a637c4707878498e933b361e216e0b7895984e77 [file] [log] [blame]
Steve Kondik95027ea2017-06-14 17:22:58 -07001//
2// vncflinger - Copyright (C) 2017 Steve Kondik
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16//
17
Steve Kondik55db0532017-06-12 11:27:18 -070018#define LOG_TAG "VNCFlinger"
19#include <utils/Log.h>
20
21#include <binder/IPCThreadState.h>
Steve Kondik55db0532017-06-12 11:27:18 -070022#include <binder/IServiceManager.h>
Steve Kondik2c9d0cf2017-06-15 23:39:29 -070023#include <binder/ProcessState.h>
Steve Kondik55db0532017-06-12 11:27:18 -070024
Steve Kondik2c9d0cf2017-06-15 23:39:29 -070025#include <gui/IGraphicBufferProducer.h>
Steve Kondik55db0532017-06-12 11:27:18 -070026#include <gui/ISurfaceComposer.h>
27#include <gui/SurfaceComposerClient.h>
Steve Kondik55db0532017-06-12 11:27:18 -070028
Steve Kondik107d2e52017-06-13 17:34:56 -070029#include "InputDevice.h"
Steve Kondik55db0532017-06-12 11:27:18 -070030#include "VNCFlinger.h"
31
32using namespace android;
33
Steve Kondik5c8655c2017-06-19 00:28:47 -070034VNCFlinger::VNCFlinger() {
35 mOrientation = -1;
36 mMainDpy = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
37 updateDisplayProjection();
38
39 createVNCServer();
40
41 String8 v4("127.0.0.1");
42 String8 v6("::1");
43
44 setListenAddress(v4, false);
45 setListenAddress(v6, true);
46}
47
48status_t VNCFlinger::setListenAddress(String8& address, bool v6) {
49 if (v6) {
50 mVNCScreen->listen6Interface = const_cast<char *>(address.string());
51 return NO_ERROR;
52 }
53 if (!rfbStringToAddr(const_cast<char *>(address.string()), &(mVNCScreen->listenInterface))) {
54 return BAD_VALUE;
55 }
56 return NO_ERROR;
57}
58
59status_t VNCFlinger::setPort(unsigned int port) {
60 if (port > 65535) {
61 port = 0;
62 }
63 if (port == 0) {
64 mVNCScreen->autoPort = 1;
65 } else {
66 mVNCScreen->autoPort = 0;
67 mVNCScreen->port = port;
68 mVNCScreen->ipv6port = port;
69 }
70 return NO_ERROR;
71}
72
73status_t VNCFlinger::clearPassword() {
74 std::remove(VNC_AUTH_FILE);
75 ALOGW("Password authentication disabled");
76 return OK;
77}
78
79status_t VNCFlinger::setPassword(String8& passwd) {
80 String8 path(VNC_AUTH_FILE);
81 if (rfbEncryptAndStorePasswd(const_cast<char *>(passwd.string()),
82 const_cast<char *>(path.string())) != 0) {
83 ALOGE("Failed to set password");
84 return BAD_VALUE;
85 }
86 ALOGI("Password has been set");
87 return OK;
88}
89
Steve Kondik55db0532017-06-12 11:27:18 -070090status_t VNCFlinger::start() {
Steve Kondik77754522017-06-14 17:00:33 -070091 sp<ProcessState> self = ProcessState::self();
92 self->startThreadPool();
Steve Kondik55db0532017-06-12 11:27:18 -070093
Steve Kondik5c8655c2017-06-19 00:28:47 -070094 status_t err = startVNCServer();
Steve Kondik55db0532017-06-12 11:27:18 -070095 if (err != NO_ERROR) {
96 ALOGE("Failed to start VNCFlinger: err=%d", err);
97 return err;
98 }
99
Steve Kondik55db0532017-06-12 11:27:18 -0700100 rfbRunEventLoop(mVNCScreen, -1, true);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700101
Steve Kondik46798992017-06-15 23:58:54 -0700102 ALOGD("VNCFlinger ready to fling");
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700103
Steve Kondik77754522017-06-14 17:00:33 -0700104 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -0700105
Steve Kondik46798992017-06-15 23:58:54 -0700106 ALOGI("VNCFlinger has left the building");
107
108 return NO_ERROR;
109}
110
111status_t VNCFlinger::stop() {
112 Mutex::Autolock _L(mEventMutex);
113
114 ALOGV("Shutting down");
115
Steve Kondik5c8655c2017-06-19 00:28:47 -0700116 rfbShutdownServer(mVNCScreen, true);
117
Steve Kondik46798992017-06-15 23:58:54 -0700118 destroyVirtualDisplayLocked();
119 mClientCount = 0;
120 mRunning = false;
121
122 mEventCond.signal();
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700123 delete[] mVNCScreen->frameBuffer;
Steve Kondik55db0532017-06-12 11:27:18 -0700124 return NO_ERROR;
125}
126
Steve Kondik77754522017-06-14 17:00:33 -0700127void VNCFlinger::eventLoop() {
128 mRunning = true;
129
130 Mutex::Autolock _l(mEventMutex);
131 while (mRunning) {
132 mEventCond.wait(mEventMutex);
133
134 // spurious wakeup? never.
135 if (mClientCount == 0) {
136 continue;
137 }
138
139 // this is a new client, so fire everything up
140 status_t err = createVirtualDisplay();
141 if (err != NO_ERROR) {
142 ALOGE("Failed to create virtual display: err=%d", err);
143 }
144
145 // loop while clients are connected and process frames
146 // on the main thread when signalled
147 while (mClientCount > 0) {
148 mEventCond.wait(mEventMutex);
149 if (mFrameAvailable) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700150 if (!updateDisplayProjection()) {
151 processFrame();
152 }
Steve Kondik77754522017-06-14 17:00:33 -0700153 mFrameAvailable = false;
154 }
155 }
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700156 Mutex::Autolock _l(mUpdateMutex);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700157 memset(mVNCScreen->frameBuffer, 0, mFrameSize);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700158 destroyVirtualDisplayLocked();
Steve Kondik77754522017-06-14 17:00:33 -0700159 }
160}
161
162status_t VNCFlinger::createVirtualDisplay() {
163 sp<IGraphicBufferConsumer> consumer;
164 BufferQueue::createBufferQueue(&mProducer, &consumer);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700165 mCpuConsumer = new CpuConsumer(consumer, NUM_BUFS);
Steve Kondik77754522017-06-14 17:00:33 -0700166 mCpuConsumer->setName(String8("vds-to-cpu"));
167 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
168 mProducer->setMaxDequeuedBufferCount(4);
169
170 mListener = new FrameListener(this);
171 mCpuConsumer->setFrameAvailableListener(mListener);
172
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700173 mDpy = SurfaceComposerClient::createDisplay(String8("VNC-VirtualDisplay"), false /*secure*/);
Steve Kondik77754522017-06-14 17:00:33 -0700174
175 SurfaceComposerClient::openGlobalTransaction();
176 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700177 // setDisplayProjection(mDpy, mainDpyInfo);
178 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
Steve Kondik77754522017-06-14 17:00:33 -0700179 SurfaceComposerClient::closeGlobalTransaction();
180
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700181 mVDSActive = true;
182
183 ALOGV("Virtual display (%dx%d) created", mWidth, mHeight);
184
Steve Kondik77754522017-06-14 17:00:33 -0700185 return NO_ERROR;
186}
187
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700188status_t VNCFlinger::destroyVirtualDisplayLocked() {
Steve Kondik46798992017-06-15 23:58:54 -0700189 if (!mVDSActive) {
190 return NO_INIT;
191 }
192
Steve Kondik77754522017-06-14 17:00:33 -0700193 mCpuConsumer.clear();
194 mProducer.clear();
195 SurfaceComposerClient::destroyDisplay(mDpy);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700196
197 mVDSActive = false;
198
199 ALOGV("Virtual display destroyed");
200
Steve Kondik77754522017-06-14 17:00:33 -0700201 return NO_ERROR;
202}
203
204status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700205 status_t err = NO_ERROR;
206
Steve Kondik55db0532017-06-12 11:27:18 -0700207 rfbLog = VNCFlinger::rfbLogger;
208 rfbErr = VNCFlinger::rfbLogger;
209
210 // 32-bit color
Steve Kondik5c8655c2017-06-19 00:28:47 -0700211 mVNCScreen = rfbGetScreen(0, NULL, mWidth, mHeight, 8, 3, 4);
Steve Kondik55db0532017-06-12 11:27:18 -0700212 if (mVNCScreen == NULL) {
213 ALOGE("Unable to create VNCScreen");
214 return NO_INIT;
215 }
216
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700217 mFrameNumber = 0;
218 mFrameSize = mWidth * mHeight * 4;
219 mVNCScreen->frameBuffer = (char*)new uint8_t[mFrameSize];
220 memset(mVNCScreen->frameBuffer, 0, mFrameSize);
221
Steve Kondik55db0532017-06-12 11:27:18 -0700222 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700223 mVNCScreen->alwaysShared = TRUE;
224 mVNCScreen->httpDir = NULL;
Steve Kondik5c8655c2017-06-19 00:28:47 -0700225 mVNCScreen->authPasswdData = (void *)VNC_AUTH_FILE;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700226 mVNCScreen->newClientHook = (rfbNewClientHookPtr)VNCFlinger::onNewClient;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700227 mVNCScreen->kbdAddEvent = InputDevice::onKeyEvent;
228 mVNCScreen->ptrAddEvent = InputDevice::onPointerEvent;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700229 mVNCScreen->displayHook = (rfbDisplayHookPtr)VNCFlinger::onFrameStart;
230 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr)VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700231 mVNCScreen->serverFormat.trueColour = true;
232 mVNCScreen->serverFormat.bitsPerPixel = 32;
233 mVNCScreen->handleEventsEagerly = true;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700234 mVNCScreen->deferUpdateTime = 1;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700235 mVNCScreen->screenData = this;
Steve Kondik5c8655c2017-06-19 00:28:47 -0700236
237 return err;
238}
239
240status_t VNCFlinger::startVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700241 rfbInitServer(mVNCScreen);
242
243 /* Mark as dirty since we haven't sent any updates at all yet. */
244 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
245
Steve Kondik5c8655c2017-06-19 00:28:47 -0700246 return NO_ERROR;
Steve Kondik55db0532017-06-12 11:27:18 -0700247}
248
Steve Kondik7225c7f2017-06-14 00:06:16 -0700249size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700250 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700251 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700252 mClientCount++;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700253 InputDevice::getInstance().start(mWidth, mHeight);
Steve Kondik77754522017-06-14 17:00:33 -0700254 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700255 }
Steve Kondik7225c7f2017-06-14 00:06:16 -0700256
257 ALOGI("Client connected (%zu)", mClientCount);
258
259 return mClientCount;
Steve Kondik55db0532017-06-12 11:27:18 -0700260}
261
Steve Kondik7225c7f2017-06-14 00:06:16 -0700262size_t VNCFlinger::removeClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700263 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700264 if (mClientCount > 0) {
265 mClientCount--;
266 if (mClientCount == 0) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700267 InputDevice::getInstance().stop();
Steve Kondik77754522017-06-14 17:00:33 -0700268 mEventCond.signal();
Steve Kondik7225c7f2017-06-14 00:06:16 -0700269 }
270 }
271
272 ALOGI("Client disconnected (%zu)", mClientCount);
273
274 return mClientCount;
275}
276
Steve Kondik77754522017-06-14 17:00:33 -0700277void VNCFlinger::processFrame() {
Steve Kondik77754522017-06-14 17:00:33 -0700278 // Take the update mutex. This ensures that we don't dequeue
279 // a new buffer and blow away the one being sent to a client.
280 // The BufferQueue is self-regulating and will drop frames
281 // automatically for us.
282 Mutex::Autolock _l(mUpdateMutex);
283
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700284 // get a frame from the virtual display
Steve Kondik77754522017-06-14 17:00:33 -0700285 CpuConsumer::LockedBuffer imgBuffer;
286 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
287 if (res != OK) {
288 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
289 return;
290 }
291
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700292 mFrameNumber = imgBuffer.frameNumber;
293 ALOGV("processFrame: [%lu] format: %x (%dx%d, stride=%d)", mFrameNumber, imgBuffer.format,
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700294 imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700295
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700296 // we don't know if there was a stride change until we get
297 // a buffer from the queue. if it changed, we need to resize
298 updateFBSize(imgBuffer);
Steve Kondik77754522017-06-14 17:00:33 -0700299
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700300 // performance is extremely bad if the gpu memory is used
301 // directly without copying because it is likely uncached
302 memcpy(mVNCScreen->frameBuffer, imgBuffer.data, mFrameSize);
Steve Kondik77754522017-06-14 17:00:33 -0700303
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700304 // update clients
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700305 rfbMarkRectAsModified(mVNCScreen, 0, 0, imgBuffer.width, imgBuffer.height);
Steve Kondik77754522017-06-14 17:00:33 -0700306
307 mCpuConsumer->unlockBuffer(imgBuffer);
308}
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700309
310/*
311 * Returns "true" if the device is rotated 90 degrees.
312 */
313bool VNCFlinger::isDeviceRotated(int orientation) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700314 return orientation != DISPLAY_ORIENTATION_0 && orientation != DISPLAY_ORIENTATION_180;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700315}
316
317/*
318 * Sets the display projection, based on the display dimensions, video size,
319 * and device orientation.
320 */
321bool VNCFlinger::updateDisplayProjection() {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700322 DisplayInfo info;
323 status_t err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &info);
324 if (err != NO_ERROR) {
325 ALOGE("Failed to get display characteristics\n");
326 return true;
327 }
328
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700329 // Set the region of the layer stack we're interested in, which in our
330 // case is "all of it". If the app is rotated (so that the width of the
331 // app is based on the height of the display), reverse width/height.
332 bool deviceRotated = isDeviceRotated(info.orientation);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700333 uint32_t sourceWidth, sourceHeight;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700334 if (!deviceRotated) {
335 sourceWidth = info.w;
336 sourceHeight = info.h;
337 } else {
338 ALOGV("using rotated width/height");
339 sourceHeight = info.w;
340 sourceWidth = info.h;
341 }
342
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700343 if (mWidth == sourceWidth && mHeight == sourceHeight && mOrientation == info.orientation) {
344 return false;
345 }
346
347 ALOGD("Display dimensions: %dx%d orientation=%d", sourceWidth, sourceHeight, info.orientation);
348
349 // orientation change
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700350 mWidth = sourceWidth;
351 mHeight = sourceHeight;
352 mOrientation = info.orientation;
353
354 if (!mVDSActive) {
355 return true;
356 }
357
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700358 // it does not appear to be possible to reconfigure the virtual display
359 // on the fly without forcing surfaceflinger to tear it down
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700360 destroyVirtualDisplayLocked();
361 createVirtualDisplay();
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700362 return false;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700363}
364
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700365bool VNCFlinger::updateFBSize(CpuConsumer::LockedBuffer& buf) {
366 uint32_t stride = (uint32_t)mVNCScreen->paddedWidthInBytes / 4;
367 uint32_t width = (uint32_t)mVNCScreen->width;
368 uint32_t height = (uint32_t)mVNCScreen->height;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700369
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700370 uint64_t newSize = buf.stride * buf.height * 4;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700371
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700372 if (stride != buf.stride || height != buf.height || width != buf.width) {
373 ALOGD("updateFBSize: old=[%dx%d %d] new=[%dx%d %d]", width, height, stride, buf.width,
374 buf.height, buf.stride);
375
376 if (mFrameSize != newSize) {
377 mFrameSize = newSize;
378 delete[] mVNCScreen->frameBuffer;
379 rfbNewFramebuffer(mVNCScreen, (char*)new uint8_t[newSize], buf.width, buf.height, 8, 3,
380 4);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700381 }
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700382 mVNCScreen->paddedWidthInBytes = buf.stride * 4;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700383 }
384 return NO_ERROR;
385}
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700386
387// ------------------------------------------------------------------------ //
388
389// libvncserver logger
390void VNCFlinger::rfbLogger(const char* format, ...) {
391 va_list args;
392 char buf[256];
393
394 va_start(args, format);
395 vsprintf(buf, format, args);
396 ALOGI("%s", buf);
397 va_end(args);
398}
399
400// libvncserver callbacks
401ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr cl) {
402 ALOGV("onClientGone");
403 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
404 vf->removeClient();
405 return 0;
406}
407
408enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
409 ALOGV("onNewClient");
410 cl->clientGoneHook = (ClientGoneHookPtr)VNCFlinger::onClientGone;
411 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
412 vf->addClient();
413 return RFB_CLIENT_ACCEPT;
414}
415
416void VNCFlinger::onFrameStart(rfbClientPtr cl) {
417 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
418 vf->mUpdateMutex.lock();
419
420 vf->mFrameStartWhen = systemTime(CLOCK_MONOTONIC);
421 ALOGV("frame start [%lu]", vf->mFrameNumber);
422}
423
424void VNCFlinger::onFrameDone(rfbClientPtr cl, int /* status */) {
425 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
426
427 float timing = (systemTime(CLOCK_MONOTONIC) - vf->mFrameStartWhen) / 1000000.0;
428 ALOGV("onFrameDone [%lu] (%.3f ms)", vf->mFrameNumber, timing);
429
430 vf->mUpdateMutex.unlock();
431}
432
433// cpuconsumer frame listener
434void VNCFlinger::FrameListener::onFrameAvailable(const BufferItem& item) {
435 Mutex::Autolock _l(mVNC->mEventMutex);
436 mVNC->mFrameAvailable = true;
437 mVNC->mEventCond.signal();
438 ALOGV("onFrameAvailable: [%lu] mTimestamp=%ld", item.mFrameNumber, item.mTimestamp);
439}