blob: b9b5da4822090bfe7875ad8797e26638af74d886 [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 Kondik59104ea2017-06-20 08:30:07 -070029#include <ui/PixelFormat.h>
30
Steve Kondik107d2e52017-06-13 17:34:56 -070031#include "InputDevice.h"
Steve Kondik55db0532017-06-12 11:27:18 -070032#include "VNCFlinger.h"
33
34using namespace android;
35
Steve Kondik5c8655c2017-06-19 00:28:47 -070036VNCFlinger::VNCFlinger() {
37 mOrientation = -1;
Steve Kondik59104ea2017-06-20 08:30:07 -070038 mScale = 1.0f;
Steve Kondik5c8655c2017-06-19 00:28:47 -070039 mMainDpy = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
40 updateDisplayProjection();
41
42 createVNCServer();
43
44 String8 v4("127.0.0.1");
45 String8 v6("::1");
46
Steve Kondik3db07472017-06-19 22:13:45 -070047 setV4Address(v4);
48 setV6Address(v6);
Steve Kondik5c8655c2017-06-19 00:28:47 -070049}
50
Steve Kondik3db07472017-06-19 22:13:45 -070051status_t VNCFlinger::setV4Address(const String8& address) {
Steve Kondik5c8655c2017-06-19 00:28:47 -070052 if (!rfbStringToAddr(const_cast<char *>(address.string()), &(mVNCScreen->listenInterface))) {
53 return BAD_VALUE;
54 }
55 return NO_ERROR;
56}
57
Steve Kondik3db07472017-06-19 22:13:45 -070058status_t VNCFlinger::setV6Address(const String8& address) {
Steve Kondik3db07472017-06-19 22:13:45 -070059 mVNCScreen->listen6Interface = const_cast<char *>(address.string());
60 return NO_ERROR;
61}
62
Steve Kondik5c8655c2017-06-19 00:28:47 -070063status_t VNCFlinger::setPort(unsigned int port) {
64 if (port > 65535) {
65 port = 0;
66 }
67 if (port == 0) {
68 mVNCScreen->autoPort = 1;
69 } else {
70 mVNCScreen->autoPort = 0;
71 mVNCScreen->port = port;
72 mVNCScreen->ipv6port = port;
73 }
74 return NO_ERROR;
75}
76
Steve Kondik59104ea2017-06-20 08:30:07 -070077status_t VNCFlinger::setScale(float scale) {
78 if (scale <= 0.0f || scale > 2.0f) {
79 return BAD_VALUE;
80 }
81 mScale = scale;
82 updateDisplayProjection();
83 return NO_ERROR;
84}
85
Steve Kondik5c8655c2017-06-19 00:28:47 -070086status_t VNCFlinger::clearPassword() {
87 std::remove(VNC_AUTH_FILE);
88 ALOGW("Password authentication disabled");
89 return OK;
90}
91
Steve Kondik3db07472017-06-19 22:13:45 -070092status_t VNCFlinger::setPassword(const String8& passwd) {
Steve Kondik5c8655c2017-06-19 00:28:47 -070093 String8 path(VNC_AUTH_FILE);
94 if (rfbEncryptAndStorePasswd(const_cast<char *>(passwd.string()),
95 const_cast<char *>(path.string())) != 0) {
96 ALOGE("Failed to set password");
97 return BAD_VALUE;
98 }
99 ALOGI("Password has been set");
100 return OK;
101}
102
Steve Kondik55db0532017-06-12 11:27:18 -0700103status_t VNCFlinger::start() {
Steve Kondik77754522017-06-14 17:00:33 -0700104 sp<ProcessState> self = ProcessState::self();
105 self->startThreadPool();
Steve Kondik55db0532017-06-12 11:27:18 -0700106
Steve Kondik5c8655c2017-06-19 00:28:47 -0700107 status_t err = startVNCServer();
Steve Kondik55db0532017-06-12 11:27:18 -0700108 if (err != NO_ERROR) {
109 ALOGE("Failed to start VNCFlinger: err=%d", err);
110 return err;
111 }
112
Steve Kondik55db0532017-06-12 11:27:18 -0700113 rfbRunEventLoop(mVNCScreen, -1, true);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700114
Steve Kondik46798992017-06-15 23:58:54 -0700115 ALOGD("VNCFlinger ready to fling");
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700116
Steve Kondik77754522017-06-14 17:00:33 -0700117 eventLoop();
Steve Kondik55db0532017-06-12 11:27:18 -0700118
Steve Kondik46798992017-06-15 23:58:54 -0700119 ALOGI("VNCFlinger has left the building");
120
121 return NO_ERROR;
122}
123
124status_t VNCFlinger::stop() {
125 Mutex::Autolock _L(mEventMutex);
Steve Kondik46798992017-06-15 23:58:54 -0700126 ALOGV("Shutting down");
127
Steve Kondik59104ea2017-06-20 08:30:07 -0700128 rfbShutdownServer(mVNCScreen, false);
Steve Kondik5c8655c2017-06-19 00:28:47 -0700129
Steve Kondik46798992017-06-15 23:58:54 -0700130 destroyVirtualDisplayLocked();
Steve Kondik59104ea2017-06-20 08:30:07 -0700131
Steve Kondik46798992017-06-15 23:58:54 -0700132 mClientCount = 0;
133 mRunning = false;
134
135 mEventCond.signal();
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700136 delete[] mVNCScreen->frameBuffer;
Steve Kondik55db0532017-06-12 11:27:18 -0700137 return NO_ERROR;
138}
139
Steve Kondik77754522017-06-14 17:00:33 -0700140void VNCFlinger::eventLoop() {
141 mRunning = true;
142
143 Mutex::Autolock _l(mEventMutex);
144 while (mRunning) {
145 mEventCond.wait(mEventMutex);
146
147 // spurious wakeup? never.
148 if (mClientCount == 0) {
149 continue;
150 }
151
152 // this is a new client, so fire everything up
153 status_t err = createVirtualDisplay();
154 if (err != NO_ERROR) {
155 ALOGE("Failed to create virtual display: err=%d", err);
156 }
157
158 // loop while clients are connected and process frames
159 // on the main thread when signalled
160 while (mClientCount > 0) {
161 mEventCond.wait(mEventMutex);
162 if (mFrameAvailable) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700163 if (!updateDisplayProjection()) {
164 processFrame();
165 }
Steve Kondik77754522017-06-14 17:00:33 -0700166 mFrameAvailable = false;
167 }
168 }
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700169 Mutex::Autolock _l(mUpdateMutex);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700170 memset(mVNCScreen->frameBuffer, 0, mFrameSize);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700171 destroyVirtualDisplayLocked();
Steve Kondik77754522017-06-14 17:00:33 -0700172 }
173}
174
175status_t VNCFlinger::createVirtualDisplay() {
176 sp<IGraphicBufferConsumer> consumer;
177 BufferQueue::createBufferQueue(&mProducer, &consumer);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700178 mCpuConsumer = new CpuConsumer(consumer, NUM_BUFS);
Steve Kondik77754522017-06-14 17:00:33 -0700179 mCpuConsumer->setName(String8("vds-to-cpu"));
180 mCpuConsumer->setDefaultBufferSize(mWidth, mHeight);
Steve Kondik59104ea2017-06-20 08:30:07 -0700181 mProducer->setMaxDequeuedBufferCount(1);
182 consumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBX_8888);
Steve Kondik77754522017-06-14 17:00:33 -0700183
184 mListener = new FrameListener(this);
185 mCpuConsumer->setFrameAvailableListener(mListener);
186
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700187 mDpy = SurfaceComposerClient::createDisplay(String8("VNC-VirtualDisplay"), false /*secure*/);
Steve Kondik77754522017-06-14 17:00:33 -0700188
189 SurfaceComposerClient::openGlobalTransaction();
190 SurfaceComposerClient::setDisplaySurface(mDpy, mProducer);
Steve Kondik59104ea2017-06-20 08:30:07 -0700191 Rect displayRect(0, 0, mSourceWidth, mSourceHeight);
192 Rect outRect(0, 0, mWidth, mHeight);
193 SurfaceComposerClient::setDisplayProjection(mDpy, 0, displayRect, outRect);
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700194 SurfaceComposerClient::setDisplayLayerStack(mDpy, 0); // default stack
Steve Kondik77754522017-06-14 17:00:33 -0700195 SurfaceComposerClient::closeGlobalTransaction();
196
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700197 mVDSActive = true;
198
199 ALOGV("Virtual display (%dx%d) created", mWidth, mHeight);
200
Steve Kondik77754522017-06-14 17:00:33 -0700201 return NO_ERROR;
202}
203
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700204status_t VNCFlinger::destroyVirtualDisplayLocked() {
Steve Kondik46798992017-06-15 23:58:54 -0700205 if (!mVDSActive) {
206 return NO_INIT;
207 }
208
Steve Kondik77754522017-06-14 17:00:33 -0700209 mCpuConsumer.clear();
210 mProducer.clear();
211 SurfaceComposerClient::destroyDisplay(mDpy);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700212
213 mVDSActive = false;
214
215 ALOGV("Virtual display destroyed");
216
Steve Kondik77754522017-06-14 17:00:33 -0700217 return NO_ERROR;
218}
219
220status_t VNCFlinger::createVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700221 status_t err = NO_ERROR;
222
Steve Kondik55db0532017-06-12 11:27:18 -0700223 rfbLog = VNCFlinger::rfbLogger;
224 rfbErr = VNCFlinger::rfbLogger;
225
226 // 32-bit color
Steve Kondik5c8655c2017-06-19 00:28:47 -0700227 mVNCScreen = rfbGetScreen(0, NULL, mWidth, mHeight, 8, 3, 4);
Steve Kondik55db0532017-06-12 11:27:18 -0700228 if (mVNCScreen == NULL) {
229 ALOGE("Unable to create VNCScreen");
230 return NO_INIT;
231 }
232
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700233 mFrameNumber = 0;
234 mFrameSize = mWidth * mHeight * 4;
235 mVNCScreen->frameBuffer = (char*)new uint8_t[mFrameSize];
236 memset(mVNCScreen->frameBuffer, 0, mFrameSize);
237
Steve Kondik55db0532017-06-12 11:27:18 -0700238 mVNCScreen->desktopName = "VNCFlinger";
Steve Kondik55db0532017-06-12 11:27:18 -0700239 mVNCScreen->alwaysShared = TRUE;
240 mVNCScreen->httpDir = NULL;
Steve Kondik5c8655c2017-06-19 00:28:47 -0700241 mVNCScreen->authPasswdData = (void *)VNC_AUTH_FILE;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700242 mVNCScreen->newClientHook = (rfbNewClientHookPtr)VNCFlinger::onNewClient;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700243 mVNCScreen->kbdAddEvent = InputDevice::onKeyEvent;
244 mVNCScreen->ptrAddEvent = InputDevice::onPointerEvent;
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700245 mVNCScreen->displayHook = (rfbDisplayHookPtr)VNCFlinger::onFrameStart;
246 mVNCScreen->displayFinishedHook = (rfbDisplayFinishedHookPtr)VNCFlinger::onFrameDone;
Steve Kondik55db0532017-06-12 11:27:18 -0700247 mVNCScreen->serverFormat.trueColour = true;
248 mVNCScreen->serverFormat.bitsPerPixel = 32;
Steve Kondik59104ea2017-06-20 08:30:07 -0700249 mVNCScreen->serverFormat.depth = 24;
Steve Kondik55db0532017-06-12 11:27:18 -0700250 mVNCScreen->handleEventsEagerly = true;
Steve Kondik59104ea2017-06-20 08:30:07 -0700251 mVNCScreen->deferUpdateTime = 0;
Steve Kondik7225c7f2017-06-14 00:06:16 -0700252 mVNCScreen->screenData = this;
Steve Kondik5c8655c2017-06-19 00:28:47 -0700253
254 return err;
255}
256
257status_t VNCFlinger::startVNCServer() {
Steve Kondik55db0532017-06-12 11:27:18 -0700258 rfbInitServer(mVNCScreen);
259
260 /* Mark as dirty since we haven't sent any updates at all yet. */
261 rfbMarkRectAsModified(mVNCScreen, 0, 0, mWidth, mHeight);
262
Steve Kondik5c8655c2017-06-19 00:28:47 -0700263 return NO_ERROR;
Steve Kondik55db0532017-06-12 11:27:18 -0700264}
265
Steve Kondik7225c7f2017-06-14 00:06:16 -0700266size_t VNCFlinger::addClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700267 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700268 if (mClientCount == 0) {
Steve Kondik77754522017-06-14 17:00:33 -0700269 mClientCount++;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700270 InputDevice::getInstance().start(mWidth, mHeight);
Steve Kondik77754522017-06-14 17:00:33 -0700271 mEventCond.signal();
Steve Kondik55db0532017-06-12 11:27:18 -0700272 }
Steve Kondik7225c7f2017-06-14 00:06:16 -0700273
274 ALOGI("Client connected (%zu)", mClientCount);
275
276 return mClientCount;
Steve Kondik55db0532017-06-12 11:27:18 -0700277}
278
Steve Kondik7225c7f2017-06-14 00:06:16 -0700279size_t VNCFlinger::removeClient() {
Steve Kondik77754522017-06-14 17:00:33 -0700280 Mutex::Autolock _l(mEventMutex);
Steve Kondik7225c7f2017-06-14 00:06:16 -0700281 if (mClientCount > 0) {
282 mClientCount--;
283 if (mClientCount == 0) {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700284 InputDevice::getInstance().stop();
Steve Kondik77754522017-06-14 17:00:33 -0700285 mEventCond.signal();
Steve Kondik7225c7f2017-06-14 00:06:16 -0700286 }
287 }
288
289 ALOGI("Client disconnected (%zu)", mClientCount);
290
291 return mClientCount;
292}
293
Steve Kondik77754522017-06-14 17:00:33 -0700294void VNCFlinger::processFrame() {
Steve Kondik77754522017-06-14 17:00:33 -0700295 // Take the update mutex. This ensures that we don't dequeue
296 // a new buffer and blow away the one being sent to a client.
297 // The BufferQueue is self-regulating and will drop frames
298 // automatically for us.
299 Mutex::Autolock _l(mUpdateMutex);
300
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700301 // get a frame from the virtual display
Steve Kondik77754522017-06-14 17:00:33 -0700302 CpuConsumer::LockedBuffer imgBuffer;
303 status_t res = mCpuConsumer->lockNextBuffer(&imgBuffer);
304 if (res != OK) {
305 ALOGE("Failed to lock next buffer: %s (%d)", strerror(-res), res);
306 return;
307 }
308
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700309 mFrameNumber = imgBuffer.frameNumber;
310 ALOGV("processFrame: [%lu] format: %x (%dx%d, stride=%d)", mFrameNumber, imgBuffer.format,
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700311 imgBuffer.width, imgBuffer.height, imgBuffer.stride);
Steve Kondik77754522017-06-14 17:00:33 -0700312
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700313 // we don't know if there was a stride change until we get
314 // a buffer from the queue. if it changed, we need to resize
315 updateFBSize(imgBuffer);
Steve Kondik77754522017-06-14 17:00:33 -0700316
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700317 // performance is extremely bad if the gpu memory is used
318 // directly without copying because it is likely uncached
319 memcpy(mVNCScreen->frameBuffer, imgBuffer.data, mFrameSize);
Steve Kondik77754522017-06-14 17:00:33 -0700320
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700321 // update clients
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700322 rfbMarkRectAsModified(mVNCScreen, 0, 0, imgBuffer.width, imgBuffer.height);
Steve Kondik77754522017-06-14 17:00:33 -0700323
324 mCpuConsumer->unlockBuffer(imgBuffer);
325}
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700326
327/*
328 * Returns "true" if the device is rotated 90 degrees.
329 */
330bool VNCFlinger::isDeviceRotated(int orientation) {
Steve Kondik2c9d0cf2017-06-15 23:39:29 -0700331 return orientation != DISPLAY_ORIENTATION_0 && orientation != DISPLAY_ORIENTATION_180;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700332}
333
334/*
335 * Sets the display projection, based on the display dimensions, video size,
336 * and device orientation.
337 */
338bool VNCFlinger::updateDisplayProjection() {
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700339 DisplayInfo info;
340 status_t err = SurfaceComposerClient::getDisplayInfo(mMainDpy, &info);
341 if (err != NO_ERROR) {
342 ALOGE("Failed to get display characteristics\n");
343 return true;
344 }
345
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700346 // Set the region of the layer stack we're interested in, which in our
347 // case is "all of it". If the app is rotated (so that the width of the
348 // app is based on the height of the display), reverse width/height.
349 bool deviceRotated = isDeviceRotated(info.orientation);
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700350 uint32_t sourceWidth, sourceHeight;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700351 if (!deviceRotated) {
352 sourceWidth = info.w;
353 sourceHeight = info.h;
354 } else {
355 ALOGV("using rotated width/height");
356 sourceHeight = info.w;
357 sourceWidth = info.h;
358 }
359
Steve Kondik59104ea2017-06-20 08:30:07 -0700360 uint32_t width = sourceWidth * mScale;
361 uint32_t height = sourceHeight * mScale;
362
363 if (mSourceWidth == sourceWidth && mSourceHeight == sourceHeight &&
364 mWidth == width && mHeight == height &&
365 mOrientation == info.orientation) {
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700366 return false;
367 }
368
Steve Kondik59104ea2017-06-20 08:30:07 -0700369 // orientation / resolution change
370 mSourceWidth = sourceWidth;
371 mSourceHeight = sourceHeight;
372 mWidth = width;
373 mHeight = height;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700374 mOrientation = info.orientation;
375
Steve Kondik59104ea2017-06-20 08:30:07 -0700376 ALOGV("Dimensions: %dx%d [out: %dx%d, scale: %f] orientation=%d",
377 mSourceWidth, mSourceHeight, mWidth, mHeight, mScale, mOrientation);
378
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700379 if (!mVDSActive) {
380 return true;
381 }
382
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700383 // it does not appear to be possible to reconfigure the virtual display
384 // on the fly without forcing surfaceflinger to tear it down
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700385 destroyVirtualDisplayLocked();
386 createVirtualDisplay();
Steve Kondik59104ea2017-06-20 08:30:07 -0700387
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700388 return false;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700389}
390
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700391bool VNCFlinger::updateFBSize(CpuConsumer::LockedBuffer& buf) {
392 uint32_t stride = (uint32_t)mVNCScreen->paddedWidthInBytes / 4;
393 uint32_t width = (uint32_t)mVNCScreen->width;
394 uint32_t height = (uint32_t)mVNCScreen->height;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700395
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700396 uint64_t newSize = buf.stride * buf.height * 4;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700397
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700398 if (stride != buf.stride || height != buf.height || width != buf.width) {
399 ALOGD("updateFBSize: old=[%dx%d %d] new=[%dx%d %d]", width, height, stride, buf.width,
400 buf.height, buf.stride);
401
402 if (mFrameSize != newSize) {
403 mFrameSize = newSize;
404 delete[] mVNCScreen->frameBuffer;
405 rfbNewFramebuffer(mVNCScreen, (char*)new uint8_t[newSize], buf.width, buf.height, 8, 3,
406 4);
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700407 }
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700408 mVNCScreen->paddedWidthInBytes = buf.stride * 4;
Steve Kondik6ec5bc82017-06-15 01:31:51 -0700409 }
410 return NO_ERROR;
411}
Steve Kondik5f7b0a82017-06-16 09:04:43 -0700412
413// ------------------------------------------------------------------------ //
414
415// libvncserver logger
416void VNCFlinger::rfbLogger(const char* format, ...) {
417 va_list args;
418 char buf[256];
419
420 va_start(args, format);
421 vsprintf(buf, format, args);
422 ALOGI("%s", buf);
423 va_end(args);
424}
425
426// libvncserver callbacks
427ClientGoneHookPtr VNCFlinger::onClientGone(rfbClientPtr cl) {
428 ALOGV("onClientGone");
429 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
430 vf->removeClient();
431 return 0;
432}
433
434enum rfbNewClientAction VNCFlinger::onNewClient(rfbClientPtr cl) {
435 ALOGV("onNewClient");
436 cl->clientGoneHook = (ClientGoneHookPtr)VNCFlinger::onClientGone;
437 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
438 vf->addClient();
439 return RFB_CLIENT_ACCEPT;
440}
441
442void VNCFlinger::onFrameStart(rfbClientPtr cl) {
443 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
444 vf->mUpdateMutex.lock();
445
446 vf->mFrameStartWhen = systemTime(CLOCK_MONOTONIC);
447 ALOGV("frame start [%lu]", vf->mFrameNumber);
448}
449
450void VNCFlinger::onFrameDone(rfbClientPtr cl, int /* status */) {
451 VNCFlinger* vf = (VNCFlinger*)cl->screen->screenData;
452
453 float timing = (systemTime(CLOCK_MONOTONIC) - vf->mFrameStartWhen) / 1000000.0;
454 ALOGV("onFrameDone [%lu] (%.3f ms)", vf->mFrameNumber, timing);
455
456 vf->mUpdateMutex.unlock();
457}
458
459// cpuconsumer frame listener
460void VNCFlinger::FrameListener::onFrameAvailable(const BufferItem& item) {
461 Mutex::Autolock _l(mVNC->mEventMutex);
462 mVNC->mFrameAvailable = true;
463 mVNC->mEventCond.signal();
464 ALOGV("onFrameAvailable: [%lu] mTimestamp=%ld", item.mFrameNumber, item.mTimestamp);
465}