blob: cd7da0f2c1737fd805e4beec4324b34f4d9c238f [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
Steve Kondik3db07472017-06-19 22:13:45 -070044 setV4Address(v4);
45 setV6Address(v6);
Steve Kondik5c8655c2017-06-19 00:28:47 -070046}
47
Steve Kondik3db07472017-06-19 22:13:45 -070048status_t VNCFlinger::setV4Address(const String8& address) {
Steve Kondik5c8655c2017-06-19 00:28:47 -070049 if (!rfbStringToAddr(const_cast<char *>(address.string()), &(mVNCScreen->listenInterface))) {
50 return BAD_VALUE;
51 }
52 return NO_ERROR;
53}
54
Steve Kondik3db07472017-06-19 22:13:45 -070055status_t VNCFlinger::setV6Address(const String8& address) {
56 ALOGD("v6: %s", const_cast<char *>(address.string()));
57 mVNCScreen->listen6Interface = const_cast<char *>(address.string());
58 return NO_ERROR;
59}
60
Steve Kondik5c8655c2017-06-19 00:28:47 -070061status_t VNCFlinger::setPort(unsigned int port) {
62 if (port > 65535) {
63 port = 0;
64 }
65 if (port == 0) {
66 mVNCScreen->autoPort = 1;
67 } else {
68 mVNCScreen->autoPort = 0;
69 mVNCScreen->port = port;
70 mVNCScreen->ipv6port = port;
71 }
72 return NO_ERROR;
73}
74
75status_t VNCFlinger::clearPassword() {
76 std::remove(VNC_AUTH_FILE);
77 ALOGW("Password authentication disabled");
78 return OK;
79}
80
Steve Kondik3db07472017-06-19 22:13:45 -070081status_t VNCFlinger::setPassword(const String8& passwd) {
Steve Kondik5c8655c2017-06-19 00:28:47 -070082 String8 path(VNC_AUTH_FILE);
83 if (rfbEncryptAndStorePasswd(const_cast<char *>(passwd.string()),
84 const_cast<char *>(path.string())) != 0) {
85 ALOGE("Failed to set password");
86 return BAD_VALUE;
87 }
88 ALOGI("Password has been set");
89 return OK;
90}
91
Steve Kondik55db0532017-06-12 11:27:18 -070092status_t VNCFlinger::start() {
Steve Kondik77754522017-06-14 17:00:33 -070093 sp<ProcessState> self = ProcessState::self();
94 self->startThreadPool();
Steve Kondik55db0532017-06-12 11:27:18 -070095
Steve Kondik5c8655c2017-06-19 00:28:47 -070096 status_t err = startVNCServer();
Steve Kondik55db0532017-06-12 11:27:18 -070097 if (err != NO_ERROR) {
98 ALOGE("Failed to start VNCFlinger: err=%d", err);
99 return err;
100 }
101
Steve Kondik55db0532017-06-12 11:27:18 -0700102 rfbRunEventLoop(mVNCScreen, -1, true);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700103
Steve Kondik46798992017-06-15 23:58:54 -0700104 ALOGD("VNCFlinger ready to fling");
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700105
Steve Kondik77754522017-06-14 17:00:33 -0700106 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -0700107
Steve Kondik46798992017-06-15 23:58:54 -0700108 ALOGI("VNCFlinger has left the building");
109
110 return NO_ERROR;
111}
112
113status_t VNCFlinger::stop() {
114 Mutex::Autolock _L(mEventMutex);
115
116 ALOGV("Shutting down");
117
Steve Kondik5c8655c2017-06-19 00:28:47 -0700118 rfbShutdownServer(mVNCScreen, true);
119
Steve Kondik46798992017-06-15 23:58:54 -0700120 destroyVirtualDisplayLocked();
121 mClientCount = 0;
122 mRunning = false;
123
124 mEventCond.signal();
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700125 delete[] mVNCScreen->frameBuffer;
Steve Kondik55db0532017-06-12 11:27:18 -0700126 return NO_ERROR;
127}
128
Steve Kondik77754522017-06-14 17:00:33 -0700129void VNCFlinger::eventLoop() {
130 mRunning = true;
131
132 Mutex::Autolock _l(mEventMutex);
133 while (mRunning) {
134 mEventCond.wait(mEventMutex);
135
136 // spurious wakeup? never.
137 if (mClientCount == 0) {
138 continue;
139 }
140
141 // this is a new client, so fire everything up
142 status_t err = createVirtualDisplay();
143 if (err != NO_ERROR) {
144 ALOGE("Failed to create virtual display: err=%d", err);
145 }
146
147 // loop while clients are connected and process frames
148 // on the main thread when signalled
149 while (mClientCount > 0) {
150 mEventCond.wait(mEventMutex);
151 if (mFrameAvailable) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700152 if (!updateDisplayProjection()) {
153 processFrame();
154 }
Steve Kondik77754522017-06-14 17:00:33 -0700155 mFrameAvailable = false;
156 }
157 }
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700158 Mutex::Autolock _l(mUpdateMutex);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700159 memset(mVNCScreen->frameBuffer, 0, mFrameSize);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700160 destroyVirtualDisplayLocked();
Steve Kondik77754522017-06-14 17:00:33 -0700161 }
162}
163
164status_t VNCFlinger::createVirtualDisplay() {
165 sp<IGraphicBufferConsumer> consumer;
166 BufferQueue::createBufferQueue(&mProducer, &consumer);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700167 mCpuConsumer = new CpuConsumer(consumer, NUM_BUFS);
Steve Kondik77754522017-06-14 17:00:33 -0700168 mCpuConsumer->setName(String8("vds-to-cpu"));
169 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
170 mProducer->setMaxDequeuedBufferCount(4);
171
172 mListener = new FrameListener(this);
173 mCpuConsumer->setFrameAvailableListener(mListener);
174
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700175 mDpy = SurfaceComposerClient::createDisplay(String8("VNC-VirtualDisplay"), false /*secure*/);
Steve Kondik77754522017-06-14 17:00:33 -0700176
177 SurfaceComposerClient::openGlobalTransaction();
178 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700179 // setDisplayProjection(mDpy, mainDpyInfo);
180 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
Steve Kondik77754522017-06-14 17:00:33 -0700181 SurfaceComposerClient::closeGlobalTransaction();
182
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700183 mVDSActive = true;
184
185 ALOGV("Virtual display (%dx%d) created", mWidth, mHeight);
186
Steve Kondik77754522017-06-14 17:00:33 -0700187 return NO_ERROR;
188}
189
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700190status_t VNCFlinger::destroyVirtualDisplayLocked() {
Steve Kondik46798992017-06-15 23:58:54 -0700191 if (!mVDSActive) {
192 return NO_INIT;
193 }
194
Steve Kondik77754522017-06-14 17:00:33 -0700195 mCpuConsumer.clear();
196 mProducer.clear();
197 SurfaceComposerClient::destroyDisplay(mDpy);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700198
199 mVDSActive = false;
200
201 ALOGV("Virtual display destroyed");
202
Steve Kondik77754522017-06-14 17:00:33 -0700203 return NO_ERROR;
204}
205
206status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700207 status_t err = NO_ERROR;
208
Steve Kondik55db0532017-06-12 11:27:18 -0700209 rfbLog = VNCFlinger::rfbLogger;
210 rfbErr = VNCFlinger::rfbLogger;
211
212 // 32-bit color
Steve Kondik5c8655c2017-06-19 00:28:47 -0700213 mVNCScreen = rfbGetScreen(0, NULL, mWidth, mHeight, 8, 3, 4);
Steve Kondik55db0532017-06-12 11:27:18 -0700214 if (mVNCScreen == NULL) {
215 ALOGE("Unable to create VNCScreen");
216 return NO_INIT;
217 }
218
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700219 mFrameNumber = 0;
220 mFrameSize = mWidth * mHeight * 4;
221 mVNCScreen->frameBuffer = (char*)new uint8_t[mFrameSize];
222 memset(mVNCScreen->frameBuffer, 0, mFrameSize);
223
Steve Kondik55db0532017-06-12 11:27:18 -0700224 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700225 mVNCScreen->alwaysShared = TRUE;
226 mVNCScreen->httpDir = NULL;
Steve Kondik5c8655c2017-06-19 00:28:47 -0700227 mVNCScreen->authPasswdData = (void *)VNC_AUTH_FILE;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700228 mVNCScreen->newClientHook = (rfbNewClientHookPtr)VNCFlinger::onNewClient;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700229 mVNCScreen->kbdAddEvent = InputDevice::onKeyEvent;
230 mVNCScreen->ptrAddEvent = InputDevice::onPointerEvent;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700231 mVNCScreen->displayHook = (rfbDisplayHookPtr)VNCFlinger::onFrameStart;
232 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr)VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700233 mVNCScreen->serverFormat.trueColour = true;
234 mVNCScreen->serverFormat.bitsPerPixel = 32;
235 mVNCScreen->handleEventsEagerly = true;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700236 mVNCScreen->deferUpdateTime = 1;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700237 mVNCScreen->screenData = this;
Steve Kondik5c8655c2017-06-19 00:28:47 -0700238
239 return err;
240}
241
242status_t VNCFlinger::startVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700243 rfbInitServer(mVNCScreen);
244
245 /* Mark as dirty since we haven't sent any updates at all yet. */
246 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
247
Steve Kondik5c8655c2017-06-19 00:28:47 -0700248 return NO_ERROR;
Steve Kondik55db0532017-06-12 11:27:18 -0700249}
250
Steve Kondik7225c7f2017-06-14 00:06:16 -0700251size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700252 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700253 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700254 mClientCount++;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700255 InputDevice::getInstance().start(mWidth, mHeight);
Steve Kondik77754522017-06-14 17:00:33 -0700256 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700257 }
Steve Kondik7225c7f2017-06-14 00:06:16 -0700258
259 ALOGI("Client connected (%zu)", mClientCount);
260
261 return mClientCount;
Steve Kondik55db0532017-06-12 11:27:18 -0700262}
263
Steve Kondik7225c7f2017-06-14 00:06:16 -0700264size_t VNCFlinger::removeClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700265 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700266 if (mClientCount > 0) {
267 mClientCount--;
268 if (mClientCount == 0) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700269 InputDevice::getInstance().stop();
Steve Kondik77754522017-06-14 17:00:33 -0700270 mEventCond.signal();
Steve Kondik7225c7f2017-06-14 00:06:16 -0700271 }
272 }
273
274 ALOGI("Client disconnected (%zu)", mClientCount);
275
276 return mClientCount;
277}
278
Steve Kondik77754522017-06-14 17:00:33 -0700279void VNCFlinger::processFrame() {
Steve Kondik77754522017-06-14 17:00:33 -0700280 // Take the update mutex. This ensures that we don't dequeue
281 // a new buffer and blow away the one being sent to a client.
282 // The BufferQueue is self-regulating and will drop frames
283 // automatically for us.
284 Mutex::Autolock _l(mUpdateMutex);
285
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700286 // get a frame from the virtual display
Steve Kondik77754522017-06-14 17:00:33 -0700287 CpuConsumer::LockedBuffer imgBuffer;
288 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
289 if (res != OK) {
290 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
291 return;
292 }
293
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700294 mFrameNumber = imgBuffer.frameNumber;
295 ALOGV("processFrame: [%lu] format: %x (%dx%d, stride=%d)", mFrameNumber, imgBuffer.format,
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700296 imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700297
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700298 // we don't know if there was a stride change until we get
299 // a buffer from the queue. if it changed, we need to resize
300 updateFBSize(imgBuffer);
Steve Kondik77754522017-06-14 17:00:33 -0700301
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700302 // performance is extremely bad if the gpu memory is used
303 // directly without copying because it is likely uncached
304 memcpy(mVNCScreen->frameBuffer, imgBuffer.data, mFrameSize);
Steve Kondik77754522017-06-14 17:00:33 -0700305
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700306 // update clients
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700307 rfbMarkRectAsModified(mVNCScreen, 0, 0, imgBuffer.width, imgBuffer.height);
Steve Kondik77754522017-06-14 17:00:33 -0700308
309 mCpuConsumer->unlockBuffer(imgBuffer);
310}
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700311
312/*
313 * Returns "true" if the device is rotated 90 degrees.
314 */
315bool VNCFlinger::isDeviceRotated(int orientation) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700316 return orientation != DISPLAY_ORIENTATION_0 && orientation != DISPLAY_ORIENTATION_180;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700317}
318
319/*
320 * Sets the display projection, based on the display dimensions, video size,
321 * and device orientation.
322 */
323bool VNCFlinger::updateDisplayProjection() {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700324 DisplayInfo info;
325 status_t err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &info);
326 if (err != NO_ERROR) {
327 ALOGE("Failed to get display characteristics\n");
328 return true;
329 }
330
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700331 // Set the region of the layer stack we're interested in, which in our
332 // case is "all of it". If the app is rotated (so that the width of the
333 // app is based on the height of the display), reverse width/height.
334 bool deviceRotated = isDeviceRotated(info.orientation);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700335 uint32_t sourceWidth, sourceHeight;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700336 if (!deviceRotated) {
337 sourceWidth = info.w;
338 sourceHeight = info.h;
339 } else {
340 ALOGV("using rotated width/height");
341 sourceHeight = info.w;
342 sourceWidth = info.h;
343 }
344
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700345 if (mWidth == sourceWidth && mHeight == sourceHeight && mOrientation == info.orientation) {
346 return false;
347 }
348
349 ALOGD("Display dimensions: %dx%d orientation=%d", sourceWidth, sourceHeight, info.orientation);
350
351 // orientation change
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700352 mWidth = sourceWidth;
353 mHeight = sourceHeight;
354 mOrientation = info.orientation;
355
356 if (!mVDSActive) {
357 return true;
358 }
359
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700360 // it does not appear to be possible to reconfigure the virtual display
361 // on the fly without forcing surfaceflinger to tear it down
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700362 destroyVirtualDisplayLocked();
363 createVirtualDisplay();
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700364 return false;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700365}
366
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700367bool VNCFlinger::updateFBSize(CpuConsumer::LockedBuffer& buf) {
368 uint32_t stride = (uint32_t)mVNCScreen->paddedWidthInBytes / 4;
369 uint32_t width = (uint32_t)mVNCScreen->width;
370 uint32_t height = (uint32_t)mVNCScreen->height;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700371
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700372 uint64_t newSize = buf.stride * buf.height * 4;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700373
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700374 if (stride != buf.stride || height != buf.height || width != buf.width) {
375 ALOGD("updateFBSize: old=[%dx%d %d] new=[%dx%d %d]", width, height, stride, buf.width,
376 buf.height, buf.stride);
377
378 if (mFrameSize != newSize) {
379 mFrameSize = newSize;
380 delete[] mVNCScreen->frameBuffer;
381 rfbNewFramebuffer(mVNCScreen, (char*)new uint8_t[newSize], buf.width, buf.height, 8, 3,
382 4);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700383 }
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700384 mVNCScreen->paddedWidthInBytes = buf.stride * 4;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700385 }
386 return NO_ERROR;
387}
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700388
389// ------------------------------------------------------------------------ //
390
391// libvncserver logger
392void VNCFlinger::rfbLogger(const char* format, ...) {
393 va_list args;
394 char buf[256];
395
396 va_start(args, format);
397 vsprintf(buf, format, args);
398 ALOGI("%s", buf);
399 va_end(args);
400}
401
402// libvncserver callbacks
403ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr cl) {
404 ALOGV("onClientGone");
405 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
406 vf->removeClient();
407 return 0;
408}
409
410enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
411 ALOGV("onNewClient");
412 cl->clientGoneHook = (ClientGoneHookPtr)VNCFlinger::onClientGone;
413 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
414 vf->addClient();
415 return RFB_CLIENT_ACCEPT;
416}
417
418void VNCFlinger::onFrameStart(rfbClientPtr cl) {
419 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
420 vf->mUpdateMutex.lock();
421
422 vf->mFrameStartWhen = systemTime(CLOCK_MONOTONIC);
423 ALOGV("frame start [%lu]", vf->mFrameNumber);
424}
425
426void VNCFlinger::onFrameDone(rfbClientPtr cl, int /* status */) {
427 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
428
429 float timing = (systemTime(CLOCK_MONOTONIC) - vf->mFrameStartWhen) / 1000000.0;
430 ALOGV("onFrameDone [%lu] (%.3f ms)", vf->mFrameNumber, timing);
431
432 vf->mUpdateMutex.unlock();
433}
434
435// cpuconsumer frame listener
436void VNCFlinger::FrameListener::onFrameAvailable(const BufferItem& item) {
437 Mutex::Autolock _l(mVNC->mEventMutex);
438 mVNC->mFrameAvailable = true;
439 mVNC->mEventCond.signal();
440 ALOGV("onFrameAvailable: [%lu] mTimestamp=%ld", item.mFrameNumber, item.mTimestamp);
441}