blob: 37a861419778e190382e6f6970701e9a8b18ace6 [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 Kondik6ec5bc82017-06-15 01:31:51 -070050 ALOGD("VNCFlinger is running!");
51
Steve Kondik77754522017-06-14 17:00:33 -070052 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -070053
Steve Kondik55db0532017-06-12 11:27:18 -070054 return NO_ERROR;
55}
56
Steve Kondik77754522017-06-14 17:00:33 -070057void VNCFlinger::eventLoop() {
58 mRunning = true;
59
60 Mutex::Autolock _l(mEventMutex);
61 while (mRunning) {
62 mEventCond.wait(mEventMutex);
63
64 // spurious wakeup? never.
65 if (mClientCount == 0) {
66 continue;
67 }
68
69 // this is a new client, so fire everything up
70 status_t err = createVirtualDisplay();
71 if (err != NO_ERROR) {
72 ALOGE("Failed to create virtual display: err=%d", err);
73 }
74
75 // loop while clients are connected and process frames
76 // on the main thread when signalled
77 while (mClientCount > 0) {
78 mEventCond.wait(mEventMutex);
79 if (mFrameAvailable) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -070080 if (!updateDisplayProjection()) {
81 processFrame();
82 }
Steve Kondik77754522017-06-14 17:00:33 -070083 mFrameAvailable = false;
84 }
85 }
Steve Kondik6ec5bc82017-06-15 01:31:51 -070086 Mutex::Autolock _l(mUpdateMutex);
87 destroyVirtualDisplayLocked();
Steve Kondik77754522017-06-14 17:00:33 -070088 }
89}
90
91status_t VNCFlinger::createVirtualDisplay() {
92 sp<IGraphicBufferConsumer> consumer;
93 BufferQueue::createBufferQueue(&mProducer, &consumer);
94 mCpuConsumer = new CpuConsumer(consumer, 1);
95 mCpuConsumer->setName(String8("vds-to-cpu"));
96 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
97 mProducer->setMaxDequeuedBufferCount(4);
98
99 mListener = new FrameListener(this);
100 mCpuConsumer->setFrameAvailableListener(mListener);
101
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700102 mDpy = SurfaceComposerClient::createDisplay(String8("VNC-VirtualDisplay"), false /*secure*/);
Steve Kondik77754522017-06-14 17:00:33 -0700103
104 SurfaceComposerClient::openGlobalTransaction();
105 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700106 // setDisplayProjection(mDpy, mainDpyInfo);
107 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
Steve Kondik77754522017-06-14 17:00:33 -0700108 SurfaceComposerClient::closeGlobalTransaction();
109
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700110 mVDSActive = true;
111
112 ALOGV("Virtual display (%dx%d) created", mWidth, mHeight);
113
Steve Kondik77754522017-06-14 17:00:33 -0700114 return NO_ERROR;
115}
116
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700117status_t VNCFlinger::destroyVirtualDisplayLocked() {
Steve Kondik77754522017-06-14 17:00:33 -0700118 mCpuConsumer.clear();
119 mProducer.clear();
120 SurfaceComposerClient::destroyDisplay(mDpy);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700121
122 mVDSActive = false;
123
124 ALOGV("Virtual display destroyed");
125
Steve Kondik77754522017-06-14 17:00:33 -0700126 return NO_ERROR;
127}
128
129status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700130 status_t err = NO_ERROR;
131
Steve Kondik55db0532017-06-12 11:27:18 -0700132 rfbLog = VNCFlinger::rfbLogger;
133 rfbErr = VNCFlinger::rfbLogger;
134
135 // 32-bit color
136 mVNCScreen = rfbGetScreen(&mArgc, mArgv, mWidth, mHeight, 8, 3, 4);
137 if (mVNCScreen == NULL) {
138 ALOGE("Unable to create VNCScreen");
139 return NO_INIT;
140 }
141
Steve Kondikdda11002017-06-13 08:20:27 -0700142 mVNCBuf = new uint8_t[mWidth * mHeight * 4];
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700143 mVNCScreen->frameBuffer = (char*)mVNCBuf;
Steve Kondik55db0532017-06-12 11:27:18 -0700144 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700145 mVNCScreen->alwaysShared = TRUE;
146 mVNCScreen->httpDir = NULL;
147 mVNCScreen->port = VNC_PORT;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700148 mVNCScreen->newClientHook = (rfbNewClientHookPtr)VNCFlinger::onNewClient;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700149 mVNCScreen->kbdAddEvent = InputDevice::onKeyEvent;
150 mVNCScreen->ptrAddEvent = InputDevice::onPointerEvent;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700151 mVNCScreen->displayHook = (rfbDisplayHookPtr)VNCFlinger::onFrameStart;
152 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr)VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700153 mVNCScreen->serverFormat.trueColour = true;
154 mVNCScreen->serverFormat.bitsPerPixel = 32;
155 mVNCScreen->handleEventsEagerly = true;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700156 mVNCScreen->deferUpdateTime = 1;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700157 mVNCScreen->screenData = this;
Steve Kondik55db0532017-06-12 11:27:18 -0700158 rfbInitServer(mVNCScreen);
159
160 /* Mark as dirty since we haven't sent any updates at all yet. */
161 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
162
163 return err;
164}
165
Steve Kondik55db0532017-06-12 11:27:18 -0700166status_t VNCFlinger::stop() {
Steve Kondik77754522017-06-14 17:00:33 -0700167 Mutex::Autolock _L(mEventMutex);
168
169 mClientCount = 0;
170 mRunning = false;
171
172 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700173
174 return NO_ERROR;
175}
176
Steve Kondik7225c7f2017-06-14 00:06:16 -0700177size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700178 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700179 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700180 mClientCount++;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700181 updateFBSize(mWidth, mHeight, mWidth);
182 InputDevice::getInstance().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 Kondik6ec5bc82017-06-15 01:31:51 -0700196 InputDevice::getInstance().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 Kondik2c9d0cf2017-06-15 23:39:29 -0700208 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700209 vf->removeClient();
Steve Kondik55db0532017-06-12 11:27:18 -0700210 return 0;
211}
212
213enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
214 ALOGV("onNewClient");
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700215 cl->clientGoneHook = (ClientGoneHookPtr)VNCFlinger::onClientGone;
216 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700217 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) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700222 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik77754522017-06-14 17:00:33 -0700223 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) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700228 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
Steve Kondik77754522017-06-14 17:00:33 -0700229 vf->mUpdateMutex.unlock();
Steve Kondikef4e8652017-06-14 15:07:54 -0700230 ALOGV("frame done! %d", status);
231}
232
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700233void VNCFlinger::rfbLogger(const char* format, ...) {
Steve Kondik55db0532017-06-12 11:27:18 -0700234 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();
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700247 ALOGV("onFrameAvailable: mTimestamp=%ld mFrameNumber=%ld", item.mTimestamp, item.mFrameNumber);
Steve Kondik77754522017-06-14 17:00:33 -0700248}
249
250void VNCFlinger::processFrame() {
251 ALOGV("processFrame\n");
252
253 // Take the update mutex. This ensures that we don't dequeue
254 // a new buffer and blow away the one being sent to a client.
255 // The BufferQueue is self-regulating and will drop frames
256 // automatically for us.
257 Mutex::Autolock _l(mUpdateMutex);
258
259 CpuConsumer::LockedBuffer imgBuffer;
260 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
261 if (res != OK) {
262 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
263 return;
264 }
265
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700266 ALOGV("processFrame: ptr: %p format: %x (%dx%d, stride=%d)", imgBuffer.data, imgBuffer.format,
267 imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700268
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700269 updateFBSize(imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700270
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700271 memcpy(mVNCBuf, imgBuffer.data, imgBuffer.stride * imgBuffer.height * 4);
Steve Kondik77754522017-06-14 17:00:33 -0700272
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700273 rfbMarkRectAsModified(mVNCScreen, 0, 0, imgBuffer.width, imgBuffer.height);
Steve Kondik77754522017-06-14 17:00:33 -0700274
275 mCpuConsumer->unlockBuffer(imgBuffer);
276}
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700277
278/*
279 * Returns "true" if the device is rotated 90 degrees.
280 */
281bool VNCFlinger::isDeviceRotated(int orientation) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700282 return orientation != DISPLAY_ORIENTATION_0 && orientation != DISPLAY_ORIENTATION_180;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700283}
284
285/*
286 * Sets the display projection, based on the display dimensions, video size,
287 * and device orientation.
288 */
289bool VNCFlinger::updateDisplayProjection() {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700290 DisplayInfo info;
291 status_t err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &info);
292 if (err != NO_ERROR) {
293 ALOGE("Failed to get display characteristics\n");
294 return true;
295 }
296
297 if (info.orientation == mOrientation) {
298 return false;
299 }
300
301 // Set the region of the layer stack we're interested in, which in our
302 // case is "all of it". If the app is rotated (so that the width of the
303 // app is based on the height of the display), reverse width/height.
304 bool deviceRotated = isDeviceRotated(info.orientation);
305 int sourceWidth, sourceHeight;
306 if (!deviceRotated) {
307 sourceWidth = info.w;
308 sourceHeight = info.h;
309 } else {
310 ALOGV("using rotated width/height");
311 sourceHeight = info.w;
312 sourceWidth = info.h;
313 }
314
315 Mutex::Autolock _l(mUpdateMutex);
316 mWidth = sourceWidth;
317 mHeight = sourceHeight;
318 mOrientation = info.orientation;
319
320 if (!mVDSActive) {
321 return true;
322 }
323
324 destroyVirtualDisplayLocked();
325 createVirtualDisplay();
326 return true;
327}
328
329status_t VNCFlinger::updateFBSize(int width, int height, int stride) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700330 if ((mVNCScreen->paddedWidthInBytes / 4) != stride || mVNCScreen->height != height ||
331 mVNCScreen->width != width) {
332 ALOGD("updateFBSize: old=[%dx%d %d] new=[%dx%d %d]", mVNCScreen->width, mVNCScreen->height,
333 mVNCScreen->paddedWidthInBytes / 4, width, height, stride);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700334
335 delete[] mVNCBuf;
336 mVNCBuf = new uint8_t[stride * height * 4];
337 memset(mVNCBuf, 0, stride * height * 4);
338
339 // little dance here to avoid an ugly immediate resize
340 if (mVNCScreen->height != height || mVNCScreen->width != width) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700341 rfbNewFramebuffer(mVNCScreen, (char*)mVNCBuf, width, height, 8, 3, 4);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700342 } else {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700343 mVNCScreen->frameBuffer = (char*)mVNCBuf;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700344 }
345 mVNCScreen->paddedWidthInBytes = stride * 4;
346 }
347 return NO_ERROR;
348}