├── Android.mk ├── README.md ├── bin └── android-vnc-server └── libs-build-note ├── fbvncserver-2.c ├── libjpeg-turbo-Android.mk ├── libvncserver-Android.mk └── note.txt /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_SRC_FILES:= \ 5 | fbvncserver.c \ 6 | 7 | LOCAL_C_INCLUDES := \ 8 | $(LOCAL_PATH) \ 9 | libvncserver \ 10 | external/zlib \ 11 | libjpeg-turbo 12 | 13 | LOCAL_SHARED_LIBRARIES := libssl libcrypto libpng libz libc 14 | #LOCAL_SHARED_LIBRARIES := libcutils libc 15 | LOCAL_STATIC_LIBRARIES := libvncserver_static libjpeg_turbo_static \ 16 | # libssl_static libcrypto_static libpng libz #libcutils libc 17 | 18 | #LOCAL_FORCE_STATIC_EXECUTABLE := true 19 | LOCAL_MODULE:= android-vnc-server 20 | LOCAL_MODULE_TAGS := optional 21 | 22 | include $(BUILD_EXECUTABLE) 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | android-vnc-server 2 | ================== 3 | android-vnc-server for kitkat 4 | This is a vnc server which pushes framebuffer of mobile device to vnc clients. 5 | This server accepts mouse drag as touch events and key inputs. 6 | 7 | Build 8 | ===== 9 | 1. download `libvncserver` and `libjpeg-turbo` from web, and put them to aosp source code tree 10 | 2. copy the related Android.mk to the related dir 11 | 3. run `cd libvncserver; ./autogen.sh && ./configure --without-crypto` 12 | 4. run `cd libjpeg-turbo; ./configure` 13 | 5. build the system image 14 | 15 | Usage 16 | ===== 17 | 1. run `./android-vnc-server` on mobile device 18 | 2. connect mobile device to pc through adb 19 | 3. run `adb forward tcp:5901 tcp:5901` on pc 20 | 4. run vnc client(e.g. remmina, gvncviewer, novnc ...) to connect to 127.0.0.1:5901 21 | 5. bang.... a mirror of your mobile device, touch with your mouse 22 | 23 | Note 24 | ==== 25 | You may need to debug it yourself. 26 | I've tested with an aosp rom, works fine. 27 | But didn't work with cyanogenmod of HTC ONE S. 28 | -------------------------------------------------------------------------------- /bin/android-vnc-server: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/z7z8th/android-vnc-server/f3fdbef6e0862fc0ddbb3d82d0997e48630802ec/bin/android-vnc-server -------------------------------------------------------------------------------- /libs-build-note/fbvncserver-2.c: -------------------------------------------------------------------------------- 1 | /* 2 | * fbvncserver.c 3 | * 4 | * This program is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU General Public License as published by the 6 | * Free Software Foundation; either version 2, or (at your option) any 7 | * later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * General Public License for more details. 13 | * 14 | * Started with original fbvncserver for the iPAQ and Zaurus. 15 | * http://fbvncserver.sourceforge.net/ 16 | * 17 | * Modified by Jim Huang 18 | * - Simplified and sizing down 19 | * - Performance tweaks 20 | * 21 | * Modified by Steve Guo (letsgoustc) 22 | * - Added keyboard/pointer input 23 | * 24 | * Modified by Danke Xie (danke.xie@gmail.com) 25 | * - Added input device search to support different devices 26 | * - Added kernel vnckbd driver to allow full-keyboard input on 12-key hw 27 | * - Supports Android framebuffer double buffering 28 | * - Performance boost and fix GCC warnings in libvncserver-0.9.7 29 | * 30 | * NOTE: depends libvncserver. 31 | */ 32 | 33 | /* define the following to enable debug messages */ 34 | /* #define DEBUG */ 35 | /* #define DEBUG_VERBOSE */ 36 | 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | #include 46 | #include /* For makedev() */ 47 | 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | /* libvncserver */ 58 | #include "rfb/rfb.h" 59 | #include "rfb/keysym.h" 60 | #include "rfb/rfbregion.h" 61 | 62 | #define APPNAME "fbvncserver" 63 | #define VNC_DESKTOP_NAME "Android" 64 | 65 | /* framebuffer */ 66 | #ifdef ANDROID 67 | # define FB_DEVICE "/dev/graphics/fb0" 68 | #else 69 | # define FB_DEVICE "/dev/fb0" 70 | #endif 71 | 72 | static const char DEV_FMT[] = "/dev/input/event%d"; 73 | 74 | /* keywords to search for input devices by name */ 75 | static const char *KBD_PATTERNS[] = { 76 | "VNC", /* VNC keyboard driver, 1st choice */ 77 | "key", /* keypad */ 78 | "qwerty", /* emulator */ 79 | NULL}; 80 | 81 | static const char *TOUCH_PATTERNS[] = { 82 | "touch", /* touchpad */ 83 | "qwerty", /* emulator */ 84 | NULL}; 85 | 86 | /* default input device paths */ 87 | static char KBD_DEVICE[PATH_MAX] = "/dev/input/event2"; 88 | static char TOUCH_DEVICE[PATH_MAX] = "/dev/input/event1"; 89 | 90 | /* for compatibility of non-android systems */ 91 | #ifndef ANDROID 92 | # define KEY_SOFT1 KEY_UNKNOWN 93 | # define KEY_SOFT2 KEY_UNKNOWN 94 | # define KEY_CENTER KEY_UNKNOWN 95 | # define KEY_SHARP KEY_UNKNOWN 96 | # define KEY_STAR KEY_UNKNOWN 97 | #endif 98 | 99 | static struct fb_var_screeninfo scrinfo; 100 | static int buffers = 2; /* mmap 2 buffers for android */ 101 | static int fbfd = -1; 102 | static int kbdfd = -1; 103 | static int touchfd = -1; 104 | static unsigned short int *fbmmap = MAP_FAILED; 105 | static unsigned short int *vncbuf; 106 | static unsigned short int *fbbuf; 107 | static int pixels_per_int; 108 | 109 | __sighandler_t old_sigint_handler = NULL; 110 | 111 | #define VNC_PORT 5901 112 | static rfbScreenInfoPtr vncscr; 113 | 114 | static int xmin, xmax; 115 | static int ymin, ymax; 116 | 117 | /* part of the frame differerencing algorithm. */ 118 | static struct varblock_t { 119 | int min_x; 120 | int min_y; 121 | int max_x; 122 | int max_y; 123 | int r_offset; 124 | int g_offset; 125 | int b_offset; 126 | int pixels_per_int; 127 | } varblock; 128 | 129 | /* event handler callback */ 130 | static void keyevent(rfbBool down, rfbKeySym key, rfbClientPtr cl); 131 | static void ptrevent(int buttonMask, int x, int y, rfbClientPtr cl); 132 | 133 | #ifdef DEBUG 134 | # define pr_debug(fmt, ...) \ 135 | fprintf(stderr, fmt, ## __VA_ARGS__) 136 | #else 137 | # define pr_debug(fmt, ...) do { } while(0) 138 | #endif 139 | 140 | #ifdef DEBUG_VERBOSE 141 | # define pr_vdebug(fmt, ...) \ 142 | pr_debug(fmt, ## __VA_ARGS__) 143 | #else 144 | # define pr_vdebug(fmt, ...) do { } while(0) 145 | #endif 146 | 147 | #define pr_info(fmt, ...) \ 148 | fprintf(stdout, fmt, ## __VA_ARGS__) 149 | 150 | #define pr_err(fmt, ...) \ 151 | fprintf(stderr, fmt, ## __VA_ARGS__) 152 | 153 | static void init_fb(void) 154 | { 155 | size_t pixels; 156 | size_t bytespp; 157 | 158 | if ((fbfd = open(FB_DEVICE, O_RDONLY)) == -1) { 159 | perror("open"); 160 | exit(EXIT_FAILURE); 161 | } 162 | 163 | if (ioctl(fbfd, FBIOGET_VSCREENINFO, &scrinfo) != 0) { 164 | perror("ioctl"); 165 | exit(EXIT_FAILURE); 166 | } 167 | 168 | pixels = scrinfo.xres * scrinfo.yres; 169 | bytespp = scrinfo.bits_per_pixel / 8; 170 | 171 | pr_info("xres=%d, yres=%d, " 172 | "xresv=%d, yresv=%d, " 173 | "xoffs=%d, yoffs=%d, " 174 | "bpp=%d\n", 175 | (int)scrinfo.xres, (int)scrinfo.yres, 176 | (int)scrinfo.xres_virtual, (int)scrinfo.yres_virtual, 177 | (int)scrinfo.xoffset, (int)scrinfo.yoffset, 178 | (int)scrinfo.bits_per_pixel); 179 | 180 | fbmmap = mmap(NULL, buffers * pixels * bytespp, 181 | PROT_READ, MAP_SHARED, fbfd, 0); 182 | 183 | if (fbmmap == MAP_FAILED) { 184 | perror("mmap"); 185 | exit(EXIT_FAILURE); 186 | } 187 | } 188 | 189 | static void cleanup_fb(void) 190 | { 191 | if(fbfd != -1) 192 | { 193 | close(fbfd); 194 | } 195 | } 196 | 197 | static void init_kbd() 198 | { 199 | if((kbdfd = open(KBD_DEVICE, O_RDWR)) == -1) 200 | { 201 | pr_err("cannot open kbd device %s\n", KBD_DEVICE); 202 | exit(EXIT_FAILURE); 203 | } 204 | } 205 | 206 | static void cleanup_kbd() 207 | { 208 | if(kbdfd != -1) 209 | { 210 | close(kbdfd); 211 | } 212 | } 213 | 214 | static void init_touch() 215 | { 216 | struct input_absinfo info; 217 | if((touchfd = open(TOUCH_DEVICE, O_RDWR)) == -1) 218 | { 219 | pr_err("cannot open touch device %s\n", TOUCH_DEVICE); 220 | exit(EXIT_FAILURE); 221 | } 222 | // Get the Range of X and Y 223 | if(ioctl(touchfd, EVIOCGABS(ABS_X), &info)) { 224 | pr_err("cannot get ABS_X info, %s\n", strerror(errno)); 225 | exit(EXIT_FAILURE); 226 | } 227 | xmin = info.minimum; 228 | xmax = info.maximum; 229 | if (xmax) 230 | pr_vdebug("touchscreen xmin=%d xmax=%d\n", xmin, xmax); 231 | else 232 | pr_vdebug("touchscreen has no xmax: using emulator mode\n"); 233 | 234 | if(ioctl(touchfd, EVIOCGABS(ABS_Y), &info)) { 235 | pr_err("cannot get ABS_Y, %s\n", strerror(errno)); 236 | exit(EXIT_FAILURE); 237 | } 238 | ymin = info.minimum; 239 | ymax = info.maximum; 240 | if (ymax) 241 | pr_vdebug("touchscreen ymin=%d ymax=%d\n", ymin, ymax); 242 | else 243 | pr_vdebug("touchscreen has no ymax: using emulator mode\n"); 244 | } 245 | 246 | static void cleanup_touch() 247 | { 248 | if(touchfd != -1) 249 | { 250 | close(touchfd); 251 | } 252 | } 253 | 254 | /*****************************************************************************/ 255 | 256 | static void init_fb_server(int argc, char **argv) 257 | { 258 | pr_info("Initializing server...\n"); 259 | 260 | /* Allocate the VNC server buffer to be managed (not manipulated) by 261 | * libvncserver. */ 262 | vncbuf = calloc(scrinfo.xres * scrinfo.yres, scrinfo.bits_per_pixel / 2); 263 | assert(vncbuf != NULL); 264 | 265 | /* Allocate the comparison buffer for detecting drawing updates from frame 266 | * to frame. */ 267 | fbbuf = calloc(scrinfo.xres * scrinfo.yres, scrinfo.bits_per_pixel / 2); 268 | assert(fbbuf != NULL); 269 | 270 | /* FIXME: This assumes scrinfo.bits_per_pixel is 16. */ 271 | vncscr = rfbGetScreen(&argc, argv, scrinfo.xres, scrinfo.yres, 272 | 5, /* bits per sample */ 273 | 2, /* samples per pixel */ 274 | 2 /* bytes/sample */ ); 275 | 276 | assert(vncscr != NULL); 277 | 278 | vncscr->desktopName = VNC_DESKTOP_NAME; 279 | vncscr->frameBuffer = (char *)vncbuf; 280 | vncscr->alwaysShared = TRUE; 281 | vncscr->httpDir = NULL; 282 | vncscr->port = VNC_PORT; 283 | 284 | vncscr->kbdAddEvent = keyevent; 285 | vncscr->ptrAddEvent = ptrevent; 286 | 287 | rfbInitServer(vncscr); 288 | 289 | /* Mark as dirty since we haven't sent any updates at all yet. */ 290 | rfbMarkRectAsModified(vncscr, 0, 0, scrinfo.xres, scrinfo.yres); 291 | 292 | /* Bit shifts */ 293 | varblock.r_offset = scrinfo.red.offset + scrinfo.red.length - 5; 294 | varblock.g_offset = scrinfo.green.offset + scrinfo.green.length - 5; 295 | varblock.b_offset = scrinfo.blue.offset + scrinfo.blue.length - 5; 296 | varblock.pixels_per_int = 8 * sizeof(int) / scrinfo.bits_per_pixel; 297 | } 298 | 299 | /*****************************************************************************/ 300 | void injectKeyEvent(uint16_t code, uint16_t value) 301 | { 302 | struct input_event ev; 303 | memset(&ev, 0, sizeof(ev)); 304 | gettimeofday(&ev.time,0); 305 | ev.type = EV_KEY; 306 | ev.code = code; 307 | ev.value = value; 308 | if(write(kbdfd, &ev, sizeof(ev)) < 0) 309 | { 310 | pr_err("write event failed, %s\n", strerror(errno)); 311 | } 312 | 313 | pr_vdebug("injectKey (%d, %d)\n", code , value); 314 | } 315 | 316 | /* device independent */ 317 | static int keysym2scancode(rfbBool down, rfbKeySym key, rfbClientPtr cl) 318 | { 319 | int scancode = 0; 320 | 321 | int code = (int) key; 322 | if (code>='0' && code<='9') { 323 | scancode = (code & 0xF) - 1; 324 | if (scancode<0) scancode += 10; 325 | scancode += KEY_1; 326 | } else if (code>=0xFF50 && code<=0xFF58) { 327 | static const uint16_t map[] = 328 | { KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN, 329 | KEY_SOFT1, KEY_SOFT2, KEY_END, 0 }; 330 | scancode = map[code & 0xF]; 331 | } else if (code>=0xFFE1 && code<=0xFFEE) { 332 | static const uint16_t map[] = 333 | { KEY_LEFTSHIFT, KEY_LEFTSHIFT, 334 | KEY_COMPOSE, KEY_COMPOSE, 335 | KEY_LEFTSHIFT, KEY_LEFTSHIFT, 336 | 0,0, 337 | KEY_LEFTALT, KEY_RIGHTALT, 338 | 0, 0, 0, 0 }; 339 | scancode = map[code & 0xF]; 340 | } else if ((code>='A' && code<='Z') || (code>='a' && code<='z')) { 341 | static const uint16_t map[] = { 342 | KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, 343 | KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, 344 | KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, 345 | KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, 346 | KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z }; 347 | scancode = map[(code & 0x5F) - 'A']; 348 | } else { 349 | switch (code) { 350 | case 0x0003: scancode = KEY_CENTER; break; 351 | case 0x0020: scancode = KEY_SPACE; break; 352 | case 0x0023: scancode = KEY_SHARP; break; 353 | case 0x0033: scancode = KEY_SHARP; break; 354 | case 0x002C: scancode = KEY_COMMA; break; 355 | case 0x003C: scancode = KEY_COMMA; break; 356 | case 0x002E: scancode = KEY_DOT; break; 357 | case 0x003E: scancode = KEY_DOT; break; 358 | case 0x002F: scancode = KEY_SLASH; break; 359 | case 0x003F: scancode = KEY_SLASH; break; 360 | case 0x0032: scancode = KEY_EMAIL; break; 361 | case 0x0040: scancode = KEY_EMAIL; break; 362 | case 0xFF08: scancode = KEY_BACKSPACE; break; 363 | case 0xFF1B: scancode = KEY_BACK; break; 364 | case 0xFF09: scancode = KEY_TAB; break; 365 | case 0xFF0D: scancode = KEY_ENTER; break; 366 | case 0x002A: scancode = KEY_STAR; break; 367 | case 0xFFBE: scancode = KEY_F1; break; // F1 368 | case 0xFFBF: scancode = KEY_F2; break; // F2 369 | case 0xFFC0: scancode = KEY_F3; break; // F3 370 | case 0xFFC5: scancode = KEY_F4; break; // F8 371 | case 0xFFC8: rfbShutdownServer(cl->screen,TRUE); break; // F11 372 | } 373 | } 374 | 375 | return scancode; 376 | } 377 | 378 | static void keyevent(rfbBool down, rfbKeySym key, rfbClientPtr cl) 379 | { 380 | int scancode; 381 | 382 | pr_vdebug("Got keysym: %04x (down=%d)\n", (unsigned int)key, (int)down); 383 | 384 | if ((scancode = keysym2scancode(down, key, cl))) 385 | { 386 | injectKeyEvent(scancode, down); 387 | } 388 | } 389 | 390 | void injectTouchEvent(int down, int x, int y) 391 | { 392 | struct input_event ev; 393 | 394 | // Re-calculate the final x and y if xmax/ymax are specified 395 | if (xmax) x = xmin + (x * (xmax - xmin)) / (scrinfo.xres); 396 | if (ymax) y = ymin + (y * (ymax - ymin)) / (scrinfo.yres); 397 | 398 | memset(&ev, 0, sizeof(ev)); 399 | 400 | // Then send a BTN_TOUCH 401 | gettimeofday(&ev.time,0); 402 | ev.type = EV_KEY; 403 | ev.code = BTN_TOUCH; 404 | ev.value = down; 405 | if(write(touchfd, &ev, sizeof(ev)) < 0) 406 | { 407 | pr_err("write event failed, %s\n", strerror(errno)); 408 | } 409 | 410 | // Then send the X 411 | gettimeofday(&ev.time,0); 412 | ev.type = EV_ABS; 413 | ev.code = ABS_X; 414 | ev.value = x; 415 | if(write(touchfd, &ev, sizeof(ev)) < 0) 416 | { 417 | pr_err("write event failed, %s\n", strerror(errno)); 418 | } 419 | 420 | // Then send the Y 421 | gettimeofday(&ev.time,0); 422 | ev.type = EV_ABS; 423 | ev.code = ABS_Y; 424 | ev.value = y; 425 | if(write(touchfd, &ev, sizeof(ev)) < 0) 426 | { 427 | pr_err("write event failed, %s\n", strerror(errno)); 428 | } 429 | 430 | // Finally send the SYN 431 | gettimeofday(&ev.time,0); 432 | ev.type = EV_SYN; 433 | ev.code = 0; 434 | ev.value = 0; 435 | if(write(touchfd, &ev, sizeof(ev)) < 0) 436 | { 437 | pr_err("write event failed, %s\n", strerror(errno)); 438 | } 439 | 440 | pr_vdebug("injectTouchEvent (x=%d, y=%d, down=%d)\n", x , y, down); 441 | } 442 | 443 | static void ptrevent(int buttonMask, int x, int y, rfbClientPtr cl) 444 | { 445 | /* Indicates either pointer movement or a pointer button press or release. The pointer is 446 | now at (x-position, y-position), and the current state of buttons 1 to 8 are represented 447 | by bits 0 to 7 of button-mask respectively, 0 meaning up, 1 meaning down (pressed). 448 | On a conventional mouse, buttons 1, 2 and 3 correspond to the left, middle and right 449 | buttons on the mouse. On a wheel mouse, each step of the wheel upwards is represented 450 | by a press and release of button 4, and each step downwards is represented by 451 | a press and release of button 5. 452 | From: http://www.vislab.usyd.edu.au/blogs/index.php/2009/05/22/an-headerless-indexed-protocol-for-input-1?blog=61 */ 453 | 454 | pr_vdebug("Got ptrevent: %04x (x=%d, y=%d)\n", buttonMask, x, y); 455 | if(buttonMask & 1) { 456 | // Simulate left mouse event as touch event 457 | injectTouchEvent(1, x, y); 458 | injectTouchEvent(0, x, y); 459 | } 460 | } 461 | 462 | static int get_framebuffer_yoffset() 463 | { 464 | if(ioctl(fbfd, FBIOGET_VSCREENINFO, &scrinfo) < 0) { 465 | pr_err("failed to get virtual screen info\n"); 466 | return -1; 467 | } 468 | 469 | return scrinfo.yoffset; 470 | } 471 | 472 | #define PIXEL_FB_TO_RFB(p,r,g,b) \ 473 | ((p >> r) & 0x1f001f) | \ 474 | (((p >> g) & 0x1f001f) << 5) | \ 475 | (((p >> b) & 0x1f001f) << 10) 476 | 477 | static void update_screen(void) 478 | { 479 | unsigned int *f, *c, *r; 480 | int x, y, y_virtual; 481 | 482 | /* get virtual screen info */ 483 | y_virtual = get_framebuffer_yoffset(); 484 | if (y_virtual < 0) 485 | y_virtual = 0; /* no info, have to assume front buffer */ 486 | 487 | varblock.min_x = varblock.min_y = INT_MAX; 488 | varblock.max_x = varblock.max_y = -1; 489 | 490 | f = (unsigned int *)fbmmap; /* -> framebuffer */ 491 | c = (unsigned int *)fbbuf; /* -> compare framebuffer */ 492 | r = (unsigned int *)vncbuf; /* -> remote framebuffer */ 493 | 494 | /* jump to right virtual screen */ 495 | f += y_virtual * scrinfo.xres / varblock.pixels_per_int; 496 | 497 | for (y = 0; y < (int) scrinfo.yres; y++) { 498 | /* Compare every 2 pixels at a time, assuming that changes are 499 | * likely in pairs. */ 500 | for (x = 0; x < (int) scrinfo.xres; x += varblock.pixels_per_int) { 501 | unsigned int pixel = *f; 502 | 503 | if (pixel != *c) { 504 | *c = pixel; /* update compare buffer */ 505 | 506 | /* XXX: Undo the checkered pattern to test the 507 | * efficiency gain using hextile encoding. */ 508 | if (pixel == 0x18e320e4 || pixel == 0x20e418e3) 509 | pixel = 0x18e318e3; /* still needed? */ 510 | 511 | /* update remote buffer */ 512 | *r = PIXEL_FB_TO_RFB(pixel, 513 | varblock.r_offset, 514 | varblock.g_offset, 515 | varblock.b_offset); 516 | 517 | if (x < varblock.min_x) 518 | varblock.min_x = x; 519 | else { 520 | if (x > varblock.max_x) 521 | varblock.max_x = x; 522 | } 523 | 524 | if (y < varblock.min_y) 525 | varblock.min_y = y; 526 | else if (y > varblock.max_y) 527 | varblock.max_y = y; 528 | } 529 | 530 | f++, c++; 531 | r++; 532 | } 533 | } 534 | 535 | if (varblock.min_x < INT_MAX) { 536 | if (varblock.max_x < 0) 537 | varblock.max_x = varblock.min_x; 538 | 539 | if (varblock.max_y < 0) 540 | varblock.max_y = varblock.min_y; 541 | 542 | pr_vdebug("Changed frame: %dx%d @ (%d,%d)...\n", 543 | (varblock.max_x + 2) - varblock.min_x, 544 | (varblock.max_y + 1) - varblock.min_y, 545 | varblock.min_x, varblock.min_y); 546 | 547 | rfbMarkRectAsModified(vncscr, varblock.min_x, varblock.min_y, 548 | varblock.max_x + 2, varblock.max_y + 1); 549 | 550 | rfbProcessEvents(vncscr, 10000); /* update quickly */ 551 | } 552 | } 553 | 554 | void blank_framebuffer() 555 | { 556 | int i, n = scrinfo.xres * scrinfo.yres / varblock.pixels_per_int; 557 | for (i = 0; i < n; i++) { 558 | ((int *)vncbuf)[i] = 0; 559 | ((int *)fbbuf)[i] = 0; 560 | } 561 | } 562 | 563 | /*****************************************************************************/ 564 | 565 | void print_usage(char **argv) 566 | { 567 | pr_info("%s [-k device] [-t device] [-h]\n" 568 | "-k device: keyboard device node, default is %s\n" 569 | "-t device: touch device node, default is %s\n" 570 | "-h : print this help\n", 571 | APPNAME, KBD_DEVICE, TOUCH_DEVICE); 572 | } 573 | 574 | int input_finder(int max_num, const char* *patterns, char *path, int path_size) 575 | { 576 | char name[128], trypath[PATH_MAX]; 577 | const char* *keystr; 578 | int fd = -1, i, j; 579 | int device_id = -1, key_id = -1; 580 | 581 | for (i = 0; i < max_num; i++) 582 | { 583 | snprintf(trypath, sizeof(trypath), DEV_FMT, i); 584 | 585 | if ((fd = open(trypath, O_RDONLY)) < 0) { 586 | continue; 587 | } 588 | 589 | if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) { 590 | close(fd); 591 | continue; 592 | } 593 | 594 | close(fd); 595 | 596 | for (keystr = patterns, j = 0; *keystr; keystr++, j++) { 597 | if (strstr(name, *keystr)) { 598 | /* save the device matching earliest pattern */ 599 | if (key_id < 0 || key_id > j) { 600 | key_id = j; 601 | device_id = i; 602 | strncpy(path, trypath, path_size); 603 | path[path_size - 1] = '\0'; 604 | } 605 | } 606 | } /* for */ 607 | } 608 | 609 | if (device_id >= 0) 610 | pr_info("Found input device %s by keyword %s\n", path, 611 | patterns[key_id]); 612 | 613 | return device_id; /* -1 if not found */ 614 | } 615 | 616 | /* determine input device paths */ 617 | int input_search() 618 | { 619 | const int max_input_num = 5; 620 | int rc = 0; 621 | if (input_finder(max_input_num, KBD_PATTERNS, 622 | KBD_DEVICE, sizeof KBD_DEVICE) < 0) { 623 | pr_vdebug("Cannot automatically find the keyboard device\n"); 624 | rc++; 625 | } 626 | 627 | if (input_finder(max_input_num, TOUCH_PATTERNS, 628 | TOUCH_DEVICE, sizeof TOUCH_DEVICE) < 0) { 629 | pr_vdebug("Cannot automatically find the touchscreen device\n"); 630 | rc++; 631 | } 632 | return rc; 633 | } 634 | 635 | void exit_cleanup(void) 636 | { 637 | pr_info("Cleaning up...\n"); 638 | cleanup_fb(); 639 | cleanup_kbd(); 640 | cleanup_touch(); 641 | } 642 | 643 | void sigint_handler(int arg) 644 | { 645 | if (old_sigint_handler) 646 | old_sigint_handler(arg); 647 | 648 | if (vncbuf) 649 | free(vncbuf); 650 | 651 | rfbScreenCleanup(vncscr); 652 | 653 | pr_err(" exit.\n"); 654 | exit(-1); 655 | } 656 | 657 | int main(int argc, char **argv) 658 | { 659 | /* attempts to auto-determine input devices first */ 660 | input_search(); 661 | 662 | if(argc > 1) 663 | { 664 | int i=1; 665 | while(i < argc) 666 | { 667 | if(*argv[i] == '-') 668 | { 669 | switch(*(argv[i] + 1)) 670 | { 671 | case 'h': 672 | print_usage(argv); 673 | exit(0); 674 | break; 675 | case 'k': 676 | i++; 677 | strcpy(KBD_DEVICE, argv[i]); 678 | break; 679 | case 't': 680 | i++; 681 | strcpy(TOUCH_DEVICE, argv[i]); 682 | break; 683 | } 684 | } 685 | i++; 686 | } 687 | } 688 | 689 | pr_info("Initializing framebuffer device " FB_DEVICE "...\n"); 690 | init_fb(); 691 | 692 | if (KBD_DEVICE[0]) { 693 | pr_info("Initializing keyboard device %s ...\n", KBD_DEVICE); 694 | init_kbd(); 695 | } 696 | 697 | if (TOUCH_DEVICE[0]) { 698 | pr_info("Initializing touch device %s ...\n", TOUCH_DEVICE); 699 | init_touch(); 700 | } 701 | 702 | pr_info("Initializing Framebuffer VNC server:\n"); 703 | pr_info(" width: %d\n", (int)scrinfo.xres); 704 | pr_info(" height: %d\n", (int)scrinfo.yres); 705 | pr_info(" bpp: %d\n", (int)scrinfo.bits_per_pixel); 706 | pr_info(" port: %d\n", (int)VNC_PORT); 707 | init_fb_server(argc, argv); 708 | 709 | atexit(exit_cleanup); 710 | old_sigint_handler = signal(SIGINT, sigint_handler); 711 | 712 | /* Implement our own event loop to detect changes in the framebuffer. */ 713 | while (1) { 714 | rfbClientPtr client_ptr; 715 | while (!vncscr->clientHead) { 716 | /* sleep until getting a client */ 717 | rfbProcessEvents(vncscr, LONG_MAX); 718 | } 719 | 720 | /* refresh screen every 100 ms */ 721 | rfbProcessEvents(vncscr, 100 * 1000 /* timeout in us */); 722 | 723 | /* all clients closed */ 724 | if (!vncscr->clientHead) { 725 | blank_framebuffer(vncbuf); 726 | } 727 | 728 | /* scan screen if at least one client has requested */ 729 | for (client_ptr = vncscr->clientHead; client_ptr; client_ptr = client_ptr->next) 730 | { 731 | if (!sraRgnEmpty(client_ptr->requestedRegion)) { 732 | update_screen(); 733 | break; 734 | } 735 | } 736 | } 737 | 738 | return 0; 739 | } 740 | -------------------------------------------------------------------------------- /libs-build-note/libjpeg-turbo-Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_C_INCLUDES := \ 5 | $(LOCAL_PATH) \ 6 | 7 | LOCAL_SRC_FILES := \ 8 | bmp.c \ 9 | cdjpeg.c \ 10 | cjpeg.c \ 11 | djpeg.c \ 12 | example.c \ 13 | jaricom.c \ 14 | jcapimin.c \ 15 | jcapistd.c \ 16 | jcarith.c \ 17 | jccoefct.c \ 18 | jccolor.c \ 19 | jcdctmgr.c \ 20 | jchuff.c \ 21 | jcinit.c \ 22 | jcmainct.c \ 23 | jcmarker.c \ 24 | jcmaster.c \ 25 | jcomapi.c \ 26 | jcparam.c \ 27 | jcphuff.c \ 28 | jcprepct.c \ 29 | jcsample.c \ 30 | jcstest.c \ 31 | jctrans.c \ 32 | jdapimin.c \ 33 | jdapistd.c \ 34 | jdarith.c \ 35 | jdatadst.c \ 36 | jdatadst-tj.c \ 37 | jdatasrc.c \ 38 | jdatasrc-tj.c \ 39 | jdcoefct.c \ 40 | jdcolor.c \ 41 | jddctmgr.c \ 42 | jdhuff.c \ 43 | jdinput.c \ 44 | jdmainct.c \ 45 | jdmarker.c \ 46 | jdmaster.c \ 47 | jdmerge.c \ 48 | jdphuff.c \ 49 | jdpostct.c \ 50 | jdsample.c \ 51 | jdtrans.c \ 52 | jerror.c \ 53 | jfdctflt.c \ 54 | jfdctfst.c \ 55 | jfdctint.c \ 56 | jidctflt.c \ 57 | jidctfst.c \ 58 | jidctint.c \ 59 | jidctred.c \ 60 | jmemmgr.c \ 61 | jmemnobs.c \ 62 | jpegtran.c \ 63 | jquant1.c \ 64 | jquant2.c \ 65 | jsimd_none.c \ 66 | jutils.c \ 67 | rdbmp.c \ 68 | rdcolmap.c \ 69 | rdgif.c \ 70 | rdjpgcom.c \ 71 | rdppm.c \ 72 | rdrle.c \ 73 | rdswitch.c \ 74 | rdtarga.c \ 75 | simd/jsimd_arm.c \ 76 | tjbench.c \ 77 | tjunittest.c \ 78 | tjutil.c \ 79 | transupp.c \ 80 | turbojpeg.c \ 81 | turbojpeg-jni.c \ 82 | wrbmp.c \ 83 | wrgif.c \ 84 | wrjpgcom.c \ 85 | wrppm.c \ 86 | wrrle.c \ 87 | wrtarga.c \ 88 | 89 | LOCAL_CFLAGS := 90 | LOCAL_MODULE := libjpeg_turbo_static 91 | 92 | include $(BUILD_STATIC_LIBRARY) 93 | -------------------------------------------------------------------------------- /libs-build-note/libvncserver-Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_C_INCLUDES := \ 5 | $(LOCAL_PATH) \ 6 | $(LOCAL_PATH)/libvncserver \ 7 | $(LOCAL_PATH)/common \ 8 | external/zlib \ 9 | external/libpng \ 10 | libjpeg-turbo \ 11 | external/openssl/include \ 12 | 13 | LOCAL_SRC_FILES := \ 14 | common/d3des.c \ 15 | common/minilzo.c \ 16 | common/sha1.c \ 17 | common/turbojpeg.c \ 18 | common/vncauth.c \ 19 | common/zywrletemplate.c \ 20 | libvncserver/auth.c \ 21 | libvncserver/cargs.c \ 22 | libvncserver/corre.c \ 23 | libvncserver/cursor.c \ 24 | libvncserver/cutpaste.c \ 25 | libvncserver/draw.c \ 26 | libvncserver/font.c \ 27 | libvncserver/hextile.c \ 28 | libvncserver/httpd.c \ 29 | libvncserver/main.c \ 30 | libvncserver/rfbssl_openssl.c \ 31 | libvncserver/rfbcrypto_openssl.c \ 32 | libvncserver/rfbregion.c \ 33 | libvncserver/rfbserver.c \ 34 | libvncserver/rre.c \ 35 | libvncserver/scale.c \ 36 | libvncserver/selbox.c \ 37 | libvncserver/sockets.c \ 38 | libvncserver/stats.c \ 39 | libvncserver/tight.c \ 40 | libvncserver/tightvnc-filetransfer/filelistinfo.c \ 41 | libvncserver/tightvnc-filetransfer/filetransfermsg.c \ 42 | libvncserver/tightvnc-filetransfer/handlefiletransferrequest.c \ 43 | libvncserver/tightvnc-filetransfer/rfbtightserver.c \ 44 | libvncserver/translate.c \ 45 | libvncserver/ultra.c \ 46 | libvncserver/websockets.c \ 47 | libvncserver/zlib.c \ 48 | libvncserver/zrle.c \ 49 | libvncserver/zrleoutstream.c \ 50 | libvncserver/zrlepalettehelper.c \ 51 | 52 | LOCAL_CFLAGS := 53 | LOCAL_MODULE := libvncserver_static 54 | 55 | include $(BUILD_STATIC_LIBRARY) 56 | -------------------------------------------------------------------------------- /libs-build-note/note.txt: -------------------------------------------------------------------------------- 1 | copy related Android.mk to each lib dir 2 | 3 | LibVNCServer-0.9.10 4 | libjpeg-turbo-1.3.1.tar.gz 5 | 6 | cd libvncserver 7 | ./autogen.sh 8 | ./configure --without-crypto 9 | 10 | 11 | cd libjpeg-turbo 12 | ./configure 13 | --------------------------------------------------------------------------------