blob: 4775d0bdd5d5becd9e32c220e3f92859b2a3186a [file] [log] [blame]
Steve Kondik55db0532017-06-12 11:27:18 -07001#define LOG_TAG "VNCFlinger"
2#include <utils/Log.h>
3
4#include <binder/IPCThreadState.h>
5#include <binder/ProcessState.h>
6#include <binder/IServiceManager.h>
7
8#include <gui/ISurfaceComposer.h>
9#include <gui/SurfaceComposerClient.h>
10#include <gui/IGraphicBufferProducer.h>
11
Steve Kondik107d2e52017-06-13 17:34:56 -070012#include "InputDevice.h"
Steve Kondik55db0532017-06-12 11:27:18 -070013#include "VNCFlinger.h"
14
Steve Kondik77754522017-06-14 17:00:33 -070015
Steve Kondik55db0532017-06-12 11:27:18 -070016using namespace android;
17
Steve Kondik55db0532017-06-12 11:27:18 -070018status_t VNCFlinger::start() {
Steve Kondik77754522017-06-14 17:00:33 -070019 sp<ProcessState> self = ProcessState::self();
20 self->startThreadPool();
Steve Kondik55db0532017-06-12 11:27:18 -070021
Steve Kondik77754522017-06-14 17:00:33 -070022 status_t err = NO_ERROR;
23
24 mMainDpy = SurfaceComposerClient::getBuiltInDisplay(
25 ISurfaceComposer::eDisplayIdMain);
26 err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &mMainDpyInfo);
27 if (err != NO_ERROR) {
28 ALOGE("Failed to get display characteristics\n");
29 return err;
30 }
31 mHeight = mMainDpyInfo.h;
32 mWidth = mMainDpyInfo.w;
33
34 err = createVNCServer();
Steve Kondik55db0532017-06-12 11:27:18 -070035 if (err != NO_ERROR) {
36 ALOGE("Failed to start VNCFlinger: err=%d", err);
37 return err;
38 }
39
40 ALOGD("VNCFlinger is running!");
41
42 rfbRunEventLoop(mVNCScreen, -1, true);
Steve Kondik7225c7f2017-06-14 00:06:16 -070043
Steve Kondik77754522017-06-14 17:00:33 -070044 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -070045
Steve Kondik55db0532017-06-12 11:27:18 -070046 return NO_ERROR;
47}
48
Steve Kondik77754522017-06-14 17:00:33 -070049void VNCFlinger::eventLoop() {
50 mRunning = true;
51
52 Mutex::Autolock _l(mEventMutex);
53 while (mRunning) {
54 mEventCond.wait(mEventMutex);
55
56 // spurious wakeup? never.
57 if (mClientCount == 0) {
58 continue;
59 }
60
61 // this is a new client, so fire everything up
62 status_t err = createVirtualDisplay();
63 if (err != NO_ERROR) {
64 ALOGE("Failed to create virtual display: err=%d", err);
65 }
66
67 // loop while clients are connected and process frames
68 // on the main thread when signalled
69 while (mClientCount > 0) {
70 mEventCond.wait(mEventMutex);
71 if (mFrameAvailable) {
72 processFrame();
73 mFrameAvailable = false;
74 }
75 }
76
77 destroyVirtualDisplay();
78 }
79}
80
81status_t VNCFlinger::createVirtualDisplay() {
82 sp<IGraphicBufferConsumer> consumer;
83 BufferQueue::createBufferQueue(&mProducer, &consumer);
84 mCpuConsumer = new CpuConsumer(consumer, 1);
85 mCpuConsumer->setName(String8("vds-to-cpu"));
86 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
87 mProducer->setMaxDequeuedBufferCount(4);
88
89 mListener = new FrameListener(this);
90 mCpuConsumer->setFrameAvailableListener(mListener);
91
92 mDpy = SurfaceComposerClient::createDisplay(
93 String8("VNC-VirtualDisplay"), false /*secure*/);
94
95 SurfaceComposerClient::openGlobalTransaction();
96 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
97 //setDisplayProjection(mDpy, mainDpyInfo);
98 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
99 SurfaceComposerClient::closeGlobalTransaction();
100
101 ALOGV("Virtual display created");
102 return NO_ERROR;
103}
104
105status_t VNCFlinger::destroyVirtualDisplay() {
106 mCpuConsumer.clear();
107 mProducer.clear();
108 SurfaceComposerClient::destroyDisplay(mDpy);
109 return NO_ERROR;
110}
111
112status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700113
114 status_t err = NO_ERROR;
115
Steve Kondik55db0532017-06-12 11:27:18 -0700116 rfbLog = VNCFlinger::rfbLogger;
117 rfbErr = VNCFlinger::rfbLogger;
118
119 // 32-bit color
120 mVNCScreen = rfbGetScreen(&mArgc, mArgv, mWidth, mHeight, 8, 3, 4);
121 if (mVNCScreen == NULL) {
122 ALOGE("Unable to create VNCScreen");
123 return NO_INIT;
124 }
125
Steve Kondikdda11002017-06-13 08:20:27 -0700126 mVNCBuf = new uint8_t[mWidth * mHeight * 4];
127 mVNCScreen->frameBuffer = (char *) mVNCBuf;
Steve Kondik55db0532017-06-12 11:27:18 -0700128 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700129 mVNCScreen->alwaysShared = TRUE;
130 mVNCScreen->httpDir = NULL;
131 mVNCScreen->port = VNC_PORT;
132 mVNCScreen->newClientHook = (rfbNewClientHookPtr) VNCFlinger::onNewClient;
Steve Kondik107d2e52017-06-13 17:34:56 -0700133 mVNCScreen->kbdAddEvent = InputDevice::keyEvent;
134 mVNCScreen->ptrAddEvent = InputDevice::pointerEvent;
Steve Kondikef4e8652017-06-14 15:07:54 -0700135 mVNCScreen->displayHook = (rfbDisplayHookPtr) VNCFlinger::onFrameStart;
136 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr) VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700137 mVNCScreen->serverFormat.trueColour = true;
138 mVNCScreen->serverFormat.bitsPerPixel = 32;
139 mVNCScreen->handleEventsEagerly = true;
Steve Kondikef4e8652017-06-14 15:07:54 -0700140 mVNCScreen->deferUpdateTime = 0;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700141 mVNCScreen->screenData = this;
Steve Kondik55db0532017-06-12 11:27:18 -0700142 rfbInitServer(mVNCScreen);
143
144 /* Mark as dirty since we haven't sent any updates at all yet. */
145 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
146
147 return err;
148}
149
Steve Kondik55db0532017-06-12 11:27:18 -0700150status_t VNCFlinger::stop() {
Steve Kondik77754522017-06-14 17:00:33 -0700151 Mutex::Autolock _L(mEventMutex);
152
153 mClientCount = 0;
154 mRunning = false;
155
156 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700157
158 return NO_ERROR;
159}
160
Steve Kondik7225c7f2017-06-14 00:06:16 -0700161size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700162 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700163 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700164 mClientCount++;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700165 InputDevice::start(mWidth, mHeight);
Steve Kondik77754522017-06-14 17:00:33 -0700166 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700167 }
Steve Kondik7225c7f2017-06-14 00:06:16 -0700168
169 ALOGI("Client connected (%zu)", mClientCount);
170
171 return mClientCount;
Steve Kondik55db0532017-06-12 11:27:18 -0700172}
173
Steve Kondik7225c7f2017-06-14 00:06:16 -0700174size_t VNCFlinger::removeClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700175 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700176 if (mClientCount > 0) {
177 mClientCount--;
178 if (mClientCount == 0) {
Steve Kondik7225c7f2017-06-14 00:06:16 -0700179 InputDevice::stop();
Steve Kondik77754522017-06-14 17:00:33 -0700180 mEventCond.signal();
Steve Kondik7225c7f2017-06-14 00:06:16 -0700181 }
182 }
183
184 ALOGI("Client disconnected (%zu)", mClientCount);
185
186 return mClientCount;
187}
188
189ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr cl) {
Steve Kondik55db0532017-06-12 11:27:18 -0700190 ALOGV("onClientGone");
Steve Kondik7225c7f2017-06-14 00:06:16 -0700191 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
192 vf->removeClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700193 return 0;
194}
195
196enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
197 ALOGV("onNewClient");
198 cl->clientGoneHook = (ClientGoneHookPtr) VNCFlinger::onClientGone;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700199 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
200 vf->addClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700201 return RFB_CLIENT_ACCEPT;
202}
203
Steve Kondik77754522017-06-14 17:00:33 -0700204void VNCFlinger::onFrameStart(rfbClientPtr cl) {
205 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
206 vf->mUpdateMutex.lock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700207 ALOGV("frame start");
208}
209
Steve Kondik77754522017-06-14 17:00:33 -0700210void VNCFlinger::onFrameDone(rfbClientPtr cl, int status) {
211 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
212 vf->mUpdateMutex.unlock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700213 ALOGV("frame done! %d", status);
214}
215
Steve Kondik55db0532017-06-12 11:27:18 -0700216void VNCFlinger::rfbLogger(const char *format, ...) {
217 va_list args;
218 char buf[256];
219
220 va_start(args, format);
221 vsprintf(buf, format, args);
222 ALOGI("%s", buf);
223 va_end(args);
224}
Steve Kondik77754522017-06-14 17:00:33 -0700225
226void VNCFlinger::FrameListener::onFrameAvailable(const BufferItem& item) {
227 Mutex::Autolock _l(mVNC->mEventMutex);
228 mVNC->mFrameAvailable = true;
229 mVNC->mEventCond.signal();
230 ALOGV("onFrameAvailable: mTimestamp=%ld mFrameNumber=%ld",
231 item.mTimestamp, item.mFrameNumber);
232}
233
234void VNCFlinger::processFrame() {
235 ALOGV("processFrame\n");
236
237 // Take the update mutex. This ensures that we don't dequeue
238 // a new buffer and blow away the one being sent to a client.
239 // The BufferQueue is self-regulating and will drop frames
240 // automatically for us.
241 Mutex::Autolock _l(mUpdateMutex);
242
243 CpuConsumer::LockedBuffer imgBuffer;
244 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
245 if (res != OK) {
246 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
247 return;
248 }
249
250 ALOGV("processFrame: ptr: %p format: %x (%dx%d, stride=%d)",
251 imgBuffer.data, imgBuffer.format, imgBuffer.width,
252 imgBuffer.height, imgBuffer.stride);
253
254 void* vncbuf = mVNCScreen->frameBuffer;
255 void* imgbuf = imgBuffer.data;
256
257 // Copy the frame to the server's buffer
258 if (imgBuffer.stride > mWidth) {
259 // Image has larger stride, so we need to copy row by row
260 for (size_t y = 0; y < mHeight; y++) {
261 memcpy(vncbuf, imgbuf, mWidth * 4);
262 vncbuf = (void *)((char *)vncbuf + mWidth * 4);
263 imgbuf = (void *)((char *)imgbuf + imgBuffer.stride * 4);
264 }
265 } else {
266 memcpy(vncbuf, imgbuf, mWidth * mHeight * 4);
267 }
268
269 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
270
271 mCpuConsumer->unlockBuffer(imgBuffer);
272}