Initial Contribution
diff --git a/libs/surfaceflinger/RFBServer.cpp b/libs/surfaceflinger/RFBServer.cpp
new file mode 100644
index 0000000..c2c1989
--- /dev/null
+++ b/libs/surfaceflinger/RFBServer.cpp
@@ -0,0 +1,722 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RFBServer"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+#include <netinet/in.h>
+
+#include <cutils/sockets.h>
+
+#include <utils/Log.h>
+#include <ui/Rect.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/input.h>
+#endif
+
+#include "RFBServer.h"
+#include "SurfaceFlinger.h"
+
+/* BUG=773511: this is a temporary hack required while developing the new
+ set of "clean kernel headers" for the Bionic C library. */
+#ifndef KEY_STAR
+#define KEY_STAR 227
+#endif
+#ifndef KEY_SHARP
+#define KEY_SHARP 228
+#endif
+#ifndef KEY_SOFT1
+#define KEY_SOFT1 229
+#endif
+#ifndef KEY_SOFT2
+#define KEY_SOFT2 230
+#endif
+#ifndef KEY_CENTER
+#define KEY_CENTER 232
+#endif
+
+// ----------------------------------------------------------------------------
+
+#define DEBUG_MSG 0
+
+// ----------------------------------------------------------------------------
+
+namespace android {
+
+const int VNC_PORT = 5900;
+
+RFBServer::RFBServer(uint32_t w, uint32_t h, android::PixelFormat format)
+ : Thread(false), mFD(-1), mStatus(NO_INIT), mIoVec(0)
+{
+ mFrameBuffer.version = sizeof(mFrameBuffer);
+ mFrameBuffer.width = w;
+ mFrameBuffer.height = h;
+ mFrameBuffer.stride = w;
+ mFrameBuffer.format = format;
+ mFrameBuffer.data = 0;
+}
+
+RFBServer::~RFBServer()
+{
+ if (mRobinThread != 0) {
+ // ask the thread to exit first
+ mRobinThread->exitAndWait();
+ }
+
+ free(mFrameBuffer.data);
+
+ delete [] mIoVec;
+}
+
+void RFBServer::onFirstRef()
+{
+ run("Batman");
+}
+
+status_t RFBServer::readyToRun()
+{
+ LOGI("RFB server ready to run");
+ return NO_ERROR;
+}
+
+bool RFBServer::threadLoop()
+{
+ struct sockaddr addr;
+ socklen_t alen;
+ int serverfd = -1;
+ int port = VNC_PORT;
+
+ do {
+ retry:
+ if (serverfd < 0) {
+ serverfd = socket_loopback_server(port, SOCK_STREAM);
+ if (serverfd < 0) {
+ if ((errno == EADDRINUSE) && (port < (VNC_PORT+10))) {
+ LOGW("port %d already in use, trying %d", port, port+1);
+ port++;
+ goto retry;
+ }
+ LOGE("couldn't create socket, port=%d, error %d (%s)",
+ port, errno, strerror(errno));
+ sleep(1);
+ break;
+ }
+ fcntl(serverfd, F_SETFD, FD_CLOEXEC);
+ }
+
+ alen = sizeof(addr);
+ mFD = accept(serverfd, &addr, &alen);
+
+ if (mFD < 0) {
+ LOGE("couldn't accept(), error %d (%s)", errno, strerror(errno));
+ // we could have run out of file descriptors, wait a bit and
+ // try again.
+ sleep(1);
+ goto retry;
+ }
+ fcntl(mFD, F_SETFD, FD_CLOEXEC);
+
+ // send protocol version and Authentication method
+ mStatus = NO_ERROR;
+ handshake(3, 3, Authentication::None);
+
+ if (alive()) {
+ // create the thread we use to send data to the client
+ mRobinThread = new ServerThread(this);
+ }
+
+ while( alive() ) {
+ // client message must be destroyed at each iteration
+ // (most of the time this is a no-op)
+ ClientMessage msg;
+ waitForClientMessage(msg);
+ if (alive()) {
+ handleClientMessage(msg);
+ }
+ }
+
+ } while( alive() );
+
+ // free-up some resources
+ if (mRobinThread != 0) {
+ mRobinThread->exitAndWait();
+ mRobinThread.clear();
+ }
+
+ free(mFrameBuffer.data);
+ mFrameBuffer.data = 0;
+
+ close(mFD);
+ close(serverfd);
+ mFD = -1;
+
+ // we'll try again
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+RFBServer::ServerThread::ServerThread(const sp<RFBServer>& receiver)
+ : Thread(false), mReceiver(receiver)
+{
+ LOGD("RFB Server Thread created");
+}
+
+RFBServer::ServerThread::~ServerThread()
+{
+ LOGD("RFB Server Thread destroyed");
+}
+
+void RFBServer::ServerThread::onFirstRef()
+{
+ mUpdateBarrier.close();
+ run("Robin");
+}
+
+status_t RFBServer::ServerThread::readyToRun()
+{
+ return NO_ERROR;
+}
+
+void RFBServer::ServerThread::wake()
+{
+ mUpdateBarrier.open();
+}
+
+void RFBServer::ServerThread::exitAndWait()
+{
+ requestExit();
+ mUpdateBarrier.open();
+ requestExitAndWait();
+}
+
+bool RFBServer::ServerThread::threadLoop()
+{
+ sp<RFBServer> receiver(mReceiver.promote());
+ if (receiver == 0)
+ return false;
+
+ // wait for something to do
+ mUpdateBarrier.wait();
+
+ // we're asked to quit, abort everything
+ if (exitPending())
+ return false;
+
+ mUpdateBarrier.close();
+
+ // process updates
+ receiver->sendFrameBufferUpdates();
+ return !exitPending();
+}
+
+// ----------------------------------------------------------------------------
+
+void RFBServer::handshake(uint8_t major, uint8_t minor, uint32_t auth)
+{
+ ProtocolVersion protocolVersion(major, minor);
+ if( !write(protocolVersion) )
+ return;
+
+ if ( !read(protocolVersion) )
+ return;
+
+ int maj, min;
+ if ( protocolVersion.decode(maj, min) != NO_ERROR ) {
+ mStatus = -1;
+ return;
+ }
+
+#if DEBUG_MSG
+ LOGD("client protocol string: <%s>", (char*)protocolVersion.payload());
+ LOGD("client wants protocol version %d.%d\n", maj, min);
+#endif
+
+ Authentication authentication(auth);
+ if( !write(authentication) )
+ return;
+
+ ClientInitialization clientInit;
+ if ( !read(clientInit) )
+ return;
+
+#if DEBUG_MSG
+ LOGD("client initialization: sharedFlags = %d\n", clientInit.sharedFlags());
+#endif
+
+ ServerInitialization serverInit("Android RFB");
+ ServerInitialization::Payload& message(serverInit.message());
+ message.framebufferWidth = htons(mFrameBuffer.width);
+ message.framebufferHeight = htons(mFrameBuffer.height);
+ message.serverPixelFormat.bitsPerPixel = 16;
+ message.serverPixelFormat.depth = 16;
+ message.serverPixelFormat.bigEndianFlag = 0;
+ message.serverPixelFormat.trueColorFlag = 1;
+ message.serverPixelFormat.redMax = htons((1<<5)-1);
+ message.serverPixelFormat.greenMax = htons((1<<6)-1);
+ message.serverPixelFormat.blueMax = htons((1<<5)-1);
+ message.serverPixelFormat.redShift = 11;
+ message.serverPixelFormat.greenShift = 5;
+ message.serverPixelFormat.blueShift = 0;
+
+ mIoVec = new iovec[mFrameBuffer.height];
+
+ write(serverInit);
+}
+
+void RFBServer::handleClientMessage(const ClientMessage& msg)
+{
+ switch(msg.type()) {
+ case SET_PIXEL_FORMAT:
+ handleSetPixelFormat(msg.messages().setPixelFormat);
+ break;
+ case SET_ENCODINGS:
+ handleSetEncodings(msg.messages().setEncodings);
+ break;
+ case FRAME_BUFFER_UPDATE_REQ:
+ handleFrameBufferUpdateReq(msg.messages().frameBufferUpdateRequest);
+ break;
+ case KEY_EVENT:
+ handleKeyEvent(msg.messages().keyEvent);
+ break;
+ }
+}
+
+void RFBServer::handleSetPixelFormat(const SetPixelFormat& msg)
+{
+ if (!validatePixelFormat(msg.pixelFormat)) {
+ LOGE("The builtin VNC server only supports the RGB 565 pixel format");
+ LOGD("requested pixel format:");
+ LOGD("bitsPerPixel: %d", msg.pixelFormat.bitsPerPixel);
+ LOGD("depth: %d", msg.pixelFormat.depth);
+ LOGD("bigEndianFlag: %d", msg.pixelFormat.bigEndianFlag);
+ LOGD("trueColorFlag: %d", msg.pixelFormat.trueColorFlag);
+ LOGD("redmax: %d", ntohs(msg.pixelFormat.redMax));
+ LOGD("bluemax: %d", ntohs(msg.pixelFormat.greenMax));
+ LOGD("greenmax: %d", ntohs(msg.pixelFormat.blueMax));
+ LOGD("redshift: %d", msg.pixelFormat.redShift);
+ LOGD("greenshift: %d", msg.pixelFormat.greenShift);
+ LOGD("blueshift: %d", msg.pixelFormat.blueShift);
+ mStatus = -1;
+ }
+}
+
+bool RFBServer::validatePixelFormat(const PixelFormat& pf)
+{
+ if ((pf.bitsPerPixel != 16) || (pf.depth != 16))
+ return false;
+
+ if (pf.bigEndianFlag || !pf.trueColorFlag)
+ return false;
+
+ if (ntohs(pf.redMax)!=0x1F ||
+ ntohs(pf.greenMax)!=0x3F ||
+ ntohs(pf.blueMax)!=0x1F) {
+ return false;
+ }
+
+ if (pf.redShift!=11 || pf.greenShift!=5 || pf.blueShift!=0)
+ return false;
+
+ return true;
+}
+
+void RFBServer::handleSetEncodings(const SetEncodings& msg)
+{
+ /* From the RFB specification:
+ Sets the encoding types in which pixel data can be sent by the server.
+ The order of the encoding types given in this message is a hint by the
+ client as to its preference (the first encoding specified being most
+ preferred). The server may or may not choose to make use of this hint.
+ Pixel data may always be sent in raw encoding even if not specified
+ explicitly here.
+ */
+
+ LOGW("SetEncodings received. Only RAW is supported.");
+}
+
+void RFBServer::handleFrameBufferUpdateReq(const FrameBufferUpdateRequest& msg)
+{
+#if DEBUG_MSG
+ LOGD("handle FrameBufferUpdateRequest");
+#endif
+
+ Rect r;
+ r.left = ntohs(msg.x);
+ r.top = ntohs(msg.y);
+ r.right = r.left + ntohs(msg.width);
+ r.bottom = r.top + ntohs(msg.height);
+
+ Mutex::Autolock _l(mRegionLock);
+ mClientRegionRequest.set(r);
+ if (!msg.incremental)
+ mDirtyRegion.orSelf(r);
+
+ mRobinThread->wake();
+}
+
+void RFBServer::handleKeyEvent(const KeyEvent& msg)
+{
+#ifdef HAVE_ANDROID_OS
+
+ int scancode = 0;
+ int code = ntohl(msg.key);
+
+ if (code>='0' && code<='9') {
+ scancode = (code & 0xF) - 1;
+ if (scancode<0) scancode += 10;
+ scancode += KEY_1;
+ } else if (code>=0xFF50 && code<=0xFF58) {
+ static const uint16_t map[] =
+ { KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
+ KEY_SOFT1, KEY_SOFT2, KEY_END, 0 };
+ scancode = map[code & 0xF];
+ } else if (code>=0xFFE1 && code<=0xFFEE) {
+ static const uint16_t map[] =
+ { KEY_LEFTSHIFT, KEY_LEFTSHIFT,
+ KEY_COMPOSE, KEY_COMPOSE,
+ KEY_LEFTSHIFT, KEY_LEFTSHIFT,
+ 0,0,
+ KEY_LEFTALT, KEY_RIGHTALT,
+ 0, 0, 0, 0 };
+ scancode = map[code & 0xF];
+ } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) {
+ static const uint16_t map[] = {
+ KEY_A, KEY_B, KEY_C, KEY_D, KEY_E,
+ KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
+ KEY_K, KEY_L, KEY_M, KEY_N, KEY_O,
+ KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
+ KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z };
+ scancode = map[(code & 0x5F) - 'A'];
+ } else {
+ switch (code) {
+ case 0x0003: scancode = KEY_CENTER; break;
+ case 0x0020: scancode = KEY_SPACE; break;
+ case 0x0023: scancode = KEY_SHARP; break;
+ case 0x0033: scancode = KEY_SHARP; break;
+ case 0x002C: scancode = KEY_COMMA; break;
+ case 0x003C: scancode = KEY_COMMA; break;
+ case 0x002E: scancode = KEY_DOT; break;
+ case 0x003E: scancode = KEY_DOT; break;
+ case 0x002F: scancode = KEY_SLASH; break;
+ case 0x003F: scancode = KEY_SLASH; break;
+ case 0x0032: scancode = KEY_EMAIL; break;
+ case 0x0040: scancode = KEY_EMAIL; break;
+ case 0xFF08: scancode = KEY_BACKSPACE; break;
+ case 0xFF1B: scancode = KEY_BACK; break;
+ case 0xFF09: scancode = KEY_TAB; break;
+ case 0xFF0D: scancode = KEY_ENTER; break;
+ case 0x002A: scancode = KEY_STAR; break;
+ case 0xFFBE: scancode = KEY_SEND; break; // F1
+ case 0xFFBF: scancode = KEY_END; break; // F2
+ case 0xFFC0: scancode = KEY_HOME; break; // F3
+ case 0xFFC5: scancode = KEY_POWER; break; // F8
+ }
+ }
+
+#if DEBUG_MSG
+ LOGD("handle KeyEvent 0x%08x, %d, scancode=%d\n", code, msg.downFlag, scancode);
+#endif
+
+ if (scancode) {
+ mEventInjector.injectKey(uint16_t(scancode),
+ msg.downFlag ? EventInjector::DOWN : EventInjector::UP);
+ }
+#endif
+}
+
+void RFBServer::waitForClientMessage(ClientMessage& msg)
+{
+ if ( !read(msg.payload(), 1) )
+ return;
+
+ switch(msg.type()) {
+
+ case SET_PIXEL_FORMAT:
+ read(msg.payload(1), sizeof(SetPixelFormat)-1);
+ break;
+
+ case FIX_COLOUR_MAP_ENTRIES:
+ mStatus = UNKNOWN_ERROR;
+ return;
+
+ case SET_ENCODINGS:
+ {
+ if ( !read(msg.payload(1), sizeof(SetEncodings)-1) )
+ return;
+
+ size_t size = ntohs( msg.messages().setEncodings.numberOfEncodings ) * 4;
+ if (msg.resize(sizeof(SetEncodings) + size) != NO_ERROR) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+
+ if ( !read(msg.payload(sizeof(SetEncodings)), size) )
+ return;
+
+ break;
+ }
+
+ case FRAME_BUFFER_UPDATE_REQ:
+ read(msg.payload(1), sizeof(FrameBufferUpdateRequest)-1);
+ break;
+
+ case KEY_EVENT:
+ read(msg.payload(1), sizeof(KeyEvent)-1);
+ break;
+
+ case POINTER_EVENT:
+ read(msg.payload(1), sizeof(PointerEvent)-1);
+ break;
+
+ case CLIENT_CUT_TEXT:
+ {
+ if ( !read(msg.payload(1), sizeof(ClientCutText)-1) )
+ return;
+
+ size_t size = ntohl( msg.messages().clientCutText.length );
+ if (msg.resize(sizeof(ClientCutText) + size) != NO_ERROR) {
+ mStatus = NO_MEMORY;
+ return;
+ }
+
+ if ( !read(msg.payload(sizeof(SetEncodings)), size) )
+ return;
+
+ break;
+ }
+
+ default:
+ LOGE("Unknown Message %d", msg.type());
+ mStatus = UNKNOWN_ERROR;
+ return;
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+bool RFBServer::write(const Message& msg)
+{
+ write(msg.payload(), msg.size());
+ return alive();
+}
+
+bool RFBServer::read(Message& msg)
+{
+ read(msg.payload(), msg.size());
+ return alive();
+}
+
+bool RFBServer::write(const void* buffer, int size)
+{
+ int wr = ::write(mFD, buffer, size);
+ if (wr != size) {
+ //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
+ mStatus = (wr == -1) ? errno : -1;
+ }
+ return alive();
+}
+
+bool RFBServer::read(void* buffer, int size)
+{
+ int rd = ::read(mFD, buffer, size);
+ if (rd != size) {
+ //LOGE("read(%d) error %d (%s)", size, rd, strerror(errno));
+ mStatus = (rd == -1) ? errno : -1;
+ }
+ return alive();
+}
+
+bool RFBServer::alive() const
+{
+ return mStatus == 0;
+}
+
+bool RFBServer::isConnected() const
+{
+ return alive();
+}
+
+// ----------------------------------------------------------------------------
+
+void RFBServer::frameBufferUpdated(const GGLSurface& front, const Region& reg)
+{
+ Mutex::Autolock _l(mRegionLock);
+
+ // update dirty region
+ mDirtyRegion.orSelf(reg);
+
+ // remember the front-buffer
+ mFrontBuffer = front;
+
+ // The client has not requested anything, don't do anything more
+ if (mClientRegionRequest.isEmpty())
+ return;
+
+ // wake the sending thread up
+ mRobinThread->wake();
+}
+
+void RFBServer::sendFrameBufferUpdates()
+{
+ Vector<Rect> rects;
+ size_t countRects;
+ GGLSurface fb;
+
+ { // Scope for the lock
+ Mutex::Autolock _l(mRegionLock);
+ if (mFrontBuffer.data == 0)
+ return;
+
+ const Region reg( mDirtyRegion.intersect(mClientRegionRequest) );
+ if (reg.isEmpty())
+ return;
+
+ mDirtyRegion.subtractSelf(reg);
+ countRects = reg.rects(rects);
+
+ // copy the frame-buffer so we can stay responsive
+ size_t bytesPerPix = bytesPerPixel(mFrameBuffer.format);
+ size_t bpr = mFrameBuffer.stride * bytesPerPix;
+ if (mFrameBuffer.data == 0) {
+ mFrameBuffer.data = (GGLubyte*)malloc(bpr * mFrameBuffer.height);
+ if (mFrameBuffer.data == 0)
+ return;
+ }
+
+ memcpy(mFrameBuffer.data, mFrontBuffer.data, bpr*mFrameBuffer.height);
+ fb = mFrameBuffer;
+ }
+
+ FrameBufferUpdate msgHeader;
+ msgHeader.type = 0;
+ msgHeader.numberOfRectangles = htons(countRects);
+ write(&msgHeader, sizeof(msgHeader));
+
+ Rectangle rectangle;
+ for (size_t i=0 ; i<countRects ; i++) {
+ const Rect& r = rects[i];
+ rectangle.x = htons( r.left );
+ rectangle.y = htons( r.top );
+ rectangle.w = htons( r.width() );
+ rectangle.h = htons( r.height() );
+ rectangle.encoding = htons( SetEncodings::Raw );
+ write(&rectangle, sizeof(rectangle));
+ size_t h = r.height();
+ size_t w = r.width();
+ size_t bytesPerPix = bytesPerPixel(fb.format);
+ size_t bpr = fb.stride * bytesPerPix;
+ size_t bytes = w * bytesPerPix;
+ size_t offset = (r.top * bpr) + (r.left * bytesPerPix);
+ uint8_t* src = static_cast<uint8_t*>(fb.data) + offset;
+ iovec* iov = mIoVec;
+ while (h--) {
+ iov->iov_base = src;
+ iov->iov_len = bytes;
+ src += bpr;
+ iov++;
+ }
+ size_t iovcnt = iov - mIoVec;
+ int wr = ::writev(mFD, mIoVec, iovcnt);
+ if (wr < 0) {
+ //LOGE("write(%d) error %d (%s)", size, wr, strerror(errno));
+ mStatus = errno;
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+RFBServer::Message::Message(size_t size)
+ : mSize(size), mAllocatedSize(size)
+{
+ mPayload = malloc(size);
+}
+
+RFBServer::Message::Message(void* payload, size_t size)
+ : mPayload(payload), mSize(size), mAllocatedSize(0)
+{
+}
+
+RFBServer::Message::~Message()
+{
+ if (mAllocatedSize)
+ free(mPayload);
+}
+
+status_t RFBServer::Message::resize(size_t size)
+{
+ if (size > mAllocatedSize) {
+ void* newp;
+ if (mAllocatedSize) {
+ newp = realloc(mPayload, size);
+ if (!newp) return NO_MEMORY;
+ } else {
+ newp = malloc(size);
+ if (!newp) return NO_MEMORY;
+ memcpy(newp, mPayload, mSize);
+ mAllocatedSize = size;
+ }
+ mPayload = newp;
+ }
+ mSize = size;
+ return NO_ERROR;
+}
+
+// ----------------------------------------------------------------------------
+
+RFBServer::EventInjector::EventInjector()
+ : mFD(-1)
+{
+}
+
+RFBServer::EventInjector::~EventInjector()
+{
+}
+
+void RFBServer::EventInjector::injectKey(uint16_t code, uint16_t value)
+{
+#ifdef HAVE_ANDROID_OS
+ // XXX: we need to open the right event device
+ int version;
+ mFD = open("/dev/input/event0", O_RDWR);
+ ioctl(mFD, EVIOCGVERSION, &version);
+
+ input_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = EV_KEY;
+ ev.code = code;
+ ev.value = value;
+ ::write(mFD, &ev, sizeof(ev));
+
+ close(mFD);
+ mFD = -1;
+#endif
+}
+
+
+}; // namespace android
+