blob: d1670ceea2a5b3cc7ab1e4289e6fd9cfe62a20ac [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 Kondik55db0532017-06-12 11:27:18 -070034status_t VNCFlinger::start() {
Steve Kondik77754522017-06-14 17:00:33 -070035 sp<ProcessState> self = ProcessState::self();
36 self->startThreadPool();
Steve Kondik55db0532017-06-12 11:27:18 -070037
Steve Kondik2c9d0cf2017-06-15 23:39:29 -070038 mMainDpy = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
Steve Kondik77754522017-06-14 17:00:33 -070039
Steve Kondik6ec5bc82017-06-15 01:31:51 -070040 updateDisplayProjection();
41
42 status_t err = createVNCServer();
Steve Kondik55db0532017-06-12 11:27:18 -070043 if (err != NO_ERROR) {
44 ALOGE("Failed to start VNCFlinger: err=%d", err);
45 return err;
46 }
47
Steve Kondik55db0532017-06-12 11:27:18 -070048 rfbRunEventLoop(mVNCScreen, -1, true);
Steve Kondik7225c7f2017-06-14 00:06:16 -070049
Steve Kondik46798992017-06-15 23:58:54 -070050 ALOGD("VNCFlinger ready to fling");
Steve Kondik6ec5bc82017-06-15 01:31:51 -070051
Steve Kondik77754522017-06-14 17:00:33 -070052 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -070053
Steve Kondik46798992017-06-15 23:58:54 -070054 ALOGI("VNCFlinger has left the building");
55
56 return NO_ERROR;
57}
58
59status_t VNCFlinger::stop() {
60 Mutex::Autolock _L(mEventMutex);
61
62 ALOGV("Shutting down");
63
64 destroyVirtualDisplayLocked();
65 mClientCount = 0;
66 mRunning = false;
67
68 mEventCond.signal();
69
Steve Kondik55db0532017-06-12 11:27:18 -070070 return NO_ERROR;
71}
72
Steve Kondik77754522017-06-14 17:00:33 -070073void VNCFlinger::eventLoop() {
74 mRunning = true;
75
76 Mutex::Autolock _l(mEventMutex);
77 while (mRunning) {
78 mEventCond.wait(mEventMutex);
79
80 // spurious wakeup? never.
81 if (mClientCount == 0) {
82 continue;
83 }
84
85 // this is a new client, so fire everything up
86 status_t err = createVirtualDisplay();
87 if (err != NO_ERROR) {
88 ALOGE("Failed to create virtual display: err=%d", err);
89 }
90
91 // loop while clients are connected and process frames
92 // on the main thread when signalled
93 while (mClientCount > 0) {
94 mEventCond.wait(mEventMutex);
95 if (mFrameAvailable) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -070096 if (!updateDisplayProjection()) {
97 processFrame();
98 }
Steve Kondik77754522017-06-14 17:00:33 -070099 mFrameAvailable = false;
100 }
101 }
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700102 Mutex::Autolock _l(mUpdateMutex);
103 destroyVirtualDisplayLocked();
Steve Kondik77754522017-06-14 17:00:33 -0700104 }
105}
106
107status_t VNCFlinger::createVirtualDisplay() {
108 sp<IGraphicBufferConsumer> consumer;
109 BufferQueue::createBufferQueue(&mProducer, &consumer);
110 mCpuConsumer = new CpuConsumer(consumer, 1);
111 mCpuConsumer->setName(String8("vds-to-cpu"));
112 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
113 mProducer->setMaxDequeuedBufferCount(4);
114
115 mListener = new FrameListener(this);
116 mCpuConsumer->setFrameAvailableListener(mListener);
117
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700118 mDpy = SurfaceComposerClient::createDisplay(String8("VNC-VirtualDisplay"), false /*secure*/);
Steve Kondik77754522017-06-14 17:00:33 -0700119
120 SurfaceComposerClient::openGlobalTransaction();
121 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700122 // setDisplayProjection(mDpy, mainDpyInfo);
123 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
Steve Kondik77754522017-06-14 17:00:33 -0700124 SurfaceComposerClient::closeGlobalTransaction();
125
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700126 mVDSActive = true;
127
128 ALOGV("Virtual display (%dx%d) created", mWidth, mHeight);
129
Steve Kondik77754522017-06-14 17:00:33 -0700130 return NO_ERROR;
131}
132
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700133status_t VNCFlinger::destroyVirtualDisplayLocked() {
Steve Kondik46798992017-06-15 23:58:54 -0700134 if (!mVDSActive) {
135 return NO_INIT;
136 }
137
Steve Kondik77754522017-06-14 17:00:33 -0700138 mCpuConsumer.clear();
139 mProducer.clear();
140 SurfaceComposerClient::destroyDisplay(mDpy);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700141
142 mVDSActive = false;
143
144 ALOGV("Virtual display destroyed");
145
Steve Kondik77754522017-06-14 17:00:33 -0700146 return NO_ERROR;
147}
148
149status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700150 status_t err = NO_ERROR;
151
Steve Kondik55db0532017-06-12 11:27:18 -0700152 rfbLog = VNCFlinger::rfbLogger;
153 rfbErr = VNCFlinger::rfbLogger;
154
155 // 32-bit color
156 mVNCScreen = rfbGetScreen(&mArgc, mArgv, mWidth, mHeight, 8, 3, 4);
157 if (mVNCScreen == NULL) {
158 ALOGE("Unable to create VNCScreen");
159 return NO_INIT;
160 }
161
Steve Kondikdda11002017-06-13 08:20:27 -0700162 mVNCBuf = new uint8_t[mWidth * mHeight * 4];
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700163 mVNCScreen->frameBuffer = (char*)mVNCBuf;
Steve Kondik55db0532017-06-12 11:27:18 -0700164 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700165 mVNCScreen->alwaysShared = TRUE;
166 mVNCScreen->httpDir = NULL;
167 mVNCScreen->port = VNC_PORT;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700168 mVNCScreen->newClientHook = (rfbNewClientHookPtr)VNCFlinger::onNewClient;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700169 mVNCScreen->kbdAddEvent = InputDevice::onKeyEvent;
170 mVNCScreen->ptrAddEvent = InputDevice::onPointerEvent;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700171 mVNCScreen->displayHook = (rfbDisplayHookPtr)VNCFlinger::onFrameStart;
172 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr)VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700173 mVNCScreen->serverFormat.trueColour = true;
174 mVNCScreen->serverFormat.bitsPerPixel = 32;
175 mVNCScreen->handleEventsEagerly = true;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700176 mVNCScreen->deferUpdateTime = 1;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700177 mVNCScreen->screenData = this;
Steve Kondik55db0532017-06-12 11:27:18 -0700178 rfbInitServer(mVNCScreen);
179
180 /* Mark as dirty since we haven't sent any updates at all yet. */
181 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
182
183 return err;
184}
185
Steve Kondik7225c7f2017-06-14 00:06:16 -0700186size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700187 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700188 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700189 mClientCount++;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700190 updateFBSize(mWidth, mHeight, mWidth);
191 InputDevice::getInstance().start(mWidth, mHeight);
Steve Kondik77754522017-06-14 17:00:33 -0700192 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700193 }
Steve Kondik7225c7f2017-06-14 00:06:16 -0700194
195 ALOGI("Client connected (%zu)", mClientCount);
196
197 return mClientCount;
Steve Kondik55db0532017-06-12 11:27:18 -0700198}
199
Steve Kondik7225c7f2017-06-14 00:06:16 -0700200size_t VNCFlinger::removeClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700201 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700202 if (mClientCount > 0) {
203 mClientCount--;
204 if (mClientCount == 0) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700205 InputDevice::getInstance().stop();
Steve Kondik77754522017-06-14 17:00:33 -0700206 mEventCond.signal();
Steve Kondik7225c7f2017-06-14 00:06:16 -0700207 }
208 }
209
210 ALOGI("Client disconnected (%zu)", mClientCount);
211
212 return mClientCount;
213}
214
215ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr cl) {
Steve Kondik55db0532017-06-12 11:27:18 -0700216 ALOGV("onClientGone");
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700217 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700218 vf->removeClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700219 return 0;
220}
221
222enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
223 ALOGV("onNewClient");
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700224 cl->clientGoneHook = (ClientGoneHookPtr)VNCFlinger::onClientGone;
225 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700226 vf->addClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700227 return RFB_CLIENT_ACCEPT;
228}
229
Steve Kondik77754522017-06-14 17:00:33 -0700230void VNCFlinger::onFrameStart(rfbClientPtr cl) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700231 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik77754522017-06-14 17:00:33 -0700232 vf->mUpdateMutex.lock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700233 ALOGV("frame start");
234}
235
Steve Kondik77754522017-06-14 17:00:33 -0700236void VNCFlinger::onFrameDone(rfbClientPtr cl, int status) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700237 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik77754522017-06-14 17:00:33 -0700238 vf->mUpdateMutex.unlock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700239 ALOGV("frame done! %d", status);
240}
241
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700242void VNCFlinger::rfbLogger(const char* format, ...) {
Steve Kondik55db0532017-06-12 11:27:18 -0700243 va_list args;
244 char buf[256];
245
246 va_start(args, format);
247 vsprintf(buf, format, args);
248 ALOGI("%s", buf);
249 va_end(args);
250}
Steve Kondik77754522017-06-14 17:00:33 -0700251
252void VNCFlinger::FrameListener::onFrameAvailable(const BufferItem& item) {
253 Mutex::Autolock _l(mVNC->mEventMutex);
254 mVNC->mFrameAvailable = true;
255 mVNC->mEventCond.signal();
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700256 ALOGV("onFrameAvailable: mTimestamp=%ld mFrameNumber=%ld", item.mTimestamp, item.mFrameNumber);
Steve Kondik77754522017-06-14 17:00:33 -0700257}
258
259void VNCFlinger::processFrame() {
260 ALOGV("processFrame\n");
261
262 // Take the update mutex. This ensures that we don't dequeue
263 // a new buffer and blow away the one being sent to a client.
264 // The BufferQueue is self-regulating and will drop frames
265 // automatically for us.
266 Mutex::Autolock _l(mUpdateMutex);
267
268 CpuConsumer::LockedBuffer imgBuffer;
269 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
270 if (res != OK) {
271 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
272 return;
273 }
274
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700275 ALOGV("processFrame: ptr: %p format: %x (%dx%d, stride=%d)", imgBuffer.data, imgBuffer.format,
276 imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700277
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700278 updateFBSize(imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700279
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700280 memcpy(mVNCBuf, imgBuffer.data, imgBuffer.stride * imgBuffer.height * 4);
Steve Kondik77754522017-06-14 17:00:33 -0700281
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700282 rfbMarkRectAsModified(mVNCScreen, 0, 0, imgBuffer.width, imgBuffer.height);
Steve Kondik77754522017-06-14 17:00:33 -0700283
284 mCpuConsumer->unlockBuffer(imgBuffer);
285}
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700286
287/*
288 * Returns "true" if the device is rotated 90 degrees.
289 */
290bool VNCFlinger::isDeviceRotated(int orientation) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700291 return orientation != DISPLAY_ORIENTATION_0 && orientation != DISPLAY_ORIENTATION_180;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700292}
293
294/*
295 * Sets the display projection, based on the display dimensions, video size,
296 * and device orientation.
297 */
298bool VNCFlinger::updateDisplayProjection() {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700299 DisplayInfo info;
300 status_t err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &info);
301 if (err != NO_ERROR) {
302 ALOGE("Failed to get display characteristics\n");
303 return true;
304 }
305
306 if (info.orientation == mOrientation) {
307 return false;
308 }
309
310 // Set the region of the layer stack we're interested in, which in our
311 // case is "all of it". If the app is rotated (so that the width of the
312 // app is based on the height of the display), reverse width/height.
313 bool deviceRotated = isDeviceRotated(info.orientation);
314 int sourceWidth, sourceHeight;
315 if (!deviceRotated) {
316 sourceWidth = info.w;
317 sourceHeight = info.h;
318 } else {
319 ALOGV("using rotated width/height");
320 sourceHeight = info.w;
321 sourceWidth = info.h;
322 }
323
324 Mutex::Autolock _l(mUpdateMutex);
325 mWidth = sourceWidth;
326 mHeight = sourceHeight;
327 mOrientation = info.orientation;
328
329 if (!mVDSActive) {
330 return true;
331 }
332
333 destroyVirtualDisplayLocked();
334 createVirtualDisplay();
335 return true;
336}
337
338status_t VNCFlinger::updateFBSize(int width, int height, int stride) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700339 if ((mVNCScreen->paddedWidthInBytes / 4) != stride || mVNCScreen->height != height ||
340 mVNCScreen->width != width) {
341 ALOGD("updateFBSize: old=[%dx%d %d] new=[%dx%d %d]", mVNCScreen->width, mVNCScreen->height,
342 mVNCScreen->paddedWidthInBytes / 4, width, height, stride);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700343
344 delete[] mVNCBuf;
345 mVNCBuf = new uint8_t[stride * height * 4];
346 memset(mVNCBuf, 0, stride * height * 4);
347
348 // little dance here to avoid an ugly immediate resize
349 if (mVNCScreen->height != height || mVNCScreen->width != width) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700350 rfbNewFramebuffer(mVNCScreen, (char*)mVNCBuf, width, height, 8, 3, 4);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700351 } else {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700352 mVNCScreen->frameBuffer = (char*)mVNCBuf;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700353 }
354 mVNCScreen->paddedWidthInBytes = stride * 4;
355 }
356 return NO_ERROR;
357}