blob: fa28bbd547cc3481e032f202a47223e186263927 [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 mMainDpy = SurfaceComposerClient::getBuiltInDisplay(
40 ISurfaceComposer::eDisplayIdMain);
Steve Kondik77754522017-06-14 17:00:33 -070041
Steve Kondik6ec5bc82017-06-15 01:31:51 -070042 updateDisplayProjection();
43
44 status_t err = createVNCServer();
Steve Kondik55db0532017-06-12 11:27:18 -070045 if (err != NO_ERROR) {
46 ALOGE("Failed to start VNCFlinger: err=%d", err);
47 return err;
48 }
49
Steve Kondik55db0532017-06-12 11:27:18 -070050 rfbRunEventLoop(mVNCScreen, -1, true);
Steve Kondik7225c7f2017-06-14 00:06:16 -070051
Steve Kondik6ec5bc82017-06-15 01:31:51 -070052 ALOGD("VNCFlinger is running!");
53
Steve Kondik77754522017-06-14 17:00:33 -070054 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -070055
Steve Kondik55db0532017-06-12 11:27:18 -070056 return NO_ERROR;
57}
58
Steve Kondik77754522017-06-14 17:00:33 -070059void VNCFlinger::eventLoop() {
60 mRunning = true;
61
62 Mutex::Autolock _l(mEventMutex);
63 while (mRunning) {
64 mEventCond.wait(mEventMutex);
65
66 // spurious wakeup? never.
67 if (mClientCount == 0) {
68 continue;
69 }
70
71 // this is a new client, so fire everything up
72 status_t err = createVirtualDisplay();
73 if (err != NO_ERROR) {
74 ALOGE("Failed to create virtual display: err=%d", err);
75 }
76
77 // loop while clients are connected and process frames
78 // on the main thread when signalled
79 while (mClientCount > 0) {
80 mEventCond.wait(mEventMutex);
81 if (mFrameAvailable) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -070082 if (!updateDisplayProjection()) {
83 processFrame();
84 }
Steve Kondik77754522017-06-14 17:00:33 -070085 mFrameAvailable = false;
86 }
87 }
Steve Kondik6ec5bc82017-06-15 01:31:51 -070088 Mutex::Autolock _l(mUpdateMutex);
89 destroyVirtualDisplayLocked();
Steve Kondik77754522017-06-14 17:00:33 -070090 }
91}
92
93status_t VNCFlinger::createVirtualDisplay() {
94 sp<IGraphicBufferConsumer> consumer;
95 BufferQueue::createBufferQueue(&mProducer, &consumer);
96 mCpuConsumer = new CpuConsumer(consumer, 1);
97 mCpuConsumer->setName(String8("vds-to-cpu"));
98 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
99 mProducer->setMaxDequeuedBufferCount(4);
100
101 mListener = new FrameListener(this);
102 mCpuConsumer->setFrameAvailableListener(mListener);
103
104 mDpy = SurfaceComposerClient::createDisplay(
105 String8("VNC-VirtualDisplay"), false /*secure*/);
106
107 SurfaceComposerClient::openGlobalTransaction();
108 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
109 //setDisplayProjection(mDpy, mainDpyInfo);
110 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
111 SurfaceComposerClient::closeGlobalTransaction();
112
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700113 mVDSActive = true;
114
115 ALOGV("Virtual display (%dx%d) created", mWidth, mHeight);
116
Steve Kondik77754522017-06-14 17:00:33 -0700117 return NO_ERROR;
118}
119
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700120status_t VNCFlinger::destroyVirtualDisplayLocked() {
121
Steve Kondik77754522017-06-14 17:00:33 -0700122 mCpuConsumer.clear();
123 mProducer.clear();
124 SurfaceComposerClient::destroyDisplay(mDpy);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700125
126 mVDSActive = false;
127
128 ALOGV("Virtual display destroyed");
129
Steve Kondik77754522017-06-14 17:00:33 -0700130 return NO_ERROR;
131}
132
133status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700134
135 status_t err = NO_ERROR;
136
Steve Kondik55db0532017-06-12 11:27:18 -0700137 rfbLog = VNCFlinger::rfbLogger;
138 rfbErr = VNCFlinger::rfbLogger;
139
140 // 32-bit color
141 mVNCScreen = rfbGetScreen(&mArgc, mArgv, mWidth, mHeight, 8, 3, 4);
142 if (mVNCScreen == NULL) {
143 ALOGE("Unable to create VNCScreen");
144 return NO_INIT;
145 }
146
Steve Kondikdda11002017-06-13 08:20:27 -0700147 mVNCBuf = new uint8_t[mWidth * mHeight * 4];
148 mVNCScreen->frameBuffer = (char *) mVNCBuf;
Steve Kondik55db0532017-06-12 11:27:18 -0700149 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700150 mVNCScreen->alwaysShared = TRUE;
151 mVNCScreen->httpDir = NULL;
152 mVNCScreen->port = VNC_PORT;
153 mVNCScreen->newClientHook = (rfbNewClientHookPtr) VNCFlinger::onNewClient;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700154 mVNCScreen->kbdAddEvent = InputDevice::onKeyEvent;
155 mVNCScreen->ptrAddEvent = InputDevice::onPointerEvent;
Steve Kondikef4e8652017-06-14 15:07:54 -0700156 mVNCScreen->displayHook = (rfbDisplayHookPtr) VNCFlinger::onFrameStart;
157 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr) VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700158 mVNCScreen->serverFormat.trueColour = true;
159 mVNCScreen->serverFormat.bitsPerPixel = 32;
160 mVNCScreen->handleEventsEagerly = true;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700161 mVNCScreen->deferUpdateTime = 1;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700162 mVNCScreen->screenData = this;
Steve Kondik55db0532017-06-12 11:27:18 -0700163 rfbInitServer(mVNCScreen);
164
165 /* Mark as dirty since we haven't sent any updates at all yet. */
166 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
167
168 return err;
169}
170
Steve Kondik55db0532017-06-12 11:27:18 -0700171status_t VNCFlinger::stop() {
Steve Kondik77754522017-06-14 17:00:33 -0700172 Mutex::Autolock _L(mEventMutex);
173
174 mClientCount = 0;
175 mRunning = false;
176
177 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700178
179 return NO_ERROR;
180}
181
Steve Kondik7225c7f2017-06-14 00:06:16 -0700182size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700183 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700184 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700185 mClientCount++;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700186 updateFBSize(mWidth, mHeight, mWidth);
187 InputDevice::getInstance().start(mWidth, mHeight);
Steve Kondik77754522017-06-14 17:00:33 -0700188 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700189 }
Steve Kondik7225c7f2017-06-14 00:06:16 -0700190
191 ALOGI("Client connected (%zu)", mClientCount);
192
193 return mClientCount;
Steve Kondik55db0532017-06-12 11:27:18 -0700194}
195
Steve Kondik7225c7f2017-06-14 00:06:16 -0700196size_t VNCFlinger::removeClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700197 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700198 if (mClientCount > 0) {
199 mClientCount--;
200 if (mClientCount == 0) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700201 InputDevice::getInstance().stop();
Steve Kondik77754522017-06-14 17:00:33 -0700202 mEventCond.signal();
Steve Kondik7225c7f2017-06-14 00:06:16 -0700203 }
204 }
205
206 ALOGI("Client disconnected (%zu)", mClientCount);
207
208 return mClientCount;
209}
210
211ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr cl) {
Steve Kondik55db0532017-06-12 11:27:18 -0700212 ALOGV("onClientGone");
Steve Kondik7225c7f2017-06-14 00:06:16 -0700213 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
214 vf->removeClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700215 return 0;
216}
217
218enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
219 ALOGV("onNewClient");
220 cl->clientGoneHook = (ClientGoneHookPtr) VNCFlinger::onClientGone;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700221 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
222 vf->addClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700223 return RFB_CLIENT_ACCEPT;
224}
225
Steve Kondik77754522017-06-14 17:00:33 -0700226void VNCFlinger::onFrameStart(rfbClientPtr cl) {
227 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
228 vf->mUpdateMutex.lock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700229 ALOGV("frame start");
230}
231
Steve Kondik77754522017-06-14 17:00:33 -0700232void VNCFlinger::onFrameDone(rfbClientPtr cl, int status) {
233 VNCFlinger *vf = (VNCFlinger *)cl->screen->screenData;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700234
235 if (vf->mInputReconfigPending) {
236 //InputDevice::getInstance().reconfigure(vf->mWidth, vf->mHeight);
237 vf->mInputReconfigPending = false;
238 }
Steve Kondik77754522017-06-14 17:00:33 -0700239 vf->mUpdateMutex.unlock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700240 ALOGV("frame done! %d", status);
241}
242
Steve Kondik55db0532017-06-12 11:27:18 -0700243void VNCFlinger::rfbLogger(const char *format, ...) {
244 va_list args;
245 char buf[256];
246
247 va_start(args, format);
248 vsprintf(buf, format, args);
249 ALOGI("%s", buf);
250 va_end(args);
251}
Steve Kondik77754522017-06-14 17:00:33 -0700252
253void VNCFlinger::FrameListener::onFrameAvailable(const BufferItem& item) {
254 Mutex::Autolock _l(mVNC->mEventMutex);
255 mVNC->mFrameAvailable = true;
256 mVNC->mEventCond.signal();
257 ALOGV("onFrameAvailable: mTimestamp=%ld mFrameNumber=%ld",
258 item.mTimestamp, item.mFrameNumber);
259}
260
261void VNCFlinger::processFrame() {
262 ALOGV("processFrame\n");
263
264 // Take the update mutex. This ensures that we don't dequeue
265 // a new buffer and blow away the one being sent to a client.
266 // The BufferQueue is self-regulating and will drop frames
267 // automatically for us.
268 Mutex::Autolock _l(mUpdateMutex);
269
270 CpuConsumer::LockedBuffer imgBuffer;
271 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
272 if (res != OK) {
273 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
274 return;
275 }
276
277 ALOGV("processFrame: ptr: %p format: %x (%dx%d, stride=%d)",
278 imgBuffer.data, imgBuffer.format, imgBuffer.width,
279 imgBuffer.height, imgBuffer.stride);
280
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700281 updateFBSize(imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700282
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700283 memcpy(mVNCBuf, imgBuffer.data, imgBuffer.stride * imgBuffer.height * 4);
Steve Kondik77754522017-06-14 17:00:33 -0700284
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700285 rfbMarkRectAsModified(mVNCScreen, 0, 0, imgBuffer.width, imgBuffer.height);
Steve Kondik77754522017-06-14 17:00:33 -0700286
287 mCpuConsumer->unlockBuffer(imgBuffer);
288}
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700289
290/*
291 * Returns "true" if the device is rotated 90 degrees.
292 */
293bool VNCFlinger::isDeviceRotated(int orientation) {
294 return orientation != DISPLAY_ORIENTATION_0 &&
295 orientation != DISPLAY_ORIENTATION_180;
296}
297
298/*
299 * Sets the display projection, based on the display dimensions, video size,
300 * and device orientation.
301 */
302bool VNCFlinger::updateDisplayProjection() {
303
304 DisplayInfo info;
305 status_t err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &info);
306 if (err != NO_ERROR) {
307 ALOGE("Failed to get display characteristics\n");
308 return true;
309 }
310
311 if (info.orientation == mOrientation) {
312 return false;
313 }
314
315 // Set the region of the layer stack we're interested in, which in our
316 // case is "all of it". If the app is rotated (so that the width of the
317 // app is based on the height of the display), reverse width/height.
318 bool deviceRotated = isDeviceRotated(info.orientation);
319 int sourceWidth, sourceHeight;
320 if (!deviceRotated) {
321 sourceWidth = info.w;
322 sourceHeight = info.h;
323 } else {
324 ALOGV("using rotated width/height");
325 sourceHeight = info.w;
326 sourceWidth = info.h;
327 }
328
329 Mutex::Autolock _l(mUpdateMutex);
330 mWidth = sourceWidth;
331 mHeight = sourceHeight;
332 mOrientation = info.orientation;
333
334 if (!mVDSActive) {
335 return true;
336 }
337
338 destroyVirtualDisplayLocked();
339 createVirtualDisplay();
340 return true;
341}
342
343status_t VNCFlinger::updateFBSize(int width, int height, int stride) {
344 if ((mVNCScreen->paddedWidthInBytes / 4) != stride ||
345 mVNCScreen->height != height ||
346 mVNCScreen->width != width) {
347
348 ALOGD("updateFBSize: old=[%dx%d %d] new=[%dx%d %d]",
349 mVNCScreen->width, mVNCScreen->height, mVNCScreen->paddedWidthInBytes / 4,
350 width, height, stride);
351
352 delete[] mVNCBuf;
353 mVNCBuf = new uint8_t[stride * height * 4];
354 memset(mVNCBuf, 0, stride * height * 4);
355
356 // little dance here to avoid an ugly immediate resize
357 if (mVNCScreen->height != height || mVNCScreen->width != width) {
358 mInputReconfigPending = true;
359 rfbNewFramebuffer(mVNCScreen, (char *)mVNCBuf, width, height, 8, 3, 4);
360 } else {
361 mVNCScreen->frameBuffer = (char *)mVNCBuf;
362 }
363 mVNCScreen->paddedWidthInBytes = stride * 4;
364 }
365 return NO_ERROR;
366}