blob: 4517e3511f19991899ea9c0fe52952dc6155e088 [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>
22#include <binder/ProcessState.h>
23#include <binder/IServiceManager.h>
24
25#include <gui/ISurfaceComposer.h>
26#include <gui/SurfaceComposerClient.h>
27#include <gui/IGraphicBufferProducer.h>
28
Steve Kondik107d2e52017-06-13 17:34:56 -070029#include "InputDevice.h"
Steve Kondik55db0532017-06-12 11:27:18 -070030#include "VNCFlinger.h"
31
Steve Kondik77754522017-06-14 17:00:33 -070032
Steve Kondik55db0532017-06-12 11:27:18 -070033using namespace android;
34
Steve Kondik55db0532017-06-12 11:27:18 -070035status_t VNCFlinger::start() {
Steve Kondik77754522017-06-14 17:00:33 -070036 sp<ProcessState> self = ProcessState::self();
37 self->startThreadPool();
Steve Kondik55db0532017-06-12 11:27:18 -070038
Steve Kondik77754522017-06-14 17:00:33 -070039 status_t err = NO_ERROR;
40
41 mMainDpy = SurfaceComposerClient::getBuiltInDisplay(
42 ISurfaceComposer::eDisplayIdMain);
43 err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &mMainDpyInfo);
44 if (err != NO_ERROR) {
45 ALOGE("Failed to get display characteristics\n");
46 return err;
47 }
48 mHeight = mMainDpyInfo.h;
49 mWidth = mMainDpyInfo.w;
50
51 err = createVNCServer();
Steve Kondik55db0532017-06-12 11:27:18 -070052 if (err != NO_ERROR) {
53 ALOGE("Failed to start VNCFlinger: err=%d", err);
54 return err;
55 }
56
57 ALOGD("VNCFlinger is running!");
58
59 rfbRunEventLoop(mVNCScreen, -1, true);
Steve Kondik7225c7f2017-06-14 00:06:16 -070060
Steve Kondik77754522017-06-14 17:00:33 -070061 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -070062
Steve Kondik55db0532017-06-12 11:27:18 -070063 return NO_ERROR;
64}
65
Steve Kondik77754522017-06-14 17:00:33 -070066void VNCFlinger::eventLoop() {
67 mRunning = true;
68
69 Mutex::Autolock _l(mEventMutex);
70 while (mRunning) {
71 mEventCond.wait(mEventMutex);
72
73 // spurious wakeup? never.
74 if (mClientCount == 0) {
75 continue;
76 }
77
78 // this is a new client, so fire everything up
79 status_t err = createVirtualDisplay();
80 if (err != NO_ERROR) {
81 ALOGE("Failed to create virtual display: err=%d", err);
82 }
83
84 // loop while clients are connected and process frames
85 // on the main thread when signalled
86 while (mClientCount > 0) {
87 mEventCond.wait(mEventMutex);
88 if (mFrameAvailable) {
89 processFrame();
90 mFrameAvailable = false;
91 }
92 }
93
94 destroyVirtualDisplay();
95 }
96}
97
98status_t VNCFlinger::createVirtualDisplay() {
99 sp<IGraphicBufferConsumer> consumer;
100 BufferQueue::createBufferQueue(&mProducer, &consumer);
101 mCpuConsumer = new CpuConsumer(consumer, 1);
102 mCpuConsumer->setName(String8("vds-to-cpu"));
103 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
104 mProducer->setMaxDequeuedBufferCount(4);
105
106 mListener = new FrameListener(this);
107 mCpuConsumer->setFrameAvailableListener(mListener);
108
109 mDpy = SurfaceComposerClient::createDisplay(
110 String8("VNC-VirtualDisplay"), false /*secure*/);
111
112 SurfaceComposerClient::openGlobalTransaction();
113 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
114 //setDisplayProjection(mDpy, mainDpyInfo);
115 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
116 SurfaceComposerClient::closeGlobalTransaction();
117
118 ALOGV("Virtual display created");
119 return NO_ERROR;
120}
121
122status_t VNCFlinger::destroyVirtualDisplay() {
123 mCpuConsumer.clear();
124 mProducer.clear();
125 SurfaceComposerClient::destroyDisplay(mDpy);
126 return NO_ERROR;
127}
128
129status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700130
131 status_t err = NO_ERROR;
132
Steve Kondik55db0532017-06-12 11:27:18 -0700133 rfbLog = VNCFlinger::rfbLogger;
134 rfbErr = VNCFlinger::rfbLogger;
135
136 // 32-bit color
137 mVNCScreen = rfbGetScreen(&mArgc, mArgv, mWidth, mHeight, 8, 3, 4);
138 if (mVNCScreen == NULL) {
139 ALOGE("Unable to create VNCScreen");
140 return NO_INIT;
141 }
142
Steve Kondikdda11002017-06-13 08:20:27 -0700143 mVNCBuf = new uint8_t[mWidth * mHeight * 4];
144 mVNCScreen->frameBuffer = (char *) mVNCBuf;
Steve Kondik55db0532017-06-12 11:27:18 -0700145 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700146 mVNCScreen->alwaysShared = TRUE;
147 mVNCScreen->httpDir = NULL;
148 mVNCScreen->port = VNC_PORT;
149 mVNCScreen->newClientHook = (rfbNewClientHookPtr) VNCFlinger::onNewClient;
Steve Kondik107d2e52017-06-13 17:34:56 -0700150 mVNCScreen->kbdAddEvent = InputDevice::keyEvent;
151 mVNCScreen->ptrAddEvent = InputDevice::pointerEvent;
Steve Kondikef4e8652017-06-14 15:07:54 -0700152 mVNCScreen->displayHook = (rfbDisplayHookPtr) VNCFlinger::onFrameStart;
153 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr) VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700154 mVNCScreen->serverFormat.trueColour = true;
155 mVNCScreen->serverFormat.bitsPerPixel = 32;
156 mVNCScreen->handleEventsEagerly = true;
Steve Kondikef4e8652017-06-14 15:07:54 -0700157 mVNCScreen->deferUpdateTime = 0;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700158 mVNCScreen->screenData = this;
Steve Kondik55db0532017-06-12 11:27:18 -0700159 rfbInitServer(mVNCScreen);
160
161 /* Mark as dirty since we haven't sent any updates at all yet. */
162 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
163
164 return err;
165}
166
Steve Kondik55db0532017-06-12 11:27:18 -0700167status_t VNCFlinger::stop() {
Steve Kondik77754522017-06-14 17:00:33 -0700168 Mutex::Autolock _L(mEventMutex);
169
170 mClientCount = 0;
171 mRunning = false;
172
173 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700174
175 return NO_ERROR;
176}
177
Steve Kondik7225c7f2017-06-14 00:06:16 -0700178size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700179 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700180 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700181 mClientCount++;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700182 InputDevice::start(mWidth, mHeight);
Steve Kondik77754522017-06-14 17:00:33 -0700183 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700184 }
Steve Kondik7225c7f2017-06-14 00:06:16 -0700185
186 ALOGI("Client connected (%zu)", mClientCount);
187
188 return mClientCount;
Steve Kondik55db0532017-06-12 11:27:18 -0700189}
190
Steve Kondik7225c7f2017-06-14 00:06:16 -0700191size_t VNCFlinger::removeClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700192 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700193 if (mClientCount > 0) {
194 mClientCount--;
195 if (mClientCount == 0) {
Steve Kondik7225c7f2017-06-14 00:06:16 -0700196 InputDevice::stop();
Steve Kondik77754522017-06-14 17:00:33 -0700197 mEventCond.signal();
Steve Kondik7225c7f2017-06-14 00:06:16 -0700198 }
199 }
200
201 ALOGI("Client disconnected (%zu)", mClientCount);
202
203 return mClientCount;
204}
205
206ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr cl) {
Steve Kondik55db0532017-06-12 11:27:18 -0700207 ALOGV("onClientGone");
Steve Kondik7225c7f2017-06-14 00:06:16 -0700208 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
209 vf->removeClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700210 return 0;
211}
212
213enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
214 ALOGV("onNewClient");
215 cl->clientGoneHook = (ClientGoneHookPtr) VNCFlinger::onClientGone;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700216 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
217 vf->addClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700218 return RFB_CLIENT_ACCEPT;
219}
220
Steve Kondik77754522017-06-14 17:00:33 -0700221void VNCFlinger::onFrameStart(rfbClientPtr cl) {
222 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
223 vf->mUpdateMutex.lock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700224 ALOGV("frame start");
225}
226
Steve Kondik77754522017-06-14 17:00:33 -0700227void VNCFlinger::onFrameDone(rfbClientPtr cl, int status) {
228 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
229 vf->mUpdateMutex.unlock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700230 ALOGV("frame done! %d", status);
231}
232
Steve Kondik55db0532017-06-12 11:27:18 -0700233void VNCFlinger::rfbLogger(const char *format, ...) {
234 va_list args;
235 char buf[256];
236
237 va_start(args, format);
238 vsprintf(buf, format, args);
239 ALOGI("%s", buf);
240 va_end(args);
241}
Steve Kondik77754522017-06-14 17:00:33 -0700242
243void VNCFlinger::FrameListener::onFrameAvailable(const BufferItem& item) {
244 Mutex::Autolock _l(mVNC->mEventMutex);
245 mVNC->mFrameAvailable = true;
246 mVNC->mEventCond.signal();
247 ALOGV("onFrameAvailable: mTimestamp=%ld mFrameNumber=%ld",
248 item.mTimestamp, item.mFrameNumber);
249}
250
251void VNCFlinger::processFrame() {
252 ALOGV("processFrame\n");
253
254 // Take the update mutex. This ensures that we don't dequeue
255 // a new buffer and blow away the one being sent to a client.
256 // The BufferQueue is self-regulating and will drop frames
257 // automatically for us.
258 Mutex::Autolock _l(mUpdateMutex);
259
260 CpuConsumer::LockedBuffer imgBuffer;
261 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
262 if (res != OK) {
263 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
264 return;
265 }
266
267 ALOGV("processFrame: ptr: %p format: %x (%dx%d, stride=%d)",
268 imgBuffer.data, imgBuffer.format, imgBuffer.width,
269 imgBuffer.height, imgBuffer.stride);
270
271 void* vncbuf = mVNCScreen->frameBuffer;
272 void* imgbuf = imgBuffer.data;
273
274 // Copy the frame to the server's buffer
275 if (imgBuffer.stride > mWidth) {
276 // Image has larger stride, so we need to copy row by row
277 for (size_t y = 0; y < mHeight; y++) {
278 memcpy(vncbuf, imgbuf, mWidth * 4);
279 vncbuf = (void *)((char *)vncbuf + mWidth * 4);
280 imgbuf = (void *)((char *)imgbuf + imgBuffer.stride * 4);
281 }
282 } else {
283 memcpy(vncbuf, imgbuf, mWidth * mHeight * 4);
284 }
285
286 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
287
288 mCpuConsumer->unlockBuffer(imgBuffer);
289}